MaiBot/src/plugins/built_in/jargon/jargon_explanation.py

181 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from typing import Any, Dict, List, Tuple
from src.common.logger import get_logger
from src.common.database.database_model import Jargon
from src.plugin_system import BaseTool, ToolParamType
logger = get_logger("jargon_explanation")
class RecordJargonExplanationTool(BaseTool):
"""记录jargon解释工具
检测聊天记录中是否有对某个词义的明确解释如果有则记录到jargon表中
"""
name: str = "record_explanation"
description: str = (
"当检测到有人明确解释了某个缩写,拼音缩写,中文缩写,英文缩写的含义时(例如:'xxx是yyy的意思''xxx指的是yyy'等)"
"当某人明确纠正了对某个词汇的错误解释时(例如:'xxx不是yyy的意思''xxx不是指的是yyy'等)"
)
parameters: List[Tuple[str, ToolParamType, str, bool, None]] = [
("content", ToolParamType.STRING, "被解释的目标词汇(黑话/俚语/缩写例如yyds、内卷、社死等", True, None),
("translation", ToolParamType.STRING, "词汇的翻译或简称,例如:永远的神、社会性死亡等", True, None),
("meaning", ToolParamType.STRING, "词汇的详细含义说明", True, None),
]
available_for_llm: bool = True
async def execute(self, function_args: Dict[str, Any]) -> Dict[str, str]:
"""执行jargon解释检测和记录
Args:
function_args: 工具参数包含content、translation、meaning
Returns:
dict: 工具执行结果
"""
if not self.chat_id:
return {"name": self.name, "content": "无法记录jargon解释缺少chat_id"}
try:
# 从参数中获取信息
content = str(function_args.get("content", "")).strip()
translation = str(function_args.get("translation", "")).strip()
meaning = str(function_args.get("meaning", "")).strip()
if not content:
return {"name": self.name, "content": "目标词汇不能为空"}
if not translation and not meaning:
return {"name": self.name, "content": "翻译和含义至少需要提供一个"}
# 检查是否已存在相同的jargon
query = Jargon.select().where(
(Jargon.chat_id == self.chat_id) &
(Jargon.content == content)
)
if query.exists():
# 已存在更新translation和meaning追加用/分隔)
obj = query.get()
existing_translation = obj.translation or ""
existing_meaning = obj.meaning or ""
# 追加新内容
if translation:
if existing_translation:
obj.translation = f"{existing_translation}/{translation}"
else:
obj.translation = translation
if meaning:
if existing_meaning:
obj.meaning = f"{existing_meaning}/{meaning}"
else:
obj.meaning = meaning
# 确保is_jargon为True
obj.is_jargon = True
obj.save()
logger.info(f"更新jargon解释: {content}, translation={obj.translation}, meaning={obj.meaning}")
# 优先使用meaning如果没有则使用translation
explanation = obj.meaning or obj.translation or ""
return {"name": self.name, "content": f"你了解到 {content}的含义应该是 {explanation}"}
else:
# 新建记录
Jargon.create(
content=content,
chat_id=self.chat_id,
translation=translation,
meaning=meaning,
is_jargon=True,
is_global=False,
count=0,
)
logger.info(f"记录新jargon解释: {content}, translation={translation}, meaning={meaning}")
# 优先使用meaning如果没有则使用translation
explanation = meaning or translation or ""
return {"name": self.name, "content": f"你了解到 {content}的含义应该是 {explanation}"}
except Exception as exc:
logger.error(f"记录jargon解释失败: {exc}", exc_info=True)
return {"name": self.name, "content": f"记录jargon解释失败: {exc}"}
class LookupJargonMeaningTool(BaseTool):
"""查询jargon含义工具
输入一个可能意义不明的词或缩写,查询数据库中是否已有匹配且带有含义或翻译的记录。
命中则返回解释字符串优先meaning其次translation未命中返回空字符串。
"""
name: str = "lookup_jargon_meaning"
description: str = (
"查询是否存在已知的jargon解释含meaning或translation若存在返回解释否则返回空字符串"
)
parameters: List[Tuple[str, ToolParamType, str, bool, None]] = [
("content", ToolParamType.STRING, "待查询的目标词汇(黑话/俚语/缩写)", True, None),
]
available_for_llm: bool = True
async def execute(self, function_args: Dict[str, Any]) -> Dict[str, str]:
if not self.chat_id:
# 和其它工具保持一致的返回结构
return {"name": self.name, "content": ""}
try:
content = str(function_args.get("content", "")).strip()
if not content:
return {"name": self.name, "content": ""}
# 优先在当前会话或global中查找该content且需要meaning或translation非空
# Peewee 条件:
# (content == 输入) AND ((chat_id == 当前chat) OR is_global) AND ((meaning非空) OR (translation非空))
candidates = (
Jargon.select()
.where(
(Jargon.content == content)
& ((Jargon.chat_id == self.chat_id) | Jargon.is_global)
& (
((Jargon.meaning.is_null(False)) & (Jargon.meaning != ""))
| ((Jargon.translation.is_null(False)) & (Jargon.translation != ""))
)
)
.limit(1)
)
if candidates.exists():
obj = candidates.get()
translation = (obj.translation or "").strip()
meaning = (obj.meaning or "").strip()
formatted = f"{content}可能为黑话或者网络简写,翻译为:{translation},含义为:{meaning}"
return {"name": self.name, "content": formatted}
# 未命中允许退化为全库搜索不限chat_id以提升命中率
fallback = (
Jargon.select()
.where(
(Jargon.content == content)
& (
((Jargon.meaning.is_null(False)) & (Jargon.meaning != ""))
| ((Jargon.translation.is_null(False)) & (Jargon.translation != ""))
)
)
.limit(1)
)
if fallback.exists():
obj = fallback.get()
translation = (obj.translation or "").strip()
meaning = (obj.meaning or "").strip()
formatted = f"{content}可能为黑话或者网络简写,翻译为:{translation},含义为:{meaning}"
return {"name": self.name, "content": formatted}
# 彻底未命中
return {"name": self.name, "content": ""}
except Exception as exc:
logger.error(f"查询jargon解释失败: {exc}", exc_info=True)
return {"name": self.name, "content": ""}