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.chat.models.utils_model import LLMRequest
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
import os
import json
MAX_EXPRESSION_COUNT = 300
MAX_EXPRESSION_COUNT = 100
logger = get_logger("expressor")
@@ -19,7 +19,7 @@ def init_prompt() -> None:
learn_style_prompt = """
{chat_str}
请从上面这段群聊中概括除了人名为"麦麦"之外的人的语言风格,只考虑文字,不要考虑表情包和图片
请从上面这段群聊中概括除了人名为"SELF"之外的人的语言风格,只考虑文字,不要考虑表情包和图片
不要涉及具体的人名,只考虑语言风格
语言风格包含特殊内容和情感
思考有没有特殊的梗,一并总结成语言风格
@@ -57,7 +57,7 @@ def init_prompt() -> None:
learn_grammar_prompt = """
{chat_str}
请从上面这段群聊中概括除了人名为"麦麦"之外的人的语法和句法特点,只考虑纯文字,不要考虑表情包和图片
请从上面这段群聊中概括除了人名为"SELF"之外的人的语法和句法特点,只考虑纯文字,不要考虑表情包和图片
不要总结【图片】,【动画表情】,[图片][动画表情],不总结 表情符号 at @ 回复 和[回复]
不要涉及具体的人名,只考虑语法和句法特点,
语法和句法特点要包括,句子长短(具体字数),有何种语病,如何拆分句子。
@@ -65,9 +65,9 @@ def init_prompt() -> None:
"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:
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:
return []
@@ -233,7 +233,7 @@ class ExpressionLearner:
chat_str=random_msg_str,
)
logger.info(f"学习{type_str}的prompt: {prompt}")
# logger.info(f"学习{type_str}的prompt: {prompt}")
try:
response, _ = await self.express_learn_model.generate_response_async(prompt)
@@ -291,7 +291,7 @@ class ExpressionLearner:
"personality_expression_prompt",
personality=global_config.expression_style,
)
logger.info(f"个性表达方式提取prompt: {prompt}")
# logger.info(f"个性表达方式提取prompt: {prompt}")
try:
response, _ = await self.express_learn_model.generate_response_async(prompt)

View File

@@ -1,6 +1,5 @@
import time
import os
import json
from typing import List, Optional, Dict, Any
@@ -9,45 +8,16 @@ class CycleDetail:
def __init__(self, cycle_id: int):
self.cycle_id = cycle_id
self.thinking_id = ""
self.start_time = time.time()
self.end_time: Optional[float] = None
self.action_taken = False
self.action_type = "unknown"
self.reasoning = ""
self.timers: Dict[str, float] = {}
self.thinking_id = ""
self.replanned = False
# 添加响应信息相关字段
self.response_info: Dict[str, Any] = {
"response_text": [], # 回复的文本列表
"emoji_info": "", # 表情信息
"anchor_message_id": "", # 锚点消息ID
"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": {}, # 解析后的结果
}
# 字段
self.loop_observation_info: Dict[str, Any] = {}
self.loop_process_info: Dict[str, Any] = {}
self.loop_plan_info: Dict[str, Any] = {}
self.loop_action_info: Dict[str, Any] = {}
def to_dict(self) -> Dict[str, Any]:
"""将循环信息转换为字典格式"""
@@ -55,229 +25,28 @@ class CycleDetail:
"cycle_id": self.cycle_id,
"start_time": self.start_time,
"end_time": self.end_time,
"action_taken": self.action_taken,
"action_type": self.action_type,
"reasoning": self.reasoning,
"timers": self.timers,
"thinking_id": self.thinking_id,
"response_info": self.response_info,
"submind_info": self.submind_info,
"tooluse_info": self.tooluse_info,
"planner_info": self.planner_info,
"loop_observation_info": self.loop_observation_info,
"loop_process_info": self.loop_process_info,
"loop_plan_info": self.loop_plan_info,
"loop_action_info": self.loop_action_info,
}
def complete_cycle(self):
"""完成循环,记录结束时间"""
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):
"""设置思考消息ID"""
self.thinking_id = thinking_id
def set_response_info(
self,
response_text: Optional[List[str]] = None,
emoji_info: Optional[str] = None,
anchor_message_id: Optional[str] = None,
reply_message_ids: Optional[List[str]] = None,
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
def set_loop_info(self, loop_info: Dict[str, Any]):
"""设置循环信息"""
self.loop_observation_info = loop_info["loop_observation_info"]
self.loop_processor_info = loop_info["loop_processor_info"]
self.loop_plan_info = loop_info["loop_plan_info"]
self.loop_action_info = loop_info["loop_action_info"]
@staticmethod
def list_cycles(stream_id: str, base_dir: str = "log_debug") -> List[str]:

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,19 +23,16 @@ class HFCloopObservation:
def add_loop_info(self, loop_info: CycleDetail):
# logger.debug(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)
async def observe(self):
recent_active_cycles: List[CycleDetail] = []
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)
# 最多找最近的3个活动循环
if len(recent_active_cycles) == 3:
if len(recent_active_cycles) == 5:
break
cycle_info_block = ""
@@ -44,10 +41,10 @@ class HFCloopObservation:
# 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看)
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
# 获取回复内容,如果不存在则返回'[空回复]'
response_text = cycle.response_info.get("response_text", "[空回复]")
response_text = cycle.loop_plan_info["action_result"]["action_data"].get("text", "[空回复]")
responses_for_prompt.append(response_text)
else:
break
@@ -70,7 +67,7 @@ class HFCloopObservation:
# 获取history_loop中最新添加的
if self.history_loop:
last_loop = self.history_loop[-1]
last_loop = self.history_loop[0]
start_time = last_loop.start_time
end_time = last_loop.end_time
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)
chat_id = msg["chat_id"]
timestamp_start = msg["time"]
# 用 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(
@@ -331,7 +332,7 @@ async def _build_readable_messages_internal(
stripped_line = stripped_line[:-1]
# 如果内容被截断,结尾已经是 ...(内容太长),不再添加分号
if not stripped_line.endswith("(内容太长)"):
output_lines.append(f"{stripped_line};")
output_lines.append(f"{stripped_line}")
else:
output_lines.append(stripped_line) # 直接添加截断后的内容
output_lines.append("\n") # 在每个消息块后添加换行,保持可读性
@@ -416,15 +417,25 @@ async def build_readable_messages(
async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
"""
构建匿名可读消息将不同人的名称转为唯一占位符A、B、C...bot自己用SELF。
处理 回复<aaa:bbb> 和 @<aaa:bbb> 字段将bbb映射为匿名占位符。
"""
if not messages:
return ""
# 分配占位符
person_map = {}
current_char = ord('A')
current_char = ord("A")
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:
user_info = msg.get("user_info", {})
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]):
continue
# 判断是否为bot
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]
anon_name = get_anon_name(platform, user_id)
# 格式化时间
readable_time = translate_timestamp_to_human_readable(timestamp, mode="relative")
header = f"{readable_time}{anon_name}说:"
# 处理 回复<aaa:bbb>
reply_pattern = r"回复<([^:<>]+):([^:<>]+)>"
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)
stripped_line = content.strip()
if stripped_line:
if stripped_line.endswith(""):
stripped_line = stripped_line[:-1]
output_lines.append(f"{stripped_line};")
output_lines.append(f"{stripped_line}")
output_lines.append("\n")
formatted_string = "".join(output_lines).strip()

View File

@@ -61,7 +61,7 @@ else:
"console_level": "INFO",
"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}",
"log_dir": LOG_ROOT,
"rotation": "00:00",
@@ -82,7 +82,7 @@ MAIN_STYLE_CONFIG = {
},
"simple": {
"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}",
},
@@ -101,7 +101,7 @@ PFC_STYLE_CONFIG = {
},
"simple": {
"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}",
},
@@ -119,7 +119,7 @@ MOOD_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}",
},
"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}",
},
}
@@ -135,7 +135,7 @@ TOOL_USE_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}",
},
"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}",
},
}
@@ -153,7 +153,7 @@ RELATION_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系 | {message}",
},
"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}",
},
}
@@ -170,7 +170,7 @@ CONFIG_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 配置 | {message}",
},
"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}",
},
}
@@ -186,7 +186,7 @@ SENDER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息发送 | {message}",
},
"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}",
},
}
@@ -203,7 +203,7 @@ HEARTFLOW_STYLE_CONFIG = {
},
"simple": {
"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
"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}",
},
"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}",
},
}
@@ -236,7 +236,7 @@ LLM_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦组织语言 | {message}",
},
"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}",
},
}
@@ -254,7 +254,7 @@ TOPIC_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 话题 | {message}",
},
"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}",
},
}
@@ -271,7 +271,7 @@ CHAT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 见闻 | {message}",
},
"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}",
},
}
@@ -287,7 +287,7 @@ REMOTE_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 远程 | {message}",
},
"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}",
},
}
@@ -303,7 +303,7 @@ SUB_HEARTFLOW_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}",
},
"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}",
},
}
@@ -319,7 +319,7 @@ INTEREST_CHAT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}",
},
"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}",
},
}
@@ -336,7 +336,7 @@ SUB_HEARTFLOW_MIND_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦小脑袋 | {message}",
},
"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}",
},
}
@@ -352,7 +352,7 @@ SUBHEARTFLOW_MANAGER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦水群[管理] | {message}",
},
"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}",
},
}
@@ -369,7 +369,7 @@ BASE_TOOL_STYLE_CONFIG = {
},
"simple": {
"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
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 工具使用 | {message}",
},
@@ -387,7 +387,7 @@ CHAT_STREAM_STYLE_CONFIG = {
},
"simple": {
"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}",
},
@@ -405,7 +405,7 @@ CHAT_MESSAGE_STYLE_CONFIG = {
},
"simple": {
"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
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天消息 | {message}",
},
@@ -423,7 +423,7 @@ PERSON_INFO_STYLE_CONFIG = {
},
"simple": {
"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
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 人物信息 | {message}",
},
@@ -441,7 +441,7 @@ BACKGROUND_TASKS_STYLE_CONFIG = {
},
"simple": {
"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
"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}",
},
"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}",
},
}
@@ -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}",
},
"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}",
},
}
@@ -491,7 +491,7 @@ EMOJI_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 表情包 | {message}",
},
"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}",
},
}
@@ -507,7 +507,7 @@ MAI_STATE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 麦麦状态 | {message}",
},
"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}",
},
}
@@ -526,7 +526,7 @@ MEMORY_STYLE_CONFIG = {
},
"simple": {
"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}",
},
@@ -546,29 +546,29 @@ LPMM_STYLE_CONFIG = {
},
"simple": {
"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}",
},
}
OBSERVATION_STYLE_CONFIG = {
"advanced": {
"console_format": (
"<white>{time:YYYY-MM-DD HH:mm:ss}</white> | "
"<level>{level: <8}</level> | "
"<light-yellow>聊天观察</light-yellow> | "
"<level>{message}</level>"
),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
},
"simple": {
"console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-yellow>聊天观察</light-yellow> | <light-yellow>{message}</light-yellow>"
), # noqa: E501
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
},
}
# OBSERVATION_STYLE_CONFIG = {
# "advanced": {
# "console_format": (
# "<white>{time:YYYY-MM-DD HH:mm:ss}</white> | "
# "<level>{level: <8}</level> | "
# "<light-yellow>聊天观察</light-yellow> | "
# "<level>{message}</level>"
# ),
# "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
# },
# "simple": {
# "console_format": (
# "<level>{time:HH:mm:ss}</level> | <light-yellow>聊天观察</light-yellow> | <light-yellow>{message}</light-yellow>"
# ), # noqa: E501
# "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 聊天观察 | {message}",
# },
# }
CHAT_IMAGE_STYLE_CONFIG = {
"advanced": {
@@ -582,7 +582,7 @@ CHAT_IMAGE_STYLE_CONFIG = {
},
"simple": {
"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
"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}",
},
"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}",
},
}
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 = {
"console_format": "<RED>{message}</RED>", # noqa: E501
@@ -624,7 +668,7 @@ TIANYI_STYLE_CONFIG = {
},
"simple": {
"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}",
},
@@ -642,7 +686,7 @@ MODEL_UTILS_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 模型 | {message}",
},
"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}",
},
}
@@ -658,7 +702,7 @@ MESSAGE_BUFFER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 消息缓存 | {message}",
},
"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}",
},
}
@@ -674,7 +718,7 @@ PROMPT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 提示词构建 | {message}",
},
"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}",
},
}
@@ -690,7 +734,7 @@ CHANGE_MOOD_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情工具 | {message}",
},
"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}",
},
}
@@ -706,7 +750,7 @@ CHANGE_RELATIONSHIP_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 关系工具 | {message}",
},
"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}",
},
}
@@ -722,7 +766,7 @@ GET_KNOWLEDGE_TOOL_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 获取知识 | {message}",
},
"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}",
},
}
@@ -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}",
},
"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}",
},
}
@@ -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}",
},
"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}",
},
}
@@ -770,7 +814,7 @@ INIT_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 初始化 | {message}",
},
"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}",
},
}
@@ -786,7 +830,7 @@ API_SERVER_STYLE_CONFIG = {
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | API服务 | {message}",
},
"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}",
},
}
@@ -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"]
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"]
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"]
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"]
@@ -852,7 +902,7 @@ LPMM_GET_KNOWLEDGE_TOOL_STYLE_CONFIG = (
if SIMPLE_OUTPUT
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["simple"] if SIMPLE_OUTPUT else MESSAGE_BUFFER_STYLE_CONFIG["advanced"]
)

View File

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