better:重构personinfo,使用Person类和类属性
This commit is contained in:
@@ -17,7 +17,7 @@ from src.chat.planner_actions.action_manager import ActionManager
|
|||||||
from src.chat.chat_loop.hfc_utils import CycleDetail
|
from src.chat.chat_loop.hfc_utils import CycleDetail
|
||||||
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
||||||
from src.chat.express.expression_learner import expression_learner_manager
|
from src.chat.express.expression_learner import expression_learner_manager
|
||||||
from src.person_info.person_info import get_person_info_manager
|
from src.person_info.person_info import Person
|
||||||
from src.person_info.group_relationship_manager import get_group_relationship_manager
|
from src.person_info.group_relationship_manager import get_group_relationship_manager
|
||||||
from src.plugin_system.base.component_types import ChatMode, EventType
|
from src.plugin_system.base.component_types import ChatMode, EventType
|
||||||
from src.plugin_system.core import events_manager
|
from src.plugin_system.core import events_manager
|
||||||
@@ -307,19 +307,13 @@ class HeartFChatting:
|
|||||||
with Timer("回复发送", cycle_timers):
|
with Timer("回复发送", cycle_timers):
|
||||||
reply_text = await self._send_response(response_set, action_message)
|
reply_text = await self._send_response(response_set, action_message)
|
||||||
|
|
||||||
# 存储reply action信息
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
|
|
||||||
# 获取 platform,如果不存在则从 chat_stream 获取,如果还是 None 则使用默认值
|
# 获取 platform,如果不存在则从 chat_stream 获取,如果还是 None 则使用默认值
|
||||||
platform = action_message.get("chat_info_platform")
|
platform = action_message.get("chat_info_platform")
|
||||||
if platform is None:
|
if platform is None:
|
||||||
platform = getattr(self.chat_stream, "platform", "unknown")
|
platform = getattr(self.chat_stream, "platform", "unknown")
|
||||||
|
|
||||||
person_id = person_info_manager.get_person_id(
|
person = Person(platform = platform ,user_id = action_message.get("user_id", ""))
|
||||||
platform,
|
person_name = person.person_name
|
||||||
action_message.get("user_id", ""),
|
|
||||||
)
|
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
|
||||||
action_prompt_display = f"你对{person_name}进行了回复:{reply_text}"
|
action_prompt_display = f"你对{person_name}进行了回复:{reply_text}"
|
||||||
|
|
||||||
await database_api.store_action_info(
|
await database_api.store_action_info(
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ class ExpressionLearner:
|
|||||||
logger.info(f"在 {group_name} 学习到表达风格:\n{learnt_expressions_str}")
|
logger.info(f"在 {group_name} 学习到表达风格:\n{learnt_expressions_str}")
|
||||||
|
|
||||||
if not learnt_expressions:
|
if not learnt_expressions:
|
||||||
logger.info(f"没有学习到表达风格")
|
logger.info("没有学习到表达风格")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# 按chat_id分组
|
# 按chat_id分组
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import time
|
|||||||
import random
|
import random
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from typing import List, Dict, Tuple, Optional, Any
|
from typing import List, Dict, Optional, Any
|
||||||
from json_repair import repair_json
|
from json_repair import repair_json
|
||||||
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
@@ -22,16 +22,22 @@ def init_prompt():
|
|||||||
|
|
||||||
你的名字是{bot_name}{target_message}
|
你的名字是{bot_name}{target_message}
|
||||||
|
|
||||||
你知道以下这些表达方式,梗和说话方式:
|
以下是可选的表达情境:
|
||||||
{all_situations}
|
{all_situations}
|
||||||
|
|
||||||
现在,请你根据聊天记录从中挑选合适的表达方式,梗和说话方式,组织一条回复风格指导,指导的目的是在组织回复的时候提供一些语言风格和梗上的参考。
|
请你分析聊天内容的语境、情绪、话题类型,从上述情境中选择最适合当前聊天情境的,最多{max_num}个情境。
|
||||||
请在reply_style_guide中以平文本输出指导,不要浮夸,并在selected_expressions中说明在指导中你挑选了哪些表达方式,梗和说话方式,以json格式输出:
|
考虑因素包括:
|
||||||
例子:
|
1. 聊天的情绪氛围(轻松、严肃、幽默等)
|
||||||
|
2. 话题类型(日常、技术、游戏、情感等)
|
||||||
|
3. 情境与当前语境的匹配度
|
||||||
|
{target_message_extra_block}
|
||||||
|
|
||||||
|
请以JSON格式输出,只需要输出选中的情境编号:
|
||||||
|
例如:
|
||||||
{{
|
{{
|
||||||
"reply_style_guide": "...",
|
"selected_situations": [2, 3, 5, 7, 19]
|
||||||
"selected_expressions": [2, 3, 4, 7]
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
请严格按照JSON格式输出,不要包含其他内容:
|
请严格按照JSON格式输出,不要包含其他内容:
|
||||||
"""
|
"""
|
||||||
Prompt(expression_evaluation_prompt, "expression_evaluation_prompt")
|
Prompt(expression_evaluation_prompt, "expression_evaluation_prompt")
|
||||||
@@ -190,14 +196,14 @@ class ExpressionSelector:
|
|||||||
chat_info: str,
|
chat_info: str,
|
||||||
max_num: int = 10,
|
max_num: int = 10,
|
||||||
target_message: Optional[str] = None,
|
target_message: Optional[str] = None,
|
||||||
) -> Tuple[str, List[Dict[str, Any]]]:
|
) -> List[Dict[str, Any]]:
|
||||||
# sourcery skip: inline-variable, list-comprehension
|
# sourcery skip: inline-variable, list-comprehension
|
||||||
"""使用LLM选择适合的表达方式"""
|
"""使用LLM选择适合的表达方式"""
|
||||||
|
|
||||||
# 检查是否允许在此聊天流中使用表达
|
# 检查是否允许在此聊天流中使用表达
|
||||||
if not self.can_use_expression_for_chat(chat_id):
|
if not self.can_use_expression_for_chat(chat_id):
|
||||||
logger.debug(f"聊天流 {chat_id} 不允许使用表达,返回空列表")
|
logger.debug(f"聊天流 {chat_id} 不允许使用表达,返回空列表")
|
||||||
return "", []
|
return []
|
||||||
|
|
||||||
# 1. 获取20个随机表达方式(现在按权重抽取)
|
# 1. 获取20个随机表达方式(现在按权重抽取)
|
||||||
style_exprs = self.get_random_expressions(chat_id, 10)
|
style_exprs = self.get_random_expressions(chat_id, 10)
|
||||||
@@ -216,7 +222,7 @@ class ExpressionSelector:
|
|||||||
|
|
||||||
if not all_expressions:
|
if not all_expressions:
|
||||||
logger.warning("没有找到可用的表达方式")
|
logger.warning("没有找到可用的表达方式")
|
||||||
return "", []
|
return []
|
||||||
|
|
||||||
all_situations_str = "\n".join(all_situations)
|
all_situations_str = "\n".join(all_situations)
|
||||||
|
|
||||||
@@ -255,24 +261,23 @@ class ExpressionSelector:
|
|||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
logger.warning("LLM返回空结果")
|
logger.warning("LLM返回空结果")
|
||||||
return "", []
|
return []
|
||||||
|
|
||||||
# 5. 解析结果
|
# 5. 解析结果
|
||||||
result = repair_json(content)
|
result = repair_json(content)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
result = json.loads(result)
|
result = json.loads(result)
|
||||||
|
|
||||||
if not isinstance(result, dict) or "reply_style_guide" not in result or "selected_expressions" not in result:
|
if not isinstance(result, dict) or "selected_situations" not in result:
|
||||||
logger.error("LLM返回格式错误")
|
logger.error("LLM返回格式错误")
|
||||||
logger.info(f"LLM返回结果: \n{content}")
|
logger.info(f"LLM返回结果: \n{content}")
|
||||||
return "", []
|
return []
|
||||||
|
|
||||||
reply_style_guide = result["reply_style_guide"]
|
selected_indices = result["selected_situations"]
|
||||||
selected_expressions = result["selected_expressions"]
|
|
||||||
|
|
||||||
# 根据索引获取完整的表达方式
|
# 根据索引获取完整的表达方式
|
||||||
valid_expressions = []
|
valid_expressions = []
|
||||||
for idx in selected_expressions:
|
for idx in selected_indices:
|
||||||
if isinstance(idx, int) and 1 <= idx <= len(all_expressions):
|
if isinstance(idx, int) and 1 <= idx <= len(all_expressions):
|
||||||
expression = all_expressions[idx - 1] # 索引从1开始
|
expression = all_expressions[idx - 1] # 索引从1开始
|
||||||
valid_expressions.append(expression)
|
valid_expressions.append(expression)
|
||||||
@@ -282,11 +287,11 @@ class ExpressionSelector:
|
|||||||
self.update_expressions_count_batch(valid_expressions, 0.006)
|
self.update_expressions_count_batch(valid_expressions, 0.006)
|
||||||
|
|
||||||
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
||||||
return reply_style_guide, valid_expressions
|
return valid_expressions
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"LLM处理表达方式选择时出错: {e}")
|
logger.error(f"LLM处理表达方式选择时出错: {e}")
|
||||||
return "", []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,22 +22,16 @@ def init_prompt():
|
|||||||
|
|
||||||
你的名字是{bot_name}{target_message}
|
你的名字是{bot_name}{target_message}
|
||||||
|
|
||||||
以下是可选的表达情境:
|
你知道以下这些表达方式,梗和说话方式:
|
||||||
{all_situations}
|
{all_situations}
|
||||||
|
|
||||||
请你分析聊天内容的语境、情绪、话题类型,从上述情境中选择最适合当前聊天情境的,最多{max_num}个情境。
|
现在,请你根据聊天记录从中挑选合适的表达方式,梗和说话方式,组织一条回复风格指导,指导的目的是在组织回复的时候提供一些语言风格和梗上的参考。
|
||||||
考虑因素包括:
|
请在reply_style_guide中以平文本输出指导,不要浮夸,并在selected_expressions中说明在指导中你挑选了哪些表达方式,梗和说话方式,以json格式输出:
|
||||||
1. 聊天的情绪氛围(轻松、严肃、幽默等)
|
例子:
|
||||||
2. 话题类型(日常、技术、游戏、情感等)
|
|
||||||
3. 情境与当前语境的匹配度
|
|
||||||
{target_message_extra_block}
|
|
||||||
|
|
||||||
请以JSON格式输出,只需要输出选中的情境编号:
|
|
||||||
例如:
|
|
||||||
{{
|
{{
|
||||||
"selected_situations": [2, 3, 5, 7, 19]
|
"reply_style_guide": "...",
|
||||||
|
"selected_expressions": [2, 3, 4, 7]
|
||||||
}}
|
}}
|
||||||
|
|
||||||
请严格按照JSON格式输出,不要包含其他内容:
|
请严格按照JSON格式输出,不要包含其他内容:
|
||||||
"""
|
"""
|
||||||
Prompt(expression_evaluation_prompt, "expression_evaluation_prompt")
|
Prompt(expression_evaluation_prompt, "expression_evaluation_prompt")
|
||||||
@@ -196,14 +190,14 @@ class ExpressionSelector:
|
|||||||
chat_info: str,
|
chat_info: str,
|
||||||
max_num: int = 10,
|
max_num: int = 10,
|
||||||
target_message: Optional[str] = None,
|
target_message: Optional[str] = None,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> Tuple[str, List[Dict[str, Any]]]:
|
||||||
# sourcery skip: inline-variable, list-comprehension
|
# sourcery skip: inline-variable, list-comprehension
|
||||||
"""使用LLM选择适合的表达方式"""
|
"""使用LLM选择适合的表达方式"""
|
||||||
|
|
||||||
# 检查是否允许在此聊天流中使用表达
|
# 检查是否允许在此聊天流中使用表达
|
||||||
if not self.can_use_expression_for_chat(chat_id):
|
if not self.can_use_expression_for_chat(chat_id):
|
||||||
logger.debug(f"聊天流 {chat_id} 不允许使用表达,返回空列表")
|
logger.debug(f"聊天流 {chat_id} 不允许使用表达,返回空列表")
|
||||||
return []
|
return "", []
|
||||||
|
|
||||||
# 1. 获取20个随机表达方式(现在按权重抽取)
|
# 1. 获取20个随机表达方式(现在按权重抽取)
|
||||||
style_exprs = self.get_random_expressions(chat_id, 10)
|
style_exprs = self.get_random_expressions(chat_id, 10)
|
||||||
@@ -222,7 +216,7 @@ class ExpressionSelector:
|
|||||||
|
|
||||||
if not all_expressions:
|
if not all_expressions:
|
||||||
logger.warning("没有找到可用的表达方式")
|
logger.warning("没有找到可用的表达方式")
|
||||||
return []
|
return "", []
|
||||||
|
|
||||||
all_situations_str = "\n".join(all_situations)
|
all_situations_str = "\n".join(all_situations)
|
||||||
|
|
||||||
@@ -261,23 +255,24 @@ class ExpressionSelector:
|
|||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
logger.warning("LLM返回空结果")
|
logger.warning("LLM返回空结果")
|
||||||
return []
|
return "", []
|
||||||
|
|
||||||
# 5. 解析结果
|
# 5. 解析结果
|
||||||
result = repair_json(content)
|
result = repair_json(content)
|
||||||
if isinstance(result, str):
|
if isinstance(result, str):
|
||||||
result = json.loads(result)
|
result = json.loads(result)
|
||||||
|
|
||||||
if not isinstance(result, dict) or "selected_situations" not in result:
|
if not isinstance(result, dict) or "reply_style_guide" not in result or "selected_expressions" not in result:
|
||||||
logger.error("LLM返回格式错误")
|
logger.error("LLM返回格式错误")
|
||||||
logger.info(f"LLM返回结果: \n{content}")
|
logger.info(f"LLM返回结果: \n{content}")
|
||||||
return []
|
return "", []
|
||||||
|
|
||||||
selected_indices = result["selected_situations"]
|
reply_style_guide = result["reply_style_guide"]
|
||||||
|
selected_expressions = result["selected_expressions"]
|
||||||
|
|
||||||
# 根据索引获取完整的表达方式
|
# 根据索引获取完整的表达方式
|
||||||
valid_expressions = []
|
valid_expressions = []
|
||||||
for idx in selected_indices:
|
for idx in selected_expressions:
|
||||||
if isinstance(idx, int) and 1 <= idx <= len(all_expressions):
|
if isinstance(idx, int) and 1 <= idx <= len(all_expressions):
|
||||||
expression = all_expressions[idx - 1] # 索引从1开始
|
expression = all_expressions[idx - 1] # 索引从1开始
|
||||||
valid_expressions.append(expression)
|
valid_expressions.append(expression)
|
||||||
@@ -287,11 +282,11 @@ class ExpressionSelector:
|
|||||||
self.update_expressions_count_batch(valid_expressions, 0.006)
|
self.update_expressions_count_batch(valid_expressions, 0.006)
|
||||||
|
|
||||||
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
# logger.info(f"LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个")
|
||||||
return valid_expressions
|
return reply_style_guide, valid_expressions
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"LLM处理表达方式选择时出错: {e}")
|
logger.error(f"LLM处理表达方式选择时出错: {e}")
|
||||||
return []
|
return "", []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -14,34 +14,14 @@ from src.chat.utils.utils import is_mentioned_bot_in_message
|
|||||||
from src.chat.utils.timer_calculator import Timer
|
from src.chat.utils.timer_calculator import Timer
|
||||||
from src.chat.utils.chat_message_builder import replace_user_references_sync
|
from src.chat.utils.chat_message_builder import replace_user_references_sync
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.person_info.relationship_manager import get_relationship_manager
|
|
||||||
from src.mood.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
|
from src.person_info.person_info import Person
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from src.chat.heart_flow.sub_heartflow import SubHeartflow
|
from src.chat.heart_flow.sub_heartflow import SubHeartflow
|
||||||
|
|
||||||
logger = get_logger("chat")
|
logger = get_logger("chat")
|
||||||
|
|
||||||
|
|
||||||
async def _process_relationship(message: MessageRecv) -> None:
|
|
||||||
"""处理用户关系逻辑
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message: 消息对象,包含用户信息
|
|
||||||
"""
|
|
||||||
platform = message.message_info.platform
|
|
||||||
user_id = message.message_info.user_info.user_id # type: ignore
|
|
||||||
nickname = message.message_info.user_info.user_nickname # type: ignore
|
|
||||||
cardname = message.message_info.user_info.user_cardname or nickname # type: ignore
|
|
||||||
|
|
||||||
relationship_manager = get_relationship_manager()
|
|
||||||
is_known = await relationship_manager.is_known_some_one(platform, user_id)
|
|
||||||
|
|
||||||
if not is_known:
|
|
||||||
logger.info(f"首次认识用户: {nickname}")
|
|
||||||
await relationship_manager.first_knowing_some_one(platform, user_id, nickname, cardname) # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
async def _calculate_interest(message: MessageRecv) -> Tuple[float, bool, list[str]]:
|
async def _calculate_interest(message: MessageRecv) -> Tuple[float, bool, list[str]]:
|
||||||
"""计算消息的兴趣度
|
"""计算消息的兴趣度
|
||||||
|
|
||||||
@@ -165,7 +145,7 @@ class HeartFCMessageReceiver:
|
|||||||
|
|
||||||
# 4. 关系处理
|
# 4. 关系处理
|
||||||
if global_config.relationship.enable_relationship:
|
if global_config.relationship.enable_relationship:
|
||||||
await _process_relationship(message)
|
person = Person(platform=message.message_info.platform, user_id=message.message_info.user_info.user_id,nickname=userinfo.user_nickname)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"消息处理失败: {e}")
|
logger.error(f"消息处理失败: {e}")
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from datetime import datetime
|
|||||||
from src.mais4u.mai_think import mai_thinking_manager
|
from src.mais4u.mai_think import mai_thinking_manager
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.config.config import global_config, model_config
|
from src.config.config import global_config, model_config
|
||||||
from src.config.api_ada_configs import TaskConfig
|
|
||||||
from src.individuality.individuality import get_individuality
|
from src.individuality.individuality import get_individuality
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.chat.message_receive.message import UserInfo, Seg, MessageRecv, MessageSending
|
from src.chat.message_receive.message import UserInfo, Seg, MessageRecv, MessageSending
|
||||||
@@ -27,8 +26,7 @@ from src.chat.express.expression_selector import expression_selector
|
|||||||
from src.chat.memory_system.memory_activator import MemoryActivator
|
from src.chat.memory_system.memory_activator import MemoryActivator
|
||||||
from src.chat.memory_system.instant_memory import InstantMemory
|
from src.chat.memory_system.instant_memory import InstantMemory
|
||||||
from src.mood.mood_manager import mood_manager
|
from src.mood.mood_manager import mood_manager
|
||||||
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
from src.person_info.person_info import Person
|
||||||
from src.person_info.person_info import get_person_info_manager
|
|
||||||
from src.plugin_system.base.component_types import ActionInfo, EventType
|
from src.plugin_system.base.component_types import ActionInfo, EventType
|
||||||
from src.plugin_system.apis import llm_api
|
from src.plugin_system.apis import llm_api
|
||||||
|
|
||||||
@@ -302,16 +300,14 @@ class DefaultReplyer:
|
|||||||
if not global_config.relationship.enable_relationship:
|
if not global_config.relationship.enable_relationship:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
relationship_fetcher = relationship_fetcher_manager.get_fetcher(self.chat_stream.stream_id)
|
|
||||||
|
|
||||||
# 获取用户ID
|
# 获取用户ID
|
||||||
person_info_manager = get_person_info_manager()
|
person = Person(platform=self.chat_stream.platform, user_id=sender)
|
||||||
person_id = person_info_manager.get_person_id_by_person_name(sender)
|
person_id = person.person_id
|
||||||
if not person_id:
|
if not person_id:
|
||||||
logger.warning(f"未找到用户 {sender} 的ID,跳过信息提取")
|
logger.warning(f"未找到用户 {sender} 的ID,跳过信息提取")
|
||||||
return f"你完全不认识{sender},不理解ta的相关信息。"
|
return f"你完全不认识{sender},不理解ta的相关信息。"
|
||||||
|
|
||||||
return await relationship_fetcher.build_relation_info(person_id, points_num=5)
|
return person.build_relationship(points_num=5)
|
||||||
|
|
||||||
async def build_expression_habits(self, chat_history: str, target: str) -> Tuple[str, str]:
|
async def build_expression_habits(self, chat_history: str, target: str) -> Tuple[str, str]:
|
||||||
"""构建表达习惯块
|
"""构建表达习惯块
|
||||||
@@ -330,7 +326,7 @@ class DefaultReplyer:
|
|||||||
style_habits = []
|
style_habits = []
|
||||||
# 使用从处理器传来的选中表达方式
|
# 使用从处理器传来的选中表达方式
|
||||||
# LLM模式:调用LLM选择5-10个,然后随机选5个
|
# LLM模式:调用LLM选择5-10个,然后随机选5个
|
||||||
reply_style_guide, selected_expressions = await expression_selector.select_suitable_expressions_llm(
|
selected_expressions = await expression_selector.select_suitable_expressions_llm(
|
||||||
self.chat_stream.stream_id, chat_history, max_num=8, target_message=target
|
self.chat_stream.stream_id, chat_history, max_num=8, target_message=target
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -354,7 +350,7 @@ class DefaultReplyer:
|
|||||||
)
|
)
|
||||||
expression_habits_block += f"{style_habits_str}\n"
|
expression_habits_block += f"{style_habits_str}\n"
|
||||||
|
|
||||||
return (f"{expression_habits_title}\n{expression_habits_block}", reply_style_guide)
|
return f"{expression_habits_title}\n{expression_habits_block}"
|
||||||
|
|
||||||
async def build_memory_block(self, chat_history: str, target: str) -> str:
|
async def build_memory_block(self, chat_history: str, target: str) -> str:
|
||||||
"""构建记忆块
|
"""构建记忆块
|
||||||
@@ -659,18 +655,16 @@ class DefaultReplyer:
|
|||||||
available_actions = {}
|
available_actions = {}
|
||||||
chat_stream = self.chat_stream
|
chat_stream = self.chat_stream
|
||||||
chat_id = chat_stream.stream_id
|
chat_id = chat_stream.stream_id
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
is_group_chat = bool(chat_stream.group_info)
|
is_group_chat = bool(chat_stream.group_info)
|
||||||
platform = chat_stream.platform
|
platform = chat_stream.platform
|
||||||
user_id = reply_message.get("user_id","")
|
user_id = reply_message.get("user_id","")
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
person_id = person_info_manager.get_person_id(platform,user_id)
|
person = Person(platform=platform, user_id=user_id)
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
person_name = person.person_name or user_id
|
||||||
sender = person_name
|
sender = person_name
|
||||||
target = reply_message.get('processed_plain_text')
|
target = reply_message.get('processed_plain_text')
|
||||||
else:
|
else:
|
||||||
person_id = ""
|
|
||||||
person_name = "用户"
|
person_name = "用户"
|
||||||
sender = "用户"
|
sender = "用户"
|
||||||
target = "消息"
|
target = "消息"
|
||||||
@@ -746,7 +740,7 @@ class DefaultReplyer:
|
|||||||
logger.warning(f"回复生成前信息获取耗时过长: {chinese_name} 耗时: {duration:.1f}s,请使用更快的模型")
|
logger.warning(f"回复生成前信息获取耗时过长: {chinese_name} 耗时: {duration:.1f}s,请使用更快的模型")
|
||||||
logger.info(f"在回复前的步骤耗时: {'; '.join(timing_logs)}")
|
logger.info(f"在回复前的步骤耗时: {'; '.join(timing_logs)}")
|
||||||
|
|
||||||
(expression_habits_block, reply_style_guide) = results_dict["expression_habits"]
|
expression_habits_block = results_dict["expression_habits"]
|
||||||
relation_info = results_dict["relation_info"]
|
relation_info = results_dict["relation_info"]
|
||||||
memory_block = results_dict["memory_block"]
|
memory_block = results_dict["memory_block"]
|
||||||
tool_info = results_dict["tool_info"]
|
tool_info = results_dict["tool_info"]
|
||||||
@@ -802,7 +796,7 @@ class DefaultReplyer:
|
|||||||
if global_config.bot.qq_account == user_id and platform == global_config.bot.platform:
|
if global_config.bot.qq_account == user_id and platform == global_config.bot.platform:
|
||||||
return await global_prompt_manager.format_prompt(
|
return await global_prompt_manager.format_prompt(
|
||||||
"replyer_self_prompt",
|
"replyer_self_prompt",
|
||||||
expression_habits_block=reply_style_guide,
|
expression_habits_block=expression_habits_block,
|
||||||
tool_info_block=tool_info,
|
tool_info_block=tool_info,
|
||||||
knowledge_prompt=prompt_info,
|
knowledge_prompt=prompt_info,
|
||||||
memory_block=memory_block,
|
memory_block=memory_block,
|
||||||
@@ -822,7 +816,7 @@ class DefaultReplyer:
|
|||||||
else:
|
else:
|
||||||
return await global_prompt_manager.format_prompt(
|
return await global_prompt_manager.format_prompt(
|
||||||
"replyer_prompt",
|
"replyer_prompt",
|
||||||
expression_habits_block=reply_style_guide,
|
expression_habits_block=expression_habits_block,
|
||||||
tool_info_block=tool_info,
|
tool_info_block=tool_info,
|
||||||
knowledge_prompt=prompt_info,
|
knowledge_prompt=prompt_info,
|
||||||
memory_block=memory_block,
|
memory_block=memory_block,
|
||||||
@@ -885,7 +879,6 @@ class DefaultReplyer:
|
|||||||
self.build_relation_info(sender, target),
|
self.build_relation_info(sender, target),
|
||||||
)
|
)
|
||||||
|
|
||||||
expression_habits_block, reply_style_guide = expression_habits_block
|
|
||||||
|
|
||||||
keywords_reaction_prompt = await self.build_keywords_reaction_prompt(target)
|
keywords_reaction_prompt = await self.build_keywords_reaction_prompt(target)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from typing import Dict, Optional, List, Tuple
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.config.api_ada_configs import TaskConfig
|
|
||||||
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
||||||
from src.chat.replyer.default_generator import DefaultReplyer
|
from src.chat.replyer.default_generator import DefaultReplyer
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from src.config.config import global_config
|
|||||||
from src.common.message_repository import find_messages, count_messages
|
from src.common.message_repository import find_messages, count_messages
|
||||||
from src.common.database.database_model import ActionRecords
|
from src.common.database.database_model import ActionRecords
|
||||||
from src.common.database.database_model import Images
|
from src.common.database.database_model import Images
|
||||||
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
|
from src.person_info.person_info import Person,get_person_id
|
||||||
from src.chat.utils.utils import translate_timestamp_to_human_readable, assign_message_ids
|
from src.chat.utils.utils import translate_timestamp_to_human_readable, assign_message_ids
|
||||||
|
|
||||||
install(extra_lines=3)
|
install(extra_lines=3)
|
||||||
@@ -35,14 +35,12 @@ def replace_user_references_sync(
|
|||||||
str: 处理后的内容字符串
|
str: 处理后的内容字符串
|
||||||
"""
|
"""
|
||||||
if name_resolver is None:
|
if name_resolver is None:
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
|
|
||||||
def default_resolver(platform: str, user_id: str) -> str:
|
def default_resolver(platform: str, user_id: str) -> str:
|
||||||
# 检查是否是机器人自己
|
# 检查是否是机器人自己
|
||||||
if replace_bot_name and user_id == global_config.bot.qq_account:
|
if replace_bot_name and user_id == global_config.bot.qq_account:
|
||||||
return f"{global_config.bot.nickname}(你)"
|
return f"{global_config.bot.nickname}(你)"
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person = Person(platform=platform, user_id=user_id)
|
||||||
return person_info_manager.get_value_sync(person_id, "person_name") or user_id # type: ignore
|
return person.person_name or user_id # type: ignore
|
||||||
|
|
||||||
name_resolver = default_resolver
|
name_resolver = default_resolver
|
||||||
|
|
||||||
@@ -110,14 +108,12 @@ async def replace_user_references_async(
|
|||||||
str: 处理后的内容字符串
|
str: 处理后的内容字符串
|
||||||
"""
|
"""
|
||||||
if name_resolver is None:
|
if name_resolver is None:
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
|
|
||||||
async def default_resolver(platform: str, user_id: str) -> str:
|
async def default_resolver(platform: str, user_id: str) -> str:
|
||||||
# 检查是否是机器人自己
|
# 检查是否是机器人自己
|
||||||
if replace_bot_name and user_id == global_config.bot.qq_account:
|
if replace_bot_name and user_id == global_config.bot.qq_account:
|
||||||
return f"{global_config.bot.nickname}(你)"
|
return f"{global_config.bot.nickname}(你)"
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person = Person(platform=platform, user_id=user_id)
|
||||||
return await person_info_manager.get_value(person_id, "person_name") or user_id # type: ignore
|
return person.person_name or user_id # type: ignore
|
||||||
|
|
||||||
name_resolver = default_resolver
|
name_resolver = default_resolver
|
||||||
|
|
||||||
@@ -506,14 +502,13 @@ def _build_readable_messages_internal(
|
|||||||
if not all([platform, user_id, timestamp is not None]):
|
if not all([platform, user_id, timestamp is not None]):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person = Person(platform=platform, user_id=user_id)
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
# 根据 replace_bot_name 参数决定是否替换机器人名称
|
# 根据 replace_bot_name 参数决定是否替换机器人名称
|
||||||
person_name: str
|
person_name: str
|
||||||
if replace_bot_name and user_id == global_config.bot.qq_account:
|
if replace_bot_name and user_id == global_config.bot.qq_account:
|
||||||
person_name = f"{global_config.bot.nickname}(你)"
|
person_name = f"{global_config.bot.nickname}(你)"
|
||||||
else:
|
else:
|
||||||
person_name = person_info_manager.get_value_sync(person_id, "person_name") # type: ignore
|
person_name = person.person_name or user_id # type: ignore
|
||||||
|
|
||||||
# 如果 person_name 未设置,则使用消息中的 nickname 或默认名称
|
# 如果 person_name 未设置,则使用消息中的 nickname 或默认名称
|
||||||
if not person_name:
|
if not person_name:
|
||||||
@@ -1009,7 +1004,7 @@ async def build_anonymous_messages(messages: List[Dict[str, Any]]) -> str:
|
|||||||
# print("SELF11111111111111")
|
# print("SELF11111111111111")
|
||||||
return "SELF"
|
return "SELF"
|
||||||
try:
|
try:
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person_id = get_person_id(platform, user_id)
|
||||||
except Exception as _e:
|
except Exception as _e:
|
||||||
person_id = None
|
person_id = None
|
||||||
if not person_id:
|
if not person_id:
|
||||||
@@ -1102,7 +1097,7 @@ async def get_person_id_list(messages: List[Dict[str, Any]]) -> List[str]:
|
|||||||
if platform is None:
|
if platform is None:
|
||||||
platform = "unknown"
|
platform = "unknown"
|
||||||
|
|
||||||
if person_id := PersonInfoManager.get_person_id(platform, user_id):
|
if person_id := get_person_id(platform, user_id):
|
||||||
person_ids_set.add(person_id)
|
person_ids_set.add(person_id)
|
||||||
|
|
||||||
return list(person_ids_set) # 将集合转换为列表返回
|
return list(person_ids_set) # 将集合转换为列表返回
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from src.config.config import global_config, model_config
|
|||||||
from src.chat.message_receive.message import MessageRecv
|
from src.chat.message_receive.message import MessageRecv
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
|
from src.person_info.person_info import Person
|
||||||
from .typo_generator import ChineseTypoGenerator
|
from .typo_generator import ChineseTypoGenerator
|
||||||
|
|
||||||
logger = get_logger("chat_utils")
|
logger = get_logger("chat_utils")
|
||||||
@@ -639,12 +639,12 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Dict]]:
|
|||||||
# Try to fetch person info
|
# Try to fetch person info
|
||||||
try:
|
try:
|
||||||
# Assume get_person_id is sync (as per original code), keep using to_thread
|
# Assume get_person_id is sync (as per original code), keep using to_thread
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person = Person(platform=platform, user_id=user_id)
|
||||||
|
person_id = person.person_id
|
||||||
person_name = None
|
person_name = None
|
||||||
if person_id:
|
if person_id:
|
||||||
# get_value is async, so await it directly
|
# get_value is async, so await it directly
|
||||||
person_info_manager = get_person_info_manager()
|
person_name = person.person_name
|
||||||
person_name = person_info_manager.get_value_sync(person_id, "person_name")
|
|
||||||
|
|
||||||
target_info["person_id"] = person_id
|
target_info["person_id"] = person_id
|
||||||
target_info["person_name"] = person_name
|
target_info["person_name"] = person_name
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ class PersonInfo(BaseModel):
|
|||||||
用于存储个人信息数据的模型。
|
用于存储个人信息数据的模型。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
is_known = BooleanField(default=False) # 是否已认识
|
||||||
person_id = TextField(unique=True, index=True) # 个人唯一ID
|
person_id = TextField(unique=True, index=True) # 个人唯一ID
|
||||||
person_name = TextField(null=True) # 个人名称 (允许为空)
|
person_name = TextField(null=True) # 个人名称 (允许为空)
|
||||||
name_reason = TextField(null=True) # 名称设定的原因
|
name_reason = TextField(null=True) # 名称设定的原因
|
||||||
@@ -261,16 +262,26 @@ class PersonInfo(BaseModel):
|
|||||||
user_id = TextField(index=True) # 用户ID
|
user_id = TextField(index=True) # 用户ID
|
||||||
nickname = TextField(null=True) # 用户昵称
|
nickname = TextField(null=True) # 用户昵称
|
||||||
points = TextField(null=True) # 个人印象的点
|
points = TextField(null=True) # 个人印象的点
|
||||||
attitude_to_me = TextField(null=True) # 对bot的态度
|
|
||||||
rudeness = TextField(null=True) # 对bot的冒犯程度
|
|
||||||
neuroticism = TextField(null=True) # 对bot的神经质程度
|
|
||||||
conscientiousness = TextField(null=True) # 对bot的尽责程度
|
|
||||||
likeness = TextField(null=True) # 对bot的相似程度
|
|
||||||
|
|
||||||
know_times = FloatField(null=True) # 认识时间 (时间戳)
|
know_times = FloatField(null=True) # 认识时间 (时间戳)
|
||||||
know_since = FloatField(null=True) # 首次印象总结时间
|
know_since = FloatField(null=True) # 首次印象总结时间
|
||||||
last_know = FloatField(null=True) # 最后一次印象总结时间
|
last_know = FloatField(null=True) # 最后一次印象总结时间
|
||||||
|
|
||||||
|
|
||||||
|
attitude_to_me = TextField(null=True) # 对bot的态度
|
||||||
|
attitude_to_me_confidence = FloatField(null=True) # 对bot的态度置信度
|
||||||
|
friendly_value = FloatField(null=True) # 对bot的友好程度
|
||||||
|
friendly_value_confidence = FloatField(null=True) # 对bot的友好程度置信度
|
||||||
|
rudeness = TextField(null=True) # 对bot的冒犯程度
|
||||||
|
rudeness_confidence = FloatField(null=True) # 对bot的冒犯程度置信度
|
||||||
|
neuroticism = TextField(null=True) # 对bot的神经质程度
|
||||||
|
neuroticism_confidence = FloatField(null=True) # 对bot的神经质程度置信度
|
||||||
|
conscientiousness = TextField(null=True) # 对bot的尽责程度
|
||||||
|
conscientiousness_confidence = FloatField(null=True) # 对bot的尽责程度置信度
|
||||||
|
likeness = TextField(null=True) # 对bot的相似程度
|
||||||
|
likeness_confidence = FloatField(null=True) # 对bot的相似程度置信度
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# database = db # 继承自 BaseModel
|
# database = db # 继承自 BaseModel
|
||||||
table_name = "person_info"
|
table_name = "person_info"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import time
|
|||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.config.config import global_config, model_config
|
from src.config.config import global_config, model_config
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.person_info.person_info import get_person_info_manager
|
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
|
|
||||||
install(extra_lines=3)
|
install(extra_lines=3)
|
||||||
@@ -19,7 +18,6 @@ class Individuality:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.name = ""
|
self.name = ""
|
||||||
self.bot_person_id = ""
|
|
||||||
self.meta_info_file_path = "data/personality/meta.json"
|
self.meta_info_file_path = "data/personality/meta.json"
|
||||||
self.personality_data_file_path = "data/personality/personality_data.json"
|
self.personality_data_file_path = "data/personality/personality_data.json"
|
||||||
|
|
||||||
@@ -32,8 +30,6 @@ class Individuality:
|
|||||||
personality_side = global_config.personality.personality_side
|
personality_side = global_config.personality.personality_side
|
||||||
identity = global_config.personality.identity
|
identity = global_config.personality.identity
|
||||||
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
self.bot_person_id = person_info_manager.get_person_id("system", "bot_id")
|
|
||||||
self.name = bot_nickname
|
self.name = bot_nickname
|
||||||
|
|
||||||
# 检查配置变化,如果变化则清空
|
# 检查配置变化,如果变化则清空
|
||||||
@@ -64,16 +60,6 @@ class Individuality:
|
|||||||
else:
|
else:
|
||||||
logger.error("人设构建失败")
|
logger.error("人设构建失败")
|
||||||
|
|
||||||
# 如果任何一个发生变化,都需要清空数据库中的info_list(因为这影响整体人设)
|
|
||||||
if personality_changed or identity_changed:
|
|
||||||
logger.info("将清空数据库中原有的关键词缓存")
|
|
||||||
update_data = {
|
|
||||||
"platform": "system",
|
|
||||||
"user_id": "bot_id",
|
|
||||||
"person_name": self.name,
|
|
||||||
"nickname": self.name,
|
|
||||||
}
|
|
||||||
await person_info_manager.update_one_field(self.bot_person_id, "info_list", [], data=update_data)
|
|
||||||
|
|
||||||
async def get_personality_block(self) -> str:
|
async def get_personality_block(self) -> str:
|
||||||
bot_name = global_config.bot.nickname
|
bot_name = global_config.bot.nickname
|
||||||
@@ -130,7 +116,6 @@ class Individuality:
|
|||||||
Returns:
|
Returns:
|
||||||
tuple: (personality_changed, identity_changed)
|
tuple: (personality_changed, identity_changed)
|
||||||
"""
|
"""
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
current_personality_hash, current_identity_hash = self._get_config_hash(
|
current_personality_hash, current_identity_hash = self._get_config_hash(
|
||||||
bot_nickname, personality_core, personality_side, identity
|
bot_nickname, personality_core, personality_side, identity
|
||||||
)
|
)
|
||||||
@@ -148,17 +133,6 @@ class Individuality:
|
|||||||
if identity_changed:
|
if identity_changed:
|
||||||
logger.info("检测到身份配置发生变化")
|
logger.info("检测到身份配置发生变化")
|
||||||
|
|
||||||
# 如果任何一个发生变化,都需要清空info_list(因为这影响整体人设)
|
|
||||||
if personality_changed or identity_changed:
|
|
||||||
logger.info("将清空原有的关键词缓存")
|
|
||||||
update_data = {
|
|
||||||
"platform": "system",
|
|
||||||
"user_id": "bot_id",
|
|
||||||
"person_name": self.name,
|
|
||||||
"nickname": self.name,
|
|
||||||
}
|
|
||||||
await person_info_manager.update_one_field(self.bot_person_id, "info_list", [], data=update_data)
|
|
||||||
|
|
||||||
# 更新元信息文件
|
# 更新元信息文件
|
||||||
new_meta_info = {
|
new_meta_info = {
|
||||||
"personality_hash": current_personality_hash,
|
"personality_hash": current_personality_hash,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import json
|
|||||||
from .s4u_mood_manager import mood_manager
|
from .s4u_mood_manager import mood_manager
|
||||||
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
from src.person_info.relationship_builder_manager import relationship_builder_manager
|
||||||
from src.mais4u.s4u_config import s4u_config
|
from src.mais4u.s4u_config import s4u_config
|
||||||
from src.person_info.person_info import PersonInfoManager
|
from src.person_info.person_info import get_person_id
|
||||||
from .super_chat_manager import get_super_chat_manager
|
from .super_chat_manager import get_super_chat_manager
|
||||||
from .yes_or_no import yes_or_no_head
|
from .yes_or_no import yes_or_no_head
|
||||||
from src.mais4u.constant_s4u import ENABLE_S4U
|
from src.mais4u.constant_s4u import ENABLE_S4U
|
||||||
@@ -262,7 +262,7 @@ class S4UChat:
|
|||||||
"""根据VIP状态和中断逻辑将消息放入相应队列。"""
|
"""根据VIP状态和中断逻辑将消息放入相应队列。"""
|
||||||
user_id = message.message_info.user_info.user_id
|
user_id = message.message_info.user_info.user_id
|
||||||
platform = message.message_info.platform
|
platform = message.message_info.platform
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person_id = get_person_id(platform, user_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
is_gift = message.is_gift
|
is_gift = message.is_gift
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ from datetime import datetime
|
|||||||
import asyncio
|
import asyncio
|
||||||
from src.mais4u.s4u_config import s4u_config
|
from src.mais4u.s4u_config import s4u_config
|
||||||
from src.chat.message_receive.message import MessageRecvS4U
|
from src.chat.message_receive.message import MessageRecvS4U
|
||||||
from src.person_info.relationship_fetcher import relationship_fetcher_manager
|
from src.person_info.person_info import Person, get_person_id
|
||||||
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
|
|
||||||
from src.chat.message_receive.chat_stream import ChatStream
|
from src.chat.message_receive.chat_stream import ChatStream
|
||||||
from src.mais4u.mais4u_chat.super_chat_manager import get_super_chat_manager
|
from src.mais4u.mais4u_chat.super_chat_manager import get_super_chat_manager
|
||||||
from src.mais4u.mais4u_chat.screen_manager import screen_manager
|
from src.mais4u.mais4u_chat.screen_manager import screen_manager
|
||||||
@@ -103,7 +102,7 @@ class PromptBuilder:
|
|||||||
|
|
||||||
# 使用从处理器传来的选中表达方式
|
# 使用从处理器传来的选中表达方式
|
||||||
# LLM模式:调用LLM选择5-10个,然后随机选5个
|
# LLM模式:调用LLM选择5-10个,然后随机选5个
|
||||||
_,selected_expressions = await expression_selector.select_suitable_expressions_llm(
|
selected_expressions = await expression_selector.select_suitable_expressions_llm(
|
||||||
chat_stream.stream_id, chat_history, max_num=12, target_message=target
|
chat_stream.stream_id, chat_history, max_num=12, target_message=target
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -142,18 +141,16 @@ class PromptBuilder:
|
|||||||
|
|
||||||
relation_prompt = ""
|
relation_prompt = ""
|
||||||
if global_config.relationship.enable_relationship and who_chat_in_group:
|
if global_config.relationship.enable_relationship and who_chat_in_group:
|
||||||
relationship_fetcher = relationship_fetcher_manager.get_fetcher(chat_stream.stream_id)
|
|
||||||
|
|
||||||
# 将 (platform, user_id, nickname) 转换为 person_id
|
# 将 (platform, user_id, nickname) 转换为 person_id
|
||||||
person_ids = []
|
person_ids = []
|
||||||
for person in who_chat_in_group:
|
for person in who_chat_in_group:
|
||||||
person_id = PersonInfoManager.get_person_id(person[0], person[1])
|
person_id = get_person_id(person[0], person[1])
|
||||||
person_ids.append(person_id)
|
person_ids.append(person_id)
|
||||||
|
|
||||||
# 使用 RelationshipFetcher 的 build_relation_info 方法,设置 points_num=3 保持与原来相同的行为
|
# 使用 Person 的 build_relationship 方法,设置 points_num=3 保持与原来相同的行为
|
||||||
relation_info_list = await asyncio.gather(
|
relation_info_list = [
|
||||||
*[relationship_fetcher.build_relation_info(person_id, points_num=3) for person_id in person_ids]
|
Person(person_id=person_id).build_relationship(points_num=3) for person_id in person_ids
|
||||||
)
|
]
|
||||||
if relation_info := "".join(relation_info_list):
|
if relation_info := "".join(relation_info_list):
|
||||||
relation_prompt = await global_prompt_manager.format_prompt(
|
relation_prompt = await global_prompt_manager.format_prompt(
|
||||||
"relation_prompt", relation_info=relation_info
|
"relation_prompt", relation_info=relation_info
|
||||||
@@ -288,11 +285,8 @@ class PromptBuilder:
|
|||||||
|
|
||||||
chat_stream = message.chat_stream
|
chat_stream = message.chat_stream
|
||||||
|
|
||||||
person_id = PersonInfoManager.get_person_id(
|
person = Person(platform=message.chat_stream.user_info.platform, user_id=message.chat_stream.user_info.user_id)
|
||||||
message.chat_stream.user_info.platform, message.chat_stream.user_info.user_id
|
person_name = person.person_name
|
||||||
)
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
|
||||||
|
|
||||||
if message.chat_stream.user_info.user_nickname:
|
if message.chat_stream.user_info.user_nickname:
|
||||||
if person_name:
|
if person_name:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from src.config.config import model_config
|
|||||||
from src.chat.message_receive.message import MessageRecvS4U
|
from src.chat.message_receive.message import MessageRecvS4U
|
||||||
from src.mais4u.mais4u_chat.s4u_prompt import prompt_builder
|
from src.mais4u.mais4u_chat.s4u_prompt import prompt_builder
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
import asyncio
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
from .person_info import get_person_info_manager
|
|
||||||
from .group_info import get_group_info_manager
|
|
||||||
|
|
||||||
__all__ = ["get_person_info_manager", "get_group_info_manager"]
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import copy
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import datetime
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
from json_repair import repair_json
|
from json_repair import repair_json
|
||||||
from typing import Any, Callable, Dict, Union, Optional
|
from typing import Union
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.common.database.database import db
|
from src.common.database.database import db
|
||||||
@@ -14,45 +14,276 @@ from src.llm_models.utils_model import LLMRequest
|
|||||||
from src.config.config import global_config, model_config
|
from src.config.config import global_config, model_config
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
PersonInfoManager 类方法功能摘要:
|
|
||||||
1. get_person_id - 根据平台和用户ID生成MD5哈希的唯一person_id
|
|
||||||
2. create_person_info - 创建新个人信息文档(自动合并默认值)
|
|
||||||
3. update_one_field - 更新单个字段值(若文档不存在则创建)
|
|
||||||
4. del_one_document - 删除指定person_id的文档
|
|
||||||
5. get_value - 获取单个字段值(返回实际值或默认值)
|
|
||||||
6. get_values - 批量获取字段值(任一字段无效则返回空字典)
|
|
||||||
7. del_all_undefined_field - 清理全集合中未定义的字段
|
|
||||||
8. get_specific_value_list - 根据指定条件,返回person_id,value字典
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("person_info")
|
logger = get_logger("person_info")
|
||||||
|
|
||||||
JSON_SERIALIZED_FIELDS = ["points"]
|
def get_person_id(platform: str, user_id: Union[int, str]) -> str:
|
||||||
|
"""获取唯一id"""
|
||||||
|
if "-" in platform:
|
||||||
|
platform = platform.split("-")[1]
|
||||||
|
components = [platform, str(user_id)]
|
||||||
|
key = "_".join(components)
|
||||||
|
return hashlib.md5(key.encode()).hexdigest()
|
||||||
|
|
||||||
person_info_default = {
|
def get_person_id_by_person_name(person_name: str) -> str:
|
||||||
"person_id": None,
|
"""根据用户名获取用户ID"""
|
||||||
"person_name": None,
|
try:
|
||||||
"name_reason": None, # Corrected from person_name_reason to match common usage if intended
|
record = PersonInfo.get_or_none(PersonInfo.person_name == person_name)
|
||||||
"platform": "unknown",
|
return record.person_id if record else ""
|
||||||
"user_id": "unknown",
|
except Exception as e:
|
||||||
"nickname": "Unknown",
|
logger.error(f"根据用户名 {person_name} 获取用户ID时出错 (Peewee): {e}")
|
||||||
"know_times": 0,
|
return ""
|
||||||
"know_since": None,
|
|
||||||
"last_know": None,
|
class Person:
|
||||||
"attitude_to_me": "0,1",
|
def __init__(self, platform: str = "", user_id: str = "",person_id: str = "",person_name: str = "",nickname: str = ""):
|
||||||
"friendly_value": 50,
|
if person_id:
|
||||||
"rudeness":50,
|
self.person_id = person_id
|
||||||
"neuroticism":"5,1",
|
elif person_name:
|
||||||
"conscientiousness": 50,
|
self.person_id = get_person_id_by_person_name(person_name)
|
||||||
"likeness": 50,
|
if not self.person_id:
|
||||||
"points": None,
|
logger.error(f"根据用户名 {person_name} 获取用户ID时出错,不存在用户{person_name}")
|
||||||
|
return ""
|
||||||
|
elif platform and user_id:
|
||||||
|
self.person_id = get_person_id(platform, user_id)
|
||||||
|
else:
|
||||||
|
logger.error("Person 初始化失败,缺少必要参数")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
self.is_known = False
|
||||||
|
self.platform = platform
|
||||||
|
self.user_id = user_id
|
||||||
|
|
||||||
|
# 初始化默认值
|
||||||
|
self.nickname = nickname
|
||||||
|
self.person_name = None
|
||||||
|
self.name_reason = None
|
||||||
|
self.know_times = 0
|
||||||
|
self.know_since = None
|
||||||
|
self.last_know = None
|
||||||
|
self.points = []
|
||||||
|
|
||||||
|
# 初始化性格特征相关字段
|
||||||
|
self.attitude_to_me:float = 0
|
||||||
|
self.attitude_to_me_confidence:float = 1
|
||||||
|
|
||||||
|
self.neuroticism:float = 5
|
||||||
|
self.neuroticism_confidence:float = 1
|
||||||
|
|
||||||
|
self.friendly_value:float = 50
|
||||||
|
self.friendly_value_confidence:float = 1
|
||||||
|
|
||||||
|
self.rudeness:float = 50
|
||||||
|
self.rudeness_confidence:float = 1
|
||||||
|
|
||||||
|
self.conscientiousness:float = 50
|
||||||
|
self.conscientiousness_confidence:float = 1
|
||||||
|
|
||||||
|
self.likeness:float = 50
|
||||||
|
self.likeness_confidence:float = 1
|
||||||
|
|
||||||
|
# 从数据库加载数据
|
||||||
|
self.load_from_database()
|
||||||
|
|
||||||
|
def load_from_database(self):
|
||||||
|
"""从数据库加载个人信息数据"""
|
||||||
|
try:
|
||||||
|
# 查询数据库中的记录
|
||||||
|
record = PersonInfo.get_or_none(PersonInfo.person_id == self.person_id)
|
||||||
|
|
||||||
|
if record:
|
||||||
|
self.is_known = record.is_known if record.is_known else False
|
||||||
|
self.nickname = record.nickname if record.nickname else self.nickname
|
||||||
|
|
||||||
|
if not self.is_known:
|
||||||
|
if self.nickname:
|
||||||
|
self.is_known = True
|
||||||
|
self.person_name = self.nickname
|
||||||
|
logger.info(f"用户 {self.person_id} 已认识,昵称:{self.nickname}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"用户 {self.person_id} 尚未认识,昵称为空")
|
||||||
|
else:
|
||||||
|
self.person_name = record.person_name if record.person_name else self.nickname
|
||||||
|
self.name_reason = record.name_reason if record.name_reason else None
|
||||||
|
self.know_times = record.know_times if record.know_times else 0
|
||||||
|
self.know_since = record.know_since if record.know_since else time.time()
|
||||||
|
self.last_know = record.last_know if record.last_know else time.time()
|
||||||
|
|
||||||
|
# 处理points字段(JSON格式的列表)
|
||||||
|
if record.points:
|
||||||
|
try:
|
||||||
|
self.points = json.loads(record.points)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
logger.warning(f"解析用户 {self.person_id} 的points字段失败,使用默认值")
|
||||||
|
self.points = []
|
||||||
|
else:
|
||||||
|
self.points = []
|
||||||
|
|
||||||
|
# 加载性格特征相关字段
|
||||||
|
if record.attitude_to_me and not isinstance(record.attitude_to_me, str):
|
||||||
|
self.attitude_to_me = record.attitude_to_me
|
||||||
|
|
||||||
|
if record.attitude_to_me_confidence is not None:
|
||||||
|
self.attitude_to_me_confidence = float(record.attitude_to_me_confidence)
|
||||||
|
|
||||||
|
if record.friendly_value is not None:
|
||||||
|
self.friendly_value = float(record.friendly_value)
|
||||||
|
|
||||||
|
if record.friendly_value_confidence is not None:
|
||||||
|
self.friendly_value_confidence = float(record.friendly_value_confidence)
|
||||||
|
|
||||||
|
if record.rudeness is not None:
|
||||||
|
self.rudeness = float(record.rudeness)
|
||||||
|
|
||||||
|
if record.rudeness_confidence is not None:
|
||||||
|
self.rudeness_confidence = float(record.rudeness_confidence)
|
||||||
|
|
||||||
|
if record.neuroticism and not isinstance(record.neuroticism, str):
|
||||||
|
self.neuroticism = float(record.neuroticism)
|
||||||
|
|
||||||
|
if record.neuroticism_confidence is not None:
|
||||||
|
self.neuroticism_confidence = float(record.neuroticism_confidence)
|
||||||
|
|
||||||
|
if record.conscientiousness is not None:
|
||||||
|
self.conscientiousness = float(record.conscientiousness)
|
||||||
|
|
||||||
|
if record.conscientiousness_confidence is not None:
|
||||||
|
self.conscientiousness_confidence = float(record.conscientiousness_confidence)
|
||||||
|
|
||||||
|
if record.likeness is not None:
|
||||||
|
self.likeness = float(record.likeness)
|
||||||
|
|
||||||
|
if record.likeness_confidence is not None:
|
||||||
|
self.likeness_confidence = float(record.likeness_confidence)
|
||||||
|
|
||||||
|
logger.info(f"已从数据库加载用户 {self.person_id} 的信息")
|
||||||
|
else:
|
||||||
|
self.sync_to_database()
|
||||||
|
logger.info(f"用户 {self.person_id} 在数据库中不存在,使用默认值并创建")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"从数据库加载用户 {self.person_id} 信息时出错: {e}")
|
||||||
|
# 出错时保持默认值
|
||||||
|
|
||||||
|
def sync_to_database(self):
|
||||||
|
"""将所有属性同步回数据库"""
|
||||||
|
try:
|
||||||
|
# 准备数据
|
||||||
|
data = {
|
||||||
|
'person_id': self.person_id,
|
||||||
|
'is_known': self.is_known,
|
||||||
|
'platform': self.platform,
|
||||||
|
'user_id': self.user_id,
|
||||||
|
'nickname': self.nickname,
|
||||||
|
'person_name': self.person_name,
|
||||||
|
'name_reason': self.name_reason,
|
||||||
|
'know_times': self.know_times,
|
||||||
|
'know_since': self.know_since,
|
||||||
|
'last_know': self.last_know,
|
||||||
|
'points': json.dumps(self.points, ensure_ascii=False) if self.points else json.dumps([], ensure_ascii=False),
|
||||||
|
'attitude_to_me': self.attitude_to_me,
|
||||||
|
'attitude_to_me_confidence': self.attitude_to_me_confidence,
|
||||||
|
'friendly_value': self.friendly_value,
|
||||||
|
'friendly_value_confidence': self.friendly_value_confidence,
|
||||||
|
'rudeness': self.rudeness,
|
||||||
|
'rudeness_confidence': self.rudeness_confidence,
|
||||||
|
'neuroticism': self.neuroticism,
|
||||||
|
'neuroticism_confidence': self.neuroticism_confidence,
|
||||||
|
'conscientiousness': self.conscientiousness,
|
||||||
|
'conscientiousness_confidence': self.conscientiousness_confidence,
|
||||||
|
'likeness': self.likeness,
|
||||||
|
'likeness_confidence': self.likeness_confidence,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 检查记录是否存在
|
||||||
|
record = PersonInfo.get_or_none(PersonInfo.person_id == self.person_id)
|
||||||
|
|
||||||
|
if record:
|
||||||
|
# 更新现有记录
|
||||||
|
for field, value in data.items():
|
||||||
|
if hasattr(record, field):
|
||||||
|
setattr(record, field, value)
|
||||||
|
record.save()
|
||||||
|
logger.debug(f"已同步用户 {self.person_id} 的信息到数据库")
|
||||||
|
else:
|
||||||
|
# 创建新记录
|
||||||
|
PersonInfo.create(**data)
|
||||||
|
logger.debug(f"已创建用户 {self.person_id} 的信息到数据库")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"同步用户 {self.person_id} 信息到数据库时出错: {e}")
|
||||||
|
|
||||||
|
def build_relationship(self,points_num=3):
|
||||||
|
if not self.is_known:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# 按时间排序forgotten_points
|
||||||
|
current_points = self.points
|
||||||
|
current_points.sort(key=lambda x: x[2])
|
||||||
|
# 按权重加权随机抽取最多3个不重复的points,point[1]的值在1-10之间,权重越高被抽到概率越大
|
||||||
|
if len(current_points) > points_num:
|
||||||
|
# point[1] 取值范围1-10,直接作为权重
|
||||||
|
weights = [max(1, min(10, int(point[1]))) for point in current_points]
|
||||||
|
# 使用加权采样不放回,保证不重复
|
||||||
|
indices = list(range(len(current_points)))
|
||||||
|
points = []
|
||||||
|
for _ in range(points_num):
|
||||||
|
if not indices:
|
||||||
|
break
|
||||||
|
sub_weights = [weights[i] for i in indices]
|
||||||
|
chosen_idx = random.choices(indices, weights=sub_weights, k=1)[0]
|
||||||
|
points.append(current_points[chosen_idx])
|
||||||
|
indices.remove(chosen_idx)
|
||||||
|
else:
|
||||||
|
points = current_points
|
||||||
|
|
||||||
|
# 构建points文本
|
||||||
|
points_text = "\n".join([f"{point[2]}:{point[0]}" for point in points])
|
||||||
|
|
||||||
|
nickname_str = ""
|
||||||
|
if self.person_name != nickname_str:
|
||||||
|
nickname_str = f"(ta在{self.platform}上的昵称是{nickname_str})"
|
||||||
|
|
||||||
|
relation_info = ""
|
||||||
|
|
||||||
|
attitude_info = ""
|
||||||
|
if self.attitude_to_me:
|
||||||
|
if self.attitude_to_me > 8:
|
||||||
|
attitude_info = f"{self.person_name}对你的态度十分好,"
|
||||||
|
elif self.attitude_to_me > 5:
|
||||||
|
attitude_info = f"{self.person_name}对你的态度较好,"
|
||||||
|
|
||||||
|
|
||||||
|
if self.attitude_to_me < -8:
|
||||||
|
attitude_info = f"{self.person_name}对你的态度十分恶劣,"
|
||||||
|
elif self.attitude_to_me < -4:
|
||||||
|
attitude_info = f"{self.person_name}对你的态度不好,"
|
||||||
|
elif self.attitude_to_me < 0:
|
||||||
|
attitude_info = f"{self.person_name}对你的态度一般,"
|
||||||
|
|
||||||
|
neuroticism_info = ""
|
||||||
|
if self.neuroticism:
|
||||||
|
if self.neuroticism > 8:
|
||||||
|
neuroticism_info = f"{self.person_name}的情绪十分活跃,容易情绪化,"
|
||||||
|
elif self.neuroticism > 6:
|
||||||
|
neuroticism_info = f"{self.person_name}的情绪比较活跃,"
|
||||||
|
elif self.neuroticism > 4:
|
||||||
|
neuroticism_info = ""
|
||||||
|
elif self.neuroticism > 2:
|
||||||
|
neuroticism_info = f"{self.person_name}的情绪比较稳定,"
|
||||||
|
else:
|
||||||
|
neuroticism_info = f"{self.person_name}的情绪非常稳定,毫无波动"
|
||||||
|
|
||||||
|
points_info = ""
|
||||||
|
if points_text:
|
||||||
|
points_info = f"你还记得ta最近做的事:{points_text}"
|
||||||
|
|
||||||
|
relation_info = f"{self.person_name}:{nickname_str}{attitude_info}{neuroticism_info}{points_info}"
|
||||||
|
|
||||||
|
return relation_info
|
||||||
|
|
||||||
|
|
||||||
class PersonInfoManager:
|
class PersonInfoManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.person_name_list = {}
|
self.person_name_list = {}
|
||||||
self.qv_name_llm = LLMRequest(model_set=model_config.model_task_config.utils, request_type="relation.qv_name")
|
self.qv_name_llm = LLMRequest(model_set=model_config.model_task_config.utils, request_type="relation.qv_name")
|
||||||
try:
|
try:
|
||||||
@@ -78,157 +309,10 @@ class PersonInfoManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"从 Peewee 加载 person_name_list 失败: {e}")
|
logger.error(f"从 Peewee 加载 person_name_list 失败: {e}")
|
||||||
|
|
||||||
@staticmethod
|
def get_person(self, platform: str, user_id: Union[int, str]) -> Person:
|
||||||
def get_person_id(platform: str, user_id: Union[int, str]) -> str:
|
person = Person(platform, user_id)
|
||||||
"""获取唯一id"""
|
return person
|
||||||
# 添加空值检查,防止 platform 为 None 时出错
|
|
||||||
if platform is None:
|
|
||||||
platform = "unknown"
|
|
||||||
elif "-" in platform:
|
|
||||||
platform = platform.split("-")[1]
|
|
||||||
|
|
||||||
components = [platform, str(user_id)]
|
|
||||||
key = "_".join(components)
|
|
||||||
return hashlib.md5(key.encode()).hexdigest()
|
|
||||||
|
|
||||||
async def is_person_known(self, platform: str, user_id: int):
|
|
||||||
"""判断是否认识某人"""
|
|
||||||
person_id = self.get_person_id(platform, user_id)
|
|
||||||
|
|
||||||
def _db_check_known_sync(p_id: str):
|
|
||||||
return PersonInfo.get_or_none(PersonInfo.person_id == p_id) is not None
|
|
||||||
|
|
||||||
try:
|
|
||||||
return await asyncio.to_thread(_db_check_known_sync, person_id)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"检查用户 {person_id} 是否已知时出错 (Peewee): {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_person_id_by_person_name(self, person_name: str) -> str:
|
|
||||||
"""根据用户名获取用户ID"""
|
|
||||||
try:
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_name == person_name)
|
|
||||||
return record.person_id if record else ""
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"根据用户名 {person_name} 获取用户ID时出错 (Peewee): {e}")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
async def _safe_create_person_info(self, person_id: str, data: Optional[dict] = None):
|
|
||||||
"""安全地创建用户信息,处理竞态条件"""
|
|
||||||
if not person_id:
|
|
||||||
logger.debug("创建失败,person_id不存在")
|
|
||||||
return
|
|
||||||
|
|
||||||
_person_info_default = copy.deepcopy(person_info_default)
|
|
||||||
model_fields = PersonInfo._meta.fields.keys() # type: ignore
|
|
||||||
|
|
||||||
final_data = {"person_id": person_id}
|
|
||||||
|
|
||||||
# Start with defaults for all model fields
|
|
||||||
for key, default_value in _person_info_default.items():
|
|
||||||
if key in model_fields:
|
|
||||||
final_data[key] = default_value
|
|
||||||
|
|
||||||
# Override with provided data
|
|
||||||
if data:
|
|
||||||
for key, value in data.items():
|
|
||||||
if key in model_fields:
|
|
||||||
final_data[key] = value
|
|
||||||
|
|
||||||
# Ensure person_id is correctly set from the argument
|
|
||||||
final_data["person_id"] = person_id
|
|
||||||
|
|
||||||
# Serialize JSON fields
|
|
||||||
for key in JSON_SERIALIZED_FIELDS:
|
|
||||||
if key in final_data:
|
|
||||||
if isinstance(final_data[key], (list, dict)):
|
|
||||||
final_data[key] = json.dumps(final_data[key], ensure_ascii=False)
|
|
||||||
elif final_data[key] is None: # Default for lists is [], store as "[]"
|
|
||||||
final_data[key] = json.dumps([], ensure_ascii=False)
|
|
||||||
|
|
||||||
def _db_safe_create_sync(p_data: dict):
|
|
||||||
try:
|
|
||||||
# 首先检查是否已存在
|
|
||||||
existing = PersonInfo.get_or_none(PersonInfo.person_id == p_data["person_id"])
|
|
||||||
if existing:
|
|
||||||
logger.debug(f"用户 {p_data['person_id']} 已存在,跳过创建")
|
|
||||||
return True
|
|
||||||
|
|
||||||
# 尝试创建
|
|
||||||
PersonInfo.create(**p_data)
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
if "UNIQUE constraint failed" in str(e):
|
|
||||||
logger.debug(f"检测到并发创建用户 {p_data.get('person_id')},跳过错误")
|
|
||||||
return True # 其他协程已创建,视为成功
|
|
||||||
else:
|
|
||||||
logger.error(f"创建 PersonInfo 记录 {p_data.get('person_id')} 失败 (Peewee): {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
await asyncio.to_thread(_db_safe_create_sync, final_data)
|
|
||||||
|
|
||||||
async def update_one_field(self, person_id: str, field_name: str, value, data: Optional[Dict] = None):
|
|
||||||
"""更新某一个字段,会补全"""
|
|
||||||
if field_name not in PersonInfo._meta.fields: # type: ignore
|
|
||||||
logger.debug(f"更新'{field_name}'失败,未在 PersonInfo Peewee 模型中定义的字段。")
|
|
||||||
return
|
|
||||||
|
|
||||||
processed_value = value
|
|
||||||
if field_name in JSON_SERIALIZED_FIELDS:
|
|
||||||
if isinstance(value, (list, dict)):
|
|
||||||
processed_value = json.dumps(value, ensure_ascii=False, indent=None)
|
|
||||||
elif value is None: # Store None as "[]" for JSON list fields
|
|
||||||
processed_value = json.dumps([], ensure_ascii=False, indent=None)
|
|
||||||
|
|
||||||
def _db_update_sync(p_id: str, f_name: str, val_to_set):
|
|
||||||
import time
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
try:
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_id == p_id)
|
|
||||||
query_time = time.time()
|
|
||||||
|
|
||||||
if record:
|
|
||||||
setattr(record, f_name, val_to_set)
|
|
||||||
record.save()
|
|
||||||
save_time = time.time()
|
|
||||||
|
|
||||||
total_time = save_time - start_time
|
|
||||||
if total_time > 0.5: # 如果超过500ms就记录日志
|
|
||||||
logger.warning(
|
|
||||||
f"数据库更新操作耗时 {total_time:.3f}秒 (查询: {query_time - start_time:.3f}s, 保存: {save_time - query_time:.3f}s) person_id={p_id}, field={f_name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return True, False # Found and updated, no creation needed
|
|
||||||
else:
|
|
||||||
total_time = time.time() - start_time
|
|
||||||
if total_time > 0.5:
|
|
||||||
logger.warning(f"数据库查询操作耗时 {total_time:.3f}秒 person_id={p_id}, field={f_name}")
|
|
||||||
return False, True # Not found, needs creation
|
|
||||||
except Exception as e:
|
|
||||||
total_time = time.time() - start_time
|
|
||||||
logger.error(f"数据库操作异常,耗时 {total_time:.3f}秒: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
found, needs_creation = await asyncio.to_thread(_db_update_sync, person_id, field_name, processed_value)
|
|
||||||
|
|
||||||
if needs_creation:
|
|
||||||
logger.info(f"{person_id} 不存在,将新建。")
|
|
||||||
creation_data = data if data is not None else {}
|
|
||||||
# Ensure platform and user_id are present for context if available from 'data'
|
|
||||||
# but primarily, set the field that triggered the update.
|
|
||||||
# The create_person_info will handle defaults and serialization.
|
|
||||||
creation_data[field_name] = value # Pass original value to create_person_info
|
|
||||||
|
|
||||||
# Ensure platform and user_id are in creation_data if available,
|
|
||||||
# otherwise create_person_info will use defaults.
|
|
||||||
if data and "platform" in data:
|
|
||||||
creation_data["platform"] = data["platform"]
|
|
||||||
if data and "user_id" in data:
|
|
||||||
creation_data["user_id"] = data["user_id"]
|
|
||||||
|
|
||||||
# 使用安全的创建方法,处理竞态条件
|
|
||||||
await self._safe_create_person_info(person_id, creation_data)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_json_from_text(text: str) -> dict:
|
def _extract_json_from_text(text: str) -> dict:
|
||||||
@@ -279,8 +363,9 @@ class PersonInfoManager:
|
|||||||
logger.debug("取名失败:person_id不能为空")
|
logger.debug("取名失败:person_id不能为空")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
old_name = await self.get_value(person_id, "person_name")
|
person = Person(person_id=person_id)
|
||||||
old_reason = await self.get_value(person_id, "name_reason")
|
old_name = person.person_name
|
||||||
|
old_reason = person.name_reason
|
||||||
|
|
||||||
max_retries = 8
|
max_retries = 8
|
||||||
current_try = 0
|
current_try = 0
|
||||||
@@ -338,8 +423,9 @@ class PersonInfoManager:
|
|||||||
current_name_set.add(generated_nickname)
|
current_name_set.add(generated_nickname)
|
||||||
|
|
||||||
if not is_duplicate:
|
if not is_duplicate:
|
||||||
await self.update_one_field(person_id, "person_name", generated_nickname)
|
person.person_name = generated_nickname
|
||||||
await self.update_one_field(person_id, "name_reason", result.get("reason", "未提供理由"))
|
person.name_reason = result.get("reason", "未提供理由")
|
||||||
|
person.sync_to_database()
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"成功给用户{user_nickname} {person_id} 取名 {generated_nickname},理由:{result.get('reason', '未提供理由')}"
|
f"成功给用户{user_nickname} {person_id} 取名 {generated_nickname},理由:{result.get('reason', '未提供理由')}"
|
||||||
@@ -357,186 +443,11 @@ class PersonInfoManager:
|
|||||||
# 如果多次尝试后仍未成功,使用唯一的 user_nickname 作为默认值
|
# 如果多次尝试后仍未成功,使用唯一的 user_nickname 作为默认值
|
||||||
unique_nickname = await self._generate_unique_person_name(user_nickname)
|
unique_nickname = await self._generate_unique_person_name(user_nickname)
|
||||||
logger.warning(f"在{max_retries}次尝试后未能生成唯一昵称,使用默认昵称 {unique_nickname}")
|
logger.warning(f"在{max_retries}次尝试后未能生成唯一昵称,使用默认昵称 {unique_nickname}")
|
||||||
await self.update_one_field(person_id, "person_name", unique_nickname)
|
person.person_name = unique_nickname
|
||||||
await self.update_one_field(person_id, "name_reason", "使用用户原始昵称作为默认值")
|
person.name_reason = "使用用户原始昵称作为默认值"
|
||||||
|
person.sync_to_database()
|
||||||
self.person_name_list[person_id] = unique_nickname
|
self.person_name_list[person_id] = unique_nickname
|
||||||
return {"nickname": unique_nickname, "reason": "使用用户原始昵称作为默认值"}
|
return {"nickname": unique_nickname, "reason": "使用用户原始昵称作为默认值"}
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_value(person_id: str, field_name: str):
|
|
||||||
"""获取指定用户指定字段的值"""
|
|
||||||
default_value_for_field = person_info_default.get(field_name)
|
|
||||||
if field_name in JSON_SERIALIZED_FIELDS and default_value_for_field is None:
|
|
||||||
default_value_for_field = [] # Ensure JSON fields default to [] if not in DB
|
|
||||||
|
|
||||||
def _db_get_value_sync(p_id: str, f_name: str):
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_id == p_id)
|
|
||||||
if record:
|
|
||||||
val = getattr(record, f_name, None)
|
|
||||||
if f_name in JSON_SERIALIZED_FIELDS:
|
|
||||||
if isinstance(val, str):
|
|
||||||
try:
|
|
||||||
return json.loads(val)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
logger.warning(f"字段 {f_name} for {p_id} 包含无效JSON: {val}. 返回默认值.")
|
|
||||||
return [] # Default for JSON fields on error
|
|
||||||
elif val is None: # Field exists in DB but is None
|
|
||||||
return [] # Default for JSON fields
|
|
||||||
# If val is already a list/dict (e.g. if somehow set without serialization)
|
|
||||||
return val # Should ideally not happen if update_one_field is always used
|
|
||||||
return val
|
|
||||||
return None # Record not found
|
|
||||||
|
|
||||||
try:
|
|
||||||
value_from_db = await asyncio.to_thread(_db_get_value_sync, person_id, field_name)
|
|
||||||
if value_from_db is not None:
|
|
||||||
return value_from_db
|
|
||||||
if field_name in person_info_default:
|
|
||||||
return default_value_for_field
|
|
||||||
logger.warning(f"字段 {field_name} 在 person_info_default 中未定义,且在数据库中未找到。")
|
|
||||||
return None # Ultimate fallback
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"获取字段 {field_name} for {person_id} 时出错 (Peewee): {e}")
|
|
||||||
# Fallback to default in case of any error during DB access
|
|
||||||
return default_value_for_field if field_name in person_info_default else None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_value_sync(person_id: str, field_name: str):
|
|
||||||
"""同步获取指定用户指定字段的值"""
|
|
||||||
default_value_for_field = person_info_default.get(field_name)
|
|
||||||
if field_name in JSON_SERIALIZED_FIELDS and default_value_for_field is None:
|
|
||||||
default_value_for_field = []
|
|
||||||
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_id == person_id)
|
|
||||||
if record:
|
|
||||||
val = getattr(record, field_name, None)
|
|
||||||
if field_name in JSON_SERIALIZED_FIELDS:
|
|
||||||
if isinstance(val, str):
|
|
||||||
try:
|
|
||||||
return json.loads(val)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
logger.warning(f"字段 {field_name} for {person_id} 包含无效JSON: {val}. 返回默认值.")
|
|
||||||
return []
|
|
||||||
elif val is None:
|
|
||||||
return []
|
|
||||||
return val
|
|
||||||
return val
|
|
||||||
|
|
||||||
if field_name in person_info_default:
|
|
||||||
return default_value_for_field
|
|
||||||
logger.warning(f"字段 {field_name} 在 person_info_default 中未定义,且在数据库中未找到。")
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_values(person_id: str, field_names: list) -> dict:
|
|
||||||
"""获取指定person_id文档的多个字段值,若不存在该字段,则返回该字段的全局默认值"""
|
|
||||||
if not person_id:
|
|
||||||
logger.debug("get_values获取失败:person_id不能为空")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
def _db_get_record_sync(p_id: str):
|
|
||||||
return PersonInfo.get_or_none(PersonInfo.person_id == p_id)
|
|
||||||
|
|
||||||
record = await asyncio.to_thread(_db_get_record_sync, person_id)
|
|
||||||
|
|
||||||
for field_name in field_names:
|
|
||||||
if field_name not in PersonInfo._meta.fields: # type: ignore
|
|
||||||
if field_name in person_info_default:
|
|
||||||
result[field_name] = copy.deepcopy(person_info_default[field_name])
|
|
||||||
logger.debug(f"字段'{field_name}'不在Peewee模型中,使用默认配置值。")
|
|
||||||
else:
|
|
||||||
logger.debug(f"get_values查询失败:字段'{field_name}'未在Peewee模型和默认配置中定义。")
|
|
||||||
result[field_name] = None
|
|
||||||
continue
|
|
||||||
|
|
||||||
if record:
|
|
||||||
value = getattr(record, field_name)
|
|
||||||
if value is not None:
|
|
||||||
result[field_name] = value
|
|
||||||
else:
|
|
||||||
result[field_name] = copy.deepcopy(person_info_default.get(field_name))
|
|
||||||
else:
|
|
||||||
result[field_name] = copy.deepcopy(person_info_default.get(field_name))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def get_or_create_person(
|
|
||||||
self, platform: str, user_id: int, nickname: str, user_cardname: str, user_avatar: Optional[str] = None
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
根据 platform 和 user_id 获取 person_id。
|
|
||||||
如果对应的用户不存在,则使用提供的可选信息创建新用户。
|
|
||||||
使用try-except处理竞态条件,避免重复创建错误。
|
|
||||||
"""
|
|
||||||
person_id = self.get_person_id(platform, user_id)
|
|
||||||
|
|
||||||
def _db_get_or_create_sync(p_id: str, init_data: dict):
|
|
||||||
"""原子性的获取或创建操作"""
|
|
||||||
# 首先尝试获取现有记录
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_id == p_id)
|
|
||||||
if record:
|
|
||||||
return record, False # 记录存在,未创建
|
|
||||||
|
|
||||||
# 记录不存在,尝试创建
|
|
||||||
try:
|
|
||||||
PersonInfo.create(**init_data)
|
|
||||||
return PersonInfo.get(PersonInfo.person_id == p_id), True # 创建成功
|
|
||||||
except Exception as e:
|
|
||||||
# 如果创建失败(可能是因为竞态条件),再次尝试获取
|
|
||||||
if "UNIQUE constraint failed" in str(e):
|
|
||||||
logger.debug(f"检测到并发创建用户 {p_id},获取现有记录")
|
|
||||||
record = PersonInfo.get_or_none(PersonInfo.person_id == p_id)
|
|
||||||
if record:
|
|
||||||
return record, False # 其他协程已创建,返回现有记录
|
|
||||||
# 如果仍然失败,重新抛出异常
|
|
||||||
raise e
|
|
||||||
|
|
||||||
unique_nickname = await self._generate_unique_person_name(nickname)
|
|
||||||
initial_data = {
|
|
||||||
"person_id": person_id,
|
|
||||||
"platform": platform,
|
|
||||||
"user_id": str(user_id),
|
|
||||||
"nickname": nickname,
|
|
||||||
"person_name": unique_nickname, # 使用群昵称作为person_name
|
|
||||||
"name_reason": "从群昵称获取",
|
|
||||||
"know_times": 0,
|
|
||||||
"know_since": int(datetime.datetime.now().timestamp()),
|
|
||||||
"last_know": int(datetime.datetime.now().timestamp()),
|
|
||||||
"impression": None,
|
|
||||||
"points": [],
|
|
||||||
"forgotten_points": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
# 序列化JSON字段
|
|
||||||
for key in JSON_SERIALIZED_FIELDS:
|
|
||||||
if key in initial_data:
|
|
||||||
if isinstance(initial_data[key], (list, dict)):
|
|
||||||
initial_data[key] = json.dumps(initial_data[key], ensure_ascii=False)
|
|
||||||
elif initial_data[key] is None:
|
|
||||||
initial_data[key] = json.dumps([], ensure_ascii=False)
|
|
||||||
|
|
||||||
model_fields = PersonInfo._meta.fields.keys() # type: ignore
|
|
||||||
filtered_initial_data = {k: v for k, v in initial_data.items() if v is not None and k in model_fields}
|
|
||||||
|
|
||||||
record, was_created = await asyncio.to_thread(_db_get_or_create_sync, person_id, filtered_initial_data)
|
|
||||||
|
|
||||||
if was_created:
|
|
||||||
logger.info(f"用户 {platform}:{user_id} (person_id: {person_id}) 不存在,将创建新记录 (Peewee)。")
|
|
||||||
logger.info(f"已为 {person_id} 创建新记录,初始数据 (filtered for model): {filtered_initial_data}")
|
|
||||||
else:
|
|
||||||
logger.debug(f"用户 {platform}:{user_id} (person_id: {person_id}) 已存在,返回现有记录。")
|
|
||||||
|
|
||||||
return person_id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
person_info_manager = None
|
|
||||||
|
|
||||||
def get_person_info_manager():
|
|
||||||
global person_info_manager
|
|
||||||
if person_info_manager is None:
|
|
||||||
person_info_manager = PersonInfoManager()
|
person_info_manager = PersonInfoManager()
|
||||||
return person_info_manager
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from typing import List, Dict, Any
|
|||||||
from src.config.config import global_config
|
from src.config.config import global_config
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.person_info.relationship_manager import get_relationship_manager
|
from src.person_info.relationship_manager import get_relationship_manager
|
||||||
from src.person_info.person_info import get_person_info_manager, PersonInfoManager
|
from src.person_info.person_info import Person,get_person_id
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||||
from src.chat.utils.chat_message_builder import (
|
from src.chat.utils.chat_message_builder import (
|
||||||
get_raw_msg_by_timestamp_with_chat,
|
get_raw_msg_by_timestamp_with_chat,
|
||||||
@@ -15,6 +15,7 @@ from src.chat.utils.chat_message_builder import (
|
|||||||
get_raw_msg_before_timestamp_with_chat,
|
get_raw_msg_before_timestamp_with_chat,
|
||||||
num_new_messages_since,
|
num_new_messages_since,
|
||||||
)
|
)
|
||||||
|
import asyncio
|
||||||
|
|
||||||
logger = get_logger("relationship_builder")
|
logger = get_logger("relationship_builder")
|
||||||
|
|
||||||
@@ -142,7 +143,8 @@ class RelationshipBuilder:
|
|||||||
}
|
}
|
||||||
segments.append(new_segment)
|
segments.append(new_segment)
|
||||||
|
|
||||||
person_name = get_person_info_manager().get_value_sync(person_id, "person_name") or person_id
|
person = Person(person_id=person_id)
|
||||||
|
person_name = person.person_name or person_id
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 眼熟用户 {person_name} 在 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))} 之间有 {new_segment['message_count']} 条消息"
|
f"{self.log_prefix} 眼熟用户 {person_name} 在 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))} 之间有 {new_segment['message_count']} 条消息"
|
||||||
)
|
)
|
||||||
@@ -188,8 +190,8 @@ class RelationshipBuilder:
|
|||||||
"message_count": self._count_messages_in_timerange(potential_start_time, message_time),
|
"message_count": self._count_messages_in_timerange(potential_start_time, message_time),
|
||||||
}
|
}
|
||||||
segments.append(new_segment)
|
segments.append(new_segment)
|
||||||
person_info_manager = get_person_info_manager()
|
person = Person(person_id=person_id)
|
||||||
person_name = person_info_manager.get_value_sync(person_id, "person_name") or person_id
|
person_name = person.person_name or person_id
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 重新眼熟用户 {person_name} 创建新消息段(超过10条消息间隔): {new_segment}"
|
f"{self.log_prefix} 重新眼熟用户 {person_name} 创建新消息段(超过10条消息间隔): {new_segment}"
|
||||||
)
|
)
|
||||||
@@ -375,7 +377,7 @@ class RelationshipBuilder:
|
|||||||
and user_id != global_config.bot.qq_account
|
and user_id != global_config.bot.qq_account
|
||||||
and msg_time > self.last_processed_message_time
|
and msg_time > self.last_processed_message_time
|
||||||
):
|
):
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
person_id = get_person_id(platform, user_id)
|
||||||
self._update_message_segments(person_id, msg_time)
|
self._update_message_segments(person_id, msg_time)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}"
|
f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}"
|
||||||
@@ -386,7 +388,8 @@ class RelationshipBuilder:
|
|||||||
users_to_build_relationship = []
|
users_to_build_relationship = []
|
||||||
for person_id, segments in self.person_engaged_cache.items():
|
for person_id, segments in self.person_engaged_cache.items():
|
||||||
total_message_count = self._get_total_message_count(person_id)
|
total_message_count = self._get_total_message_count(person_id)
|
||||||
person_name = get_person_info_manager().get_value_sync(person_id, "person_name") or person_id
|
person = Person(person_id=person_id)
|
||||||
|
person_name = person.person_name or person_id
|
||||||
|
|
||||||
if total_message_count >= max_build_threshold or (total_message_count >= 5 and (immediate_build == person_id or immediate_build == "all")):
|
if total_message_count >= max_build_threshold or (total_message_count >= 5 and (immediate_build == person_id or immediate_build == "all")):
|
||||||
users_to_build_relationship.append(person_id)
|
users_to_build_relationship.append(person_id)
|
||||||
@@ -403,8 +406,8 @@ class RelationshipBuilder:
|
|||||||
for person_id in users_to_build_relationship:
|
for person_id in users_to_build_relationship:
|
||||||
segments = self.person_engaged_cache[person_id]
|
segments = self.person_engaged_cache[person_id]
|
||||||
# 异步执行关系构建
|
# 异步执行关系构建
|
||||||
import asyncio
|
person = Person(person_id=person_id)
|
||||||
|
if person.is_known:
|
||||||
asyncio.create_task(self.update_impression_on_segments(person_id, self.chat_id, segments))
|
asyncio.create_task(self.update_impression_on_segments(person_id, self.chat_id, segments))
|
||||||
# 移除已处理的用户缓存
|
# 移除已处理的用户缓存
|
||||||
del self.person_engaged_cache[person_id]
|
del self.person_engaged_cache[person_id]
|
||||||
|
|||||||
@@ -1,468 +0,0 @@
|
|||||||
import time
|
|
||||||
import traceback
|
|
||||||
import json
|
|
||||||
import random
|
|
||||||
|
|
||||||
from typing import List, Dict, Any
|
|
||||||
from json_repair import repair_json
|
|
||||||
|
|
||||||
from src.common.logger import get_logger
|
|
||||||
from src.config.config import global_config, model_config
|
|
||||||
from src.llm_models.utils_model import LLMRequest
|
|
||||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
|
||||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
|
||||||
from src.person_info.person_info import get_person_info_manager
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger("relationship_fetcher")
|
|
||||||
|
|
||||||
|
|
||||||
def init_real_time_info_prompts():
|
|
||||||
"""初始化实时信息提取相关的提示词"""
|
|
||||||
relationship_prompt = """
|
|
||||||
<聊天记录>
|
|
||||||
{chat_observe_info}
|
|
||||||
</聊天记录>
|
|
||||||
|
|
||||||
{name_block}
|
|
||||||
现在,你想要回复{person_name}的消息,消息内容是:{target_message}。请根据聊天记录和你要回复的消息,从你对{person_name}的了解中提取有关的信息:
|
|
||||||
1.你需要提供你想要提取的信息具体是哪方面的信息,例如:年龄,性别,你们之间的交流方式,最近发生的事等等。
|
|
||||||
2.请注意,请不要重复调取相同的信息,已经调取的信息如下:
|
|
||||||
{info_cache_block}
|
|
||||||
3.如果当前聊天记录中没有需要查询的信息,或者现有信息已经足够回复,请返回{{"none": "不需要查询"}}
|
|
||||||
|
|
||||||
请以json格式输出,例如:
|
|
||||||
|
|
||||||
{{
|
|
||||||
"info_type": "信息类型",
|
|
||||||
}}
|
|
||||||
|
|
||||||
请严格按照json输出格式,不要输出多余内容:
|
|
||||||
"""
|
|
||||||
Prompt(relationship_prompt, "real_time_info_identify_prompt")
|
|
||||||
|
|
||||||
fetch_info_prompt = """
|
|
||||||
|
|
||||||
{name_block}
|
|
||||||
以下是你在之前与{person_name}的交流中,产生的对{person_name}的了解:
|
|
||||||
{person_impression_block}
|
|
||||||
{points_text_block}
|
|
||||||
|
|
||||||
请从中提取用户"{person_name}"的有关"{info_type}"信息
|
|
||||||
请以json格式输出,例如:
|
|
||||||
|
|
||||||
{{
|
|
||||||
{info_json_str}
|
|
||||||
}}
|
|
||||||
|
|
||||||
请严格按照json输出格式,不要输出多余内容:
|
|
||||||
"""
|
|
||||||
Prompt(fetch_info_prompt, "real_time_fetch_person_info_prompt")
|
|
||||||
|
|
||||||
|
|
||||||
class RelationshipFetcher:
|
|
||||||
def __init__(self, chat_id):
|
|
||||||
self.chat_id = chat_id
|
|
||||||
|
|
||||||
# 信息获取缓存:记录正在获取的信息请求
|
|
||||||
self.info_fetching_cache: List[Dict[str, Any]] = []
|
|
||||||
|
|
||||||
# 信息结果缓存:存储已获取的信息结果,带TTL
|
|
||||||
self.info_fetched_cache: Dict[str, Dict[str, Any]] = {}
|
|
||||||
# 结构:{person_id: {info_type: {"info": str, "ttl": int, "start_time": float, "person_name": str, "unknown": bool}}}
|
|
||||||
|
|
||||||
# LLM模型配置
|
|
||||||
self.llm_model = LLMRequest(
|
|
||||||
model_set=model_config.model_task_config.utils_small, request_type="relation.fetcher"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 小模型用于即时信息提取
|
|
||||||
self.instant_llm_model = LLMRequest(
|
|
||||||
model_set=model_config.model_task_config.utils_small, request_type="relation.fetch"
|
|
||||||
)
|
|
||||||
|
|
||||||
name = get_chat_manager().get_stream_name(self.chat_id)
|
|
||||||
self.log_prefix = f"[{name}] 实时信息"
|
|
||||||
|
|
||||||
def _cleanup_expired_cache(self):
|
|
||||||
"""清理过期的信息缓存"""
|
|
||||||
for person_id in list(self.info_fetched_cache.keys()):
|
|
||||||
for info_type in list(self.info_fetched_cache[person_id].keys()):
|
|
||||||
self.info_fetched_cache[person_id][info_type]["ttl"] -= 1
|
|
||||||
if self.info_fetched_cache[person_id][info_type]["ttl"] <= 0:
|
|
||||||
del self.info_fetched_cache[person_id][info_type]
|
|
||||||
if not self.info_fetched_cache[person_id]:
|
|
||||||
del self.info_fetched_cache[person_id]
|
|
||||||
|
|
||||||
async def build_relation_info(self, person_id, points_num=3):
|
|
||||||
# 清理过期的信息缓存
|
|
||||||
self._cleanup_expired_cache()
|
|
||||||
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
|
||||||
attitude_to_me = await person_info_manager.get_value(person_id, "attitude_to_me")
|
|
||||||
neuroticism = await person_info_manager.get_value(person_id, "neuroticism")
|
|
||||||
conscientiousness = await person_info_manager.get_value(person_id, "conscientiousness")
|
|
||||||
likeness = await person_info_manager.get_value(person_id, "likeness")
|
|
||||||
|
|
||||||
nickname_str = await person_info_manager.get_value(person_id, "nickname")
|
|
||||||
platform = await person_info_manager.get_value(person_id, "platform")
|
|
||||||
|
|
||||||
current_points = await person_info_manager.get_value(person_id, "points") or []
|
|
||||||
|
|
||||||
# 按时间排序forgotten_points
|
|
||||||
current_points.sort(key=lambda x: x[2])
|
|
||||||
# 按权重加权随机抽取最多3个不重复的points,point[1]的值在1-10之间,权重越高被抽到概率越大
|
|
||||||
if len(current_points) > points_num:
|
|
||||||
# point[1] 取值范围1-10,直接作为权重
|
|
||||||
weights = [max(1, min(10, int(point[1]))) for point in current_points]
|
|
||||||
# 使用加权采样不放回,保证不重复
|
|
||||||
indices = list(range(len(current_points)))
|
|
||||||
points = []
|
|
||||||
for _ in range(points_num):
|
|
||||||
if not indices:
|
|
||||||
break
|
|
||||||
sub_weights = [weights[i] for i in indices]
|
|
||||||
chosen_idx = random.choices(indices, weights=sub_weights, k=1)[0]
|
|
||||||
points.append(current_points[chosen_idx])
|
|
||||||
indices.remove(chosen_idx)
|
|
||||||
else:
|
|
||||||
points = current_points
|
|
||||||
|
|
||||||
# 构建points文本
|
|
||||||
points_text = "\n".join([f"{point[2]}:{point[0]}" for point in points])
|
|
||||||
|
|
||||||
nickname_str = ""
|
|
||||||
if person_name != nickname_str:
|
|
||||||
nickname_str = f"(ta在{platform}上的昵称是{nickname_str})"
|
|
||||||
|
|
||||||
relation_info = ""
|
|
||||||
|
|
||||||
attitude_info = ""
|
|
||||||
attitude_parts = attitude_to_me.split(',')
|
|
||||||
current_attitude_score = float(attitude_parts[0]) if len(attitude_parts) > 0 else 0.0
|
|
||||||
total_confidence = float(attitude_parts[1]) if len(attitude_parts) > 1 else 1.0
|
|
||||||
if attitude_to_me:
|
|
||||||
if current_attitude_score > 8:
|
|
||||||
attitude_info = f"{person_name}对你的态度十分好,"
|
|
||||||
elif current_attitude_score > 5:
|
|
||||||
attitude_info = f"{person_name}对你的态度较好,"
|
|
||||||
|
|
||||||
|
|
||||||
if current_attitude_score < -8:
|
|
||||||
attitude_info = f"{person_name}对你的态度十分恶劣,"
|
|
||||||
elif current_attitude_score < -4:
|
|
||||||
attitude_info = f"{person_name}对你的态度不好,"
|
|
||||||
elif current_attitude_score < 0:
|
|
||||||
attitude_info = f"{person_name}对你的态度一般,"
|
|
||||||
|
|
||||||
neuroticism_info = ""
|
|
||||||
neuroticism_parts = neuroticism.split(',')
|
|
||||||
current_neuroticism_score = float(neuroticism_parts[0]) if len(neuroticism_parts) > 0 else 0.0
|
|
||||||
total_confidence = float(neuroticism_parts[1]) if len(neuroticism_parts) > 1 else 1.0
|
|
||||||
if neuroticism:
|
|
||||||
if current_neuroticism_score > 8:
|
|
||||||
neuroticism_info = f"{person_name}的情绪十分活跃,容易情绪化,"
|
|
||||||
elif current_neuroticism_score > 6:
|
|
||||||
neuroticism_info = f"{person_name}的情绪比较活跃,"
|
|
||||||
elif current_neuroticism_score > 4:
|
|
||||||
neuroticism_info = ""
|
|
||||||
elif current_neuroticism_score > 2:
|
|
||||||
neuroticism_info = f"{person_name}的情绪比较稳定,"
|
|
||||||
else:
|
|
||||||
neuroticism_info = f"{person_name}的情绪非常稳定,毫无波动"
|
|
||||||
|
|
||||||
points_info = ""
|
|
||||||
if points_text:
|
|
||||||
points_info = f"你还记得ta最近做的事:{points_text}"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
relation_info = f"{person_name}:{nickname_str}{attitude_info}{neuroticism_info}{points_info}"
|
|
||||||
|
|
||||||
|
|
||||||
return relation_info
|
|
||||||
|
|
||||||
async def _build_fetch_query(self, person_id, target_message, chat_history):
|
|
||||||
nickname_str = ",".join(global_config.bot.alias_names)
|
|
||||||
name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
person_name: str = await person_info_manager.get_value(person_id, "person_name") # type: ignore
|
|
||||||
|
|
||||||
info_cache_block = self._build_info_cache_block()
|
|
||||||
|
|
||||||
prompt = (await global_prompt_manager.get_prompt_async("real_time_info_identify_prompt")).format(
|
|
||||||
chat_observe_info=chat_history,
|
|
||||||
name_block=name_block,
|
|
||||||
info_cache_block=info_cache_block,
|
|
||||||
person_name=person_name,
|
|
||||||
target_message=target_message,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
logger.debug(f"{self.log_prefix} 信息识别prompt: \n{prompt}\n")
|
|
||||||
content, _ = await self.llm_model.generate_response_async(prompt=prompt)
|
|
||||||
|
|
||||||
if content:
|
|
||||||
content_json = json.loads(repair_json(content))
|
|
||||||
|
|
||||||
# 检查是否返回了不需要查询的标志
|
|
||||||
if "none" in content_json:
|
|
||||||
logger.debug(f"{self.log_prefix} LLM判断当前不需要查询任何信息:{content_json.get('none', '')}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
if info_type := content_json.get("info_type"):
|
|
||||||
# 记录信息获取请求
|
|
||||||
self.info_fetching_cache.append(
|
|
||||||
{
|
|
||||||
"person_id": get_person_info_manager().get_person_id_by_person_name(person_name),
|
|
||||||
"person_name": person_name,
|
|
||||||
"info_type": info_type,
|
|
||||||
"start_time": time.time(),
|
|
||||||
"forget": False,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# 限制缓存大小
|
|
||||||
if len(self.info_fetching_cache) > 10:
|
|
||||||
self.info_fetching_cache.pop(0)
|
|
||||||
|
|
||||||
logger.info(f"{self.log_prefix} 识别到需要调取用户 {person_name} 的[{info_type}]信息")
|
|
||||||
return info_type
|
|
||||||
else:
|
|
||||||
logger.warning(f"{self.log_prefix} LLM未返回有效的info_type。响应: {content}")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"{self.log_prefix} 执行信息识别LLM请求时出错: {e}")
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _build_info_cache_block(self) -> str:
|
|
||||||
"""构建已获取信息的缓存块"""
|
|
||||||
info_cache_block = ""
|
|
||||||
if self.info_fetching_cache:
|
|
||||||
# 对于每个(person_id, info_type)组合,只保留最新的记录
|
|
||||||
latest_records = {}
|
|
||||||
for info_fetching in self.info_fetching_cache:
|
|
||||||
key = (info_fetching["person_id"], info_fetching["info_type"])
|
|
||||||
if key not in latest_records or info_fetching["start_time"] > latest_records[key]["start_time"]:
|
|
||||||
latest_records[key] = info_fetching
|
|
||||||
|
|
||||||
# 按时间排序并生成显示文本
|
|
||||||
sorted_records = sorted(latest_records.values(), key=lambda x: x["start_time"])
|
|
||||||
for info_fetching in sorted_records:
|
|
||||||
info_cache_block += (
|
|
||||||
f"你已经调取了[{info_fetching['person_name']}]的[{info_fetching['info_type']}]信息\n"
|
|
||||||
)
|
|
||||||
return info_cache_block
|
|
||||||
|
|
||||||
async def _extract_single_info(self, person_id: str, info_type: str, person_name: str):
|
|
||||||
"""提取单个信息类型
|
|
||||||
|
|
||||||
Args:
|
|
||||||
person_id: 用户ID
|
|
||||||
info_type: 信息类型
|
|
||||||
person_name: 用户名
|
|
||||||
"""
|
|
||||||
start_time = time.time()
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
|
|
||||||
# 首先检查 info_list 缓存
|
|
||||||
info_list = await person_info_manager.get_value(person_id, "info_list") or []
|
|
||||||
cached_info = None
|
|
||||||
|
|
||||||
# 查找对应的 info_type
|
|
||||||
for info_item in info_list:
|
|
||||||
if info_item.get("info_type") == info_type:
|
|
||||||
cached_info = info_item.get("info_content")
|
|
||||||
logger.debug(f"{self.log_prefix} 在info_list中找到 {person_name} 的 {info_type} 信息: {cached_info}")
|
|
||||||
break
|
|
||||||
|
|
||||||
# 如果缓存中有信息,直接使用
|
|
||||||
if cached_info:
|
|
||||||
if person_id not in self.info_fetched_cache:
|
|
||||||
self.info_fetched_cache[person_id] = {}
|
|
||||||
|
|
||||||
self.info_fetched_cache[person_id][info_type] = {
|
|
||||||
"info": cached_info,
|
|
||||||
"ttl": 2,
|
|
||||||
"start_time": start_time,
|
|
||||||
"person_name": person_name,
|
|
||||||
"unknown": cached_info == "none",
|
|
||||||
}
|
|
||||||
logger.info(f"{self.log_prefix} 记得 {person_name} 的 {info_type}: {cached_info}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 如果缓存中没有,尝试从用户档案中提取
|
|
||||||
try:
|
|
||||||
person_impression = await person_info_manager.get_value(person_id, "impression")
|
|
||||||
points = await person_info_manager.get_value(person_id, "points")
|
|
||||||
|
|
||||||
# 构建印象信息块
|
|
||||||
if person_impression:
|
|
||||||
person_impression_block = (
|
|
||||||
f"<对{person_name}的总体了解>\n{person_impression}\n</对{person_name}的总体了解>"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
person_impression_block = ""
|
|
||||||
|
|
||||||
# 构建要点信息块
|
|
||||||
if points:
|
|
||||||
points_text = "\n".join([f"{point[2]}:{point[0]}" for point in points])
|
|
||||||
points_text_block = f"<对{person_name}的近期了解>\n{points_text}\n</对{person_name}的近期了解>"
|
|
||||||
else:
|
|
||||||
points_text_block = ""
|
|
||||||
|
|
||||||
# 如果完全没有用户信息
|
|
||||||
if not points_text_block and not person_impression_block:
|
|
||||||
if person_id not in self.info_fetched_cache:
|
|
||||||
self.info_fetched_cache[person_id] = {}
|
|
||||||
self.info_fetched_cache[person_id][info_type] = {
|
|
||||||
"info": "none",
|
|
||||||
"ttl": 2,
|
|
||||||
"start_time": start_time,
|
|
||||||
"person_name": person_name,
|
|
||||||
"unknown": True,
|
|
||||||
}
|
|
||||||
logger.info(f"{self.log_prefix} 完全不认识 {person_name}")
|
|
||||||
await self._save_info_to_cache(person_id, info_type, "none")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 使用LLM提取信息
|
|
||||||
nickname_str = ",".join(global_config.bot.alias_names)
|
|
||||||
name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
|
|
||||||
|
|
||||||
prompt = (await global_prompt_manager.get_prompt_async("real_time_fetch_person_info_prompt")).format(
|
|
||||||
name_block=name_block,
|
|
||||||
info_type=info_type,
|
|
||||||
person_impression_block=person_impression_block,
|
|
||||||
person_name=person_name,
|
|
||||||
info_json_str=f'"{info_type}": "有关{info_type}的信息内容"',
|
|
||||||
points_text_block=points_text_block,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 使用小模型进行即时提取
|
|
||||||
content, _ = await self.instant_llm_model.generate_response_async(prompt=prompt)
|
|
||||||
|
|
||||||
if content:
|
|
||||||
content_json = json.loads(repair_json(content))
|
|
||||||
if info_type in content_json:
|
|
||||||
info_content = content_json[info_type]
|
|
||||||
is_unknown = info_content == "none" or not info_content
|
|
||||||
|
|
||||||
# 保存到运行时缓存
|
|
||||||
if person_id not in self.info_fetched_cache:
|
|
||||||
self.info_fetched_cache[person_id] = {}
|
|
||||||
self.info_fetched_cache[person_id][info_type] = {
|
|
||||||
"info": "unknown" if is_unknown else info_content,
|
|
||||||
"ttl": 3,
|
|
||||||
"start_time": start_time,
|
|
||||||
"person_name": person_name,
|
|
||||||
"unknown": is_unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
# 保存到持久化缓存 (info_list)
|
|
||||||
await self._save_info_to_cache(person_id, info_type, "none" if is_unknown else info_content)
|
|
||||||
|
|
||||||
if not is_unknown:
|
|
||||||
logger.info(f"{self.log_prefix} 思考得到,{person_name} 的 {info_type}: {info_content}")
|
|
||||||
else:
|
|
||||||
logger.info(f"{self.log_prefix} 思考了也不知道{person_name} 的 {info_type} 信息")
|
|
||||||
else:
|
|
||||||
logger.warning(f"{self.log_prefix} 小模型返回空结果,获取 {person_name} 的 {info_type} 信息失败。")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"{self.log_prefix} 执行信息提取时出错: {e}")
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
async def _save_info_to_cache(self, person_id: str, info_type: str, info_content: str):
|
|
||||||
# sourcery skip: use-next
|
|
||||||
"""将提取到的信息保存到 person_info 的 info_list 字段中
|
|
||||||
|
|
||||||
Args:
|
|
||||||
person_id: 用户ID
|
|
||||||
info_type: 信息类型
|
|
||||||
info_content: 信息内容
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
|
|
||||||
# 获取现有的 info_list
|
|
||||||
info_list = await person_info_manager.get_value(person_id, "info_list") or []
|
|
||||||
|
|
||||||
# 查找是否已存在相同 info_type 的记录
|
|
||||||
found_index = -1
|
|
||||||
for i, info_item in enumerate(info_list):
|
|
||||||
if isinstance(info_item, dict) and info_item.get("info_type") == info_type:
|
|
||||||
found_index = i
|
|
||||||
break
|
|
||||||
|
|
||||||
# 创建新的信息记录
|
|
||||||
new_info_item = {
|
|
||||||
"info_type": info_type,
|
|
||||||
"info_content": info_content,
|
|
||||||
}
|
|
||||||
|
|
||||||
if found_index >= 0:
|
|
||||||
# 更新现有记录
|
|
||||||
info_list[found_index] = new_info_item
|
|
||||||
logger.info(f"{self.log_prefix} [缓存更新] 更新 {person_id} 的 {info_type} 信息缓存")
|
|
||||||
else:
|
|
||||||
# 添加新记录
|
|
||||||
info_list.append(new_info_item)
|
|
||||||
logger.info(f"{self.log_prefix} [缓存保存] 新增 {person_id} 的 {info_type} 信息缓存")
|
|
||||||
|
|
||||||
# 保存更新后的 info_list
|
|
||||||
await person_info_manager.update_one_field(person_id, "info_list", info_list)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"{self.log_prefix} [缓存保存] 保存信息到缓存失败: {e}")
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
class RelationshipFetcherManager:
|
|
||||||
"""关系提取器管理器
|
|
||||||
|
|
||||||
管理不同 chat_id 的 RelationshipFetcher 实例
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._fetchers: Dict[str, RelationshipFetcher] = {}
|
|
||||||
|
|
||||||
def get_fetcher(self, chat_id: str) -> RelationshipFetcher:
|
|
||||||
"""获取或创建指定 chat_id 的 RelationshipFetcher
|
|
||||||
|
|
||||||
Args:
|
|
||||||
chat_id: 聊天ID
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
RelationshipFetcher: 关系提取器实例
|
|
||||||
"""
|
|
||||||
if chat_id not in self._fetchers:
|
|
||||||
self._fetchers[chat_id] = RelationshipFetcher(chat_id)
|
|
||||||
return self._fetchers[chat_id]
|
|
||||||
|
|
||||||
def remove_fetcher(self, chat_id: str):
|
|
||||||
"""移除指定 chat_id 的 RelationshipFetcher
|
|
||||||
|
|
||||||
Args:
|
|
||||||
chat_id: 聊天ID
|
|
||||||
"""
|
|
||||||
if chat_id in self._fetchers:
|
|
||||||
del self._fetchers[chat_id]
|
|
||||||
|
|
||||||
def clear_all(self):
|
|
||||||
"""清空所有 RelationshipFetcher"""
|
|
||||||
self._fetchers.clear()
|
|
||||||
|
|
||||||
def get_active_chat_ids(self) -> List[str]:
|
|
||||||
"""获取所有活跃的 chat_id 列表"""
|
|
||||||
return list(self._fetchers.keys())
|
|
||||||
|
|
||||||
|
|
||||||
# 全局管理器实例
|
|
||||||
relationship_fetcher_manager = RelationshipFetcherManager()
|
|
||||||
|
|
||||||
|
|
||||||
init_real_time_info_prompts()
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from .person_info import PersonInfoManager, get_person_info_manager
|
from .person_info import Person
|
||||||
import time
|
|
||||||
import random
|
import random
|
||||||
from src.llm_models.utils_model import LLMRequest
|
from src.llm_models.utils_model import LLMRequest
|
||||||
from src.config.config import global_config, model_config
|
from src.config.config import global_config, model_config
|
||||||
@@ -8,11 +7,7 @@ from src.chat.utils.chat_message_builder import build_readable_messages
|
|||||||
import json
|
import json
|
||||||
from json_repair import repair_json
|
from json_repair import repair_json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from difflib import SequenceMatcher
|
from typing import List, Dict, Any
|
||||||
import jieba
|
|
||||||
from sklearn.feature_extraction.text import TfidfVectorizer
|
|
||||||
from sklearn.metrics.pairwise import cosine_similarity
|
|
||||||
from typing import List, Dict, Any, Tuple
|
|
||||||
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
@@ -52,8 +47,7 @@ def init_prompt():
|
|||||||
}}
|
}}
|
||||||
]
|
]
|
||||||
|
|
||||||
如果没有,就输出none,或返回空数组:
|
如果没有,就只输出空数组:[]
|
||||||
[]
|
|
||||||
""",
|
""",
|
||||||
"relation_points",
|
"relation_points",
|
||||||
)
|
)
|
||||||
@@ -83,7 +77,9 @@ def init_prompt():
|
|||||||
"attitude": 0,
|
"attitude": 0,
|
||||||
"confidence": 0.5
|
"confidence": 0.5
|
||||||
}}
|
}}
|
||||||
现在,请你输出json:
|
如果无法看出对方对你的态度,就只输出空数组:[]
|
||||||
|
|
||||||
|
现在,请你输出:
|
||||||
""",
|
""",
|
||||||
"attitude_to_me_prompt",
|
"attitude_to_me_prompt",
|
||||||
)
|
)
|
||||||
@@ -115,7 +111,9 @@ def init_prompt():
|
|||||||
"neuroticism": 0,
|
"neuroticism": 0,
|
||||||
"confidence": 0.5
|
"confidence": 0.5
|
||||||
}}
|
}}
|
||||||
现在,请你输出json:
|
如果无法看出对方的神经质程度,就只输出空数组:[]
|
||||||
|
|
||||||
|
现在,请你输出:
|
||||||
""",
|
""",
|
||||||
"neuroticism_prompt",
|
"neuroticism_prompt",
|
||||||
)
|
)
|
||||||
@@ -124,38 +122,7 @@ class RelationshipManager:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.relationship_llm = LLMRequest(
|
self.relationship_llm = LLMRequest(
|
||||||
model_set=model_config.model_task_config.utils, request_type="relationship.person"
|
model_set=model_config.model_task_config.utils, request_type="relationship.person"
|
||||||
) # 用于动作规划
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def is_known_some_one(platform, user_id):
|
|
||||||
"""判断是否认识某人"""
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
return await person_info_manager.is_person_known(platform, user_id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def first_knowing_some_one(platform: str, user_id: str, user_nickname: str, user_cardname: str):
|
|
||||||
"""判断是否认识某人"""
|
|
||||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
|
||||||
# 生成唯一的 person_name
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
unique_nickname = await person_info_manager._generate_unique_person_name(user_nickname)
|
|
||||||
data = {
|
|
||||||
"platform": platform,
|
|
||||||
"user_id": user_id,
|
|
||||||
"nickname": user_nickname,
|
|
||||||
"konw_time": int(time.time()),
|
|
||||||
"person_name": unique_nickname, # 使用唯一的 person_name
|
|
||||||
}
|
|
||||||
# 先创建用户基本信息,使用安全创建方法避免竞态条件
|
|
||||||
await person_info_manager._safe_create_person_info(person_id=person_id, data=data)
|
|
||||||
# 更新昵称
|
|
||||||
await person_info_manager.update_one_field(
|
|
||||||
person_id=person_id, field_name="nickname", value=user_nickname, data=data
|
|
||||||
)
|
)
|
||||||
# 尝试生成更好的名字
|
|
||||||
# await person_info_manager.qv_person_name(
|
|
||||||
# person_id=person_id, user_nickname=user_nickname, user_cardname=user_cardname, user_avatar=user_avatar
|
|
||||||
# )
|
|
||||||
|
|
||||||
async def get_points(self,
|
async def get_points(self,
|
||||||
person_name: str,
|
person_name: str,
|
||||||
@@ -163,7 +130,7 @@ class RelationshipManager:
|
|||||||
readable_messages: str,
|
readable_messages: str,
|
||||||
name_mapping: Dict[str, str],
|
name_mapping: Dict[str, str],
|
||||||
timestamp: float,
|
timestamp: float,
|
||||||
current_points: List[Tuple[str, float, str]]):
|
person: Person):
|
||||||
alias_str = ", ".join(global_config.bot.alias_names)
|
alias_str = ", ".join(global_config.bot.alias_names)
|
||||||
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
@@ -198,9 +165,7 @@ class RelationshipManager:
|
|||||||
points_data = json.loads(points)
|
points_data = json.loads(points)
|
||||||
|
|
||||||
# 只处理正确的格式,错误格式直接跳过
|
# 只处理正确的格式,错误格式直接跳过
|
||||||
if points_data == "none" or not points_data:
|
if points_data == "none" or not points_data or (isinstance(points_data, str) and points_data.lower() == "none") or (isinstance(points_data, list) and len(points_data) == 0):
|
||||||
points_list = []
|
|
||||||
elif isinstance(points_data, str) and points_data.lower() == "none":
|
|
||||||
points_list = []
|
points_list = []
|
||||||
elif isinstance(points_data, list):
|
elif isinstance(points_data, list):
|
||||||
points_list = [(item["point"], float(item["weight"]), current_time) for item in points_data]
|
points_list = [(item["point"], float(item["weight"]), current_time) for item in points_data]
|
||||||
@@ -238,15 +203,15 @@ class RelationshipManager:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
current_points.extend(points_list)
|
person.points.extend(points_list)
|
||||||
# 如果points超过10条,按权重随机选择多余的条目移动到forgotten_points
|
# 如果points超过10条,按权重随机选择多余的条目移动到forgotten_points
|
||||||
if len(current_points) > 20:
|
if len(person.points) > 20:
|
||||||
# 计算当前时间
|
# 计算当前时间
|
||||||
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
# 计算每个点的最终权重(原始权重 * 时间权重)
|
# 计算每个点的最终权重(原始权重 * 时间权重)
|
||||||
weighted_points = []
|
weighted_points = []
|
||||||
for point in current_points:
|
for point in person.points:
|
||||||
time_weight = self.calculate_time_weight(point[2], current_time)
|
time_weight = self.calculate_time_weight(point[2], current_time)
|
||||||
final_weight = point[1] * time_weight
|
final_weight = point[1] * time_weight
|
||||||
weighted_points.append((point, final_weight))
|
weighted_points.append((point, final_weight))
|
||||||
@@ -270,16 +235,15 @@ class RelationshipManager:
|
|||||||
idx_to_remove = random.randrange(len(remaining_points))
|
idx_to_remove = random.randrange(len(remaining_points))
|
||||||
remaining_points[idx_to_remove] = point
|
remaining_points[idx_to_remove] = point
|
||||||
|
|
||||||
return remaining_points
|
person.points = remaining_points
|
||||||
return current_points
|
return person
|
||||||
|
|
||||||
async def get_attitude_to_me(self, person_name, nickname, readable_messages, timestamp, current_attitude):
|
async def get_attitude_to_me(self, person_name, nickname, readable_messages, timestamp, person: Person):
|
||||||
alias_str = ", ".join(global_config.bot.alias_names)
|
alias_str = ", ".join(global_config.bot.alias_names)
|
||||||
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
# 解析当前态度值
|
# 解析当前态度值
|
||||||
attitude_parts = current_attitude.split(',')
|
current_attitude_score = person.attitude_to_me
|
||||||
current_attitude_score = float(attitude_parts[0]) if len(attitude_parts) > 0 else 0.0
|
total_confidence = person.attitude_to_me_confidence
|
||||||
total_confidence = float(attitude_parts[1]) if len(attitude_parts) > 1 else 1.0
|
|
||||||
|
|
||||||
prompt = await global_prompt_manager.format_prompt(
|
prompt = await global_prompt_manager.format_prompt(
|
||||||
"attitude_to_me_prompt",
|
"attitude_to_me_prompt",
|
||||||
@@ -301,23 +265,31 @@ class RelationshipManager:
|
|||||||
attitude = repair_json(attitude)
|
attitude = repair_json(attitude)
|
||||||
attitude_data = json.loads(attitude)
|
attitude_data = json.loads(attitude)
|
||||||
|
|
||||||
|
if attitude_data == "none" or not attitude_data or (isinstance(attitude_data, str) and attitude_data.lower() == "none") or (isinstance(attitude_data, list) and len(attitude_data) == 0):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# 确保 attitude_data 是字典格式
|
||||||
|
if not isinstance(attitude_data, dict):
|
||||||
|
logger.warning(f"LLM返回了错误的JSON格式,跳过解析: {type(attitude_data)}, 内容: {attitude_data}")
|
||||||
|
return ""
|
||||||
|
|
||||||
attitude_score = attitude_data["attitude"]
|
attitude_score = attitude_data["attitude"]
|
||||||
confidence = attitude_data["confidence"]
|
confidence = attitude_data["confidence"]
|
||||||
|
|
||||||
new_confidence = total_confidence + confidence
|
new_confidence = total_confidence + confidence
|
||||||
|
|
||||||
new_attitude_score = (current_attitude_score * total_confidence + attitude_score * confidence)/new_confidence
|
new_attitude_score = (current_attitude_score * total_confidence + attitude_score * confidence)/new_confidence
|
||||||
|
|
||||||
|
person.attitude_to_me = new_attitude_score
|
||||||
|
person.attitude_to_me_confidence = new_confidence
|
||||||
|
|
||||||
return f"{new_attitude_score:.3f},{new_confidence:.3f}"
|
return person
|
||||||
|
|
||||||
async def get_neuroticism(self, person_name, nickname, readable_messages, timestamp, current_neuroticism):
|
async def get_neuroticism(self, person_name, nickname, readable_messages, timestamp, person: Person):
|
||||||
alias_str = ", ".join(global_config.bot.alias_names)
|
alias_str = ", ".join(global_config.bot.alias_names)
|
||||||
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
# 解析当前态度值
|
# 解析当前态度值
|
||||||
neuroticism_parts = current_neuroticism.split(',')
|
current_neuroticism_score = person.neuroticism
|
||||||
current_neuroticism_score = float(neuroticism_parts[0]) if len(neuroticism_parts) > 0 else 0.0
|
total_confidence = person.neuroticism_confidence
|
||||||
total_confidence = float(neuroticism_parts[1]) if len(neuroticism_parts) > 1 else 1.0
|
|
||||||
|
|
||||||
prompt = await global_prompt_manager.format_prompt(
|
prompt = await global_prompt_manager.format_prompt(
|
||||||
"neuroticism_prompt",
|
"neuroticism_prompt",
|
||||||
@@ -339,6 +311,14 @@ class RelationshipManager:
|
|||||||
neuroticism = repair_json(neuroticism)
|
neuroticism = repair_json(neuroticism)
|
||||||
neuroticism_data = json.loads(neuroticism)
|
neuroticism_data = json.loads(neuroticism)
|
||||||
|
|
||||||
|
if neuroticism_data == "none" or not neuroticism_data or (isinstance(neuroticism_data, str) and neuroticism_data.lower() == "none") or (isinstance(neuroticism_data, list) and len(neuroticism_data) == 0):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# 确保 neuroticism_data 是字典格式
|
||||||
|
if not isinstance(neuroticism_data, dict):
|
||||||
|
logger.warning(f"LLM返回了错误的JSON格式,跳过解析: {type(neuroticism_data)}, 内容: {neuroticism_data}")
|
||||||
|
return ""
|
||||||
|
|
||||||
neuroticism_score = neuroticism_data["neuroticism"]
|
neuroticism_score = neuroticism_data["neuroticism"]
|
||||||
confidence = neuroticism_data["confidence"]
|
confidence = neuroticism_data["confidence"]
|
||||||
|
|
||||||
@@ -346,8 +326,10 @@ class RelationshipManager:
|
|||||||
|
|
||||||
new_neuroticism_score = (current_neuroticism_score * total_confidence + neuroticism_score * confidence)/new_confidence
|
new_neuroticism_score = (current_neuroticism_score * total_confidence + neuroticism_score * confidence)/new_confidence
|
||||||
|
|
||||||
|
person.neuroticism = new_neuroticism_score
|
||||||
|
person.neuroticism_confidence = new_confidence
|
||||||
|
|
||||||
return f"{new_neuroticism_score:.3f},{new_confidence:.3f}"
|
return person
|
||||||
|
|
||||||
|
|
||||||
async def update_person_impression(self, person_id, timestamp, bot_engaged_messages: List[Dict[str, Any]]):
|
async def update_person_impression(self, person_id, timestamp, bot_engaged_messages: List[Dict[str, Any]]):
|
||||||
@@ -360,21 +342,13 @@ class RelationshipManager:
|
|||||||
timestamp: 时间戳 (用于记录交互时间)
|
timestamp: 时间戳 (用于记录交互时间)
|
||||||
bot_engaged_messages: bot参与的消息列表
|
bot_engaged_messages: bot参与的消息列表
|
||||||
"""
|
"""
|
||||||
person_info_manager = get_person_info_manager()
|
person = Person(person_id=person_id)
|
||||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
person_name = person.person_name
|
||||||
nickname = await person_info_manager.get_value(person_id, "nickname")
|
nickname = person.nickname
|
||||||
know_times: float = await person_info_manager.get_value(person_id, "know_times") or 0 # type: ignore
|
know_times: float = person.know_times
|
||||||
current_points = await person_info_manager.get_value(person_id, "points") or []
|
|
||||||
attitude_to_me = await person_info_manager.get_value(person_id, "attitude_to_me") or "0,1"
|
|
||||||
neuroticism = await person_info_manager.get_value(person_id, "neuroticism") or "5,1"
|
|
||||||
|
|
||||||
# personality_block =get_individuality().get_personality_prompt(x_person=2, level=2)
|
|
||||||
# identity_block =get_individuality().get_identity_prompt(x_person=2, level=2)
|
|
||||||
|
|
||||||
user_messages = bot_engaged_messages
|
user_messages = bot_engaged_messages
|
||||||
|
|
||||||
current_time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
|
|
||||||
# 匿名化消息
|
# 匿名化消息
|
||||||
# 创建用户名称映射
|
# 创建用户名称映射
|
||||||
name_mapping = {}
|
name_mapping = {}
|
||||||
@@ -383,33 +357,23 @@ class RelationshipManager:
|
|||||||
|
|
||||||
# 遍历消息,构建映射
|
# 遍历消息,构建映射
|
||||||
for msg in user_messages:
|
for msg in user_messages:
|
||||||
await person_info_manager.get_or_create_person(
|
msg_person = Person(user_id=msg.get("user_id"), platform=msg.get("chat_info_platform"))
|
||||||
platform=msg.get("chat_info_platform"), # type: ignore
|
|
||||||
user_id=msg.get("user_id"), # type: ignore
|
|
||||||
nickname=msg.get("user_nickname"), # type: ignore
|
|
||||||
user_cardname=msg.get("user_cardname"), # type: ignore
|
|
||||||
)
|
|
||||||
replace_user_id: str = msg.get("user_id") # type: ignore
|
|
||||||
replace_platform: str = msg.get("chat_info_platform") # type: ignore
|
|
||||||
replace_person_id = PersonInfoManager.get_person_id(replace_platform, replace_user_id)
|
|
||||||
replace_person_name = await person_info_manager.get_value(replace_person_id, "person_name")
|
|
||||||
|
|
||||||
# 跳过机器人自己
|
# 跳过机器人自己
|
||||||
if replace_user_id == global_config.bot.qq_account:
|
if msg_person.user_id == global_config.bot.qq_account:
|
||||||
name_mapping[f"{global_config.bot.nickname}"] = f"{global_config.bot.nickname}"
|
name_mapping[f"{global_config.bot.nickname}"] = f"{global_config.bot.nickname}"
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 跳过目标用户
|
# 跳过目标用户
|
||||||
if replace_person_name == person_name:
|
if msg_person.person_name == person_name:
|
||||||
name_mapping[replace_person_name] = f"{person_name}"
|
name_mapping[msg_person.person_name] = f"{person_name}"
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 其他用户映射
|
# 其他用户映射
|
||||||
if replace_person_name not in name_mapping:
|
if msg_person.person_name not in name_mapping:
|
||||||
if current_user > "Z":
|
if current_user > "Z":
|
||||||
current_user = "A"
|
current_user = "A"
|
||||||
user_count += 1
|
user_count += 1
|
||||||
name_mapping[replace_person_name] = f"用户{current_user}{user_count if user_count > 1 else ''}"
|
name_mapping[msg_person.person_name] = f"用户{current_user}{user_count if user_count > 1 else ''}"
|
||||||
current_user = chr(ord(current_user) + 1)
|
current_user = chr(ord(current_user) + 1)
|
||||||
|
|
||||||
readable_messages = build_readable_messages(
|
readable_messages = build_readable_messages(
|
||||||
@@ -420,23 +384,16 @@ class RelationshipManager:
|
|||||||
# print(f"original_name: {original_name}, mapped_name: {mapped_name}")
|
# print(f"original_name: {original_name}, mapped_name: {mapped_name}")
|
||||||
readable_messages = readable_messages.replace(f"{original_name}", f"{mapped_name}")
|
readable_messages = readable_messages.replace(f"{original_name}", f"{mapped_name}")
|
||||||
|
|
||||||
|
print(name_mapping)
|
||||||
|
|
||||||
|
person = await self.get_points(person_name, nickname, readable_messages, name_mapping, timestamp, person)
|
||||||
|
person = await self.get_attitude_to_me(person_name, nickname, readable_messages, timestamp, person)
|
||||||
|
person = await self.get_neuroticism(person_name, nickname, readable_messages, timestamp, person)
|
||||||
|
|
||||||
remaining_points = await self.get_points(person_name, nickname, readable_messages, name_mapping, timestamp, current_points)
|
person.know_times = know_times + 1
|
||||||
attitude_to_me = await self.get_attitude_to_me(person_name, nickname, readable_messages, timestamp, attitude_to_me)
|
person.last_know = timestamp
|
||||||
neuroticism = await self.get_neuroticism(person_name, nickname, readable_messages, timestamp, neuroticism)
|
|
||||||
|
|
||||||
# 更新数据库
|
person.sync_to_database()
|
||||||
await person_info_manager.update_one_field(
|
|
||||||
person_id, "points", json.dumps(remaining_points, ensure_ascii=False, indent=None)
|
|
||||||
)
|
|
||||||
await person_info_manager.update_one_field(person_id, "neuroticism", neuroticism)
|
|
||||||
await person_info_manager.update_one_field(person_id, "attitude_to_me", attitude_to_me)
|
|
||||||
await person_info_manager.update_one_field(person_id, "know_times", know_times + 1)
|
|
||||||
await person_info_manager.update_one_field(person_id, "last_know", timestamp)
|
|
||||||
know_since = await person_info_manager.get_value(person_id, "know_since") or 0
|
|
||||||
if know_since == 0:
|
|
||||||
await person_info_manager.update_one_field(person_id, "know_since", timestamp)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import traceback
|
|||||||
from typing import Tuple, Any, Dict, List, Optional
|
from typing import Tuple, Any, Dict, List, Optional
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.config.api_ada_configs import TaskConfig
|
|
||||||
from src.chat.replyer.default_generator import DefaultReplyer
|
from src.chat.replyer.default_generator import DefaultReplyer
|
||||||
from src.chat.message_receive.chat_stream import ChatStream
|
from src.chat.message_receive.chat_stream import ChatStream
|
||||||
from src.chat.utils.utils import process_llm_response
|
from src.chat.utils.utils import process_llm_response
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
value = await person_api.get_person_value(person_id, "nickname")
|
value = await person_api.get_person_value(person_id, "nickname")
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Any, Optional
|
from typing import Any
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.person_info.person_info import get_person_info_manager, PersonInfoManager
|
from src.person_info.person_info import Person
|
||||||
|
|
||||||
logger = get_logger("person_api")
|
logger = get_logger("person_api")
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ def get_person_id(platform: str, user_id: int) -> str:
|
|||||||
person_id = person_api.get_person_id("qq", 123456)
|
person_id = person_api.get_person_id("qq", 123456)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return PersonInfoManager.get_person_id(platform, user_id)
|
return Person(platform=platform, user_id=user_id).person_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[PersonAPI] 获取person_id失败: platform={platform}, user_id={user_id}, error={e}")
|
logger.error(f"[PersonAPI] 获取person_id失败: platform={platform}, user_id={user_id}, error={e}")
|
||||||
return ""
|
return ""
|
||||||
@@ -55,85 +55,14 @@ async def get_person_value(person_id: str, field_name: str, default: Any = None)
|
|||||||
impression = await person_api.get_person_value(person_id, "impression")
|
impression = await person_api.get_person_value(person_id, "impression")
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
person_info_manager = get_person_info_manager()
|
person = Person(person_id=person_id)
|
||||||
value = await person_info_manager.get_value(person_id, field_name)
|
value = getattr(person, field_name)
|
||||||
return value if value is not None else default
|
return value if value is not None else default
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[PersonAPI] 获取用户信息失败: person_id={person_id}, field={field_name}, error={e}")
|
logger.error(f"[PersonAPI] 获取用户信息失败: person_id={person_id}, field={field_name}, error={e}")
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
async def get_person_values(person_id: str, field_names: list, default_dict: Optional[dict] = None) -> dict:
|
|
||||||
"""批量获取用户信息字段值
|
|
||||||
|
|
||||||
Args:
|
|
||||||
person_id: 用户的唯一标识ID
|
|
||||||
field_names: 要获取的字段名列表
|
|
||||||
default_dict: 默认值字典,键为字段名,值为默认值
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: 字段名到值的映射字典
|
|
||||||
|
|
||||||
示例:
|
|
||||||
values = await person_api.get_person_values(
|
|
||||||
person_id,
|
|
||||||
["nickname", "impression", "know_times"],
|
|
||||||
{"nickname": "未知用户", "know_times": 0}
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
values = await person_info_manager.get_values(person_id, field_names)
|
|
||||||
|
|
||||||
# 如果获取成功,返回结果
|
|
||||||
if values:
|
|
||||||
return values
|
|
||||||
|
|
||||||
# 如果获取失败,构建默认值字典
|
|
||||||
result = {}
|
|
||||||
if default_dict:
|
|
||||||
for field in field_names:
|
|
||||||
result[field] = default_dict.get(field, None)
|
|
||||||
else:
|
|
||||||
for field in field_names:
|
|
||||||
result[field] = None
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[PersonAPI] 批量获取用户信息失败: person_id={person_id}, fields={field_names}, error={e}")
|
|
||||||
# 返回默认值字典
|
|
||||||
result = {}
|
|
||||||
if default_dict:
|
|
||||||
for field in field_names:
|
|
||||||
result[field] = default_dict.get(field, None)
|
|
||||||
else:
|
|
||||||
for field in field_names:
|
|
||||||
result[field] = None
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
async def is_person_known(platform: str, user_id: int) -> bool:
|
|
||||||
"""判断是否认识某个用户
|
|
||||||
|
|
||||||
Args:
|
|
||||||
platform: 平台名称
|
|
||||||
user_id: 用户ID
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: 是否认识该用户
|
|
||||||
|
|
||||||
示例:
|
|
||||||
known = await person_api.is_person_known("qq", 123456)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
person_info_manager = get_person_info_manager()
|
|
||||||
return await person_info_manager.is_person_known(platform, user_id)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[PersonAPI] 检查用户是否已知失败: platform={platform}, user_id={user_id}, error={e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_person_id_by_name(person_name: str) -> str:
|
def get_person_id_by_name(person_name: str) -> str:
|
||||||
"""根据用户名获取person_id
|
"""根据用户名获取person_id
|
||||||
|
|
||||||
@@ -147,8 +76,8 @@ def get_person_id_by_name(person_name: str) -> str:
|
|||||||
person_id = person_api.get_person_id_by_name("张三")
|
person_id = person_api.get_person_id_by_name("张三")
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
person_info_manager = get_person_info_manager()
|
person = Person(person_name=person_name)
|
||||||
return person_info_manager.get_person_id_by_person_name(person_name)
|
return person.person_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[PersonAPI] 根据用户名获取person_id失败: person_name={person_name}, error={e}")
|
logger.error(f"[PersonAPI] 根据用户名获取person_id失败: person_name={person_name}, error={e}")
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user