mirror of https://github.com/Mai-with-u/MaiBot.git
170 lines
7.3 KiB
Python
170 lines
7.3 KiB
Python
# 定义了来自外部世界的信息
|
||
# 外部世界可以是某个聊天 不同平台的聊天 也可以是任意媒体
|
||
from datetime import datetime
|
||
from src.plugins.models.utils_model import LLM_request
|
||
from src.plugins.config.config import global_config
|
||
from src.common.database import db
|
||
from src.common.logger import get_module_logger
|
||
import traceback
|
||
|
||
logger = get_module_logger("observation")
|
||
|
||
|
||
# 所有观察的基类
|
||
class Observation:
|
||
def __init__(self, observe_type, observe_id):
|
||
self.observe_info = ""
|
||
self.observe_type = observe_type
|
||
self.observe_id = observe_id
|
||
self.last_observe_time = datetime.now().timestamp() # 初始化为当前时间
|
||
|
||
|
||
# 聊天观察
|
||
class ChattingObservation(Observation):
|
||
def __init__(self, chat_id):
|
||
super().__init__("chat", chat_id)
|
||
self.chat_id = chat_id
|
||
|
||
self.talking_message = []
|
||
self.talking_message_str = ""
|
||
|
||
self.name = global_config.BOT_NICKNAME
|
||
self.nick_name = global_config.BOT_ALIAS_NAMES
|
||
|
||
self.max_now_obs_len = global_config.observation_context_size
|
||
self.overlap_len = global_config.compressed_length
|
||
self.mid_memorys = []
|
||
self.max_mid_memory_len = global_config.compress_length_limit
|
||
self.mid_memory_info = ""
|
||
self.now_message_info = ""
|
||
|
||
self.updating_old = False
|
||
|
||
self.llm_summary = LLM_request(
|
||
model=global_config.llm_observation, temperature=0.7, max_tokens=300, request_type="chat_observation"
|
||
)
|
||
|
||
# 进行一次观察 返回观察结果observe_info
|
||
def get_observe_info(self, ids=None):
|
||
if ids:
|
||
mid_memory_str = ""
|
||
for id in ids:
|
||
print(f"id:{id}")
|
||
try:
|
||
for mid_memory in self.mid_memorys:
|
||
if mid_memory["id"] == id:
|
||
mid_memory_by_id = mid_memory
|
||
msg_str = ""
|
||
for msg in mid_memory_by_id["messages"]:
|
||
msg_str += f"{msg['detailed_plain_text']}"
|
||
# time_diff = int((datetime.now().timestamp() - mid_memory_by_id["created_at"]) / 60)
|
||
# mid_memory_str += f"距离现在{time_diff}分钟前:\n{msg_str}\n"
|
||
mid_memory_str += f"{msg_str}\n"
|
||
except Exception as e:
|
||
logger.error(f"获取mid_memory_id失败: {e}")
|
||
traceback.print_exc()
|
||
# print(f"获取mid_memory_id失败: {e}")
|
||
return self.now_message_info
|
||
|
||
return mid_memory_str + "现在群里正在聊:\n" + self.now_message_info
|
||
|
||
else:
|
||
return self.now_message_info
|
||
|
||
async def observe(self):
|
||
# 查找新消息
|
||
new_messages = list(
|
||
db.messages.find({"chat_id": self.chat_id, "time": {"$gt": self.last_observe_time}}).sort("time", 1)
|
||
) # 按时间正序排列
|
||
|
||
if not new_messages:
|
||
return self.observe_info # 没有新消息,返回上次观察结果
|
||
|
||
self.last_observe_time = new_messages[-1]["time"]
|
||
|
||
self.talking_message.extend(new_messages)
|
||
|
||
# 将新消息转换为字符串格式
|
||
new_messages_str = ""
|
||
for msg in new_messages:
|
||
if "detailed_plain_text" in msg:
|
||
new_messages_str += f"{msg['detailed_plain_text']}"
|
||
|
||
# print(f"new_messages_str:{new_messages_str}")
|
||
|
||
# 将新消息添加到talking_message,同时保持列表长度不超过20条
|
||
|
||
if len(self.talking_message) > self.max_now_obs_len and not self.updating_old:
|
||
self.updating_old = True
|
||
# 计算需要保留的消息数量
|
||
keep_messages_count = self.max_now_obs_len - self.overlap_len
|
||
# 提取所有超出保留数量的最老消息
|
||
oldest_messages = self.talking_message[:-keep_messages_count]
|
||
self.talking_message = self.talking_message[-keep_messages_count:]
|
||
oldest_messages_str = "\n".join([msg["detailed_plain_text"] for msg in oldest_messages])
|
||
oldest_timestamps = [msg["time"] for msg in oldest_messages]
|
||
|
||
# 调用 LLM 总结主题
|
||
prompt = f"请总结以下聊天记录的主题:\n{oldest_messages_str}\n主题,用一句话概括包括人物事件和主要信息,不要分点:"
|
||
try:
|
||
summary, _ = await self.llm_summary.generate_response_async(prompt)
|
||
except Exception as e:
|
||
print(f"总结主题失败: {e}")
|
||
summary = "无法总结主题"
|
||
|
||
mid_memory = {
|
||
"id": str(int(datetime.now().timestamp())),
|
||
"theme": summary,
|
||
"messages": oldest_messages,
|
||
"timestamps": oldest_timestamps,
|
||
"chat_id": self.chat_id,
|
||
"created_at": datetime.now().timestamp(),
|
||
}
|
||
# print(f"mid_memory:{mid_memory}")
|
||
# 存入内存中的 mid_memorys
|
||
self.mid_memorys.append(mid_memory)
|
||
if len(self.mid_memorys) > self.max_mid_memory_len:
|
||
self.mid_memorys.pop(0)
|
||
|
||
mid_memory_str = "之前聊天的内容概括是:\n"
|
||
for mid_memory in self.mid_memorys:
|
||
time_diff = int((datetime.now().timestamp() - mid_memory["created_at"]) / 60)
|
||
mid_memory_str += f"距离现在{time_diff}分钟前(聊天记录id:{mid_memory['id']}):{mid_memory['theme']}\n"
|
||
self.mid_memory_info = mid_memory_str
|
||
|
||
self.updating_old = False
|
||
|
||
# print(f"处理后self.talking_message:{self.talking_message}")
|
||
|
||
now_message_str = ""
|
||
now_message_str += self.translate_message_list_to_str(talking_message=self.talking_message)
|
||
self.now_message_info = now_message_str
|
||
|
||
logger.debug(f"压缩早期记忆:{self.mid_memory_info}\n现在聊天内容:{self.now_message_info}")
|
||
|
||
async def update_talking_summary(self, new_messages_str):
|
||
prompt = ""
|
||
# prompt += f"{personality_info}"
|
||
prompt += f"你的名字叫:{self.name}\n,标识'{self.name}'的都是你自己说的话"
|
||
prompt += f"你正在参与一个qq群聊的讨论,你记得这个群之前在聊的内容是:{self.observe_info}\n"
|
||
prompt += f"现在群里的群友们产生了新的讨论,有了新的发言,具体内容如下:{new_messages_str}\n"
|
||
prompt += """以上是群里在进行的聊天,请你对这个聊天内容进行总结,总结内容要包含聊天的大致内容,目前最新讨论的话题
|
||
以及聊天中的一些重要信息,记得不要分点,精简的概括成一段文本\n"""
|
||
prompt += "总结概括:"
|
||
try:
|
||
updated_observe_info, reasoning_content = await self.llm_summary.generate_response_async(prompt)
|
||
except Exception as e:
|
||
print(f"获取总结失败: {e}")
|
||
updated_observe_info = ""
|
||
|
||
return updated_observe_info
|
||
# print(f"prompt:{prompt}")
|
||
# print(f"self.observe_info:{self.observe_info}")
|
||
|
||
def translate_message_list_to_str(self, talking_message):
|
||
talking_message_str = ""
|
||
for message in talking_message:
|
||
talking_message_str += message["detailed_plain_text"]
|
||
|
||
return talking_message_str
|