feat:拆分HFC组件,为插件做准备

This commit is contained in:
SengokuCola
2025-05-14 14:24:52 +08:00
parent 7ec356c00f
commit e603a00a5f
23 changed files with 1115 additions and 1228 deletions

View File

@@ -1,216 +0,0 @@
import os
import time
from typing import List, Dict, Any, Tuple
from src.chat.focus_chat.heartFC_Cycleinfo import CycleInfo
from src.common.logger_manager import get_logger
logger = get_logger("cycle_analyzer")
class CycleAnalyzer:
"""循环信息分析类提供查询和分析CycleInfo的工具"""
def __init__(self, base_dir: str = "log_debug"):
"""
初始化分析器
参数:
base_dir: 存储CycleInfo的基础目录默认为log_debug
"""
self.base_dir = base_dir
def list_streams(self) -> List[str]:
"""
获取所有聊天流ID列表
返回:
List[str]: 聊天流ID列表
"""
try:
if not os.path.exists(self.base_dir):
return []
return [d for d in os.listdir(self.base_dir) if os.path.isdir(os.path.join(self.base_dir, d))]
except Exception as e:
logger.error(f"获取聊天流列表时出错: {e}")
return []
def get_stream_cycle_count(self, stream_id: str) -> int:
"""
获取指定聊天流的循环数量
参数:
stream_id: 聊天流ID
返回:
int: 循环数量
"""
try:
files = CycleInfo.list_cycles(stream_id, self.base_dir)
return len(files)
except Exception as e:
logger.error(f"获取聊天流循环数量时出错: {e}")
return 0
def get_stream_cycles(self, stream_id: str, start: int = 0, limit: int = -1) -> List[str]:
"""
获取指定聊天流的循环文件列表
参数:
stream_id: 聊天流ID
start: 起始索引默认为0
limit: 返回的最大数量,默认为-1全部
返回:
List[str]: 循环文件路径列表
"""
try:
files = CycleInfo.list_cycles(stream_id, self.base_dir)
if limit < 0:
return files[start:]
else:
return files[start : start + limit]
except Exception as e:
logger.error(f"获取聊天流循环文件列表时出错: {e}")
return []
def get_cycle_content(self, filepath: str) -> str:
"""
获取循环文件的内容
参数:
filepath: 文件路径
返回:
str: 文件内容
"""
try:
if not os.path.exists(filepath):
return f"文件不存在: {filepath}"
with open(filepath, "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
logger.error(f"读取循环文件内容时出错: {e}")
return f"读取文件出错: {e}"
def analyze_stream_cycles(self, stream_id: str) -> Dict[str, Any]:
"""
分析指定聊天流的所有循环,生成统计信息
参数:
stream_id: 聊天流ID
返回:
Dict[str, Any]: 统计信息
"""
try:
files = CycleInfo.list_cycles(stream_id, self.base_dir)
if not files:
return {"error": "没有找到循环记录"}
total_cycles = len(files)
action_counts = {"text_reply": 0, "emoji_reply": 0, "no_reply": 0, "unknown": 0}
total_duration = 0
tool_usage = {}
for filepath in files:
with open(filepath, "r", encoding="utf-8") as f:
content = f.read()
# 解析动作类型
for line in content.split("\n"):
if line.startswith("动作:"):
action = line[3:].strip()
action_counts[action] = action_counts.get(action, 0) + 1
# 解析耗时
elif line.startswith("耗时:"):
try:
duration = float(line[3:].strip().split("")[0])
total_duration += duration
except Exception as e:
logger.error(f"解析耗时时出错: {e}")
pass
# 解析工具使用
elif line.startswith("使用的工具:"):
tools = line[6:].strip().split(", ")
for tool in tools:
tool_usage[tool] = tool_usage.get(tool, 0) + 1
avg_duration = total_duration / total_cycles if total_cycles > 0 else 0
return {
"总循环数": total_cycles,
"动作统计": action_counts,
"平均耗时": f"{avg_duration:.2f}",
"总耗时": f"{total_duration:.2f}",
"工具使用次数": tool_usage,
}
except Exception as e:
logger.error(f"分析聊天流循环时出错: {e}")
return {"error": f"分析出错: {e}"}
def get_latest_cycles(self, count: int = 10) -> List[Tuple[str, str]]:
"""
获取所有聊天流中最新的几个循环
参数:
count: 获取的数量默认为10
返回:
List[Tuple[str, str]]: 聊天流ID和文件路径的元组列表
"""
try:
all_cycles = []
streams = self.list_streams()
for stream_id in streams:
files = CycleInfo.list_cycles(stream_id, self.base_dir)
for filepath in files:
try:
# 从文件名中提取时间戳
filename = os.path.basename(filepath)
timestamp_str = filename.split("_", 2)[2].split(".")[0]
timestamp = time.mktime(time.strptime(timestamp_str, "%Y%m%d_%H%M%S"))
all_cycles.append((timestamp, stream_id, filepath))
except Exception as e:
logger.error(f"从文件名中提取时间戳时出错: {e}")
continue
# 按时间戳排序取最新的count个
all_cycles.sort(reverse=True)
return [(item[1], item[2]) for item in all_cycles[:count]]
except Exception as e:
logger.error(f"获取最新循环时出错: {e}")
return []
# 使用示例
if __name__ == "__main__":
analyzer = CycleAnalyzer()
# 列出所有聊天流
streams = analyzer.list_streams()
print(f"找到 {len(streams)} 个聊天流: {streams}")
# 分析第一个聊天流的循环
if streams:
stream_id = streams[0]
stats = analyzer.analyze_stream_cycles(stream_id)
print(f"\n聊天流 {stream_id} 的统计信息:")
for key, value in stats.items():
print(f" {key}: {value}")
# 获取最新的循环
cycles = analyzer.get_stream_cycles(stream_id, limit=1)
if cycles:
print("\n最新循环内容:")
print(analyzer.get_cycle_content(cycles[0]))
# 获取所有聊天流中最新的3个循环
latest_cycles = analyzer.get_latest_cycles(3)
print(f"\n所有聊天流中最新的 {len(latest_cycles)} 个循环:")
for stream_id, filepath in latest_cycles:
print(f" 聊天流 {stream_id}: {os.path.basename(filepath)}")

View File

@@ -4,13 +4,13 @@ from typing import List, Dict, Optional, Any, Tuple
from src.common.logger_manager import get_logger from src.common.logger_manager import get_logger
from src.chat.models.utils_model import LLMRequest from src.chat.models.utils_model import LLMRequest
from src.config.config import global_config from src.config.config import global_config
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_readable_messages, build_anonymous_messages from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_random, build_anonymous_messages
from src.chat.focus_chat.heartflow_prompt_builder import Prompt, global_prompt_manager from src.chat.focus_chat.heartflow_prompt_builder import Prompt, global_prompt_manager
import os import os
import json import json
MAX_EXPRESSION_COUNT = 300 MAX_EXPRESSION_COUNT = 100
logger = get_logger("expressor") logger = get_logger("expressor")
@@ -19,7 +19,7 @@ def init_prompt() -> None:
learn_style_prompt = """ learn_style_prompt = """
{chat_str} {chat_str}
请从上面这段群聊中概括除了人名为"麦麦"之外的人的语言风格,只考虑文字,不要考虑表情包和图片 请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格,只考虑文字,不要考虑表情包和图片
不要涉及具体的人名,只考虑语言风格 不要涉及具体的人名,只考虑语言风格
语言风格包含特殊内容和情感 语言风格包含特殊内容和情感
思考有没有特殊的梗,一并总结成语言风格 思考有没有特殊的梗,一并总结成语言风格
@@ -57,7 +57,7 @@ def init_prompt() -> None:
learn_grammar_prompt = """ learn_grammar_prompt = """
{chat_str} {chat_str}
请从上面这段群聊中概括除了人名为"麦麦"之外的人的语法和句法特点,只考虑纯文字,不要考虑表情包和图片 请从上面这段群聊中概括除了人名为"SELF"之外的人的语法和句法特点,只考虑纯文字,不要考虑表情包和图片
不要总结【图片】,【动画表情】,[图片][动画表情],不总结 表情符号 at @ 回复 和[回复] 不要总结【图片】,【动画表情】,[图片][动画表情],不总结 表情符号 at @ 回复 和[回复]
不要涉及具体的人名,只考虑语法和句法特点, 不要涉及具体的人名,只考虑语法和句法特点,
语法和句法特点要包括,句子长短(具体字数),有何种语病,如何拆分句子。 语法和句法特点要包括,句子长短(具体字数),有何种语病,如何拆分句子。
@@ -65,9 +65,9 @@ def init_prompt() -> None:
"xxx"时,可以"xxx" "xxx"时,可以"xxx"
例如: 例如:
"表达观点较复杂"时,使用"省略主语"的句法 "表达观点较复杂"时,使用"省略主语(3-6个字)"的句法
"不用详细说明的一般表达"时,使用"非常简洁的句子"的句法 "不用详细说明的一般表达"时,使用"非常简洁的句子"的句法
"需要单纯简单的确认"时,使用"单字或几个字的肯定"的句法 "需要单纯简单的确认"时,使用"单字或几个字的肯定(1-2个字)"的句法
注意不要总结你自己的发言 注意不要总结你自己的发言
现在请你概括 现在请你概括
@@ -122,11 +122,11 @@ class ExpressionLearner:
""" """
学习并存储表达方式,分别学习语言风格和句法特点 学习并存储表达方式,分别学习语言风格和句法特点
""" """
learnt_style: Optional[List[Tuple[str, str, str]]] = await self.learn_and_store(type="style", num=3) learnt_style: Optional[List[Tuple[str, str, str]]] = await self.learn_and_store(type="style", num=15)
if not learnt_style: if not learnt_style:
return [] return []
learnt_grammar: Optional[List[Tuple[str, str, str]]] = await self.learn_and_store(type="grammar", num=2) learnt_grammar: Optional[List[Tuple[str, str, str]]] = await self.learn_and_store(type="grammar", num=15)
if not learnt_grammar: if not learnt_grammar:
return [] return []
@@ -233,7 +233,7 @@ class ExpressionLearner:
chat_str=random_msg_str, chat_str=random_msg_str,
) )
logger.info(f"学习{type_str}的prompt: {prompt}") # logger.info(f"学习{type_str}的prompt: {prompt}")
try: try:
response, _ = await self.express_learn_model.generate_response_async(prompt) response, _ = await self.express_learn_model.generate_response_async(prompt)
@@ -291,7 +291,7 @@ class ExpressionLearner:
"personality_expression_prompt", "personality_expression_prompt",
personality=global_config.expression_style, personality=global_config.expression_style,
) )
logger.info(f"个性表达方式提取prompt: {prompt}") # logger.info(f"个性表达方式提取prompt: {prompt}")
try: try:
response, _ = await self.express_learn_model.generate_response_async(prompt) response, _ = await self.express_learn_model.generate_response_async(prompt)

View File

@@ -1,6 +1,5 @@
import time import time
import os import os
import json
from typing import List, Optional, Dict, Any from typing import List, Optional, Dict, Any
@@ -9,45 +8,16 @@ class CycleDetail:
def __init__(self, cycle_id: int): def __init__(self, cycle_id: int):
self.cycle_id = cycle_id self.cycle_id = cycle_id
self.thinking_id = ""
self.start_time = time.time() self.start_time = time.time()
self.end_time: Optional[float] = None self.end_time: Optional[float] = None
self.action_taken = False
self.action_type = "unknown"
self.reasoning = ""
self.timers: Dict[str, float] = {} self.timers: Dict[str, float] = {}
self.thinking_id = ""
self.replanned = False
# 添加响应信息相关字段 # 字段
self.response_info: Dict[str, Any] = { self.loop_observation_info: Dict[str, Any] = {}
"response_text": [], # 回复的文本列表 self.loop_process_info: Dict[str, Any] = {}
"emoji_info": "", # 表情信息 self.loop_plan_info: Dict[str, Any] = {}
"anchor_message_id": "", # 锚点消息ID self.loop_action_info: Dict[str, Any] = {}
"reply_message_ids": [], # 回复消息ID列表
"sub_mind_thinking": "", # 子思维思考内容
"in_mind_reply": [], # 子思维思考内容
}
# 添加SubMind相关信息
self.submind_info: Dict[str, Any] = {
"prompt": "", # SubMind输入的prompt
"structured_info": "", # 结构化信息
"result": "", # SubMind的思考结果
}
# 添加ToolUse相关信息
self.tooluse_info: Dict[str, Any] = {
"prompt": "", # 工具使用的prompt
"tools_used": [], # 使用了哪些工具
"tool_results": [], # 工具获得的信息
}
# 添加Planner相关信息
self.planner_info: Dict[str, Any] = {
"prompt": "", # 规划器的prompt
"response": "", # 规划器的原始回复
"parsed_result": {}, # 解析后的结果
}
def to_dict(self) -> Dict[str, Any]: def to_dict(self) -> Dict[str, Any]:
"""将循环信息转换为字典格式""" """将循环信息转换为字典格式"""
@@ -55,229 +25,28 @@ class CycleDetail:
"cycle_id": self.cycle_id, "cycle_id": self.cycle_id,
"start_time": self.start_time, "start_time": self.start_time,
"end_time": self.end_time, "end_time": self.end_time,
"action_taken": self.action_taken,
"action_type": self.action_type,
"reasoning": self.reasoning,
"timers": self.timers, "timers": self.timers,
"thinking_id": self.thinking_id, "thinking_id": self.thinking_id,
"response_info": self.response_info, "loop_observation_info": self.loop_observation_info,
"submind_info": self.submind_info, "loop_process_info": self.loop_process_info,
"tooluse_info": self.tooluse_info, "loop_plan_info": self.loop_plan_info,
"planner_info": self.planner_info, "loop_action_info": self.loop_action_info,
} }
def complete_cycle(self): def complete_cycle(self):
"""完成循环,记录结束时间""" """完成循环,记录结束时间"""
self.end_time = time.time() self.end_time = time.time()
def set_action_info(
self, action_type: str, reasoning: str, action_taken: bool, action_data: Optional[Dict[str, Any]] = None
):
"""设置动作信息"""
self.action_type = action_type
self.action_data = action_data
self.reasoning = reasoning
self.action_taken = action_taken
def set_thinking_id(self, thinking_id: str): def set_thinking_id(self, thinking_id: str):
"""设置思考消息ID""" """设置思考消息ID"""
self.thinking_id = thinking_id self.thinking_id = thinking_id
def set_response_info( def set_loop_info(self, loop_info: Dict[str, Any]):
self, """设置循环信息"""
response_text: Optional[List[str]] = None, self.loop_observation_info = loop_info["loop_observation_info"]
emoji_info: Optional[str] = None, self.loop_processor_info = loop_info["loop_processor_info"]
anchor_message_id: Optional[str] = None, self.loop_plan_info = loop_info["loop_plan_info"]
reply_message_ids: Optional[List[str]] = None, self.loop_action_info = loop_info["loop_action_info"]
sub_mind_thinking: Optional[str] = None,
):
"""设置响应信息"""
if response_text is not None:
self.response_info["response_text"] = response_text
if emoji_info is not None:
self.response_info["emoji_info"] = emoji_info
if anchor_message_id is not None:
self.response_info["anchor_message_id"] = anchor_message_id
if reply_message_ids is not None:
self.response_info["reply_message_ids"] = reply_message_ids
if sub_mind_thinking is not None:
self.response_info["sub_mind_thinking"] = sub_mind_thinking
def set_submind_info(
self,
prompt: Optional[str] = None,
structured_info: Optional[str] = None,
result: Optional[str] = None,
):
"""设置SubMind信息"""
if prompt is not None:
self.submind_info["prompt"] = prompt
if structured_info is not None:
self.submind_info["structured_info"] = structured_info
if result is not None:
self.submind_info["result"] = result
def set_tooluse_info(
self,
prompt: Optional[str] = None,
tools_used: Optional[List[str]] = None,
tool_results: Optional[List[Dict[str, Any]]] = None,
):
"""设置ToolUse信息"""
if prompt is not None:
self.tooluse_info["prompt"] = prompt
if tools_used is not None:
self.tooluse_info["tools_used"] = tools_used
if tool_results is not None:
self.tooluse_info["tool_results"] = tool_results
def set_planner_info(
self,
prompt: Optional[str] = None,
response: Optional[str] = None,
parsed_result: Optional[Dict[str, Any]] = None,
):
"""设置Planner信息"""
if prompt is not None:
self.planner_info["prompt"] = prompt
if response is not None:
self.planner_info["response"] = response
if parsed_result is not None:
self.planner_info["parsed_result"] = parsed_result
@staticmethod
def save_to_file(cycle_info: "CycleDetail", stream_id: str, base_dir: str = "log_debug") -> str:
"""
将CycleInfo保存到文件
参数:
cycle_info: CycleInfo对象
stream_id: 聊天流ID
base_dir: 基础目录默认为log_debug
返回:
str: 保存的文件路径
"""
try:
# 创建目录结构
stream_dir = os.path.join(base_dir, stream_id)
os.makedirs(stream_dir, exist_ok=True)
# 生成文件名和路径
timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime(cycle_info.start_time))
filename = f"cycle_{cycle_info.cycle_id}_{timestamp}.txt"
filepath = os.path.join(stream_dir, filename)
# 格式化输出成易读的格式
with open(filepath, "w", encoding="utf-8") as f:
# 写入基本信息
f.write(f"循环ID: {cycle_info.cycle_id}\n")
f.write(f"开始时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(cycle_info.start_time))}\n")
if cycle_info.end_time:
f.write(f"结束时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(cycle_info.end_time))}\n")
duration = cycle_info.end_time - cycle_info.start_time
f.write(f"耗时: {duration:.2f}\n")
f.write(f"动作: {cycle_info.action_type}\n")
f.write(f"原因: {cycle_info.reasoning}\n")
f.write(f"执行状态: {'已执行' if cycle_info.action_taken else '未执行'}\n")
f.write(f"思考ID: {cycle_info.thinking_id}\n")
f.write(f"是否为重新规划: {'' if cycle_info.replanned else ''}\n\n")
# 写入计时器信息
if cycle_info.timers:
f.write("== 计时器信息 ==\n")
for name, elapsed in cycle_info.timers.items():
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}"
f.write(f"{name}: {formatted_time}\n")
f.write("\n")
# 写入响应信息
f.write("== 响应信息 ==\n")
f.write(f"锚点消息ID: {cycle_info.response_info['anchor_message_id']}\n")
if cycle_info.response_info["response_text"]:
f.write("回复文本:\n")
for i, text in enumerate(cycle_info.response_info["response_text"]):
f.write(f" [{i + 1}] {text}\n")
if cycle_info.response_info["emoji_info"]:
f.write(f"表情信息: {cycle_info.response_info['emoji_info']}\n")
if cycle_info.response_info["reply_message_ids"]:
f.write(f"回复消息ID: {', '.join(cycle_info.response_info['reply_message_ids'])}\n")
f.write("\n")
# 写入SubMind信息
f.write("== SubMind信息 ==\n")
f.write(f"结构化信息:\n{cycle_info.submind_info['structured_info']}\n\n")
f.write(f"思考结果:\n{cycle_info.submind_info['result']}\n\n")
f.write("SubMind Prompt:\n")
f.write(f"{cycle_info.submind_info['prompt']}\n\n")
# 写入ToolUse信息
f.write("== 工具使用信息 ==\n")
if cycle_info.tooluse_info["tools_used"]:
f.write(f"使用的工具: {', '.join(cycle_info.tooluse_info['tools_used'])}\n")
else:
f.write("未使用工具\n")
if cycle_info.tooluse_info["tool_results"]:
f.write("工具结果:\n")
for i, result in enumerate(cycle_info.tooluse_info["tool_results"]):
f.write(f" [{i + 1}] 类型: {result.get('type', '未知')}, 内容: {result.get('content', '')}\n")
f.write("\n")
f.write("工具执行 Prompt:\n")
f.write(f"{cycle_info.tooluse_info['prompt']}\n\n")
# 写入Planner信息
f.write("== Planner信息 ==\n")
f.write("Planner Prompt:\n")
f.write(f"{cycle_info.planner_info['prompt']}\n\n")
f.write("原始回复:\n")
f.write(f"{cycle_info.planner_info['response']}\n\n")
f.write("解析结果:\n")
f.write(f"{json.dumps(cycle_info.planner_info['parsed_result'], ensure_ascii=False, indent=2)}\n")
return filepath
except Exception as e:
print(f"保存CycleInfo到文件时出错: {e}")
return ""
@staticmethod
def load_from_file(filepath: str) -> Optional[Dict[str, Any]]:
"""
从文件加载CycleInfo信息只加载JSON格式的数据不解析文本格式
参数:
filepath: 文件路径
返回:
Optional[Dict[str, Any]]: 加载的CycleInfo数据失败则返回None
"""
try:
if not os.path.exists(filepath):
print(f"文件不存在: {filepath}")
return None
# 尝试从文件末尾读取JSON数据
with open(filepath, "r", encoding="utf-8") as f:
lines = f.readlines()
# 查找"解析结果:"后的JSON数据
for i, line in enumerate(lines):
if "解析结果:" in line and i + 1 < len(lines):
# 尝试解析后面的行
json_data = ""
for j in range(i + 1, len(lines)):
json_data += lines[j]
try:
return json.loads(json_data)
except json.JSONDecodeError:
continue
# 如果没有找到JSON数据则返回None
return None
except Exception as e:
print(f"从文件加载CycleInfo时出错: {e}")
return None
@staticmethod @staticmethod
def list_cycles(stream_id: str, base_dir: str = "log_debug") -> List[str]: def list_cycles(stream_id: str, base_dir: str = "log_debug") -> List[str]:

View File

@@ -1,7 +1,5 @@
import asyncio import asyncio
import contextlib import contextlib
import json # <--- 确保导入 json
import random # <--- 添加导入
import time import time
import traceback import traceback
from collections import deque from collections import deque
@@ -10,19 +8,10 @@ from src.chat.message_receive.chat_stream import ChatStream
from src.chat.message_receive.chat_stream import chat_manager from src.chat.message_receive.chat_stream import chat_manager
from rich.traceback import install from rich.traceback import install
from src.common.logger_manager import get_logger from src.common.logger_manager import get_logger
from src.chat.models.utils_model import LLMRequest
from src.config.config import global_config
from src.chat.utils.timer_calculator import Timer from src.chat.utils.timer_calculator import Timer
from src.chat.heart_flow.observation.observation import Observation from src.chat.heart_flow.observation.observation import Observation
from src.chat.focus_chat.heartflow_prompt_builder import prompt_builder
from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
from src.chat.focus_chat.info.info_base import InfoBase from src.chat.focus_chat.info.info_base import InfoBase
from src.chat.focus_chat.info.obs_info import ObsInfo
from src.chat.focus_chat.info.cycle_info import CycleInfo
from src.chat.focus_chat.info.mind_info import MindInfo
from src.chat.focus_chat.info.structured_info import StructuredInfo
from src.chat.focus_chat.info_processors.chattinginfo_processor import ChattingInfoProcessor from src.chat.focus_chat.info_processors.chattinginfo_processor import ChattingInfoProcessor
from src.chat.focus_chat.info_processors.mind_processor import MindProcessor from src.chat.focus_chat.info_processors.mind_processor import MindProcessor
from src.chat.heart_flow.observation.memory_observation import MemoryObservation from src.chat.heart_flow.observation.memory_observation import MemoryObservation
@@ -30,8 +19,10 @@ from src.chat.heart_flow.observation.hfcloop_observation import HFCloopObservati
from src.chat.heart_flow.observation.working_observation import WorkingObservation from src.chat.heart_flow.observation.working_observation import WorkingObservation
from src.chat.focus_chat.info_processors.tool_processor import ToolProcessor from src.chat.focus_chat.info_processors.tool_processor import ToolProcessor
from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor
from src.chat.focus_chat.hfc_utils import create_empty_anchor_message, parse_thinking_id_to_timestamp
from src.chat.focus_chat.memory_activator import MemoryActivator from src.chat.focus_chat.memory_activator import MemoryActivator
from src.chat.focus_chat.info_processors.base_processor import BaseProcessor
from src.chat.focus_chat.planners.action_factory import ActionFactory
from src.chat.focus_chat.planners.planner import ActionPlanner
install(extra_lines=3) install(extra_lines=3)
@@ -45,78 +36,6 @@ CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
logger = get_logger("hfc") # Logger Name Changed logger = get_logger("hfc") # Logger Name Changed
# 默认动作定义
DEFAULT_ACTIONS = {"no_reply": "不操作,继续浏览", "reply": "表达想法,可以只包含文本、表情或两者都有"}
class ActionManager:
"""动作管理器:控制每次决策可以使用的动作"""
def __init__(self):
# 初始化为新的默认动作集
self._available_actions: Dict[str, str] = DEFAULT_ACTIONS.copy()
self._original_actions_backup: Optional[Dict[str, str]] = None
def get_available_actions(self) -> Dict[str, str]:
"""获取当前可用的动作集"""
return self._available_actions.copy() # 返回副本以防外部修改
def add_action(self, action_name: str, description: str) -> bool:
"""
添加新的动作
参数:
action_name: 动作名称
description: 动作描述
返回:
bool: 是否添加成功
"""
if action_name in self._available_actions:
return False
self._available_actions[action_name] = description
return True
def remove_action(self, action_name: str) -> bool:
"""
移除指定动作
参数:
action_name: 动作名称
返回:
bool: 是否移除成功
"""
if action_name not in self._available_actions:
return False
del self._available_actions[action_name]
return True
def temporarily_remove_actions(self, actions_to_remove: List[str]):
"""
临时移除指定的动作,备份原始动作集。
如果已经有备份,则不重复备份。
"""
if self._original_actions_backup is None:
self._original_actions_backup = self._available_actions.copy()
actions_actually_removed = []
for action_name in actions_to_remove:
if action_name in self._available_actions:
del self._available_actions[action_name]
actions_actually_removed.append(action_name)
# logger.debug(f"临时移除了动作: {actions_actually_removed}") # 可选日志
def restore_actions(self):
"""
恢复之前备份的原始动作集。
"""
if self._original_actions_backup is not None:
self._available_actions = self._original_actions_backup.copy()
self._original_actions_backup = None
# logger.debug("恢复了原始动作集") # 可选日志
async def _handle_cycle_delay(action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str): async def _handle_cycle_delay(action_taken_this_cycle: bool, cycle_start_time: float, log_prefix: str):
"""处理循环延迟""" """处理循环延迟"""
cycle_duration = time.monotonic() - cycle_start_time cycle_duration = time.monotonic() - cycle_start_time
@@ -162,39 +81,23 @@ class HeartFChatting:
self.chat_stream: Optional[ChatStream] = None # 关联的聊天流 self.chat_stream: Optional[ChatStream] = None # 关联的聊天流
self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态 self.observations: List[Observation] = observations # 关联的观察列表,用于监控聊天流状态
self.on_consecutive_no_reply_callback = on_consecutive_no_reply_callback self.on_consecutive_no_reply_callback = on_consecutive_no_reply_callback
self.log_prefix: str = str(chat_id) # Initial default, will be updated
self.chatting_info_processor = ChattingInfoProcessor()
self.mind_processor = MindProcessor(subheartflow_id=self.stream_id)
self.memory_observation = MemoryObservation(observe_id=self.stream_id) self.memory_observation = MemoryObservation(observe_id=self.stream_id)
self.hfcloop_observation = HFCloopObservation(observe_id=self.stream_id) self.hfcloop_observation = HFCloopObservation(observe_id=self.stream_id)
self.tool_processor = ToolProcessor(subheartflow_id=self.stream_id)
self.working_observation = WorkingObservation(observe_id=self.stream_id) self.working_observation = WorkingObservation(observe_id=self.stream_id)
self.memory_activator = MemoryActivator() self.memory_activator = MemoryActivator()
# 日志前缀
self.log_prefix: str = str(chat_id) # Initial default, will be updated
# --- Initialize attributes (defaults) ---
self.is_group_chat: bool = False
self.chat_target_info: Optional[dict] = None
# --- End Initialization ---
self.expressor = DefaultExpressor(chat_id=self.stream_id) self.expressor = DefaultExpressor(chat_id=self.stream_id)
self.action_planner = ActionPlanner(log_prefix=self.log_prefix)
# 动作管理器 # --- 处理器列表 ---
self.action_manager = ActionManager() self.processors: List[BaseProcessor] = []
self._register_default_processors()
# 初始化状态控制 # 初始化状态控制
self._initialized = False self._initialized = False
self._processing_lock = asyncio.Lock() self._processing_lock = asyncio.Lock()
# LLM规划器配置
self.planner_llm = LLMRequest(
model=global_config.llm_plan,
max_tokens=1000,
request_type="action_planning", # 用于动作规划
)
# 循环控制内部状态 # 循环控制内部状态
self._loop_active: bool = False # 循环是否正在运行 self._loop_active: bool = False # 循环是否正在运行
self._loop_task: Optional[asyncio.Task] = None # 主循环任务 self._loop_task: Optional[asyncio.Task] = None # 主循环任务
@@ -203,9 +106,9 @@ class HeartFChatting:
self._cycle_counter = 0 self._cycle_counter = 0
self._cycle_history: Deque[CycleDetail] = deque(maxlen=10) # 保留最近10个循环的信息 self._cycle_history: Deque[CycleDetail] = deque(maxlen=10) # 保留最近10个循环的信息
self._current_cycle: Optional[CycleDetail] = None self._current_cycle: Optional[CycleDetail] = None
self.total_no_reply_count: int = 0 # <--- 新增:连续不回复计数器 self.total_no_reply_count: int = 0 # 连续不回复计数器
self._shutting_down: bool = False # <--- 新增:关闭标志位 self._shutting_down: bool = False # 关闭标志位
self.total_waiting_time: float = 0.0 # <--- 新增:累计等待时间 self.total_waiting_time: float = 0.0 # 累计等待时间
async def _initialize(self) -> bool: async def _initialize(self) -> bool:
""" """
@@ -228,7 +131,6 @@ class HeartFChatting:
return True return True
try: try:
self.is_group_chat, self.chat_target_info = await get_chat_type_and_target_info(self.stream_id)
await self.expressor.initialize() await self.expressor.initialize()
self.chat_stream = await asyncio.to_thread(chat_manager.get_stream, self.stream_id) self.chat_stream = await asyncio.to_thread(chat_manager.get_stream, self.stream_id)
self.expressor.chat_stream = self.chat_stream self.expressor.chat_stream = self.chat_stream
@@ -242,6 +144,13 @@ class HeartFChatting:
logger.debug(f"{self.log_prefix} 初始化完成,准备开始处理消息") logger.debug(f"{self.log_prefix} 初始化完成,准备开始处理消息")
return True return True
def _register_default_processors(self):
"""注册默认的信息处理器"""
self.processors.append(ChattingInfoProcessor())
self.processors.append(MindProcessor(subheartflow_id=self.stream_id))
self.processors.append(ToolProcessor(subheartflow_id=self.stream_id))
logger.info(f"{self.log_prefix} 已注册默认处理器: {[p.__class__.__name__ for p in self.processors]}")
async def start(self): async def start(self):
""" """
启动 HeartFChatting 的主循环。 启动 HeartFChatting 的主循环。
@@ -270,10 +179,7 @@ class HeartFChatting:
pass # 忽略取消或超时错误 pass # 忽略取消或超时错误
self._loop_task = None # 清理旧任务引用 self._loop_task = None # 清理旧任务引用
logger.debug(f"{self.log_prefix} 启动认真水群(HFC)主循环...") self._loop_task = asyncio.create_task(self._run_focus_chat())
# 创建新的循环任务
self._loop_task = asyncio.create_task(self._hfc_loop())
# 添加完成回调
self._loop_task.add_done_callback(self._handle_loop_completion) self._loop_task.add_done_callback(self._handle_loop_completion)
def _handle_loop_completion(self, task: asyncio.Task): def _handle_loop_completion(self, task: asyncio.Task):
@@ -284,7 +190,6 @@ class HeartFChatting:
logger.error(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(异常): {exception}") logger.error(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(异常): {exception}")
logger.error(traceback.format_exc()) # Log full traceback for exceptions logger.error(traceback.format_exc()) # Log full traceback for exceptions
else: else:
# Loop completing normally now means it was cancelled/shutdown externally
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天 (外部停止)") logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天 (外部停止)")
except asyncio.CancelledError: except asyncio.CancelledError:
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(任务取消)") logger.info(f"{self.log_prefix} HeartFChatting: 麦麦脱离了聊天(任务取消)")
@@ -295,16 +200,14 @@ class HeartFChatting:
logger.warning(f"{self.log_prefix} HeartFChatting: 处理锁在循环结束时仍被锁定,强制释放。") logger.warning(f"{self.log_prefix} HeartFChatting: 处理锁在循环结束时仍被锁定,强制释放。")
self._processing_lock.release() self._processing_lock.release()
async def _hfc_loop(self): async def _run_focus_chat(self):
"""主循环,持续进行计划并可能回复消息,直到被外部取消。""" """主循环,持续进行计划并可能回复消息,直到被外部取消。"""
try: try:
while True: # 主循环 while True: # 主循环
logger.debug(f"{self.log_prefix} 开始第{self._cycle_counter}次循环") logger.debug(f"{self.log_prefix} 开始第{self._cycle_counter}次循环")
# --- 在循环开始处检查关闭标志 ---
if self._shutting_down: if self._shutting_down:
logger.info(f"{self.log_prefix} 检测到关闭标志,退出 HFC 循环。") logger.info(f"{self.log_prefix} 检测到关闭标志,退出 Focus Chat 循环。")
break break
# --------------------------------
# 创建新的循环信息 # 创建新的循环信息
self._cycle_counter += 1 self._cycle_counter += 1
@@ -315,63 +218,49 @@ class HeartFChatting:
loop_cycle_start_time = time.monotonic() loop_cycle_start_time = time.monotonic()
# 执行规划和处理阶段 # 执行规划和处理阶段
async with self._get_cycle_context() as acquired_lock: async with self._get_cycle_context():
if not acquired_lock:
# 如果未能获取锁(理论上不太可能,除非 shutdown 过程中释放了但又被抢了?)
# 或者也可以在这里再次检查 self._shutting_down
if self._shutting_down:
break # 再次检查,确保退出
logger.warning(f"{self.log_prefix} 未能获取循环处理锁,跳过本次循环。")
await asyncio.sleep(0.1) # 短暂等待避免空转
continue
# thinking_id 是思考过程的ID用于标记每一轮思考
thinking_id = "tid" + str(round(time.time(), 2)) thinking_id = "tid" + str(round(time.time(), 2))
self._current_cycle.set_thinking_id(thinking_id)
# 主循环:思考->决策->执行 # 主循环:思考->决策->执行
action_taken = await self._think_plan_execute_loop(cycle_timers, thinking_id) loop_info = await self._observe_process_plan_action_loop(cycle_timers, thinking_id)
# 更新循环信息 self._current_cycle.set_loop_info(loop_info)
self._current_cycle.set_thinking_id(thinking_id)
self.hfcloop_observation.add_loop_info(self._current_cycle)
self._current_cycle.timers = cycle_timers self._current_cycle.timers = cycle_timers
# 防止循环过快消耗资源 # 防止循环过快消耗资源
await _handle_cycle_delay(action_taken, loop_cycle_start_time, self.log_prefix) await _handle_cycle_delay(
loop_info["loop_action_info"]["action_taken"], loop_cycle_start_time, self.log_prefix
)
# 完成当前循环并保存历史 # 完成当前循环并保存历史
self._current_cycle.complete_cycle() self._current_cycle.complete_cycle()
self._cycle_history.append(self._current_cycle) self._cycle_history.append(self._current_cycle)
# 保存CycleInfo到文件
try:
filepath = CycleDetail.save_to_file(self._current_cycle, self.stream_id)
logger.info(f"{self.log_prefix} 已保存循环信息到文件: {filepath}")
except Exception as e:
logger.error(f"{self.log_prefix} 保存循环信息到文件时出错: {e}")
# 记录循环信息和计时器结果 # 记录循环信息和计时器结果
timer_strings = [] timer_strings = []
for name, elapsed in cycle_timers.items(): for name, elapsed in cycle_timers.items():
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}" formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}"
timer_strings.append(f"{name}: {formatted_time}") timer_strings.append(f"{name}: {formatted_time}")
logger.debug( logger.info(
f"{self.log_prefix} 第 #{self._current_cycle.cycle_id}次思考完成," f"{self.log_prefix} {self._current_cycle.cycle_id}次思考,"
f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, " f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.1f}秒, "
f"动作: {self._current_cycle.action_type}" f"动作: {self._current_cycle.loop_plan_info['action_result']['action_type']}"
+ (f"\n计时器详情: {'; '.join(timer_strings)}" if timer_strings else "") + (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
) )
except asyncio.CancelledError: except asyncio.CancelledError:
# 设置了关闭标志位后被取消是正常流程 # 设置了关闭标志位后被取消是正常流程
if not self._shutting_down: if not self._shutting_down:
logger.warning(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)循环意外被取消") logger.warning(f"{self.log_prefix} 麦麦Focus聊天模式意外被取消")
else: else:
logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的认真水群(HFC)循环已取消 (正常关闭)") logger.info(f"{self.log_prefix} 麦麦已离开Focus聊天模式")
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} HeartFChatting: 意外错误: {e}") logger.error(f"{self.log_prefix} 麦麦Focus聊天模式意外错误: {e}")
logger.error(traceback.format_exc()) print(traceback.format_exc())
@contextlib.asynccontextmanager @contextlib.asynccontextmanager
async def _get_cycle_context(self): async def _get_cycle_context(self):
@@ -392,7 +281,70 @@ class HeartFChatting:
if acquired and self._processing_lock.locked(): if acquired and self._processing_lock.locked():
self._processing_lock.release() self._processing_lock.release()
async def _think_plan_execute_loop(self, cycle_timers: dict, thinking_id: str) -> tuple[bool, str]: async def _process_processors(
self, observations: List[Observation], running_memorys: List[Dict[str, Any]], cycle_timers: dict
) -> List[InfoBase]:
# 记录并行任务开始时间
parallel_start_time = time.time()
logger.debug(f"{self.log_prefix} 开始信息处理器并行任务")
processor_tasks = []
task_to_name_map = {}
for processor in self.processors:
processor_name = processor.__class__.log_prefix
task = asyncio.create_task(
processor.process_info(observations=observations, running_memorys=running_memorys)
)
processor_tasks.append(task)
task_to_name_map[task] = processor_name
logger.debug(f"{self.log_prefix} 启动处理器任务: {processor_name}")
pending_tasks = set(processor_tasks)
all_plan_info: List[InfoBase] = []
while pending_tasks:
done, pending_tasks = await asyncio.wait(pending_tasks, return_when=asyncio.FIRST_COMPLETED)
for task in done:
processor_name = task_to_name_map[task]
task_completed_time = time.time()
duration_since_parallel_start = task_completed_time - parallel_start_time
try:
# 使用 await task 来获取结果或触发异常
result_list = await task
logger.info(
f"{self.log_prefix} 处理器 {processor_name} 已完成,信息已处理: {duration_since_parallel_start:.2f}"
)
if result_list is not None:
all_plan_info.extend(result_list)
else:
logger.warning(f"{self.log_prefix} 处理器 {processor_name} 返回了 None")
except Exception as e:
logger.error(
f"{self.log_prefix} 处理器 {processor_name} 执行失败,耗时 (自并行开始): {duration_since_parallel_start:.2f}秒. 错误: {e}",
exc_info=True,
)
# 即使出错,也认为该任务结束了,已从 pending_tasks 中移除
if pending_tasks:
current_progress_time = time.time()
elapsed_for_log = current_progress_time - parallel_start_time
pending_names_for_log = [task_to_name_map[t] for t in pending_tasks]
logger.info(
f"{self.log_prefix} 信息处理已进行 {elapsed_for_log:.2f}秒,待完成任务: {', '.join(pending_names_for_log)}"
)
# 所有任务完成后的最终日志
parallel_end_time = time.time()
total_duration = parallel_end_time - parallel_start_time
logger.info(f"{self.log_prefix} 所有处理器任务全部完成,总耗时: {total_duration:.2f}")
logger.debug(f"{self.log_prefix} 所有信息处理器处理后的信息: {all_plan_info}")
return all_plan_info
async def _observe_process_plan_action_loop(self, cycle_timers: dict, thinking_id: str) -> tuple[bool, str]:
try: try:
with Timer("观察", cycle_timers): with Timer("观察", cycle_timers):
await self.observations[0].observe() await self.observations[0].observe()
@@ -405,122 +357,69 @@ class HeartFChatting:
observations.append(self.working_observation) observations.append(self.working_observation)
observations.append(self.hfcloop_observation) observations.append(self.hfcloop_observation)
for observation in observations: loop_observation_info = {
logger.debug(f"{self.log_prefix} 观察信息: {observation}") "observations": observations,
}
with Timer("回忆", cycle_timers): with Timer("回忆", cycle_timers):
running_memorys = await self.memory_activator.activate_memory(observations) running_memorys = await self.memory_activator.activate_memory(observations)
# 记录并行任务开始时间
parallel_start_time = time.time()
logger.debug(f"{self.log_prefix} 开始信息处理器并行任务")
# 并行执行两个任务:思考和工具执行
with Timer("执行 信息处理器", cycle_timers): with Timer("执行 信息处理器", cycle_timers):
# 1. 子思维思考 - 不执行工具调用 all_plan_info = await self._process_processors(observations, running_memorys, cycle_timers)
think_task = asyncio.create_task(
self.mind_processor.process_info(observations=observations, running_memorys=running_memorys)
)
logger.debug(f"{self.log_prefix} 启动子思维思考任务")
# 2. 工具执行器 - 专门处理工具调用 loop_processor_info = {
tool_task = asyncio.create_task( "all_plan_info": all_plan_info,
self.tool_processor.process_info(observations=observations, running_memorys=running_memorys) }
)
logger.debug(f"{self.log_prefix} 启动工具执行任务")
# 3. 聊天信息处理器
chatting_info_task = asyncio.create_task(
self.chatting_info_processor.process_info(
observations=observations, running_memorys=running_memorys
)
)
logger.debug(f"{self.log_prefix} 启动聊天信息处理器任务")
# 创建任务完成状态追踪
tasks = {"思考任务": think_task, "工具任务": tool_task, "聊天信息处理任务": chatting_info_task}
pending = set(tasks.values())
# 等待所有任务完成,同时追踪每个任务的完成情况
results: dict[str, list[InfoBase]] = {}
while pending:
# 等待任务完成
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED, timeout=1.0)
# 记录完成的任务
for task in done:
for name, t in tasks.items():
if task == t:
task_end_time = time.time()
task_duration = task_end_time - parallel_start_time
logger.info(f"{self.log_prefix} {name}已完成,耗时: {task_duration:.2f}")
results[name] = task.result()
break
# 如果仍有未完成任务,记录进行中状态
if pending:
current_time = time.time()
elapsed = current_time - parallel_start_time
pending_names = [name for name, t in tasks.items() if t in pending]
logger.info(
f"{self.log_prefix} 并行处理已进行{elapsed:.2f}秒,待完成任务: {', '.join(pending_names)}"
)
# 所有任务完成,从结果中提取数据
mind_processed_infos = results.get("思考任务", [])
tool_processed_infos = results.get("工具任务", [])
chatting_info_processed_infos = results.get("聊天信息处理任务", [])
# 记录总耗时
parallel_end_time = time.time()
total_duration = parallel_end_time - parallel_start_time
logger.info(f"{self.log_prefix} 思考和工具并行任务全部完成,总耗时: {total_duration:.2f}")
all_plan_info = mind_processed_infos + tool_processed_infos + chatting_info_processed_infos
logger.debug(f"{self.log_prefix} 所有信息处理器处理后的信息: {all_plan_info}")
# 串行执行规划器 - 使用刚获取的思考结果
logger.debug(f"{self.log_prefix} 开始 规划器")
with Timer("规划器", cycle_timers): with Timer("规划器", cycle_timers):
planner_result = await self._planner(all_plan_info, cycle_timers) plan_result = await self.action_planner.plan(all_plan_info, cycle_timers)
action = planner_result.get("action", "error") loop_plan_info = {
action_data = planner_result.get("action_data", {}) # 新增获取动作数据 "action_result": plan_result.get("action_result", {}),
reasoning = planner_result.get("reasoning", "未提供理由") "current_mind": plan_result.get("current_mind", ""),
"observed_messages": plan_result.get("observed_messages", ""),
}
logger.debug(f"{self.log_prefix} 动作和动作信息: {action}, {action_data}, {reasoning}") with Timer("执行动作", cycle_timers):
action_type, action_data, reasoning = (
# 更新循环信息 plan_result.get("action_result", {}).get("action_type", "error"),
self._current_cycle.set_action_info( plan_result.get("action_result", {}).get("action_data", {}),
action_type=action, plan_result.get("action_result", {}).get("reasoning", "未提供理由"),
action_data=action_data,
reasoning=reasoning,
action_taken=True,
) )
# 处理LLM错误
if planner_result.get("llm_error"):
logger.error(f"{self.log_prefix} LLM失败: {reasoning}")
return False, ""
# 在此处添加日志记录 # 在此处添加日志记录
if action == "reply": if action_type == "reply":
action_str = "回复" action_str = "回复"
elif action == "no_reply": elif action_type == "no_reply":
action_str = "不回复" action_str = "不回复"
else: else:
action_str = "位置动作" action_type = "unknown"
action_str = "未知动作"
logger.info(f"{self.log_prefix} 麦麦决定'{action_str}', 原因'{reasoning}'") logger.info(f"{self.log_prefix} 麦麦决定'{action_str}', 原因'{reasoning}'")
self.hfcloop_observation.add_loop_info(self._current_cycle) success, reply_text = await self._handle_action(
action_type, reasoning, action_data, cycle_timers, thinking_id
)
return await self._handle_action(action, reasoning, action_data, cycle_timers, thinking_id) loop_action_info = {
"action_taken": success,
"reply_text": reply_text,
}
loop_info = {
"loop_observation_info": loop_observation_info,
"loop_processor_info": loop_processor_info,
"loop_plan_info": loop_plan_info,
"loop_action_info": loop_action_info,
}
return loop_info
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} 并行+串行处理失败: {e}") logger.error(f"{self.log_prefix} FOCUS聊天处理失败: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return False, "" return {}
async def _handle_action( async def _handle_action(
self, self,
@@ -531,148 +430,59 @@ class HeartFChatting:
thinking_id: str, thinking_id: str,
) -> tuple[bool, str]: ) -> tuple[bool, str]:
""" """
处理规划动作 处理规划动作,使用动作工厂创建相应的动作处理器
参数: 参数:
action: 动作类型 action: 动作类型
reasoning: 决策理由 reasoning: 决策理由
action_data: 动作数据,包含不同动作需要的参数 action_data: 动作数据,包含不同动作需要的参数
cycle_timers: 计时器字典 cycle_timers: 计时器字典
planner_start_db_time: 规划开始时间 thinking_id: 思考ID
返回: 返回:
tuple[bool, str]: (是否执行了动作, 思考消息ID) tuple[bool, str]: (是否执行了动作, 思考消息ID)
""" """
action_handlers = { try:
"reply": self._handle_reply, # 使用工厂创建动作处理器实例
"no_reply": self._handle_no_reply, action_handler = ActionFactory.create_action(
} action_name=action,
action_data=action_data,
reasoning=reasoning,
cycle_timers=cycle_timers,
thinking_id=thinking_id,
observations=self.observations,
expressor=self.expressor,
chat_stream=self.chat_stream,
current_cycle=self._current_cycle,
log_prefix=self.log_prefix,
on_consecutive_no_reply_callback=self.on_consecutive_no_reply_callback,
total_no_reply_count=self.total_no_reply_count,
total_waiting_time=self.total_waiting_time,
shutting_down=self._shutting_down,
)
handler = action_handlers.get(action) if not action_handler:
if not handler: logger.warning(f"{self.log_prefix} 未能创建动作处理器: {action}, 原因: {reasoning}")
logger.warning(f"{self.log_prefix} 未知动作: {action}, 原因: {reasoning}")
return False, "" return False, ""
try: # 处理动作并获取结果
if action == "reply": success, reply_text = await action_handler.handle_action()
return await handler(reasoning, action_data, cycle_timers, thinking_id)
else: # no_reply # 更新状态计数器
return await handler(reasoning, cycle_timers, thinking_id) if action == "no_reply":
self.total_no_reply_count = getattr(action_handler, "total_no_reply_count", self.total_no_reply_count)
self.total_waiting_time = getattr(action_handler, "total_waiting_time", self.total_waiting_time)
elif action == "reply":
self.total_no_reply_count = 0
self.total_waiting_time = 0.0
return success, reply_text
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} 处理{action}时出错: {e}") logger.error(f"{self.log_prefix} 处理{action}时出错: {e}")
traceback.print_exc() traceback.print_exc()
return False, "" return False, ""
async def _handle_no_reply(self, reasoning: str, cycle_timers: dict, thinking_id: str) -> bool:
"""
处理不回复的情况
工作流程:
1. 等待新消息、超时或关闭信号
2. 根据等待结果更新连续不回复计数
3. 如果达到阈值,触发回调
参数:
reasoning: 不回复的原因
planner_start_db_time: 规划开始时间
cycle_timers: 计时器字典
返回:
bool: 是否成功处理
"""
logger.info(f"{self.log_prefix} 决定不回复: {reasoning}")
observation = self.observations[0] if self.observations else None
try:
with Timer("等待新消息", cycle_timers):
# 等待新消息、超时或关闭信号,并获取结果
await self._wait_for_new_message(observation, thinking_id, self.log_prefix)
# 从计时器获取实际等待时间
current_waiting = cycle_timers.get("等待新消息", 0.0)
if not self._shutting_down:
self.total_no_reply_count += 1
self.total_waiting_time += current_waiting # 累加等待时间
logger.debug(
f"{self.log_prefix} 连续不回复计数增加: {self.total_no_reply_count}/{CONSECUTIVE_NO_REPLY_THRESHOLD}, "
f"本次等待: {current_waiting:.2f}秒, 累计等待: {self.total_waiting_time:.2f}"
)
# 检查是否同时达到次数和时间阈值
time_threshold = 0.66 * WAITING_TIME_THRESHOLD * CONSECUTIVE_NO_REPLY_THRESHOLD
if (
self.total_no_reply_count >= CONSECUTIVE_NO_REPLY_THRESHOLD
and self.total_waiting_time >= time_threshold
):
logger.info(
f"{self.log_prefix} 连续不回复达到阈值 ({self.total_no_reply_count}次) "
f"且累计等待时间达到 {self.total_waiting_time:.2f}秒 (阈值 {time_threshold}秒)"
f"调用回调请求状态转换"
)
# 调用回调。注意:这里不重置计数器和时间,依赖回调函数成功改变状态来隐式重置上下文。
await self.on_consecutive_no_reply_callback()
elif self.total_no_reply_count >= CONSECUTIVE_NO_REPLY_THRESHOLD:
# 仅次数达到阈值,但时间未达到
logger.debug(
f"{self.log_prefix} 连续不回复次数达到阈值 ({self.total_no_reply_count}次) "
f"但累计等待时间 {self.total_waiting_time:.2f}秒 未达到时间阈值 ({time_threshold}秒),暂不调用回调"
)
# else: 次数和时间都未达到阈值,不做处理
return True, thinking_id
except asyncio.CancelledError:
logger.info(f"{self.log_prefix} 处理 'no_reply' 时等待被中断 (CancelledError)")
raise
except Exception as e: # 捕获调用管理器或其他地方可能发生的错误
logger.error(f"{self.log_prefix} 处理 'no_reply' 时发生错误: {e}")
logger.error(traceback.format_exc())
return False, thinking_id
async def _wait_for_new_message(self, observation: ChattingObservation, thinking_id: str, log_prefix: str) -> bool:
"""
等待新消息 或 检测到关闭信号
参数:
observation: 观察实例
planner_start_db_time: 开始等待的时间
log_prefix: 日志前缀
返回:
bool: 是否检测到新消息 (如果因关闭信号退出则返回 False)
"""
wait_start_time = time.monotonic()
while True:
# --- 在每次循环开始时检查关闭标志 ---
if self._shutting_down:
logger.info(f"{log_prefix} 等待新消息时检测到关闭信号,中断等待。")
return False # 表示因为关闭而退出
# -----------------------------------
thinking_id_timestamp = parse_thinking_id_to_timestamp(thinking_id)
# 检查新消息
if await observation.has_new_messages_since(thinking_id_timestamp):
logger.info(f"{log_prefix} 检测到新消息")
return True
# 检查超时 (放在检查新消息和关闭之后)
if time.monotonic() - wait_start_time > WAITING_TIME_THRESHOLD:
logger.warning(f"{log_prefix} 等待新消息超时({WAITING_TIME_THRESHOLD}秒)")
return False
try:
# 短暂休眠,让其他任务有机会运行,并能更快响应取消或关闭
await asyncio.sleep(0.5) # 缩短休眠时间
except asyncio.CancelledError:
# 如果在休眠时被取消,再次检查关闭标志
# 如果是正常关闭,则不需要警告
if not self._shutting_down:
logger.warning(f"{log_prefix} _wait_for_new_message 的休眠被意外取消")
# 无论如何,重新抛出异常,让上层处理
raise
async def shutdown(self): async def shutdown(self):
"""优雅关闭HeartFChatting实例取消活动循环任务""" """优雅关闭HeartFChatting实例取消活动循环任务"""
logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...") logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...")
@@ -714,272 +524,3 @@ class HeartFChatting:
if last_n is not None: if last_n is not None:
history = history[-last_n:] history = history[-last_n:]
return [cycle.to_dict() for cycle in history] return [cycle.to_dict() for cycle in history]
async def _planner(self, all_plan_info: List[InfoBase], cycle_timers: dict) -> Dict[str, Any]:
"""
规划器 (Planner): 使用LLM根据上下文决定是否和如何回复。
重构为让LLM返回结构化JSON文本然后在代码中解析。
参数:
current_mind: 子思维的当前思考结果
cycle_timers: 计时器字典
is_re_planned: 是否为重新规划 (此重构中暂时简化,不处理 is_re_planned 的特殊逻辑)
"""
logger.info(f"{self.log_prefix}开始 规划")
actions_to_remove_temporarily = []
# --- 检查历史动作并决定临时移除动作 (逻辑保持不变) ---
lian_xu_wen_ben_hui_fu = 0
probability_roll = random.random()
for cycle in reversed(self._cycle_history):
if cycle.action_taken:
if cycle.action_type == "text_reply":
lian_xu_wen_ben_hui_fu += 1
else:
break
if len(self._cycle_history) > 0 and cycle.cycle_id <= self._cycle_history[0].cycle_id + (
len(self._cycle_history) - 4
):
break
logger.debug(f"{self.log_prefix}[Planner] 检测到连续文本回复次数: {lian_xu_wen_ben_hui_fu}")
if lian_xu_wen_ben_hui_fu >= 3:
logger.info(f"{self.log_prefix}[Planner] 连续回复 >= 3 次,强制移除 text_reply 和 emoji_reply")
actions_to_remove_temporarily.extend(["text_reply", "emoji_reply"])
elif lian_xu_wen_ben_hui_fu == 2:
if probability_roll < 0.8:
logger.info(f"{self.log_prefix}[Planner] 连续回复 2 次80% 概率移除 text_reply 和 emoji_reply (触发)")
actions_to_remove_temporarily.extend(["text_reply", "emoji_reply"])
else:
logger.info(
f"{self.log_prefix}[Planner] 连续回复 2 次80% 概率移除 text_reply 和 emoji_reply (未触发)"
)
elif lian_xu_wen_ben_hui_fu == 1:
if probability_roll < 0.4:
logger.info(f"{self.log_prefix}[Planner] 连续回复 1 次40% 概率移除 text_reply (触发)")
actions_to_remove_temporarily.append("text_reply")
else:
logger.info(f"{self.log_prefix}[Planner] 连续回复 1 次40% 概率移除 text_reply (未触发)")
# --- 结束检查历史动作 ---
# 获取观察信息
for info in all_plan_info:
if isinstance(info, ObsInfo):
logger.debug(f"{self.log_prefix} 观察信息: {info}")
observed_messages = info.get_talking_message()
observed_messages_str = info.get_talking_message_str_truncate()
chat_type = info.get_chat_type()
if chat_type == "group":
is_group_chat = True
else:
is_group_chat = False
elif isinstance(info, MindInfo):
logger.debug(f"{self.log_prefix} 思维信息: {info}")
current_mind = info.get_current_mind()
elif isinstance(info, CycleInfo):
logger.debug(f"{self.log_prefix} 循环信息: {info}")
cycle_info = info.get_observe_info()
elif isinstance(info, StructuredInfo):
logger.debug(f"{self.log_prefix} 结构化信息: {info}")
structured_info = info.get_data()
# --- 使用 LLM 进行决策 (JSON 输出模式) --- #
action = "no_reply" # 默认动作
reasoning = "规划器初始化默认"
llm_error = False # LLM 请求或解析错误标志
# 获取我们将传递给 prompt 构建器和用于验证的当前可用动作
current_available_actions = self.action_manager.get_available_actions()
try:
# --- 应用临时动作移除 ---
if actions_to_remove_temporarily:
self.action_manager.temporarily_remove_actions(actions_to_remove_temporarily)
# 更新 current_available_actions 以反映移除后的状态
current_available_actions = self.action_manager.get_available_actions()
logger.debug(
f"{self.log_prefix}[Planner] 临时移除的动作: {actions_to_remove_temporarily}, 当前可用: {list(current_available_actions.keys())}"
)
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
prompt = await prompt_builder.build_planner_prompt(
is_group_chat=is_group_chat, # <-- Pass HFC state
chat_target_info=None,
observed_messages_str=observed_messages_str, # <-- Pass local variable
current_mind=current_mind, # <-- Pass argument
structured_info=structured_info, # <-- Pass SubMind info
current_available_actions=current_available_actions, # <-- Pass determined actions
cycle_info=cycle_info, # <-- Pass cycle info
)
# --- 调用 LLM (普通文本生成) ---
llm_content = None
try:
llm_content, _, _ = await self.planner_llm.generate_response(prompt=prompt)
logger.debug(f"{self.log_prefix}[Planner] LLM 原始 JSON 响应 (预期): {llm_content}")
except Exception as req_e:
logger.error(f"{self.log_prefix}[Planner] LLM 请求执行失败: {req_e}")
reasoning = f"LLM 请求失败: {req_e}"
llm_error = True
# 直接使用默认动作返回错误结果
action = "no_reply" # 明确设置为默认值
# --- 解析 LLM 返回的 JSON (仅当 LLM 请求未出错时进行) ---
if not llm_error and llm_content:
try:
# 尝试去除可能的 markdown 代码块标记
cleaned_content = (
llm_content.strip().removeprefix("```json").removeprefix("```").removesuffix("```").strip()
)
if not cleaned_content:
raise json.JSONDecodeError("Cleaned content is empty", cleaned_content, 0)
parsed_json = json.loads(cleaned_content)
# 提取决策,提供默认值
extracted_action = parsed_json.get("action", "no_reply")
extracted_reasoning = parsed_json.get("reasoning", "LLM未提供理由")
# extracted_emoji_query = parsed_json.get("emoji_query", "")
# 新的reply格式
if extracted_action == "reply":
action_data = {
"text": parsed_json.get("text", []),
"emojis": parsed_json.get("emojis", []),
"target": parsed_json.get("target", ""),
}
else:
action_data = {} # 其他动作可能不需要额外数据
# 验证动作是否在当前可用列表中
# !! 使用调用 prompt 时实际可用的动作列表进行验证
if extracted_action not in current_available_actions:
logger.warning(
f"{self.log_prefix}[Planner] LLM 返回了当前不可用或无效的动作: '{extracted_action}' (可用: {list(current_available_actions.keys())}),将强制使用 'no_reply'"
)
action = "no_reply"
reasoning = f"LLM 返回了当前不可用的动作 '{extracted_action}' (可用: {list(current_available_actions.keys())})。原始理由: {extracted_reasoning}"
# 检查 no_reply 是否也恰好被移除了 (极端情况)
if "no_reply" not in current_available_actions:
logger.error(
f"{self.log_prefix}[Planner] 严重错误:'no_reply' 动作也不可用!无法执行任何动作。"
)
action = "error" # 回退到错误状态
reasoning = "无法执行任何有效动作,包括 no_reply"
llm_error = True # 标记为严重错误
else:
llm_error = False # 视为逻辑修正而非 LLM 错误
else:
# 动作有效且可用
action = extracted_action
reasoning = extracted_reasoning
llm_error = False # 解析成功
logger.debug(
f"{self.log_prefix}[要做什么]\nPrompt:\n{prompt}\n\n决策结果 (来自JSON): {action}, 理由: {reasoning}"
)
logger.debug(f"{self.log_prefix}动作信息: '{action_data}'")
except Exception as json_e:
logger.warning(
f"{self.log_prefix}[Planner] 解析LLM响应JSON失败: {json_e}. LLM原始输出: '{llm_content}'"
)
reasoning = f"解析LLM响应JSON失败: {json_e}. 将使用默认动作 'no_reply'."
action = "no_reply" # 解析失败则默认不回复
llm_error = True # 标记解析错误
elif not llm_error and not llm_content:
# LLM 请求成功但返回空内容
logger.warning(f"{self.log_prefix}[Planner] LLM 返回了空内容。")
reasoning = "LLM 返回了空内容,使用默认动作 'no_reply'."
action = "no_reply"
llm_error = True # 标记为空响应错误
except Exception as outer_e:
logger.error(f"{self.log_prefix}[Planner] Planner 处理过程中发生意外错误: {outer_e}")
traceback.print_exc()
action = "error" # 发生未知错误,标记为 error 动作
reasoning = f"Planner 内部处理错误: {outer_e}"
llm_error = True
finally:
# --- 确保动作恢复 ---
if self.action_manager._original_actions_backup is not None:
self.action_manager.restore_actions()
logger.debug(
f"{self.log_prefix}[Planner] 恢复了原始动作集, 当前可用: {list(self.action_manager.get_available_actions().keys())}"
)
# --- 概率性忽略文本回复附带的表情 (逻辑保持不变) ---
try:
emoji = action_data.get("emojis")
if action == "reply" and emoji:
logger.debug(f"{self.log_prefix}[Planner] 大模型建议文字回复带表情: '{emoji}'")
if random.random() > EMOJI_SEND_PRO:
logger.info(f"{self.log_prefix}但是麦麦这次不想加表情 ({1 - EMOJI_SEND_PRO:.0%}),忽略表情 '{emoji}'")
action_data["emojis"] = "" # 清空表情请求
else:
logger.info(f"{self.log_prefix}好吧,加上表情 '{emoji}'")
except Exception as e:
logger.error(f"{self.log_prefix}[Planner] 概率性忽略表情时发生错误: {e}")
traceback.print_exc()
# --- 结束概率性忽略 ---
# 返回结果字典
return {
"action": action,
"action_data": action_data,
"reasoning": reasoning,
"current_mind": current_mind,
"observed_messages": observed_messages,
"llm_error": llm_error, # 返回错误状态
}
async def _handle_reply(
self, reasoning: str, reply_data: dict, cycle_timers: dict, thinking_id: str
) -> tuple[bool, str]:
"""
处理统一的回复动作 - 可包含文本和表情,顺序任意
reply_data格式:
{
"text": "你好啊" # 文本内容列表(可选)
"target": "锚定消息", # 锚定消息的文本内容
"emojis": "微笑" # 表情关键词列表(可选)
}
"""
# 重置连续不回复计数器
self.total_no_reply_count = 0
self.total_waiting_time = 0.0
# 从聊天观察获取锚定消息
observations: ChattingObservation = self.observations[0]
anchor_message = observations.serch_message_by_text(reply_data["target"])
# 如果没有找到锚点消息,创建一个占位符
if not anchor_message:
logger.info(f"{self.log_prefix} 未找到锚点消息,创建占位符")
anchor_message = await create_empty_anchor_message(
self.chat_stream.platform, self.chat_stream.group_info, self.chat_stream
)
else:
anchor_message.update_chat_stream(self.chat_stream)
success, reply_set = await self.expressor.deal_reply(
cycle_timers=cycle_timers,
action_data=reply_data,
anchor_message=anchor_message,
reasoning=reasoning,
thinking_id=thinking_id,
)
reply_text = ""
for reply in reply_set:
type = reply[0]
data = reply[1]
if type == "text":
reply_text += data
elif type == "emoji":
reply_text += data
self._current_cycle.set_response_info(
response_text=reply_text,
)
return success, reply_text

View File

@@ -77,6 +77,7 @@ def init_prompt():
- 一次只回复一个人,一次只回复一个话题,突出重点 - 一次只回复一个人,一次只回复一个话题,突出重点
- 如果是自己发的消息想继续,需自然衔接 - 如果是自己发的消息想继续,需自然衔接
- 避免重复或评价自己的发言,不要和自己聊天 - 避免重复或评价自己的发言,不要和自己聊天
注意:回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。
你必须从上面列出的可用行动中选择一个,并说明原因。 你必须从上面列出的可用行动中选择一个,并说明原因。
你的决策必须以严格的 JSON 格式输出,且仅包含 JSON 内容,不要有任何其他文字或解释。 你的决策必须以严格的 JSON 格式输出,且仅包含 JSON 内容,不要有任何其他文字或解释。
@@ -291,7 +292,7 @@ async def _build_prompt_focus(
) )
# --- End choosing template --- # --- End choosing template ---
logger.debug(f"focus_chat_prompt (is_group={is_group_chat}): \n{prompt}") # logger.debug(f"focus_chat_prompt (is_group={is_group_chat}): \n{prompt}")
return prompt return prompt

View File

@@ -14,15 +14,15 @@ class BaseProcessor(ABC):
支持处理InfoBase和Observation类型的输入。 支持处理InfoBase和Observation类型的输入。
""" """
log_prefix = "Base信息处理器"
@abstractmethod @abstractmethod
def __init__(self): def __init__(self):
"""初始化处理器""" """初始化处理器"""
pass
@abstractmethod @abstractmethod
async def process_info( async def process_info(
self, self,
infos: List[InfoBase],
observations: Optional[List[Observation]] = None, observations: Optional[List[Observation]] = None,
running_memorys: Optional[List[Dict]] = None, running_memorys: Optional[List[Dict]] = None,
**kwargs: Any, **kwargs: Any,

View File

@@ -12,7 +12,7 @@ from typing import Dict
from src.chat.models.utils_model import LLMRequest from src.chat.models.utils_model import LLMRequest
from src.config.config import global_config from src.config.config import global_config
logger = get_logger("observation") logger = get_logger("processor")
class ChattingInfoProcessor(BaseProcessor): class ChattingInfoProcessor(BaseProcessor):
@@ -21,12 +21,14 @@ class ChattingInfoProcessor(BaseProcessor):
用于处理Observation对象将其转换为ObsInfo对象。 用于处理Observation对象将其转换为ObsInfo对象。
""" """
log_prefix = "聊天信息处理"
def __init__(self): def __init__(self):
"""初始化观察处理器""" """初始化观察处理器"""
super().__init__()
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"
) )
super().__init__()
async def process_info( async def process_info(
self, self,

View File

@@ -24,17 +24,16 @@ from src.chat.focus_chat.info_processors.processor_utils import (
from typing import Dict from typing import Dict
from src.chat.focus_chat.info.info_base import InfoBase from src.chat.focus_chat.info.info_base import InfoBase
logger = get_logger("sub_heartflow") logger = get_logger("processor")
def init_prompt(): def init_prompt():
# --- Group Chat Prompt --- # --- Group Chat Prompt ---
group_prompt = """ group_prompt = """
你的名字是{bot_name}
{memory_str} {memory_str}
{extra_info} {extra_info}
{relation_prompt} {relation_prompt}
你的名字是{bot_name}
{mood_info}
{cycle_info_block} {cycle_info_block}
现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容 现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
{chat_observe_info} {chat_observe_info}
@@ -74,8 +73,11 @@ def init_prompt():
class MindProcessor(BaseProcessor): class MindProcessor(BaseProcessor):
log_prefix = "聊天思考"
def __init__(self, subheartflow_id: str): def __init__(self, subheartflow_id: str):
super().__init__() super().__init__()
self.subheartflow_id = subheartflow_id self.subheartflow_id = subheartflow_id
self.llm_model = LLMRequest( self.llm_model = LLMRequest(
@@ -228,7 +230,7 @@ class MindProcessor(BaseProcessor):
bot_name=individuality.name, bot_name=individuality.name,
time_now=time_now, time_now=time_now,
chat_observe_info=chat_observe_info, chat_observe_info=chat_observe_info,
mood_info="mood_info", # mood_info="mood_info",
hf_do_next=spark_prompt, hf_do_next=spark_prompt,
last_mind=previous_mind, last_mind=previous_mind,
cycle_info_block=hfcloop_observe_info, cycle_info_block=hfcloop_observe_info,

View File

@@ -14,7 +14,7 @@ from src.chat.heart_flow.observation.observation import Observation
from src.chat.heart_flow.observation.working_observation import WorkingObservation from src.chat.heart_flow.observation.working_observation import WorkingObservation
from src.chat.focus_chat.info.structured_info import StructuredInfo from src.chat.focus_chat.info.structured_info import StructuredInfo
logger = get_logger("tool_use") logger = get_logger("processor")
def init_prompt(): def init_prompt():
@@ -45,6 +45,8 @@ def init_prompt():
class ToolProcessor(BaseProcessor): class ToolProcessor(BaseProcessor):
log_prefix = "工具执行器"
def __init__(self, subheartflow_id: str): def __init__(self, subheartflow_id: str):
super().__init__() super().__init__()
self.subheartflow_id = subheartflow_id self.subheartflow_id = subheartflow_id

View File

@@ -8,6 +8,7 @@ from src.chat.utils.prompt_builder import Prompt
from datetime import datetime from datetime import datetime
from src.chat.memory_system.Hippocampus import HippocampusManager from src.chat.memory_system.Hippocampus import HippocampusManager
from typing import List, Dict from typing import List, Dict
import difflib
logger = get_logger("memory_activator") logger = get_logger("memory_activator")
@@ -82,7 +83,7 @@ class MemoryActivator:
text=obs_info_text, max_memory_num=3, max_memory_length=2, max_depth=3, fast_retrieval=True 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}")
# 激活时所有已有记忆的duration+1达到3则移除 # 激活时所有已有记忆的duration+1达到3则移除
for m in self.running_memory[:]: for m in self.running_memory[:]:
@@ -91,14 +92,21 @@ class MemoryActivator:
if related_memory: if related_memory:
for topic, memory in related_memory: for topic, memory in related_memory:
# 检查是否已存在相同topic和content的记忆 # 检查是否已存在相同topic或相似内容(相似度>=0.7的记忆
exists = any(m["topic"] == topic and m["content"] == memory for m in self.running_memory) exists = any(
m["topic"] == topic or difflib.SequenceMatcher(None, m["content"], memory).ratio() >= 0.7
for m in self.running_memory
)
if not exists: if not exists:
self.running_memory.append( self.running_memory.append(
{"topic": topic, "content": memory, "timestamp": datetime.now().isoformat(), "duration": 1} {"topic": topic, "content": memory, "timestamp": datetime.now().isoformat(), "duration": 1}
) )
logger.debug(f"添加新记忆: {topic} - {memory}") logger.debug(f"添加新记忆: {topic} - {memory}")
# 限制同时加载的记忆条数最多保留最后3条
if len(self.running_memory) > 3:
self.running_memory = self.running_memory[-3:]
return self.running_memory return self.running_memory

View File

@@ -0,0 +1,165 @@
from typing import Dict, List, Optional, Callable, Coroutine, Type
from src.chat.focus_chat.planners.actions.base_action import BaseAction
from src.chat.focus_chat.planners.actions.reply_action import ReplyAction
from src.chat.focus_chat.planners.actions.no_reply_action import NoReplyAction
from src.chat.heart_flow.observation.observation import Observation
from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor
from src.chat.message_receive.chat_stream import ChatStream
from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail
from src.common.logger_manager import get_logger
logger = get_logger("action_factory")
class ActionFactory:
"""
动作工厂类,用于创建各种类型的动作处理器
"""
# 注册的动作处理器类映射
_action_handlers: Dict[str, Type[BaseAction]] = {
"reply": ReplyAction,
"no_reply": NoReplyAction,
}
# 可用动作集定义原ActionManager.DEFAULT_ACTIONS
DEFAULT_ACTIONS: Dict[str, str] = {
"no_reply": "不操作,继续浏览",
"reply": "表达想法,可以只包含文本、表情或两者都有",
}
_available_actions: Dict[str, str] = DEFAULT_ACTIONS.copy()
_original_actions_backup: Optional[Dict[str, str]] = None
@classmethod
def register_action_handler(cls, action_name: str, handler_class: Type[BaseAction]) -> None:
"""
注册新的动作处理器类
Args:
action_name: 动作名称
handler_class: 处理器类必须是BaseAction的子类
"""
if not issubclass(handler_class, BaseAction):
raise TypeError(f"{handler_class.__name__} 不是 BaseAction 的子类")
cls._action_handlers[action_name] = handler_class
logger.info(f"已注册动作处理器: {action_name} -> {handler_class.__name__}")
@classmethod
def create_action(
cls,
action_name: str,
action_data: dict,
reasoning: str,
cycle_timers: dict,
thinking_id: str,
observations: List[Observation],
expressor: DefaultExpressor,
chat_stream: ChatStream,
current_cycle: CycleDetail,
log_prefix: str,
on_consecutive_no_reply_callback: Callable[[], Coroutine[None, None, None]],
total_no_reply_count: int = 0,
total_waiting_time: float = 0.0,
shutting_down: bool = False,
) -> Optional[BaseAction]:
"""
创建动作处理器实例
Args:
action_name: 动作名称
action_data: 动作数据
reasoning: 执行理由
cycle_timers: 计时器字典
thinking_id: 思考ID
observations: 观察列表
expressor: 表达器
chat_stream: 聊天流
current_cycle: 当前循环信息
log_prefix: 日志前缀
on_consecutive_no_reply_callback: 连续不回复回调
total_no_reply_count: 连续不回复计数
total_waiting_time: 累计等待时间
shutting_down: 是否正在关闭
Returns:
Optional[BaseAction]: 创建的动作处理器实例如果动作名称未注册则返回None
"""
handler_class = cls._action_handlers.get(action_name)
if not handler_class:
logger.warning(f"未注册的动作类型: {action_name}")
return None
try:
if action_name == "reply":
return handler_class(
action_name=action_name,
action_data=action_data,
reasoning=reasoning,
cycle_timers=cycle_timers,
thinking_id=thinking_id,
observations=observations,
expressor=expressor,
chat_stream=chat_stream,
current_cycle=current_cycle,
log_prefix=log_prefix,
)
elif action_name == "no_reply":
return handler_class(
action_name=action_name,
action_data=action_data,
reasoning=reasoning,
cycle_timers=cycle_timers,
thinking_id=thinking_id,
observations=observations,
on_consecutive_no_reply_callback=on_consecutive_no_reply_callback,
current_cycle=current_cycle,
log_prefix=log_prefix,
total_no_reply_count=total_no_reply_count,
total_waiting_time=total_waiting_time,
shutting_down=shutting_down,
)
else:
# 对于未来可能添加的其他动作类型,可以在这里扩展
logger.warning(f"未实现的动作处理逻辑: {action_name}")
return None
except Exception as e:
logger.error(f"创建动作处理器实例失败: {e}")
return None
@classmethod
def get_available_actions(cls) -> Dict[str, str]:
"""获取当前可用的动作集"""
return cls._available_actions.copy()
@classmethod
def add_action(cls, action_name: str, description: str) -> bool:
"""添加新的动作"""
if action_name in cls._available_actions:
return False
cls._available_actions[action_name] = description
return True
@classmethod
def remove_action(cls, action_name: str) -> bool:
"""移除指定动作"""
if action_name not in cls._available_actions:
return False
del cls._available_actions[action_name]
return True
@classmethod
def temporarily_remove_actions(cls, actions_to_remove: List[str]) -> None:
"""临时移除指定动作,备份原始动作集"""
if cls._original_actions_backup is None:
cls._original_actions_backup = cls._available_actions.copy()
for name in actions_to_remove:
cls._available_actions.pop(name, None)
@classmethod
def restore_actions(cls) -> None:
"""恢复之前备份的原始动作集"""
if cls._original_actions_backup is not None:
cls._available_actions = cls._original_actions_backup.copy()
cls._original_actions_backup = None

View File

@@ -0,0 +1,72 @@
from typing import List, Optional, Dict
# 默认动作定义
DEFAULT_ACTIONS = {"no_reply": "不操作,继续浏览", "reply": "表达想法,可以只包含文本、表情或两者都有"}
class ActionManager:
"""动作管理器:控制每次决策可以使用的动作"""
def __init__(self):
# 初始化为新的默认动作集
self._available_actions: Dict[str, str] = DEFAULT_ACTIONS.copy()
self._original_actions_backup: Optional[Dict[str, str]] = None
def get_available_actions(self) -> Dict[str, str]:
"""获取当前可用的动作集"""
return self._available_actions.copy() # 返回副本以防外部修改
def add_action(self, action_name: str, description: str) -> bool:
"""
添加新的动作
参数:
action_name: 动作名称
description: 动作描述
返回:
bool: 是否添加成功
"""
if action_name in self._available_actions:
return False
self._available_actions[action_name] = description
return True
def remove_action(self, action_name: str) -> bool:
"""
移除指定动作
参数:
action_name: 动作名称
返回:
bool: 是否移除成功
"""
if action_name not in self._available_actions:
return False
del self._available_actions[action_name]
return True
def temporarily_remove_actions(self, actions_to_remove: List[str]):
"""
临时移除指定的动作,备份原始动作集。
如果已经有备份,则不重复备份。
"""
if self._original_actions_backup is None:
self._original_actions_backup = self._available_actions.copy()
actions_actually_removed = []
for action_name in actions_to_remove:
if action_name in self._available_actions:
del self._available_actions[action_name]
actions_actually_removed.append(action_name)
# logger.debug(f"临时移除了动作: {actions_actually_removed}") # 可选日志
def restore_actions(self):
"""
恢复之前备份的原始动作集。
"""
if self._original_actions_backup is not None:
self._available_actions = self._original_actions_backup.copy()
self._original_actions_backup = None
# logger.debug("恢复了原始动作集") # 可选日志

View File

@@ -0,0 +1,37 @@
from abc import ABC, abstractmethod
from typing import Tuple
from src.common.logger_manager import get_logger
logger = get_logger("base_action")
class BaseAction(ABC):
"""动作处理基类接口
所有具体的动作处理类都应该继承这个基类并实现handle_action方法。
"""
def __init__(self, action_name: str, action_data: dict, reasoning: str, cycle_timers: dict, thinking_id: str):
"""初始化动作处理器
Args:
action_name: 动作名称
action_data: 动作数据
reasoning: 执行该动作的理由
cycle_timers: 计时器字典
thinking_id: 思考ID
"""
self.action_name = action_name
self.action_data = action_data
self.reasoning = reasoning
self.cycle_timers = cycle_timers
self.thinking_id = thinking_id
@abstractmethod
async def handle_action(self) -> Tuple[bool, str]:
"""处理动作的抽象方法,需要被子类实现
Returns:
Tuple[bool, str]: (是否执行成功, 回复文本)
"""
pass

View File

@@ -0,0 +1,168 @@
import asyncio
import traceback
from src.common.logger_manager import get_logger
from src.chat.utils.timer_calculator import Timer
from src.chat.focus_chat.planners.actions.base_action import BaseAction
from typing import Tuple, List, Callable, Coroutine
from src.chat.heart_flow.observation.observation import Observation
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail
from src.chat.focus_chat.hfc_utils import parse_thinking_id_to_timestamp
logger = get_logger("action_taken")
# 常量定义
WAITING_TIME_THRESHOLD = 300 # 等待新消息时间阈值,单位秒
CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
class NoReplyAction(BaseAction):
"""不回复动作处理类
处理决定不回复的动作。
"""
def __init__(
self,
action_name: str,
action_data: dict,
reasoning: str,
cycle_timers: dict,
thinking_id: str,
observations: List[Observation],
on_consecutive_no_reply_callback: Callable[[], Coroutine[None, None, None]],
current_cycle: CycleDetail,
log_prefix: str,
total_no_reply_count: int = 0,
total_waiting_time: float = 0.0,
shutting_down: bool = False,
):
"""初始化不回复动作处理器
Args:
action_name: 动作名称
action_data: 动作数据
reasoning: 执行该动作的理由
cycle_timers: 计时器字典
thinking_id: 思考ID
observations: 观察列表
on_consecutive_no_reply_callback: 连续不回复达到阈值时调用的回调函数
current_cycle: 当前循环信息
log_prefix: 日志前缀
total_no_reply_count: 连续不回复计数
total_waiting_time: 累计等待时间
shutting_down: 是否正在关闭
"""
super().__init__(action_name, action_data, reasoning, cycle_timers, thinking_id)
self.observations = observations
self.on_consecutive_no_reply_callback = on_consecutive_no_reply_callback
self._current_cycle = current_cycle
self.log_prefix = log_prefix
self.total_no_reply_count = total_no_reply_count
self.total_waiting_time = total_waiting_time
self._shutting_down = shutting_down
async def handle_action(self) -> Tuple[bool, str]:
"""
处理不回复的情况
工作流程:
1. 等待新消息、超时或关闭信号
2. 根据等待结果更新连续不回复计数
3. 如果达到阈值,触发回调
Returns:
Tuple[bool, str]: (是否执行成功, 空字符串)
"""
logger.info(f"{self.log_prefix} 决定不回复: {self.reasoning}")
observation = self.observations[0] if self.observations else None
try:
with Timer("等待新消息", self.cycle_timers):
# 等待新消息、超时或关闭信号,并获取结果
await self._wait_for_new_message(observation, self.thinking_id, self.log_prefix)
# 从计时器获取实际等待时间
current_waiting = self.cycle_timers.get("等待新消息", 0.0)
if not self._shutting_down:
self.total_no_reply_count += 1
self.total_waiting_time += current_waiting # 累加等待时间
logger.debug(
f"{self.log_prefix} 连续不回复计数增加: {self.total_no_reply_count}/{CONSECUTIVE_NO_REPLY_THRESHOLD}, "
f"本次等待: {current_waiting:.2f}秒, 累计等待: {self.total_waiting_time:.2f}"
)
# 检查是否同时达到次数和时间阈值
time_threshold = 0.66 * WAITING_TIME_THRESHOLD * CONSECUTIVE_NO_REPLY_THRESHOLD
if (
self.total_no_reply_count >= CONSECUTIVE_NO_REPLY_THRESHOLD
and self.total_waiting_time >= time_threshold
):
logger.info(
f"{self.log_prefix} 连续不回复达到阈值 ({self.total_no_reply_count}次) "
f"且累计等待时间达到 {self.total_waiting_time:.2f}秒 (阈值 {time_threshold}秒)"
f"调用回调请求状态转换"
)
# 调用回调。注意:这里不重置计数器和时间,依赖回调函数成功改变状态来隐式重置上下文。
await self.on_consecutive_no_reply_callback()
elif self.total_no_reply_count >= CONSECUTIVE_NO_REPLY_THRESHOLD:
# 仅次数达到阈值,但时间未达到
logger.debug(
f"{self.log_prefix} 连续不回复次数达到阈值 ({self.total_no_reply_count}次) "
f"但累计等待时间 {self.total_waiting_time:.2f}秒 未达到时间阈值 ({time_threshold}秒),暂不调用回调"
)
# else: 次数和时间都未达到阈值,不做处理
return True, "" # 不回复动作没有回复文本
except asyncio.CancelledError:
logger.info(f"{self.log_prefix} 处理 'no_reply' 时等待被中断 (CancelledError)")
raise
except Exception as e: # 捕获调用管理器或其他地方可能发生的错误
logger.error(f"{self.log_prefix} 处理 'no_reply' 时发生错误: {e}")
logger.error(traceback.format_exc())
return False, ""
async def _wait_for_new_message(self, observation: ChattingObservation, thinking_id: str, log_prefix: str) -> bool:
"""
等待新消息 或 检测到关闭信号
参数:
observation: 观察实例
thinking_id: 思考ID
log_prefix: 日志前缀
返回:
bool: 是否检测到新消息 (如果因关闭信号退出则返回 False)
"""
wait_start_time = asyncio.get_event_loop().time()
while True:
# --- 在每次循环开始时检查关闭标志 ---
if self._shutting_down:
logger.info(f"{log_prefix} 等待新消息时检测到关闭信号,中断等待。")
return False # 表示因为关闭而退出
# -----------------------------------
thinking_id_timestamp = parse_thinking_id_to_timestamp(thinking_id)
# 检查新消息
if await observation.has_new_messages_since(thinking_id_timestamp):
logger.info(f"{log_prefix} 检测到新消息")
return True
# 检查超时 (放在检查新消息和关闭之后)
if asyncio.get_event_loop().time() - wait_start_time > WAITING_TIME_THRESHOLD:
logger.warning(f"{log_prefix} 等待新消息超时({WAITING_TIME_THRESHOLD}秒)")
return False
try:
# 短暂休眠,让其他任务有机会运行,并能更快响应取消或关闭
await asyncio.sleep(0.5) # 缩短休眠时间
except asyncio.CancelledError:
# 如果在休眠时被取消,再次检查关闭标志
# 如果是正常关闭,则不需要警告
if not self._shutting_down:
logger.warning(f"{log_prefix} _wait_for_new_message 的休眠被意外取消")
# 无论如何,重新抛出异常,让上层处理
raise

View File

@@ -0,0 +1,104 @@
from src.common.logger_manager import get_logger
from src.chat.heart_flow.observation.chatting_observation import ChattingObservation
from src.chat.focus_chat.hfc_utils import create_empty_anchor_message
from src.chat.focus_chat.planners.actions.base_action import BaseAction
from typing import Tuple, List
from src.chat.focus_chat.heartFC_Cycleinfo import CycleDetail
from src.chat.message_receive.chat_stream import ChatStream
from src.chat.heart_flow.observation.observation import Observation
from src.chat.focus_chat.expressors.default_expressor import DefaultExpressor
logger = get_logger("action_taken")
class ReplyAction(BaseAction):
"""回复动作处理类
处理发送回复消息的动作,包括文本和表情。
"""
def __init__(
self,
action_name: str,
action_data: dict,
reasoning: str,
cycle_timers: dict,
thinking_id: str,
observations: List[Observation],
expressor: DefaultExpressor,
chat_stream: ChatStream,
current_cycle: CycleDetail,
log_prefix: str,
):
"""初始化回复动作处理器
Args:
action_name: 动作名称
action_data: 动作数据
reasoning: 执行该动作的理由
cycle_timers: 计时器字典
thinking_id: 思考ID
observations: 观察列表
expressor: 表达器
chat_stream: 聊天流
current_cycle: 当前循环信息
log_prefix: 日志前缀
"""
super().__init__(action_name, action_data, reasoning, cycle_timers, thinking_id)
self.observations = observations
self.expressor = expressor
self.chat_stream = chat_stream
self._current_cycle = current_cycle
self.log_prefix = log_prefix
self.total_no_reply_count = 0
self.total_waiting_time = 0.0
async def handle_action(self) -> Tuple[bool, str]:
"""
处理统一的回复动作 - 可包含文本和表情,顺序任意
reply_data格式:
{
"text": "你好啊" # 文本内容列表(可选)
"target": "锚定消息", # 锚定消息的文本内容
"emojis": "微笑" # 表情关键词列表(可选)
}
Returns:
Tuple[bool, str]: (是否执行成功, 回复文本)
"""
# 重置连续不回复计数器
self.total_no_reply_count = 0
self.total_waiting_time = 0.0
# 从聊天观察获取锚定消息
observations: ChattingObservation = self.observations[0]
anchor_message = observations.serch_message_by_text(self.action_data["target"])
# 如果没有找到锚点消息,创建一个占位符
if not anchor_message:
logger.info(f"{self.log_prefix} 未找到锚点消息,创建占位符")
anchor_message = await create_empty_anchor_message(
self.chat_stream.platform, self.chat_stream.group_info, self.chat_stream
)
else:
anchor_message.update_chat_stream(self.chat_stream)
success, reply_set = await self.expressor.deal_reply(
cycle_timers=self.cycle_timers,
action_data=self.action_data,
anchor_message=anchor_message,
reasoning=self.reasoning,
thinking_id=self.thinking_id,
)
reply_text = ""
for reply in reply_set:
type = reply[0]
data = reply[1]
if type == "text":
reply_text += data
elif type == "emoji":
reply_text += data
return success, reply_text

View File

@@ -0,0 +1,156 @@
import json # <--- 确保导入 json
import traceback
from typing import List, Dict, Any
from rich.traceback import install
from src.chat.models.utils_model import LLMRequest
from src.config.config import global_config
from src.chat.focus_chat.heartflow_prompt_builder import prompt_builder
from src.chat.focus_chat.info.info_base import InfoBase
from src.chat.focus_chat.info.obs_info import ObsInfo
from src.chat.focus_chat.info.cycle_info import CycleInfo
from src.chat.focus_chat.info.mind_info import MindInfo
from src.chat.focus_chat.info.structured_info import StructuredInfo
from src.chat.focus_chat.planners.action_factory import ActionFactory
from src.common.logger_manager import get_logger
logger = get_logger("planner")
install(extra_lines=3)
class ActionPlanner:
def __init__(self, log_prefix: str):
self.log_prefix = log_prefix
# LLM规划器配置
self.planner_llm = LLMRequest(
model=global_config.llm_plan,
max_tokens=1000,
request_type="action_planning", # 用于动作规划
)
async def plan(self, all_plan_info: List[InfoBase], cycle_timers: dict) -> Dict[str, Any]:
"""
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
参数:
all_plan_info: 所有计划信息
cycle_timers: 计时器字典
"""
action = "no_reply" # 默认动作
reasoning = "规划器初始化默认"
try:
# 获取观察信息
for info in all_plan_info:
if isinstance(info, ObsInfo):
logger.debug(f"{self.log_prefix} 观察信息: {info}")
observed_messages = info.get_talking_message()
observed_messages_str = info.get_talking_message_str_truncate()
chat_type = info.get_chat_type()
if chat_type == "group":
is_group_chat = True
else:
is_group_chat = False
elif isinstance(info, MindInfo):
logger.debug(f"{self.log_prefix} 思维信息: {info}")
current_mind = info.get_current_mind()
elif isinstance(info, CycleInfo):
logger.debug(f"{self.log_prefix} 循环信息: {info}")
cycle_info = info.get_observe_info()
elif isinstance(info, StructuredInfo):
logger.debug(f"{self.log_prefix} 结构化信息: {info}")
structured_info = info.get_data()
# 获取我们将传递给 prompt 构建器和用于验证的当前可用动作
current_available_actions = ActionFactory.get_available_actions()
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
prompt = await prompt_builder.build_planner_prompt(
is_group_chat=is_group_chat, # <-- Pass HFC state
chat_target_info=None,
observed_messages_str=observed_messages_str, # <-- Pass local variable
current_mind=current_mind, # <-- Pass argument
structured_info=structured_info, # <-- Pass SubMind info
current_available_actions=current_available_actions, # <-- Pass determined actions
cycle_info=cycle_info, # <-- Pass cycle info
)
# --- 调用 LLM (普通文本生成) ---
llm_content = None
try:
llm_content, _, _ = await self.planner_llm.generate_response(prompt=prompt)
logger.debug(f"{self.log_prefix}[Planner] LLM 原始 JSON 响应 (预期): {llm_content}")
except Exception as req_e:
logger.error(f"{self.log_prefix}[Planner] LLM 请求执行失败: {req_e}")
reasoning = f"LLM 请求失败,你的模型出现问题: {req_e}"
action = "no_reply"
if llm_content:
try:
# 尝试去除可能的 markdown 代码块标记
cleaned_content = (
llm_content.strip().removeprefix("```json").removeprefix("```").removesuffix("```").strip()
)
if not cleaned_content:
raise json.JSONDecodeError("Cleaned content is empty", cleaned_content, 0)
parsed_json = json.loads(cleaned_content)
# 提取决策,提供默认值
extracted_action = parsed_json.get("action", "no_reply")
extracted_reasoning = parsed_json.get("reasoning", "LLM未提供理由")
# 新的reply格式
if extracted_action == "reply":
action_data = {
"text": parsed_json.get("text", []),
"emojis": parsed_json.get("emojis", []),
"target": parsed_json.get("target", ""),
}
else:
action_data = {} # 其他动作可能不需要额外数据
if extracted_action not in current_available_actions:
logger.warning(
f"{self.log_prefix}LLM 返回了当前不可用或无效的动作: '{extracted_action}' (可用: {list(current_available_actions.keys())}),将强制使用 'no_reply'"
)
action = "no_reply"
reasoning = f"LLM 返回了当前不可用的动作 '{extracted_action}' (可用: {list(current_available_actions.keys())})。原始理由: {extracted_reasoning}"
else:
# 动作有效且可用
action = extracted_action
reasoning = extracted_reasoning
except Exception as json_e:
logger.warning(
f"{self.log_prefix}解析LLM响应JSON失败模型返回不标准: {json_e}. LLM原始输出: '{llm_content}'"
)
reasoning = f"解析LLM响应JSON失败: {json_e}. 将使用默认动作 'no_reply'."
action = "no_reply"
except Exception as outer_e:
logger.error(f"{self.log_prefix}Planner 处理过程中发生意外错误,规划失败,将执行 no_reply: {outer_e}")
traceback.print_exc()
action = "no_reply" # 发生未知错误,标记为 error 动作
reasoning = f"Planner 内部处理错误: {outer_e}"
logger.debug(
f"{self.log_prefix}规划器Prompt:\n{prompt}\n\n决策动作:{action},\n动作信息: '{action_data}'\n理由: {reasoning}"
)
# 恢复原始动作集
ActionFactory.restore_actions()
logger.debug(
f"{self.log_prefix}恢复了原始动作集, 当前可用: {list(ActionFactory.get_available_actions().keys())}"
)
action_result = {"action_type": action, "action_data": action_data, "reasoning": reasoning}
plan_result = {
"action_result": action_result,
"current_mind": current_mind,
"observed_messages": observed_messages,
}
# 返回结果字典
return plan_result

View File

@@ -19,7 +19,7 @@ from src.chat.heart_flow.utils_chat import get_chat_type_and_target_info
from src.chat.utils.prompt_builder import Prompt from src.chat.utils.prompt_builder import Prompt
logger = get_logger(__name__) logger = get_logger("observation")
Prompt( Prompt(

View File

@@ -23,19 +23,16 @@ class HFCloopObservation:
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_type: {loop_info.action_type}")
print(f"response_info: {loop_info.response_info}")
self.history_loop.append(loop_info) self.history_loop.append(loop_info)
async def observe(self): async def observe(self):
recent_active_cycles: List[CycleDetail] = [] recent_active_cycles: List[CycleDetail] = []
for cycle in reversed(self.history_loop): for cycle in reversed(self.history_loop):
# 只关心实际执行了动作的循环 # 只关心实际执行了动作的循环
if cycle.action_taken: action_taken = cycle.loop_action_info["action_taken"]
if action_taken:
recent_active_cycles.append(cycle) recent_active_cycles.append(cycle)
# 最多找最近的3个活动循环 if len(recent_active_cycles) == 5:
if len(recent_active_cycles) == 3:
break break
cycle_info_block = "" cycle_info_block = ""
@@ -44,10 +41,10 @@ class HFCloopObservation:
# 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看) # 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看)
for cycle in recent_active_cycles: for cycle in recent_active_cycles:
if cycle.action_type == "reply": action_type = cycle.loop_plan_info["action_result"]["action_type"]
if action_type == "reply":
consecutive_text_replies += 1 consecutive_text_replies += 1
# 获取回复内容,如果不存在则返回'[空回复]' response_text = cycle.loop_plan_info["action_result"]["action_data"].get("text", "[空回复]")
response_text = cycle.response_info.get("response_text", "[空回复]")
responses_for_prompt.append(response_text) responses_for_prompt.append(response_text)
else: else:
break break
@@ -70,7 +67,7 @@ class HFCloopObservation:
# 获取history_loop中最新添加的 # 获取history_loop中最新添加的
if self.history_loop: if self.history_loop:
last_loop = self.history_loop[-1] last_loop = self.history_loop[0]
start_time = last_loop.start_time start_time = last_loop.start_time
end_time = last_loop.end_time end_time = last_loop.end_time
if start_time is not None and end_time is not None: if start_time is not None and end_time is not None:

View File

@@ -71,8 +71,9 @@ def get_raw_msg_by_timestamp_random(
# 随机选一条 # 随机选一条
msg = random.choice(all_msgs) msg = random.choice(all_msgs)
chat_id = msg["chat_id"] chat_id = msg["chat_id"]
timestamp_start = msg["time"]
# 用 chat_id 获取该聊天在指定时间戳范围内的消息 # 用 chat_id 获取该聊天在指定时间戳范围内的消息
return get_raw_msg_by_timestamp_with_chat(chat_id, timestamp_start, timestamp_end, limit, limit_mode) return get_raw_msg_by_timestamp_with_chat(chat_id, timestamp_start, timestamp_end, limit, "earliest")
def get_raw_msg_by_timestamp_with_users( def get_raw_msg_by_timestamp_with_users(
@@ -331,7 +332,7 @@ async def _build_readable_messages_internal(
stripped_line = stripped_line[:-1] stripped_line = stripped_line[:-1]
# 如果内容被截断,结尾已经是 ...(内容太长),不再添加分号 # 如果内容被截断,结尾已经是 ...(内容太长),不再添加分号
if not stripped_line.endswith("(内容太长)"): if not stripped_line.endswith("(内容太长)"):
output_lines.append(f"{stripped_line};") output_lines.append(f"{stripped_line}")
else: else:
output_lines.append(stripped_line) # 直接添加截断后的内容 output_lines.append(stripped_line) # 直接添加截断后的内容
output_lines.append("\n") # 在每个消息块后添加换行,保持可读性 output_lines.append("\n") # 在每个消息块后添加换行,保持可读性
@@ -416,15 +417,25 @@ async def build_readable_messages(
async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str: async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
""" """
构建匿名可读消息将不同人的名称转为唯一占位符A、B、C...bot自己用SELF。 构建匿名可读消息将不同人的名称转为唯一占位符A、B、C...bot自己用SELF。
处理 回复<aaa:bbb> 和 @<aaa:bbb> 字段将bbb映射为匿名占位符。
""" """
if not messages: if not messages:
return "" return ""
# 分配占位符
person_map = {} person_map = {}
current_char = ord('A') current_char = ord("A")
output_lines = [] output_lines = []
def get_anon_name(platform, user_id):
if user_id == global_config.BOT_QQ:
return "SELF"
person_id = person_info_manager.get_person_id(platform, user_id)
if person_id not in person_map:
nonlocal current_char
person_map[person_id] = chr(current_char)
current_char += 1
return person_map[person_id]
for msg in messages: for msg in messages:
user_info = msg.get("user_info", {}) user_info = msg.get("user_info", {})
platform = user_info.get("platform") platform = user_info.get("platform")
@@ -435,25 +446,37 @@ async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
if not all([platform, user_id, timestamp is not None]): if not all([platform, user_id, timestamp is not None]):
continue continue
# 判断是否为bot anon_name = get_anon_name(platform, user_id)
if user_id == global_config.BOT_QQ:
anon_name = "SELF"
else:
person_id = person_info_manager.get_person_id(platform, user_id)
if person_id not in person_map:
person_map[person_id] = chr(current_char)
current_char += 1
anon_name = person_map[person_id]
# 格式化时间 # 处理 回复<aaa:bbb>
readable_time = translate_timestamp_to_human_readable(timestamp, mode="relative") reply_pattern = r"回复<([^:<>]+):([^:<>]+)>"
header = f"{readable_time}{anon_name}说:"
def reply_replacer(match):
aaa = match.group(1)
bbb = match.group(2)
anon_reply = get_anon_name(platform, bbb)
return f"回复 {anon_reply}"
content = re.sub(reply_pattern, reply_replacer, content, count=1)
# 处理 @<aaa:bbb>
at_pattern = r"@<([^:<>]+):([^:<>]+)>"
def at_replacer(match):
aaa = match.group(1)
bbb = match.group(2)
anon_at = get_anon_name(platform, bbb)
return f"@{anon_at}"
content = re.sub(at_pattern, at_replacer, content)
header = f"{anon_name}"
output_lines.append(header) output_lines.append(header)
stripped_line = content.strip() stripped_line = content.strip()
if stripped_line: if stripped_line:
if stripped_line.endswith(""): if stripped_line.endswith(""):
stripped_line = stripped_line[:-1] stripped_line = stripped_line[:-1]
output_lines.append(f"{stripped_line};") output_lines.append(f"{stripped_line}")
output_lines.append("\n") output_lines.append("\n")
formatted_string = "".join(output_lines).strip() formatted_string = "".join(output_lines).strip()

View File

@@ -61,7 +61,7 @@ else:
"console_level": "INFO", "console_level": "INFO",
"file_level": "DEBUG", "file_level": "DEBUG",
# 格式配置 # 格式配置
"console_format": "<level>{time:MM-DD HH:mm}</level> | <cyan>{extra[module]}</cyan> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <cyan>{extra[module]}</cyan> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | {message}",
"log_dir": LOG_ROOT, "log_dir": LOG_ROOT,
"rotation": "00:00", "rotation": "00:00",
@@ -82,7 +82,7 @@ MAIN_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-yellow>主程序</light-yellow> | <light-yellow>{message}</light-yellow>" "<level>{time:HH:mm:ss}</level> | <light-yellow>主程序</light-yellow> | <light-yellow>{message}</light-yellow>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 主程序 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 主程序 | {message}",
}, },
@@ -101,7 +101,7 @@ PFC_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-green>PFC</light-green> | <light-green>{message}</light-green>" "<level>{time:HH:mm:ss}</level> | <light-green>PFC</light-green> | <light-green>{message}</light-green>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC | {message}",
}, },
@@ -119,7 +119,7 @@ MOOD_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <magenta>心情 | {message} </magenta>", "console_format": "<level>{time:HH:mm:ss}</level> | <magenta>心情 | {message} </magenta>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}",
}, },
} }
@@ -135,7 +135,7 @@ TOOL_USE_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <magenta>工具使用</magenta> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <magenta>工具使用</magenta> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}",
}, },
} }
@@ -153,7 +153,7 @@ RELATION_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-magenta>关系</light-magenta> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-magenta>关系</light-magenta> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系 | {message}",
}, },
} }
@@ -170,7 +170,7 @@ CONFIG_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 配置 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 配置 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-cyan>配置</light-cyan> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-cyan>配置</light-cyan> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 配置 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 配置 | {message}",
}, },
} }
@@ -186,7 +186,7 @@ SENDER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息发送 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息发送 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <green>消息发送</green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <green>消息发送</green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息发送 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息发送 | {message}",
}, },
} }
@@ -203,7 +203,7 @@ HEARTFLOW_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-green>麦麦大脑袋</light-green> | <light-green>{message}</light-green>" "<level>{time:HH:mm:ss}</level> | <light-green>麦麦大脑袋</light-green> | <light-green>{message}</light-green>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦大脑袋 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦大脑袋 | {message}",
}, },
@@ -220,7 +220,7 @@ SCHEDULE_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 在干嘛 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 在干嘛 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <cyan>在干嘛</cyan> | <cyan>{message}</cyan>", "console_format": "<level>{time:HH:mm:ss}</level> | <cyan>在干嘛</cyan> | <cyan>{message}</cyan>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 在干嘛 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 在干嘛 | {message}",
}, },
} }
@@ -236,7 +236,7 @@ LLM_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦组织语言 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦组织语言 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>麦麦组织语言</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>麦麦组织语言</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦组织语言 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦组织语言 | {message}",
}, },
} }
@@ -254,7 +254,7 @@ TOPIC_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 话题 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 话题 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-blue>主题</light-blue> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-blue>主题</light-blue> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 话题 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 话题 | {message}",
}, },
} }
@@ -271,7 +271,7 @@ CHAT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <green>见闻</green> | <green>{message}</green>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <green>见闻</green> | <green>{message}</green>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
}, },
} }
@@ -287,7 +287,7 @@ REMOTE_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #00788A>远程| {message}</fg #00788A>", "console_format": "<level>{time:HH:mm:ss}</level> | <fg #00788A>远程| {message}</fg #00788A>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
}, },
} }
@@ -303,7 +303,7 @@ SUB_HEARTFLOW_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #3399FF>麦麦水群 | {message}</fg #3399FF>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #3399FF>麦麦水群 | {message}</fg #3399FF>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群 | {message}",
}, },
} }
@@ -319,7 +319,7 @@ INTEREST_CHAT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #55DDFF>兴趣 | {message}</fg #55DDFF>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #55DDFF>兴趣 | {message}</fg #55DDFF>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}",
}, },
} }
@@ -336,7 +336,7 @@ SUB_HEARTFLOW_MIND_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #66CCFF>麦麦小脑袋 | {message}</fg #66CCFF>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #66CCFF>麦麦小脑袋 | {message}</fg #66CCFF>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}",
}, },
} }
@@ -352,7 +352,7 @@ SUBHEARTFLOW_MANAGER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群[管理] | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群[管理] | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #005BA2>麦麦水群[管理] | {message}</fg #005BA2>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #005BA2>麦麦水群[管理] | {message}</fg #005BA2>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群[管理] | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群[管理] | {message}",
}, },
} }
@@ -369,7 +369,7 @@ BASE_TOOL_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-blue>工具使用</light-blue> | <light-blue>{message}</light-blue>" "<level>{time:HH:mm:ss}</level> | <light-blue>工具使用</light-blue> | <light-blue>{message}</light-blue>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}",
}, },
@@ -387,7 +387,7 @@ CHAT_STREAM_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-blue>聊天流</light-blue> | <light-blue>{message}</light-blue>" "<level>{time:HH:mm:ss}</level> | <light-blue>聊天流</light-blue> | <light-blue>{message}</light-blue>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天流 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天流 | {message}",
}, },
@@ -405,7 +405,7 @@ CHAT_MESSAGE_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-blue>聊天消息</light-blue> | <light-blue>{message}</light-blue>" "<level>{time:HH:mm:ss}</level> | <light-blue>聊天消息</light-blue> | <light-blue>{message}</light-blue>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天消息 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天消息 | {message}",
}, },
@@ -423,7 +423,7 @@ PERSON_INFO_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-blue>人物信息</light-blue> | <light-blue>{message}</light-blue>" "<level>{time:HH:mm:ss}</level> | <light-blue>人物信息</light-blue> | <light-blue>{message}</light-blue>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 人物信息 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 人物信息 | {message}",
}, },
@@ -441,7 +441,7 @@ BACKGROUND_TASKS_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-blue>后台任务</light-blue> | <light-blue>{message}</light-blue>" "<level>{time:HH:mm:ss}</level> | <light-blue>后台任务</light-blue> | <light-blue>{message}</light-blue>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 后台任务 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 后台任务 | {message}",
}, },
@@ -458,7 +458,7 @@ WILLING_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 意愿 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 意愿 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-blue>意愿 | {message} </light-blue>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <light-blue>意愿 | {message} </light-blue>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 意愿 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 意愿 | {message}",
}, },
} }
@@ -474,7 +474,7 @@ PFC_ACTION_PLANNER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC私聊规划 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC私聊规划 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-blue>PFC私聊规划 | {message} </light-blue>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <light-blue>PFC私聊规划 | {message} </light-blue>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC私聊规划 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | PFC私聊规划 | {message}",
}, },
} }
@@ -491,7 +491,7 @@ EMOJI_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 表情包 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 表情包 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #FFD700>表情包 | {message} </fg #FFD700>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #FFD700>表情包 | {message} </fg #FFD700>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 表情包 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 表情包 | {message}",
}, },
} }
@@ -507,7 +507,7 @@ MAI_STATE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦状态 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦状态 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <fg #66CCFF>麦麦状态 | {message} </fg #66CCFF>", # noqa: E501 "console_format": "<level>{time:HH:mm:ss}</level> | <fg #66CCFF>麦麦状态 | {message} </fg #66CCFF>", # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦状态 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦状态 | {message}",
}, },
} }
@@ -526,7 +526,7 @@ MEMORY_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <fg #7CFFE6>海马体</fg #7CFFE6> | <fg #7CFFE6>{message}</fg #7CFFE6>" "<level>{time:HH:mm:ss}</level> | <fg #7CFFE6>海马体</fg #7CFFE6> | <fg #7CFFE6>{message}</fg #7CFFE6>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 海马体 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 海马体 | {message}",
}, },
@@ -546,29 +546,29 @@ LPMM_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <fg #37FFB4>LPMM</fg #37FFB4> | <fg #37FFB4>{message}</fg #37FFB4>" "<level>{time:HH:mm:ss}</level> | <fg #37FFB4>LPMM</fg #37FFB4> | <fg #37FFB4>{message}</fg #37FFB4>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM | {message}",
}, },
} }
OBSERVATION_STYLE_CONFIG = { # OBSERVATION_STYLE_CONFIG = {
"advanced": { # "advanced": {
"console_format": ( # "console_format": (
"<white>{time:YYYY-MM-DD HH:mm:ss}</white> | " # "<white>{time:YYYY-MM-DD HH:mm:ss}</white> | "
"<level>{level: <8}</level> | " # "<level>{level: <8}</level> | "
"<light-yellow>聊天观察</light-yellow> | " # "<light-yellow>聊天观察</light-yellow> | "
"<level>{message}</level>" # "<level>{message}</level>"
), # ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}", # "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
}, # },
"simple": { # "simple": {
"console_format": ( # "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-yellow>聊天观察</light-yellow> | <light-yellow>{message}</light-yellow>" # "<level>{time:HH:mm:ss}</level> | <light-yellow>聊天观察</light-yellow> | <light-yellow>{message}</light-yellow>"
), # noqa: E501 # ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}", # "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
}, # },
} # }
CHAT_IMAGE_STYLE_CONFIG = { CHAT_IMAGE_STYLE_CONFIG = {
"advanced": { "advanced": {
@@ -582,7 +582,7 @@ CHAT_IMAGE_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-yellow>聊天图片</light-yellow> | <light-yellow>{message}</light-yellow>" "<level>{time:HH:mm:ss}</level> | <light-yellow>聊天图片</light-yellow> | <light-yellow>{message}</light-yellow>"
), # noqa: E501 ), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天图片 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天图片 | {message}",
}, },
@@ -600,11 +600,55 @@ HFC_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>专注聊天 | {message}</light-green>", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>专注聊天 | {message}</light-green>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}",
}, },
} }
OBSERVATION_STYLE_CONFIG = {
"advanced": {
"console_format": "<level>{time:HH:mm:ss}</level> | <light-yellow>观察</light-yellow> | <light-yellow>{message}</light-yellow>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 观察 | {message}",
},
"simple": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #66CCFF>观察</fg #66CCFF> | <fg #66CCFF>{message}</fg #66CCFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 观察 | {message}",
},
}
PROCESSOR_STYLE_CONFIG = {
"advanced": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #54DDFF>处理器</fg #54DDFF> | <fg #54DDFF>{message}</fg #54DDFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 处理器 | {message}",
},
"simple": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #54DDFF>处理器</fg #54DDFF> | <fg #54DDFF>{message}</fg #54DDFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 处理器 | {message}",
},
}
PLANNER_STYLE_CONFIG = {
"advanced": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #36DEFF>规划器</fg #36DEFF> | <fg #36DEFF>{message}</fg #36DEFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 规划器 | {message}",
},
"simple": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #36DEFF>规划器</fg #36DEFF> | <fg #36DEFF>{message}</fg #36DEFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 规划器 | {message}",
},
}
ACTION_TAKEN_STYLE_CONFIG = {
"advanced": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #22DAFF>动作</fg #22DAFF> | <fg #22DAFF>{message}</fg #22DAFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 动作 | {message}",
},
"simple": {
"console_format": "<level>{time:HH:mm:ss}</level> | <fg #22DAFF>动作</fg #22DAFF> | <fg #22DAFF>{message}</fg #22DAFF>",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 动作 | {message}",
},
}
CONFIRM_STYLE_CONFIG = { CONFIRM_STYLE_CONFIG = {
"console_format": "<RED>{message}</RED>", # noqa: E501 "console_format": "<RED>{message}</RED>", # noqa: E501
@@ -624,7 +668,7 @@ TIANYI_STYLE_CONFIG = {
}, },
"simple": { "simple": {
"console_format": ( "console_format": (
"<level>{time:MM-DD HH:mm}</level> | <fg #66CCFF>天依</fg #66CCFF> | <fg #66CCFF>{message}</fg #66CCFF>" "<level>{time:HH:mm:ss}</level> | <fg #66CCFF>天依</fg #66CCFF> | <fg #66CCFF>{message}</fg #66CCFF>"
), ),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 天依 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 天依 | {message}",
}, },
@@ -642,7 +686,7 @@ MODEL_UTILS_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 模型 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 模型 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>模型</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>模型</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 模型 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 模型 | {message}",
}, },
} }
@@ -658,7 +702,7 @@ MESSAGE_BUFFER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息缓存 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息缓存 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>消息缓存</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>消息缓存</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息缓存 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息缓存 | {message}",
}, },
} }
@@ -674,7 +718,7 @@ PROMPT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 提示词构建 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 提示词构建 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>提示词构建</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>提示词构建</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 提示词构建 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 提示词构建 | {message}",
}, },
} }
@@ -690,7 +734,7 @@ CHANGE_MOOD_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情工具 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情工具 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>心情工具</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>心情工具</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情工具 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情工具 | {message}",
}, },
} }
@@ -706,7 +750,7 @@ CHANGE_RELATIONSHIP_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系工具 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系工具 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>关系工具</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>关系工具</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系工具 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系工具 | {message}",
}, },
} }
@@ -722,7 +766,7 @@ GET_KNOWLEDGE_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取知识 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取知识 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>获取知识</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>获取知识</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取知识 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取知识 | {message}",
}, },
} }
@@ -738,7 +782,7 @@ GET_TIME_DATE_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取时间日期 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取时间日期 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>获取时间日期</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>获取时间日期</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取时间日期 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取时间日期 | {message}",
}, },
} }
@@ -754,7 +798,7 @@ LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM获取知识 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM获取知识 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>LPMM获取知识</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>LPMM获取知识</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM获取知识 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | LPMM获取知识 | {message}",
}, },
} }
@@ -770,7 +814,7 @@ INIT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 初始化 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 初始化 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>初始化</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>初始化</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 初始化 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 初始化 | {message}",
}, },
} }
@@ -786,7 +830,7 @@ API_SERVER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | API服务 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | API服务 | {message}",
}, },
"simple": { "simple": {
"console_format": "<level>{time:MM-DD HH:mm}</level> | <light-green>API服务</light-green> | {message}", "console_format": "<level>{time:HH:mm:ss}</level> | <light-green>API服务</light-green> | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | API服务 | {message}", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | API服务 | {message}",
}, },
} }
@@ -830,6 +874,12 @@ TOOL_USE_STYLE_CONFIG = TOOL_USE_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else TO
PFC_STYLE_CONFIG = PFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PFC_STYLE_CONFIG["advanced"] PFC_STYLE_CONFIG = PFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PFC_STYLE_CONFIG["advanced"]
LPMM_STYLE_CONFIG = LPMM_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else LPMM_STYLE_CONFIG["advanced"] LPMM_STYLE_CONFIG = LPMM_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else LPMM_STYLE_CONFIG["advanced"]
HFC_STYLE_CONFIG = HFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else HFC_STYLE_CONFIG["advanced"] HFC_STYLE_CONFIG = HFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else HFC_STYLE_CONFIG["advanced"]
ACTION_TAKEN_STYLE_CONFIG = (
ACTION_TAKEN_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else ACTION_TAKEN_STYLE_CONFIG["advanced"]
)
OBSERVATION_STYLE_CONFIG = OBSERVATION_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else OBSERVATION_STYLE_CONFIG["advanced"]
PLANNER_STYLE_CONFIG = PLANNER_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PLANNER_STYLE_CONFIG["advanced"]
PROCESSOR_STYLE_CONFIG = PROCESSOR_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PROCESSOR_STYLE_CONFIG["advanced"]
TIANYI_STYLE_CONFIG = TIANYI_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else TIANYI_STYLE_CONFIG["advanced"] TIANYI_STYLE_CONFIG = TIANYI_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else TIANYI_STYLE_CONFIG["advanced"]
MODEL_UTILS_STYLE_CONFIG = MODEL_UTILS_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else MODEL_UTILS_STYLE_CONFIG["advanced"] MODEL_UTILS_STYLE_CONFIG = MODEL_UTILS_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else MODEL_UTILS_STYLE_CONFIG["advanced"]
PROMPT_STYLE_CONFIG = PROMPT_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PROMPT_STYLE_CONFIG["advanced"] PROMPT_STYLE_CONFIG = PROMPT_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PROMPT_STYLE_CONFIG["advanced"]
@@ -852,7 +902,7 @@ LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG = (
if SIMPLE_OUTPUT if SIMPLE_OUTPUT
else LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG["advanced"] else LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG["advanced"]
) )
OBSERVATION_STYLE_CONFIG = OBSERVATION_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else OBSERVATION_STYLE_CONFIG["advanced"] # OBSERVATION_STYLE_CONFIG = OBSERVATION_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else OBSERVATION_STYLE_CONFIG["advanced"]
MESSAGE_BUFFER_STYLE_CONFIG = ( MESSAGE_BUFFER_STYLE_CONFIG = (
MESSAGE_BUFFER_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else MESSAGE_BUFFER_STYLE_CONFIG["advanced"] MESSAGE_BUFFER_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else MESSAGE_BUFFER_STYLE_CONFIG["advanced"]
) )

View File

@@ -23,6 +23,10 @@ from src.common.logger import (
MAI_STATE_CONFIG, MAI_STATE_CONFIG,
LPMM_STYLE_CONFIG, LPMM_STYLE_CONFIG,
HFC_STYLE_CONFIG, HFC_STYLE_CONFIG,
OBSERVATION_STYLE_CONFIG,
PLANNER_STYLE_CONFIG,
PROCESSOR_STYLE_CONFIG,
ACTION_TAKEN_STYLE_CONFIG,
TIANYI_STYLE_CONFIG, TIANYI_STYLE_CONFIG,
REMOTE_STYLE_CONFIG, REMOTE_STYLE_CONFIG,
TOPIC_STYLE_CONFIG, TOPIC_STYLE_CONFIG,
@@ -35,7 +39,6 @@ from src.common.logger import (
GET_KNOWLEDGE_TOOL_STYLE_CONFIG, GET_KNOWLEDGE_TOOL_STYLE_CONFIG,
GET_TIME_DATE_TOOL_STYLE_CONFIG, GET_TIME_DATE_TOOL_STYLE_CONFIG,
LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG, LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG,
OBSERVATION_STYLE_CONFIG,
MESSAGE_BUFFER_STYLE_CONFIG, MESSAGE_BUFFER_STYLE_CONFIG,
CHAT_MESSAGE_STYLE_CONFIG, CHAT_MESSAGE_STYLE_CONFIG,
CHAT_IMAGE_STYLE_CONFIG, CHAT_IMAGE_STYLE_CONFIG,
@@ -69,6 +72,10 @@ MODULE_LOGGER_CONFIGS = {
"mai_state": MAI_STATE_CONFIG, # 麦麦状态 "mai_state": MAI_STATE_CONFIG, # 麦麦状态
"lpmm": LPMM_STYLE_CONFIG, # LPMM "lpmm": LPMM_STYLE_CONFIG, # LPMM
"hfc": HFC_STYLE_CONFIG, # HFC "hfc": HFC_STYLE_CONFIG, # HFC
"observation": OBSERVATION_STYLE_CONFIG, # 聊天观察
"planner": PLANNER_STYLE_CONFIG, # 规划器
"processor": PROCESSOR_STYLE_CONFIG, # 处理器
"action_taken": ACTION_TAKEN_STYLE_CONFIG, # 动作
"tianyi": TIANYI_STYLE_CONFIG, # 天依 "tianyi": TIANYI_STYLE_CONFIG, # 天依
"remote": REMOTE_STYLE_CONFIG, # 远程 "remote": REMOTE_STYLE_CONFIG, # 远程
"topic": TOPIC_STYLE_CONFIG, # 话题 "topic": TOPIC_STYLE_CONFIG, # 话题
@@ -81,7 +88,6 @@ MODULE_LOGGER_CONFIGS = {
"get_knowledge_tool": GET_KNOWLEDGE_TOOL_STYLE_CONFIG, # 获取知识工具 "get_knowledge_tool": GET_KNOWLEDGE_TOOL_STYLE_CONFIG, # 获取知识工具
"get_time_date": GET_TIME_DATE_TOOL_STYLE_CONFIG, # 获取时间日期工具 "get_time_date": GET_TIME_DATE_TOOL_STYLE_CONFIG, # 获取时间日期工具
"lpm_get_knowledge_tool": LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG, # LPMM获取知识工具 "lpm_get_knowledge_tool": LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG, # LPMM获取知识工具
"observation": OBSERVATION_STYLE_CONFIG, # 聊天观察
"message_buffer": MESSAGE_BUFFER_STYLE_CONFIG, # 消息缓冲 "message_buffer": MESSAGE_BUFFER_STYLE_CONFIG, # 消息缓冲
"chat_message": CHAT_MESSAGE_STYLE_CONFIG, # 聊天消息 "chat_message": CHAT_MESSAGE_STYLE_CONFIG, # 聊天消息
"chat_image": CHAT_IMAGE_STYLE_CONFIG, # 聊天图片 "chat_image": CHAT_IMAGE_STYLE_CONFIG, # 聊天图片