ForcePilot/backend/package/yuxi/channels/adapters/feishu/audio.py
Kris a6fa7245e5 feat(feishu): 完整实现飞书适配器核心模块
新增飞书机器人适配器全套功能,包括:
- 基础适配器入口与工具导出
- 消息格式化、卡片渲染、回复调度逻辑
- 会话ID生成、模型覆盖策略
- 消息发送缓存、顺序队列管理
- 飞书签名验证、加解密webhook请求
- 审批权限校验、机器人菜单事件处理
- 文档评论、钉消息、语音转码处理
- 静态/动态目录管理、子代理生命周期管理
- 各类工具集:聊天、云盘、文档、知识库API封装
2026-05-12 00:43:59 +08:00

75 lines
2.0 KiB
Python

from __future__ import annotations
import logging
import subprocess
import tempfile
from pathlib import Path
logger = logging.getLogger(__name__)
TARGET_SAMPLE_RATE = 48000
TARGET_BITRATE = "64k"
TARGET_FORMAT = "ogg"
TARGET_CODEC = "libopus"
def check_ffmpeg_available() -> bool:
try:
result = subprocess.run(["ffmpeg", "-version"], capture_output=True, timeout=5)
return result.returncode == 0
except (FileNotFoundError, subprocess.TimeoutExpired):
return False
def transcode_to_ogg_opus(
input_data: bytes,
input_format: str = "mp3",
sample_rate: int = TARGET_SAMPLE_RATE,
bitrate: str = TARGET_BITRATE,
) -> bytes | None:
if not check_ffmpeg_available():
logger.warning("[FeishuAudio] FFmpeg not available, skipping transcode")
return None
with tempfile.NamedTemporaryFile(suffix=f".{input_format}", delete=False) as infile:
infile.write(input_data)
input_path = infile.name
output_path = input_path + f".{TARGET_FORMAT}"
try:
cmd = [
"ffmpeg",
"-y",
"-i",
input_path,
"-ar",
str(sample_rate),
"-b:a",
bitrate,
"-c:a",
TARGET_CODEC,
output_path,
]
result = subprocess.run(cmd, capture_output=True, timeout=60)
if result.returncode != 0:
logger.error(
"[FeishuAudio] FFmpeg transcode failed: %s",
result.stderr.decode(errors="replace")[:300],
)
return None
output_bytes = Path(output_path).read_bytes()
logger.info(
"[FeishuAudio] Transcode complete: %d -> %d bytes",
len(input_data),
len(output_bytes),
)
return output_bytes
except Exception as e:
logger.error("[FeishuAudio] Transcode error: %s", e)
return None
finally:
Path(input_path).unlink(missing_ok=True)
Path(output_path).unlink(missing_ok=True)