This commit is contained in:
SengokuCola
2025-04-24 23:45:49 +08:00
parent af08ef9b04
commit 3ab3979047
6 changed files with 117 additions and 130 deletions

View File

@@ -405,7 +405,6 @@ class BotConfig:
config.save_emoji = emoji_config.get("save_emoji", config.save_emoji)
config.steal_emoji = emoji_config.get("steal_emoji", config.steal_emoji)
def bot(parent: dict):
# 机器人基础配置
bot_config = parent["bot"]

View File

@@ -12,7 +12,6 @@ import re
from ...common.database import db
from ...config.config import global_config
from ..chat.utils import get_embedding
from ..chat.utils_image import image_path_to_base64, image_manager
from ..models.utils_model import LLMRequest
from src.common.logger import get_module_logger, LogConfig, EMOJI_STYLE_CONFIG
@@ -31,6 +30,7 @@ EMOJI_REGISTED_DIR = os.path.join("data", "emoji_registed") # 已注册的表
class MaiEmoji:
"""定义一个表情包"""
def __init__(self, filename: str, path: str):
self.path = path # 存储目录路径
self.filename = filename
@@ -64,7 +64,6 @@ class MaiEmoji:
logger.error(f"[错误] 无法读取图片: {file_path}")
return None
# 计算哈希值
image_bytes = base64.b64decode(image_base64)
self.hash = hashlib.md5(image_bytes).hexdigest()
@@ -72,7 +71,6 @@ class MaiEmoji:
# 获取图片格式
self.format = Image.open(io.BytesIO(image_bytes)).format.lower()
except Exception as e:
logger.error(f"[错误] 初始化表情包失败: {str(e)}")
logger.error(traceback.format_exc())
@@ -110,30 +108,26 @@ class MaiEmoji:
self.path = EMOJI_REGISTED_DIR
except Exception as move_error:
logger.error(f"[错误] 移动文件失败: {str(move_error)}")
return False # 文件移动失败,不继续
return False # 文件移动失败,不继续
# --- 数据库操作 ---
try:
# 准备数据库记录 for emoji collection
emoji_record = {
"filename": self.filename,
"path": os.path.join(self.path, self.filename), # 使用更新后的路径
"path": os.path.join(self.path, self.filename), # 使用更新后的路径
"embedding": self.embedding,
"description": self.description,
"emotion": self.emotion, # 添加情感标签字段
"hash": self.hash,
"format": self.format,
"timestamp": int(self.register_time), # 使用实例的注册时间
"timestamp": int(self.register_time), # 使用实例的注册时间
"usage_count": self.usage_count,
"last_used_time": self.last_used_time
"last_used_time": self.last_used_time,
}
# 使用upsert确保记录存在或被更新
db["emoji"].update_one(
{"hash": self.hash},
{"$set": emoji_record},
upsert=True
)
db["emoji"].update_one({"hash": self.hash}, {"$set": emoji_record}, upsert=True)
logger.success(f"[注册] 表情包信息保存到数据库: {self.description}")
return True
@@ -188,7 +182,6 @@ class MaiEmoji:
class EmojiManager:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
@@ -213,7 +206,6 @@ class EmojiManager:
"""确保表情存储目录存在"""
os.makedirs(EMOJI_DIR, exist_ok=True)
def initialize(self):
"""初始化数据库连接和表情目录"""
if not self._initialized:
@@ -314,9 +306,7 @@ class EmojiManager:
# 更新使用次数
db.emoji.update_one({"hash": selected_emoji.hash}, {"$inc": {"usage_count": 1}})
logger.info(
f"[匹配] 找到表情包: {selected_emoji.description} (相似度: {similarity:.4f})"
)
logger.info(f"[匹配] 找到表情包: {selected_emoji.description} (相似度: {similarity:.4f})")
time_end = time.time()
logger.info(f"[匹配] 搜索表情包用时: {time_end - time_start:.2f}")
@@ -420,11 +410,14 @@ class EmojiManager:
continue
# 检查是否需要处理表情包(数量超过最大值或不足)
if (self.emoji_num > self.emoji_num_max and global_config.max_reach_deletion) or (self.emoji_num < self.emoji_num_max):
if (self.emoji_num > self.emoji_num_max and global_config.max_reach_deletion) or (
self.emoji_num < self.emoji_num_max
):
try:
# 获取目录下所有图片文件
files_to_process = [
f for f in files
f
for f in files
if os.path.isfile(os.path.join(EMOJI_DIR, f))
and f.lower().endswith((".jpg", ".jpeg", ".png", ".gif"))
]
@@ -540,8 +533,6 @@ class EmojiManager:
return emoji
return None
async def delete_emoji(self, emoji_hash: str) -> bool:
"""根据哈希值删除表情包
@@ -596,10 +587,7 @@ class EmojiManager:
time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(emoji.register_time))
# 构建每个表情包的信息字符串
emoji_info = (
f"编号: {i+1}\n"
f"描述: {emoji.description}\n"
f"使用次数: {emoji.usage_count}\n"
f"添加时间: {time_str}\n"
f"编号: {i + 1}\n描述: {emoji.description}\n使用次数: {emoji.usage_count}\n添加时间: {time_str}\n"
)
emoji_info_list.append(emoji_info)
return emoji_info_list
@@ -629,10 +617,10 @@ class EmojiManager:
f"新表情包信息:\n"
f"描述: {new_emoji.description}\n\n"
f"现有表情包列表:\n" + "\n".join(emoji_info_list) + "\n\n"
f"请决定:\n"
f"1. 是否要删除某个现有表情包来为新表情包腾出空间?\n"
f"2. 如果要删除,应该删除哪一个(给出编号)\n"
f"请只回答:'不删除''删除编号X'(X为表情包编号)。"
"请决定:\n"
"1. 是否要删除某个现有表情包来为新表情包腾出空间?\n"
"2. 如果要删除,应该删除哪一个(给出编号)\n"
"请只回答:'不删除''删除编号X'(X为表情包编号)。"
)
# 调用大模型进行决策
@@ -645,7 +633,7 @@ class EmojiManager:
return False
# 尝试从决策中提取表情包编号
match = re.search(r'删除编号(\d+)', decision)
match = re.search(r"删除编号(\d+)", decision)
if match:
emoji_index = int(match.group(1)) - 1 # 转换为0-based索引
@@ -669,10 +657,10 @@ class EmojiManager:
logger.error(f"[错误] 注册表情包到数据库失败: {new_emoji.filename}")
return False
else:
logger.error(f"[错误] 删除表情包失败,无法完成替换")
logger.error("[错误] 删除表情包失败,无法完成替换")
return False
else:
logger.error(f"[错误] 无效的表情包编号: {emoji_index+1}")
logger.error(f"[错误] 无效的表情包编号: {emoji_index + 1}")
else:
logger.error(f"[错误] 无法从决策中提取表情包编号: {decision}")
@@ -721,17 +709,17 @@ class EmojiManager:
return None, []
# 分析情感含义
emotion_prompt = f'''
emotion_prompt = f"""
基于这个表情包的描述:'{description}'请列出1-3个可能的情感标签每个标签用一个词组表示格式如下
幽默的讽刺
悲伤的无奈
愤怒的抗议
愤怒的讽刺
直接输出词组,词组检用逗号分隔。'''
直接输出词组,词组检用逗号分隔。"""
emotions_text, _ = await self.llm_emotion_judge.generate_response_async(emotion_prompt, temperature=0.7)
# 处理情感列表
emotions = [e.strip() for e in emotions_text.split(',') if e.strip()]
emotions = [e.strip() for e in emotions_text.split(",") if e.strip()]
return f"[表情包:{description}]", emotions
@@ -739,7 +727,6 @@ class EmojiManager:
logger.error(f"获取表情包描述失败: {str(e)}")
return "", []
async def register_emoji_by_filename(self, filename: str) -> bool:
"""读取指定文件名的表情包图片,分析并注册到数据库

View File

@@ -78,7 +78,7 @@ class HeartFCGenerator:
) -> str:
info_catcher = info_catcher_manager.get_info_catcher(thinking_id)
with Timer() as t_build_prompt:
with Timer() as _t_build_prompt:
prompt = await prompt_builder.build_prompt(
build_mode="focus",
reason=reason,

View File

@@ -122,13 +122,14 @@ class PromptBuilder:
elif build_mode == "focus":
return await self._build_prompt_focus(
reason, current_mind_info, structured_info, chat_stream,
reason,
current_mind_info,
structured_info,
chat_stream,
)
return None
async def _build_prompt_focus(
self, reason, current_mind_info, structured_info, chat_stream
) -> tuple[str, str]:
async def _build_prompt_focus(self, reason, current_mind_info, structured_info, chat_stream) -> tuple[str, str]:
individuality = Individuality.get_instance()
prompt_personality = individuality.get_prompt(type="personality", x_person=2, level=1)
prompt_identity = individuality.get_prompt(type="identity", x_person=2, level=1)