video-generate / app.py
tstech1's picture
Update app.py
dfe14ad verified
raw
history blame
2.56 kB
import os
import uuid
import time
from pathlib import Path
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from huggingface_hub import InferenceClient
# --- config ---
OUT_DIR = Path("outputs")
OUT_DIR.mkdir(exist_ok=True)
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
raise RuntimeError("Missing HF_TOKEN environment variable. Add it in Hugging Face Space settings (Repository secrets).")
# Initialize client (Fal.ai provider)
client = InferenceClient(provider="fal-ai", api_key=HF_TOKEN)
app = FastAPI(title="Fal.ai Text-to-Video API")
# Serve the outputs folder at /download/<filename>
app.mount("/download", StaticFiles(directory=str(OUT_DIR)), name="download")
class PromptIn(BaseModel):
prompt: str
model: str = "akhaliq/veo3.1-fast" # default; override if you want
@app.post("/generate", response_class=JSONResponse)
def generate_video(payload: PromptIn, request: Request):
"""
Generate a video from `payload.prompt` using Fal.ai-backed model.
Returns: { success, file_url, filename }
"""
prompt = payload.prompt.strip()
model = payload.model.strip()
if not prompt:
raise HTTPException(status_code=400, detail="prompt is required")
# unique filename
filename = f"{uuid.uuid4().hex}.mp4"
out_path = OUT_DIR / filename
try:
# Call text_to_video (synchronous call returns bytes)
# Note: This may take some time depending on model & quota.
print("⏳ text_to_video request:", model, "prompt len:", len(prompt))
video_bytes = client.text_to_video(prompt=prompt, model=model)
if not video_bytes:
raise RuntimeError("Empty response from text_to_video")
# Save file
with open(out_path, "wb") as f:
f.write(video_bytes)
# Build absolute URL to download
base = str(request.base_url).rstrip("/")
file_url = f"{base}/download/{filename}"
print("βœ… Video saved:", out_path)
return {"success": True, "filename": filename, "file_url": file_url}
except Exception as e:
# log but return friendly message
print("❌ Error generating video:", repr(e))
# If provider returns specific errors (quota / 429), bubble them up
raise HTTPException(status_code=500, detail=str(e))
@app.get("/")
def root():
return {"message": "Text-to-Video API running. POST /generate with JSON {\"prompt\":\"...\"}."}