mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-12 16:02:35 +08:00
Improve agent image capability routing
This commit is contained in:
@@ -181,7 +181,9 @@ class DiscordModule(_ModuleBase, _MessageBase[Discord]):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _extract_images(msg_json: dict) -> Optional[List[str]]:
|
||||
def _extract_images(
|
||||
msg_json: dict,
|
||||
) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
"""
|
||||
从Discord消息中提取图片URL
|
||||
"""
|
||||
@@ -200,7 +202,14 @@ class DiscordModule(_ModuleBase, _MessageBase[Discord]):
|
||||
or content_type.startswith("image/")
|
||||
or filename.endswith(DiscordModule._IMAGE_SUFFIXES)
|
||||
):
|
||||
images.append(url)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=url,
|
||||
name=attachment.get("filename"),
|
||||
mime_type=attachment.get("content_type"),
|
||||
size=attachment.get("size"),
|
||||
)
|
||||
)
|
||||
return images if images else None
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -155,8 +155,10 @@ class QQBotModule(_ModuleBase, _MessageBase[QQBot]):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _extract_images(cls, msg_body: dict) -> Optional[List[str]]:
|
||||
images: List[str] = []
|
||||
def _extract_images(
|
||||
cls, msg_body: dict
|
||||
) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
images: List[CommingMessage.MessageImage] = []
|
||||
attachments = msg_body.get("attachments") or []
|
||||
if isinstance(attachments, list):
|
||||
for attachment in attachments:
|
||||
@@ -176,26 +178,42 @@ class QQBotModule(_ModuleBase, _MessageBase[QQBot]):
|
||||
or ""
|
||||
).lower()
|
||||
if content_type.startswith("image/") or filename.endswith(cls._IMAGE_SUFFIXES):
|
||||
images.append(url)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=url,
|
||||
name=attachment.get("filename") or attachment.get("name"),
|
||||
mime_type=attachment.get("content_type")
|
||||
or attachment.get("mime_type"),
|
||||
size=attachment.get("size"),
|
||||
)
|
||||
)
|
||||
|
||||
for key in ("image", "image_url", "pic_url"):
|
||||
value = msg_body.get(key)
|
||||
if isinstance(value, str) and value.startswith("http"):
|
||||
images.append(value)
|
||||
images.append(CommingMessage.MessageImage(ref=value))
|
||||
|
||||
extra_images = msg_body.get("images")
|
||||
if isinstance(extra_images, list):
|
||||
for item in extra_images:
|
||||
if isinstance(item, str) and item.startswith("http"):
|
||||
images.append(item)
|
||||
images.append(CommingMessage.MessageImage(ref=item))
|
||||
elif isinstance(item, dict):
|
||||
url = item.get("url") or item.get("image_url")
|
||||
if isinstance(url, str) and url.startswith("http"):
|
||||
images.append(url)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=url,
|
||||
name=item.get("name") or item.get("filename"),
|
||||
mime_type=item.get("content_type")
|
||||
or item.get("mime_type"),
|
||||
size=item.get("size"),
|
||||
)
|
||||
)
|
||||
|
||||
deduped = []
|
||||
for image in images:
|
||||
if image not in deduped:
|
||||
if image.ref not in [item.ref for item in deduped]:
|
||||
deduped.append(image)
|
||||
return deduped or None
|
||||
|
||||
|
||||
@@ -301,7 +301,9 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _extract_images(msg_json: dict) -> Optional[List[str]]:
|
||||
def _extract_images(
|
||||
msg_json: dict,
|
||||
) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
"""
|
||||
从Slack消息中提取图片URL
|
||||
"""
|
||||
@@ -320,7 +322,14 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]):
|
||||
):
|
||||
url = file.get("url_private") or file.get("url_private_download")
|
||||
if url:
|
||||
images.append(url)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=url,
|
||||
name=file.get("name") or file.get("title"),
|
||||
mime_type=file.get("mimetype"),
|
||||
size=file.get("size"),
|
||||
)
|
||||
)
|
||||
return images if images else None
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -141,12 +141,14 @@ class SynologyChatModule(_ModuleBase, _MessageBase[SynologyChat]):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _extract_images(cls, message: dict) -> Optional[List[str]]:
|
||||
def _extract_images(
|
||||
cls, message: dict
|
||||
) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
images = []
|
||||
for key in ("file_url", "image_url", "pic_url"):
|
||||
value = message.get(key)
|
||||
if isinstance(value, str) and cls._looks_like_image(value):
|
||||
images.append(value)
|
||||
images.append(CommingMessage.MessageImage(ref=value))
|
||||
|
||||
for key in ("attachments", "files"):
|
||||
raw_value = message.get(key)
|
||||
@@ -159,15 +161,23 @@ class SynologyChatModule(_ModuleBase, _MessageBase[SynologyChat]):
|
||||
items = parsed if isinstance(parsed, list) else [parsed]
|
||||
for item in items:
|
||||
if isinstance(item, str) and cls._looks_like_image(item):
|
||||
images.append(item)
|
||||
images.append(CommingMessage.MessageImage(ref=item))
|
||||
elif isinstance(item, dict):
|
||||
url = item.get("url") or item.get("file_url") or item.get("image_url")
|
||||
if isinstance(url, str) and cls._looks_like_image(url):
|
||||
images.append(url)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=url,
|
||||
name=item.get("name") or item.get("filename"),
|
||||
mime_type=item.get("content_type")
|
||||
or item.get("mime_type"),
|
||||
size=item.get("size"),
|
||||
)
|
||||
)
|
||||
|
||||
deduped = []
|
||||
for image in images:
|
||||
if image not in deduped:
|
||||
if image.ref not in [item.ref for item in deduped]:
|
||||
deduped.append(image)
|
||||
return deduped or None
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class TelegramModule(_ModuleBase, _MessageBase[Telegram]):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _extract_images(msg: dict) -> Optional[List[str]]:
|
||||
def _extract_images(msg: dict) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
"""
|
||||
从Telegram消息中提取图片file_id
|
||||
"""
|
||||
@@ -283,14 +283,27 @@ class TelegramModule(_ModuleBase, _MessageBase[Telegram]):
|
||||
largest_photo = photo[-1]
|
||||
file_id = largest_photo.get("file_id")
|
||||
if file_id:
|
||||
images.append(f"tg://file_id/{file_id}")
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=f"tg://file_id/{file_id}",
|
||||
mime_type="image/jpeg",
|
||||
size=largest_photo.get("file_size"),
|
||||
)
|
||||
)
|
||||
|
||||
document = msg.get("document")
|
||||
if document:
|
||||
file_id = document.get("file_id")
|
||||
mime_type = document.get("mime_type", "")
|
||||
if file_id and mime_type.startswith("image/"):
|
||||
images.append(f"tg://file_id/{file_id}")
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=f"tg://file_id/{file_id}",
|
||||
name=document.get("file_name"),
|
||||
mime_type=document.get("mime_type"),
|
||||
size=document.get("file_size"),
|
||||
)
|
||||
)
|
||||
|
||||
return images if images else None
|
||||
|
||||
|
||||
@@ -162,7 +162,9 @@ class VoceChatModule(_ModuleBase, _MessageBase[VoceChat]):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _extract_images(cls, detail: dict) -> Optional[List[str]]:
|
||||
def _extract_images(
|
||||
cls, detail: dict
|
||||
) -> Optional[List[CommingMessage.MessageImage]]:
|
||||
content_type = detail.get("content_type") or ""
|
||||
if content_type != "vocechat/file":
|
||||
return None
|
||||
@@ -194,9 +196,23 @@ class VoceChatModule(_ModuleBase, _MessageBase[VoceChat]):
|
||||
if not is_image:
|
||||
return None
|
||||
if isinstance(direct_url, str) and direct_url.startswith("http"):
|
||||
return [direct_url]
|
||||
return [
|
||||
CommingMessage.MessageImage(
|
||||
ref=direct_url,
|
||||
name=properties.get("name") or properties.get("filename"),
|
||||
mime_type=mime_type or None,
|
||||
size=properties.get("size"),
|
||||
)
|
||||
]
|
||||
if isinstance(file_path, str) and file_path:
|
||||
return [f"vocechat://file/{quote(file_path, safe='')}"]
|
||||
return [
|
||||
CommingMessage.MessageImage(
|
||||
ref=f"vocechat://file/{quote(file_path, safe='')}",
|
||||
name=properties.get("name") or properties.get("filename"),
|
||||
mime_type=mime_type or None,
|
||||
size=properties.get("size"),
|
||||
)
|
||||
]
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -189,9 +189,9 @@ class WechatModule(_ModuleBase, _MessageBase[WeChat]):
|
||||
media_id = DomUtils.tag_value(root_node, "MediaId")
|
||||
pic_url = DomUtils.tag_value(root_node, "PicUrl")
|
||||
if media_id:
|
||||
images = [f"wxwork://media_id/{media_id}"]
|
||||
images = [CommingMessage.MessageImage(ref=f"wxwork://media_id/{media_id}")]
|
||||
elif pic_url:
|
||||
images = [pic_url]
|
||||
images = [CommingMessage.MessageImage(ref=pic_url)]
|
||||
logger.info(
|
||||
f"收到来自 {client_config.name} 的微信图片消息:userid={user_id}, images={len(images) if images else 0}"
|
||||
)
|
||||
|
||||
@@ -16,6 +16,7 @@ from app.core.config import settings
|
||||
from app.core.context import MediaInfo, Context
|
||||
from app.core.metainfo import MetaInfo
|
||||
from app.log import logger
|
||||
from app.schemas import CommingMessage
|
||||
from app.utils.http import RequestUtils
|
||||
from app.utils.string import StringUtils
|
||||
|
||||
@@ -359,27 +360,50 @@ class WeChatBot:
|
||||
return f"wxbot://image/{encoded}"
|
||||
|
||||
@classmethod
|
||||
def _extract_images_from_body(cls, body: dict) -> Optional[List[str]]:
|
||||
images: List[str] = []
|
||||
def _extract_images_from_body(
|
||||
cls, body: dict
|
||||
) -> Optional[List["CommingMessage.MessageImage"]]:
|
||||
images: List["CommingMessage.MessageImage"] = []
|
||||
msgtype = body.get("msgtype")
|
||||
|
||||
if msgtype == "image":
|
||||
image_ref = cls._build_image_ref(body.get("image") or {})
|
||||
image_payload = body.get("image") or {}
|
||||
image_ref = cls._build_image_ref(image_payload)
|
||||
if image_ref:
|
||||
images.append(image_ref)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=image_ref,
|
||||
mime_type=image_payload.get("mime_type")
|
||||
or image_payload.get("content_type"),
|
||||
)
|
||||
)
|
||||
elif msgtype == "mixed":
|
||||
for item in (body.get("mixed") or {}).get("msg_item") or []:
|
||||
if item.get("msgtype") != "image":
|
||||
continue
|
||||
image_ref = cls._build_image_ref(item.get("image") or {})
|
||||
image_payload = item.get("image") or {}
|
||||
image_ref = cls._build_image_ref(image_payload)
|
||||
if image_ref:
|
||||
images.append(image_ref)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=image_ref,
|
||||
mime_type=image_payload.get("mime_type")
|
||||
or image_payload.get("content_type"),
|
||||
)
|
||||
)
|
||||
|
||||
quote = body.get("quote") or {}
|
||||
if not images and quote.get("msgtype") == "image":
|
||||
image_ref = cls._build_image_ref(quote.get("image") or {})
|
||||
image_payload = quote.get("image") or {}
|
||||
image_ref = cls._build_image_ref(image_payload)
|
||||
if image_ref:
|
||||
images.append(image_ref)
|
||||
images.append(
|
||||
CommingMessage.MessageImage(
|
||||
ref=image_ref,
|
||||
mime_type=image_payload.get("mime_type")
|
||||
or image_payload.get("content_type"),
|
||||
)
|
||||
)
|
||||
|
||||
return images or None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user