feat:normal可以一种简洁的方式切换到focus

This commit is contained in:
SengokuCola
2025-07-12 16:12:30 +08:00
parent 0bc059434b
commit 8fae6272bc
7 changed files with 62 additions and 302 deletions

View File

@@ -1,91 +0,0 @@
# 定义了来自外部世界的信息
# 外部世界可以是某个聊天 不同平台的聊天 也可以是任意媒体
from datetime import datetime
from src.common.logger import get_logger
from src.chat.focus_chat.hfc_utils import CycleDetail
from typing import List
# Import the new utility function
logger = get_logger("loop_info")
# 所有观察的基类
class FocusLoopInfo:
def __init__(self, observe_id):
self.observe_id = observe_id
self.last_observe_time = datetime.now().timestamp() # 初始化为当前时间
self.history_loop: List[CycleDetail] = []
def add_loop_info(self, loop_info: CycleDetail):
self.history_loop.append(loop_info)
async def observe(self):
recent_active_cycles: List[CycleDetail] = []
for cycle in reversed(self.history_loop):
# 只关心实际执行了动作的循环
# action_taken = cycle.loop_action_info["action_taken"]
# if action_taken:
recent_active_cycles.append(cycle)
if len(recent_active_cycles) == 5:
break
cycle_info_block = ""
action_detailed_str = ""
consecutive_text_replies = 0
responses_for_prompt = []
cycle_last_reason = ""
# 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看)
for cycle in recent_active_cycles:
action_result = cycle.loop_plan_info.get("action_result", {})
action_type = action_result.get("action_type", "unknown")
action_reasoning = action_result.get("reasoning", "未提供理由")
is_taken = cycle.loop_action_info.get("action_taken", False)
action_taken_time = cycle.loop_action_info.get("taken_time", 0)
action_taken_time_str = (
datetime.fromtimestamp(action_taken_time).strftime("%H:%M:%S") if action_taken_time > 0 else "未知时间"
)
if action_reasoning != cycle_last_reason:
cycle_last_reason = action_reasoning
action_reasoning_str = f"你选择这个action的原因是:{action_reasoning}"
else:
action_reasoning_str = ""
if action_type == "reply":
consecutive_text_replies += 1
response_text = cycle.loop_action_info.get("reply_text", "")
responses_for_prompt.append(response_text)
if is_taken:
action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}')。{action_reasoning_str}\n"
else:
action_detailed_str += f"{action_taken_time_str}时,你选择回复(action:{action_type},内容是:'{response_text}'),但是动作失败了。{action_reasoning_str}\n"
elif action_type == "no_reply":
pass
else:
if is_taken:
action_detailed_str += (
f"{action_taken_time_str}时,你选择执行了(action:{action_type}){action_reasoning_str}\n"
)
else:
action_detailed_str += f"{action_taken_time_str}时,你选择执行了(action:{action_type}),但是动作失败了。{action_reasoning_str}\n"
if action_detailed_str:
cycle_info_block = f"\n你最近做的事:\n{action_detailed_str}\n"
else:
cycle_info_block = "\n"
# 获取history_loop中最新添加的
if self.history_loop:
last_loop = self.history_loop[0]
start_time = last_loop.start_time
end_time = last_loop.end_time
if start_time is not None and end_time is not None:
time_diff = int(end_time - start_time)
if time_diff > 60:
cycle_info_block += f"距离你上一次阅读消息并思考和规划,已经过去了{int(time_diff / 60)}分钟\n"
else:
cycle_info_block += f"距离你上一次阅读消息并思考和规划,已经过去了{time_diff}\n"
else:
cycle_info_block += "你还没看过消息\n"

View File

@@ -2,14 +2,13 @@ import asyncio
import time import time
import traceback import traceback
from collections import deque from collections import deque
from typing import Optional, Deque from typing import Optional, Deque, List
from src.chat.message_receive.chat_stream import get_chat_manager from src.chat.message_receive.chat_stream import get_chat_manager
from rich.traceback import install from rich.traceback import install
from src.chat.utils.prompt_builder import global_prompt_manager from src.chat.utils.prompt_builder import global_prompt_manager
from src.common.logger import get_logger from src.common.logger import get_logger
from src.chat.utils.timer_calculator import Timer from src.chat.utils.timer_calculator import Timer
from src.chat.focus_chat.focus_loop_info import FocusLoopInfo
from src.chat.planner_actions.planner import ActionPlanner from src.chat.planner_actions.planner import ActionPlanner
from src.chat.planner_actions.action_modifier import ActionModifier from src.chat.planner_actions.action_modifier import ActionModifier
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ActionManager
@@ -22,7 +21,7 @@ from src.person_info.person_info import get_person_info_manager
from src.plugin_system.apis import generator_api from src.plugin_system.apis import generator_api
from src.chat.willing.willing_manager import get_willing_manager from src.chat.willing.willing_manager import get_willing_manager
from .priority_manager import PriorityManager from .priority_manager import PriorityManager
from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat_inclusive from src.chat.utils.chat_message_builder import get_raw_msg_by_timestamp_with_chat
@@ -88,8 +87,6 @@ class HeartFChatting:
self.loop_mode = "normal" self.loop_mode = "normal"
self.recent_replies = []
# 新增:消息计数器和疲惫阈值 # 新增:消息计数器和疲惫阈值
self._message_count = 0 # 发送的消息计数 self._message_count = 0 # 发送的消息计数
# 基于exit_focus_threshold动态计算疲惫阈值 # 基于exit_focus_threshold动态计算疲惫阈值
@@ -97,7 +94,6 @@ class HeartFChatting:
self._message_threshold = max(10, int(30 * global_config.chat.exit_focus_threshold)) self._message_threshold = max(10, int(30 * global_config.chat.exit_focus_threshold))
self._fatigue_triggered = False # 是否已触发疲惫退出 self._fatigue_triggered = False # 是否已触发疲惫退出
self.loop_info: FocusLoopInfo = FocusLoopInfo(observe_id=self.stream_id)
self.action_manager = ActionManager() self.action_manager = ActionManager()
self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager) self.action_planner = ActionPlanner(chat_id=self.stream_id, action_manager=self.action_manager)
@@ -108,8 +104,8 @@ class HeartFChatting:
self._loop_task: Optional[asyncio.Task] = None # 主循环任务 self._loop_task: Optional[asyncio.Task] = None # 主循环任务
# 添加循环信息管理相关的属性 # 添加循环信息管理相关的属性
self.history_loop: List[CycleDetail] = []
self._cycle_counter = 0 self._cycle_counter = 0
self._cycle_history: Deque[CycleDetail] = deque(maxlen=10) # 保留最近10个循环的信息
self._current_cycle_detail: Optional[CycleDetail] = None self._current_cycle_detail: Optional[CycleDetail] = None
self.reply_timeout_count = 0 self.reply_timeout_count = 0
@@ -118,31 +114,27 @@ class HeartFChatting:
self.last_read_time = time.time()-1 self.last_read_time = time.time()-1
self.willing_amplifier = 1 self.willing_amplifier = 1
self.willing_manager = get_willing_manager()
self.action_type: Optional[str] = None # 当前动作类型
self.is_parallel_action: bool = False # 是否是可并行动作
self._chat_task: Optional[asyncio.Task] = None
self._priority_chat_task: Optional[asyncio.Task] = None # for priority mode consumer
self.reply_mode = self.chat_stream.context.get_priority_mode() self.reply_mode = self.chat_stream.context.get_priority_mode()
if self.reply_mode == "priority": if self.reply_mode == "priority":
self.priority_manager = PriorityManager( self.priority_manager = PriorityManager(
normal_queue_max_size=5, normal_queue_max_size=5,
) )
self.loop_mode = "priority"
else: else:
self.priority_manager = None self.priority_manager = None
self.willing_manager = get_willing_manager()
logger.info( logger.info(
f"{self.log_prefix} HeartFChatting 初始化完成,消息疲惫阈值: {self._message_threshold}基于exit_focus_threshold={global_config.chat.exit_focus_threshold}计算仅在auto模式下生效" 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): async def start(self):
"""检查是否需要启动主循环,如果未激活则启动。""" """检查是否需要启动主循环,如果未激活则启动。"""
@@ -152,8 +144,6 @@ class HeartFChatting:
return return
try: try:
# 重置消息计数器开始新的focus会话
self.reset_message_count()
# 标记为活动状态,防止重复启动 # 标记为活动状态,防止重复启动
self.running = True self.running = True
@@ -178,26 +168,20 @@ class HeartFChatting:
else: else:
logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天 (外部停止)") logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天 (外部停止)")
except asyncio.CancelledError: except asyncio.CancelledError:
logger.info(f"{self.log_prefix} HeartFChatting: 脱离了聊天(任务取消)") logger.info(f"{self.log_prefix} HeartFChatting: 结束了聊天")
finally:
self.running = False
self._loop_task = None
def start_cycle(self): def start_cycle(self):
self._cycle_counter += 1 self._cycle_counter += 1
self._current_cycle_detail = CycleDetail(self._cycle_counter) self._current_cycle_detail = CycleDetail(self._cycle_counter)
self._current_cycle_detail.prefix = self.log_prefix self._current_cycle_detail.thinking_id = "tid" + str(round(time.time(), 2))
thinking_id = "tid" + str(round(time.time(), 2))
self._current_cycle_detail.set_thinking_id(thinking_id)
cycle_timers = {} cycle_timers = {}
return cycle_timers, thinking_id 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._current_cycle_detail.set_loop_info(loop_info)
self.loop_info.add_loop_info(self._current_cycle_detail) self.history_loop.append(self._current_cycle_detail)
self._current_cycle_detail.timers = cycle_timers self._current_cycle_detail.timers = cycle_timers
self._current_cycle_detail.complete_cycle() self._current_cycle_detail.end_time = time.time()
self._cycle_history.append(self._current_cycle_detail)
def print_cycle_info(self,cycle_timers): def print_cycle_info(self,cycle_timers):
# 记录循环信息和计时器结果 # 记录循环信息和计时器结果
@@ -217,28 +201,24 @@ class HeartFChatting:
async def _loopbody(self): async def _loopbody(self):
if self.loop_mode == "focus": if self.loop_mode == "focus":
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次观察")
return await self._observe() return await self._observe()
elif self.loop_mode == "normal": elif self.loop_mode == "normal":
now = time.time() new_messages_data = get_raw_msg_by_timestamp_with_chat(
new_messages_data = get_raw_msg_by_timestamp_with_chat_inclusive( 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=now, limit_mode="earliest"
) )
if new_messages_data: if len(new_messages_data) > 5:
self.last_read_time = now self.loop_mode = "focus"
for msg_data in new_messages_data:
try:
self.adjust_reply_frequency()
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次循环")
await self.normal_response(msg_data)
# TODO: 这个地方可能导致阻塞,需要优化
return True return True
except Exception as e:
logger.error(f"[{self.log_prefix}] 处理消息时出错: {e} {traceback.format_exc()}") if new_messages_data:
else: earliest_messages_data = new_messages_data[0]
await asyncio.sleep(0.1) self.last_read_time = earliest_messages_data.get("time")
await self.normal_response(earliest_messages_data)
return True
await asyncio.sleep(1)
return True return True
@@ -248,6 +228,9 @@ class HeartFChatting:
# 创建新的循环信息 # 创建新的循环信息
cycle_timers, thinking_id = self.start_cycle() cycle_timers, thinking_id = self.start_cycle()
logger.info(f"{self.log_prefix} 开始第{self._cycle_counter}次思考")
if message_data:
await create_thinking_message_from_dict(message_data,self.chat_stream,thinking_id) await create_thinking_message_from_dict(message_data,self.chat_stream,thinking_id)
async with global_prompt_manager.async_message_scope( async with global_prompt_manager.async_message_scope(
@@ -255,7 +238,7 @@ class HeartFChatting:
): ):
loop_start_time = time.time() loop_start_time = time.time()
await self.loop_info.observe() # await self.loop_info.observe()
await self.relationship_builder.build_relation() await self.relationship_builder.build_relation()
# 第一步:动作修改 # 第一步:动作修改
@@ -263,7 +246,7 @@ class HeartFChatting:
try: try:
if self.loop_mode == "focus": if self.loop_mode == "focus":
await self.action_modifier.modify_actions( await self.action_modifier.modify_actions(
loop_info=self.loop_info, history_loop=self.history_loop,
mode="focus", mode="focus",
) )
elif self.loop_mode == "normal": elif self.loop_mode == "normal":
@@ -317,11 +300,10 @@ class HeartFChatting:
if action_type == "no_action": if action_type == "no_action":
gather_timeout = global_config.chat.thinking_timeout gather_timeout = global_config.chat.thinking_timeout
results = await asyncio.wait_for( try:
asyncio.gather(gen_task, return_exceptions=True), response_set = await asyncio.wait_for(gen_task, timeout=gather_timeout)
timeout=gather_timeout, except asyncio.TimeoutError:
) response_set = None
response_set = results[0]
if response_set: if response_set:
content = " ".join([item[1] for item in response_set if item[0] == "text"]) content = " ".join([item[1] for item in response_set if item[0] == "text"])
@@ -334,7 +316,7 @@ class HeartFChatting:
logger.warning(f"[{self.log_prefix}] 模型未生成回复内容") logger.warning(f"[{self.log_prefix}] 模型未生成回复内容")
elif action_type not in ["no_action"] and not is_parallel: elif action_type not in ["no_action"] and not is_parallel:
logger.info( logger.info(
f"[{self.log_prefix}] {global_config.bot.nickname} 原本想要回复:{content},但选择执行{self.action_type},不发表回复" f"[{self.log_prefix}] {global_config.bot.nickname} 原本想要回复:{content},但选择执行{action_type},不发表回复"
) )
# 如果模型未生成回复,移除思考消息 # 如果模型未生成回复,移除思考消息
await cleanup_thinking_message_by_id(self.chat_stream.stream_id,thinking_id,self.log_prefix) await cleanup_thinking_message_by_id(self.chat_stream.stream_id,thinking_id,self.log_prefix)
@@ -350,27 +332,8 @@ class HeartFChatting:
return False return False
# 发送回复 (不再需要传入 chat) # 发送回复 (不再需要传入 chat)
first_bot_msg = await add_messages_to_manager(message_data, reply_texts, thinking_id,self.chat_stream.stream_id) await add_messages_to_manager(message_data, reply_texts, thinking_id,self.chat_stream.stream_id)
# 检查 first_bot_msg 是否为 None (例如思考消息已被移除的情况)
if first_bot_msg:
# 消息段已在接收消息时更新,这里不需要额外处理
# 记录回复信息到最近回复列表中
reply_info = {
"time": time.time(),
"user_message": message_data.get("processed_plain_text"),
"user_info": {
"user_id": message_data.get("user_id"),
"user_nickname": message_data.get("user_nickname"),
},
"response": response_set,
"is_reference_reply": message_data.get("reply") is not None, # 判断是否为引用回复
}
self.recent_replies.append(reply_info)
# 保持最近回复历史在限定数量内
if len(self.recent_replies) > 10:
self.recent_replies = self.recent_replies[-10 :]
return response_set if response_set else False return response_set if response_set else False
@@ -416,6 +379,7 @@ class HeartFChatting:
try: try:
while self.running: # 主循环 while self.running: # 主循环
success = await self._loopbody() success = await self._loopbody()
await asyncio.sleep(0.1)
if not success: if not success:
break break
@@ -531,12 +495,6 @@ class HeartFChatting:
return max(10, int(30 / global_config.chat.exit_focus_threshold)) return max(10, int(30 / global_config.chat.exit_focus_threshold))
def reset_message_count(self):
"""重置消息计数器用于重新启动focus模式时"""
self._message_count = 0
self._fatigue_triggered = False
logger.info(f"{self.log_prefix} 消息计数器已重置")
async def shutdown(self): async def shutdown(self):
"""优雅关闭HeartFChatting实例取消活动循环任务""" """优雅关闭HeartFChatting实例取消活动循环任务"""
logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...") logger.info(f"{self.log_prefix} 正在关闭HeartFChatting...")
@@ -675,16 +633,6 @@ class HeartFChatting:
if message_data.get("is_emoji") or message_data.get("is_picid"): if message_data.get("is_emoji") or message_data.get("is_picid"):
reply_probability = 0 reply_probability = 0
# 应用疲劳期回复频率调整
fatigue_multiplier = self._get_fatigue_reply_multiplier()
original_probability = reply_probability
reply_probability *= fatigue_multiplier
# 如果应用了疲劳调整,记录日志
if fatigue_multiplier < 1.0:
logger.info(
f"[{self.log_prefix}] 疲劳期回复频率调整: {original_probability * 100:.1f}% -> {reply_probability * 100:.1f}% (系数: {fatigue_multiplier:.2f})"
)
# 打印消息信息 # 打印消息信息
mes_name = self.chat_stream.group_info.group_name if self.chat_stream.group_info else "私聊" mes_name = self.chat_stream.group_info.group_name if self.chat_stream.group_info else "私聊"
@@ -734,63 +682,3 @@ class HeartFChatting:
except Exception as e: except Exception as e:
logger.error(f"[{self.log_prefix}] 回复生成出现错误:{str(e)} {traceback.format_exc()}") logger.error(f"[{self.log_prefix}] 回复生成出现错误:{str(e)} {traceback.format_exc()}")
return None return None
def _get_fatigue_reply_multiplier(self) -> float:
"""获取疲劳期回复频率调整系数
Returns:
float: 回复频率调整系数范围0.5-1.0
"""
if not self.get_cooldown_progress_callback:
return 1.0 # 没有冷却进度回调,返回正常系数
try:
cooldown_progress = self.get_cooldown_progress_callback()
if cooldown_progress >= 1.0:
return 1.0 # 冷却完成,正常回复频率
# 疲劳期间从0.5逐渐恢复到1.0
# progress=0时系数为0.5progress=1时系数为1.0
multiplier = 0.2 + (0.8 * cooldown_progress)
return multiplier
except Exception as e:
logger.warning(f"[{self.log_prefix}] 获取疲劳调整系数时出错: {e}")
return 1.0 # 出错时返回正常系数
# async def _check_should_switch_to_focus(self) -> bool:
# """
# 检查是否满足切换到focus模式的条件
# Returns:
# bool: 是否应该切换到focus模式
# """
# # 检查思考消息堆积情况
# container = await message_manager.get_container(self.stream_id)
# if container:
# thinking_count = sum(1 for msg in container.messages if isinstance(msg, MessageThinking))
# if thinking_count >= 4 * global_config.chat.auto_focus_threshold: # 如果堆积超过阈值条思考消息
# logger.debug(f"[{self.stream_name}] 检测到思考消息堆积({thinking_count}条)切换到focus模式")
# return True
# if not self.recent_replies:
# return False
# current_time = time.time()
# time_threshold = 120 / global_config.chat.auto_focus_threshold
# reply_threshold = 6 * global_config.chat.auto_focus_threshold
# one_minute_ago = current_time - time_threshold
# # 统计指定时间内的回复数量
# recent_reply_count = sum(1 for reply in self.recent_replies if reply["time"] > one_minute_ago)
# should_switch = recent_reply_count > reply_threshold
# if should_switch:
# logger.debug(
# f"[{self.stream_name}] 检测到{time_threshold:.0f}秒内回复数量({recent_reply_count})大于{reply_threshold}满足切换到focus模式条件"
# )
# return should_switch

View File

@@ -23,7 +23,6 @@ class CycleDetail:
def __init__(self, cycle_id: int): def __init__(self, cycle_id: int):
self.cycle_id = cycle_id self.cycle_id = cycle_id
self.prefix = ""
self.thinking_id = "" self.thinking_id = ""
self.start_time = time.time() self.start_time = time.time()
self.end_time: Optional[float] = None self.end_time: Optional[float] = None
@@ -85,43 +84,12 @@ class CycleDetail:
"loop_action_info": convert_to_serializable(self.loop_action_info), "loop_action_info": convert_to_serializable(self.loop_action_info),
} }
def complete_cycle(self):
"""完成循环,记录结束时间"""
self.end_time = time.time()
# 处理 prefix只保留中英文字符和基本标点
if not self.prefix:
self.prefix = "group"
else:
# 只保留中文、英文字母、数字和基本标点
allowed_chars = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
self.prefix = (
"".join(char for char in self.prefix if "\u4e00" <= char <= "\u9fff" or char in allowed_chars)
or "group"
)
def set_thinking_id(self, thinking_id: str):
"""设置思考消息ID"""
self.thinking_id = thinking_id
def set_loop_info(self, loop_info: Dict[str, Any]): def set_loop_info(self, loop_info: Dict[str, Any]):
"""设置循环信息""" """设置循环信息"""
self.loop_plan_info = loop_info["loop_plan_info"] self.loop_plan_info = loop_info["loop_plan_info"]
self.loop_action_info = loop_info["loop_action_info"] self.loop_action_info = loop_info["loop_action_info"]
def parse_thinking_id_to_timestamp(thinking_id: str) -> float:
"""
将形如 'tid<timestamp>' 的 thinking_id 解析回 float 时间戳
例如: 'tid1718251234.56' -> 1718251234.56
"""
if not thinking_id.startswith("tid"):
raise ValueError("thinking_id 格式不正确")
ts_str = thinking_id[3:]
return float(ts_str)
async def create_thinking_message_from_dict(message_data: dict, chat_stream: ChatStream, thinking_id: str) -> str: async def create_thinking_message_from_dict(message_data: dict, chat_stream: ChatStream, thinking_id: str) -> str:
"""创建思考消息""" """创建思考消息"""
bot_user_info = UserInfo( bot_user_info = UserInfo(

View File

@@ -1,5 +1,5 @@
import traceback import traceback
from src.chat.heart_flow.sub_heartflow import SubHeartflow, ChatState from src.chat.heart_flow.sub_heartflow import SubHeartflow
from src.common.logger import get_logger from src.common.logger import get_logger
from typing import Any, Optional from typing import Any, Optional
from typing import Dict from typing import Dict
@@ -39,20 +39,5 @@ class Heartflow:
traceback.print_exc() traceback.print_exc()
return None return None
async def force_change_subheartflow_status(self, subheartflow_id: str, status: ChatState) -> None:
"""强制改变子心流的状态"""
# 这里的 message 是可选的,可能是一个消息对象,也可能是其他类型的数据
return await self.force_change_state(subheartflow_id, status)
async def force_change_state(self, subflow_id: Any, target_state: ChatState) -> bool:
"""强制改变指定子心流的状态"""
subflow = self.subheartflows.get(subflow_id)
if not subflow:
logger.warning(f"[强制状态转换]尝试转换不存在的子心流{subflow_id}{target_state.value}")
return False
await subflow.change_chat_state(target_state)
logger.info(f"[强制状态转换]子心流 {subflow_id} 已转换到 {target_state.value}")
return True
heartflow = Heartflow() heartflow = Heartflow()

View File

@@ -1,6 +1,6 @@
from typing import List, Optional, Any, Dict from typing import List, Optional, Any, Dict
from src.common.logger import get_logger from src.common.logger import get_logger
from src.chat.focus_chat.focus_loop_info import FocusLoopInfo from src.chat.focus_chat.hfc_utils import CycleDetail
from src.chat.message_receive.chat_stream import get_chat_manager from src.chat.message_receive.chat_stream import get_chat_manager
from src.config.config import global_config from src.config.config import global_config
from src.llm_models.utils_model import LLMRequest from src.llm_models.utils_model import LLMRequest
@@ -43,7 +43,7 @@ class ActionModifier:
async def modify_actions( async def modify_actions(
self, self,
loop_info=None, history_loop=None,
mode: str = "focus", mode: str = "focus",
message_content: str = "", message_content: str = "",
): ):
@@ -82,8 +82,8 @@ class ActionModifier:
chat_content = chat_content + "\n" + f"现在,最新的消息是:{message_content}" chat_content = chat_content + "\n" + f"现在,最新的消息是:{message_content}"
# === 第一阶段:传统观察处理 === # === 第一阶段:传统观察处理 ===
if loop_info: if history_loop:
removals_from_loop = await self.analyze_loop_actions(loop_info) removals_from_loop = await self.analyze_loop_actions(history_loop)
if removals_from_loop: if removals_from_loop:
removals_s1.extend(removals_from_loop) removals_s1.extend(removals_from_loop)
@@ -459,7 +459,7 @@ class ActionModifier:
logger.debug(f"{self.log_prefix}动作 {action_name} 未匹配到任何关键词: {activation_keywords}") logger.debug(f"{self.log_prefix}动作 {action_name} 未匹配到任何关键词: {activation_keywords}")
return False return False
async def analyze_loop_actions(self, obs: FocusLoopInfo) -> List[tuple[str, str]]: async def analyze_loop_actions(self, history_loop: List[CycleDetail]) -> List[tuple[str, str]]:
"""分析最近的循环内容并决定动作的移除 """分析最近的循环内容并决定动作的移除
Returns: Returns:
@@ -469,7 +469,7 @@ class ActionModifier:
removals = [] removals = []
# 获取最近10次循环 # 获取最近10次循环
recent_cycles = obs.history_loop[-10:] if len(obs.history_loop) > 10 else obs.history_loop recent_cycles = history_loop[-10:] if len(history_loop) > 10 else history_loop
if not recent_cycles: if not recent_cycles:
return removals return removals

View File

@@ -28,7 +28,7 @@ def get_raw_msg_by_timestamp(
def get_raw_msg_by_timestamp_with_chat( def get_raw_msg_by_timestamp_with_chat(
chat_id: str, timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest" chat_id: str, timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest", fliter_bot = False
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
"""获取在特定聊天从指定时间戳到指定时间戳的消息,按时间升序排序,返回消息列表 """获取在特定聊天从指定时间戳到指定时间戳的消息,按时间升序排序,返回消息列表
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
@@ -38,11 +38,11 @@ def get_raw_msg_by_timestamp_with_chat(
# 只有当 limit 为 0 时才应用外部 sort # 只有当 limit 为 0 时才应用外部 sort
sort_order = [("time", 1)] if limit == 0 else None sort_order = [("time", 1)] if limit == 0 else None
# 直接将 limit_mode 传递给 find_messages # 直接将 limit_mode 传递给 find_messages
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode) 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( 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" chat_id: str, timestamp_start: float, timestamp_end: float, limit: int = 0, limit_mode: str = "latest", fliter_bot = False
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
"""获取在特定聊天从指定时间戳到指定时间戳的消息(包含边界),按时间升序排序,返回消息列表 """获取在特定聊天从指定时间戳到指定时间戳的消息(包含边界),按时间升序排序,返回消息列表
limit: 限制返回的消息数量0为不限制 limit: 限制返回的消息数量0为不限制
@@ -52,7 +52,8 @@ def get_raw_msg_by_timestamp_with_chat_inclusive(
# 只有当 limit 为 0 时才应用外部 sort # 只有当 limit 为 0 时才应用外部 sort
sort_order = [("time", 1)] if limit == 0 else None sort_order = [("time", 1)] if limit == 0 else None
# 直接将 limit_mode 传递给 find_messages # 直接将 limit_mode 传递给 find_messages
return find_messages(message_filter=filter_query, sort=sort_order, limit=limit, limit_mode=limit_mode)
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( def get_raw_msg_by_timestamp_with_chat_users(
@@ -580,6 +581,10 @@ def build_readable_actions(actions: List[Dict[str, Any]]) -> str:
for action in actions: for action in actions:
action_time = action.get("time", current_time) action_time = action.get("time", current_time)
action_name = action.get("action_name", "未知动作") 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", "无具体内容") action_prompt_display = action.get("action_prompt_display", "无具体内容")
time_diff_seconds = current_time - action_time time_diff_seconds = current_time - action_time

View File

@@ -3,6 +3,7 @@ from src.common.logger import get_logger
import traceback import traceback
from typing import List, Any, Optional from typing import List, Any, Optional
from peewee import Model # 添加 Peewee Model 导入 from peewee import Model # 添加 Peewee Model 导入
from src.config.config import global_config
logger = get_logger(__name__) logger = get_logger(__name__)
@@ -19,6 +20,7 @@ def find_messages(
sort: Optional[List[tuple[str, int]]] = None, sort: Optional[List[tuple[str, int]]] = None,
limit: int = 0, limit: int = 0,
limit_mode: str = "latest", limit_mode: str = "latest",
fliter_bot = False
) -> List[dict[str, Any]]: ) -> List[dict[str, Any]]:
""" """
根据提供的过滤器、排序和限制条件查找消息。 根据提供的过滤器、排序和限制条件查找消息。
@@ -68,6 +70,9 @@ def find_messages(
if conditions: if conditions:
query = query.where(*conditions) query = query.where(*conditions)
if fliter_bot:
query = query.where(Messages.user_id != global_config.bot.qq_account)
if limit > 0: if limit > 0:
if limit_mode == "earliest": if limit_mode == "earliest":
# 获取时间最早的 limit 条记录,已经是正序 # 获取时间最早的 limit 条记录,已经是正序