File size: 3,160 Bytes
4b064b1
fe737ff
c6c29f9
ca2ffc8
4b064b1
c6c29f9
 
0f32810
 
fe737ff
0f32810
fe737ff
ca2ffc8
 
 
fe737ff
ca2ffc8
63f43d7
c6c29f9
 
0f32810
c6c29f9
 
 
ed486f9
fe737ff
ed486f9
ca2ffc8
 
c6c29f9
ed486f9
ca2ffc8
 
fe737ff
ca2ffc8
 
 
 
0f32810
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fe737ff
ca2ffc8
 
 
 
fe737ff
 
 
 
c6c29f9
fe737ff
 
 
c6c29f9
 
 
 
0f32810
 
 
 
 
c6c29f9
fe737ff
 
 
c6c29f9
fe737ff
63f43d7
 
 
ca2ffc8
 
 
fe737ff
 
 
ca2ffc8
4b064b1
fe737ff
c6c29f9
 
fe737ff
4b064b1
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# app.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
import uvicorn
import os
import uuid
import subprocess
import json

from huggingface_hub import hf_hub_download
from moviepy.editor import ImageSequenceClip

app = FastAPI(title="WAN2 GGUF API", version="1.0")

# -------------------- Directories --------------------
MODEL_REPO = "calcuis/wan2-gguf"
MODEL_FILE = "wan2.2-animate-14b-q4_0.gguf"
MODEL_DIR = "models"
OUTPUT_DIR = "outputs"
NODE_CLI = "gguf-node-cli.js"  # Path to your gguf-node CLI

os.makedirs(MODEL_DIR, exist_ok=True)
os.makedirs(OUTPUT_DIR, exist_ok=True)

# -------------------- Download model --------------------
model_path = hf_hub_download(
    repo_id=MODEL_REPO,
    filename=MODEL_FILE,
    local_dir=MODEL_DIR
)
print("✅ Model downloaded to:", model_path)

# -------------------- Request schema --------------------
class PromptRequest(BaseModel):
    prompt: str
    steps: int = 20

# -------------------- Helper: GGUF Node CLI --------------------
def generate_frames_with_node(prompt, steps=20):
    """
    Calls gguf-node CLI to generate frames.
    CLI should output JSON array of frame image paths.
    """
    try:
        result = subprocess.run(
            ["node", NODE_CLI, "--model", model_path, "--prompt", prompt, "--steps", str(steps)],
            capture_output=True,
            text=True,
            check=True
        )
        frames = json.loads(result.stdout)
        return frames
    except subprocess.CalledProcessError as e:
        print("Error calling gguf-node:", e.stderr)
        return []

# -------------------- Routes --------------------
@app.get("/")
def root():
    return {"message": "WAN2 GGUF API is running!"}

@app.get("/generate")
def generate_video_get(q: str, steps: int = 20):
    """Allows GET requests with ?q=... for browser testing"""
    return generate_video(PromptRequest(prompt=q, steps=steps))

@app.post("/generate")
def generate_video(request: PromptRequest):
    """Generates video from prompt using WAN2 GGUF"""
    # Unique filename
    file_id = str(uuid.uuid4())
    file_path = os.path.join(OUTPUT_DIR, f"{file_id}.mp4")

    # ---- WAN2 inference via Node CLI ----
    frames = generate_frames_with_node(request.prompt, request.steps)

    if not frames:
        return {"status": "error", "message": "Failed to generate frames"}

    # ---- Save frames as MP4 ----
    clip = ImageSequenceClip(frames, fps=12)
    clip.write_videofile(file_path, codec="libx264", audio=False, verbose=False, logger=None)

    # Build full URL for Hugging Face Space
    base_url = "https://abrahamdw882-wan2-api.hf.space"
    video_url = f"{base_url}/file/{file_id}.mp4"

    return {
        "status": "success",
        "model_file": MODEL_FILE,
        "prompt": request.prompt,
        "steps": request.steps,
        "video_url": video_url
    }

# -------------------- Serve output videos --------------------
app.mount("/file", StaticFiles(directory=OUTPUT_DIR), name="file")

# -------------------- Run server --------------------
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)