feat: 添加 NapCat 适配器的入站消息编解码功能,增强插件配置更新逻辑和数据库交互测试

This commit is contained in:
DrSmoothl
2026-03-22 00:43:34 +08:00
parent 56a6d2fd8c
commit 89df7ccf6b
10 changed files with 511 additions and 35 deletions

View File

@@ -461,25 +461,43 @@ class ExpressionLearner:
def _find_similar_expression(
self, situation: str, similarity_threshold: float = 0.75
) -> Optional[Tuple[MaiExpression, float]]:
"""在数据库中查找相似的表达方式"""
"""在数据库中查找相似的表达方式
Args:
situation: 当前待匹配的情景描述。
similarity_threshold: 认定为相似表达方式的最低相似度阈值。
Returns:
Optional[Tuple[MaiExpression, float]]: 若找到最相似的表达方式,则返回
``(表达方式对象, 相似度)``;否则返回 ``None``。
"""
try:
with get_db_session() as session:
with get_db_session(auto_commit=False) as session:
statement = select(Expression).filter_by(session_id=self.session_id)
expressions = session.exec(statement).all()
best_match: Optional[Expression] = None
best_similarity = 0.0
best_match: Optional[MaiExpression] = None
best_similarity = 0.0
for db_expression in expressions:
expression = MaiExpression.from_db_instance(db_expression)
candidate_situations = [expression.situation, *expression.content]
for candidate_situation in candidate_situations:
normalized_candidate_situation = candidate_situation.strip()
if not normalized_candidate_situation:
continue
similarity = difflib.SequenceMatcher(
None,
situation,
normalized_candidate_situation,
).ratio()
if similarity > similarity_threshold and similarity > best_similarity:
best_similarity = similarity
best_match = expression
for expr in expressions:
content_list = json.loads(expr.content_list)
for situation in content_list:
similarity = difflib.SequenceMatcher(None, situation, expr.situation).ratio()
if similarity > similarity_threshold and similarity > best_similarity:
best_similarity = similarity
best_match = expr
if best_match:
logger.debug(f"找到相似表达方式情景 [ID: {best_match.id}],相似度: {best_similarity:.2f}")
return MaiExpression.from_db_instance(best_match), best_similarity
logger.debug(f"找到相似表达方式情景 [ID: {best_match.item_id}],相似度: {best_similarity:.2f}")
return best_match, best_similarity
except Exception as e:
logger.error(f"查找相似表达方式失败: {e}")

View File

@@ -199,7 +199,7 @@ class JargonMiner:
async def process_extracted_entries(
self, entries: List[JargonEntry], person_name_filter: Optional[Callable[[str], bool]] = None
):
) -> None:
"""
处理已提取的黑话条目(从 expression_learner 路由过来的)
@@ -230,7 +230,7 @@ class JargonMiner:
content = entry["content"]
raw_content_set = entry["raw_content"]
try:
with get_db_session() as session:
with get_db_session(auto_commit=False) as session:
jargon_items = session.exec(select(Jargon).filter_by(content=content)).all()
except Exception as e:
logger.error(f"查询黑话 '{content}' 失败: {e}")
@@ -306,7 +306,13 @@ class JargonMiner:
removed_content, _ = self.cache.popitem(last=False)
logger.debug(f"缓存已满,移除最旧的黑话: {removed_content}")
def _update_jargon(self, db_jargon: Jargon, raw_content_set: Set[str]):
def _update_jargon(self, db_jargon: Jargon, raw_content_set: Set[str]) -> None:
"""更新已有黑话记录并写回数据库。
Args:
db_jargon: 已命中的黑话 ORM 对象。
raw_content_set: 本次新增的原始上下文集合。
"""
db_jargon.count += 1
existing_raw_content: List[str] = []
if db_jargon.raw_content:
@@ -328,7 +334,17 @@ class JargonMiner:
try:
with get_db_session() as session:
session.add(db_jargon)
if db_jargon.id is None:
raise ValueError("黑话记录缺少 id无法更新数据库")
statement = select(Jargon).filter_by(id=db_jargon.id).limit(1)
if persisted_jargon := session.exec(statement).first():
persisted_jargon.count = db_jargon.count
persisted_jargon.raw_content = db_jargon.raw_content
persisted_jargon.session_id_dict = db_jargon.session_id_dict
persisted_jargon.is_global = db_jargon.is_global
session.add(persisted_jargon)
else:
logger.warning(f"黑话 ID {db_jargon.id} 在数据库中未找到,无法更新")
except Exception as e:
logger.error(f"更新黑话 '{db_jargon.content}' 失败: {e}")