Download app/api/voice.py from gitdeem/mp4: direct link, hf CLI and curl.
- Browser
- Download file 3.78 kB
-
https://huggingface.co/spaces/gitdeem/mp4/resolve/main/app/api/voice.py
- Command line
-
hf download hf://spaces/gitdeem/mp4/app/api/voice.py
-
curl -L -o voice.py https://huggingface.co/spaces/gitdeem/mp4/resolve/main/app/api/voice.py
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 | |
| 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)) | |
| 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)) | |
| async def list_voices(request: VoiceRequest) -> dict: | |
| """ | |
| 获取所有支持的语音列表 | |
| """ | |
| return {"voices": get_all_azure_voices(request.area)} | |