better:优化表情包处理,优化logger显示

This commit is contained in:
SengokuCola
2025-04-30 18:16:38 +08:00
parent 5963214d95
commit 09b1807132
10 changed files with 69 additions and 54 deletions

View File

@@ -621,22 +621,22 @@ CHAT_IMAGE_STYLE_CONFIG = {
},
}
# 兴趣log
INTEREST_STYLE_CONFIG = {
# HFC log
HFC_STYLE_CONFIG = {
"advanced": {
"console_format": (
"<white>{time:YYYY-MM-DD HH:mm:ss}</white> | "
"<level>{level: <8}</level> | "
"<light-yellow>兴趣</light-yellow> | "
"<light-green>专注聊天</light-green> | "
"<level>{message}</level>"
),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}",
},
"simple": {
"console_format": (
"<level>{time:MM-DD HH:mm}</level> | <light-green>兴趣</light-green> | <light-green>{message}</light-green>"
"<level>{time:MM-DD HH:mm}</level> | <light-green>专注聊天</light-green> | <light-green>{message}</light-green>"
),
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 兴趣 | {message}",
"file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 专注聊天 | {message}",
},
}
@@ -847,7 +847,7 @@ CONFIG_STYLE_CONFIG = CONFIG_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else CONFIG
TOOL_USE_STYLE_CONFIG = TOOL_USE_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else TOOL_USE_STYLE_CONFIG["advanced"]
PFC_STYLE_CONFIG = PFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PFC_STYLE_CONFIG["advanced"]
LPMM_STYLE_CONFIG = LPMM_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else LPMM_STYLE_CONFIG["advanced"]
INTEREST_STYLE_CONFIG = INTEREST_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else INTEREST_STYLE_CONFIG["advanced"]
HFC_STYLE_CONFIG = HFC_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else HFC_STYLE_CONFIG["advanced"]
TIANYI_STYLE_CONFIG = TIANYI_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else TIANYI_STYLE_CONFIG["advanced"]
MODEL_UTILS_STYLE_CONFIG = MODEL_UTILS_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else MODEL_UTILS_STYLE_CONFIG["advanced"]
PROMPT_STYLE_CONFIG = PROMPT_STYLE_CONFIG["simple"] if SIMPLE_OUTPUT else PROMPT_STYLE_CONFIG["advanced"]

View File

@@ -23,7 +23,7 @@ from src.common.logger import (
PFC_ACTION_PLANNER_STYLE_CONFIG,
MAI_STATE_CONFIG,
LPMM_STYLE_CONFIG,
INTEREST_STYLE_CONFIG,
HFC_STYLE_CONFIG,
TIANYI_STYLE_CONFIG,
REMOTE_STYLE_CONFIG,
TOPIC_STYLE_CONFIG,
@@ -68,7 +68,7 @@ MODULE_LOGGER_CONFIGS = {
"pfc_action_planner": PFC_ACTION_PLANNER_STYLE_CONFIG, # PFC私聊规划
"mai_state": MAI_STATE_CONFIG, # 麦麦状态
"lpmm": LPMM_STYLE_CONFIG, # LPMM
"interest": INTEREST_STYLE_CONFIG, # 兴趣
"hfc": HFC_STYLE_CONFIG, # HFC
"tianyi": TIANYI_STYLE_CONFIG, # 天依
"remote": REMOTE_STYLE_CONFIG, # 远程
"topic": TOPIC_STYLE_CONFIG, # 话题

View File

@@ -62,7 +62,7 @@ def register_tool(tool_class: Type[BaseTool]):
raise ValueError(f"工具类 {tool_class.__name__} 没有定义 name 属性")
TOOL_REGISTRY[tool_name] = tool_class
logger.info(f"已注册工具: {tool_name}")
logger.info(f"已注册: {tool_name}")
def discover_tools():

View File

@@ -200,12 +200,12 @@ class BackgroundTaskManager:
async def _perform_absent_into_chat(self):
"""调用llm检测是否转换ABSENT-CHAT状态"""
logger.info("[状态评估任务] 开始基于LLM评估子心流状态...")
logger.debug("[状态评估任务] 开始基于LLM评估子心流状态...")
await self.subheartflow_manager.sbhf_absent_into_chat()
async def _normal_chat_timeout_check_work(self):
"""检查处于CHAT状态的子心流是否因长时间未发言而超时并将其转为ABSENT"""
logger.info("[聊天超时检查] 开始检查处于CHAT状态的子心流...")
logger.debug("[聊天超时检查] 开始检查处于CHAT状态的子心流...")
await self.subheartflow_manager.sbhf_chat_into_absent()
async def _perform_cleanup_work(self):

View File

@@ -299,7 +299,7 @@ class SubHeartflow:
chat_stream = chat_manager.get_stream(self.chat_id)
self.normal_chat_instance = NormalChat(chat_stream=chat_stream, interest_dict=self.get_interest_dict())
logger.info(f"{log_prefix} 启动 NormalChat 随便水群...")
logger.info(f"{log_prefix} 开始普通聊天,随便水群...")
await self.normal_chat_instance.start_chat() # <--- 修正:调用 start_chat
return True
except Exception as e:
@@ -311,7 +311,7 @@ class SubHeartflow:
async def _stop_heart_fc_chat(self):
"""停止并清理 HeartFChatting 实例"""
if self.heart_fc_instance:
logger.info(f"{self.log_prefix} 关闭 HeartFChatting 实例...")
logger.debug(f"{self.log_prefix} 结束专注聊天...")
try:
await self.heart_fc_instance.shutdown()
except Exception as e:
@@ -386,7 +386,7 @@ class SubHeartflow:
# 移除限额检查逻辑
logger.debug(f"{log_prefix} 准备进入或保持 聊天 状态")
if await self._start_normal_chat():
logger.info(f"{log_prefix} 成功进入或保持 NormalChat 状态。")
# logger.info(f"{log_prefix} 成功进入或保持 NormalChat 状态。")
state_changed = True
else:
logger.error(f"{log_prefix} 启动 NormalChat 失败,无法进入 CHAT 状态。")
@@ -416,7 +416,7 @@ class SubHeartflow:
self.history_chat_state.append((current_state, self.chat_state_last_time))
logger.info(
f"{log_prefix} 麦麦的聊天状态从 {current_state.value} (持续了 {self.chat_state_last_time} 秒) 变更为 {new_state.value}"
f"{log_prefix} 麦麦的聊天状态从 {current_state.value} (持续了 {int(self.chat_state_last_time)} 秒) 变更为 {new_state.value}"
)
self.chat_state.chat_status = new_state

View File

@@ -1,7 +1,7 @@
import asyncio
import time
import random
from typing import Dict, Any, Optional, List
from typing import Dict, Any, Optional, List, Tuple
import json # 导入 json 模块
import functools # <-- 新增导入
@@ -23,6 +23,7 @@ from src.individuality.individuality import Individuality
import traceback
# 初始化日志记录器
logger = get_logger("subheartflow_manager")
@@ -358,7 +359,7 @@ class SubHeartflowManager:
# 3. 检查 CHAT 上限
current_chat_count = self.count_subflows_by_state_nolock(ChatState.CHAT)
if current_chat_count >= chat_limit:
logger.debug(
logger.info(
f"{log_prefix} 想看看能不能聊,但是聊天太多了, ({current_chat_count}/{chat_limit}) 满了。"
)
return # 满了,这次就算了
@@ -419,14 +420,22 @@ class SubHeartflowManager:
# --- 结束修改 ---
# --- 4. LLM 评估是否想聊 ---
yao_kai_shi_liao_ma = await self._llm_evaluate_state_transition(prompt)
yao_kai_shi_liao_ma, reason = await self._llm_evaluate_state_transition(prompt)
if reason:
if yao_kai_shi_liao_ma:
logger.info(f"{log_prefix} 打算开始聊,原因是: {reason}")
else:
logger.info(f"{log_prefix} 不打算聊,原因是: {reason}")
else:
logger.info(f"{log_prefix} 结果: {yao_kai_shi_liao_ma}")
if yao_kai_shi_liao_ma is None:
logger.debug(f"{log_prefix} 问AI想不想聊失败了这次算了。")
return # 评估失败,结束
if not yao_kai_shi_liao_ma:
logger.info(f"{log_prefix} 现在不想聊这个群。")
# logger.info(f"{log_prefix} 现在不想聊这个群。")
return # 不想聊,结束
# --- 5. AI想聊再次检查额度并尝试转换 ---
@@ -434,7 +443,7 @@ class SubHeartflowManager:
current_chat_count_before_change = self.count_subflows_by_state_nolock(ChatState.CHAT)
if current_chat_count_before_change < chat_limit:
logger.info(
f"{log_prefix} 想聊,而且还有空位 ({current_chat_count_before_change}/{chat_limit}),这就去聊!"
f"{log_prefix} 想聊,而且还有精力 ({current_chat_count_before_change}/{chat_limit}),这就去聊!"
)
await sub_hf_to_evaluate.change_chat_state(ChatState.CHAT)
# 确认转换成功
@@ -492,7 +501,7 @@ class SubHeartflowManager:
should_deactivate = True
reason = f"超过 {NORMAL_CHAT_TIMEOUT_SECONDS / 60:.0f} 分钟没 BB"
logger.info(
f"{log_prefix} 检测到超时 ({reason})准备转为 ABSENT。上次活动时间: {last_bot_dong_zuo_time:.0f}"
f"{log_prefix} 太久没有发言 ({reason})不看了。上次活动时间: {last_bot_dong_zuo_time:.0f}"
)
# else:
# logger.debug(f"{log_prefix} Bot活动时间未超时 ({time_since_last_bb:.0f}s < {NORMAL_CHAT_TIMEOUT_SECONDS}s),保持 CHAT 状态。")
@@ -509,25 +518,24 @@ class SubHeartflowManager:
# --- 执行状态转换(如果超时) ---
if should_deactivate:
logger.info(f"{log_prefix} 因超时 ({reason}),尝试转换为 ABSENT 状态。")
logger.debug(f"{log_prefix} 因超时 ({reason}),尝试转换为 ABSENT 状态。")
await sub_hf.change_chat_state(ChatState.ABSENT)
# 再次检查确保状态已改变
if sub_hf.chat_state.chat_status == ChatState.ABSENT:
transitioned_to_absent += 1
logger.info(f"{log_prefix} 已成功转换为 ABSENT 状态")
logger.info(f"{log_prefix} 不看了")
else:
logger.warning(f"{log_prefix} 尝试因超时转换为 ABSENT 失败。")
if transitioned_to_absent > 0:
logger.info(
logger.debug(
f"{log_prefix_task} 完成,共检查 {checked_count} 个子心流,{transitioned_to_absent} 个因超时转为 ABSENT。"
)
# else:
# logger.debug(f"{log_prefix_task} 完成,共检查 {checked_count} 个子心流,无超时转换。")
# --- 结束新增 ---
async def _llm_evaluate_state_transition(self, prompt: str) -> Optional[bool]:
async def _llm_evaluate_state_transition(self, prompt: str) -> Tuple[Optional[bool], Optional[str]]:
"""
使用 LLM 评估是否应进行状态转换,期望 LLM 返回 JSON 格式。
@@ -544,7 +552,7 @@ class SubHeartflowManager:
response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt)
# logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估")
logger.debug(f"{log_prefix} 原始输入: {prompt}")
logger.debug(f"{log_prefix} 原始响应: {response_text}")
logger.debug(f"{log_prefix} 原始评估结果: {response_text}")
# --- 解析 JSON 响应 ---
try:
@@ -555,34 +563,36 @@ class SubHeartflowManager:
data = json.loads(cleaned_response)
decision = data.get("decision") # 使用 .get() 避免 KeyError
reason = data.get("reason")
if isinstance(decision, bool):
logger.debug(f"{log_prefix} LLM评估结果 (来自JSON): {'建议转换' if decision else '建议不转换'}")
return decision
return decision , reason
else:
logger.warning(
f"{log_prefix} LLM 返回的 JSON 中 'decision' 键的值不是布尔型: {decision}。响应: {response_text}"
)
return None # 值类型不正确
return None, None # 值类型不正确
except json.JSONDecodeError as json_err:
logger.warning(f"{log_prefix} LLM 返回的响应不是有效的 JSON: {json_err}。响应: {response_text}")
# 尝试在非JSON响应中查找关键词作为后备方案 (可选)
if "true" in response_text.lower():
logger.debug(f"{log_prefix} 在非JSON响应中找到 'true',解释为建议转换")
return True
return True, None
if "false" in response_text.lower():
logger.debug(f"{log_prefix} 在非JSON响应中找到 'false',解释为建议不转换")
return False
return None # JSON 解析失败,也未找到关键词
return False, None
return None, None # JSON 解析失败,也未找到关键词
except Exception as parse_err: # 捕获其他可能的解析错误
logger.warning(f"{log_prefix} 解析 LLM JSON 响应时发生意外错误: {parse_err}。响应: {response_text}")
return None
return None, None
except Exception as e:
logger.error(f"{log_prefix} 调用 LLM 或处理其响应时出错: {e}", exc_info=True)
traceback.print_exc()
return None # LLM 调用或处理失败
return None, None # LLM 调用或处理失败
def count_subflows_by_state(self, state: ChatState) -> int:
"""统计指定状态的子心流数量"""

View File

@@ -159,16 +159,16 @@ class MessageManager:
logger.warning("Processor task already running.")
return
self._processor_task = asyncio.create_task(self._start_processor_loop())
logger.info("MessageManager processor task started.")
logger.debug("MessageManager processor task started.")
def stop(self):
"""停止后台处理器任务。"""
self._running = False
if hasattr(self, "_processor_task") and not self._processor_task.done():
self._processor_task.cancel()
logger.info("MessageManager processor task stopping.")
logger.debug("MessageManager processor task stopping.")
else:
logger.info("MessageManager processor task not running or already stopped.")
logger.debug("MessageManager processor task not running or already stopped.")
async def get_container(self, chat_id: str) -> MessageContainer:
"""获取或创建聊天流的消息容器 (异步,使用锁)"""

View File

@@ -106,7 +106,7 @@ class MaiEmoji:
os.remove(destination_path)
os.rename(source_path, destination_path)
logger.info(f"[移动] 文件从 {source_path} 移动到 {destination_path}")
logger.debug(f"[移动] 文件从 {source_path} 移动到 {destination_path}")
# 更新实例的路径属性为新目录
self.path = EMOJI_REGISTED_DIR
except Exception as move_error:
@@ -131,7 +131,7 @@ class MaiEmoji:
# 使用upsert确保记录存在或被更新
db["emoji"].update_one({"hash": self.hash}, {"$set": emoji_record}, upsert=True)
logger.success(f"[注册] 表情包信息保存到数据库: {self.description}")
logger.success(f"[注册] 表情包信息保存到数据库: {self.description[:30]}...")
return True
@@ -158,7 +158,7 @@ class MaiEmoji:
if os.path.exists(os.path.join(self.path, self.filename)):
try:
os.remove(os.path.join(self.path, self.filename))
logger.info(f"[删除] 文件: {os.path.join(self.path, self.filename)}")
logger.debug(f"[删除] 文件: {os.path.join(self.path, self.filename)}")
except Exception as e:
logger.error(f"[错误] 删除文件失败 {os.path.join(self.path, self.filename)}: {str(e)}")
# 继续执行,即使文件删除失败也尝试删除数据库记录
@@ -168,7 +168,7 @@ class MaiEmoji:
deleted_in_db = result.deleted_count > 0
if deleted_in_db:
logger.success(f"[删除] 成功删除表情包记录: {self.description}")
logger.info(f"[删除] 表情包 {self.filename} 无对应文件,已删除")
# 3. 标记对象已被删除
self.is_deleted = True
@@ -195,7 +195,7 @@ class EmojiManager:
self._scan_task = None
self.vlm = LLMRequest(model=global_config.vlm, temperature=0.3, max_tokens=1000, request_type="emoji")
self.llm_emotion_judge = LLMRequest(
model=global_config.llm_summary, max_tokens=600, temperature=0.8, request_type="emoji"
model=global_config.llm_normal, max_tokens=600, request_type="emoji"
) # 更高的温度更少的token后续可以根据情绪来调整温度
self.emoji_num = 0
@@ -682,7 +682,7 @@ class EmojiManager:
if register_success:
self.emoji_objects.append(new_emoji)
self.emoji_num += 1
logger.success(f"[成功] 注册表情包: {new_emoji.description}")
logger.success(f"[成功] 注册: {new_emoji.filename}")
return True
else:
logger.error(f"[错误] 注册表情包到数据库失败: {new_emoji.filename}")
@@ -719,10 +719,10 @@ class EmojiManager:
# 调用AI获取描述
if image_format == "gif" or image_format == "GIF":
image_base64 = image_manager.transform_gif(image_base64)
prompt = "这是一个动态图表情包,每一张图代表了动态图的某一帧,黑色背景代表透明,描述一下表情包表达的情感和内容,你可以关注其幽默和讽刺意味,必须从互联网梗,meme的角度去分析"
prompt = "这是一个动态图表情包,每一张图代表了动态图的某一帧,黑色背景代表透明,描述一下表情包表达的情感和内容,你可以关注其幽默和讽刺意味,动用贴吧,微博,小红书的知识,必须从互联网梗,meme的角度去分析"
description, _ = await self.vlm.generate_response_for_image(prompt, image_base64, "jpg")
else:
prompt = "这是一个表情包,请详细描述一下表情包所表达的情感和内容,你可以关注其幽默和讽刺意味,必须从互联网梗,meme的角度去分析"
prompt = "这是一个表情包,请详细描述一下表情包所表达的情感和内容,你可以关注其幽默和讽刺意味,动用贴吧,微博,小红书的知识,必须从互联网梗,meme的角度去分析"
description, _ = await self.vlm.generate_response_for_image(prompt, image_base64, image_format)
# 审核表情包
@@ -797,7 +797,7 @@ class EmojiManager:
if register_success:
self.emoji_objects.append(new_emoji)
self.emoji_num += 1
logger.success(f"[成功] 注册表情包: {filename}")
logger.success(f"[成功] 注册: {filename}")
return True
else:
logger.error(f"[错误] 注册表情包到数据库失败: {filename}")
@@ -814,7 +814,7 @@ class EmojiManager:
当目录中文件数超过50时会全部删除
"""
logger.info("[清理] 开始清理临时表情包...")
logger.info("[清理] 开始清理缓存...")
# 清理emoji目录
emoji_dir = os.path.join(BASE_DIR, "emoji")
@@ -826,7 +826,7 @@ class EmojiManager:
file_path = os.path.join(emoji_dir, filename)
if os.path.isfile(file_path):
os.remove(file_path)
logger.debug(f"[清理] 删除表情包文件: {filename}")
logger.debug(f"[清理] 删除: {filename}")
# 清理image目录
image_dir = os.path.join(BASE_DIR, "image")
@@ -838,14 +838,19 @@ class EmojiManager:
file_path = os.path.join(image_dir, filename)
if os.path.isfile(file_path):
os.remove(file_path)
logger.debug(f"[清理] 删除图片文件: {filename}")
logger.debug(f"[清理] 删除图片: {filename}")
logger.success("[清理] 临时文件清理完成")
logger.success("[清理] 完成")
async def clean_unused_emojis(self, emoji_dir, emoji_objects):
"""清理未使用的表情包文件
遍历指定文件夹中的所有文件删除未在emoji_objects列表中的文件
"""
# 首先检查目录是否存在喵~
if not os.path.exists(emoji_dir):
logger.warning(f"[清理] 表情包目录不存在,跳过清理: {emoji_dir}")
return
# 获取所有表情包路径
emoji_paths = {emoji.path for emoji in emoji_objects}

View File

@@ -37,7 +37,7 @@ EMOJI_SEND_PRO = 0.3 # 设置一个概率,比如 30% 才真的发
CONSECUTIVE_NO_REPLY_THRESHOLD = 3 # 连续不回复的阈值
logger = get_logger("interest") # Logger Name Changed
logger = get_logger("HFC") # Logger Name Changed
# 默认动作定义

View File

@@ -77,7 +77,7 @@ class BaseWillingManager(ABC):
if not issubclass(manager_class, cls):
raise TypeError(f"Manager class {manager_class.__name__} is not a subclass of {cls.__name__}")
else:
logger.info(f"成功载入willing模式:{manager_type}")
logger.info(f"普通回复模式:{manager_type}")
return manager_class()
except (ImportError, AttributeError, TypeError) as e:
module = importlib.import_module(".mode_classical", __package__)