tstech1 commited on
Commit
dfe14ad
Β·
verified Β·
1 Parent(s): 800127e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -46
app.py CHANGED
@@ -1,64 +1,72 @@
1
- from fastapi import FastAPI, HTTPException
 
 
 
 
 
 
2
  from pydantic import BaseModel
3
- import time, os
4
- from google import genai
5
- from google.genai import types
6
 
7
- app = FastAPI(title="Gemini Veo3 Video Generator")
 
 
8
 
9
- API_KEY = os.getenv("GEMINI_API_KEY")
10
- if not API_KEY:
11
- raise ValueError("❌ GEMINI_API_KEY not found. Add it in Hugging Face β†’ Settings β†’ Repository secrets.")
12
 
13
- client = genai.Client(api_key=API_KEY)
 
14
 
15
- class VideoPrompt(BaseModel):
16
- prompt: str
17
-
18
- @app.post("/generate_video")
19
- async def generate_video(data: VideoPrompt):
20
- try:
21
- print(f"🎬 Generating video for prompt: {data.prompt}")
22
 
23
- operation = client.models.generate_videos(
24
- model="veo-3.0-generate-001",
25
- prompt=data.prompt,
26
- config=types.GenerateVideosConfig(
27
- aspect_ratio="16:9",
28
- resolution="1080p",
29
- negative_prompt="cartoon, unrealistic, text distortion"
30
- ),
31
- )
32
 
33
- # Poll until generation completes
34
- while not operation.done:
35
- print("⏳ Still generating...")
36
- time.sleep(10)
37
- operation = client.operations.get(name=operation.name) # βœ… correct call
38
 
39
- if not operation.response.generated_videos:
40
- raise HTTPException(status_code=500, detail="No video generated.")
 
 
 
 
 
 
 
 
41
 
42
- generated_video = operation.response.generated_videos[0]
43
- video_file_id = generated_video.video.name # βœ… file name or ID
 
44
 
45
- # βœ… Correct file retrieval syntax
46
- file_info = client.files.get(name=video_file_id)
47
- video_url = file_info.uri # This is the downloadable URL
 
 
 
 
48
 
49
- print(f"βœ… Video ready: {video_url}")
 
 
50
 
51
- return {
52
- "success": True,
53
- "video_url": video_url,
54
- "message": "Video generation complete."
55
- }
56
 
 
 
57
  except Exception as e:
58
- print("❌ Error:", e)
 
 
59
  raise HTTPException(status_code=500, detail=str(e))
60
 
61
-
62
  @app.get("/")
63
  def root():
64
- return {"message": "βœ… Gemini Veo3 API running. Use /docs to test."}
 
1
+ import os
2
+ import uuid
3
+ import time
4
+ from pathlib import Path
5
+ from fastapi import FastAPI, HTTPException, Request
6
+ from fastapi.responses import FileResponse, JSONResponse
7
+ from fastapi.staticfiles import StaticFiles
8
  from pydantic import BaseModel
9
+ from huggingface_hub import InferenceClient
 
 
10
 
11
+ # --- config ---
12
+ OUT_DIR = Path("outputs")
13
+ OUT_DIR.mkdir(exist_ok=True)
14
 
15
+ HF_TOKEN = os.getenv("HF_TOKEN")
16
+ if not HF_TOKEN:
17
+ raise RuntimeError("Missing HF_TOKEN environment variable. Add it in Hugging Face Space settings (Repository secrets).")
18
 
19
+ # Initialize client (Fal.ai provider)
20
+ client = InferenceClient(provider="fal-ai", api_key=HF_TOKEN)
21
 
22
+ app = FastAPI(title="Fal.ai Text-to-Video API")
 
 
 
 
 
 
23
 
24
+ # Serve the outputs folder at /download/<filename>
25
+ app.mount("/download", StaticFiles(directory=str(OUT_DIR)), name="download")
 
 
 
 
 
 
 
26
 
27
+ class PromptIn(BaseModel):
28
+ prompt: str
29
+ model: str = "akhaliq/veo3.1-fast" # default; override if you want
 
 
30
 
31
+ @app.post("/generate", response_class=JSONResponse)
32
+ def generate_video(payload: PromptIn, request: Request):
33
+ """
34
+ Generate a video from `payload.prompt` using Fal.ai-backed model.
35
+ Returns: { success, file_url, filename }
36
+ """
37
+ prompt = payload.prompt.strip()
38
+ model = payload.model.strip()
39
+ if not prompt:
40
+ raise HTTPException(status_code=400, detail="prompt is required")
41
 
42
+ # unique filename
43
+ filename = f"{uuid.uuid4().hex}.mp4"
44
+ out_path = OUT_DIR / filename
45
 
46
+ try:
47
+ # Call text_to_video (synchronous call returns bytes)
48
+ # Note: This may take some time depending on model & quota.
49
+ print("⏳ text_to_video request:", model, "prompt len:", len(prompt))
50
+ video_bytes = client.text_to_video(prompt=prompt, model=model)
51
+ if not video_bytes:
52
+ raise RuntimeError("Empty response from text_to_video")
53
 
54
+ # Save file
55
+ with open(out_path, "wb") as f:
56
+ f.write(video_bytes)
57
 
58
+ # Build absolute URL to download
59
+ base = str(request.base_url).rstrip("/")
60
+ file_url = f"{base}/download/{filename}"
 
 
61
 
62
+ print("βœ… Video saved:", out_path)
63
+ return {"success": True, "filename": filename, "file_url": file_url}
64
  except Exception as e:
65
+ # log but return friendly message
66
+ print("❌ Error generating video:", repr(e))
67
+ # If provider returns specific errors (quota / 429), bubble them up
68
  raise HTTPException(status_code=500, detail=str(e))
69
 
 
70
  @app.get("/")
71
  def root():
72
+ return {"message": "Text-to-Video API running. POST /generate with JSON {\"prompt\":\"...\"}."}