跟新dev的修改

This commit is contained in:
UnCLAS-Prommer
2025-07-08 23:35:38 +08:00
12 changed files with 344 additions and 366 deletions

View File

@@ -324,8 +324,6 @@ async def clear_temp_emoji() -> None:
os.remove(file_path)
logger.debug(f"[清理] 删除: {filename}")
logger.info("[清理] 完成")
async def clean_unused_emojis(emoji_dir: str, emoji_objects: List["MaiEmoji"], removed_count: int) -> int:
"""清理指定目录中未被 emoji_objects 追踪的表情包文件"""
@@ -590,7 +588,7 @@ class EmojiManager:
"""定期检查表情包完整性和数量"""
await self.get_all_emoji_from_db()
while True:
logger.info("[扫描] 开始检查表情包完整性...")
# logger.info("[扫描] 开始检查表情包完整性...")
await self.check_emoji_file_integrity()
await clear_temp_emoji()
logger.info("[扫描] 开始扫描新表情包...")

View File

@@ -110,15 +110,13 @@ class HeartFCMessageReceiver:
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id)
# 如果消息中包含图片标识,则日志展示为图片
# 如果消息中包含图片标识,则将 [picid:...] 替换为 [图片]
picid_pattern = r"\[picid:([^\]]+)\]"
processed_plain_text = re.sub(picid_pattern, "[图片]", message.processed_plain_text)
picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text)
if picid_match:
logger.info(f"[{mes_name}]{userinfo.user_nickname}: [图片] [当前回复频率: {current_talk_frequency}]")
else:
logger.info(
f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]"
)
logger.info(f"[{mes_name}]{userinfo.user_nickname}:{processed_plain_text}")
logger.debug(f"[{mes_name}][当前时段回复频率: {current_talk_frequency}]")
# 8. 关系处理
if global_config.relationship.enable_relationship:

View File

@@ -131,7 +131,7 @@ class MessageStorage:
if matched_message:
# 更新找到的消息记录
Messages.update(message_id=qq_message_id).where(Messages.id == matched_message.id).execute()
logger.info(f"更新消息ID成功: {matched_message.message_id} -> {qq_message_id}")
logger.debug(f"更新消息ID成功: {matched_message.message_id} -> {qq_message_id}")
else:
logger.debug("未找到匹配的消息")

View File

@@ -302,13 +302,17 @@ class NormalChat:
logger.info(f"[{self.stream_name}] 在处理上下文中检测到停止信号,退出")
break
# 并行处理兴趣消息
async def process_single_message(msg_id, message, interest_value, is_mentioned):
"""处理单个兴趣消息"""
semaphore = asyncio.Semaphore(5)
async def process_and_acquire(msg_id, message, interest_value, is_mentioned):
"""处理单个兴趣消息并管理信号量"""
async with semaphore:
try:
# 在处理每个消息前检查停止状态
if self._disabled:
logger.debug(f"[{self.stream_name}] 处理消息时检测到停用,跳过消息 {msg_id}")
logger.debug(
f"[{self.stream_name}] 处理消息时检测到停用,跳过消息 {msg_id}"
)
return
# 处理消息
@@ -329,23 +333,13 @@ class NormalChat:
# 无论如何都要清理消息
self.interest_dict.pop(msg_id, None)
# 创建并行任务列表
coroutines = []
for msg_id, (message, interest_value, is_mentioned) in items_to_process:
coroutine = process_single_message(msg_id, message, interest_value, is_mentioned)
coroutines.append(coroutine)
tasks = [
process_and_acquire(msg_id, message, interest_value, is_mentioned)
for msg_id, (message, interest_value, is_mentioned) in items_to_process
]
# 并行执行所有任务,限制并发数量避免资源过度消耗
if coroutines:
# 使用信号量控制并发数最多同时处理5个消息
semaphore = asyncio.Semaphore(5)
async def limited_process(coroutine, sem):
async with sem:
await coroutine
limited_tasks = [limited_process(coroutine, semaphore) for coroutine in coroutines]
await asyncio.gather(*limited_tasks, return_exceptions=True)
if tasks:
await asyncio.gather(*tasks, return_exceptions=True)
except asyncio.CancelledError:
logger.info(f"[{self.stream_name}] 处理上下文时任务被取消")
@@ -591,10 +585,21 @@ class NormalChat:
)
response_set, plan_result = results
except asyncio.TimeoutError:
gen_timed_out = not gen_task.done()
plan_timed_out = not plan_task.done()
timeout_details = []
if gen_timed_out:
timeout_details.append("回复生成(gen)")
if plan_timed_out:
timeout_details.append("动作规划(plan)")
timeout_source = "".join(timeout_details)
logger.warning(
f"[{self.stream_name}] 并行执行回复生成和动作规划超时 ({gather_timeout}秒),正在取消相关任务..."
f"[{self.stream_name}] {timeout_source} 任务超时 ({global_config.chat.thinking_timeout}秒),正在取消相关任务..."
)
print(f"111{self.timeout_count}")
# print(f"111{self.timeout_count}")
self.timeout_count += 1
if self.timeout_count > 5:
logger.warning(

View File

@@ -551,6 +551,9 @@ def build_readable_messages(
show_actions: 是否显示动作记录
"""
# 创建messages的深拷贝避免修改原始列表
if not messages:
return ""
copy_messages = [msg.copy() for msg in messages]
if show_actions and copy_messages:

View File

@@ -252,8 +252,7 @@ class PersonInfo(BaseModel):
know_times = FloatField(null=True) # 认识时间 (时间戳)
know_since = FloatField(null=True) # 首次印象总结时间
last_know = FloatField(null=True) # 最后一次印象总结时间
familiarity_value = IntegerField(null=True, default=0) # 熟悉0-100完全陌生到非常熟悉
liking_value = IntegerField(null=True, default=50) # 好感度0-100从非常厌恶到十分喜欢
attitude = IntegerField(null=True, default=50) # 0-100非常厌恶到十分喜欢
class Meta:
# database = db # 继承自 BaseModel

View File

@@ -321,14 +321,13 @@ MODULE_COLORS = {
# 核心模块
"main": "\033[1;97m", # 亮白色+粗体 (主程序)
"api": "\033[92m", # 亮绿色
"emoji": "\033[92m", # 亮绿色
"emoji": "\033[33m", # 亮绿色
"chat": "\033[92m", # 亮蓝色
"config": "\033[93m", # 亮黄色
"common": "\033[95m", # 亮紫色
"tools": "\033[96m", # 亮青色
"lpmm": "\033[96m",
"plugin_system": "\033[91m", # 亮红色
"experimental": "\033[97m", # 亮白色
"person_info": "\033[32m", # 绿色
"individuality": "\033[34m", # 蓝色
"manager": "\033[35m", # 紫色
@@ -339,8 +338,7 @@ MODULE_COLORS = {
"planner": "\033[36m",
"memory": "\033[34m",
"hfc": "\033[96m",
"base_action": "\033[96m",
"action_manager": "\033[32m",
"action_manager": "\033[38;5;166m",
# 关系系统
"relation": "\033[38;5;201m", # 深粉色
# 聊天相关模块
@@ -356,11 +354,9 @@ MODULE_COLORS = {
"message_storage": "\033[38;5;33m", # 深蓝色
# 专注聊天模块
"replyer": "\033[38;5;166m", # 橙色
"expressor": "\033[38;5;172m", # 黄橙色
"processor": "\033[38;5;184m", # 黄绿色
"base_processor": "\033[38;5;190m", # 绿黄色
"working_memory": "\033[38;5;22m", # 深绿色
"memory_activator": "\033[38;5;28m", # 绿色
"memory_activator": "\033[34m", # 绿色
# 插件系统
"plugin_manager": "\033[38;5;208m", # 红色
"base_plugin": "\033[38;5;202m", # 橙红色
@@ -386,11 +382,9 @@ MODULE_COLORS = {
"tool_executor": "\033[38;5;64m", # 深绿色
"base_tool": "\033[38;5;70m", # 绿色
# 工具和实用模块
"prompt": "\033[38;5;99m", # 紫色
"prompt_build": "\033[38;5;105m", # 紫色
"chat_utils": "\033[38;5;111m", # 蓝色
"chat_image": "\033[38;5;117m", # 浅蓝色
"typo_gen": "\033[38;5;123m", # 青绿色
"maibot_statistic": "\033[38;5;129m", # 紫色
# 特殊功能插件
"mute_plugin": "\033[38;5;240m", # 灰色
@@ -402,16 +396,13 @@ MODULE_COLORS = {
# 数据库和消息
"database_model": "\033[38;5;94m", # 橙褐色
"maim_message": "\033[38;5;100m", # 绿褐色
# 实验性模块
"pfc": "\033[38;5;252m", # 浅灰色
# 日志系统
"logger": "\033[38;5;8m", # 深灰色
"demo": "\033[38;5;15m", # 白色
"confirm": "\033[1;93m", # 黄色+粗体
# 模型相关
"model_utils": "\033[38;5;164m", # 紫红色
"relationship_fetcher": "\033[38;5;170m", # 浅紫色
"relationship_builder": "\033[38;5;117m", # 浅蓝色
"relationship_builder": "\033[38;5;93m", # 浅蓝色
}
RESET_COLOR = "\033[0m"

View File

@@ -48,6 +48,7 @@ person_info_default = {
"points": None,
"forgotten_points": None,
"relation_value": None,
"attitude": 50,
}

View File

@@ -1,12 +1,10 @@
from src.common.logger import get_logger
import math
from src.person_info.person_info import PersonInfoManager, get_person_info_manager
import time
import random
from src.llm_models.utils_model import LLMRequest
from src.config.config import global_config
from src.chat.utils.chat_message_builder import build_readable_messages
from src.manager.mood_manager import mood_manager
import json
from json_repair import repair_json
from datetime import datetime
@@ -21,67 +19,11 @@ logger = get_logger("relation")
class RelationshipManager:
def __init__(self):
self.positive_feedback_value = 0 # 正反馈系统
self.gain_coefficient = [1.0, 1.0, 1.1, 1.2, 1.4, 1.7, 1.9, 2.0]
self._mood_manager = None
self.relationship_llm = LLMRequest(
model=global_config.model.relation,
request_type="relationship", # 用于动作规划
)
@property
def mood_manager(self):
if self._mood_manager is None:
self._mood_manager = mood_manager
return self._mood_manager
def positive_feedback_sys(self, label: str, stance: str):
"""正反馈系统,通过正反馈系数增益情绪变化,根据情绪再影响关系变更"""
positive_list = [
"开心",
"惊讶",
"害羞",
]
negative_list = [
"愤怒",
"悲伤",
"恐惧",
"厌恶",
]
if label in positive_list:
if 7 > self.positive_feedback_value >= 0:
self.positive_feedback_value += 1
elif self.positive_feedback_value < 0:
self.positive_feedback_value = 0
elif label in negative_list:
if -7 < self.positive_feedback_value <= 0:
self.positive_feedback_value -= 1
elif self.positive_feedback_value > 0:
self.positive_feedback_value = 0
if abs(self.positive_feedback_value) > 1:
logger.debug(f"触发mood变更增益当前增益系数{self.gain_coefficient[abs(self.positive_feedback_value)]}")
def mood_feedback(self, value):
"""情绪反馈"""
mood_manager = self.mood_manager
mood_gain = mood_manager.current_mood.valence**2 * math.copysign(1, value * mood_manager.current_mood.valence)
value += value * mood_gain
logger.debug(f"当前relationship增益系数{mood_gain:.3f}")
return value
def feedback_to_mood(self, mood_value):
"""对情绪的反馈"""
coefficient = self.gain_coefficient[abs(self.positive_feedback_value)]
if mood_value > 0 and self.positive_feedback_value > 0 or mood_value < 0 and self.positive_feedback_value < 0:
return mood_value * coefficient
else:
return mood_value / coefficient
@staticmethod
async def is_known_some_one(platform, user_id):
"""判断是否认识某人"""
@@ -168,19 +110,6 @@ class RelationshipManager:
return relation_prompt
async def _update_list_field(self, person_id: str, field_name: str, new_items: list) -> None:
"""更新列表类型的字段,将新项目添加到现有列表中
Args:
person_id: 用户ID
field_name: 字段名称
new_items: 新的项目列表
"""
person_info_manager = get_person_info_manager()
old_items = await person_info_manager.get_value(person_id, field_name) or []
updated_items = list(set(old_items + [item for item in new_items if isinstance(item, str) and item]))
await person_info_manager.update_one_field(person_id, field_name, updated_items)
async def update_person_impression(self, person_id, timestamp, bot_engaged_messages=None):
"""更新用户印象
@@ -194,6 +123,7 @@ class RelationshipManager:
person_info_manager = get_person_info_manager()
person_name = await person_info_manager.get_value(person_id, "person_name")
nickname = await person_info_manager.get_value(person_id, "nickname")
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
alias_str = ", ".join(global_config.bot.alias_names)
# personality_block =get_individuality().get_personality_prompt(x_person=2, level=2)
@@ -240,7 +170,9 @@ class RelationshipManager:
name_mapping[replace_person_name] = f"用户{current_user}{user_count if user_count > 1 else ''}"
current_user = chr(ord(current_user) + 1)
readable_messages = self.build_focus_readable_messages(messages=user_messages, target_person_id=person_id)
readable_messages = build_readable_messages(
messages=user_messages, replace_bot_name=True, timestamp_mode="normal_no_YMD", truncate=True
)
if not readable_messages:
return
@@ -385,7 +317,52 @@ class RelationshipManager:
# 如果points超过10条按权重随机选择多余的条目移动到forgotten_points
if len(current_points) > 10:
current_points = await self._update_impression(person_id, current_points, timestamp)
# 更新数据库
await person_info_manager.update_one_field(
person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None)
)
await person_info_manager.update_one_field(person_id, "know_times", know_times + 1)
know_since = await person_info_manager.get_value(person_id, "know_since") or 0
if know_since == 0:
await person_info_manager.update_one_field(person_id, "know_since", timestamp)
await person_info_manager.update_one_field(person_id, "last_know", timestamp)
logger.debug(f"{person_name} 的印象更新完成")
async def _update_impression(self, person_id, current_points, timestamp):
# 获取现有forgotten_points
person_info_manager = get_person_info_manager()
person_name = await person_info_manager.get_value(person_id, "person_name")
nickname = await person_info_manager.get_value(person_id, "nickname")
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
attitude = await person_info_manager.get_value(person_id, "attitude") or 50
# 根据熟悉度,调整印象和简短印象的最大长度
if know_times > 300:
max_impression_length = 2000
max_short_impression_length = 800
elif know_times > 100:
max_impression_length = 1000
max_short_impression_length = 500
elif know_times > 50:
max_impression_length = 500
max_short_impression_length = 300
elif know_times > 10:
max_impression_length = 200
max_short_impression_length = 100
else:
max_impression_length = 100
max_short_impression_length = 50
# 根据好感度,调整印象和简短印象的最大长度
attitude_multiplier = (abs(100 - attitude) / 100) + 1
max_impression_length = max_impression_length * attitude_multiplier
max_short_impression_length = max_short_impression_length * attitude_multiplier
forgotten_points = await person_info_manager.get_value(person_id, "forgotten_points") or []
if isinstance(forgotten_points, str):
try:
@@ -436,7 +413,7 @@ class RelationshipManager:
current_points = remaining_points
forgotten_points.extend(points_to_move)
# 检查forgotten_points是否达到5
# 检查forgotten_points是否达到10
if len(forgotten_points) >= 10:
# 构建压缩总结提示词
alias_str = ", ".join(global_config.bot.alias_names)
@@ -466,7 +443,7 @@ class RelationshipManager:
你记得ta最近做的事
{points_text}
请输出一段平文本,以陈诉自白的语气,输出你对{person_name}的了解,不要输出任何其他内容。
请输出一段{max_impression_length}字左右的平文本,以陈诉自白的语气,输出你对{person_name}的了解,不要输出任何其他内容。
"""
# 调用LLM生成压缩总结
compressed_summary, _ = await self.relationship_llm.generate_response_async(prompt=compress_prompt)
@@ -487,7 +464,7 @@ class RelationshipManager:
1.对{person_name}的直观印象
2.{global_config.bot.nickname}{person_name}的关系
3.{person_name}的关键信息
请输出一段平文本,以陈诉自白的语气,输出你对{person_name}的概括,不要输出任何其他内容。
请输出一段{max_short_impression_length}字左右的平文本,以陈诉自白的语气,输出你对{person_name}的概括,不要输出任何其他内容。
"""
compressed_short_summary, _ = await self.relationship_llm.generate_response_async(
prompt=compress_short_prompt
@@ -503,15 +480,9 @@ class RelationshipManager:
你最近对{person_name}的了解如下:
{points_text}
请根据以上信息,评估你和{person_name}的关系,给出两个维度的值:熟悉度和好感度。
1. 了解度 (familiarity_value): 0-100的整数表示这些信息让你对ta的了解增进程度。
- 0: 没有任何进一步了解
- 25: 有点进一步了解
- 50: 有进一步了解
- 75: 有更多了解
- 100: 有了更多重要的了解
请根据以上信息,评估你和{person_name}的关系,给出你对ta的态度。
2. **好感度 (liking_value)**: 0-100的整数表示这些信息让你对ta的
态度: 0-100的整数表示这些信息让你对ta的态度
- 0: 非常厌恶
- 25: 有点反感
- 50: 中立/无感(或者文本中无法明显看出)
@@ -520,8 +491,7 @@ class RelationshipManager:
请严格按照json格式输出不要有其他多余内容
{{
"familiarity_value": <0-100之间的整数>,
"liking_value": <0-100之间的整数>
"attitude": <0-100之间的整数>,
}}
"""
try:
@@ -531,28 +501,25 @@ class RelationshipManager:
relation_value_json = json.loads(repair_json(relation_value_response))
# 从LLM获取新生成的值
new_familiarity_value = int(relation_value_json.get("familiarity_value", 0))
new_liking_value = int(relation_value_json.get("liking_value", 50))
new_attitude = int(relation_value_json.get("attitude", 50))
# 获取当前的关系值
old_familiarity_value = await person_info_manager.get_value(person_id, "familiarity_value") or 0
liking_value = await person_info_manager.get_value(person_id, "liking_value") or 50
old_attitude = await person_info_manager.get_value(person_id, "attitude") or 50
# 更新熟悉度
if new_familiarity_value > 25:
familiarity_value = old_familiarity_value + (new_familiarity_value - 25) / 75
if new_attitude > 25:
attitude = old_attitude + (new_attitude - 25) / 75
else:
familiarity_value = old_familiarity_value
attitude = old_attitude
# 更新好感度
if new_liking_value > 50:
liking_value += (new_liking_value - 50) / 50
elif new_liking_value < 50:
liking_value -= (50 - new_liking_value) / 50 * 1.5
if new_attitude > 50:
attitude += (new_attitude - 50) / 50
elif new_attitude < 50:
attitude -= (50 - new_attitude) / 50 * 1.5
await person_info_manager.update_one_field(person_id, "familiarity_value", familiarity_value)
await person_info_manager.update_one_field(person_id, "liking_value", liking_value)
logger.info(f"更新了与 {person_name} 的关系值: 熟悉度={familiarity_value}, 好感度={liking_value}")
await person_info_manager.update_one_field(person_id, "attitude", attitude)
logger.info(f"更新了与 {person_name} 的态度: {attitude}")
except (json.JSONDecodeError, ValueError, TypeError) as e:
logger.error(f"解析relation_value JSON失败或值无效: {e}, 响应: {relation_value_response}")
@@ -566,28 +533,7 @@ class RelationshipManager:
person_id, "forgotten_points", json.dumps(forgotten_points, ensure_ascii=False, indent=None)
)
# 更新数据库
await person_info_manager.update_one_field(
person_id, "points", json.dumps(current_points, ensure_ascii=False, indent=None)
)
know_times = await person_info_manager.get_value(person_id, "know_times") or 0
await person_info_manager.update_one_field(person_id, "know_times", know_times + 1)
know_since = await person_info_manager.get_value(person_id, "know_since") or 0
if know_since == 0:
await person_info_manager.update_one_field(person_id, "know_since", timestamp)
await person_info_manager.update_one_field(person_id, "last_know", timestamp)
logger.info(f"{person_name} 的印象更新完成")
def build_focus_readable_messages(self, messages: list, target_person_id: str = None) -> str:
"""格式化消息,处理所有消息内容"""
if not messages:
return ""
# 直接处理所有消息,不进行过滤
return build_readable_messages(
messages=messages, replace_bot_name=True, timestamp_mode="normal_no_YMD", truncate=True
)
return current_points
def calculate_time_weight(self, point_time: str, current_time: str) -> float:
"""计算基于时间的权重系数"""

View File

@@ -103,6 +103,7 @@ class NoReplyAction(BaseAction):
logger.info(f"{self.log_prefix} 选择不回复(第{count}次),开始摸鱼,原因: {reason}")
# 进入等待状态
while True:
current_time = time.time()
elapsed_time = current_time - start_time
@@ -141,19 +142,9 @@ class NoReplyAction(BaseAction):
# 判定条件累计3条消息或等待超过5秒且有新消息
time_since_last_judge = current_time - last_judge_time
should_judge = (
new_message_count >= 3 # 累计3条消息
or (new_message_count > 0 and time_since_last_judge >= 15.0) # 等待超过5秒且有新消息
)
should_judge, trigger_reason = self._should_trigger_judge(new_message_count, time_since_last_judge)
if should_judge and time_since_last_judge >= min_judge_interval:
# 判断触发原因
trigger_reason = ""
if new_message_count >= 3:
trigger_reason = f"累计{new_message_count}条消息"
elif time_since_last_judge >= 10.0:
trigger_reason = f"等待{time_since_last_judge:.1f}秒且有新消息"
logger.info(f"{self.log_prefix} 触发判定({trigger_reason}),进行智能判断...")
# 获取最近的消息内容用于判断
@@ -166,7 +157,10 @@ class NoReplyAction(BaseAction):
if recent_messages:
# 使用message_api构建可读的消息字符串
messages_text = message_api.build_readable_messages(
messages=recent_messages, timestamp_mode="normal_no_YMD", truncate=False, show_actions=False
messages=recent_messages,
timestamp_mode="normal_no_YMD",
truncate=False,
show_actions=False,
)
# 获取身份信息
@@ -189,81 +183,13 @@ class NoReplyAction(BaseAction):
history_block += "\n"
# 检查过去10分钟的发言频率
frequency_block = ""
should_skip_llm_judge = False # 是否跳过LLM判断
try:
# 获取过去10分钟的所有消息
past_10min_time = current_time - 600 # 10分钟前
all_messages_10min = message_api.get_messages_by_time_in_chat(
chat_id=self.chat_id,
start_time=past_10min_time,
end_time=current_time,
)
# 手动过滤bot自己的消息
bot_message_count = 0
if all_messages_10min:
user_id = global_config.bot.qq_account
for message in all_messages_10min:
# 检查消息发送者是否是bot
sender_id = message.get("user_id", "")
if sender_id == user_id:
bot_message_count += 1
talk_frequency_threshold = global_config.chat.get_current_talk_frequency(self.chat_id) * 10
if bot_message_count > talk_frequency_threshold:
over_count = bot_message_count - talk_frequency_threshold
# 根据超过的数量设置不同的提示词和跳过概率
skip_probability = 0
if over_count <= 3:
frequency_block = "你感觉稍微有些累,回复的有点多了。\n"
elif over_count <= 5:
frequency_block = "你今天说话比较多,感觉有点疲惫,想要稍微休息一下。\n"
elif over_count <= 8:
frequency_block = "你发现自己说话太多了,感觉很累,想要安静一会儿,除非有重要的事情否则不想回复。\n"
skip_probability = self._skip_probability
else:
frequency_block = "你感觉非常累,想要安静一会儿。\n"
skip_probability = 1
# 根据配置和概率决定是否跳过LLM判断
if self._skip_judge_when_tired and random.random() < skip_probability:
should_skip_llm_judge = True
logger.info(
f"{self.log_prefix} 发言过多(超过{over_count}条)随机决定跳过此次LLM判断(概率{skip_probability * 100:.0f}%)"
)
logger.info(
f"{self.log_prefix} 过去10分钟发言{bot_message_count}条,超过阈值{talk_frequency_threshold},添加疲惫提示"
)
else:
# 回复次数少时的正向提示
under_count = talk_frequency_threshold - bot_message_count
if under_count >= talk_frequency_threshold * 0.8: # 回复很少少于20%
frequency_block = "你感觉精力充沛,状态很好,积极参与聊天。\n"
elif under_count >= talk_frequency_threshold * 0.5: # 回复较少少于50%
frequency_block = "你感觉状态不错。\n"
else: # 刚好达到阈值
frequency_block = ""
logger.info(
f"{self.log_prefix} 过去10分钟发言{bot_message_count}条,未超过阈值{talk_frequency_threshold},添加正向提示"
)
except Exception as e:
logger.warning(f"{self.log_prefix} 检查发言频率时出错: {e}")
frequency_block = ""
frequency_block, should_skip_llm_judge = self._get_fatigue_status(current_time)
# 如果决定跳过LLM判断直接更新时间并继续等待
if should_skip_llm_judge:
logger.info(f"{self.log_prefix} 疲劳,继续等待。")
last_judge_time = time.time() # 更新判断时间,避免立即重新判断
start_time = current_time # 更新消息检查的起始时间,以避免重复判断
continue # 跳过本次LLM判断继续循环等待
# 构建判断上下文
@@ -355,14 +281,13 @@ class NoReplyAction(BaseAction):
last_judge_time = time.time() # 异常时也更新时间,避免频繁重试
# 每10秒输出一次等待状态
logger.info(f"{self.log_prefix} 开始等待新消息...")
if elapsed_time < 60:
if int(elapsed_time) % 10 == 0 and int(elapsed_time) > 0:
logger.debug(f"{self.log_prefix} 已等待{elapsed_time:.0f}秒,等待新消息...")
await asyncio.sleep(1)
else:
if int(elapsed_time) % 60 == 0 and int(elapsed_time) > 0:
logger.debug(f"{self.log_prefix} 已等待{elapsed_time / 60:.0f}分钟,等待新消息...")
if int(elapsed_time) % 180 == 0 and int(elapsed_time) > 0:
logger.info(f"{self.log_prefix} 已等待{elapsed_time / 60:.0f}分钟,等待新消息...")
await asyncio.sleep(1)
# 短暂等待后继续检查
@@ -380,6 +305,109 @@ class NoReplyAction(BaseAction):
)
return False, f"不回复动作执行失败: {e}"
def _should_trigger_judge(self, new_message_count: int, time_since_last_judge: float) -> Tuple[bool, str]:
"""判断是否应该触发智能判断,并返回触发原因。
Args:
new_message_count: 新消息的数量。
time_since_last_judge: 距离上次判断的时间。
Returns:
一个元组 (should_judge, reason)。
- should_judge: 一个布尔值,指示是否应该触发判断。
- reason: 触发判断的原因字符串。
"""
# 判定条件累计3条消息或等待超过15秒且有新消息
should_judge_flag = new_message_count >= 3 or (new_message_count > 0 and time_since_last_judge >= 15.0)
if not should_judge_flag:
return False, ""
# 判断触发原因
if new_message_count >= 3:
return True, f"累计{new_message_count}条消息"
elif new_message_count > 0 and time_since_last_judge >= 15.0:
return True, f"等待{time_since_last_judge:.1f}秒且有新消息"
return False, ""
def _get_fatigue_status(self, current_time: float) -> Tuple[str, bool]:
"""
根据最近的发言频率生成疲劳提示,并决定是否跳过判断。
Args:
current_time: 当前时间戳。
Returns:
一个元组 (frequency_block, should_skip_judge)。
- frequency_block: 疲劳度相关的提示字符串。
- should_skip_judge: 是否应该跳过LLM判断的布尔值。
"""
try:
# 获取过去10分钟的所有消息
past_10min_time = current_time - 600 # 10分钟前
all_messages_10min = message_api.get_messages_by_time_in_chat(
chat_id=self.chat_id,
start_time=past_10min_time,
end_time=current_time,
)
# 手动过滤bot自己的消息
bot_message_count = 0
if all_messages_10min:
user_id = global_config.bot.qq_account
for message in all_messages_10min:
sender_id = message.get("user_id", "")
if sender_id == user_id:
bot_message_count += 1
talk_frequency_threshold = global_config.chat.get_current_talk_frequency(self.chat_id) * 10
if bot_message_count > talk_frequency_threshold:
over_count = bot_message_count - talk_frequency_threshold
skip_probability = 0
frequency_block = ""
if over_count <= 3:
frequency_block = "你感觉稍微有些累,回复的有点多了。\n"
elif over_count <= 5:
frequency_block = "你今天说话比较多,感觉有点疲惫,想要稍微休息一下。\n"
elif over_count <= 8:
frequency_block = "你发现自己说话太多了,感觉很累,想要安静一会儿,除非有重要的事情否则不想回复。\n"
skip_probability = self._skip_probability
else:
frequency_block = "你感觉非常累,想要安静一会儿。\n"
skip_probability = 1
should_skip_judge = self._skip_judge_when_tired and random.random() < skip_probability
if should_skip_judge:
logger.info(
f"{self.log_prefix} 发言过多(超过{over_count}条)随机决定跳过此次LLM判断(概率{skip_probability * 100:.0f}%)"
)
logger.info(
f"{self.log_prefix} 过去10分钟发言{bot_message_count}条,超过阈值{talk_frequency_threshold},添加疲惫提示"
)
return frequency_block, should_skip_judge
else:
# 回复次数少时的正向提示
under_count = talk_frequency_threshold - bot_message_count
frequency_block = ""
if under_count >= talk_frequency_threshold * 0.8:
frequency_block = "你感觉精力充沛,状态很好,积极参与聊天。\n"
elif under_count >= talk_frequency_threshold * 0.5:
frequency_block = "你感觉状态不错。\n"
logger.info(
f"{self.log_prefix} 过去10分钟发言{bot_message_count}条,未超过阈值{talk_frequency_threshold},添加正向提示"
)
return frequency_block, False
except Exception as e:
logger.warning(f"{self.log_prefix} 检查发言频率时出错: {e}")
return "", False
def _check_no_activity_and_exit_focus(self, current_time: float) -> bool:
"""检查过去10分钟是否完全没有发言决定是否退出专注模式

View File

@@ -60,6 +60,11 @@ class TTSAction(BaseAction):
# 发送TTS消息
await self.send_custom(message_type="tts_text", content=processed_text)
# 记录动作信息
await self.store_action_info(
action_build_into_prompt=True, action_prompt_display="已经发送了语音消息。", action_done=True
)
logger.info(f"{self.log_prefix} TTS动作执行成功文本长度: {len(processed_text)}")
return True, "TTS动作执行成功"

View File

@@ -187,7 +187,11 @@ class ToolExecutor:
tool_results.append(tool_info)
logger.info(f"{self.log_prefix}工具{tool_name}执行成功,类型: {tool_info['type']}")
logger.debug(f"{self.log_prefix}工具{tool_name}结果内容: {tool_info['content'][:200]}...")
content = tool_info["content"]
if not isinstance(content, (str, list, tuple)):
content = str(content)
preview = content[:200]
logger.debug(f"{self.log_prefix}工具{tool_name}结果内容: {preview}...")
except Exception as e:
logger.error(f"{self.log_prefix}工具{tool_name}执行失败: {e}")