Merge branch 'dev' of https://github.com/SnowindMe/MaiBot into dev
This commit is contained in:
14
.github/workflows/ruff.yml
vendored
14
.github/workflows/ruff.yml
vendored
@@ -1,9 +1,23 @@
|
||||
name: Ruff
|
||||
on: [ push, pull_request ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/ruff-action@v3
|
||||
- run: ruff check --fix
|
||||
- run: ruff format
|
||||
- name: Commit changes
|
||||
if: success()
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add -A
|
||||
git diff --quiet && git diff --staged --quiet || git commit -m "🤖 自动格式化代码 [skip ci]"
|
||||
git push
|
||||
|
||||
|
||||
@@ -283,17 +283,13 @@ WILLING_STYLE_CONFIG = {
|
||||
"file_format": ("{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 意愿 | {message}"),
|
||||
},
|
||||
"simple": {
|
||||
"console_format": (
|
||||
"<green>{time:MM-DD HH:mm}</green> | <light-blue>意愿</light-blue> | {message}"
|
||||
), # noqa: E501
|
||||
"console_format": ("<green>{time:MM-DD HH:mm}</green> | <light-blue>意愿</light-blue> | {message}"), # noqa: E501
|
||||
"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
|
||||
"console_format": ("<RED>{message}</RED>"), # noqa: E501
|
||||
"file_format": ("{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | EULA与PRIVACY确认 | {message}"),
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,16 @@ from src.do_tool.tool_can_use.base_tool import (
|
||||
discover_tools,
|
||||
get_all_tool_definitions,
|
||||
get_tool_instance,
|
||||
TOOL_REGISTRY
|
||||
TOOL_REGISTRY,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'BaseTool',
|
||||
'register_tool',
|
||||
'discover_tools',
|
||||
'get_all_tool_definitions',
|
||||
'get_tool_instance',
|
||||
'TOOL_REGISTRY'
|
||||
"BaseTool",
|
||||
"register_tool",
|
||||
"discover_tools",
|
||||
"get_all_tool_definitions",
|
||||
"get_tool_instance",
|
||||
"TOOL_REGISTRY",
|
||||
]
|
||||
|
||||
# 自动发现并注册工具
|
||||
|
||||
@@ -10,8 +10,10 @@ logger = get_module_logger("base_tool")
|
||||
# 工具注册表
|
||||
TOOL_REGISTRY = {}
|
||||
|
||||
|
||||
class BaseTool:
|
||||
"""所有工具的基类"""
|
||||
|
||||
# 工具名称,子类必须重写
|
||||
name = None
|
||||
# 工具描述,子类必须重写
|
||||
@@ -31,11 +33,7 @@ class BaseTool:
|
||||
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": cls.name,
|
||||
"description": cls.description,
|
||||
"parameters": cls.parameters
|
||||
}
|
||||
"function": {"name": cls.name, "description": cls.description, "parameters": cls.parameters},
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
|
||||
@@ -4,20 +4,16 @@ from typing import Dict, Any
|
||||
|
||||
logger = get_module_logger("fibonacci_sequence_tool")
|
||||
|
||||
|
||||
class FibonacciSequenceTool(BaseTool):
|
||||
"""生成斐波那契数列的工具"""
|
||||
|
||||
name = "fibonacci_sequence"
|
||||
description = "生成指定长度的斐波那契数列"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"n": {
|
||||
"type": "integer",
|
||||
"description": "斐波那契数列的长度",
|
||||
"minimum": 1
|
||||
}
|
||||
},
|
||||
"required": ["n"]
|
||||
"properties": {"n": {"type": "integer", "description": "斐波那契数列的长度", "minimum": 1}},
|
||||
"required": ["n"],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
@@ -41,16 +37,11 @@ class FibonacciSequenceTool(BaseTool):
|
||||
sequence.append(a)
|
||||
a, b = b, a + b
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": sequence
|
||||
}
|
||||
return {"name": self.name, "content": sequence}
|
||||
except Exception as e:
|
||||
logger.error(f"fibonacci_sequence工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"执行失败: {str(e)}"
|
||||
}
|
||||
return {"name": self.name, "content": f"执行失败: {str(e)}"}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(FibonacciSequenceTool)
|
||||
@@ -4,8 +4,10 @@ from typing import Dict, Any
|
||||
|
||||
logger = get_module_logger("generate_buddha_emoji_tool")
|
||||
|
||||
|
||||
class GenerateBuddhaEmojiTool(BaseTool):
|
||||
"""生成佛祖颜文字的工具类"""
|
||||
|
||||
name = "generate_buddha_emoji"
|
||||
description = "生成一个佛祖的颜文字表情"
|
||||
parameters = {
|
||||
@@ -13,7 +15,7 @@ class GenerateBuddhaEmojiTool(BaseTool):
|
||||
"properties": {
|
||||
# 无参数
|
||||
},
|
||||
"required": []
|
||||
"required": [],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
@@ -29,16 +31,11 @@ class GenerateBuddhaEmojiTool(BaseTool):
|
||||
try:
|
||||
buddha_emoji = "这是一个佛祖emoji:༼ つ ◕_◕ ༽つ"
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": buddha_emoji
|
||||
}
|
||||
return {"name": self.name, "content": buddha_emoji}
|
||||
except Exception as e:
|
||||
logger.error(f"generate_buddha_emoji工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"执行失败: {str(e)}"
|
||||
}
|
||||
return {"name": self.name, "content": f"执行失败: {str(e)}"}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(GenerateBuddhaEmojiTool)
|
||||
@@ -4,15 +4,13 @@ from typing import Dict, Any
|
||||
|
||||
logger = get_module_logger("generate_cmd_tutorial_tool")
|
||||
|
||||
|
||||
class GenerateCmdTutorialTool(BaseTool):
|
||||
"""生成Windows CMD基本操作教程的工具"""
|
||||
|
||||
name = "generate_cmd_tutorial"
|
||||
description = "生成关于Windows命令提示符(CMD)的基本操作教程,包括常用命令和使用方法"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
parameters = {"type": "object", "properties": {}, "required": []}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
"""执行工具功能
|
||||
@@ -58,16 +56,11 @@ class GenerateCmdTutorialTool(BaseTool):
|
||||
注意:使用命令时要小心,特别是删除操作。
|
||||
"""
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": tutorial_content
|
||||
}
|
||||
return {"name": self.name, "content": tutorial_content}
|
||||
except Exception as e:
|
||||
logger.error(f"generate_cmd_tutorial工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"执行失败: {str(e)}"
|
||||
}
|
||||
return {"name": self.name, "content": f"执行失败: {str(e)}"}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(GenerateCmdTutorialTool)
|
||||
@@ -5,23 +5,19 @@ from typing import Dict, Any
|
||||
|
||||
logger = get_module_logger("get_current_task_tool")
|
||||
|
||||
|
||||
class GetCurrentTaskTool(BaseTool):
|
||||
"""获取当前正在做的事情/最近的任务工具"""
|
||||
|
||||
name = "get_current_task"
|
||||
description = "获取当前正在做的事情/最近的任务"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"num": {
|
||||
"type": "integer",
|
||||
"description": "要获取的任务数量"
|
||||
"num": {"type": "integer", "description": "要获取的任务数量"},
|
||||
"time_info": {"type": "boolean", "description": "是否包含时间信息"},
|
||||
},
|
||||
"time_info": {
|
||||
"type": "boolean",
|
||||
"description": "是否包含时间信息"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
"required": [],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
@@ -48,16 +44,11 @@ class GetCurrentTaskTool(BaseTool):
|
||||
else:
|
||||
task_info = "当前没有正在进行的任务"
|
||||
|
||||
return {
|
||||
"name": "get_current_task",
|
||||
"content": f"当前任务信息: {task_info}"
|
||||
}
|
||||
return {"name": "get_current_task", "content": f"当前任务信息: {task_info}"}
|
||||
except Exception as e:
|
||||
logger.error(f"获取当前任务工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": "get_current_task",
|
||||
"content": f"获取当前任务失败: {str(e)}"
|
||||
}
|
||||
return {"name": "get_current_task", "content": f"获取当前任务失败: {str(e)}"}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(GetCurrentTaskTool)
|
||||
@@ -6,23 +6,19 @@ from typing import Dict, Any, Union
|
||||
|
||||
logger = get_module_logger("get_knowledge_tool")
|
||||
|
||||
|
||||
class SearchKnowledgeTool(BaseTool):
|
||||
"""从知识库中搜索相关信息的工具"""
|
||||
|
||||
name = "search_knowledge"
|
||||
description = "从知识库中搜索相关信息"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "搜索查询关键词"
|
||||
"query": {"type": "string", "description": "搜索查询关键词"},
|
||||
"threshold": {"type": "number", "description": "相似度阈值,0.0到1.0之间"},
|
||||
},
|
||||
"threshold": {
|
||||
"type": "number",
|
||||
"description": "相似度阈值,0.0到1.0之间"
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
"required": ["query"],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
@@ -47,20 +43,11 @@ class SearchKnowledgeTool(BaseTool):
|
||||
content = f"你知道这些知识: {knowledge_info}"
|
||||
else:
|
||||
content = f"你不太了解有关{query}的知识"
|
||||
return {
|
||||
"name": "search_knowledge",
|
||||
"content": content
|
||||
}
|
||||
return {
|
||||
"name": "search_knowledge",
|
||||
"content": f"无法获取关于'{query}'的嵌入向量"
|
||||
}
|
||||
return {"name": "search_knowledge", "content": content}
|
||||
return {"name": "search_knowledge", "content": f"无法获取关于'{query}'的嵌入向量"}
|
||||
except Exception as e:
|
||||
logger.error(f"知识库搜索工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": "search_knowledge",
|
||||
"content": f"知识库搜索失败: {str(e)}"
|
||||
}
|
||||
return {"name": "search_knowledge", "content": f"知识库搜索失败: {str(e)}"}
|
||||
|
||||
def get_info_from_db(
|
||||
self, query_embedding: list, limit: int = 1, threshold: float = 0.5, return_raw: bool = False
|
||||
@@ -143,5 +130,6 @@ class SearchKnowledgeTool(BaseTool):
|
||||
# 返回所有找到的内容,用换行分隔
|
||||
return "\n".join(str(result["content"]) for result in results)
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(SearchKnowledgeTool)
|
||||
|
||||
@@ -5,23 +5,19 @@ from typing import Dict, Any
|
||||
|
||||
logger = get_module_logger("get_memory_tool")
|
||||
|
||||
|
||||
class GetMemoryTool(BaseTool):
|
||||
"""从记忆系统中获取相关记忆的工具"""
|
||||
|
||||
name = "get_memory"
|
||||
description = "从记忆系统中获取相关记忆"
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "要查询的相关文本"
|
||||
"text": {"type": "string", "description": "要查询的相关文本"},
|
||||
"max_memory_num": {"type": "integer", "description": "最大返回记忆数量"},
|
||||
},
|
||||
"max_memory_num": {
|
||||
"type": "integer",
|
||||
"description": "最大返回记忆数量"
|
||||
}
|
||||
},
|
||||
"required": ["text"]
|
||||
"required": ["text"],
|
||||
}
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any], message_txt: str = "") -> Dict[str, Any]:
|
||||
@@ -40,11 +36,7 @@ class GetMemoryTool(BaseTool):
|
||||
|
||||
# 调用记忆系统
|
||||
related_memory = await HippocampusManager.get_instance().get_memory_from_text(
|
||||
text=text,
|
||||
max_memory_num=max_memory_num,
|
||||
max_memory_length=2,
|
||||
max_depth=3,
|
||||
fast_retrieval=False
|
||||
text=text, max_memory_num=max_memory_num, max_memory_length=2, max_depth=3, fast_retrieval=False
|
||||
)
|
||||
|
||||
memory_info = ""
|
||||
@@ -57,16 +49,11 @@ class GetMemoryTool(BaseTool):
|
||||
else:
|
||||
content = f"你不太记得有关{text}的记忆,你对此不太了解"
|
||||
|
||||
return {
|
||||
"name": "get_memory",
|
||||
"content": content
|
||||
}
|
||||
return {"name": "get_memory", "content": content}
|
||||
except Exception as e:
|
||||
logger.error(f"记忆获取工具执行失败: {str(e)}")
|
||||
return {
|
||||
"name": "get_memory",
|
||||
"content": f"记忆获取失败: {str(e)}"
|
||||
}
|
||||
return {"name": "get_memory", "content": f"记忆获取失败: {str(e)}"}
|
||||
|
||||
|
||||
# 注册工具
|
||||
register_tool(GetMemoryTool)
|
||||
@@ -16,7 +16,7 @@ class ToolUser:
|
||||
model=global_config.llm_heartflow, temperature=0.2, max_tokens=1000, request_type="tool_use"
|
||||
)
|
||||
|
||||
async def _build_tool_prompt(self, message_txt:str, sender_name:str, chat_stream:ChatStream):
|
||||
async def _build_tool_prompt(self, message_txt: str, sender_name: str, chat_stream: ChatStream):
|
||||
"""构建工具使用的提示词
|
||||
|
||||
Args:
|
||||
@@ -28,9 +28,7 @@ class ToolUser:
|
||||
str: 构建好的提示词
|
||||
"""
|
||||
new_messages = list(
|
||||
db.messages.find({"chat_id": chat_stream.stream_id, "time": {"$gt": time.time()}})
|
||||
.sort("time", 1)
|
||||
.limit(15)
|
||||
db.messages.find({"chat_id": chat_stream.stream_id, "time": {"$gt": time.time()}}).sort("time", 1).limit(15)
|
||||
)
|
||||
new_messages_str = ""
|
||||
for msg in new_messages:
|
||||
@@ -55,7 +53,7 @@ class ToolUser:
|
||||
"""
|
||||
return get_all_tool_definitions()
|
||||
|
||||
async def _execute_tool_call(self, tool_call, message_txt:str):
|
||||
async def _execute_tool_call(self, tool_call, message_txt: str):
|
||||
"""执行特定的工具调用
|
||||
|
||||
Args:
|
||||
@@ -82,14 +80,14 @@ class ToolUser:
|
||||
"tool_call_id": tool_call["id"],
|
||||
"role": "tool",
|
||||
"name": function_name,
|
||||
"content": result["content"]
|
||||
"content": result["content"],
|
||||
}
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"执行工具调用时发生错误: {str(e)}")
|
||||
return None
|
||||
|
||||
async def use_tool(self, message_txt:str, sender_name:str, chat_stream:ChatStream):
|
||||
async def use_tool(self, message_txt: str, sender_name: str, chat_stream: ChatStream):
|
||||
"""使用工具辅助思考,判断是否需要额外信息
|
||||
|
||||
Args:
|
||||
@@ -113,15 +111,13 @@ class ToolUser:
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
"max_tokens": global_config.max_response_length,
|
||||
"tools": tools,
|
||||
"temperature": 0.2
|
||||
"temperature": 0.2,
|
||||
}
|
||||
|
||||
logger.debug(f"发送工具调用请求,模型: {self.llm_model_tool.model_name}")
|
||||
# 发送请求获取模型是否需要调用工具
|
||||
response = await self.llm_model_tool._execute_request(
|
||||
endpoint="/chat/completions",
|
||||
payload=payload,
|
||||
prompt=prompt
|
||||
endpoint="/chat/completions", payload=payload, prompt=prompt
|
||||
)
|
||||
|
||||
# 根据返回值数量判断是否有工具调用
|
||||
|
||||
@@ -43,7 +43,6 @@ def init_prompt():
|
||||
|
||||
class CurrentState:
|
||||
def __init__(self):
|
||||
|
||||
self.current_state_info = ""
|
||||
|
||||
self.mood_manager = MoodManager()
|
||||
@@ -67,9 +66,6 @@ class Heartflow:
|
||||
|
||||
self._subheartflows: Dict[Any, SubHeartflow] = {}
|
||||
|
||||
|
||||
|
||||
|
||||
async def _cleanup_inactive_subheartflows(self):
|
||||
"""定期清理不活跃的子心流"""
|
||||
while True:
|
||||
@@ -103,7 +99,6 @@ class Heartflow:
|
||||
await asyncio.sleep(global_config.heart_flow_update_interval) # 5分钟思考一次
|
||||
|
||||
async def heartflow_start_working(self):
|
||||
|
||||
# 启动清理任务
|
||||
asyncio.create_task(self._cleanup_inactive_subheartflows())
|
||||
|
||||
@@ -155,7 +150,7 @@ class Heartflow:
|
||||
# prompt += f"你现在{mood_info}。"
|
||||
# prompt += "现在你接下去继续思考,产生新的想法,但是要基于原有的主要想法,不要分点输出,"
|
||||
# prompt += "输出连贯的内心独白,不要太长,但是记得结合上述的消息,关注新内容:"
|
||||
prompt = global_prompt_manager.get_prompt("thinking_prompt").format(
|
||||
prompt = (await global_prompt_manager.get_prompt_async("thinking_prompt")).format(
|
||||
schedule_info, personality_info, related_memory_info, current_thinking_info, sub_flows_info, mood_info
|
||||
)
|
||||
|
||||
@@ -212,7 +207,7 @@ class Heartflow:
|
||||
# prompt += f"你现在{mood_info}\n"
|
||||
# prompt += """现在请你总结这些聊天内容,注意关注聊天内容对原有的想法的影响,输出连贯的内心独白
|
||||
# 不要太长,但是记得结合上述的消息,要记得你的人设,关注新内容:"""
|
||||
prompt = global_prompt_manager.get_prompt("mind_summary_prompt").format(
|
||||
prompt = (await global_prompt_manager.get_prompt_async("mind_summary_prompt")).format(
|
||||
personality_info, global_config.BOT_NICKNAME, self.current_mind, minds_str, mood_info
|
||||
)
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ from src.plugins.models.utils_model import LLM_request
|
||||
from src.plugins.config.config import global_config
|
||||
import re
|
||||
import time
|
||||
|
||||
# from src.plugins.schedule.schedule_generator import bot_schedule
|
||||
# from src.plugins.memory_system.Hippocampus import HippocampusManager
|
||||
from src.common.logger import get_module_logger, LogConfig, SUB_HEARTFLOW_STYLE_CONFIG # noqa: E402
|
||||
|
||||
# from src.plugins.chat.utils import get_embedding
|
||||
# from src.common.database import db
|
||||
# from typing import Union
|
||||
@@ -17,6 +19,7 @@ from src.plugins.chat.chat_stream import ChatStream
|
||||
from src.plugins.person_info.relationship_manager import relationship_manager
|
||||
from src.plugins.chat.utils import get_recent_group_speaker
|
||||
from src.do_tool.tool_use import ToolUser
|
||||
from ..plugins.utils.prompt_builder import Prompt, global_prompt_manager
|
||||
|
||||
subheartflow_config = LogConfig(
|
||||
# 使用海马体专用样式
|
||||
@@ -26,6 +29,35 @@ subheartflow_config = LogConfig(
|
||||
logger = get_module_logger("subheartflow", config=subheartflow_config)
|
||||
|
||||
|
||||
def init_prompt():
|
||||
prompt = ""
|
||||
# prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n"
|
||||
prompt += "{collected_info}\n"
|
||||
prompt += "{relation_prompt_all}\n"
|
||||
prompt += "{prompt_personality}\n"
|
||||
prompt += "刚刚你的想法是{current_thinking_info}。如果有新的内容,记得转换话题\n"
|
||||
prompt += "-----------------------------------\n"
|
||||
prompt += "现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
prompt += "你现在{mood_info}\n"
|
||||
prompt += "你注意到{sender_name}刚刚说:{message_txt}\n"
|
||||
prompt += "现在你接下去继续思考,产生新的想法,不要分点输出,输出连贯的内心独白"
|
||||
prompt += "思考时可以想想如何对群聊内容进行回复。回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话\n"
|
||||
prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写"
|
||||
prompt += "记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{bot_name},{bot_name}指的就是你。"
|
||||
Prompt(prompt, "sub_heartflow_prompt_before")
|
||||
prompt = ""
|
||||
# prompt += f"你现在正在做的事情是:{schedule_info}\n"
|
||||
prompt += "{prompt_personality}\n"
|
||||
prompt += "现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
prompt += "刚刚你的想法是{current_thinking_info}。"
|
||||
prompt += "你现在看到了网友们发的新消息:{message_new_info}\n"
|
||||
prompt += "你刚刚回复了群友们:{reply_info}"
|
||||
prompt += "你现在{mood_info}"
|
||||
prompt += "现在你接下去继续思考,产生新的想法,记得保留你刚刚的想法,不要分点输出,输出连贯的内心独白"
|
||||
prompt += "不要太长,但是记得结合上述的消息,要记得你的人设,关注聊天和新内容,关注你回复的内容,不要思考太多:"
|
||||
Prompt(prompt, "sub_heartflow_prompt_after")
|
||||
|
||||
|
||||
class CurrentState:
|
||||
def __init__(self):
|
||||
self.willing = 0
|
||||
@@ -49,7 +81,6 @@ class SubHeartflow:
|
||||
model=global_config.llm_sub_heartflow, temperature=0.2, max_tokens=600, request_type="sub_heart_flow"
|
||||
)
|
||||
|
||||
|
||||
self.main_heartflow_info = ""
|
||||
|
||||
self.last_reply_time = time.time()
|
||||
@@ -115,12 +146,12 @@ class SubHeartflow:
|
||||
): # 5分钟无回复/不在场,销毁
|
||||
logger.info(f"子心流 {self.subheartflow_id} 已经5分钟没有激活,正在销毁...")
|
||||
break # 退出循环,销毁自己
|
||||
|
||||
async def do_observe(self):
|
||||
observation = self.observations[0]
|
||||
await observation.observe()
|
||||
|
||||
|
||||
async def do_thinking_before_reply(self, message_txt:str, sender_name:str, chat_stream:ChatStream):
|
||||
async def do_thinking_before_reply(self, message_txt: str, sender_name: str, chat_stream: ChatStream):
|
||||
current_thinking_info = self.current_mind
|
||||
mood_info = self.current_state.mood
|
||||
# mood_info = "你很生气,很愤怒"
|
||||
@@ -170,26 +201,41 @@ class SubHeartflow:
|
||||
for person in who_chat_in_group:
|
||||
relation_prompt += await relationship_manager.build_relationship_info(person)
|
||||
|
||||
relation_prompt_all = (
|
||||
f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录,"
|
||||
f"根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。"
|
||||
# relation_prompt_all = (
|
||||
# f"{relation_prompt}关系等级越大,关系越好,请分析聊天记录,"
|
||||
# f"根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。"
|
||||
# )
|
||||
relation_prompt_all = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format(
|
||||
relation_prompt, sender_name
|
||||
)
|
||||
|
||||
prompt = ""
|
||||
# prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n"
|
||||
if tool_result.get("used_tools", False):
|
||||
prompt += f"{collected_info}\n"
|
||||
prompt += f"{relation_prompt_all}\n"
|
||||
prompt += f"{prompt_personality}\n"
|
||||
prompt += f"刚刚你的想法是{current_thinking_info}。如果有新的内容,记得转换话题\n"
|
||||
prompt += "-----------------------------------\n"
|
||||
prompt += f"现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
prompt += f"你现在{mood_info}\n"
|
||||
prompt += f"你注意到{sender_name}刚刚说:{message_txt}\n"
|
||||
prompt += "现在你接下去继续思考,产生新的想法,不要分点输出,输出连贯的内心独白"
|
||||
prompt += "思考时可以想想如何对群聊内容进行回复。回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话\n"
|
||||
prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写"
|
||||
prompt += f"记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{self.bot_name},{self.bot_name}指的就是你。"
|
||||
# prompt = ""
|
||||
# # prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n"
|
||||
# if tool_result.get("used_tools", False):
|
||||
# prompt += f"{collected_info}\n"
|
||||
# prompt += f"{relation_prompt_all}\n"
|
||||
# prompt += f"{prompt_personality}\n"
|
||||
# prompt += f"刚刚你的想法是{current_thinking_info}。如果有新的内容,记得转换话题\n"
|
||||
# prompt += "-----------------------------------\n"
|
||||
# prompt += f"现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
# prompt += f"你现在{mood_info}\n"
|
||||
# prompt += f"你注意到{sender_name}刚刚说:{message_txt}\n"
|
||||
# prompt += "现在你接下去继续思考,产生新的想法,不要分点输出,输出连贯的内心独白"
|
||||
# prompt += "思考时可以想想如何对群聊内容进行回复。回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话\n"
|
||||
# prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写"
|
||||
# prompt += f"记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{self.bot_name},{self.bot_name}指的就是你。"
|
||||
|
||||
prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_before")).format(
|
||||
collected_info,
|
||||
relation_prompt_all,
|
||||
prompt_personality,
|
||||
current_thinking_info,
|
||||
chat_observe_info,
|
||||
mood_info,
|
||||
sender_name,
|
||||
message_txt,
|
||||
self.bot_name,
|
||||
)
|
||||
|
||||
try:
|
||||
response, reasoning_content = await self.llm_model.generate_response_async(prompt)
|
||||
@@ -233,16 +279,20 @@ class SubHeartflow:
|
||||
reply_info = reply_content
|
||||
# schedule_info = bot_schedule.get_current_num_task(num=1, time_info=False)
|
||||
|
||||
prompt = ""
|
||||
# prompt += f"你现在正在做的事情是:{schedule_info}\n"
|
||||
prompt += f"{prompt_personality}\n"
|
||||
prompt += f"现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
prompt += f"刚刚你的想法是{current_thinking_info}。"
|
||||
prompt += f"你现在看到了网友们发的新消息:{message_new_info}\n"
|
||||
prompt += f"你刚刚回复了群友们:{reply_info}"
|
||||
prompt += f"你现在{mood_info}"
|
||||
prompt += "现在你接下去继续思考,产生新的想法,记得保留你刚刚的想法,不要分点输出,输出连贯的内心独白"
|
||||
prompt += "不要太长,但是记得结合上述的消息,要记得你的人设,关注聊天和新内容,关注你回复的内容,不要思考太多:"
|
||||
# prompt = ""
|
||||
# # prompt += f"你现在正在做的事情是:{schedule_info}\n"
|
||||
# prompt += f"{prompt_personality}\n"
|
||||
# prompt += f"现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n"
|
||||
# prompt += f"刚刚你的想法是{current_thinking_info}。"
|
||||
# prompt += f"你现在看到了网友们发的新消息:{message_new_info}\n"
|
||||
# prompt += f"你刚刚回复了群友们:{reply_info}"
|
||||
# prompt += f"你现在{mood_info}"
|
||||
# prompt += "现在你接下去继续思考,产生新的想法,记得保留你刚刚的想法,不要分点输出,输出连贯的内心独白"
|
||||
# prompt += "不要太长,但是记得结合上述的消息,要记得你的人设,关注聊天和新内容,关注你回复的内容,不要思考太多:"
|
||||
prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_after")).format(
|
||||
prompt_personality, chat_observe_info, current_thinking_info, message_new_info, reply_info, mood_info
|
||||
)
|
||||
|
||||
try:
|
||||
response, reasoning_content = await self.llm_model.generate_response_async(prompt)
|
||||
except Exception as e:
|
||||
@@ -302,4 +352,5 @@ class SubHeartflow:
|
||||
self.current_mind = response
|
||||
|
||||
|
||||
init_prompt()
|
||||
# subheartflow = SubHeartflow()
|
||||
|
||||
@@ -53,8 +53,8 @@ class ActionPlanner:
|
||||
goal = goal_reason[0]
|
||||
reasoning = goal_reason[1] if len(goal_reason) > 1 else "没有明确原因"
|
||||
elif isinstance(goal_reason, dict):
|
||||
goal = goal_reason.get('goal')
|
||||
reasoning = goal_reason.get('reasoning', "没有明确原因")
|
||||
goal = goal_reason.get("goal")
|
||||
reasoning = goal_reason.get("reasoning", "没有明确原因")
|
||||
else:
|
||||
# 如果是其他类型,尝试转为字符串
|
||||
goal = str(goal_reason)
|
||||
@@ -68,7 +68,11 @@ class ActionPlanner:
|
||||
goals_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n"
|
||||
|
||||
# 获取聊天历史记录
|
||||
chat_history_list = observation_info.chat_history[-20:] if len(observation_info.chat_history) >= 20 else observation_info.chat_history
|
||||
chat_history_list = (
|
||||
observation_info.chat_history[-20:]
|
||||
if len(observation_info.chat_history) >= 20
|
||||
else observation_info.chat_history
|
||||
)
|
||||
chat_history_text = ""
|
||||
for msg in chat_history_list:
|
||||
chat_history_text += f"{msg.get('detailed_plain_text', '')}\n"
|
||||
@@ -85,15 +89,21 @@ class ActionPlanner:
|
||||
personality_text = f"你的名字是{self.name},{self.personality_info}"
|
||||
|
||||
# 构建action历史文本
|
||||
action_history_list = conversation_info.done_action[-10:] if len(conversation_info.done_action) >= 10 else conversation_info.done_action
|
||||
action_history_list = (
|
||||
conversation_info.done_action[-10:]
|
||||
if len(conversation_info.done_action) >= 10
|
||||
else conversation_info.done_action
|
||||
)
|
||||
action_history_text = "你之前做的事情是:"
|
||||
for action in action_history_list:
|
||||
if isinstance(action, dict):
|
||||
action_type = action.get('action')
|
||||
action_reason = action.get('reason')
|
||||
action_status = action.get('status')
|
||||
action_type = action.get("action")
|
||||
action_reason = action.get("reason")
|
||||
action_status = action.get("status")
|
||||
if action_status == "recall":
|
||||
action_history_text += f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
action_history_text += (
|
||||
f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
)
|
||||
elif action_status == "done":
|
||||
action_history_text += f"你之前做了:{action_type},原因:{action_reason}\n"
|
||||
elif isinstance(action, tuple):
|
||||
@@ -102,7 +112,9 @@ class ActionPlanner:
|
||||
action_reason = action[1] if len(action) > 1 else "未知原因"
|
||||
action_status = action[2] if len(action) > 2 else "done"
|
||||
if action_status == "recall":
|
||||
action_history_text += f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
action_history_text += (
|
||||
f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
)
|
||||
elif action_status == "done":
|
||||
action_history_text += f"你之前做了:{action_type},原因:{action_reason}\n"
|
||||
|
||||
@@ -147,7 +159,14 @@ end_conversation: 结束对话,长时间没回复或者当你觉得谈话暂
|
||||
reason = result["reason"]
|
||||
|
||||
# 验证action类型
|
||||
if action not in ["direct_reply", "fetch_knowledge", "wait", "listening", "rethink_goal", "end_conversation"]:
|
||||
if action not in [
|
||||
"direct_reply",
|
||||
"fetch_knowledge",
|
||||
"wait",
|
||||
"listening",
|
||||
"rethink_goal",
|
||||
"end_conversation",
|
||||
]:
|
||||
logger.warning(f"未知的行动类型: {action},默认使用listening")
|
||||
action = "listening"
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ class ChatObserver:
|
||||
|
||||
self.waiting_start_time: float = time.time() # 等待开始时间,初始化为当前时间
|
||||
|
||||
|
||||
# 运行状态
|
||||
self._running: bool = False
|
||||
self._task: Optional[asyncio.Task] = None
|
||||
@@ -94,10 +93,11 @@ class ChatObserver:
|
||||
message: 消息数据
|
||||
"""
|
||||
try:
|
||||
|
||||
# 发送新消息通知
|
||||
# logger.info(f"发送新ccchandleer消息通知: {message}")
|
||||
notification = create_new_message_notification(sender="chat_observer", target="observation_info", message=message)
|
||||
notification = create_new_message_notification(
|
||||
sender="chat_observer", target="observation_info", message=message
|
||||
)
|
||||
# logger.info(f"发送新消ddddd息通知: {notification}")
|
||||
# print(self.notification_manager)
|
||||
await self.notification_manager.send_notification(notification)
|
||||
@@ -131,7 +131,6 @@ class ChatObserver:
|
||||
notification = create_cold_chat_notification(sender="chat_observer", target="pfc", is_cold=is_cold)
|
||||
await self.notification_manager.send_notification(notification)
|
||||
|
||||
|
||||
def new_message_after(self, time_point: float) -> bool:
|
||||
"""判断是否在指定时间点后有新消息
|
||||
|
||||
@@ -347,7 +346,6 @@ class ChatObserver:
|
||||
|
||||
return time_info
|
||||
|
||||
|
||||
def get_cached_messages(self, limit: int = 50) -> List[Dict[str, Any]]:
|
||||
"""获取缓存的消息历史
|
||||
|
||||
|
||||
@@ -141,7 +141,6 @@ class NotificationManager:
|
||||
else:
|
||||
self._active_states.discard(notification.type)
|
||||
|
||||
|
||||
# 调用目标接收者的处理器
|
||||
target = notification.target
|
||||
if target in self._handlers:
|
||||
@@ -295,5 +294,3 @@ class ChatStateManager:
|
||||
|
||||
current_time = datetime.now().timestamp()
|
||||
return (current_time - self.state_info.last_message_time) <= threshold
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ class Conversation:
|
||||
self.observation_info.bind_to_chat_observer(self.chat_observer)
|
||||
# print(self.chat_observer.get_cached_messages(limit=)
|
||||
|
||||
|
||||
self.conversation_info = ConversationInfo()
|
||||
except Exception as e:
|
||||
logger.error(f"初始化对话实例:注册信息组件失败: {e}")
|
||||
@@ -174,7 +173,6 @@ class Conversation:
|
||||
|
||||
await self._send_reply()
|
||||
|
||||
|
||||
conversation_info.done_action[-1].update(
|
||||
{
|
||||
"status": "done",
|
||||
@@ -208,7 +206,6 @@ class Conversation:
|
||||
logger.info("倾听对方发言...")
|
||||
await self.waiter.wait_listening(conversation_info)
|
||||
|
||||
|
||||
elif action == "end_conversation":
|
||||
self.should_continue = False
|
||||
logger.info("决定结束对话...")
|
||||
@@ -239,9 +236,7 @@ class Conversation:
|
||||
return
|
||||
|
||||
try:
|
||||
await self.direct_sender.send_message(
|
||||
chat_stream=self.chat_stream, content=self.generated_reply
|
||||
)
|
||||
await self.direct_sender.send_message(chat_stream=self.chat_stream, content=self.generated_reply)
|
||||
self.chat_observer.trigger_update() # 触发立即更新
|
||||
if not await self.chat_observer.wait_for_update():
|
||||
logger.warning("等待消息更新超时")
|
||||
|
||||
@@ -2,6 +2,7 @@ from abc import ABC, abstractmethod
|
||||
from typing import List, Dict, Any
|
||||
from src.common.database import db
|
||||
|
||||
|
||||
class MessageStorage(ABC):
|
||||
"""消息存储接口"""
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class ObservationInfoHandler(NotificationHandler):
|
||||
"processed_plain_text": processed_plain_text,
|
||||
"detailed_plain_text": detailed_plain_text,
|
||||
"user_info": user_info,
|
||||
"time": time_value
|
||||
"time": time_value,
|
||||
}
|
||||
|
||||
self.observation_info.update_from_message(message)
|
||||
@@ -233,4 +233,3 @@ class ObservationInfo:
|
||||
self.unprocessed_messages.clear()
|
||||
self.chat_history_count = len(self.chat_history)
|
||||
self.new_messages_count = 0
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Programmable Friendly Conversationalist
|
||||
# Prefrontal cortex
|
||||
import datetime
|
||||
|
||||
# import asyncio
|
||||
from typing import List, Optional, Tuple, TYPE_CHECKING
|
||||
from src.common.logger import get_module_logger
|
||||
@@ -63,8 +64,8 @@ class GoalAnalyzer:
|
||||
goal = goal_reason[0]
|
||||
reasoning = goal_reason[1] if len(goal_reason) > 1 else "没有明确原因"
|
||||
elif isinstance(goal_reason, dict):
|
||||
goal = goal_reason.get('goal')
|
||||
reasoning = goal_reason.get('reasoning', "没有明确原因")
|
||||
goal = goal_reason.get("goal")
|
||||
reasoning = goal_reason.get("reasoning", "没有明确原因")
|
||||
else:
|
||||
# 如果是其他类型,尝试转为字符串
|
||||
goal = str(goal_reason)
|
||||
@@ -143,9 +144,7 @@ class GoalAnalyzer:
|
||||
|
||||
# 使用改进后的get_items_from_json函数处理JSON数组
|
||||
success, result = get_items_from_json(
|
||||
content, "goal", "reasoning",
|
||||
required_types={"goal": str, "reasoning": str},
|
||||
allow_array=True
|
||||
content, "goal", "reasoning", required_types={"goal": str, "reasoning": str}, allow_array=True
|
||||
)
|
||||
|
||||
if success:
|
||||
@@ -293,7 +292,6 @@ class GoalAnalyzer:
|
||||
return False, False, f"分析出错: {str(e)}"
|
||||
|
||||
|
||||
|
||||
class DirectMessageSender:
|
||||
"""直接发送消息到平台的发送器"""
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ class ReplyGenerator:
|
||||
goal = goal_reason[0]
|
||||
reasoning = goal_reason[1] if len(goal_reason) > 1 else "没有明确原因"
|
||||
elif isinstance(goal_reason, dict):
|
||||
goal = goal_reason.get('goal')
|
||||
reasoning = goal_reason.get('reasoning', "没有明确原因")
|
||||
goal = goal_reason.get("goal")
|
||||
reasoning = goal_reason.get("reasoning", "没有明确原因")
|
||||
else:
|
||||
# 如果是其他类型,尝试转为字符串
|
||||
goal = str(goal_reason)
|
||||
@@ -64,7 +64,11 @@ class ReplyGenerator:
|
||||
goals_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n"
|
||||
|
||||
# 获取聊天历史记录
|
||||
chat_history_list = observation_info.chat_history[-20:] if len(observation_info.chat_history) >= 20 else observation_info.chat_history
|
||||
chat_history_list = (
|
||||
observation_info.chat_history[-20:]
|
||||
if len(observation_info.chat_history) >= 20
|
||||
else observation_info.chat_history
|
||||
)
|
||||
chat_history_text = ""
|
||||
for msg in chat_history_list:
|
||||
chat_history_text += f"{msg.get('detailed_plain_text', '')}\n"
|
||||
@@ -81,15 +85,21 @@ class ReplyGenerator:
|
||||
personality_text = f"你的名字是{self.name},{self.personality_info}"
|
||||
|
||||
# 构建action历史文本
|
||||
action_history_list = conversation_info.done_action[-10:] if len(conversation_info.done_action) >= 10 else conversation_info.done_action
|
||||
action_history_list = (
|
||||
conversation_info.done_action[-10:]
|
||||
if len(conversation_info.done_action) >= 10
|
||||
else conversation_info.done_action
|
||||
)
|
||||
action_history_text = "你之前做的事情是:"
|
||||
for action in action_history_list:
|
||||
if isinstance(action, dict):
|
||||
action_type = action.get('action')
|
||||
action_reason = action.get('reason')
|
||||
action_status = action.get('status')
|
||||
action_type = action.get("action")
|
||||
action_reason = action.get("reason")
|
||||
action_status = action.get("status")
|
||||
if action_status == "recall":
|
||||
action_history_text += f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
action_history_text += (
|
||||
f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
)
|
||||
elif action_status == "done":
|
||||
action_history_text += f"你之前做了:{action_type},原因:{action_reason}\n"
|
||||
elif isinstance(action, tuple):
|
||||
@@ -98,7 +108,9 @@ class ReplyGenerator:
|
||||
action_reason = action[1] if len(action) > 1 else "未知原因"
|
||||
action_status = action[2] if len(action) > 2 else "done"
|
||||
if action_status == "recall":
|
||||
action_history_text += f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
action_history_text += (
|
||||
f"原本打算:{action_type},但是因为有新消息,你发现这个行动不合适,所以你没做\n"
|
||||
)
|
||||
elif action_status == "done":
|
||||
action_history_text += f"你之前做了:{action_type},原因:{action_reason}\n"
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ class Waiter:
|
||||
|
||||
logger.info("等待超过300秒,结束对话")
|
||||
wait_goal = {
|
||||
"goal": f"你等待了{self.wait_accumulated_time/60}分钟,思考接下来要做什么",
|
||||
"reason": "对方很久没有回复你的消息了"
|
||||
"goal": f"你等待了{self.wait_accumulated_time / 60}分钟,思考接下来要做什么",
|
||||
"reason": "对方很久没有回复你的消息了",
|
||||
}
|
||||
conversation_info.goal_list.append(wait_goal)
|
||||
print(f"添加目标: {wait_goal}")
|
||||
@@ -73,8 +73,8 @@ class Waiter:
|
||||
self.wait_accumulated_time += 300
|
||||
logger.info("等待超过300秒,结束对话")
|
||||
wait_goal = {
|
||||
"goal": f"你等待了{self.wait_accumulated_time/60}分钟,思考接下来要做什么",
|
||||
"reason": "对方话说一半消失了,很久没有回复"
|
||||
"goal": f"你等待了{self.wait_accumulated_time / 60}分钟,思考接下来要做什么",
|
||||
"reason": "对方话说一半消失了,很久没有回复",
|
||||
}
|
||||
conversation_info.goal_list.append(wait_goal)
|
||||
print(f"添加目标: {wait_goal}")
|
||||
@@ -83,4 +83,3 @@ class Waiter:
|
||||
|
||||
await asyncio.sleep(1)
|
||||
logger.info("等待中...")
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from ..chat_module.only_process.only_message_process import MessageProcessor
|
||||
from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig
|
||||
from ..chat_module.think_flow_chat.think_flow_chat import ThinkFlowChat
|
||||
from ..chat_module.reasoning_chat.reasoning_chat import ReasoningChat
|
||||
from ..utils.prompt_builder import Prompt, global_prompt_manager
|
||||
import traceback
|
||||
|
||||
# 定义日志配置
|
||||
@@ -89,6 +90,18 @@ class ChatBot:
|
||||
logger.debug(f"用户{userinfo.user_id}被禁止回复")
|
||||
return
|
||||
|
||||
if message.message_info.template_info and not message.message_info.template_info.template_default:
|
||||
template_group_name = message.message_info.template_info.template_name
|
||||
template_items = message.message_info.template_info.template_items
|
||||
async with global_prompt_manager.async_message_scope(template_group_name):
|
||||
if isinstance(template_items, dict):
|
||||
for k in template_items.keys():
|
||||
await Prompt.create_async(template_items[k], k)
|
||||
print(f"注册{template_items[k]},{k}")
|
||||
else:
|
||||
template_group_name = None
|
||||
|
||||
async def preprocess():
|
||||
if global_config.enable_pfc_chatting:
|
||||
try:
|
||||
if groupinfo is None:
|
||||
@@ -135,6 +148,13 @@ class ChatBot:
|
||||
await self.reasoning_chat.process_message(message_data)
|
||||
else:
|
||||
logger.error(f"未知的回复模式,请检查配置文件!!: {global_config.response_mode}")
|
||||
|
||||
if template_group_name:
|
||||
async with global_prompt_manager.async_message_scope(template_group_name):
|
||||
await preprocess()
|
||||
else:
|
||||
await preprocess()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"预处理消息失败: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
@@ -87,7 +87,6 @@ async def get_embedding(text, request_type="embedding"):
|
||||
return embedding
|
||||
|
||||
|
||||
|
||||
async def get_recent_group_messages(chat_id: str, limit: int = 12) -> list:
|
||||
"""从数据库获取群组最近的消息记录
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class PromptBuilder:
|
||||
for memory in related_memory:
|
||||
related_memory_info += memory[1]
|
||||
# memory_prompt = f"你想起你之前见过的事情:{related_memory_info}。\n以上是你的回忆,不一定是目前聊天里的人说的,也不一定是现在发生的事情,请记住。\n"
|
||||
memory_prompt = global_prompt_manager.format_prompt(
|
||||
memory_prompt = await global_prompt_manager.format_prompt(
|
||||
"memory_prompt", related_memory_info=related_memory_info
|
||||
)
|
||||
else:
|
||||
@@ -144,12 +144,10 @@ class PromptBuilder:
|
||||
for pattern in rule.get("regex", []):
|
||||
result = pattern.search(message_txt)
|
||||
if result:
|
||||
reaction = rule.get('reaction', '')
|
||||
reaction = rule.get("reaction", "")
|
||||
for name, content in result.groupdict().items():
|
||||
reaction = reaction.replace(f'[{name}]', content)
|
||||
logger.info(
|
||||
f"匹配到以下正则表达式:{pattern},触发反应:{reaction}"
|
||||
)
|
||||
reaction = reaction.replace(f"[{name}]", content)
|
||||
logger.info(f"匹配到以下正则表达式:{pattern},触发反应:{reaction}")
|
||||
keywords_reaction_prompt += reaction + ","
|
||||
break
|
||||
|
||||
@@ -168,7 +166,7 @@ class PromptBuilder:
|
||||
prompt_info = await self.get_prompt_info(message_txt, threshold=0.38)
|
||||
if prompt_info:
|
||||
# prompt_info = f"""\n你有以下这些**知识**:\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n"""
|
||||
prompt_info = global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info)
|
||||
prompt_info = await global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info)
|
||||
|
||||
end_time = time.time()
|
||||
logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}秒")
|
||||
@@ -194,22 +192,22 @@ class PromptBuilder:
|
||||
# 请注意不要输出多余内容(包括前后缀,冒号和引号,括号,表情等),只输出回复内容。
|
||||
# {moderation_prompt}不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。"""
|
||||
|
||||
prompt = global_prompt_manager.format_prompt(
|
||||
prompt = await global_prompt_manager.format_prompt(
|
||||
"reasoning_prompt_main",
|
||||
relation_prompt_all=global_prompt_manager.get_prompt("relationship_prompt"),
|
||||
relation_prompt_all=await global_prompt_manager.get_prompt_async("relationship_prompt"),
|
||||
replation_prompt=relation_prompt,
|
||||
sender_name=sender_name,
|
||||
memory_prompt=memory_prompt,
|
||||
prompt_info=prompt_info,
|
||||
schedule_prompt=global_prompt_manager.format_prompt(
|
||||
schedule_prompt=await global_prompt_manager.format_prompt(
|
||||
"schedule_prompt", schedule_info=bot_schedule.get_current_num_task(num=1, time_info=False)
|
||||
),
|
||||
chat_target=global_prompt_manager.get_prompt("chat_target_group1")
|
||||
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1")
|
||||
if chat_in_group
|
||||
else global_prompt_manager.get_prompt("chat_target_private1"),
|
||||
chat_target_2=global_prompt_manager.get_prompt("chat_target_group2")
|
||||
else await global_prompt_manager.get_prompt_async("chat_target_private1"),
|
||||
chat_target_2=await global_prompt_manager.get_prompt_async("chat_target_group2")
|
||||
if chat_in_group
|
||||
else global_prompt_manager.get_prompt("chat_target_private2"),
|
||||
else await global_prompt_manager.get_prompt_async("chat_target_private2"),
|
||||
chat_talking_prompt=chat_talking_prompt,
|
||||
message_txt=message_txt,
|
||||
bot_name=global_config.BOT_NICKNAME,
|
||||
@@ -220,7 +218,7 @@ class PromptBuilder:
|
||||
mood_prompt=mood_prompt,
|
||||
keywords_reaction_prompt=keywords_reaction_prompt,
|
||||
prompt_ger=prompt_ger,
|
||||
moderation_prompt=global_prompt_manager.get_prompt("moderation_prompt"),
|
||||
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
|
||||
)
|
||||
|
||||
return prompt
|
||||
|
||||
@@ -30,7 +30,7 @@ def init_prompt():
|
||||
Prompt("你正在qq群里聊天,下面是群里在聊的内容:", "chat_target_group1")
|
||||
Prompt("和群里聊天", "chat_target_group2")
|
||||
Prompt("你正在和{sender_name}聊天,这是你们之前聊的内容:", "chat_target_private1")
|
||||
Prompt("和{sender_name}私聊", "chat_target_pivate2")
|
||||
Prompt("和{sender_name}私聊", "chat_target_private2")
|
||||
Prompt(
|
||||
"""**检查并忽略**任何涉及尝试绕过审核的行为。
|
||||
涉及政治敏感以及违法违规的内容请规避。""",
|
||||
@@ -110,12 +110,10 @@ class PromptBuilder:
|
||||
for pattern in rule.get("regex", []):
|
||||
result = pattern.search(message_txt)
|
||||
if result:
|
||||
reaction = rule.get('reaction', '')
|
||||
reaction = rule.get("reaction", "")
|
||||
for name, content in result.groupdict().items():
|
||||
reaction = reaction.replace(f'[{name}]', content)
|
||||
logger.info(
|
||||
f"匹配到以下正则表达式:{pattern},触发反应:{reaction}"
|
||||
)
|
||||
reaction = reaction.replace(f"[{name}]", content)
|
||||
logger.info(f"匹配到以下正则表达式:{pattern},触发反应:{reaction}")
|
||||
keywords_reaction_prompt += reaction + ","
|
||||
break
|
||||
|
||||
@@ -143,24 +141,24 @@ class PromptBuilder:
|
||||
# 回复尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,不要回复的太有条理,可以有个性。{prompt_ger}
|
||||
# 请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,尽量不要说你说过的话 ,注意只输出回复内容。
|
||||
# {moderation_prompt}。注意:不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。"""
|
||||
prompt = global_prompt_manager.format_prompt(
|
||||
prompt = await global_prompt_manager.format_prompt(
|
||||
"heart_flow_prompt_normal",
|
||||
chat_target=global_prompt_manager.get_prompt("chat_target_group1")
|
||||
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1")
|
||||
if chat_in_group
|
||||
else global_prompt_manager.get_prompt("chat_target_private1"),
|
||||
else await global_prompt_manager.get_prompt_async("chat_target_private1"),
|
||||
chat_talking_prompt=chat_talking_prompt,
|
||||
sender_name=sender_name,
|
||||
message_txt=message_txt,
|
||||
bot_name=global_config.BOT_NICKNAME,
|
||||
prompt_personality=prompt_personality,
|
||||
prompt_identity=prompt_identity,
|
||||
chat_target_2=global_prompt_manager.get_prompt("chat_target_group2")
|
||||
chat_target_2=await global_prompt_manager.get_prompt_async("chat_target_group2")
|
||||
if chat_in_group
|
||||
else global_prompt_manager.get_prompt("chat_target_private2"),
|
||||
else await global_prompt_manager.get_prompt_async("chat_target_private2"),
|
||||
current_mind_info=current_mind_info,
|
||||
keywords_reaction_prompt=keywords_reaction_prompt,
|
||||
prompt_ger=prompt_ger,
|
||||
moderation_prompt=global_prompt_manager.get_prompt("moderation_prompt"),
|
||||
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
|
||||
)
|
||||
|
||||
return prompt
|
||||
@@ -218,13 +216,13 @@ class PromptBuilder:
|
||||
# 你刚刚脑子里在想:{current_mind_info}
|
||||
# 现在请你读读之前的聊天记录,然后给出日常,口语化且简短的回复内容,只给出文字的回复内容,不要有内心独白:
|
||||
# """
|
||||
prompt = global_prompt_manager.format_prompt(
|
||||
prompt = await global_prompt_manager.format_prompt(
|
||||
"heart_flow_prompt_simple",
|
||||
bot_name=global_config.BOT_NICKNAME,
|
||||
prompt_personality=prompt_personality,
|
||||
chat_target=global_prompt_manager.get_prompt("chat_target_group1")
|
||||
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1")
|
||||
if chat_in_group
|
||||
else global_prompt_manager.get_prompt("chat_target_private1"),
|
||||
else await global_prompt_manager.get_prompt_async("chat_target_private1"),
|
||||
chat_talking_prompt=chat_talking_prompt,
|
||||
sender_name=sender_name,
|
||||
message_txt=message_txt,
|
||||
@@ -266,14 +264,14 @@ class PromptBuilder:
|
||||
# {chat_target},你希望在群里回复:{content}。现在请你根据以下信息修改回复内容。将这个回复修改的更加日常且口语化的回复,平淡一些,回复尽量简短一些。不要回复的太有条理。
|
||||
# {prompt_ger},不要刻意突出自身学科背景,注意只输出回复内容。
|
||||
# {moderation_prompt}。注意:不要输出多余内容(包括前后缀,冒号和引号,括号,表情包,at或 @等 )。"""
|
||||
prompt = global_prompt_manager.format_prompt(
|
||||
prompt = await global_prompt_manager.format_prompt(
|
||||
"heart_flow_prompt_response",
|
||||
bot_name=global_config.BOT_NICKNAME,
|
||||
prompt_identity=prompt_identity,
|
||||
chat_target=global_prompt_manager.get_prompt("chat_target_group1"),
|
||||
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1"),
|
||||
content=content,
|
||||
prompt_ger=prompt_ger,
|
||||
moderation_prompt=global_prompt_manager.get_prompt("moderation_prompt"),
|
||||
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
|
||||
)
|
||||
|
||||
return prompt
|
||||
|
||||
@@ -225,6 +225,7 @@ class Memory_graph:
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# 海马体
|
||||
class Hippocampus:
|
||||
def __init__(self):
|
||||
@@ -653,7 +654,6 @@ class Hippocampus:
|
||||
return activation_ratio
|
||||
|
||||
|
||||
|
||||
# 负责海马体与其他部分的交互
|
||||
class EntorhinalCortex:
|
||||
def __init__(self, hippocampus: Hippocampus):
|
||||
|
||||
@@ -27,7 +27,6 @@ async def test_memory_system():
|
||||
# 测试记忆检索
|
||||
test_text = "千石可乐在群里聊天"
|
||||
|
||||
|
||||
# test_text = '''千石可乐:分不清AI的陪伴和人类的陪伴,是这样吗?'''
|
||||
print(f"开始测试记忆检索,测试文本: {test_text}\n")
|
||||
memories = await hippocampus_manager.get_memory_from_text(
|
||||
|
||||
@@ -137,7 +137,7 @@ class FormatInfo:
|
||||
class TemplateInfo:
|
||||
"""模板信息类"""
|
||||
|
||||
template_items: Optional[List[Dict]] = None
|
||||
template_items: Optional[Dict] = None
|
||||
template_name: Optional[str] = None
|
||||
template_default: bool = True
|
||||
|
||||
|
||||
@@ -657,9 +657,7 @@ class LLM_request:
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
response = await self._execute_request(
|
||||
endpoint="/chat/completions", payload=data, prompt=prompt
|
||||
)
|
||||
response = await self._execute_request(endpoint="/chat/completions", payload=data, prompt=prompt)
|
||||
# 原样返回响应,不做处理
|
||||
return response
|
||||
|
||||
|
||||
@@ -242,10 +242,10 @@ class MoodManager:
|
||||
def get_arousal_multiplier(self) -> float:
|
||||
"""根据当前情绪状态返回唤醒度乘数"""
|
||||
if self.current_mood.arousal > 0.4:
|
||||
multiplier = 1 + min(0.15,(self.current_mood.arousal - 0.4)/3)
|
||||
multiplier = 1 + min(0.15, (self.current_mood.arousal - 0.4) / 3)
|
||||
return multiplier
|
||||
elif self.current_mood.arousal < -0.4:
|
||||
multiplier = 1 - min(0.15,((0 - self.current_mood.arousal) - 0.4)/3)
|
||||
multiplier = 1 - min(0.15, ((0 - self.current_mood.arousal) - 0.4) / 3)
|
||||
return multiplier
|
||||
return 1.0
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from src.plugins.config.config import global_config
|
||||
from src.plugins.chat.message import MessageRecv,MessageSending,Message
|
||||
from src.plugins.chat.message import MessageRecv, MessageSending, Message
|
||||
from src.common.database import db
|
||||
import time
|
||||
import traceback
|
||||
from typing import List
|
||||
|
||||
|
||||
class InfoCatcher:
|
||||
def __init__(self):
|
||||
self.chat_history = [] # 聊天历史,长度为三倍使用的上下文
|
||||
@@ -32,16 +33,11 @@ class InfoCatcher:
|
||||
"sub_heartflow_model": "",
|
||||
"prompt": "",
|
||||
"response": "",
|
||||
"model": ""
|
||||
"model": "",
|
||||
}
|
||||
|
||||
# 使用字典来存储 reasoning 模式的数据
|
||||
self.reasoning_data = {
|
||||
"thinking_log": "",
|
||||
"prompt": "",
|
||||
"response": "",
|
||||
"model": ""
|
||||
}
|
||||
self.reasoning_data = {"thinking_log": "", "prompt": "", "response": "", "model": ""}
|
||||
|
||||
# 耗时
|
||||
self.timing_results = {
|
||||
@@ -51,7 +47,7 @@ class InfoCatcher:
|
||||
"make_response_time": 0,
|
||||
}
|
||||
|
||||
def catch_decide_to_response(self,message:MessageRecv):
|
||||
def catch_decide_to_response(self, message: MessageRecv):
|
||||
# 搜集决定回复时的信息
|
||||
self.trigger_response_message = message
|
||||
self.trigger_response_text = message.detailed_plain_text
|
||||
@@ -62,12 +58,12 @@ class InfoCatcher:
|
||||
|
||||
self.chat_history = self.get_message_from_db_before_msg(message)
|
||||
|
||||
def catch_after_observe(self,obs_duration:float):#这里可以有更多信息
|
||||
def catch_after_observe(self, obs_duration: float): # 这里可以有更多信息
|
||||
self.timing_results["sub_heartflow_observe_time"] = obs_duration
|
||||
|
||||
# def catch_shf
|
||||
|
||||
def catch_afer_shf_step(self,step_duration:float,past_mind:str,current_mind:str):
|
||||
def catch_afer_shf_step(self, step_duration: float, past_mind: str, current_mind: str):
|
||||
self.timing_results["sub_heartflow_step_time"] = step_duration
|
||||
if len(past_mind) > 1:
|
||||
self.heartflow_data["sub_heartflow_before"] = past_mind[-1]
|
||||
@@ -76,10 +72,7 @@ class InfoCatcher:
|
||||
self.heartflow_data["sub_heartflow_before"] = past_mind[-1]
|
||||
self.heartflow_data["sub_heartflow_now"] = current_mind
|
||||
|
||||
def catch_after_llm_generated(self,prompt:str,
|
||||
response:str,
|
||||
reasoning_content:str = "",
|
||||
model_name:str = ""):
|
||||
def catch_after_llm_generated(self, prompt: str, response: str, reasoning_content: str = "", model_name: str = ""):
|
||||
if self.response_mode == "heart_flow":
|
||||
self.heartflow_data["prompt"] = prompt
|
||||
self.heartflow_data["response"] = response
|
||||
@@ -92,20 +85,20 @@ class InfoCatcher:
|
||||
|
||||
self.response_text = response
|
||||
|
||||
def catch_after_generate_response(self,response_duration:float):
|
||||
def catch_after_generate_response(self, response_duration: float):
|
||||
self.timing_results["make_response_time"] = response_duration
|
||||
|
||||
|
||||
|
||||
def catch_after_response(self,response_duration:float,
|
||||
response_message:List[str],
|
||||
first_bot_msg:MessageSending):
|
||||
def catch_after_response(
|
||||
self, response_duration: float, response_message: List[str], first_bot_msg: MessageSending
|
||||
):
|
||||
self.timing_results["make_response_time"] = response_duration
|
||||
self.response_time = time.time()
|
||||
for msg in response_message:
|
||||
self.response_messages.append(msg)
|
||||
|
||||
self.chat_history_in_thinking = self.get_message_from_db_between_msgs(self.trigger_response_message,first_bot_msg)
|
||||
self.chat_history_in_thinking = self.get_message_from_db_between_msgs(
|
||||
self.trigger_response_message, first_bot_msg
|
||||
)
|
||||
|
||||
def get_message_from_db_between_msgs(self, message_start: Message, message_end: Message):
|
||||
try:
|
||||
@@ -118,10 +111,7 @@ class InfoCatcher:
|
||||
|
||||
# 查询数据库,获取 chat_id 相同且时间在 start 和 end 之间的数据
|
||||
messages_between = db.messages.find(
|
||||
{
|
||||
"chat_id": chat_id,
|
||||
"time": {"$gt": time_start, "$lt": time_end}
|
||||
}
|
||||
{"chat_id": chat_id, "time": {"$gt": time_start, "$lt": time_end}}
|
||||
).sort("time", -1)
|
||||
|
||||
result = list(messages_between)
|
||||
@@ -140,14 +130,16 @@ class InfoCatcher:
|
||||
chat_id = message.chat_stream.stream_id
|
||||
|
||||
# 查询数据库,获取 chat_id 相同且 message_id 小于当前消息的 30 条数据
|
||||
messages_before = db.messages.find(
|
||||
{"chat_id": chat_id, "message_id": {"$lt": message_id}}
|
||||
).sort("time", -1).limit(self.context_length*3) #获取更多历史信息
|
||||
messages_before = (
|
||||
db.messages.find({"chat_id": chat_id, "message_id": {"$lt": message_id}})
|
||||
.sort("time", -1)
|
||||
.limit(self.context_length * 3)
|
||||
) # 获取更多历史信息
|
||||
|
||||
return list(messages_before)
|
||||
|
||||
def message_list_to_dict(self, message_list):
|
||||
#存储简化的聊天记录
|
||||
# 存储简化的聊天记录
|
||||
result = []
|
||||
for message in message_list:
|
||||
if not isinstance(message, dict):
|
||||
@@ -198,7 +190,7 @@ class InfoCatcher:
|
||||
"timing_results": self.timing_results,
|
||||
"chat_history": self.message_list_to_dict(self.chat_history),
|
||||
"chat_history_in_thinking": self.message_list_to_dict(self.chat_history_in_thinking),
|
||||
"chat_history_after_response": self.message_list_to_dict(self.chat_history_after_response)
|
||||
"chat_history_after_response": self.message_list_to_dict(self.chat_history_after_response),
|
||||
}
|
||||
|
||||
# 根据不同的响应模式添加相应的数据
|
||||
@@ -216,13 +208,15 @@ class InfoCatcher:
|
||||
print(traceback.format_exc())
|
||||
return False
|
||||
|
||||
|
||||
class InfoCatcherManager:
|
||||
def __init__(self):
|
||||
self.info_catchers = {}
|
||||
|
||||
def get_info_catcher(self,thinking_id:str) -> InfoCatcher:
|
||||
def get_info_catcher(self, thinking_id: str) -> InfoCatcher:
|
||||
if thinking_id not in self.info_catchers:
|
||||
self.info_catchers[thinking_id] = InfoCatcher()
|
||||
return self.info_catchers[thinking_id]
|
||||
|
||||
|
||||
info_catcher_manager = InfoCatcherManager()
|
||||
@@ -32,7 +32,7 @@ class ScheduleGenerator:
|
||||
# 使用离线LLM模型
|
||||
self.llm_scheduler_all = LLM_request(
|
||||
model=global_config.llm_reasoning,
|
||||
temperature=global_config.SCHEDULE_TEMPERATURE+0.3,
|
||||
temperature=global_config.SCHEDULE_TEMPERATURE + 0.3,
|
||||
max_tokens=7000,
|
||||
request_type="schedule",
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ from src.common.logger import get_module_logger
|
||||
|
||||
logger = get_module_logger("message_storage")
|
||||
|
||||
|
||||
class MessageStorage:
|
||||
async def store_message(self, message: Union[MessageSending, MessageRecv], chat_stream: ChatStream) -> None:
|
||||
"""存储消息到数据库"""
|
||||
|
||||
@@ -2,16 +2,69 @@
|
||||
import ast
|
||||
from typing import Dict, Any, Optional, List, Union
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
import asyncio
|
||||
|
||||
|
||||
class PromptContext:
|
||||
def __init__(self):
|
||||
self._context_prompts: Dict[str, Dict[str, "Prompt"]] = {}
|
||||
self._current_context: Optional[str] = None
|
||||
self._context_lock = asyncio.Lock() # 添加异步锁
|
||||
|
||||
@asynccontextmanager
|
||||
async def async_scope(self, context_id: str):
|
||||
"""创建一个异步的临时提示模板作用域"""
|
||||
async with self._context_lock:
|
||||
if context_id not in self._context_prompts:
|
||||
self._context_prompts[context_id] = {}
|
||||
|
||||
previous_context = self._current_context
|
||||
self._current_context = context_id
|
||||
try:
|
||||
yield self
|
||||
finally:
|
||||
async with self._context_lock:
|
||||
self._current_context = previous_context
|
||||
|
||||
async def get_prompt_async(self, name: str) -> Optional["Prompt"]:
|
||||
"""异步获取当前作用域中的提示模板"""
|
||||
async with self._context_lock:
|
||||
if self._current_context and name in self._context_prompts[self._current_context]:
|
||||
return self._context_prompts[self._current_context][name]
|
||||
return None
|
||||
|
||||
async def register_async(self, prompt: "Prompt", context_id: Optional[str] = None) -> None:
|
||||
"""异步注册提示模板到指定作用域"""
|
||||
async with self._context_lock:
|
||||
target_context = context_id or self._current_context
|
||||
if target_context:
|
||||
self._context_prompts.setdefault(target_context, {})[prompt.name] = prompt
|
||||
|
||||
|
||||
class PromptManager:
|
||||
_instance = None
|
||||
def __init__(self):
|
||||
self._prompts = {}
|
||||
self._counter = 0
|
||||
self._context = PromptContext()
|
||||
self._lock = asyncio.Lock()
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._prompts = {}
|
||||
cls._instance._counter = 0
|
||||
return cls._instance
|
||||
@asynccontextmanager
|
||||
async def async_message_scope(self, message_id: str):
|
||||
"""为消息处理创建异步临时作用域"""
|
||||
async with self._context.async_scope(message_id):
|
||||
yield self
|
||||
|
||||
async def get_prompt_async(self, name: str) -> "Prompt":
|
||||
# 首先尝试从当前上下文获取
|
||||
context_prompt = await self._context.get_prompt_async(name)
|
||||
if context_prompt is not None:
|
||||
return context_prompt
|
||||
# 如果上下文中不存在,则使用全局提示模板
|
||||
async with self._lock:
|
||||
if name not in self._prompts:
|
||||
raise KeyError(f"Prompt '{name}' not found")
|
||||
return self._prompts[name]
|
||||
|
||||
def generate_name(self, template: str) -> str:
|
||||
"""为未命名的prompt生成名称"""
|
||||
@@ -29,13 +82,8 @@ class PromptManager:
|
||||
self._prompts[prompt.name] = prompt
|
||||
return prompt
|
||||
|
||||
def get_prompt(self, name: str) -> "Prompt":
|
||||
if name not in self._prompts:
|
||||
raise KeyError(f"Prompt '{name}' not found")
|
||||
return self._prompts[name]
|
||||
|
||||
def format_prompt(self, name: str, **kwargs) -> str:
|
||||
prompt = self.get_prompt(name)
|
||||
async def format_prompt(self, name: str, **kwargs) -> str:
|
||||
prompt = await self.get_prompt_async(name)
|
||||
return prompt.format(**kwargs)
|
||||
|
||||
|
||||
@@ -71,10 +119,26 @@ class Prompt(str):
|
||||
obj._args = args or []
|
||||
obj._kwargs = kwargs
|
||||
|
||||
# 自动注册到全局管理器
|
||||
# 修改自动注册逻辑
|
||||
if global_prompt_manager._context._current_context:
|
||||
# 如果存在当前上下文,则注册到上下文中
|
||||
# asyncio.create_task(global_prompt_manager._context.register_async(obj))
|
||||
pass
|
||||
else:
|
||||
# 否则注册到全局管理器
|
||||
global_prompt_manager.register(obj)
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
async def create_async(
|
||||
cls, fstr: str, name: Optional[str] = None, args: Union[List[Any], tuple[Any, ...]] = None, **kwargs
|
||||
):
|
||||
"""异步创建Prompt实例"""
|
||||
prompt = cls(fstr, name, args, **kwargs)
|
||||
if global_prompt_manager._context._current_context:
|
||||
await global_prompt_manager._context.register_async(prompt)
|
||||
return prompt
|
||||
|
||||
@classmethod
|
||||
def _format_template(cls, template: str, args: List[Any] = None, kwargs: Dict[str, Any] = None) -> str:
|
||||
fmt_str = f"f'''{template}'''"
|
||||
|
||||
@@ -337,7 +337,7 @@ class LLMStatistics:
|
||||
stats_output = self._format_stats_section_lite(
|
||||
hour_stats, "最近1小时统计:详细信息见根目录文件:llm_statistics.txt"
|
||||
)
|
||||
logger.info("\n" + stats_output + "\n" + "=" * 50)
|
||||
logger.debug("\n" + stats_output + "\n" + "=" * 50)
|
||||
|
||||
except Exception:
|
||||
logger.exception("控制台统计数据输出失败")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
from .willing_manager import BaseWillingManager
|
||||
|
||||
|
||||
class ClassicalWillingManager(BaseWillingManager):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -41,10 +42,15 @@ class ClassicalWillingManager(BaseWillingManager):
|
||||
|
||||
self.chat_reply_willing[chat_id] = min(current_willing, 3.0)
|
||||
|
||||
reply_probability = min(max((current_willing - 0.5), 0.01) * self.global_config.response_willing_amplifier * 2, 1)
|
||||
reply_probability = min(
|
||||
max((current_willing - 0.5), 0.01) * self.global_config.response_willing_amplifier * 2, 1
|
||||
)
|
||||
|
||||
# 检查群组权限(如果是群聊)
|
||||
if willing_info.group_info and willing_info.group_info.group_id in self.global_config.talk_frequency_down_groups:
|
||||
if (
|
||||
willing_info.group_info
|
||||
and willing_info.group_info.group_id in self.global_config.talk_frequency_down_groups
|
||||
):
|
||||
reply_probability = reply_probability / self.global_config.down_frequency_rate
|
||||
|
||||
if is_emoji_not_reply:
|
||||
@@ -74,5 +80,3 @@ class ClassicalWillingManager(BaseWillingManager):
|
||||
|
||||
async def set_variable_parameters(self, parameters):
|
||||
return await super().set_variable_parameters(parameters)
|
||||
|
||||
|
||||
|
||||
@@ -4,4 +4,3 @@ from .willing_manager import BaseWillingManager
|
||||
class CustomWillingManager(BaseWillingManager):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ class DynamicWillingManager(BaseWillingManager):
|
||||
self._decay_task = None
|
||||
self._mode_switch_task = None
|
||||
|
||||
|
||||
async def async_task_starter(self):
|
||||
if self._decay_task is None:
|
||||
self._decay_task = asyncio.create_task(self._decay_reply_willing())
|
||||
@@ -84,7 +83,9 @@ class DynamicWillingManager(BaseWillingManager):
|
||||
self.chat_high_willing_mode[chat_id] = True
|
||||
self.chat_reply_willing[chat_id] = 1.0 # 设置为较高回复意愿
|
||||
self.chat_high_willing_duration[chat_id] = random.randint(180, 240) # 3-4分钟
|
||||
self.logger.debug(f"聊天流 {chat_id} 切换到高回复意愿期,持续 {self.chat_high_willing_duration[chat_id]} 秒")
|
||||
self.logger.debug(
|
||||
f"聊天流 {chat_id} 切换到高回复意愿期,持续 {self.chat_high_willing_duration[chat_id]} 秒"
|
||||
)
|
||||
|
||||
self.chat_last_mode_change[chat_id] = time.time()
|
||||
self.chat_msg_count[chat_id] = 0 # 重置消息计数
|
||||
@@ -148,7 +149,9 @@ class DynamicWillingManager(BaseWillingManager):
|
||||
|
||||
# 根据话题兴趣度适当调整
|
||||
if willing_info.interested_rate > 0.5:
|
||||
current_willing += (willing_info.interested_rate - 0.5) * 0.5 * self.global_config.response_interested_rate_amplifier
|
||||
current_willing += (
|
||||
(willing_info.interested_rate - 0.5) * 0.5 * self.global_config.response_interested_rate_amplifier
|
||||
)
|
||||
|
||||
# 根据当前模式计算回复概率
|
||||
base_probability = 0.0
|
||||
|
||||
@@ -17,14 +17,17 @@ Mxp 模式:梦溪畔独家赞助
|
||||
中策是发issue
|
||||
下下策是询问一个菜鸟(@梦溪畔)
|
||||
"""
|
||||
|
||||
from .willing_manager import BaseWillingManager
|
||||
from typing import Dict
|
||||
import asyncio
|
||||
import time
|
||||
import math
|
||||
|
||||
|
||||
class MxpWillingManager(BaseWillingManager):
|
||||
"""Mxp意愿管理器"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.chat_person_reply_willing: Dict[str, Dict[str, float]] = {} # chat_id: {person_id: 意愿值}
|
||||
@@ -73,9 +76,16 @@ class MxpWillingManager(BaseWillingManager):
|
||||
w_info = self.ongoing_messages[message_id]
|
||||
if w_info.is_mentioned_bot:
|
||||
self.chat_person_reply_willing[w_info.chat_id][w_info.person_id] += 0.2
|
||||
if w_info.chat_id in self.last_response_person and self.last_response_person[w_info.chat_id][0] == w_info.person_id:
|
||||
self.chat_person_reply_willing[w_info.chat_id][w_info.person_id] +=\
|
||||
self.single_chat_gain * (2 * self.last_response_person[w_info.chat_id][1] + 1)
|
||||
if (
|
||||
w_info.chat_id in self.last_response_person
|
||||
and self.last_response_person[w_info.chat_id][0] == w_info.person_id
|
||||
):
|
||||
self.chat_person_reply_willing[w_info.chat_id][w_info.person_id] += self.single_chat_gain * (
|
||||
2 * self.last_response_person[w_info.chat_id][1] + 1
|
||||
)
|
||||
now_chat_new_person = self.last_response_person.get(w_info.chat_id, ["", 0])
|
||||
if now_chat_new_person[0] != w_info.person_id:
|
||||
self.last_response_person[w_info.chat_id] = [w_info.person_id, 0]
|
||||
|
||||
async def get_reply_probability(self, message_id: str):
|
||||
"""获取回复概率"""
|
||||
@@ -95,7 +105,10 @@ class MxpWillingManager(BaseWillingManager):
|
||||
rel_level = self._get_relationship_level_num(rel_value)
|
||||
current_willing += rel_level * 0.1
|
||||
|
||||
if w_info.chat_id in self.last_response_person and self.last_response_person[w_info.chat_id][0] == w_info.person_id:
|
||||
if (
|
||||
w_info.chat_id in self.last_response_person
|
||||
and self.last_response_person[w_info.chat_id][0] == w_info.person_id
|
||||
):
|
||||
current_willing += self.single_chat_gain * (2 * self.last_response_person[w_info.chat_id][1] + 1)
|
||||
|
||||
chat_ongoing_messages = [msg for msg in self.ongoing_messages.values() if msg.chat_id == w_info.chat_id]
|
||||
@@ -138,16 +151,22 @@ class MxpWillingManager(BaseWillingManager):
|
||||
self.logger.debug(f"聊天流{chat_id}不存在,错误")
|
||||
continue
|
||||
basic_willing = self.chat_reply_willing[chat_id]
|
||||
person_willing[person_id] = basic_willing + (willing - basic_willing) * self.intention_decay_rate
|
||||
person_willing[person_id] = (
|
||||
basic_willing + (willing - basic_willing) * self.intention_decay_rate
|
||||
)
|
||||
|
||||
def setup(self, message, chat, is_mentioned_bot, interested_rate):
|
||||
super().setup(message, chat, is_mentioned_bot, interested_rate)
|
||||
|
||||
self.chat_reply_willing[chat.stream_id] = self.chat_reply_willing.get(chat.stream_id, self.basic_maximum_willing)
|
||||
self.chat_reply_willing[chat.stream_id] = self.chat_reply_willing.get(
|
||||
chat.stream_id, self.basic_maximum_willing
|
||||
)
|
||||
self.chat_person_reply_willing[chat.stream_id] = self.chat_person_reply_willing.get(chat.stream_id, {})
|
||||
self.chat_person_reply_willing[chat.stream_id][self.ongoing_messages[message.message_info.message_id].person_id] = \
|
||||
self.chat_person_reply_willing[chat.stream_id].get(self.ongoing_messages[message.message_info.message_id].person_id,
|
||||
self.chat_reply_willing[chat.stream_id])
|
||||
self.chat_person_reply_willing[chat.stream_id][
|
||||
self.ongoing_messages[message.message_info.message_id].person_id
|
||||
] = self.chat_person_reply_willing[chat.stream_id].get(
|
||||
self.ongoing_messages[message.message_info.message_id].person_id, self.chat_reply_willing[chat.stream_id]
|
||||
)
|
||||
|
||||
if chat.stream_id not in self.chat_new_message_time:
|
||||
self.chat_new_message_time[chat.stream_id] = []
|
||||
@@ -171,10 +190,11 @@ class MxpWillingManager(BaseWillingManager):
|
||||
await asyncio.sleep(update_time)
|
||||
async with self.lock:
|
||||
for chat_id, message_times in self.chat_new_message_time.items():
|
||||
|
||||
# 清理过期消息
|
||||
current_time = time.time()
|
||||
message_times = [msg_time for msg_time in message_times if current_time - msg_time < self.message_expiration_time]
|
||||
message_times = [
|
||||
msg_time for msg_time in message_times if current_time - msg_time < self.message_expiration_time
|
||||
]
|
||||
self.chat_new_message_time[chat_id] = message_times
|
||||
|
||||
if len(message_times) < self.number_of_message_storage:
|
||||
@@ -182,7 +202,9 @@ class MxpWillingManager(BaseWillingManager):
|
||||
update_time = 20
|
||||
elif len(message_times) == self.number_of_message_storage:
|
||||
time_interval = current_time - message_times[0]
|
||||
basic_willing = self.basic_maximum_willing * math.sqrt(time_interval / self.message_expiration_time)
|
||||
basic_willing = self.basic_maximum_willing * math.sqrt(
|
||||
time_interval / self.message_expiration_time
|
||||
)
|
||||
self.chat_reply_willing[chat_id] = basic_willing
|
||||
update_time = 17 * math.sqrt(time_interval / self.message_expiration_time) + 3
|
||||
else:
|
||||
@@ -200,7 +222,7 @@ class MxpWillingManager(BaseWillingManager):
|
||||
"interest_willing_gain": "兴趣意愿增益",
|
||||
"emoji_response_penalty": "表情包回复惩罚",
|
||||
"down_frequency_rate": "降低回复频率的群组惩罚系数",
|
||||
"single_chat_gain": "单聊增益(不仅是私聊)"
|
||||
"single_chat_gain": "单聊增益(不仅是私聊)",
|
||||
}
|
||||
|
||||
async def set_variable_parameters(self, parameters: Dict[str, any]):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
from src.common.logger import LogConfig, WILLING_STYLE_CONFIG, LoguruLogger, get_module_logger
|
||||
from dataclasses import dataclass
|
||||
from ..config.config import global_config, BotConfig
|
||||
@@ -38,6 +37,7 @@ willing_config = LogConfig(
|
||||
)
|
||||
logger = get_module_logger("willing", config=willing_config)
|
||||
|
||||
|
||||
@dataclass
|
||||
class WillingInfo:
|
||||
"""此类保存意愿模块常用的参数
|
||||
@@ -53,6 +53,7 @@ class WillingInfo:
|
||||
is_emoji (bool): 是否为表情包
|
||||
interested_rate (float): 兴趣度
|
||||
"""
|
||||
|
||||
message: MessageRecv
|
||||
chat: ChatStream
|
||||
person_info_manager: PersonInfoManager
|
||||
@@ -64,18 +65,17 @@ class WillingInfo:
|
||||
interested_rate: float
|
||||
# current_mood: float 当前心情?
|
||||
|
||||
|
||||
class BaseWillingManager(ABC):
|
||||
"""回复意愿管理基类"""
|
||||
|
||||
@classmethod
|
||||
def create(cls, manager_type: str) -> 'BaseWillingManager':
|
||||
def create(cls, manager_type: str) -> "BaseWillingManager":
|
||||
try:
|
||||
module = importlib.import_module(f".mode_{manager_type}", __package__)
|
||||
manager_class = getattr(module, f"{manager_type.capitalize()}WillingManager")
|
||||
if not issubclass(manager_class, cls):
|
||||
raise TypeError(
|
||||
f"Manager class {manager_class.__name__} is not a subclass of {cls.__name__}"
|
||||
)
|
||||
raise TypeError(f"Manager class {manager_class.__name__} is not a subclass of {cls.__name__}")
|
||||
else:
|
||||
logger.info(f"成功载入willing模式:{manager_type}")
|
||||
return manager_class()
|
||||
@@ -173,5 +173,6 @@ def init_willing_manager() -> BaseWillingManager:
|
||||
mode = global_config.willing_mode.lower()
|
||||
return BaseWillingManager.create(mode)
|
||||
|
||||
|
||||
# 全局willing_manager对象
|
||||
willing_manager = init_willing_manager()
|
||||
|
||||
@@ -42,8 +42,8 @@ if errorlevel 2 (
|
||||
echo Conda 环境 "!CONDA_ENV!" 激活成功
|
||||
python src/plugins/zhishi/knowledge_library.py
|
||||
) else (
|
||||
if exist "venv\Scripts\python.exe" (
|
||||
venv\Scripts\python src/plugins/zhishi/knowledge_library.py
|
||||
if exist "..\maibot_env\Scripts\python.exe" (
|
||||
..\maibot_env\Scripts\python src/plugins/zhishi/knowledge_library.py
|
||||
) else (
|
||||
echo ======================================
|
||||
echo 错误: venv环境不存在,请先创建虚拟环境
|
||||
|
||||
@@ -42,8 +42,8 @@ if errorlevel 2 (
|
||||
echo Conda 环境 "!CONDA_ENV!" 激活成功
|
||||
python src/individuality/per_bf_gen.py
|
||||
) else (
|
||||
if exist "venv\Scripts\python.exe" (
|
||||
venv\Scripts\python src/individuality/per_bf_gen.py
|
||||
if exist "..\maibot_env\Scripts\python.exe" (
|
||||
..\maibot_env\Scripts\python src/individuality/per_bf_gen.py
|
||||
) else (
|
||||
echo ======================================
|
||||
echo 错误: venv环境不存在,请先创建虚拟环境
|
||||
|
||||
Reference in New Issue
Block a user