diff --git a/astrbot/core/pipeline/preprocess_stage/stage.py b/astrbot/core/pipeline/preprocess_stage/stage.py index 464f584f8e..0d6d09370e 100644 --- a/astrbot/core/pipeline/preprocess_stage/stage.py +++ b/astrbot/core/pipeline/preprocess_stage/stage.py @@ -76,8 +76,8 @@ async def process( return message_chain = event.get_messages() for idx, component in enumerate(message_chain): - if isinstance(component, Record) and component.url: - path = component.url.removeprefix("file://") + if isinstance(component, Record): + path = await component.convert_to_file_path() retry = 5 for i in range(retry): try: diff --git a/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py b/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py index 82a6afbacf..8419c0ea01 100644 --- a/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +++ b/astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py @@ -5,6 +5,8 @@ import os import random import time +import uuid +from pathlib import Path from types import SimpleNamespace from typing import Any, cast @@ -24,6 +26,8 @@ ) from astrbot.core.message.components import BaseMessageComponent from astrbot.core.platform.astr_message_event import MessageSesion +from astrbot.core.utils.astrbot_path import get_astrbot_temp_path +from astrbot.core.utils.io import download_file from ...register import register_platform_adapter from .qqofficial_message_event import QQOfficialMessageEvent @@ -42,7 +46,7 @@ def set_platform(self, platform: QQOfficialPlatformAdapter) -> None: async def on_group_at_message_create( self, message: botpy.message.GroupMessage ) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.GROUP_MESSAGE, ) @@ -53,7 +57,7 @@ async def on_group_at_message_create( # 收到频道消息 async def on_at_message_create(self, message: botpy.message.Message) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.GROUP_MESSAGE, ) @@ -66,7 +70,7 @@ async def on_at_message_create(self, message: botpy.message.Message) -> None: async def on_direct_message_create( self, message: botpy.message.DirectMessage ) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.FRIEND_MESSAGE, ) @@ -76,7 +80,7 @@ async def on_direct_message_create( # 收到 C2C 消息 async def on_c2c_message_create(self, message: botpy.message.C2CMessage) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.FRIEND_MESSAGE, ) @@ -336,7 +340,22 @@ def _normalize_attachment_url(url: str | None) -> str: return f"https://{url}" @staticmethod - def _append_attachments( + async def _prepare_audio_attachment( + url: str, + filename: str, + ) -> Record: + temp_dir = Path(get_astrbot_temp_path()) + temp_dir.mkdir(parents=True, exist_ok=True) + + ext = Path(filename).suffix.lower() + source_ext = ext or ".audio" + source_path = temp_dir / f"qqofficial_{uuid.uuid4().hex}{source_ext}" + await download_file(url, str(source_path)) + + return Record(file=str(source_path), url=str(source_path)) + + @staticmethod + async def _append_attachments( msg: list[BaseMessageComponent], attachments: list | None, ) -> None: @@ -363,7 +382,7 @@ def _append_attachments( or getattr(attachment, "name", None) or "attachment", ) - ext = os.path.splitext(filename)[1].lower() + ext = Path(filename).suffix.lower() image_exts = {".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"} audio_exts = { ".mp3", @@ -381,8 +400,21 @@ def _append_attachments( ".webm", } - if content_type.startswith("audio") or ext in audio_exts: - msg.append(Record.fromURL(url)) + if content_type.startswith("voice") or ext in audio_exts: + try: + msg.append( + await QQOfficialPlatformAdapter._prepare_audio_attachment( + url, + filename, + ) + ) + except Exception as e: + logger.warning( + "[QQOfficial] Failed to prepare audio attachment %s: %s", + url, + e, + ) + msg.append(Record.fromURL(url)) elif content_type.startswith("video") or ext in video_exts: msg.append(Video.fromURL(url)) elif content_type.startswith("image") or ext in image_exts: @@ -432,13 +464,13 @@ def replace_face(match): return re.sub(r"]*>", replace_face, content) @staticmethod - def _parse_from_qqofficial( + async def _parse_from_qqofficial( message: botpy.message.Message | botpy.message.GroupMessage | botpy.message.DirectMessage | botpy.message.C2CMessage, message_type: MessageType, - ): + ) -> AstrBotMessage: abm = AstrBotMessage() abm.type = message_type abm.timestamp = int(time.time()) @@ -463,7 +495,9 @@ def _parse_from_qqofficial( abm.self_id = "unknown_selfid" msg.append(At(qq="qq_official")) msg.append(Plain(abm.message_str)) - QQOfficialPlatformAdapter._append_attachments(msg, message.attachments) + await QQOfficialPlatformAdapter._append_attachments( + msg, message.attachments + ) abm.message = msg elif isinstance(message, botpy.message.Message) or isinstance( @@ -482,7 +516,9 @@ def _parse_from_qqofficial( ).strip() ) - QQOfficialPlatformAdapter._append_attachments(msg, message.attachments) + await QQOfficialPlatformAdapter._append_attachments( + msg, message.attachments + ) abm.message = msg abm.message_str = plain_content abm.sender = MessageMember( diff --git a/astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py b/astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py index 4c73fdf381..b4dbe36b0d 100644 --- a/astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +++ b/astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py @@ -31,7 +31,7 @@ def set_platform(self, platform: "QQOfficialWebhookPlatformAdapter") -> None: async def on_group_at_message_create( self, message: botpy.message.GroupMessage ) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.GROUP_MESSAGE, ) @@ -42,7 +42,7 @@ async def on_group_at_message_create( # 收到频道消息 async def on_at_message_create(self, message: botpy.message.Message) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.GROUP_MESSAGE, ) @@ -55,7 +55,7 @@ async def on_at_message_create(self, message: botpy.message.Message) -> None: async def on_direct_message_create( self, message: botpy.message.DirectMessage ) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.FRIEND_MESSAGE, ) @@ -65,7 +65,7 @@ async def on_direct_message_create( # 收到 C2C 消息 async def on_c2c_message_create(self, message: botpy.message.C2CMessage) -> None: - abm = QQOfficialPlatformAdapter._parse_from_qqofficial( + abm = await QQOfficialPlatformAdapter._parse_from_qqofficial( message, MessageType.FRIEND_MESSAGE, )