From f75c2d30b4ccbf211c9058c4dd94753b32d1d025 Mon Sep 17 00:00:00 2001 From: No-22-Github <132265925+No-22-Github@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:59:22 +0800 Subject: [PATCH] fix(core): Record.path was incorrectly treated as required under Pydantic v2 (#7048) * fix: make Record.path optional for pydantic v2 compatibility * fix: preserve telegram voice record path --- astrbot/core/message/components.py | 2 +- .../platform/sources/telegram/tg_adapter.py | 6 ++-- tests/test_telegram_adapter.py | 36 ++++++++++++++++++- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py index 6311681cd..29bb478da 100644 --- a/astrbot/core/message/components.py +++ b/astrbot/core/message/components.py @@ -122,7 +122,7 @@ class Record(BaseMessageComponent): # Original text content (e.g. TTS source text), used as caption in fallback scenarios text: str | None = None # 额外 - path: str | None + path: str | None = None def __init__(self, file: str | None, **_) -> None: for k in _: diff --git a/astrbot/core/platform/sources/telegram/tg_adapter.py b/astrbot/core/platform/sources/telegram/tg_adapter.py index 6c22a1aa5..337d6f56d 100644 --- a/astrbot/core/platform/sources/telegram/tg_adapter.py +++ b/astrbot/core/platform/sources/telegram/tg_adapter.py @@ -458,9 +458,9 @@ class TelegramPlatformAdapter(Platform): ) path_wav = await convert_audio_to_wav(temp_path, path_wav) - message.message = [ - Comp.Record(file=path_wav, url=path_wav), - ] + record = Comp.Record(file=path_wav, url=path_wav) + record.path = path_wav + message.message = [record] elif update.message.photo: photo = update.message.photo[-1] # get the largest photo diff --git a/tests/test_telegram_adapter.py b/tests/test_telegram_adapter.py index f7ae4d4be..480d6f131 100644 --- a/tests/test_telegram_adapter.py +++ b/tests/test_telegram_adapter.py @@ -1,7 +1,7 @@ import asyncio import importlib import sys -from unittest.mock import MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -106,3 +106,37 @@ async def test_telegram_video_caption_populates_message_text_and_plain(): isinstance(component, Comp.Plain) and component.text == "这段视频讲了什么" for component in result.message ) + + +@pytest.mark.asyncio +async def test_telegram_voice_message_creates_record_component(tmp_path): + TelegramPlatformAdapter = _load_telegram_adapter() + adapter = TelegramPlatformAdapter( + make_platform_config("telegram"), + {}, + asyncio.Queue(), + ) + voice = create_mock_file("https://api.telegram.org/file/test/voice.oga") + update = create_mock_update( + message_text=None, + voice=voice, + ) + wav_path = tmp_path / "voice.oga.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(), + "convert_audio_to_wav": AsyncMock(return_value=str(wav_path)), + }, + ): + result = await adapter.convert_message(update, _build_context()) + + assert result is not None + assert len(result.message) == 1 + 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)