ref:解耦表情包识别和图片识别
This commit is contained in:
@@ -745,6 +745,58 @@ class ActionPlanner:
|
||||
logger.warning(f"解析JSON块失败: {e}, 块内容: {match[:100]}...")
|
||||
continue
|
||||
|
||||
# 如果没有找到完整的```json```块,尝试查找不完整的代码块(缺少结尾```)
|
||||
if not json_objects:
|
||||
json_start_pos = content.find("```json")
|
||||
if json_start_pos != -1:
|
||||
# 找到```json之后的内容
|
||||
json_content_start = json_start_pos + 7 # ```json的长度
|
||||
# 提取从```json之后到内容结尾的所有内容
|
||||
incomplete_json_str = content[json_content_start:].strip()
|
||||
|
||||
# 提取JSON之前的内容作为推理文本
|
||||
if json_start_pos > 0:
|
||||
reasoning_content = content[:json_start_pos].strip()
|
||||
reasoning_content = re.sub(r"^//\s*", "", reasoning_content, flags=re.MULTILINE)
|
||||
reasoning_content = reasoning_content.strip()
|
||||
|
||||
if incomplete_json_str:
|
||||
try:
|
||||
# 清理可能的注释和格式问题
|
||||
json_str = re.sub(r"//.*?\n", "\n", incomplete_json_str)
|
||||
json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL)
|
||||
json_str = json_str.strip()
|
||||
|
||||
if json_str:
|
||||
# 尝试按行分割,每行可能是一个JSON对象
|
||||
lines = [line.strip() for line in json_str.split("\n") if line.strip()]
|
||||
for line in lines:
|
||||
try:
|
||||
json_obj = json.loads(repair_json(line))
|
||||
if isinstance(json_obj, dict):
|
||||
json_objects.append(json_obj)
|
||||
elif isinstance(json_obj, list):
|
||||
for item in json_obj:
|
||||
if isinstance(item, dict):
|
||||
json_objects.append(item)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
# 如果按行解析没有成功,尝试将整个块作为一个JSON对象或数组
|
||||
if not json_objects:
|
||||
try:
|
||||
json_obj = json.loads(repair_json(json_str))
|
||||
if isinstance(json_obj, dict):
|
||||
json_objects.append(json_obj)
|
||||
elif isinstance(json_obj, list):
|
||||
for item in json_obj:
|
||||
if isinstance(item, dict):
|
||||
json_objects.append(item)
|
||||
except Exception as e:
|
||||
logger.debug(f"尝试解析不完整的JSON代码块失败: {e}")
|
||||
except Exception as e:
|
||||
logger.debug(f"处理不完整的JSON代码块时出错: {e}")
|
||||
|
||||
return json_objects, reasoning_content
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from rich.traceback import install
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.common.database.database import db
|
||||
from src.common.database.database_model import Images, ImageDescriptions
|
||||
from src.common.database.database_model import Images, ImageDescriptions, EmojiDescriptionCache
|
||||
from src.config.config import global_config, model_config
|
||||
from src.llm_models.utils_model import LLMRequest
|
||||
|
||||
@@ -40,7 +40,7 @@ class ImageManager:
|
||||
|
||||
try:
|
||||
db.connect(reuse_if_open=True)
|
||||
db.create_tables([Images, ImageDescriptions], safe=True)
|
||||
db.create_tables([Images, ImageDescriptions, EmojiDescriptionCache], safe=True)
|
||||
except Exception as e:
|
||||
logger.error(f"数据库连接或表创建失败: {e}")
|
||||
|
||||
@@ -49,6 +49,11 @@ class ImageManager:
|
||||
except Exception as e:
|
||||
logger.warning(f"数据库清理失败: {e}")
|
||||
|
||||
try:
|
||||
self._cleanup_emoji_from_image_descriptions()
|
||||
except Exception as e:
|
||||
logger.warning(f"清理ImageDescriptions中的emoji记录失败: {e}")
|
||||
|
||||
self._initialized = True
|
||||
|
||||
def _ensure_image_dir(self):
|
||||
@@ -119,6 +124,31 @@ class ImageManager:
|
||||
else:
|
||||
logger.info("[清理完成] 未发现无效描述记录")
|
||||
|
||||
@staticmethod
|
||||
def _cleanup_emoji_from_image_descriptions():
|
||||
"""清理Images和ImageDescriptions表中type为emoji的记录(已迁移到EmojiDescriptionCache)"""
|
||||
try:
|
||||
# 清理Images表中type为emoji的记录
|
||||
deleted_images = Images.delete().where(Images.type == "emoji").execute()
|
||||
|
||||
# 清理ImageDescriptions表中type为emoji的记录
|
||||
deleted_descriptions = (
|
||||
ImageDescriptions.delete().where(ImageDescriptions.type == "emoji").execute()
|
||||
)
|
||||
|
||||
total_deleted = deleted_images + deleted_descriptions
|
||||
if total_deleted > 0:
|
||||
logger.info(
|
||||
f"[清理完成] 从Images表中删除 {deleted_images} 条emoji类型记录, "
|
||||
f"从ImageDescriptions表中删除 {deleted_descriptions} 条emoji类型记录, "
|
||||
f"共删除 {total_deleted} 条记录"
|
||||
)
|
||||
else:
|
||||
logger.info("[清理完成] Images和ImageDescriptions表中未发现emoji类型记录")
|
||||
except Exception as e:
|
||||
logger.error(f"清理Images和ImageDescriptions中的emoji记录时出错: {str(e)}")
|
||||
raise
|
||||
|
||||
async def get_emoji_tag(self, image_base64: str) -> str:
|
||||
from src.chat.emoji_system.emoji_manager import get_emoji_manager
|
||||
|
||||
@@ -135,7 +165,7 @@ class ImageManager:
|
||||
return f"[表情包:{tag_str}]"
|
||||
|
||||
async def get_emoji_description(self, image_base64: str) -> str:
|
||||
"""获取表情包描述,优先使用Emoji表中的缓存数据"""
|
||||
"""获取表情包描述,优先使用EmojiDescriptionCache表中的缓存数据"""
|
||||
try:
|
||||
# 计算图片哈希
|
||||
# 确保base64字符串只包含ASCII字符
|
||||
@@ -158,10 +188,19 @@ class ImageManager:
|
||||
except Exception as e:
|
||||
logger.debug(f"查询EmojiManager时出错: {e}")
|
||||
|
||||
# 查询ImageDescriptions表的缓存描述
|
||||
if cached_description := self._get_description_from_db(image_hash, "emoji"):
|
||||
logger.info(f"[缓存命中] 使用ImageDescriptions表中的描述: {cached_description[:50]}...")
|
||||
return f"[表情包:{cached_description}]"
|
||||
# 查询EmojiDescriptionCache表的缓存(包含描述和情感标签)
|
||||
try:
|
||||
cache_record = EmojiDescriptionCache.get_or_none(EmojiDescriptionCache.emoji_hash == image_hash)
|
||||
if cache_record:
|
||||
# 优先使用情感标签,如果没有则使用详细描述
|
||||
if cache_record.emotion_tags:
|
||||
logger.info(f"[缓存命中] 使用EmojiDescriptionCache表中的情感标签: {cache_record.emotion_tags[:50]}...")
|
||||
return f"[表情包:{cache_record.emotion_tags}]"
|
||||
elif cache_record.description:
|
||||
logger.info(f"[缓存命中] 使用EmojiDescriptionCache表中的描述: {cache_record.description[:50]}...")
|
||||
return f"[表情包:{cache_record.description}]"
|
||||
except Exception as e:
|
||||
logger.debug(f"查询EmojiDescriptionCache时出错: {e}")
|
||||
|
||||
# === 二步走识别流程 ===
|
||||
|
||||
@@ -221,45 +260,35 @@ class ImageManager:
|
||||
|
||||
logger.debug(f"[emoji识别] 详细描述: {detailed_description[:50]}... -> 情感标签: {final_emotion}")
|
||||
|
||||
if cached_description := self._get_description_from_db(image_hash, "emoji"):
|
||||
logger.warning(f"虽然生成了描述,但是找到缓存表情包描述: {cached_description}")
|
||||
return f"[表情包:{cached_description}]"
|
||||
|
||||
# 保存表情包文件和元数据(用于可能的后续分析)
|
||||
logger.debug(f"保存表情包: {image_hash}")
|
||||
current_timestamp = time.time()
|
||||
filename = f"{int(current_timestamp)}_{image_hash[:8]}.{image_format}"
|
||||
emoji_dir = os.path.join(self.IMAGE_DIR, "emoji")
|
||||
os.makedirs(emoji_dir, exist_ok=True)
|
||||
file_path = os.path.join(emoji_dir, filename)
|
||||
|
||||
# 再次检查缓存(防止并发情况下其他线程已经保存)
|
||||
try:
|
||||
# 保存文件
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(image_bytes)
|
||||
|
||||
# 保存到数据库 (Images表) - 包含详细描述用于可能的注册流程
|
||||
try:
|
||||
img_obj = Images.get((Images.emoji_hash == image_hash) & (Images.type == "emoji"))
|
||||
img_obj.path = file_path
|
||||
img_obj.description = detailed_description # 保存详细描述
|
||||
img_obj.timestamp = current_timestamp
|
||||
img_obj.save()
|
||||
except Images.DoesNotExist: # type: ignore
|
||||
Images.create(
|
||||
image_id=str(uuid.uuid4()),
|
||||
emoji_hash=image_hash,
|
||||
path=file_path,
|
||||
type="emoji",
|
||||
description=detailed_description, # 保存详细描述
|
||||
timestamp=current_timestamp,
|
||||
vlm_processed=True,
|
||||
)
|
||||
cache_record = EmojiDescriptionCache.get_or_none(EmojiDescriptionCache.emoji_hash == image_hash)
|
||||
if cache_record and cache_record.emotion_tags:
|
||||
logger.warning(f"虽然生成了描述,但是找到缓存表情包情感标签: {cache_record.emotion_tags}")
|
||||
return f"[表情包:{cache_record.emotion_tags}]"
|
||||
except Exception as e:
|
||||
logger.error(f"保存表情包文件或元数据失败: {str(e)}")
|
||||
logger.debug(f"再次查询EmojiDescriptionCache时出错: {e}")
|
||||
|
||||
# 保存最终的情感标签到缓存 (ImageDescriptions表)
|
||||
self._save_description_to_db(image_hash, final_emotion, "emoji")
|
||||
# 保存识别出的详细描述和情感标签到 emoji_description_cache
|
||||
try:
|
||||
current_timestamp = time.time()
|
||||
cache_record, created = EmojiDescriptionCache.get_or_create(
|
||||
emoji_hash=image_hash,
|
||||
defaults={
|
||||
"description": detailed_description,
|
||||
"emotion_tags": final_emotion,
|
||||
"timestamp": current_timestamp,
|
||||
},
|
||||
)
|
||||
if not created:
|
||||
# 更新已有记录
|
||||
cache_record.description = detailed_description
|
||||
cache_record.emotion_tags = final_emotion
|
||||
cache_record.timestamp = current_timestamp
|
||||
cache_record.save()
|
||||
logger.info(f"[缓存保存] 表情包描述和情感标签已保存到EmojiDescriptionCache: {image_hash[:8]}...")
|
||||
except Exception as e:
|
||||
logger.error(f"保存表情包描述和情感标签缓存失败: {str(e)}")
|
||||
|
||||
return f"[表情包:{final_emotion}]"
|
||||
|
||||
|
||||
@@ -239,6 +239,20 @@ class ImageDescriptions(BaseModel):
|
||||
table_name = "image_descriptions"
|
||||
|
||||
|
||||
class EmojiDescriptionCache(BaseModel):
|
||||
"""
|
||||
存储表情包的详细描述和情感标签缓存
|
||||
"""
|
||||
|
||||
emoji_hash = TextField(unique=True, index=True)
|
||||
description = TextField() # 详细描述
|
||||
emotion_tags = TextField(null=True) # 情感标签,逗号分隔
|
||||
timestamp = FloatField()
|
||||
|
||||
class Meta:
|
||||
table_name = "emoji_description_cache"
|
||||
|
||||
|
||||
class OnlineTime(BaseModel):
|
||||
"""
|
||||
用于存储在线时长记录的模型。
|
||||
@@ -389,6 +403,7 @@ MODELS = [
|
||||
Messages,
|
||||
Images,
|
||||
ImageDescriptions,
|
||||
EmojiDescriptionCache,
|
||||
OnlineTime,
|
||||
PersonInfo,
|
||||
Expression,
|
||||
|
||||
Reference in New Issue
Block a user