持久化表情中文语义资产\n\n- 新增 t_emoji_assets 表及迁移脚本,持久化保存表情发送参数、中文语义与预览图路径\n- 在消息归档与媒体补偿流程中自动回填表情资产,实现收到表情即落语义、补图后回填预览\n- 后台表情库与自动回复优先读取持久化表情资产,仅在空表场景下小范围回补历史数据

This commit is contained in:
liuwei
2026-04-27 11:52:31 +08:00
parent 623ca505d4
commit 62e6f67836
7 changed files with 334 additions and 172 deletions

View File

@@ -15,12 +15,14 @@ from typing import Dict, Optional
from db.connection import DBConnectionManager
from db.contacts_db import ContactsDBOperator
from db.emoji_asset_db import EmojiAssetDB
from db.levels_db import LevelsDBOperator
from db.message_storage import MessageStorageDB
# 导入积分系统
from db.points_db import PointsDBOperator, PointSource
from utils.robot_cmd.robot_command import Feature, GroupBotManager, PermissionStatus
from utils.wechat.contact_manager import ContactManager
from utils.wechat.emoji_semantic_parser import safe_text
from wechat_ipad import WechatAPIClient
from wechat_ipad.models.message import WxMessage, MessageType
@@ -36,6 +38,7 @@ class MessageStorage:
self.db_manager = DBConnectionManager.get_instance()
self.message_db = MessageStorageDB(self.db_manager)
self.contacts_db = ContactsDBOperator(self.db_manager)
self.emoji_asset_db = EmojiAssetDB(self.db_manager)
self.points_db = PointsDBOperator(self.db_manager)
# 初始化本地缓存字典,使用 group_id 作为键
@@ -180,6 +183,8 @@ class MessageStorage:
# 使用 MessageStorageDB 类存档消息
result = self.message_db.archive_message(msg)
if result and msg.msg_type in {MessageType.EMOTICON, MessageType.EMOJI}:
self._sync_emoji_asset_from_wx_message(msg)
return {
'success': result,
'roomid': msg.roomid,
@@ -198,6 +203,25 @@ class MessageStorage:
'error': str(e)
}
def _sync_emoji_asset_from_wx_message(self, msg: WxMessage):
"""将表情消息同步到持久化表情资产表。
说明:
1. 群里一旦收到表情,先把 md5/len/语义落表,不必等预览图下载完成;
2. 这样自动回复和后台检索都能尽早看到结构化资产;
3. 后续定时媒体任务补到 image_path 后,会再次 upsert 同一 md5把 preview_url 回填完整。
"""
attachment_url = safe_text(getattr(msg.content, "xml_content", "") or getattr(msg.content, "clean_content", "")).strip()
if not attachment_url.startswith("<"):
return
self.emoji_asset_db.upsert_asset_from_message_record({
"attachment_url": attachment_url,
"image_path": "",
"message_id": safe_text(msg.msg_id),
"group_id": safe_text(msg.roomid),
"sender": safe_text(msg.sender),
})
def process_image(self, msg: WxMessage):
"""图片消息已通过 archive_message 存入数据库,不再实时处理
改为定时任务批量处理,减少对主流程的影响和数据库锁竞争
@@ -243,6 +267,14 @@ class MessageStorage:
if existing and existing.get("image_path"):
linked_path = existing.get("image_path")
success = self.message_db.update_message_image_file_path(message_id, linked_path)
if success and message_type in {str(MessageType.EMOTICON.value), str(MessageType.EMOJI.value)}:
self.emoji_asset_db.upsert_asset_from_message_record({
"attachment_url": xml_content,
"image_path": linked_path,
"message_id": safe_text(message_id),
"group_id": safe_text(group_id),
"sender": safe_text(sender),
})
return {
"success": bool(success),
"message_id": message_id,
@@ -283,6 +315,14 @@ class MessageStorage:
success = self.message_db.update_message_image_file_path(message_id, web_path)
if success:
if message_type in {str(MessageType.EMOTICON.value), str(MessageType.EMOJI.value)}:
self.emoji_asset_db.upsert_asset_from_message_record({
"attachment_url": xml_content,
"image_path": web_path,
"message_id": safe_text(message_id),
"group_id": safe_text(group_id),
"sender": safe_text(sender),
})
logger.debug(f"媒体处理成功: message_id={message_id}, path={web_path}")
else:
logger.warning(f"媒体路径更新失败: message_id={message_id}")