feat(agent): add audio message extraction and download support for Slack, QQ, Discord, SynologyChat, and VoceChat

This commit is contained in:
jxxghp
2026-04-13 08:36:57 +08:00
parent 8d938c2273
commit e09f9ad009
7 changed files with 601 additions and 15 deletions
+58
View File
@@ -3,6 +3,7 @@ import re
import time
from datetime import datetime, timedelta
from typing import Any, Optional, Dict, Union, List
from urllib.parse import unquote
import base64
@@ -1338,8 +1339,39 @@ class MessageChain(ChainBase):
"download_wechat_media_bytes", media_ref=audio_ref, source=source
)
filename = "input.amr"
elif audio_ref.startswith("slack://file/"):
content = self.run_module(
"download_slack_file_bytes", file_ref=audio_ref, source=source
)
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
elif audio_ref.startswith("discord://file/"):
content = self.run_module(
"download_discord_file_bytes", file_ref=audio_ref, source=source
)
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
elif audio_ref.startswith("qq://file/"):
content = self.run_module(
"download_qq_file_bytes", file_ref=audio_ref, source=source
)
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
elif audio_ref.startswith("vocechat://file/"):
content = self.run_module(
"download_vocechat_file_bytes", file_ref=audio_ref, source=source
)
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
elif audio_ref.startswith("synology://file/"):
content = self.run_module(
"download_synologychat_file_bytes",
file_ref=audio_ref,
source=source,
)
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
elif audio_ref.startswith("wxbot://voice"):
continue
elif audio_ref.startswith("http"):
resp = RequestUtils(timeout=30).get_res(audio_ref)
content = resp.content if resp and resp.content else None
filename = self._guess_audio_filename(audio_ref, default="input.ogg")
else:
logger.debug(
"暂不支持的语音引用: channel=%s, source=%s, ref=%s",
@@ -1349,6 +1381,15 @@ class MessageChain(ChainBase):
)
continue
if not content:
logger.warning(
"语音下载失败,跳过识别: channel=%s, source=%s, ref=%s",
channel.value if channel else None,
source,
audio_ref,
)
continue
transcript = VoiceHelper.transcribe_bytes(content=content, filename=filename)
if transcript:
transcripts.append(transcript)
@@ -1364,6 +1405,23 @@ class MessageChain(ChainBase):
return "\n".join(transcripts).strip() if transcripts else None
@staticmethod
def _guess_audio_filename(audio_ref: str, default: str = "input.ogg") -> str:
"""
根据引用中的扩展名推测音频文件名,便于 STT 服务识别格式。
"""
if not audio_ref:
return default
raw_ref = unquote(audio_ref).split("?", 1)[0].split("#", 1)[0]
match = re.search(
r"([^/]+\.(mp3|m4a|wav|ogg|oga|opus|aac|amr|flac|mpga|mpeg|webm))$",
raw_ref,
flags=re.IGNORECASE,
)
if match:
return match.group(1)
return default
def _download_images_to_base64(
self, images: List[str], channel: MessageChannel, source: str
) -> List[str]: