ForcePilot/backend/package/yuxi/channels/adapters/telegram/voice.py
Kris 31736aef74 refactor(telegram-adapter): 整理导入顺序并实现多账号管理增强
1.  整理多个文件的导入顺序,统一模块导入规范
2.  为多账号管理器添加线程安全的账号守卫和生命周期钩子
3.  新增账号增删、启停和配置变更的完整操作方法
4.  重构轮询偏移存储,使用适配器状态替代本地缓存
5.  优化BotCommandScope的参数构建逻辑
2026-05-13 16:15:39 +08:00

128 lines
3.1 KiB
Python

from __future__ import annotations
import io
from typing import Any
from telegram import Bot
from telegram.error import TelegramError
from yuxi.utils.logging_config import logger
_VOICE_COMPATIBLE_FORMATS = frozenset({"ogg", "opus", "flac", "wav", "m4a", "mp3", "aac"})
def is_voice_compatible_audio(filename: str) -> bool:
ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""
return ext in _VOICE_COMPATIBLE_FORMATS
async def send_voice_from_bytes(
bot: Bot,
chat_id: str,
audio_bytes: bytes,
filename: str = "voice.ogg",
duration: int | None = None,
caption: str | None = None,
**kwargs,
) -> Any:
try:
buf = io.BytesIO(audio_bytes)
buf.name = filename
return await bot.send_voice(
chat_id=chat_id,
voice=buf,
duration=duration,
caption=caption,
**kwargs,
)
except TelegramError as e:
logger.error(f"[Telegram] Failed to send voice: {e}")
raise
async def send_audio_from_bytes(
bot: Bot,
chat_id: str,
audio_bytes: bytes,
filename: str = "audio.mp3",
title: str | None = None,
performer: str | None = None,
duration: int | None = None,
caption: str | None = None,
**kwargs,
) -> Any:
try:
buf = io.BytesIO(audio_bytes)
buf.name = filename
return await bot.send_audio(
chat_id=chat_id,
audio=buf,
title=title,
performer=performer,
duration=duration,
caption=caption,
**kwargs,
)
except TelegramError as e:
logger.error(f"[Telegram] Failed to send audio: {e}")
raise
async def send_voice_or_audio(
bot: Bot,
chat_id: str,
audio_bytes: bytes,
filename: str = "audio.ogg",
as_voice: bool = False,
duration: int | None = None,
caption: str | None = None,
title: str | None = None,
performer: str | None = None,
**kwargs,
) -> Any:
if as_voice or is_voice_compatible_audio(filename):
return await send_voice_from_bytes(
bot,
chat_id,
audio_bytes,
filename=filename or "voice.ogg",
duration=duration,
caption=caption,
**kwargs,
)
return await send_audio_from_bytes(
bot,
chat_id,
audio_bytes,
filename=filename or "audio.mp3",
title=title,
performer=performer,
duration=duration,
caption=caption,
**kwargs,
)
async def send_video_note_from_bytes(
bot: Bot,
chat_id: str,
video_bytes: bytes,
filename: str = "video_note.mp4",
duration: int | None = None,
length: int | None = None,
**kwargs,
) -> Any:
try:
buf = io.BytesIO(video_bytes)
buf.name = filename
return await bot.send_video_note(
chat_id=chat_id,
video_note=buf,
duration=duration,
length=length,
**kwargs,
)
except TelegramError as e:
logger.error(f"[Telegram] Failed to send video note: {e}")
raise