🤖 自动格式化代码 [skip ci]

This commit is contained in:
github-actions[bot]
2025-06-20 11:20:41 +00:00
parent 7dafbff036
commit 865645e02d
5 changed files with 132 additions and 137 deletions

View File

@@ -536,14 +536,16 @@ class RelationshipProcessor(BaseProcessor):
# 对于每个(person_id, info_type)组合,只保留最新的记录 # 对于每个(person_id, info_type)组合,只保留最新的记录
latest_records = {} latest_records = {}
for info_fetching in self.info_fetching_cache: for info_fetching in self.info_fetching_cache:
key = (info_fetching['person_id'], info_fetching['info_type']) 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']: if key not in latest_records or info_fetching["start_time"] > latest_records[key]["start_time"]:
latest_records[key] = info_fetching latest_records[key] = info_fetching
# 按时间排序并生成显示文本 # 按时间排序并生成显示文本
sorted_records = sorted(latest_records.values(), key=lambda x: x['start_time']) sorted_records = sorted(latest_records.values(), key=lambda x: x["start_time"])
for info_fetching in sorted_records: for info_fetching in sorted_records:
info_cache_block += f"你已经调取了[{info_fetching['person_name']}]的[{info_fetching['info_type']}]信息\n" info_cache_block += (
f"你已经调取了[{info_fetching['person_name']}]的[{info_fetching['info_type']}]信息\n"
)
prompt = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format( prompt = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format(
name_block=name_block, name_block=name_block,
@@ -569,13 +571,13 @@ class RelationshipProcessor(BaseProcessor):
if not person_id: if not person_id:
logger.warning(f"{self.log_prefix} 未找到用户 {person_name} 的ID跳过调取信息。") logger.warning(f"{self.log_prefix} 未找到用户 {person_name} 的ID跳过调取信息。")
continue continue
# 检查是否是bot自己如果是则跳过 # 检查是否是bot自己如果是则跳过
user_id = person_info_manager.get_value_sync(person_id, "user_id") user_id = person_info_manager.get_value_sync(person_id, "user_id")
if user_id == global_config.bot.qq_account: if user_id == global_config.bot.qq_account:
logger.info(f"{self.log_prefix} 跳过调取bot自己({person_name})的信息。") logger.info(f"{self.log_prefix} 跳过调取bot自己({person_name})的信息。")
continue continue
self.info_fetching_cache.append( self.info_fetching_cache.append(
{ {
"person_id": person_id, "person_id": person_id,
@@ -625,7 +627,6 @@ class RelationshipProcessor(BaseProcessor):
if person_infos_str: if person_infos_str:
persons_infos_str += f"你对 {person_name} 的了解:{person_infos_str}\n" persons_infos_str += f"你对 {person_name} 的了解:{person_infos_str}\n"
return persons_infos_str return persons_infos_str
# ================================ # ================================
@@ -733,32 +734,31 @@ class RelationshipProcessor(BaseProcessor):
使用小模型提取单个信息类型 使用小模型提取单个信息类型
""" """
person_info_manager = get_person_info_manager() person_info_manager = get_person_info_manager()
# 首先检查 info_list 缓存 # 首先检查 info_list 缓存
info_list = await person_info_manager.get_value(person_id, "info_list") or [] info_list = await person_info_manager.get_value(person_id, "info_list") or []
cached_info = None cached_info = None
print(f"info_list: {info_list}") print(f"info_list: {info_list}")
# 查找对应的 info_type # 查找对应的 info_type
for info_item in info_list: for info_item in info_list:
if info_item.get("info_type") == info_type: if info_item.get("info_type") == info_type:
cached_info = info_item.get("info_content") cached_info = info_item.get("info_content")
logger.info(f"{self.log_prefix} [缓存命中] 从 info_list 中找到 {info_type} 信息: {cached_info}") logger.info(f"{self.log_prefix} [缓存命中] 从 info_list 中找到 {info_type} 信息: {cached_info}")
break break
# 如果缓存中有信息,直接使用 # 如果缓存中有信息,直接使用
if cached_info : if cached_info:
person_name = await person_info_manager.get_value(person_id, "person_name") person_name = await person_info_manager.get_value(person_id, "person_name")
if person_id not in self.info_fetched_cache: if person_id not in self.info_fetched_cache:
self.info_fetched_cache[person_id] = {} self.info_fetched_cache[person_id] = {}
if cached_info == "none": if cached_info == "none":
unknow = True unknow = True
else: else:
unknow = False unknow = False
self.info_fetched_cache[person_id][info_type] = { self.info_fetched_cache[person_id][info_type] = {
"info": cached_info, "info": cached_info,
"ttl": 8, "ttl": 8,
@@ -768,26 +768,28 @@ class RelationshipProcessor(BaseProcessor):
} }
logger.info(f"{self.log_prefix} [缓存使用] 直接使用缓存的 {person_name}{info_type}: {cached_info}") logger.info(f"{self.log_prefix} [缓存使用] 直接使用缓存的 {person_name}{info_type}: {cached_info}")
return return
logger.info(f"{self.log_prefix} [缓存命中] 缓存中没有信息") logger.info(f"{self.log_prefix} [缓存命中] 缓存中没有信息")
try: try:
nickname_str = ",".join(global_config.bot.alias_names) nickname_str = ",".join(global_config.bot.alias_names)
name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
person_name = await person_info_manager.get_value(person_id, "person_name") person_name = await person_info_manager.get_value(person_id, "person_name")
person_impression = await person_info_manager.get_value(person_id, "impression") person_impression = await person_info_manager.get_value(person_id, "impression")
if person_impression: if person_impression:
person_impression_block = f"<对{person_name}的总体了解>\n{person_impression}\n</对{person_name}的总体了解>" person_impression_block = (
f"<对{person_name}的总体了解>\n{person_impression}\n</对{person_name}的总体了解>"
)
else: else:
person_impression_block = "" person_impression_block = ""
points = await person_info_manager.get_value(person_id, "points") points = await person_info_manager.get_value(person_id, "points")
if points: if points:
points_text = "\n".join([f"{point[2]}:{point[0]}" for point in 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}的近期了解>" points_text_block = f"<对{person_name}的近期了解>\n{points_text}\n</对{person_name}的近期了解>"
else: else:
points_text_block = "" points_text_block = ""
if not points_text_block and not person_impression_block: if not points_text_block and not person_impression_block:
if person_id not in self.info_fetched_cache: if person_id not in self.info_fetched_cache:
self.info_fetched_cache[person_id] = {} self.info_fetched_cache[person_id] = {}
@@ -799,7 +801,7 @@ class RelationshipProcessor(BaseProcessor):
"unknow": True, "unknow": True,
} }
return return
prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format( prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format(
name_block=name_block, name_block=name_block,
info_type=info_type, info_type=info_type,
@@ -810,7 +812,7 @@ class RelationshipProcessor(BaseProcessor):
) )
except Exception: except Exception:
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
print(prompt) print(prompt)
try: try:
@@ -824,7 +826,7 @@ class RelationshipProcessor(BaseProcessor):
if info_type in content_json: if info_type in content_json:
info_content = content_json[info_type] info_content = content_json[info_type]
is_unknown = info_content == "none" or not info_content is_unknown = info_content == "none" or not info_content
# 保存到运行时缓存 # 保存到运行时缓存
if person_id not in self.info_fetched_cache: if person_id not in self.info_fetched_cache:
self.info_fetched_cache[person_id] = {} self.info_fetched_cache[person_id] = {}
@@ -835,16 +837,20 @@ class RelationshipProcessor(BaseProcessor):
"person_name": person_name, "person_name": person_name,
"unknow": is_unknown, "unknow": is_unknown,
} }
# 保存到持久化缓存 (info_list) # 保存到持久化缓存 (info_list)
await self._save_info_to_cache(person_id, info_type, info_content if not is_unknown else "none") await self._save_info_to_cache(person_id, info_type, info_content if not is_unknown else "none")
if not is_unknown: if not is_unknown:
logger.info(f"{self.log_prefix} [LLM提取] 成功获取并缓存 {person_name}{info_type}: {info_content}") logger.info(
f"{self.log_prefix} [LLM提取] 成功获取并缓存 {person_name}{info_type}: {info_content}"
)
else: else:
logger.info(f"{self.log_prefix} [LLM提取] {person_name}{info_type} 信息不明确") logger.info(f"{self.log_prefix} [LLM提取] {person_name}{info_type} 信息不明确")
else: else:
logger.warning(f"{self.log_prefix} [LLM提取] 小模型返回空结果,获取 {person_name}{info_type} 信息失败。") logger.warning(
f"{self.log_prefix} [LLM提取] 小模型返回空结果,获取 {person_name}{info_type} 信息失败。"
)
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} [LLM提取] 执行小模型请求获取用户信息时出错: {e}") logger.error(f"{self.log_prefix} [LLM提取] 执行小模型请求获取用户信息时出错: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
@@ -852,7 +858,7 @@ class RelationshipProcessor(BaseProcessor):
async def _save_info_to_cache(self, person_id: str, info_type: str, info_content: str): async def _save_info_to_cache(self, person_id: str, info_type: str, info_content: str):
""" """
将提取到的信息保存到 person_info 的 info_list 字段中 将提取到的信息保存到 person_info 的 info_list 字段中
Args: Args:
person_id: 用户ID person_id: 用户ID
info_type: 信息类型 info_type: 信息类型
@@ -860,23 +866,23 @@ class RelationshipProcessor(BaseProcessor):
""" """
try: try:
person_info_manager = get_person_info_manager() person_info_manager = get_person_info_manager()
# 获取现有的 info_list # 获取现有的 info_list
info_list = await person_info_manager.get_value(person_id, "info_list") or [] info_list = await person_info_manager.get_value(person_id, "info_list") or []
# 查找是否已存在相同 info_type 的记录 # 查找是否已存在相同 info_type 的记录
found_index = -1 found_index = -1
for i, info_item in enumerate(info_list): for i, info_item in enumerate(info_list):
if isinstance(info_item, dict) and info_item.get("info_type") == info_type: if isinstance(info_item, dict) and info_item.get("info_type") == info_type:
found_index = i found_index = i
break break
# 创建新的信息记录 # 创建新的信息记录
new_info_item = { new_info_item = {
"info_type": info_type, "info_type": info_type,
"info_content": info_content, "info_content": info_content,
} }
if found_index >= 0: if found_index >= 0:
# 更新现有记录 # 更新现有记录
info_list[found_index] = new_info_item info_list[found_index] = new_info_item
@@ -885,14 +891,13 @@ class RelationshipProcessor(BaseProcessor):
# 添加新记录 # 添加新记录
info_list.append(new_info_item) info_list.append(new_info_item)
logger.info(f"{self.log_prefix} [缓存保存] 新增 {person_id}{info_type} 信息缓存") logger.info(f"{self.log_prefix} [缓存保存] 新增 {person_id}{info_type} 信息缓存")
# 保存更新后的 info_list # 保存更新后的 info_list
await person_info_manager.update_one_field(person_id, "info_list", info_list) await person_info_manager.update_one_field(person_id, "info_list", info_list)
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} [缓存保存] 保存信息到缓存失败: {e}") logger.error(f"{self.log_prefix} [缓存保存] 保存信息到缓存失败: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
init_prompt() init_prompt()

View File

@@ -18,7 +18,6 @@ logger = get_logger("processor")
def init_prompt(): def init_prompt():
indentify_prompt = """ indentify_prompt = """
{time_now},以下是正在进行的聊天内容: {time_now},以下是正在进行的聊天内容:
<聊天记录> <聊天记录>
@@ -46,7 +45,7 @@ class SelfProcessor(BaseProcessor):
super().__init__() super().__init__()
self.subheartflow_id = subheartflow_id self.subheartflow_id = subheartflow_id
self.info_fetched_cache: Dict[str, Dict[str, any]] = {} self.info_fetched_cache: Dict[str, Dict[str, any]] = {}
self.llm_model = LLMRequest( self.llm_model = LLMRequest(
@@ -57,8 +56,6 @@ class SelfProcessor(BaseProcessor):
name = get_chat_manager().get_stream_name(self.subheartflow_id) name = get_chat_manager().get_stream_name(self.subheartflow_id)
self.log_prefix = f"[{name}] " self.log_prefix = f"[{name}] "
async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]: async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]:
"""处理信息对象 """处理信息对象
@@ -123,22 +120,22 @@ class SelfProcessor(BaseProcessor):
individuality = get_individuality() individuality = get_individuality()
available_keywords = individuality.get_all_keywords() available_keywords = individuality.get_all_keywords()
available_keywords_str = "".join(available_keywords) if available_keywords else "暂无关键词" available_keywords_str = "".join(available_keywords) if available_keywords else "暂无关键词"
prompt = (await global_prompt_manager.get_prompt_async("indentify_prompt")).format( prompt = (await global_prompt_manager.get_prompt_async("indentify_prompt")).format(
name_block=name_block, name_block=name_block,
time_now=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), time_now=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
chat_observe_info=chat_observe_info[-200:], chat_observe_info=chat_observe_info[-200:],
available_keywords=available_keywords_str, available_keywords=available_keywords_str,
bot_name = global_config.bot.nickname bot_name=global_config.bot.nickname,
) )
keyword = "" keyword = ""
try: try:
keyword, _ = await self.llm_model.generate_response_async(prompt=prompt) keyword, _ = await self.llm_model.generate_response_async(prompt=prompt)
print(f"prompt: {prompt}\nkeyword: {keyword}") print(f"prompt: {prompt}\nkeyword: {keyword}")
if not keyword: if not keyword:
logger.warning(f"{self.log_prefix} LLM返回空结果自我识别失败。") logger.warning(f"{self.log_prefix} LLM返回空结果自我识别失败。")
except Exception as e: except Exception as e:
@@ -146,7 +143,6 @@ class SelfProcessor(BaseProcessor):
logger.error(f"{self.log_prefix} 执行LLM请求或处理响应时出错: {e}") logger.error(f"{self.log_prefix} 执行LLM请求或处理响应时出错: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
keyword = "我是谁,我从哪来,要到哪去" keyword = "我是谁,我从哪来,要到哪去"
# 解析关键词 # 解析关键词
keyword = keyword.strip() keyword = keyword.strip()
@@ -155,20 +151,20 @@ class SelfProcessor(BaseProcessor):
else: else:
# 只保留非空关键词,去除多余空格 # 只保留非空关键词,去除多余空格
keyword_set = [k.strip() for k in keyword.split(",") if k.strip()] keyword_set = [k.strip() for k in keyword.split(",") if k.strip()]
# 从individuality缓存中查询关键词信息 # 从individuality缓存中查询关键词信息
for keyword in keyword_set: for keyword in keyword_set:
if keyword not in self.info_fetched_cache: if keyword not in self.info_fetched_cache:
# 直接从individuality的json缓存中获取关键词信息 # 直接从individuality的json缓存中获取关键词信息
fetched_info = individuality.get_keyword_info(keyword) fetched_info = individuality.get_keyword_info(keyword)
if fetched_info: if fetched_info:
self.info_fetched_cache[keyword] = { self.info_fetched_cache[keyword] = {
"info": fetched_info, "info": fetched_info,
"ttl": 5, "ttl": 5,
} }
logger.info(f"{self.log_prefix} 从个体特征缓存中获取关键词 '{keyword}' 的信息") logger.info(f"{self.log_prefix} 从个体特征缓存中获取关键词 '{keyword}' 的信息")
# 管理TTL生存时间 # 管理TTL生存时间
expired_keywords = [] expired_keywords = []
for fetched_keyword, info in self.info_fetched_cache.items(): for fetched_keyword, info in self.info_fetched_cache.items():
@@ -176,18 +172,16 @@ class SelfProcessor(BaseProcessor):
info["ttl"] -= 1 info["ttl"] -= 1
else: else:
expired_keywords.append(fetched_keyword) expired_keywords.append(fetched_keyword)
# 删除过期的关键词 # 删除过期的关键词
for expired_keyword in expired_keywords: for expired_keyword in expired_keywords:
del self.info_fetched_cache[expired_keyword] del self.info_fetched_cache[expired_keyword]
fetched_info_str = "" fetched_info_str = ""
for keyword, info in self.info_fetched_cache.items(): for keyword, info in self.info_fetched_cache.items():
fetched_info_str += f"你的:{keyword}信息是: {info['info']}\n" fetched_info_str += f"你的:{keyword}信息是: {info['info']}\n"
return fetched_info_str return fetched_info_str
init_prompt() init_prompt()

View File

@@ -342,11 +342,8 @@ class ActionPlanner(BasePlanner):
else: else:
chat_content_block = "你还未开始聊天" chat_content_block = "你还未开始聊天"
action_options_block = "" action_options_block = ""
for using_actions_name, using_actions_info in current_available_actions.items(): for using_actions_name, using_actions_info in current_available_actions.items():
using_action_prompt = await global_prompt_manager.get_prompt_async("action_prompt") using_action_prompt = await global_prompt_manager.get_prompt_async("action_prompt")
if using_actions_info["parameters"]: if using_actions_info["parameters"]:
@@ -383,7 +380,7 @@ class ActionPlanner(BasePlanner):
# 获取当前时间 # 获取当前时间
time_block = f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" time_block = f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
bot_name = global_config.bot.nickname bot_name = global_config.bot.nickname
if global_config.bot.alias_names: if global_config.bot.alias_names:
bot_nickname = f",也有人叫你{','.join(global_config.bot.alias_names)}" bot_nickname = f",也有人叫你{','.join(global_config.bot.alias_names)}"

View File

@@ -7,7 +7,6 @@ import json
import os import os
import hashlib import hashlib
import traceback import traceback
import time
from rich.traceback import install from rich.traceback import install
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
from src.manager.async_task_manager import AsyncTask from src.manager.async_task_manager import AsyncTask
@@ -19,11 +18,10 @@ install(extra_lines=3)
logger = get_logger("individuality") logger = get_logger("individuality")
def init_prompt(): def init_prompt():
"""初始化用于关键词提取的prompts""" """初始化用于关键词提取的prompts"""
extract_keywords_prompt = """ extract_keywords_prompt = """
请分析以下对某人的描述,提取出其中的独立关键词。每个关键词应该是可以用来从某一角度概括的方面:性格,身高,喜好,外貌,身份,兴趣,爱好,习惯,等等。 请分析以下对某人的描述,提取出其中的独立关键词。每个关键词应该是可以用来从某一角度概括的方面:性格,身高,喜好,外貌,身份,兴趣,爱好,习惯,等等。
@@ -38,7 +36,7 @@ def init_prompt():
请输出关键词: 请输出关键词:
""" """
Prompt(extract_keywords_prompt, "extract_keywords_prompt") Prompt(extract_keywords_prompt, "extract_keywords_prompt")
fetch_info_prompt = """ fetch_info_prompt = """
{name_block},你的性格的特征是: {name_block},你的性格的特征是:
{prompt_personality} {prompt_personality}
@@ -49,7 +47,6 @@ def init_prompt():
Prompt(fetch_info_prompt, "fetch_info_prompt") Prompt(fetch_info_prompt, "fetch_info_prompt")
class Individuality: class Individuality:
"""个体特征管理类""" """个体特征管理类"""
@@ -60,7 +57,7 @@ class Individuality:
self.express_style: PersonalityExpression = PersonalityExpression() self.express_style: PersonalityExpression = PersonalityExpression()
self.name = "" self.name = ""
# 关键词缓存相关 # 关键词缓存相关
self.keyword_info_cache: dict = {} # {keyword: [info_list]} self.keyword_info_cache: dict = {} # {keyword: [info_list]}
self.fetch_info_file_path = "data/personality/fetch_info.json" self.fetch_info_file_path = "data/personality/fetch_info.json"
@@ -92,7 +89,7 @@ class Individuality:
await self.express_style.extract_and_store_personality_expressions() await self.express_style.extract_and_store_personality_expressions()
self.name = bot_nickname self.name = bot_nickname
# 预处理关键词和生成信息缓存 # 预处理关键词和生成信息缓存
await self._preprocess_personality_keywords(personality_sides, identity_detail) await self._preprocess_personality_keywords(personality_sides, identity_detail)
@@ -265,18 +262,17 @@ class Individuality:
def _get_config_hash(self, personality_sides: list, identity_detail: list) -> str: def _get_config_hash(self, personality_sides: list, identity_detail: list) -> str:
"""获取当前personality和identity配置的哈希值""" """获取当前personality和identity配置的哈希值"""
# 将配置转换为字符串并排序,确保一致性 # 将配置转换为字符串并排序,确保一致性
config_str = json.dumps({ config_str = json.dumps(
"personality_sides": sorted(personality_sides), {"personality_sides": sorted(personality_sides), "identity_detail": sorted(identity_detail)}, sort_keys=True
"identity_detail": sorted(identity_detail) )
}, sort_keys=True)
return hashlib.md5(config_str.encode("utf-8")).hexdigest()
return hashlib.md5(config_str.encode('utf-8')).hexdigest()
def _load_meta_info(self) -> dict: def _load_meta_info(self) -> dict:
"""从JSON文件中加载元信息""" """从JSON文件中加载元信息"""
if os.path.exists(self.meta_info_file_path): if os.path.exists(self.meta_info_file_path):
try: try:
with open(self.meta_info_file_path, 'r', encoding='utf-8') as f: with open(self.meta_info_file_path, "r", encoding="utf-8") as f:
return json.load(f) return json.load(f)
except Exception as e: except Exception as e:
print(f"读取meta_info文件失败: {e}") print(f"读取meta_info文件失败: {e}")
@@ -288,7 +284,7 @@ class Individuality:
try: try:
# 确保目录存在 # 确保目录存在
os.makedirs(os.path.dirname(self.meta_info_file_path), exist_ok=True) os.makedirs(os.path.dirname(self.meta_info_file_path), exist_ok=True)
with open(self.meta_info_file_path, 'w', encoding='utf-8') as f: with open(self.meta_info_file_path, "w", encoding="utf-8") as f:
json.dump(meta_info, f, ensure_ascii=False, indent=2) json.dump(meta_info, f, ensure_ascii=False, indent=2)
except Exception as e: except Exception as e:
print(f"保存meta_info文件失败: {e}") print(f"保存meta_info文件失败: {e}")
@@ -297,30 +293,30 @@ class Individuality:
"""检查配置是否发生变化如果变化则清空fetch_info.json""" """检查配置是否发生变化如果变化则清空fetch_info.json"""
current_config_hash = self._get_config_hash(personality_sides, identity_detail) current_config_hash = self._get_config_hash(personality_sides, identity_detail)
meta_info = self._load_meta_info() meta_info = self._load_meta_info()
stored_config_hash = meta_info.get("config_hash", "") stored_config_hash = meta_info.get("config_hash", "")
if current_config_hash != stored_config_hash: if current_config_hash != stored_config_hash:
logger.info(f"检测到personality或identity配置发生变化清空fetch_info数据") logger.info("检测到personality或identity配置发生变化清空fetch_info数据")
# 清空fetch_info文件 # 清空fetch_info文件
if os.path.exists(self.fetch_info_file_path): if os.path.exists(self.fetch_info_file_path):
try: try:
os.remove(self.fetch_info_file_path) os.remove(self.fetch_info_file_path)
logger.info(f"已清空fetch_info文件") logger.info("已清空fetch_info文件")
except Exception as e: except Exception as e:
logger.error(f"清空fetch_info文件失败: {e}") logger.error(f"清空fetch_info文件失败: {e}")
# 更新元信息 # 更新元信息
meta_info["config_hash"] = current_config_hash meta_info["config_hash"] = current_config_hash
self._save_meta_info(meta_info) self._save_meta_info(meta_info)
logger.info(f"已更新配置哈希值") logger.info("已更新配置哈希值")
def _load_fetch_info_from_file(self) -> dict: def _load_fetch_info_from_file(self) -> dict:
"""从JSON文件中加载已保存的fetch_info数据""" """从JSON文件中加载已保存的fetch_info数据"""
if os.path.exists(self.fetch_info_file_path): if os.path.exists(self.fetch_info_file_path):
try: try:
with open(self.fetch_info_file_path, 'r', encoding='utf-8') as f: with open(self.fetch_info_file_path, "r", encoding="utf-8") as f:
data = json.load(f) data = json.load(f)
# 兼容旧格式:如果是字符串则转换为列表 # 兼容旧格式:如果是字符串则转换为列表
for keyword, value in data.items(): for keyword, value in data.items():
@@ -337,7 +333,7 @@ class Individuality:
try: try:
# 确保目录存在 # 确保目录存在
os.makedirs(os.path.dirname(self.fetch_info_file_path), exist_ok=True) os.makedirs(os.path.dirname(self.fetch_info_file_path), exist_ok=True)
with open(self.fetch_info_file_path, 'w', encoding='utf-8') as f: with open(self.fetch_info_file_path, "w", encoding="utf-8") as f:
json.dump(fetch_info_data, f, ensure_ascii=False, indent=2) json.dump(fetch_info_data, f, ensure_ascii=False, indent=2)
except Exception as e: except Exception as e:
logger.error(f"保存fetch_info文件失败: {e}") logger.error(f"保存fetch_info文件失败: {e}")
@@ -345,22 +341,21 @@ class Individuality:
async def _preprocess_personality_keywords(self, personality_sides: list, identity_detail: list): async def _preprocess_personality_keywords(self, personality_sides: list, identity_detail: list):
"""预处理personality关键词提取关键词并生成缓存""" """预处理personality关键词提取关键词并生成缓存"""
try: try:
logger.info("开始预处理personality关键词...") logger.info("开始预处理personality关键词...")
# 检查配置变化 # 检查配置变化
self._check_config_change_and_clear(personality_sides, identity_detail) self._check_config_change_and_clear(personality_sides, identity_detail)
# 加载已有的预处理数据(如果存在) # 加载已有的预处理数据(如果存在)
fetch_info_data = self._load_fetch_info_from_file() fetch_info_data = self._load_fetch_info_from_file()
logger.info(f"加载已有数据,现有关键词数量: {len(fetch_info_data)}") logger.info(f"加载已有数据,现有关键词数量: {len(fetch_info_data)}")
# 检查并清理错误分割的关键词(包含逗号的键) # 检查并清理错误分割的关键词(包含逗号的键)
keys_to_fix = [] keys_to_fix = []
for key in fetch_info_data.keys(): for key in fetch_info_data.keys():
if "," in key: if "," in key:
keys_to_fix.append(key) keys_to_fix.append(key)
if keys_to_fix: if keys_to_fix:
logger.info(f"发现 {len(keys_to_fix)} 个需要重新分割的关键词") logger.info(f"发现 {len(keys_to_fix)} 个需要重新分割的关键词")
for bad_key in keys_to_fix: for bad_key in keys_to_fix:
@@ -369,7 +364,7 @@ class Individuality:
info_list = fetch_info_data[bad_key] info_list = fetch_info_data[bad_key]
# 删除旧的错误键 # 删除旧的错误键
del fetch_info_data[bad_key] del fetch_info_data[bad_key]
# 按逗号分割并重新添加 # 按逗号分割并重新添加
split_keywords = [k.strip() for k in bad_key.split(",") if k.strip()] split_keywords = [k.strip() for k in bad_key.split(",") if k.strip()]
for split_keyword in split_keywords: for split_keyword in split_keywords:
@@ -380,64 +375,64 @@ class Individuality:
if info not in fetch_info_data[split_keyword]: if info not in fetch_info_data[split_keyword]:
fetch_info_data[split_keyword].append(info) fetch_info_data[split_keyword].append(info)
logger.info(f"已将信息分配给关键词: '{split_keyword}'") logger.info(f"已将信息分配给关键词: '{split_keyword}'")
# 保存清理后的数据 # 保存清理后的数据
self._save_fetch_info_to_file(fetch_info_data) self._save_fetch_info_to_file(fetch_info_data)
logger.info(f"清理完成,现在共有 {len(fetch_info_data)} 个关键词") logger.info(f"清理完成,现在共有 {len(fetch_info_data)} 个关键词")
# 构建完整描述personality + identity # 构建完整描述personality + identity
personality_sides_str = "" personality_sides_str = ""
for personality_side in personality_sides: for personality_side in personality_sides:
personality_sides_str += f"{personality_side}" personality_sides_str += f"{personality_side}"
# 添加identity内容 # 添加identity内容
for detail in identity_detail: for detail in identity_detail:
personality_sides_str += f"{detail}" personality_sides_str += f"{detail}"
if not personality_sides_str: if not personality_sides_str:
logger.info("没有personality和identity配置跳过预处理") logger.info("没有personality和identity配置跳过预处理")
return return
# 提取关键词 # 提取关键词
extract_prompt = (await global_prompt_manager.get_prompt_async("extract_keywords_prompt")).format( extract_prompt = (await global_prompt_manager.get_prompt_async("extract_keywords_prompt")).format(
personality_sides=personality_sides_str personality_sides=personality_sides_str
) )
llm_model = LLMRequest( llm_model = LLMRequest(
model=global_config.model.utils_small, model=global_config.model.utils_small,
request_type="individuality.keyword_extract", request_type="individuality.keyword_extract",
) )
keywords_result, _ = await llm_model.generate_response_async(prompt=extract_prompt) keywords_result, _ = await llm_model.generate_response_async(prompt=extract_prompt)
logger.info(f"LLM返回的原始关键词结果: '{keywords_result}'") logger.info(f"LLM返回的原始关键词结果: '{keywords_result}'")
if not keywords_result or keywords_result.strip() == "none": if not keywords_result or keywords_result.strip() == "none":
logger.info("未提取到有效关键词") logger.info("未提取到有效关键词")
return return
# 解析关键词 # 解析关键词
keyword_set = [k.strip() for k in keywords_result.split(",") if k.strip()] keyword_set = [k.strip() for k in keywords_result.split(",") if k.strip()]
logger.info(f"分割后的关键词列表: {keyword_set}") logger.info(f"分割后的关键词列表: {keyword_set}")
logger.info(f"共提取到 {len(keyword_set)} 个关键词") logger.info(f"共提取到 {len(keyword_set)} 个关键词")
# 构建名称块和身份信息 # 构建名称块和身份信息
nickname_str = "" nickname_str = ""
for nickname in global_config.bot.alias_names: for nickname in global_config.bot.alias_names:
nickname_str += f"{nickname}," nickname_str += f"{nickname},"
name_block = f"你的名字是{self.name},你的昵称有{nickname_str},有人也会用这些昵称称呼你。" name_block = f"你的名字是{self.name},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
identity_detail_str = "" identity_detail_str = ""
for detail in identity_detail: for detail in identity_detail:
identity_detail_str += f"{detail}," identity_detail_str += f"{detail},"
# 为每个关键词生成fetched_info添加到现有数据中 # 为每个关键词生成fetched_info添加到现有数据中
updated_count = 0 updated_count = 0
new_count = 0 new_count = 0
for keyword in keyword_set: for keyword in keyword_set:
try: try:
logger.info(f"正在处理关键词: '{keyword}' (长度: {len(keyword)})") logger.info(f"正在处理关键词: '{keyword}' (长度: {len(keyword)})")
# 检查是否已存在该关键词 # 检查是否已存在该关键词
if keyword in fetch_info_data: if keyword in fetch_info_data:
logger.info(f"关键词 '{keyword}' 已存在,将添加新信息...") logger.info(f"关键词 '{keyword}' 已存在,将添加新信息...")
@@ -446,17 +441,17 @@ class Individuality:
logger.info(f"正在为新关键词 '{keyword}' 生成信息...") logger.info(f"正在为新关键词 '{keyword}' 生成信息...")
action_type = "新增" action_type = "新增"
fetch_info_data[keyword] = [] # 初始化为空列表 fetch_info_data[keyword] = [] # 初始化为空列表
fetch_prompt = (await global_prompt_manager.get_prompt_async("fetch_info_prompt")).format( fetch_prompt = (await global_prompt_manager.get_prompt_async("fetch_info_prompt")).format(
name_block=name_block, name_block=name_block,
prompt_personality=personality_sides_str, prompt_personality=personality_sides_str,
indentify_block=identity_detail_str, indentify_block=identity_detail_str,
keyword=keyword, keyword=keyword,
bot_name=self.name bot_name=self.name,
) )
fetched_info, _ = await llm_model.generate_response_async(prompt=fetch_prompt) fetched_info, _ = await llm_model.generate_response_async(prompt=fetch_prompt)
if fetched_info and fetched_info.strip() != "none": if fetched_info and fetched_info.strip() != "none":
# 添加到列表中,避免重复 # 添加到列表中,避免重复
if fetched_info not in fetch_info_data[keyword]: if fetched_info not in fetch_info_data[keyword]:
@@ -470,26 +465,29 @@ class Individuality:
logger.info(f"关键词 '{keyword}' 的信息已存在,跳过重复添加") logger.info(f"关键词 '{keyword}' 的信息已存在,跳过重复添加")
else: else:
logger.info(f"关键词 '{keyword}' 没有相关信息") logger.info(f"关键词 '{keyword}' 没有相关信息")
except Exception as e: except Exception as e:
logger.error(f"为关键词 '{keyword}' 生成信息时出错: {e}") logger.error(f"为关键词 '{keyword}' 生成信息时出错: {e}")
continue continue
# 保存合并后的数据到文件和内存缓存 # 保存合并后的数据到文件和内存缓存
if updated_count > 0 or new_count > 0: if updated_count > 0 or new_count > 0:
self._save_fetch_info_to_file(fetch_info_data) self._save_fetch_info_to_file(fetch_info_data)
logger.info(f"预处理完成,新增 {new_count} 个关键词,追加 {updated_count} 个关键词信息,总计 {len(fetch_info_data)} 个关键词") logger.info(
f"预处理完成,新增 {new_count} 个关键词,追加 {updated_count} 个关键词信息,总计 {len(fetch_info_data)} 个关键词"
)
else: else:
logger.info("预处理完成,但没有生成任何新的有效信息") logger.info("预处理完成,但没有生成任何新的有效信息")
# 将数据加载到内存缓存 # 将数据加载到内存缓存
self.keyword_info_cache = fetch_info_data self.keyword_info_cache = fetch_info_data
logger.info(f"关键词缓存已加载,共 {len(self.keyword_info_cache)} 个关键词") logger.info(f"关键词缓存已加载,共 {len(self.keyword_info_cache)} 个关键词")
# 注册定时任务(延迟执行,避免阻塞初始化) # 注册定时任务(延迟执行,避免阻塞初始化)
import asyncio import asyncio
asyncio.create_task(self._register_keyword_update_task_delayed()) asyncio.create_task(self._register_keyword_update_task_delayed())
except Exception as e: except Exception as e:
logger.error(f"预处理personality关键词时出错: {e}") logger.error(f"预处理personality关键词时出错: {e}")
traceback.print_exc() traceback.print_exc()
@@ -499,32 +497,34 @@ class Individuality:
try: try:
# 等待一小段时间确保系统完全初始化 # 等待一小段时间确保系统完全初始化
import asyncio import asyncio
await asyncio.sleep(5) await asyncio.sleep(5)
from src.manager.async_task_manager import async_task_manager from src.manager.async_task_manager import async_task_manager
logger = get_logger("individuality") logger = get_logger("individuality")
# 创建定时任务 # 创建定时任务
task = KeywordUpdateTask( task = KeywordUpdateTask(
personality_sides=list(global_config.personality.personality_sides), personality_sides=list(global_config.personality.personality_sides),
identity_detail=list(global_config.identity.identity_detail), identity_detail=list(global_config.identity.identity_detail),
individuality_instance=self individuality_instance=self,
) )
# 注册任务 # 注册任务
await async_task_manager.add_task(task) await async_task_manager.add_task(task)
logger.info("关键词更新定时任务已注册") logger.info("关键词更新定时任务已注册")
except Exception as e: except Exception as e:
logger.error(f"注册关键词更新定时任务失败: {e}") logger.error(f"注册关键词更新定时任务失败: {e}")
traceback.print_exc() traceback.print_exc()
def get_keyword_info(self, keyword: str) -> str: def get_keyword_info(self, keyword: str) -> str:
"""获取指定关键词的信息 """获取指定关键词的信息
Args: Args:
keyword: 关键词 keyword: 关键词
Returns: Returns:
str: 随机选择的一条信息,如果没有则返回空字符串 str: 随机选择的一条信息,如果没有则返回空字符串
""" """
@@ -549,37 +549,38 @@ def get_individuality():
class KeywordUpdateTask(AsyncTask): class KeywordUpdateTask(AsyncTask):
"""关键词更新定时任务""" """关键词更新定时任务"""
def __init__(self, personality_sides: list, identity_detail: list, individuality_instance): def __init__(self, personality_sides: list, identity_detail: list, individuality_instance):
# 调用父类构造函数 # 调用父类构造函数
super().__init__( super().__init__(
task_name="keyword_update_task", task_name="keyword_update_task",
wait_before_start=3600, # 1小时后开始 wait_before_start=3600, # 1小时后开始
run_interval=3600 # 每小时运行一次 run_interval=3600, # 每小时运行一次
) )
self.personality_sides = personality_sides self.personality_sides = personality_sides
self.identity_detail = identity_detail self.identity_detail = identity_detail
self.individuality_instance = individuality_instance self.individuality_instance = individuality_instance
# 任务控制参数 # 任务控制参数
self.max_runs = 20 self.max_runs = 20
self.current_runs = 0 self.current_runs = 0
self.original_config_hash = individuality_instance._get_config_hash(personality_sides, identity_detail) self.original_config_hash = individuality_instance._get_config_hash(personality_sides, identity_detail)
async def run(self): async def run(self):
"""执行任务""" """执行任务"""
try: try:
from src.common.logger import get_logger from src.common.logger import get_logger
logger = get_logger("individuality.task") logger = get_logger("individuality.task")
# 检查是否超过最大运行次数 # 检查是否超过最大运行次数
if self.current_runs >= self.max_runs: if self.current_runs >= self.max_runs:
logger.info(f"关键词更新任务已达到最大运行次数({self.max_runs}),停止执行") logger.info(f"关键词更新任务已达到最大运行次数({self.max_runs}),停止执行")
# 设置为0间隔来停止循环任务 # 设置为0间隔来停止循环任务
self.run_interval = 0 self.run_interval = 0
return return
# 检查配置是否发生变化 # 检查配置是否发生变化
current_config_hash = self.individuality_instance._get_config_hash( current_config_hash = self.individuality_instance._get_config_hash(
self.personality_sides, self.identity_detail self.personality_sides, self.identity_detail
@@ -589,17 +590,17 @@ class KeywordUpdateTask(AsyncTask):
# 设置为0间隔来停止循环任务 # 设置为0间隔来停止循环任务
self.run_interval = 0 self.run_interval = 0
return return
self.current_runs += 1 self.current_runs += 1
logger.info(f"开始执行关键词更新任务 (第{self.current_runs}/{self.max_runs}次)") logger.info(f"开始执行关键词更新任务 (第{self.current_runs}/{self.max_runs}次)")
# 执行关键词预处理 # 执行关键词预处理
await self.individuality_instance._preprocess_personality_keywords( await self.individuality_instance._preprocess_personality_keywords(
self.personality_sides, self.identity_detail self.personality_sides, self.identity_detail
) )
logger.info(f"关键词更新任务完成 (第{self.current_runs}/{self.max_runs}次)") logger.info(f"关键词更新任务完成 (第{self.current_runs}/{self.max_runs}次)")
except Exception as e: except Exception as e:
logger.error(f"关键词更新任务执行失败: {e}") logger.error(f"关键词更新任务执行失败: {e}")
traceback.print_exc() traceback.print_exc()

View File

@@ -283,13 +283,12 @@ class RelationshipManager:
points_data = [points_data] points_data = [points_data]
# 添加可读时间到每个point # 添加可读时间到每个point
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]
logger_str = f"了解了有关{person_name}的新印象:\n"
logger_str=f"了解了有关{person_name}的新印象:\n"
for point in points_list: for point in points_list:
logger_str+=f"{point[0]},重要性:{point[1]}\n\n" logger_str += f"{point[0]},重要性:{point[1]}\n\n"
logger.info("logger_str") logger.info("logger_str")
except json.JSONDecodeError: except json.JSONDecodeError:
logger.error(f"解析points JSON失败: {points}") logger.error(f"解析points JSON失败: {points}")
return return
@@ -476,7 +475,6 @@ class RelationshipManager:
person_id, "forgotten_points", json.dumps(forgotten_points, ensure_ascii=False, indent=None) person_id, "forgotten_points", json.dumps(forgotten_points, ensure_ascii=False, indent=None)
) )
# 更新数据库 # 更新数据库
await person_info_manager.update_one_field( await person_info_manager.update_one_field(
person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None) person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None)