mp4 / app /api /voice.py
gitdeem's picture
Upload 34 files
a9837a2 verified
raw
history blame
3.78 kB
from fastapi import APIRouter, HTTPException, Request, Query
from fastapi.responses import JSONResponse
from app.schemas.voice import VoiceGenerationRequest, VoiceGenerationResponse
from app.schemas.video import VideoGenerateResponse, StoryScene
from app.services.voice import generate_voice, get_all_azure_voices
from app.services.video import create_video_with_scenes
import os
import json
from typing import List, Optional
from pydantic import BaseModel
router = APIRouter()
class VoiceRequest(BaseModel):
area: Optional[List[str]] = None
@router.post("/test_subtitle")
async def test_subtitle_endpoint(task_id: str = Query(..., description="任务ID,对应 storage/tasks/ 下的目录名")) -> VideoGenerateResponse:
"""测试字幕添加功能"""
try:
# 构建任务目录路径
task_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "storage", "tasks", task_id)
if not os.path.exists(task_dir):
raise HTTPException(status_code=404, detail=f"Task directory not found: {task_id}")
# 读取 story.json
story_file = os.path.join(task_dir, "story.json")
if not os.path.exists(story_file):
raise HTTPException(status_code=404, detail=f"Story file not found: {story_file}")
with open(story_file, 'r', encoding='utf-8') as f:
scenes_data = json.load(f)
# 转换为 StoryScene 对象
scenes = [StoryScene(**scene) for scene in scenes_data]
# 生成语音和字幕
voice_name = "zh-CN-XiaoxiaoNeural"
voice_rate = 0
for i, scene in enumerate(scenes, 1):
audio_file = os.path.join(task_dir, f"{i}.mp3")
subtitle_file = os.path.join(task_dir, f"{i}.srt")
await generate_voice(scene.text, voice_name, voice_rate, audio_file, subtitle_file)
# 创建视频
video_file = await create_video_with_scenes(task_dir, scenes, voice_name, voice_rate)
video_url = "/" + video_file.split("/tasks/")[-1]
return VideoGenerateResponse(video_url=video_url, scenes=scenes)
except Exception as e:
logger.error(f"Failed to test subtitle: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/generate", response_model=VoiceGenerationResponse)
async def generate_voice_api(request: Request) -> VoiceGenerationResponse:
"""
生成语音和字幕文件
Args:
request: 包含文本内容和语音配置的请求
Returns:
生成的音频和字幕文件的URL
"""
try:
# 手动解析请求体
body = await request.json()
req = VoiceGenerationRequest(**body)
audio_file, subtitle_file = await generate_voice(
text=req.text,
voice_name=req.voice_name,
voice_rate=req.voice_rate
)
if not audio_file or not subtitle_file:
raise HTTPException(status_code=500, detail="Failed to generate voice")
# 将文件路径转换为URL路径
audio_url = f"/tasks/{os.path.basename(audio_file)}"
subtitle_url = f"/tasks/{os.path.basename(subtitle_file)}"
return VoiceGenerationResponse(
audio_url=audio_url,
subtitle_url=subtitle_url
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/voices")
async def list_voices(request: VoiceRequest) -> dict:
"""
获取所有支持的语音列表
"""
return {"voices": get_all_azure_voices(request.area)}