datasea's picture
Update app.py
b08c203 verified
from fastapi import FastAPI, UploadFile, Form
from fastapi.responses import FileResponse
import uuid
import os
import subprocess
app = FastAPI()
# Overlay 和字体资源路径(固定)
FONT_PATH = "/app/assets/fonts/FonderLTHTCH.ttf"
OVERLAY_PATH = "/app/assets/overlays/dust_particles-1.mp4"
@app.post("/render")
async def render_video(
image: UploadFile,
audio: UploadFile,
fps: int = Form(...),
filter_complex: str = Form(...),
preset: str = Form(...),
filename: str = Form(...),
video_path: str = Form(...),
shortest: bool = Form(True),
):
# 文件处理
image_ext = image.filename.split(".")[-1]
audio_ext = audio.filename.split(".")[-1]
image_path = f"/tmp/{uuid.uuid4()}.{image_ext}"
audio_path = f"/tmp/{uuid.uuid4()}.{audio_ext}"
output_path = f"{video_path.rstrip('/')}/{filename}.mp4"
# 保存上传的 image 和 audio
with open(image_path, "wb") as f:
f.write(await image.read())
with open(audio_path, "wb") as f:
f.write(await audio.read())
# 构造 FFmpeg 命令
cmd = [
"ffmpeg", "-y", "-nostdin", "-hide_banner", "-loglevel", "error",
"-loop", "1", "-framerate", str(fps), "-i", image_path,
"-i", OVERLAY_PATH,
"-i", audio_path,
"-filter_complex", filter_complex,
"-map", "[v]", "-map", "2:a",
"-c:v", "libx264", "-preset", preset, "-pix_fmt", "yuv420p",
"-c:a", "aac", "-b:a", "192k",
"-movflags", "+faststart",
"-metadata", f"title={filename}"
]
if shortest:
cmd.append("-shortest")
cmd.append(output_path)
# 确保目标路径存在(仅用于 Space /tmp 测试)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
# 执行 FFmpeg
subprocess.run(cmd, check=True)
return FileResponse(output_path, media_type="video/mp4", filename=f"{filename}.mp4")