Files
Mofox-Core/src/person_info/impression_update_task.py
春河晴 3e854719ee ruff
2025-06-10 17:31:05 +09:00

175 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from src.manager.async_task_manager import AsyncTask
from src.common.logger_manager import get_logger
from src.person_info.person_info import PersonInfoManager
from src.person_info.relationship_manager import relationship_manager
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp
from src.config.config import global_config
from src.chat.message_receive.chat_stream import chat_manager
import time
import random
from collections import defaultdict
logger = get_logger("relation")
# 暂时弃用,改为实时更新
class ImpressionUpdateTask(AsyncTask):
def __init__(self):
super().__init__(
task_name="impression_update",
wait_before_start=60,
run_interval=global_config.relationship.build_relationship_interval,
)
async def run(self):
try:
# 获取最近的消息
current_time = int(time.time())
start_time = current_time - global_config.relationship.build_relationship_interval # 100分钟前
# 获取所有消息
messages = get_raw_msg_by_timestamp(timestamp_start=start_time, timestamp_end=current_time)
if not messages:
logger.info("没有找到需要处理的消息")
return
logger.info(f"获取到 {len(messages)} 条消息")
# 按chat_id分组消息
chat_messages = defaultdict(list)
for msg in messages:
chat_messages[msg["chat_id"]].append(msg)
logger.info(f"消息按聊天分组: {len(chat_messages)} 个聊天组")
# 处理每个聊天组
for chat_id, msgs in chat_messages.items():
# 获取chat_stream
if len(msgs) < 30:
logger.info(f"聊天组 {chat_id} 消息数小于30跳过处理")
continue
chat_stream = chat_manager.get_stream(chat_id)
if not chat_stream:
logger.warning(f"未找到聊天组 {chat_id} 的chat_stream跳过处理")
continue
# 找到bot的消息
bot_messages = [msg for msg in msgs if msg["user_nickname"] == global_config.bot.nickname]
if not bot_messages:
logger.info(f"聊天组 {chat_id} 没有bot消息跳过处理")
continue
# 按时间排序所有消息
sorted_messages = sorted(msgs, key=lambda x: x["time"])
# 找到第一条和最后一条bot消息
first_bot_msg = bot_messages[0]
last_bot_msg = bot_messages[-1]
# 获取第一条bot消息前15条消息
first_bot_index = sorted_messages.index(first_bot_msg)
start_index = max(0, first_bot_index - 25)
# 获取最后一条bot消息后15条消息
last_bot_index = sorted_messages.index(last_bot_msg)
end_index = min(len(sorted_messages), last_bot_index + 26)
# 获取相关消息
relevant_messages = sorted_messages[start_index:end_index]
# 统计用户发言权重
user_weights = defaultdict(lambda: {"weight": 0, "messages": []})
# 计算权重
for bot_msg in bot_messages:
bot_time = bot_msg["time"]
context_messages = [
msg for msg in relevant_messages if abs(msg["time"] - bot_time) <= 600
] # 前后10分钟
logger.debug(f"Bot消息 {bot_time} 的上下文消息数: {len(context_messages)}")
for msg in context_messages:
if msg["user_nickname"] == global_config.bot.nickname:
continue
person_id = PersonInfoManager.get_person_id(msg["chat_info_platform"], msg["user_id"])
if not person_id:
logger.warning(f"未找到用户 {msg['user_nickname']} 的person_id")
continue
# 在bot消息附近的发言权重加倍
if abs(msg["time"] - bot_time) <= 120: # 前后2分钟
user_weights[person_id]["weight"] += 2
logger.debug(f"用户 {msg['user_nickname']} 在bot消息附近发言权重+2")
else:
user_weights[person_id]["weight"] += 1
logger.debug(f"用户 {msg['user_nickname']} 发言,权重+1")
user_weights[person_id]["messages"].append(msg)
# 按权重排序
sorted_users = sorted(user_weights.items(), key=lambda x: x[1]["weight"], reverse=True)
logger.debug(
f"用户权重排序: {[(msg[1]['messages'][0]['user_nickname'], msg[1]['weight']) for msg in sorted_users]}"
)
# 选择最多5个用户
selected_users = []
if len(sorted_users) > 5:
# 使用权重作为概率进行随机选择,确保不重复
weights = [user[1]["weight"] for user in sorted_users]
total_weight = sum(weights)
# 计算每个用户的概率
probabilities = [w / total_weight for w in weights]
# 使用累积概率进行选择
selected_indices = []
remaining_indices = list(range(len(sorted_users)))
for _ in range(5):
if not remaining_indices:
break
# 计算剩余索引的累积概率
remaining_probs = [probabilities[i] for i in remaining_indices]
# 归一化概率
remaining_probs = [p / sum(remaining_probs) for p in remaining_probs]
# 选择索引
chosen_idx = random.choices(remaining_indices, weights=remaining_probs, k=1)[0]
selected_indices.append(chosen_idx)
remaining_indices.remove(chosen_idx)
selected_users = [sorted_users[i] for i in selected_indices]
logger.info(
f"开始进一步了解这些用户: {[msg[1]['messages'][0]['user_nickname'] for msg in selected_users]}"
)
else:
selected_users = sorted_users
logger.info(
f"开始进一步了解用户: {[msg[1]['messages'][0]['user_nickname'] for msg in selected_users]}"
)
# 更新选中用户的印象
for person_id, data in selected_users:
user_nickname = data["messages"][0]["user_nickname"]
platform = data["messages"][0]["chat_info_platform"]
user_id = data["messages"][0]["user_id"]
cardname = data["messages"][0]["user_cardname"]
is_known = await relationship_manager.is_known_some_one(platform, user_id)
if not is_known:
logger.info(f"首次认识用户: {user_nickname}")
await relationship_manager.first_knowing_some_one(platform, user_id, user_nickname, cardname)
logger.info(f"开始更新用户 {user_nickname} 的印象")
await relationship_manager.update_person_impression(
person_id=person_id, timestamp=last_bot_msg["time"], bot_engaged_messages=relevant_messages
)
logger.debug("印象更新任务执行完成")
except Exception as e:
logger.exception(f"更新印象任务失败: {str(e)}")