feat: add real-time TTS endpoint POST /api/tts
This commit is contained in:
65
app/main.py
65
app/main.py
@@ -219,6 +219,71 @@ async def get_chapter_audio(book_id: str, chapter_id: str):
|
||||
return FileResponse(chapter.audio_file, media_type="audio/mpeg", filename=f"{chapter_id}.mp3")
|
||||
|
||||
|
||||
# ── 实时 TTS 接口(兼容百度/阿里云风格)──────────────────────────────────
|
||||
|
||||
from fastapi.responses import Response
|
||||
|
||||
@app.post("/api/tts")
|
||||
async def realtime_tts(request: Request):
|
||||
"""
|
||||
实时 TTS 生成接口
|
||||
请求体 (JSON):
|
||||
- text: 要合成的文本(必填)
|
||||
- style: 风格(可选,如"开心"、"东北话")
|
||||
- speed: 语速调整(可选,暂未使用,MiMo 通过 style 控制语速)
|
||||
返回: MP3 音频二进制流 (audio/mpeg)
|
||||
"""
|
||||
data = await request.json()
|
||||
text = data.get("text", "").strip()
|
||||
style = data.get("style", "").strip()
|
||||
|
||||
if not text:
|
||||
return Response(
|
||||
content=json.dumps({"status": 40000001, "message": "text 不能为空"}, ensure_ascii=False),
|
||||
media_type="application/json",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
try:
|
||||
# MiMo TTS 生成 WAV
|
||||
wav_bytes = await call_mimo_tts(text, style)
|
||||
|
||||
# WAV → MP3(内存中完成)
|
||||
tmp_dir = Path(config.AUDIO_DIR) / "_tmp"
|
||||
tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||
tmp_id = uuid.uuid4().hex
|
||||
wav_path = str(tmp_dir / f"{tmp_id}.wav")
|
||||
mp3_path = str(tmp_dir / f"{tmp_id}.mp3")
|
||||
|
||||
with open(wav_path, "wb") as f:
|
||||
f.write(wav_bytes)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, wav_to_mp3, wav_path, mp3_path)
|
||||
|
||||
with open(mp3_path, "rb") as f:
|
||||
mp3_bytes = f.read()
|
||||
|
||||
# 清理临时文件
|
||||
os.remove(wav_path)
|
||||
os.remove(mp3_path)
|
||||
|
||||
return Response(content=mp3_bytes, media_type="audio/mpeg")
|
||||
|
||||
except HTTPException:
|
||||
return Response(
|
||||
content=json.dumps({"status": 50000001, "message": "TTS 生成失败"}, ensure_ascii=False),
|
||||
media_type="application/json",
|
||||
status_code=502,
|
||||
)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
content=json.dumps({"status": 50000002, "message": str(e)[:300]}, ensure_ascii=False),
|
||||
media_type="application/json",
|
||||
status_code=500,
|
||||
)
|
||||
|
||||
|
||||
# ── 管理 API ──────────────────────────────────────────────────────────────
|
||||
|
||||
# --- Books ---
|
||||
|
||||
Reference in New Issue
Block a user