133 lines
4.0 KiB
Python
133 lines
4.0 KiB
Python
|
import datetime
|
|||
|
import logging
|
|||
|
import uuid
|
|||
|
from typing import Optional
|
|||
|
|
|||
|
from fastapi import APIRouter, HTTPException, Query, Request
|
|||
|
from fastapi.responses import JSONResponse
|
|||
|
from pydantic import BaseModel
|
|||
|
|
|||
|
from Config import Config
|
|||
|
from Util.VideoRetalk import VideoRetalk
|
|||
|
|
|||
|
# 创建视频生成路由
|
|||
|
router = APIRouter(prefix="/api/video", tags=["视频生成"])
|
|||
|
|
|||
|
# 配置日志
|
|||
|
logger = logging.getLogger(__name__)
|
|||
|
|
|||
|
# 仅保留视频相关模型定义
|
|||
|
class VideoRetalkRequest(BaseModel):
|
|||
|
"""视频生成请求参数"""
|
|||
|
image_url: str
|
|||
|
audio_url: str
|
|||
|
template_id: Optional[str] = "normal"
|
|||
|
eye_move_freq: Optional[float] = 0.5
|
|||
|
video_fps: Optional[int] = 30
|
|||
|
mouth_move_strength: Optional[float] = 1.0
|
|||
|
paste_back: Optional[bool] = True
|
|||
|
head_move_strength: Optional[float] = 0.7
|
|||
|
|
|||
|
|
|||
|
class VideoRetalkResponse(BaseModel):
|
|||
|
"""视频生成响应"""
|
|||
|
success: bool
|
|||
|
message: str
|
|||
|
task_id: Optional[str] = None
|
|||
|
video_url: Optional[str] = None
|
|||
|
video_duration: Optional[float] = None
|
|||
|
video_ratio: Optional[str] = None
|
|||
|
request_id: Optional[str] = None
|
|||
|
|
|||
|
|
|||
|
@router.post("/generate", response_model=VideoRetalkResponse)
|
|||
|
async def generate_video(request: VideoRetalkRequest):
|
|||
|
"""
|
|||
|
生成人物朗读视频接口
|
|||
|
根据输入的人物图片和音频,生成口型匹配的朗读视频
|
|||
|
"""
|
|||
|
try:
|
|||
|
# 初始化VideoRetalk实例
|
|||
|
video_retalk = VideoRetalk(Config.ALY_LLM_API_KEY)
|
|||
|
|
|||
|
# 调用视频生成方法
|
|||
|
video_url = video_retalk.generate_video(
|
|||
|
image_url=request.image_url,
|
|||
|
audio_url=request.audio_url,
|
|||
|
template_id=request.template_id,
|
|||
|
eye_move_freq=request.eye_move_freq,
|
|||
|
video_fps=request.video_fps,
|
|||
|
mouth_move_strength=request.mouth_move_strength,
|
|||
|
paste_back=request.paste_back,
|
|||
|
head_move_strength=request.head_move_strength
|
|||
|
)
|
|||
|
|
|||
|
if video_url:
|
|||
|
return VideoRetalkResponse(
|
|||
|
success=True,
|
|||
|
message="视频生成成功",
|
|||
|
video_url=video_url,
|
|||
|
# 以下字段在实际实现中可以从API响应中获取
|
|||
|
task_id=str(uuid.uuid4()),
|
|||
|
video_duration=10.23, # 示例值,实际应从API响应获取
|
|||
|
video_ratio="standard", # 示例值,实际应从API响应获取
|
|||
|
request_id=str(uuid.uuid4())
|
|||
|
)
|
|||
|
else:
|
|||
|
return VideoRetalkResponse(
|
|||
|
success=False,
|
|||
|
message="视频生成失败"
|
|||
|
)
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"视频生成接口错误: {e}")
|
|||
|
raise HTTPException(
|
|||
|
status_code=500,
|
|||
|
detail=f"视频生成失败: {str(e)}"
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
@router.get("/task/status")
|
|||
|
async def get_task_status(task_id: str = Query(..., description="任务ID")):
|
|||
|
"""
|
|||
|
查询视频生成任务状态
|
|||
|
"""
|
|||
|
try:
|
|||
|
video_retalk = VideoRetalk(Config.ALY_LLM_API_KEY)
|
|||
|
task_status = video_retalk.get_task_status(task_id)
|
|||
|
|
|||
|
return {
|
|||
|
"success": True,
|
|||
|
"data": task_status
|
|||
|
}
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"查询任务状态错误: {e}")
|
|||
|
raise HTTPException(
|
|||
|
status_code=500,
|
|||
|
detail=f"查询任务状态失败: {str(e)}"
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
@router.get("/health")
|
|||
|
async def health_check():
|
|||
|
"""
|
|||
|
健康检查接口
|
|||
|
"""
|
|||
|
return {
|
|||
|
"status": "healthy",
|
|||
|
"timestamp": datetime.datetime.now().isoformat(),
|
|||
|
"service": "VideoRetalk API"
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
# 保留全局异常处理
|
|||
|
def global_exception_handler(request: Request, exc: Exception):
|
|||
|
logger.error(f"全局异常: {exc}")
|
|||
|
return JSONResponse(
|
|||
|
status_code=500,
|
|||
|
content={"success": False, "message": f"服务器内部错误: {str(exc)}"}
|
|||
|
)
|
|||
|
|
|||
|
|