🤖 自动格式化代码 [skip ci]
This commit is contained in:
@@ -17,13 +17,12 @@ from src.chat.focus_chat.hfc_utils import CycleDetail
|
||||
import random
|
||||
from src.chat.focus_chat.hfc_utils import get_recent_message_stats
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
from src.plugin_system.apis import generator_api,send_api,message_api
|
||||
from src.plugin_system.apis import generator_api, send_api, message_api
|
||||
from src.chat.willing.willing_manager import get_willing_manager
|
||||
from .priority_manager import PriorityManager
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat
|
||||
|
||||
|
||||
|
||||
ERROR_LOOP_INFO = {
|
||||
"loop_plan_info": {
|
||||
"action_result": {
|
||||
@@ -85,7 +84,7 @@ class HeartFChatting:
|
||||
self.relationship_builder = relationship_builder_manager.get_or_create_builder(self.stream_id)
|
||||
|
||||
self.loop_mode = "normal"
|
||||
|
||||
|
||||
# 新增:消息计数器和疲惫阈值
|
||||
self._message_count = 0 # 发送的消息计数
|
||||
# 基于exit_focus_threshold动态计算疲惫阈值
|
||||
@@ -93,7 +92,6 @@ class HeartFChatting:
|
||||
self._message_threshold = max(10, int(30 * global_config.chat.exit_focus_threshold))
|
||||
self._fatigue_triggered = False # 是否已触发疲惫退出
|
||||
|
||||
|
||||
self.action_manager = ActionManager()
|
||||
self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager)
|
||||
self.action_modifier = ActionModifier(action_manager=self.action_manager, chat_id=self.stream_id)
|
||||
@@ -109,14 +107,12 @@ class HeartFChatting:
|
||||
|
||||
self.reply_timeout_count = 0
|
||||
self.plan_timeout_count = 0
|
||||
|
||||
self.last_read_time = time.time()-1
|
||||
|
||||
|
||||
|
||||
self.last_read_time = time.time() - 1
|
||||
|
||||
self.willing_amplifier = 1
|
||||
self.willing_manager = get_willing_manager()
|
||||
|
||||
|
||||
|
||||
self.reply_mode = self.chat_stream.context.get_priority_mode()
|
||||
if self.reply_mode == "priority":
|
||||
self.priority_manager = PriorityManager(
|
||||
@@ -125,13 +121,11 @@ class HeartFChatting:
|
||||
self.loop_mode = "priority"
|
||||
else:
|
||||
self.priority_manager = None
|
||||
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} HeartFChatting 初始化完成,消息疲惫阈值: {self._message_threshold}条(基于exit_focus_threshold={global_config.chat.exit_focus_threshold}计算,仅在auto模式下生效)"
|
||||
)
|
||||
|
||||
|
||||
|
||||
self.energy_value = 100
|
||||
|
||||
async def start(self):
|
||||
@@ -168,68 +162,69 @@ class HeartFChatting:
|
||||
logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天 (外部停止)")
|
||||
except asyncio.CancelledError:
|
||||
logger.info(f"{self.log_prefix} HeartFChatting: 结束了聊天")
|
||||
|
||||
|
||||
def start_cycle(self):
|
||||
self._cycle_counter += 1
|
||||
self._current_cycle_detail = CycleDetail(self._cycle_counter)
|
||||
self._current_cycle_detail.thinking_id = "tid" + str(round(time.time(), 2))
|
||||
cycle_timers = {}
|
||||
return cycle_timers, self._current_cycle_detail.thinking_id
|
||||
|
||||
def end_cycle(self,loop_info,cycle_timers):
|
||||
|
||||
def end_cycle(self, loop_info, cycle_timers):
|
||||
self._current_cycle_detail.set_loop_info(loop_info)
|
||||
self.history_loop.append(self._current_cycle_detail)
|
||||
self._current_cycle_detail.timers = cycle_timers
|
||||
self._current_cycle_detail.end_time = time.time()
|
||||
|
||||
def print_cycle_info(self,cycle_timers):
|
||||
# 记录循环信息和计时器结果
|
||||
timer_strings = []
|
||||
for name, elapsed in cycle_timers.items():
|
||||
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒"
|
||||
timer_strings.append(f"{name}: {formatted_time}")
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} 第{self._current_cycle_detail.cycle_id}次思考,"
|
||||
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, "
|
||||
f"选择动作: {self._current_cycle_detail.loop_plan_info.get('action_result', {}).get('action_type', '未知动作')}"
|
||||
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||
)
|
||||
|
||||
def print_cycle_info(self, cycle_timers):
|
||||
# 记录循环信息和计时器结果
|
||||
timer_strings = []
|
||||
for name, elapsed in cycle_timers.items():
|
||||
formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒"
|
||||
timer_strings.append(f"{name}: {formatted_time}")
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} 第{self._current_cycle_detail.cycle_id}次思考,"
|
||||
f"耗时: {self._current_cycle_detail.end_time - self._current_cycle_detail.start_time:.1f}秒, "
|
||||
f"选择动作: {self._current_cycle_detail.loop_plan_info.get('action_result', {}).get('action_type', '未知动作')}"
|
||||
+ (f"\n详情: {'; '.join(timer_strings)}" if timer_strings else "")
|
||||
)
|
||||
|
||||
|
||||
async def _loopbody(self):
|
||||
if self.loop_mode == "focus":
|
||||
|
||||
self.energy_value -= 5 * (1/global_config.chat.exit_focus_threshold)
|
||||
self.energy_value -= 5 * (1 / global_config.chat.exit_focus_threshold)
|
||||
if self.energy_value <= 0:
|
||||
self.loop_mode = "normal"
|
||||
return True
|
||||
|
||||
|
||||
|
||||
return await self._observe()
|
||||
elif self.loop_mode == "normal":
|
||||
new_messages_data = get_raw_msg_by_timestamp_with_chat(
|
||||
chat_id=self.stream_id, timestamp_start=self.last_read_time, timestamp_end=time.time(),limit=10,limit_mode="earliest",fliter_bot=True
|
||||
chat_id=self.stream_id,
|
||||
timestamp_start=self.last_read_time,
|
||||
timestamp_end=time.time(),
|
||||
limit=10,
|
||||
limit_mode="earliest",
|
||||
fliter_bot=True,
|
||||
)
|
||||
|
||||
|
||||
if len(new_messages_data) > 4 * global_config.chat.auto_focus_threshold:
|
||||
self.loop_mode = "focus"
|
||||
self.energy_value = 100
|
||||
return True
|
||||
|
||||
|
||||
if new_messages_data:
|
||||
earliest_messages_data = new_messages_data[0]
|
||||
self.last_read_time = earliest_messages_data.get("time")
|
||||
|
||||
|
||||
await self.normal_response(earliest_messages_data)
|
||||
return True
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
async def build_reply_to_str(self,message_data:dict):
|
||||
|
||||
async def build_reply_to_str(self, message_data: dict):
|
||||
person_info_manager = get_person_info_manager()
|
||||
person_id = person_info_manager.get_person_id(
|
||||
message_data.get("chat_info_platform"), message_data.get("user_id")
|
||||
@@ -238,22 +233,17 @@ class HeartFChatting:
|
||||
reply_to_str = f"{person_name}:{message_data.get('processed_plain_text')}"
|
||||
return reply_to_str
|
||||
|
||||
|
||||
async def _observe(self,message_data:dict = None):
|
||||
async def _observe(self, message_data: dict = None):
|
||||
# 创建新的循环信息
|
||||
cycle_timers, thinking_id = self.start_cycle()
|
||||
|
||||
|
||||
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考[模式:{self.loop_mode}]")
|
||||
|
||||
|
||||
async with global_prompt_manager.async_message_scope(
|
||||
self.chat_stream.context.get_template_name()
|
||||
):
|
||||
|
||||
async with global_prompt_manager.async_message_scope(self.chat_stream.context.get_template_name()):
|
||||
loop_start_time = time.time()
|
||||
# await self.loop_info.observe()
|
||||
await self.relationship_builder.build_relation()
|
||||
|
||||
|
||||
# 第一步:动作修改
|
||||
with Timer("动作修改", cycle_timers):
|
||||
try:
|
||||
@@ -261,18 +251,15 @@ class HeartFChatting:
|
||||
available_actions = self.action_manager.get_using_actions()
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 动作修改失败: {e}")
|
||||
|
||||
#如果normal,开始一个回复生成进程,先准备好回复(其实是和planer同时进行的)
|
||||
|
||||
# 如果normal,开始一个回复生成进程,先准备好回复(其实是和planer同时进行的)
|
||||
if self.loop_mode == "normal":
|
||||
reply_to_str = await self.build_reply_to_str(message_data)
|
||||
gen_task = asyncio.create_task(self._generate_response(message_data, available_actions,reply_to_str))
|
||||
|
||||
gen_task = asyncio.create_task(self._generate_response(message_data, available_actions, reply_to_str))
|
||||
|
||||
with Timer("规划器", cycle_timers):
|
||||
plan_result = await self.action_planner.plan(mode=self.loop_mode)
|
||||
|
||||
|
||||
|
||||
action_result = plan_result.get("action_result", {})
|
||||
action_type, action_data, reasoning, is_parallel = (
|
||||
action_result.get("action_type", "error"),
|
||||
@@ -282,7 +269,7 @@ class HeartFChatting:
|
||||
)
|
||||
|
||||
action_data["loop_start_time"] = loop_start_time
|
||||
|
||||
|
||||
if self.loop_mode == "normal":
|
||||
if action_type == "no_action":
|
||||
logger.info(f"[{self.log_prefix}] {global_config.bot.nickname} 决定进行回复")
|
||||
@@ -293,8 +280,6 @@ class HeartFChatting:
|
||||
else:
|
||||
logger.info(f"[{self.log_prefix}] {global_config.bot.nickname} 决定执行{action_type}动作")
|
||||
|
||||
|
||||
|
||||
if action_type == "no_action":
|
||||
# 等待回复生成完毕
|
||||
gather_timeout = global_config.chat.thinking_timeout
|
||||
@@ -307,9 +292,7 @@ class HeartFChatting:
|
||||
content = " ".join([item[1] for item in response_set if item[0] == "text"])
|
||||
|
||||
# 模型炸了,没有回复内容生成
|
||||
if not response_set or (
|
||||
action_type not in ["no_action"] and not is_parallel
|
||||
):
|
||||
if not response_set or (action_type not in ["no_action"] and not is_parallel):
|
||||
if not response_set:
|
||||
logger.warning(f"[{self.log_prefix}] 模型未生成回复内容")
|
||||
elif action_type not in ["no_action"] and not is_parallel:
|
||||
@@ -320,14 +303,11 @@ class HeartFChatting:
|
||||
|
||||
logger.info(f"[{self.log_prefix}] {global_config.bot.nickname} 决定的回复内容: {content}")
|
||||
|
||||
|
||||
# 发送回复 (不再需要传入 chat)
|
||||
await self._send_response(response_set, reply_to_str, loop_start_time)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
else:
|
||||
# 动作执行计时
|
||||
with Timer("动作执行", cycle_timers):
|
||||
@@ -350,18 +330,16 @@ class HeartFChatting:
|
||||
if loop_info["loop_action_info"]["command"] == "stop_focus_chat":
|
||||
logger.info(f"{self.log_prefix} 麦麦决定停止专注聊天")
|
||||
return False
|
||||
#停止该聊天模式的循环
|
||||
# 停止该聊天模式的循环
|
||||
|
||||
self.end_cycle(loop_info,cycle_timers)
|
||||
self.end_cycle(loop_info, cycle_timers)
|
||||
self.print_cycle_info(cycle_timers)
|
||||
|
||||
if self.loop_mode == "normal":
|
||||
await self.willing_manager.after_generate_reply_handle(message_data.get("message_id"))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
async def _main_chat_loop(self):
|
||||
"""主循环,持续进行计划并可能回复消息,直到被外部取消。"""
|
||||
try:
|
||||
@@ -370,7 +348,7 @@ class HeartFChatting:
|
||||
await asyncio.sleep(0.1)
|
||||
if not success:
|
||||
break
|
||||
|
||||
|
||||
logger.info(f"{self.log_prefix} 麦麦已强制离开聊天")
|
||||
except asyncio.CancelledError:
|
||||
# 设置了关闭标志位后被取消是正常流程
|
||||
@@ -430,7 +408,7 @@ class HeartFChatting:
|
||||
else:
|
||||
success, reply_text = result
|
||||
command = ""
|
||||
|
||||
|
||||
if reply_text == "timeout":
|
||||
self.reply_timeout_count += 1
|
||||
if self.reply_timeout_count > 5:
|
||||
@@ -446,8 +424,6 @@ class HeartFChatting:
|
||||
logger.error(f"{self.log_prefix} 处理{action}时出错: {e}")
|
||||
traceback.print_exc()
|
||||
return False, "", ""
|
||||
|
||||
|
||||
|
||||
async def shutdown(self):
|
||||
"""优雅关闭HeartFChatting实例,取消活动循环任务"""
|
||||
@@ -483,7 +459,6 @@ class HeartFChatting:
|
||||
|
||||
logger.info(f"{self.log_prefix} HeartFChatting关闭完成")
|
||||
|
||||
|
||||
def adjust_reply_frequency(self):
|
||||
"""
|
||||
根据预设规则动态调整回复意愿(willing_amplifier)。
|
||||
@@ -553,18 +528,16 @@ class HeartFChatting:
|
||||
f"[{self.log_prefix}] 调整回复意愿。10分钟内回复: {bot_reply_count_10_min} (目标: {target_replies_in_window:.0f}) -> "
|
||||
f"意愿放大器更新为: {self.willing_amplifier:.2f}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
async def normal_response(self, message_data: dict) -> None:
|
||||
"""
|
||||
处理接收到的消息。
|
||||
在"兴趣"模式下,判断是否回复并生成内容。
|
||||
"""
|
||||
|
||||
|
||||
is_mentioned = message_data.get("is_mentioned", False)
|
||||
interested_rate = message_data.get("interest_rate", 0.0) * self.willing_amplifier
|
||||
|
||||
|
||||
reply_probability = (
|
||||
1.0 if is_mentioned and global_config.normal_chat.mentioned_bot_inevitable_reply else 0.0
|
||||
) # 如果被提及,且开启了提及必回复,则基础概率为1,否则需要意愿判断
|
||||
@@ -587,7 +560,6 @@ class HeartFChatting:
|
||||
if message_data.get("is_emoji") or message_data.get("is_picid"):
|
||||
reply_probability = 0
|
||||
|
||||
|
||||
# 打印消息信息
|
||||
mes_name = self.chat_stream.group_info.group_name if self.chat_stream.group_info else "私聊"
|
||||
if reply_probability > 0.1:
|
||||
@@ -599,16 +571,15 @@ class HeartFChatting:
|
||||
|
||||
if random.random() < reply_probability:
|
||||
await self.willing_manager.before_generate_reply_handle(message_data.get("message_id"))
|
||||
await self._observe(message_data = message_data)
|
||||
await self._observe(message_data=message_data)
|
||||
|
||||
# 意愿管理器:注销当前message信息 (无论是否回复,只要处理过就删除)
|
||||
self.willing_manager.delete(message_data.get("message_id"))
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
async def _generate_response(
|
||||
self, message_data: dict, available_actions: Optional[list],reply_to:str
|
||||
self, message_data: dict, available_actions: Optional[list], reply_to: str
|
||||
) -> Optional[list]:
|
||||
"""生成普通回复"""
|
||||
try:
|
||||
@@ -629,29 +600,28 @@ class HeartFChatting:
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.log_prefix}] 回复生成出现错误:{str(e)} {traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
|
||||
async def _send_response(
|
||||
self, reply_set, reply_to, thinking_start_time
|
||||
):
|
||||
|
||||
async def _send_response(self, reply_set, reply_to, thinking_start_time):
|
||||
current_time = time.time()
|
||||
new_message_count = message_api.count_new_messages(
|
||||
chat_id=self.chat_stream.stream_id, start_time=thinking_start_time, end_time=current_time
|
||||
)
|
||||
|
||||
|
||||
need_reply = new_message_count >= random.randint(2, 4)
|
||||
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} 从思考到回复,共有{new_message_count}条新消息,{'使用' if need_reply else '不使用'}引用回复"
|
||||
)
|
||||
|
||||
|
||||
reply_text = ""
|
||||
first_replyed = False
|
||||
for reply_seg in reply_set:
|
||||
data = reply_seg[1]
|
||||
if not first_replyed:
|
||||
if need_reply:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, reply_to=reply_to, typing=False)
|
||||
await send_api.text_to_stream(
|
||||
text=data, stream_id=self.chat_stream.stream_id, reply_to=reply_to, typing=False
|
||||
)
|
||||
first_replyed = True
|
||||
else:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, typing=False)
|
||||
@@ -659,7 +629,5 @@ class HeartFChatting:
|
||||
else:
|
||||
await send_api.text_to_stream(text=data, stream_id=self.chat_stream.stream_id, typing=True)
|
||||
reply_text += data
|
||||
|
||||
|
||||
return reply_text
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ from src.config.config import global_config
|
||||
from src.common.message_repository import count_messages
|
||||
|
||||
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@@ -82,7 +81,6 @@ class CycleDetail:
|
||||
self.loop_action_info = loop_info["loop_action_info"]
|
||||
|
||||
|
||||
|
||||
def get_recent_message_stats(minutes: int = 30, chat_id: str = None) -> dict:
|
||||
"""
|
||||
Args:
|
||||
|
||||
@@ -49,7 +49,7 @@ class PriorityManager:
|
||||
添加新消息到合适的队列中。
|
||||
"""
|
||||
user_id = message_data.get("user_id")
|
||||
|
||||
|
||||
priority_info_raw = message_data.get("priority_info")
|
||||
priority_info = {}
|
||||
if isinstance(priority_info_raw, str):
|
||||
|
||||
@@ -109,12 +109,12 @@ class HeartFCMessageReceiver:
|
||||
interested_rate, is_mentioned = await _calculate_interest(message)
|
||||
message.interest_value = interested_rate
|
||||
message.is_mentioned = is_mentioned
|
||||
|
||||
|
||||
await self.storage.store_message(message, chat)
|
||||
|
||||
subheartflow = await heartflow.get_or_create_subheartflow(chat.stream_id)
|
||||
message.update_chat_stream(chat)
|
||||
|
||||
|
||||
# subheartflow.add_message_to_normal_chat_cache(message, interested_rate, is_mentioned)
|
||||
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(subheartflow.chat_id)
|
||||
|
||||
@@ -28,26 +28,22 @@ class SubHeartflow:
|
||||
self.subheartflow_id = subheartflow_id
|
||||
self.chat_id = subheartflow_id
|
||||
|
||||
|
||||
self.is_group_chat, self.chat_target_info = get_chat_type_and_target_info(self.chat_id)
|
||||
self.log_prefix = get_chat_manager().get_stream_name(self.subheartflow_id) or self.subheartflow_id
|
||||
|
||||
|
||||
# focus模式退出冷却时间管理
|
||||
self.last_focus_exit_time: float = 0 # 上次退出focus模式的时间
|
||||
|
||||
# 随便水群 normal_chat 和 认真水群 focus_chat 实例
|
||||
# CHAT模式激活 随便水群 FOCUS模式激活 认真水群
|
||||
self.heart_fc_instance: Optional[HeartFChatting] = HeartFChatting(
|
||||
chat_id=self.subheartflow_id,
|
||||
) # 该sub_heartflow的HeartFChatting实例
|
||||
chat_id=self.subheartflow_id,
|
||||
) # 该sub_heartflow的HeartFChatting实例
|
||||
|
||||
async def initialize(self):
|
||||
"""异步初始化方法,创建兴趣流并确定聊天类型"""
|
||||
await self.heart_fc_instance.start()
|
||||
|
||||
|
||||
|
||||
|
||||
async def _stop_heart_fc_chat(self):
|
||||
"""停止并清理 HeartFChatting 实例"""
|
||||
if self.heart_fc_instance.running:
|
||||
@@ -85,7 +81,6 @@ class SubHeartflow:
|
||||
logger.error(f"{self.log_prefix} _start_heart_fc_chat 执行时出错: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
|
||||
def is_in_focus_cooldown(self) -> bool:
|
||||
"""检查是否在focus模式的冷却期内
|
||||
|
||||
@@ -444,11 +444,8 @@ class MessageSet:
|
||||
|
||||
|
||||
def message_recv_from_dict(message_dict: dict) -> MessageRecv:
|
||||
return MessageRecv(
|
||||
|
||||
message_dict
|
||||
|
||||
)
|
||||
return MessageRecv(message_dict)
|
||||
|
||||
|
||||
def message_from_db_dict(db_dict: dict) -> MessageRecv:
|
||||
"""从数据库字典创建MessageRecv实例"""
|
||||
@@ -492,4 +489,4 @@ def message_from_db_dict(db_dict: dict) -> MessageRecv:
|
||||
msg.is_emoji = db_dict.get("is_emoji", False)
|
||||
msg.is_picid = db_dict.get("is_picid", False)
|
||||
|
||||
return msg
|
||||
return msg
|
||||
|
||||
@@ -84,4 +84,3 @@ class HeartFCSender:
|
||||
except Exception as e:
|
||||
logger.error(f"[{chat_id}] 处理或存储消息 {message_id} 时出错: {e}")
|
||||
raise e
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ logger = get_logger("normal_chat")
|
||||
|
||||
LOOP_INTERVAL = 0.3
|
||||
|
||||
|
||||
class NormalChat:
|
||||
"""
|
||||
普通聊天处理类,负责处理非核心对话的聊天逻辑。
|
||||
@@ -43,7 +44,7 @@ class NormalChat:
|
||||
"""
|
||||
self.chat_stream = chat_stream
|
||||
self.stream_id = chat_stream.stream_id
|
||||
self.last_read_time = time.time()-1
|
||||
self.last_read_time = time.time() - 1
|
||||
|
||||
self.stream_name = get_chat_manager().get_stream_name(self.stream_id) or self.stream_id
|
||||
|
||||
@@ -56,7 +57,7 @@ class NormalChat:
|
||||
|
||||
# self.mood_manager = mood_manager
|
||||
self.start_time = time.time()
|
||||
|
||||
|
||||
self.running = False
|
||||
|
||||
self._initialized = False # Track initialization status
|
||||
@@ -86,7 +87,7 @@ class NormalChat:
|
||||
|
||||
# 任务管理
|
||||
self._chat_task: Optional[asyncio.Task] = None
|
||||
self._priority_chat_task: Optional[asyncio.Task] = None # for priority mode consumer
|
||||
self._priority_chat_task: Optional[asyncio.Task] = None # for priority mode consumer
|
||||
self._disabled = False # 停用标志
|
||||
|
||||
# 新增:回复模式和优先级管理器
|
||||
@@ -106,11 +107,11 @@ class NormalChat:
|
||||
if self.reply_mode == "priority" and self._priority_chat_task and not self._priority_chat_task.done():
|
||||
self._priority_chat_task.cancel()
|
||||
logger.info(f"[{self.stream_name}] NormalChat 已停用。")
|
||||
|
||||
|
||||
# async def _interest_mode_loopbody(self):
|
||||
# try:
|
||||
# await asyncio.sleep(LOOP_INTERVAL)
|
||||
|
||||
|
||||
# if self._disabled:
|
||||
# return False
|
||||
|
||||
@@ -118,10 +119,10 @@ class NormalChat:
|
||||
# new_messages_data = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
# chat_id=self.stream_id, timestamp_start=self.last_read_time, timestamp_end=now, limit_mode="earliest"
|
||||
# )
|
||||
|
||||
|
||||
# if new_messages_data:
|
||||
# self.last_read_time = now
|
||||
|
||||
|
||||
# for msg_data in new_messages_data:
|
||||
# try:
|
||||
# self.adjust_reply_frequency()
|
||||
@@ -134,44 +135,42 @@ class NormalChat:
|
||||
# except Exception as e:
|
||||
# logger.error(f"[{self.stream_name}] 处理消息时出错: {e} {traceback.format_exc()}")
|
||||
|
||||
|
||||
# except asyncio.CancelledError:
|
||||
# logger.info(f"[{self.stream_name}] 兴趣模式轮询任务被取消")
|
||||
# return False
|
||||
# except Exception:
|
||||
# logger.error(f"[{self.stream_name}] 兴趣模式轮询循环出现错误: {traceback.format_exc()}", exc_info=True)
|
||||
# await asyncio.sleep(10)
|
||||
|
||||
|
||||
async def _priority_mode_loopbody(self):
|
||||
try:
|
||||
await asyncio.sleep(LOOP_INTERVAL)
|
||||
try:
|
||||
await asyncio.sleep(LOOP_INTERVAL)
|
||||
|
||||
if self._disabled:
|
||||
return False
|
||||
|
||||
now = time.time()
|
||||
new_messages_data = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
chat_id=self.stream_id, timestamp_start=self.last_read_time, timestamp_end=now, limit_mode="earliest"
|
||||
)
|
||||
|
||||
if new_messages_data:
|
||||
self.last_read_time = now
|
||||
|
||||
for msg_data in new_messages_data:
|
||||
try:
|
||||
if self.priority_manager:
|
||||
self.priority_manager.add_message(msg_data, msg_data.get("interest_rate", 0.0))
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.stream_name}] 添加消息到优先级队列时出错: {e} {traceback.format_exc()}")
|
||||
|
||||
|
||||
except asyncio.CancelledError:
|
||||
logger.info(f"[{self.stream_name}] 优先级消息生产者任务被取消")
|
||||
if self._disabled:
|
||||
return False
|
||||
except Exception:
|
||||
logger.error(f"[{self.stream_name}] 优先级消息生产者循环出现错误: {traceback.format_exc()}", exc_info=True)
|
||||
await asyncio.sleep(10)
|
||||
|
||||
now = time.time()
|
||||
new_messages_data = get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
chat_id=self.stream_id, timestamp_start=self.last_read_time, timestamp_end=now, limit_mode="earliest"
|
||||
)
|
||||
|
||||
if new_messages_data:
|
||||
self.last_read_time = now
|
||||
|
||||
for msg_data in new_messages_data:
|
||||
try:
|
||||
if self.priority_manager:
|
||||
self.priority_manager.add_message(msg_data, msg_data.get("interest_rate", 0.0))
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[{self.stream_name}] 添加消息到优先级队列时出错: {e} {traceback.format_exc()}")
|
||||
|
||||
except asyncio.CancelledError:
|
||||
logger.info(f"[{self.stream_name}] 优先级消息生产者任务被取消")
|
||||
return False
|
||||
except Exception:
|
||||
logger.error(f"[{self.stream_name}] 优先级消息生产者循环出现错误: {traceback.format_exc()}", exc_info=True)
|
||||
await asyncio.sleep(10)
|
||||
|
||||
# async def _interest_message_polling_loop(self):
|
||||
# """
|
||||
@@ -181,16 +180,13 @@ class NormalChat:
|
||||
# try:
|
||||
# while not self._disabled:
|
||||
# success = await self._interest_mode_loopbody()
|
||||
|
||||
|
||||
# if not success:
|
||||
# break
|
||||
|
||||
# except asyncio.CancelledError:
|
||||
# logger.info(f"[{self.stream_name}] 兴趣模式消息轮询任务被优雅地取消了")
|
||||
|
||||
|
||||
|
||||
|
||||
async def _priority_chat_loop(self):
|
||||
"""
|
||||
使用优先级队列的消息处理循环。
|
||||
@@ -272,9 +268,8 @@ class NormalChat:
|
||||
# user_nickname=message_data.get("user_nickname"),
|
||||
# platform=message_data.get("chat_info_platform"),
|
||||
# )
|
||||
|
||||
|
||||
# reply = message_from_db_dict(message_data)
|
||||
|
||||
|
||||
# mark_head = False
|
||||
# first_bot_msg = None
|
||||
@@ -652,7 +647,9 @@ class NormalChat:
|
||||
# Start consumer loop
|
||||
consumer_task = asyncio.create_task(self._priority_chat_loop())
|
||||
self._priority_chat_task = consumer_task
|
||||
self._priority_chat_task.add_done_callback(lambda t: self._handle_task_completion(t, "priority_consumer"))
|
||||
self._priority_chat_task.add_done_callback(
|
||||
lambda t: self._handle_task_completion(t, "priority_consumer")
|
||||
)
|
||||
else: # Interest mode
|
||||
polling_task = asyncio.create_task(self._interest_message_polling_loop())
|
||||
self._chat_task = polling_task
|
||||
@@ -712,7 +709,6 @@ class NormalChat:
|
||||
self._chat_task = None
|
||||
self._priority_chat_task = None
|
||||
|
||||
|
||||
# def adjust_reply_frequency(self):
|
||||
# """
|
||||
# 根据预设规则动态调整回复意愿(willing_amplifier)。
|
||||
|
||||
@@ -82,9 +82,9 @@ class ActionModifier:
|
||||
|
||||
# === 第一阶段:传统观察处理 ===
|
||||
# if history_loop:
|
||||
# removals_from_loop = await self.analyze_loop_actions(history_loop)
|
||||
# if removals_from_loop:
|
||||
# removals_s1.extend(removals_from_loop)
|
||||
# removals_from_loop = await self.analyze_loop_actions(history_loop)
|
||||
# if removals_from_loop:
|
||||
# removals_s1.extend(removals_from_loop)
|
||||
|
||||
# 检查动作的关联类型
|
||||
chat_context = self.chat_stream.context
|
||||
@@ -188,7 +188,7 @@ class ActionModifier:
|
||||
reason = "激活类型为never"
|
||||
deactivated_actions.append((action_name, reason))
|
||||
logger.debug(f"{self.log_prefix}未激活动作: {action_name},原因: 激活类型为never")
|
||||
|
||||
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix}未知的激活类型: {activation_type},跳过处理")
|
||||
|
||||
@@ -500,13 +500,13 @@ class ActionModifier:
|
||||
|
||||
return removals
|
||||
|
||||
def get_available_actions_count(self,mode:str = "focus") -> int:
|
||||
def get_available_actions_count(self, mode: str = "focus") -> int:
|
||||
"""获取当前可用动作数量(排除默认的no_action)"""
|
||||
current_actions = self.action_manager.get_using_actions_for_mode(mode)
|
||||
# 排除no_action(如果存在)
|
||||
filtered_actions = {k: v for k, v in current_actions.items() if k != "no_action"}
|
||||
return len(filtered_actions)
|
||||
|
||||
|
||||
def should_skip_planning_for_no_reply(self) -> bool:
|
||||
"""判断是否应该跳过规划过程"""
|
||||
current_actions = self.action_manager.get_using_actions_for_mode("focus")
|
||||
|
||||
@@ -76,7 +76,7 @@ class ActionPlanner:
|
||||
|
||||
self.last_obs_time_mark = 0.0
|
||||
|
||||
async def plan(self,mode:str = "focus") -> Dict[str, Any]:
|
||||
async def plan(self, mode: str = "focus") -> Dict[str, Any]:
|
||||
"""
|
||||
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
|
||||
"""
|
||||
|
||||
@@ -506,7 +506,6 @@ class DefaultReplyer:
|
||||
show_actions=True,
|
||||
)
|
||||
|
||||
|
||||
message_list_before_short = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=chat_id,
|
||||
timestamp=time.time(),
|
||||
|
||||
@@ -28,7 +28,12 @@ def get_raw_msg_by_timestamp(
|
||||
|
||||
|
||||
def get_raw_msg_by_timestamp_with_chat(
|
||||
chat_id: str, timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest", fliter_bot = False
|
||||
chat_id: str,
|
||||
timestamp_start: float,
|
||||
timestamp_end: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
fliter_bot=False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取在特定聊天从指定时间戳到指定时间戳的消息,按时间升序排序,返回消息列表
|
||||
limit: 限制返回的消息数量,0为不限制
|
||||
@@ -38,11 +43,18 @@ def get_raw_msg_by_timestamp_with_chat(
|
||||
# 只有当 limit 为 0 时才应用外部 sort
|
||||
sort_order = [("time", 1)] if limit == 0 else None
|
||||
# 直接将 limit_mode 传递给 find_messages
|
||||
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode, fliter_bot=fliter_bot)
|
||||
return find_messages(
|
||||
message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode, fliter_bot=fliter_bot
|
||||
)
|
||||
|
||||
|
||||
def get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
chat_id: str, timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest", fliter_bot = False
|
||||
chat_id: str,
|
||||
timestamp_start: float,
|
||||
timestamp_end: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
fliter_bot=False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取在特定聊天从指定时间戳到指定时间戳的消息(包含边界),按时间升序排序,返回消息列表
|
||||
limit: 限制返回的消息数量,0为不限制
|
||||
@@ -52,8 +64,10 @@ def get_raw_msg_by_timestamp_with_chat_inclusive(
|
||||
# 只有当 limit 为 0 时才应用外部 sort
|
||||
sort_order = [("time", 1)] if limit == 0 else None
|
||||
# 直接将 limit_mode 传递给 find_messages
|
||||
|
||||
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode, fliter_bot=fliter_bot)
|
||||
|
||||
return find_messages(
|
||||
message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode, fliter_bot=fliter_bot
|
||||
)
|
||||
|
||||
|
||||
def get_raw_msg_by_timestamp_with_chat_users(
|
||||
@@ -583,8 +597,7 @@ def build_readable_actions(actions: List[Dict[str, Any]]) -> str:
|
||||
action_name = action.get("action_name", "未知动作")
|
||||
if action_name == "no_action" or action_name == "no_reply":
|
||||
continue
|
||||
|
||||
|
||||
|
||||
action_prompt_display = action.get("action_prompt_display", "无具体内容")
|
||||
|
||||
time_diff_seconds = current_time - action_time
|
||||
|
||||
@@ -20,7 +20,7 @@ def find_messages(
|
||||
sort: Optional[List[tuple[str, int]]] = None,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
fliter_bot = False
|
||||
fliter_bot=False,
|
||||
) -> List[dict[str, Any]]:
|
||||
"""
|
||||
根据提供的过滤器、排序和限制条件查找消息。
|
||||
@@ -69,10 +69,10 @@ def find_messages(
|
||||
logger.warning(f"过滤器键 '{key}' 在 Messages 模型中未找到。将跳过此条件。")
|
||||
if conditions:
|
||||
query = query.where(*conditions)
|
||||
|
||||
|
||||
if fliter_bot:
|
||||
query = query.where(Messages.user_id != global_config.bot.qq_account)
|
||||
|
||||
|
||||
if limit > 0:
|
||||
if limit_mode == "earliest":
|
||||
# 获取时间最早的 limit 条记录,已经是正序
|
||||
|
||||
@@ -278,7 +278,6 @@ class NormalChatConfig(ConfigBase):
|
||||
"""@bot 必然回复"""
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class FocusChatConfig(ConfigBase):
|
||||
"""专注聊天配置类"""
|
||||
|
||||
@@ -125,7 +125,6 @@ class MainSystem:
|
||||
logger.info("个体特征初始化成功")
|
||||
|
||||
try:
|
||||
|
||||
init_time = int(1000 * (time.time() - init_start_time))
|
||||
logger.info(f"初始化完成,神经元放电{init_time}次")
|
||||
except Exception as e:
|
||||
|
||||
@@ -77,7 +77,7 @@ class ChatMood:
|
||||
|
||||
if random.random() > update_probability:
|
||||
return
|
||||
|
||||
|
||||
logger.info(f"更新情绪状态,感兴趣度: {interested_rate}, 更新概率: {update_probability}")
|
||||
|
||||
message_time = message.message_info.time
|
||||
|
||||
@@ -56,7 +56,12 @@ def get_messages_by_time(
|
||||
|
||||
|
||||
def get_messages_by_time_in_chat(
|
||||
chat_id: str, start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest", filter_mai: bool = False
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取指定聊天中指定时间范围内的消息
|
||||
@@ -78,7 +83,12 @@ def get_messages_by_time_in_chat(
|
||||
|
||||
|
||||
def get_messages_by_time_in_chat_inclusive(
|
||||
chat_id: str, start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest", filter_mai: bool = False
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取指定聊天中指定时间范围内的消息(包含边界)
|
||||
@@ -95,7 +105,9 @@ def get_messages_by_time_in_chat_inclusive(
|
||||
消息列表
|
||||
"""
|
||||
if filter_mai:
|
||||
return filter_mai_messages(get_raw_msg_by_timestamp_with_chat_inclusive(chat_id, start_time, end_time, limit, limit_mode))
|
||||
return filter_mai_messages(
|
||||
get_raw_msg_by_timestamp_with_chat_inclusive(chat_id, start_time, end_time, limit, limit_mode)
|
||||
)
|
||||
return get_raw_msg_by_timestamp_with_chat_inclusive(chat_id, start_time, end_time, limit, limit_mode)
|
||||
|
||||
|
||||
@@ -181,7 +193,9 @@ def get_messages_before_time(timestamp: float, limit: int = 0, filter_mai: bool
|
||||
return get_raw_msg_before_timestamp(timestamp, limit)
|
||||
|
||||
|
||||
def get_messages_before_time_in_chat(chat_id: str, timestamp: float, limit: int = 0, filter_mai: bool = False) -> List[Dict[str, Any]]:
|
||||
def get_messages_before_time_in_chat(
|
||||
chat_id: str, timestamp: float, limit: int = 0, filter_mai: bool = False
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取指定聊天中指定时间戳之前的消息
|
||||
|
||||
@@ -342,10 +356,12 @@ async def get_person_ids_from_messages(messages: List[Dict[str, Any]]) -> List[s
|
||||
"""
|
||||
return await get_person_id_list(messages)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 消息过滤函数
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def filter_mai_messages(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
从消息列表中移除麦麦的消息
|
||||
|
||||
Reference in New Issue
Block a user