175 lines
7.9 KiB
Python
175 lines
7.9 KiB
Python
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)}")
|