ForcePilot/backend/package/yuxi/channels/adapters/whatsapp/voice/transcode.py
Kris e9b57546ea feat(whatsapp): 新增WhatsApp适配器完整功能模块
新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
2026-05-12 00:51:58 +08:00

86 lines
2.5 KiB
Python

from __future__ import annotations
import asyncio
import os
import tempfile
from pathlib import Path
from yuxi.utils.logging_config import logger
class Transcoder:
def __init__(self, ffmpeg_path: str = "ffmpeg"):
self._ffmpeg = ffmpeg_path
async def to_ogg_opus(self, input_path: str, sample_rate: int = 16000) -> str:
output_path = input_path + ".ogg"
cmd = [
self._ffmpeg,
"-y",
"-i",
input_path,
"-c:a",
"libopus",
"-b:a",
"24k",
"-ar",
str(sample_rate),
"-ac",
"1",
"-vbr",
"on",
"-application",
"voip",
"-frame_duration",
"20",
output_path,
]
try:
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
err_msg = stderr.decode()[:500] if stderr else "unknown error"
raise RuntimeError(f"FFmpeg transcode failed (exit {process.returncode}): {err_msg}")
logger.debug(f"Transcoded {input_path}{output_path}")
return output_path
except FileNotFoundError:
raise RuntimeError(f"FFmpeg not found at '{self._ffmpeg}'. Install FFmpeg to use TTS voice notes.")
async def wav_to_ogg_opus(self, wav_data: bytes) -> bytes:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
f.write(wav_data)
tmp_in = f.name
try:
tmp_out = await self.to_ogg_opus(tmp_in)
try:
return Path(tmp_out).read_bytes()
finally:
if os.path.exists(tmp_out):
os.unlink(tmp_out)
finally:
if os.path.exists(tmp_in):
os.unlink(tmp_in)
async def check_available(self) -> bool:
try:
proc = await asyncio.create_subprocess_exec(
self._ffmpeg,
"-version",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
await proc.communicate()
return proc.returncode == 0
except FileNotFoundError:
return False
transcoder = Transcoder()