feat:添加语言风格学习

This commit is contained in:
SengokuCola
2025-05-12 21:12:59 +08:00
parent 11248cd0e3
commit 900ce21175
13 changed files with 340 additions and 109 deletions

View File

@@ -37,6 +37,14 @@ class ObsInfo(InfoBase):
""" """
self.data["talking_message_str_truncate"] = message self.data["talking_message_str_truncate"] = message
def set_previous_chat_info(self, message: str) -> None:
"""设置之前聊天信息
Args:
message (str): 之前聊天信息内容
"""
self.data["previous_chat_info"] = message
def set_chat_type(self, chat_type: str) -> None: def set_chat_type(self, chat_type: str) -> None:
"""设置聊天类型 """设置聊天类型

View File

@@ -61,6 +61,9 @@ class ChattingObservation(Observation):
self.max_mid_memory_len = global_config.compress_length_limit self.max_mid_memory_len = global_config.compress_length_limit
self.mid_memory_info = "" self.mid_memory_info = ""
self.person_list = [] self.person_list = []
self.oldest_messages = []
self.oldest_messages_str = ""
self.compressor_prompt = ""
self.llm_summary = LLMRequest( self.llm_summary = LLMRequest(
model=global_config.llm_observation, temperature=0.7, max_tokens=300, request_type="chat_observation" model=global_config.llm_observation, temperature=0.7, max_tokens=300, request_type="chat_observation"
) )
@@ -75,8 +78,8 @@ class ChattingObservation(Observation):
# 进行一次观察 返回观察结果observe_info # 进行一次观察 返回观察结果observe_info
def get_observe_info(self, ids=None): def get_observe_info(self, ids=None):
mid_memory_str = ""
if ids: if ids:
mid_memory_str = ""
for id in ids: for id in ids:
print(f"id{id}") print(f"id{id}")
try: try:
@@ -97,7 +100,10 @@ class ChattingObservation(Observation):
return mid_memory_str + "现在群里正在聊:\n" + self.talking_message_str return mid_memory_str + "现在群里正在聊:\n" + self.talking_message_str
else: else:
return self.talking_message_str mid_memory_str = "之前的聊天内容:\n"
for mid_memory in self.mid_memorys:
mid_memory_str += f"{mid_memory['theme']}\n"
return mid_memory_str + "现在群里正在聊:\n" + self.talking_message_str
def serch_message_by_text(self, text: str) -> Optional[MessageRecv]: def serch_message_by_text(self, text: str) -> Optional[MessageRecv]:
""" """
@@ -221,40 +227,10 @@ class ChattingObservation(Observation):
logger.error(f"构建总结 Prompt 失败 for chat {self.chat_id}: {e}") logger.error(f"构建总结 Prompt 失败 for chat {self.chat_id}: {e}")
# prompt remains None # prompt remains None
summary = "没有主题的闲聊" # 默认值
if prompt: # Check if prompt was built successfully if prompt: # Check if prompt was built successfully
try: self.compressor_prompt = prompt
summary_result, _, _ = await self.llm_summary.generate_response(prompt) self.oldest_messages = oldest_messages
if summary_result: # 确保结果不为空 self.oldest_messages_str = oldest_messages_str
summary = summary_result
except Exception as e:
logger.error(f"总结主题失败 for chat {self.chat_id}: {e}")
# 保留默认总结 "没有主题的闲聊"
else:
logger.warning(f"因 Prompt 构建失败,跳过 LLM 总结 for chat {self.chat_id}")
mid_memory = {
"id": str(int(datetime.now().timestamp())),
"theme": summary,
"messages": oldest_messages, # 存储原始消息对象
"readable_messages": oldest_messages_str,
# "timestamps": oldest_timestamps,
"chat_id": self.chat_id,
"created_at": datetime.now().timestamp(),
}
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_item in self.mid_memorys: # 重命名循环变量以示区分
time_diff = int((datetime.now().timestamp() - mid_memory_item["created_at"]) / 60)
mid_memory_str += (
f"距离现在{time_diff}分钟前(聊天记录id:{mid_memory_item['id']}){mid_memory_item['theme']}\n"
)
self.mid_memory_info = mid_memory_str
self.talking_message_str = await build_readable_messages( self.talking_message_str = await build_readable_messages(
messages=self.talking_message, messages=self.talking_message,

View File

@@ -21,8 +21,8 @@ class HFCloopObservation:
return self.observe_info return self.observe_info
def add_loop_info(self, loop_info: CycleDetail): def add_loop_info(self, loop_info: CycleDetail):
logger.debug(f"添加循环信息111111111111111111111111111111111111: {loop_info}") # logger.debug(f"添加循环信息111111111111111111111111111111111111: {loop_info}")
print(f"添加循环信息111111111111111111111111111111111111: {loop_info}") # print(f"添加循环信息111111111111111111111111111111111111: {loop_info}")
print(f"action_taken: {loop_info.action_taken}") print(f"action_taken: {loop_info.action_taken}")
print(f"action_type: {loop_info.action_type}") print(f"action_type: {loop_info.action_type}")
print(f"response_info: {loop_info.response_info}") print(f"response_info: {loop_info.response_info}")
@@ -63,9 +63,18 @@ class HFCloopObservation:
# 包装提示块,增加可读性,即使没有连续回复也给个标记 # 包装提示块,增加可读性,即使没有连续回复也给个标记
if cycle_info_block: if cycle_info_block:
cycle_info_block = f"\n【近期回复历史】\n{cycle_info_block}\n" cycle_info_block = f"\n你最近的回复\n{cycle_info_block}\n"
else: else:
# 如果最近的活动循环不是文本回复,或者没有活动循环 # 如果最近的活动循环不是文本回复,或者没有活动循环
cycle_info_block = "\n【近期回复历史】\n(最近没有连续文本回复)\n" cycle_info_block = "\n"
# 获取history_loop中最新添加的
if self.history_loop:
last_loop = self.history_loop[-1]
start_time = last_loop.start_time
end_time = last_loop.end_time
time_diff = int(end_time - start_time)
cycle_info_block += f"\n距离你上一次阅读消息已经过去了{time_diff}分钟\n"
self.observe_info = cycle_info_block self.observe_info = cycle_info_block

View File

@@ -18,6 +18,7 @@ from .plugins.remote import heartbeat_thread # noqa: F401
from .individuality.individuality import Individuality from .individuality.individuality import Individuality
from .common.server import global_server from .common.server import global_server
from rich.traceback import install from rich.traceback import install
from .plugins.heartFC_chat.expressors.exprssion_learner import expression_learner
from .api.main import start_api_server from .api.main import start_api_server
install(extra_lines=3) install(extra_lines=3)
@@ -129,6 +130,7 @@ class MainSystem:
self.build_memory_task(), self.build_memory_task(),
self.forget_memory_task(), self.forget_memory_task(),
self.consolidate_memory_task(), self.consolidate_memory_task(),
self.learn_and_store_expression_task(),
self.print_mood_task(), self.print_mood_task(),
self.remove_recalled_message_task(), self.remove_recalled_message_task(),
emoji_manager.start_periodic_check_register(), emoji_manager.start_periodic_check_register(),
@@ -163,6 +165,15 @@ class MainSystem:
await HippocampusManager.get_instance().consolidate_memory() await HippocampusManager.get_instance().consolidate_memory()
print("\033[1;32m[记忆整合]\033[0m 记忆整合完成") print("\033[1;32m[记忆整合]\033[0m 记忆整合完成")
@staticmethod
async def learn_and_store_expression_task():
"""学习并存储表达方式任务"""
while True:
await asyncio.sleep(60)
print("\033[1;32m[表达方式学习]\033[0m 开始学习表达方式...")
await expression_learner.learn_and_store_expression()
print("\033[1;32m[表达方式学习]\033[0m 表达方式学习完成")
async def print_mood_task(self): async def print_mood_task(self):
"""打印情绪状态""" """打印情绪状态"""
while True: while True:

View File

@@ -54,10 +54,10 @@ class DefaultExpressor:
user_nickname=global_config.BOT_NICKNAME, user_nickname=global_config.BOT_NICKNAME,
platform=messageinfo.platform, platform=messageinfo.platform,
) )
logger.debug(f"创建思考消息:{anchor_message}") # logger.debug(f"创建思考消息:{anchor_message}")
logger.debug(f"创建思考消息chat{chat}") # logger.debug(f"创建思考消息chat{chat}")
logger.debug(f"创建思考消息bot_user_info{bot_user_info}") # logger.debug(f"创建思考消息bot_user_info{bot_user_info}")
logger.debug(f"创建思考消息messageinfo{messageinfo}") # logger.debug(f"创建思考消息messageinfo{messageinfo}")
thinking_time_point = round(time.time(), 2) thinking_time_point = round(time.time(), 2)
thinking_id = "mt" + str(thinking_time_point) thinking_id = "mt" + str(thinking_time_point)

View File

@@ -0,0 +1,148 @@
import time
from typing import List, Dict, Optional, Any, Tuple, Coroutine
from src.common.logger_manager import get_logger
from src.plugins.models.utils_model import LLMRequest
from src.config.config import global_config
from src.plugins.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages
from src.plugins.heartFC_chat.heartflow_prompt_builder import Prompt, global_prompt_manager
import os
import json
logger = get_logger("expressor")
def init_prompt() -> None:
learn_expression_prompt = """
{chat_str}
请从上面这段群聊中概括除了人名为"麦麦"之外的人的语言风格,只考虑文字,不要考虑表情包和图片
不要涉及具体的人名,只考虑语言风格
思考回复语法,长度和情感
思考有没有特殊的梗,一并总结成语言风格
总结成如下格式的规律,总结的内容要详细,但具有概括性:
"xxx"时,可以"xxx", xxx不超过10个字
例如:
"表示十分惊叹"时,使用"我嘞个xxxx"
"表示讽刺的赞同,不想讲道理"时,使用"对对对"
"想表达某个观点,但不想明说",使用"反讽"
"想说明某个观点,但懒得明说",使用"懂的都懂"
现在请你概括
"""
Prompt(learn_expression_prompt, "learn_expression_prompt")
class ExpressionLearner:
def __init__(self) -> None:
self.express_learn_model: LLMRequest = LLMRequest(
model=global_config.llm_normal,
temperature=global_config.llm_normal["temp"],
max_tokens=256,
request_type="response_heartflow",
)
async def get_expression_by_chat_id(self, chat_id: str) -> List[Dict[str, str]]:
"""从/data/expression/对应chat_id/expressions.json中读取表达方式"""
file_path: str = os.path.join("data", "expression", str(chat_id), "expressions.json")
if not os.path.exists(file_path):
return []
with open(file_path, "r", encoding="utf-8") as f:
expressions: List[dict] = json.load(f)
return expressions
async def learn_and_store_expression(self) -> List[Tuple[str, str, str]]:
"""选择从当前到最近1小时内的随机10条消息然后学习这些消息的表达方式"""
logger.info("开始学习表达方式...")
expressions: Optional[List[Tuple[str, str, str]]] = await self.learn_expression()
logger.info(f"学习到{len(expressions) if expressions else 0}条表达方式")
# expressions: List[(chat_id, situation, style)]
if not expressions:
logger.info("没有学习到表达方式")
return []
# 按chat_id分组
chat_dict: Dict[str, List[Dict[str, str]]] = {}
for chat_id, situation, style in expressions:
if chat_id not in chat_dict:
chat_dict[chat_id] = []
chat_dict[chat_id].append({"situation": situation, "style": style})
# 存储到/data/expression/对应chat_id/expressions.json
for chat_id, expr_list in chat_dict.items():
dir_path = os.path.join("data", "expression", str(chat_id))
os.makedirs(dir_path, exist_ok=True)
file_path = os.path.join(dir_path, "expressions.json")
# 若已存在,先读出合并
if os.path.exists(file_path):
old_data: List[Dict[str, str]] = []
try:
with open(file_path, "r", encoding="utf-8") as f:
old_data = json.load(f)
except Exception:
old_data = []
expr_list = old_data + expr_list
with open(file_path, "w", encoding="utf-8") as f:
json.dump(expr_list, f, ensure_ascii=False, indent=2)
return expressions
async def learn_expression(self) -> Optional[List[Tuple[str, str, str]]]:
"""选择从当前到最近1小时内的随机10条消息然后学习这些消息的表达方式
Args:
chat_stream (ChatStream): _description_
"""
current_time = time.time()
random_msg: Optional[List[Dict[str, Any]]] = get_raw_msg_by_timestamp_random(current_time - 3600 * 24, current_time, limit=10)
if not random_msg:
return None
# 转化成str
chat_id: str = random_msg[0]["chat_id"]
random_msg_str: str = await build_readable_messages(random_msg, timestamp_mode="normal")
prompt: str = await global_prompt_manager.format_prompt(
"learn_expression_prompt",
chat_str=random_msg_str,
)
logger.info(f"学习表达方式的prompt: {prompt}")
response, _ = await self.express_learn_model.generate_response_async(prompt)
logger.info(f"学习表达方式的response: {response}")
expressions: List[Tuple[str, str, str]] = self.parse_expression_response(response, chat_id)
return expressions
def parse_expression_response(self, response: str, chat_id: str) -> List[Tuple[str, str, str]]:
"""
解析LLM返回的表达风格总结每一行提取"""使用"之间的内容,存储为(situation, style)元组
"""
expressions: List[Tuple[str, str, str]] = []
for line in response.splitlines():
line = line.strip()
if not line:
continue
# 查找"当"和下一个引号
idx_when = line.find('"')
if idx_when == -1:
continue
idx_quote1 = idx_when + 1
idx_quote2 = line.find('"', idx_quote1 + 1)
if idx_quote2 == -1:
continue
situation = line[idx_quote1 + 1 : idx_quote2]
# 查找"使用"
idx_use = line.find('使用"', idx_quote2)
if idx_use == -1:
continue
idx_quote3 = idx_use + 2
idx_quote4 = line.find('"', idx_quote3 + 1)
if idx_quote4 == -1:
continue
style = line[idx_quote3 + 1 : idx_quote4]
expressions.append((chat_id, situation, style))
return expressions
init_prompt()
expression_learner = ExpressionLearner()

View File

@@ -408,7 +408,8 @@ class HeartFChatting:
for observation in observations: for observation in observations:
logger.debug(f"{self.log_prefix} 观察信息: {observation}") logger.debug(f"{self.log_prefix} 观察信息: {observation}")
running_memorys = await self.memory_activator.activate_memory(observations) with Timer("回忆", cycle_timers):
running_memorys = await self.memory_activator.activate_memory(observations)
# 记录并行任务开始时间 # 记录并行任务开始时间
parallel_start_time = time.time() parallel_start_time = time.time()

View File

@@ -14,6 +14,7 @@ from ..moods.moods import MoodManager
from ..memory_system.Hippocampus import HippocampusManager from ..memory_system.Hippocampus import HippocampusManager
from ..schedule.schedule_generator import bot_schedule from ..schedule.schedule_generator import bot_schedule
from ..knowledge.knowledge_lib import qa_manager from ..knowledge.knowledge_lib import qa_manager
from .expressors.exprssion_learner import expression_learner
import traceback import traceback
@@ -42,24 +43,22 @@ def init_prompt():
# ) # )
Prompt( Prompt(
""" """
你可以参考以下的语言习惯: 你可以参考以下的语言习惯,如果情景合适就使用,不要盲目使用
当表示惊叹时,使用 我嘞个xxxx {language_habits}
当表示惊讶无语是,使用 不是?
当表示无语时,使用 阿这 不要生硬使用,而是结合到表达中
当表示震惊时,使用 卧槽
{chat_info}
你需要学习聊天内容中其他人的回复风格,并结合到你的回复中
{chat_target} {chat_target}
现在你想要在群里发言或者回复。\n 你的名字是{bot_name}{prompt_personality},你想表达:{in_mind_reply},原因是:{reason}
你需要扮演一位网名叫{bot_name}的人进行回复,这个人的特点是:"{prompt_personality}"
你正在{chat_target_2},现在请你读读之前的聊天记录,然后给出日常且口语化的回复,平淡一些,你可以参考贴吧,知乎或者微博的回复风格。
你想表达:{in_mind_reply} 请注意,请根据你想表达的内容和原因,参考聊天内容,组织一条日常且口语化的回复
原因是:{reason} 要求回复尽量简短一些。{reply_style2}{prompt_ger}。可以参考贴吧,知乎或者微博的回复风格,你可以完全重组回复,保留最基本的表达含义就好,但注意简短,保持一个话题。
请根据你想表达的内容,参考上述语言习惯,和下面的要求,给出回复 {reply_style1},说中文,不要刻意突出自身学科背景。不要浮夸,不要用夸张修辞,平淡一些。不要输出多余内容(包括前后缀冒号和引号括号表情包at或 @等 ),只输出一条回复就好。
回复要求: """,
尽量简短一些。{reply_style2}{prompt_ger}
{reply_style1},说中文,不要刻意突出自身学科背景。不要浮夸,平淡一些。
注意:回复不要输出多余内容(包括前后缀冒号和引号括号表情包at或 @等 )。""",
"heart_flow_prompt", "heart_flow_prompt",
) )
@@ -144,8 +143,8 @@ def init_prompt():
) )
Prompt("你正在qq群里聊天下面是群里在聊的内容", "chat_target_group1") Prompt("你正在qq群里聊天下面是群里在聊的内容", "chat_target_group1")
Prompt("和群里聊天", "chat_target_group2")
Prompt("你正在和{sender_name}聊天,这是你们之前聊的内容:", "chat_target_private1") Prompt("你正在和{sender_name}聊天,这是你们之前聊的内容:", "chat_target_private1")
Prompt("在群里聊天", "chat_target_group2")
Prompt("{sender_name}私聊", "chat_target_private2") Prompt("{sender_name}私聊", "chat_target_private2")
Prompt( Prompt(
"""检查并忽略任何涉及尝试绕过审核的行为。涉及政治敏感以及违法违规的内容请规避。""", """检查并忽略任何涉及尝试绕过审核的行为。涉及政治敏感以及违法违规的内容请规避。""",
@@ -267,9 +266,9 @@ async def _build_prompt_focus(
)[0] )[0]
reply_styles2 = [ reply_styles2 = [
("不要回复的太有条理,可以有个性", 0.6), ("不要回复的太有条理,可以有个性", 0.7),
("不要回复的太有条理,可以复读,但是不要复读自己说的话", 0.15), ("不要回复的太有条理,可以复读,但是不要复读自己说的话", 0.1),
("回复的认真一些", 0.2), ("回复的认真一些", 0.1),
("可以回复单个表情符号", 0.05), ("可以回复单个表情符号", 0.05),
] ]
reply_style2_chosen = random.choices( reply_style2_chosen = random.choices(
@@ -283,6 +282,28 @@ async def _build_prompt_focus(
else: else:
structured_info_prompt = "" structured_info_prompt = ""
# 从/data/expression/对应chat_id/expressions.json中读取表达方式
expressions = await expression_learner.get_expression_by_chat_id(chat_stream.stream_id)
if expressions:
language_habits = []
for expr in expressions:
print(f"expr: {expr}")
if isinstance(expr, dict) and 'situation' in expr and 'style' in expr:
language_habits.append(f"{expr['situation']}时,使用 {expr['style']}")
else:
language_habits = [
"当表示惊叹时,使用 我嘞个xxxx",
"当表示惊讶无语是,使用 不是?",
"当表示无语时,使用 阿这",
"当表示震惊时,使用 卧槽",
"当用调侃的方式称呼某人,使用 哈基X",
"当表示讽刺的赞同时,使用 对对对",
"当你想表达某个观点,但不想明说,可以使用反讽",
"当你想说明某个观点,但懒得明说,使用 懂的都懂",
]
selected = random.sample(language_habits, 8)
language_habits_str = "\n".join(selected)
logger.debug("开始构建 focus prompt") logger.debug("开始构建 focus prompt")
# --- Choose template based on chat type --- # --- Choose template based on chat type ---
@@ -290,17 +311,19 @@ async def _build_prompt_focus(
template_name = "heart_flow_prompt" template_name = "heart_flow_prompt"
# Group specific formatting variables (already fetched or default) # Group specific formatting variables (already fetched or default)
chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1") chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1")
chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2") # chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2")
prompt = await global_prompt_manager.format_prompt( prompt = await global_prompt_manager.format_prompt(
template_name, template_name,
# info_from_tools=structured_info_prompt, # info_from_tools=structured_info_prompt,
language_habits=language_habits_str,
chat_target=chat_target_1, # Used in group template chat_target=chat_target_1, # Used in group template
# chat_talking_prompt=chat_talking_prompt, # chat_talking_prompt=chat_talking_prompt,
chat_info=chat_talking_prompt,
bot_name=global_config.BOT_NICKNAME, bot_name=global_config.BOT_NICKNAME,
# prompt_personality=prompt_personality, # prompt_personality=prompt_personality,
prompt_personality="", prompt_personality="",
chat_target_2=chat_target_2, # Used in group template # chat_target_2=chat_target_2, # Used in group template
# current_mind_info=current_mind_info, # current_mind_info=current_mind_info,
reply_style2=reply_style2_chosen, reply_style2=reply_style2_chosen,
reply_style1=reply_style1_chosen, reply_style1=reply_style1_chosen,

View File

@@ -7,7 +7,10 @@ from src.common.logger_manager import get_logger
from src.heart_flow.observation.chatting_observation import ChattingObservation from src.heart_flow.observation.chatting_observation import ChattingObservation
from src.heart_flow.observation.hfcloop_observation import HFCloopObservation from src.heart_flow.observation.hfcloop_observation import HFCloopObservation
from src.heart_flow.info.cycle_info import CycleInfo from src.heart_flow.info.cycle_info import CycleInfo
from datetime import datetime
from typing import Dict from typing import Dict
from src.plugins.models.utils_model import LLMRequest
from src.config.config import global_config
logger = get_logger("observation") logger = get_logger("observation")
@@ -20,6 +23,9 @@ class ChattingInfoProcessor(BaseProcessor):
def __init__(self): def __init__(self):
"""初始化观察处理器""" """初始化观察处理器"""
self.llm_summary = LLMRequest(
model=global_config.llm_observation, temperature=0.7, max_tokens=300, request_type="chat_observation"
)
super().__init__() super().__init__()
async def process_info( async def process_info(
@@ -48,6 +54,8 @@ class ChattingInfoProcessor(BaseProcessor):
if isinstance(obs, ChattingObservation): if isinstance(obs, ChattingObservation):
obs_info = ObsInfo() obs_info = ObsInfo()
await self.chat_compress(obs)
# 设置说话消息 # 设置说话消息
if hasattr(obs, "talking_message_str"): if hasattr(obs, "talking_message_str"):
obs_info.set_talking_message(obs.talking_message_str) obs_info.set_talking_message(obs.talking_message_str)
@@ -56,6 +64,9 @@ class ChattingInfoProcessor(BaseProcessor):
if hasattr(obs, "talking_message_str_truncate"): if hasattr(obs, "talking_message_str_truncate"):
obs_info.set_talking_message_str_truncate(obs.talking_message_str_truncate) obs_info.set_talking_message_str_truncate(obs.talking_message_str_truncate)
if hasattr(obs, "mid_memory_info"):
obs_info.set_previous_chat_info(obs.mid_memory_info)
# 设置聊天类型 # 设置聊天类型
is_group_chat = obs.is_group_chat is_group_chat = obs.is_group_chat
if is_group_chat: if is_group_chat:
@@ -65,7 +76,7 @@ class ChattingInfoProcessor(BaseProcessor):
obs_info.set_chat_target(obs.chat_target_info.get("person_name", "某人")) obs_info.set_chat_target(obs.chat_target_info.get("person_name", "某人"))
obs_info.set_chat_type(chat_type) obs_info.set_chat_type(chat_type)
logger.debug(f"聊天信息处理器处理后的信息: {obs_info}") # logger.debug(f"聊天信息处理器处理后的信息: {obs_info}")
processed_infos.append(obs_info) processed_infos.append(obs_info)
if isinstance(obs, HFCloopObservation): if isinstance(obs, HFCloopObservation):
@@ -74,3 +85,39 @@ class ChattingInfoProcessor(BaseProcessor):
processed_infos.append(obs_info) processed_infos.append(obs_info)
return processed_infos return processed_infos
async def chat_compress(self, obs: ChattingObservation):
if obs.compressor_prompt:
try:
summary_result, _, _ = await self.llm_summary.generate_response(obs.compressor_prompt)
summary = "没有主题的闲聊" # 默认值
if summary_result: # 确保结果不为空
summary = summary_result
except Exception as e:
logger.error(f"总结主题失败 for chat {obs.chat_id}: {e}")
mid_memory = {
"id": str(int(datetime.now().timestamp())),
"theme": summary,
"messages": obs.oldest_messages, # 存储原始消息对象
"readable_messages": obs.oldest_messages_str,
# "timestamps": oldest_timestamps,
"chat_id": obs.chat_id,
"created_at": datetime.now().timestamp(),
}
obs.mid_memorys.append(mid_memory)
if len(obs.mid_memorys) > obs.max_mid_memory_len:
obs.mid_memorys.pop(0) # 移除最旧的
mid_memory_str = "之前聊天的内容概述是:\n"
for mid_memory_item in obs.mid_memorys: # 重命名循环变量以示区分
time_diff = int((datetime.now().timestamp() - mid_memory_item["created_at"]) / 60)
mid_memory_str += (
f"距离现在{time_diff}分钟前(聊天记录id:{mid_memory_item['id']}){mid_memory_item['theme']}\n"
)
obs.mid_memory_info = mid_memory_str
obs.compressor_prompt = ""
obs.oldest_messages = []
obs.oldest_messages_str = ""

View File

@@ -32,20 +32,20 @@ def init_prompt():
{memory_str} {memory_str}
{extra_info} {extra_info}
{relation_prompt} {relation_prompt}
你的名字是{bot_name},{prompt_personality},你现在{mood_info} 你的名字是{bot_name}
{mood_info}
{cycle_info_block} {cycle_info_block}
现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容 现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
{chat_observe_info} {chat_observe_info}
以下是你之前对这个群聊的陈述 以下是你之前对聊天的观察和规划,你的名字是{bot_name}
{last_mind} {last_mind}
现在请你继续输出思考内容,输出要求: 现在请你继续输出观察和规划,输出要求:
1. 根据聊天内容生成你的想法,{hf_do_next} 1. 先关注未读新消息的内容和近期回复历史
2. 参考之前的思考,基于之前的内容对这个群聊继续陈述,可以删除不重要的内容,添加新的内容 2. 根据新信息,修改和删除之前的观察和规划
3. 思考群内进行的话题,话题由谁发起,进展状况如何,你如何参与?思考你在群聊天中的角色,你是一个什么样的人,你在这个群聊中扮演什么角色? 3. 根据聊天内容继续输出观察和规划,{hf_do_next}
4. 注意群聊的时间线索,思考聊天的时间线。 4. 注意群聊的时间线索,话题由谁发起,进展状况如何,思考聊天的时间线。
5. 请结合你做出的行为,对前面的陈述进行补充
6. 语言简洁自然,不要分点,不要浮夸,不要修辞,仅输出思考内容就好""" 6. 语言简洁自然,不要分点,不要浮夸,不要修辞,仅输出思考内容就好"""
Prompt(group_prompt, "sub_heartflow_prompt_before") Prompt(group_prompt, "sub_heartflow_prompt_before")
@@ -58,10 +58,8 @@ def init_prompt():
{cycle_info_block} {cycle_info_block}
现在是{time_now},你正在上网,和 {chat_target_name} 私聊,以下是你们的聊天内容: 现在是{time_now},你正在上网,和 {chat_target_name} 私聊,以下是你们的聊天内容:
{chat_observe_info} {chat_observe_info}
以下是你之前对聊天的观察和规划:
以下是你之前在这个群聊中的思考:
{last_mind} {last_mind}
请仔细阅读聊天内容,想想你和 {chat_target_name} 的关系,回顾你们刚刚的交流,你刚刚发言和对方的反应,思考聊天的主题。 请仔细阅读聊天内容,想想你和 {chat_target_name} 的关系,回顾你们刚刚的交流,你刚刚发言和对方的反应,思考聊天的主题。
请思考你要不要回复以及如何回复对方。 请思考你要不要回复以及如何回复对方。
思考并输出你的内心想法 思考并输出你的内心想法
@@ -222,7 +220,7 @@ class MindProcessor(BaseProcessor):
prompt = (await global_prompt_manager.get_prompt_async(template_name)).format( prompt = (await global_prompt_manager.get_prompt_async(template_name)).format(
memory_str=memory_str, memory_str=memory_str,
extra_info=self.structured_info_str, extra_info=self.structured_info_str,
prompt_personality=prompt_personality, # prompt_personality=prompt_personality,
relation_prompt=relation_prompt, relation_prompt=relation_prompt,
bot_name=individuality.name, bot_name=individuality.name,
time_now=time_now, time_now=time_now,

View File

@@ -28,14 +28,8 @@ def init_prompt():
{prompt_personality} {prompt_personality}
你当前的额外信息: 你当前的额外信息:
{extra_info}
{memory_str} {memory_str}
你的心情是:{mood_info}
{relation_prompt}
群里正在进行的聊天内容: 群里正在进行的聊天内容:
{chat_observe_info} {chat_observe_info}
@@ -46,7 +40,6 @@ def init_prompt():
4. 考虑用户与你的关系以及当前的对话氛围 4. 考虑用户与你的关系以及当前的对话氛围
如果需要使用工具,请直接调用相应的工具函数。如果不需要使用工具,请简单输出"无需使用工具" 如果需要使用工具,请直接调用相应的工具函数。如果不需要使用工具,请简单输出"无需使用工具"
尽量只在确实必要时才使用工具。
""" """
Prompt(tool_executor_prompt, "tool_executor_prompt") Prompt(tool_executor_prompt, "tool_executor_prompt")
@@ -57,7 +50,7 @@ class ToolProcessor(BaseProcessor):
self.subheartflow_id = subheartflow_id self.subheartflow_id = subheartflow_id
self.log_prefix = f"[{subheartflow_id}:ToolExecutor] " self.log_prefix = f"[{subheartflow_id}:ToolExecutor] "
self.llm_model = LLMRequest( self.llm_model = LLMRequest(
model=global_config.llm_normal, model=global_config.llm_tool_use,
max_tokens=500, max_tokens=500,
request_type="tool_execution", request_type="tool_execution",
) )
@@ -141,9 +134,6 @@ class ToolProcessor(BaseProcessor):
individuality = Individuality.get_instance() individuality = Individuality.get_instance()
prompt_personality = individuality.get_prompt(x_person=2, level=2) prompt_personality = individuality.get_prompt(x_person=2, level=2)
# 获取心情信息
mood_info = observation.chat_state.mood if hasattr(observation, "chat_state") else ""
# 获取时间信息 # 获取时间信息
time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
@@ -151,13 +141,13 @@ class ToolProcessor(BaseProcessor):
prompt = await global_prompt_manager.format_prompt( prompt = await global_prompt_manager.format_prompt(
"tool_executor_prompt", "tool_executor_prompt",
memory_str=memory_str, memory_str=memory_str,
extra_info="extra_structured_info", # extra_info="extra_structured_info",
chat_observe_info=chat_observe_info, chat_observe_info=chat_observe_info,
# chat_target_name=chat_target_name, # chat_target_name=chat_target_name,
is_group_chat=is_group_chat, is_group_chat=is_group_chat,
relation_prompt=relation_prompt, # relation_prompt=relation_prompt,
prompt_personality=prompt_personality, prompt_personality=prompt_personality,
mood_info=mood_info, # mood_info=mood_info,
bot_name=individuality.name, bot_name=individuality.name,
time_now=time_now, time_now=time_now,
) )

View File

@@ -4,8 +4,7 @@ from src.heart_flow.observation.hfcloop_observation import HFCloopObservation
from src.plugins.models.utils_model import LLMRequest from src.plugins.models.utils_model import LLMRequest
from src.config.config import global_config from src.config.config import global_config
from src.common.logger_manager import get_logger from src.common.logger_manager import get_logger
from src.plugins.utils.prompt_builder import Prompt, global_prompt_manager from src.plugins.utils.prompt_builder import Prompt
from src.plugins.heartFC_chat.hfc_utils import get_keywords_from_json
from datetime import datetime from datetime import datetime
from src.plugins.memory_system.Hippocampus import HippocampusManager from src.plugins.memory_system.Hippocampus import HippocampusManager
from typing import List, Dict from typing import List, Dict
@@ -35,7 +34,7 @@ def init_prompt():
class MemoryActivator: class MemoryActivator:
def __init__(self): def __init__(self):
self.summary_model = LLMRequest( self.summary_model = LLMRequest(
model=global_config.llm_summary, temperature=0.7, max_tokens=300, request_type="chat_observation" model=global_config.llm_summary, temperature=0.7, max_tokens=50, request_type="chat_observation"
) )
self.running_memory = [] self.running_memory = []
@@ -60,24 +59,27 @@ class MemoryActivator:
elif isinstance(observation, HFCloopObservation): elif isinstance(observation, HFCloopObservation):
obs_info_text += observation.get_observe_info() obs_info_text += observation.get_observe_info()
prompt = await global_prompt_manager.format_prompt( # prompt = await global_prompt_manager.format_prompt(
"memory_activator_prompt", # "memory_activator_prompt",
obs_info_text=obs_info_text, # obs_info_text=obs_info_text,
) # )
logger.debug(f"prompt: {prompt}") # logger.debug(f"prompt: {prompt}")
response = await self.summary_model.generate_response(prompt) # response = await self.summary_model.generate_response(prompt)
logger.debug(f"response: {response}") # logger.debug(f"response: {response}")
# 只取response的第一个元素字符串 # # 只取response的第一个元素字符串
response_str = response[0] # response_str = response[0]
keywords = list(get_keywords_from_json(response_str)) # keywords = list(get_keywords_from_json(response_str))
# 调用记忆系统获取相关记忆 # #调用记忆系统获取相关记忆
related_memory = await HippocampusManager.get_instance().get_memory_from_topic( # related_memory = await HippocampusManager.get_instance().get_memory_from_topic(
valid_keywords=keywords, max_memory_num=3, max_memory_length=2, max_depth=3 # valid_keywords=keywords, max_memory_num=3, max_memory_length=2, max_depth=3
# )
related_memory = await HippocampusManager.get_instance().get_memory_from_text(
text=obs_info_text, max_memory_num=3, max_memory_length=2, max_depth=3, fast_retrieval=True
) )
logger.debug(f"获取到的记忆: {related_memory}") logger.debug(f"获取到的记忆: {related_memory}")
@@ -85,7 +87,7 @@ class MemoryActivator:
# 激活时所有已有记忆的duration+1达到3则移除 # 激活时所有已有记忆的duration+1达到3则移除
for m in self.running_memory[:]: for m in self.running_memory[:]:
m["duration"] = m.get("duration", 1) + 1 m["duration"] = m.get("duration", 1) + 1
self.running_memory = [m for m in self.running_memory if m["duration"] < 4] self.running_memory = [m for m in self.running_memory if m["duration"] < 3]
if related_memory: if related_memory:
for topic, memory in related_memory: for topic, memory in related_memory:

View File

@@ -7,6 +7,7 @@ from src.config.config import global_config
# import traceback # import traceback
from typing import List, Dict, Any, Tuple # 确保类型提示被导入 from typing import List, Dict, Any, Tuple # 确保类型提示被导入
import time # 导入 time 模块以获取当前时间 import time # 导入 time 模块以获取当前时间
import random
# 导入新的 repository 函数 # 导入新的 repository 函数
from src.common.message_repository import find_messages, count_messages from src.common.message_repository import find_messages, count_messages
@@ -69,6 +70,23 @@ def get_raw_msg_by_timestamp_with_chat_users(
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode) return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode)
def get_raw_msg_by_timestamp_random(
timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest"
) -> List[Dict[str, Any]]:
"""
先在范围时间戳内随机选择一条消息取得消息的chat_id然后根据chat_id获取该聊天在指定时间戳范围内的消息
"""
# 获取所有消息只取chat_id字段
all_msgs = get_raw_msg_by_timestamp(timestamp_start, timestamp_end)
if not all_msgs:
return []
# 随机选一条
msg = random.choice(all_msgs)
chat_id = msg["chat_id"]
# 用 chat_id 获取该聊天在指定时间戳范围内的消息
return get_raw_msg_by_timestamp_with_chat(chat_id, timestamp_start, timestamp_end, limit, limit_mode)
def get_raw_msg_by_timestamp_with_users( def get_raw_msg_by_timestamp_with_users(
timestamp_start: float, timestamp_end: float, person_ids: list, limit: int = 0, limit_mode: str = "latest" timestamp_start: float, timestamp_end: float, person_ids: list, limit: int = 0, limit_mode: str = "latest"
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]: