diff --git a/astrbot/core/platform/sources/telegram/tg_adapter.py b/astrbot/core/platform/sources/telegram/tg_adapter.py index 82e2a4dfd1..b8c3a7a079 100644 --- a/astrbot/core/platform/sources/telegram/tg_adapter.py +++ b/astrbot/core/platform/sources/telegram/tg_adapter.py @@ -588,6 +588,25 @@ def _apply_caption() -> None: record.path = path_wav message.message = [record] + elif update.message.audio: + # Audio files use their own Bot API field and do not fall back to document. + file = await update.message.audio.get_file() + + file_basename = os.path.basename(cast(str, file.file_path)) + temp_dir = get_astrbot_temp_path() + temp_path = os.path.join(temp_dir, file_basename) + await download_file(cast(str, file.file_path), path=temp_path) + path_wav = await MediaResolver( + temp_path, + media_type="audio", + default_suffix=".wav", + ).to_path(target_format="wav") + + record = Comp.Record(file=path_wav, url=path_wav) + record.path = path_wav + message.message.append(record) + _apply_caption() + elif update.message.photo: photo = update.message.photo[-1] # get the largest photo file = await photo.get_file() diff --git a/tests/fixtures/helpers.py b/tests/fixtures/helpers.py index 5f3e78e5d7..de4aa30a74 100644 --- a/tests/fixtures/helpers.py +++ b/tests/fixtures/helpers.py @@ -98,6 +98,7 @@ def create_mock_update( video: MagicMock | None = None, document: MagicMock | None = None, voice: MagicMock | None = None, + audio: MagicMock | None = None, sticker: MagicMock | None = None, video_note: MagicMock | None = None, reply_to_message: MagicMock | None = None, @@ -122,6 +123,7 @@ def create_mock_update( video: 视频对象 document: 文档对象 voice: 语音对象 + audio: 音频文件对象 sticker: 贴纸对象 video_note: 圆形视频消息对象 reply_to_message: 回复的消息 @@ -160,6 +162,7 @@ def create_mock_update( message.video = video message.document = document message.voice = voice + message.audio = audio message.sticker = sticker message.video_note = video_note message.reply_to_message = reply_to_message diff --git a/tests/test_telegram_adapter.py b/tests/test_telegram_adapter.py index 07c9808806..47e2c16e3c 100644 --- a/tests/test_telegram_adapter.py +++ b/tests/test_telegram_adapter.py @@ -349,6 +349,49 @@ async def test_telegram_voice_message_creates_record_component(tmp_path): assert result.message[0].url == str(wav_path) +@pytest.mark.asyncio +async def test_telegram_audio_caption_populates_message_text_and_plain(tmp_path): + TelegramPlatformAdapter = _load_telegram_adapter() + adapter = TelegramPlatformAdapter( + make_platform_config("telegram"), + {}, + asyncio.Queue(), + ) + audio = create_mock_file("https://api.telegram.org/file/test/song.mp3") + update = create_mock_update( + message_text=None, + audio=audio, + caption="这首歌是什么", + ) + wav_path = tmp_path / "song.mp3.wav" + convert_message_globals = adapter.convert_message.__func__.__globals__ + + with ( + patch.dict( + convert_message_globals, + { + "get_astrbot_temp_path": MagicMock(return_value=str(tmp_path)), + "download_file": AsyncMock(), + }, + ), + patch( + "astrbot.core.utils.media_utils.ensure_wav", + AsyncMock(return_value=str(wav_path)), + ), + ): + result = await adapter.convert_message(update, _build_context()) + + assert result is not None + assert result.message_str == "这首歌是什么" + assert len(result.message) == 2 + assert isinstance(result.message[0], Comp.Record) + assert result.message[0].file == str(wav_path) + assert result.message[0].path == str(wav_path) + assert result.message[0].url == str(wav_path) + assert isinstance(result.message[1], Comp.Plain) + assert result.message[1].text == "这首歌是什么" + + @pytest.mark.asyncio async def test_telegram_final_segment_splits_long_markdown_messages(): TelegramPlatformEvent = _load_telegram_platform_event()