Files
xiaoxia-saas/packages/application/tts_job/audio_merger.py
T
xiaoxia 531aacb57e
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
fix(code-quality): 第二批 - B904 raise-without-from 批量修复 (71个) (#353)
2026-07-15 11:51:45 +08:00

94 lines
2.8 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""FFmpeg 音频合并器 — P1 长文本分段合成。
将多个分段音频文件合并为一个完整音频文件。
"""
from __future__ import annotations
import logging
import os
import shutil
import tempfile
from subprocess import CalledProcessError, TimeoutExpired
from packages.shared.ffmpeg_utils import FFMPEG_BIN, run_ffmpeg
logger = logging.getLogger(__name__)
class AudioMergeError(Exception):
"""音频合并异常。"""
pass
class AudioMerger:
"""使用 FFmpeg 合并多个音频文件。"""
def merge(self, audio_paths: list[str], output_format: str = "mp3") -> bytes:
"""合并多个音频文件,返回合并后的音频数据。
使用 FFmpeg concat demuxer 按顺序拼接音频。
所有输入文件必须为相同格式和采样率。
Args:
audio_paths: 音频文件路径列表(按合成顺序)
output_format: 输出格式(mp3/wav/pcm
Returns:
合并后的音频文件字节数据
Raises:
AudioMergeError: 合并失败
"""
if not audio_paths:
raise AudioMergeError("没有可合并的音频文件")
if len(audio_paths) == 1:
with open(audio_paths[0], "rb") as f:
return f.read()
temp_dir = tempfile.mkdtemp(prefix="tts_merge_")
try:
# 生成 concat demuxer 列表文件
list_path = os.path.join(temp_dir, "concat_list.txt")
with open(list_path, "w") as f:
for path in audio_paths:
# FFmpeg concat 文件需要 file: 前缀,路径中的 ' 和 \n 需转义
escaped = path.replace("'", "'\\''").replace("\n", "\\n")
f.write(f"file '{escaped}'\n")
output_path = os.path.join(temp_dir, f"merged.{output_format}")
cmd = [
FFMPEG_BIN,
"-y",
"-f",
"concat",
"-safe",
"0",
"-i",
list_path,
"-c",
"copy",
output_path,
]
try:
run_ffmpeg(cmd, timeout=120)
except CalledProcessError as e:
logger.error(f"FFmpeg 合并失败: stderr={e.stderr}")
raise AudioMergeError(f"FFmpeg 合并失败: {str(e)[:500]}") from e
with open(output_path, "rb") as f:
return f.read()
except TimeoutExpired as _e:
raise AudioMergeError("FFmpeg 合并超时(120 秒)") from _e
except AudioMergeError:
raise
except Exception as e:
raise AudioMergeError(f"音频合并失败: {e}") from e
finally:
shutil.rmtree(temp_dir, ignore_errors=True)