fix:图片保存的意外warning

This commit is contained in:
SengokuCola
2026-05-07 17:21:10 +08:00
parent 2b327a31d3
commit 93cef02d92
3 changed files with 35 additions and 15 deletions

View File

@@ -119,7 +119,7 @@ class ImageManager:
logger.warning("图片哈希值未找到,且未提供图片字节数据,返回无描述") logger.warning("图片哈希值未找到,且未提供图片字节数据,返回无描述")
return "" return ""
try: try:
await self.ensure_image_saved(image_bytes) saved_image = await self.ensure_image_saved(image_bytes)
except Exception as e: except Exception as e:
logger.error(f"保存图片文件时发生错误: {e}") logger.error(f"保存图片文件时发生错误: {e}")
return "" return ""
@@ -127,22 +127,29 @@ class ImageManager:
logger.info("未配置 VLM 模型,跳过图片识别") logger.info("未配置 VLM 模型,跳过图片识别")
return "" return ""
if not wait_for_build: if not wait_for_build:
self._schedule_description_build(hash_str, image_bytes) self._schedule_description_build(hash_str, image_bytes, saved_image=saved_image)
return "" return ""
logger.info(f"图片描述未找到,哈希值: {hash_str},准备生成新描述") logger.info(f"图片描述未找到,哈希值: {hash_str},准备生成新描述")
try: try:
image = await self.build_image_description(image_bytes) image = await self.build_image_description(image_bytes, saved_image=saved_image)
return image.description return image.description
except Exception as e: except Exception as e:
logger.error(f"生成图片描述时发生错误: {e}") logger.error(f"生成图片描述时发生错误: {e}")
return "" return ""
def _schedule_description_build(self, image_hash: str, image_bytes: bytes) -> None: def _schedule_description_build(
self,
image_hash: str,
image_bytes: bytes,
*,
saved_image: Optional[MaiImage] = None,
) -> None:
"""调度图片描述后台构建任务。 """调度图片描述后台构建任务。
Args: Args:
image_hash: 图片哈希值。 image_hash: 图片哈希值。
image_bytes: 图片字节数据。 image_bytes: 图片字节数据。
saved_image: 已保存的图片对象,避免后台任务重复执行保存流程。
""" """
if not _is_vlm_task_configured(): if not _is_vlm_task_configured():
logger.info("未配置 VLM 模型,跳过图片后台识别任务") logger.info("未配置 VLM 模型,跳过图片后台识别任务")
@@ -151,20 +158,27 @@ class ImageManager:
if image_hash in self._pending_description_tasks: if image_hash in self._pending_description_tasks:
return return
task = asyncio.create_task(self._build_description_in_background(image_hash, image_bytes)) task = asyncio.create_task(self._build_description_in_background(image_hash, image_bytes, saved_image=saved_image))
self._pending_description_tasks[image_hash] = task self._pending_description_tasks[image_hash] = task
task.add_done_callback(lambda finished_task: self._finalize_description_build(image_hash, finished_task)) task.add_done_callback(lambda finished_task: self._finalize_description_build(image_hash, finished_task))
async def _build_description_in_background(self, image_hash: str, image_bytes: bytes) -> None: async def _build_description_in_background(
self,
image_hash: str,
image_bytes: bytes,
*,
saved_image: Optional[MaiImage] = None,
) -> None:
"""在后台构建并缓存图片描述。 """在后台构建并缓存图片描述。
Args: Args:
image_hash: 图片哈希值。 image_hash: 图片哈希值。
image_bytes: 图片字节数据。 image_bytes: 图片字节数据。
saved_image: 已保存的图片对象,避免重复查询和更新访问计数。
""" """
try: try:
logger.info(f"图片描述后台构建已开始,哈希值: {image_hash}") logger.info(f"图片描述后台构建已开始,哈希值: {image_hash}")
await self.build_image_description(image_bytes) await self.build_image_description(image_bytes, saved_image=saved_image)
logger.info(f"图片描述后台构建完成,哈希值: {image_hash}") logger.info(f"图片描述后台构建完成,哈希值: {image_hash}")
except Exception as exc: except Exception as exc:
logger.warning(f"图片描述后台构建失败,哈希值: {image_hash},错误: {exc}") logger.warning(f"图片描述后台构建失败,哈希值: {image_hash},错误: {exc}")
@@ -315,9 +329,14 @@ class ImageManager:
raise RuntimeError(f"保存图片记录到数据库失败: {hash_str}") raise RuntimeError(f"保存图片记录到数据库失败: {hash_str}")
return mai_image return mai_image
async def build_image_description(self, image_bytes: bytes) -> MaiImage: async def build_image_description(
self,
image_bytes: bytes,
*,
saved_image: Optional[MaiImage] = None,
) -> MaiImage:
"""在图片已保存的前提下生成或补齐图片描述。""" """在图片已保存的前提下生成或补齐图片描述。"""
mai_image = await self.ensure_image_saved(image_bytes) mai_image = saved_image or await self.ensure_image_saved(image_bytes)
if not mai_image.image_format: if not mai_image.image_format:
await mai_image.calculate_hash_format() await mai_image.calculate_hash_format()
if mai_image.vlm_processed and mai_image.description: if mai_image.vlm_processed and mai_image.description:

View File

@@ -57,7 +57,7 @@ MODEL_CONFIG_PATH: Path = (CONFIG_DIR / "model_config.toml").resolve().absolute(
LEGACY_ENV_PATH: Path = (PROJECT_ROOT / ".env").resolve().absolute() LEGACY_ENV_PATH: Path = (PROJECT_ROOT / ".env").resolve().absolute()
A_MEMORIX_LEGACY_CONFIG_PATH: Path = (CONFIG_DIR / "a_memorix.toml").resolve().absolute() A_MEMORIX_LEGACY_CONFIG_PATH: Path = (CONFIG_DIR / "a_memorix.toml").resolve().absolute()
MMC_VERSION: str = "1.0.0-pre.14" MMC_VERSION: str = "1.0.0-pre.14"
CONFIG_VERSION: str = "8.10.12" CONFIG_VERSION: str = "8.10.13"
MODEL_CONFIG_VERSION: str = "1.16.0" MODEL_CONFIG_VERSION: str = "1.16.0"
logger = get_logger("config") logger = get_logger("config")

View File

@@ -394,7 +394,7 @@ class ChatConfig(ConfigBase):
"""上下文长度""" """上下文长度"""
max_private_context_size: int = Field( max_private_context_size: int = Field(
default=40, default=60,
json_schema_extra={ json_schema_extra={
"label": { "label": {
"zh_CN": "私聊上下文", "zh_CN": "私聊上下文",
@@ -422,20 +422,21 @@ class ChatConfig(ConfigBase):
"""Planner 连续被新消息打断的最大次数0 表示不启用打断""" """Planner 连续被新消息打断的最大次数0 表示不启用打断"""
timing_gate_non_continue_cooldown_seconds: float = Field( timing_gate_non_continue_cooldown_seconds: float = Field(
default=0, default=8,
ge=0, ge=0,
json_schema_extra={ json_schema_extra={
"label": { "label": {
"zh_CN": "Timing Gate 非 continue 冷却", "zh_CN": "Timing Gate 平滑",
"en_US": "Timing Gate non-continue cooldown", "en_US": "Timing Gate non-continue cooldown",
"ja_JP": "Timing Gate 非 continue クールダウン", "ja_JP": "Timing Gate 非 continue クールダウン",
}, },
"x-widget": "input", "x-widget": "input",
"x-icon": "timer", "x-icon": "timer",
"advanced": True, "x-description-display": "icon",
"advanced": False,
}, },
) )
"""Timing Gate 返回 no_reply 时的最小窗口秒数0 表示不启用冷却""" """这个值决定了 timing gate 判断的频率值越大timing gate 的判断越平滑,但也可能导致反应变慢。建议根据实际情况调整,找到一个既能保持反应及时又不过于频繁的平衡点。"""
group_chat_prompt: str = Field( group_chat_prompt: str = Field(
default=( default=(