Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,6 +10,10 @@ import asyncio
|
|
| 10 |
import re
|
| 11 |
from random import randint
|
| 12 |
from urllib.parse import quote
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
app = FastAPI()
|
| 15 |
|
|
@@ -694,4 +698,89 @@ async def genvideo(request: Request, prompt: str = None):
|
|
| 694 |
"Content-Length": str(len(response.content)),
|
| 695 |
"Accept-Ranges": "bytes"
|
| 696 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 697 |
)
|
|
|
|
| 10 |
import re
|
| 11 |
from random import randint
|
| 12 |
from urllib.parse import quote
|
| 13 |
+
import uuid
|
| 14 |
+
|
| 15 |
+
WAN_SPACE = "https://huggingface.co/spaces/Wan-AI/Wan2.1"
|
| 16 |
+
WAN_API_BASE = f"{WAN_SPACE}/gradio_api"
|
| 17 |
|
| 18 |
app = FastAPI()
|
| 19 |
|
|
|
|
| 698 |
"Content-Length": str(len(response.content)),
|
| 699 |
"Accept-Ranges": "bytes"
|
| 700 |
}
|
| 701 |
+
)
|
| 702 |
+
|
| 703 |
+
@app.get("/gen/video/exp/{prompt}")
|
| 704 |
+
@app.post("/gen/video/exp")
|
| 705 |
+
async def genvideo_wan(request: Request, prompt: str = None):
|
| 706 |
+
client_ip = request.client.host
|
| 707 |
+
check_rate_limit(client_ip)
|
| 708 |
+
|
| 709 |
+
if prompt is None:
|
| 710 |
+
body = await request.json()
|
| 711 |
+
prompt = body.get("prompt")
|
| 712 |
+
|
| 713 |
+
if not prompt:
|
| 714 |
+
raise HTTPException(400, "Prompt is required")
|
| 715 |
+
|
| 716 |
+
session_hash = uuid.uuid4().hex
|
| 717 |
+
|
| 718 |
+
join_payload = {
|
| 719 |
+
"fn_index": 0,
|
| 720 |
+
"session_hash": session_hash,
|
| 721 |
+
"data": [prompt],
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 725 |
+
# 1️⃣ Join queue
|
| 726 |
+
join = await client.post(
|
| 727 |
+
f"{WAN_API_BASE}/queue/join",
|
| 728 |
+
json=join_payload,
|
| 729 |
+
)
|
| 730 |
+
|
| 731 |
+
if join.status_code != 200:
|
| 732 |
+
raise HTTPException(
|
| 733 |
+
join.status_code,
|
| 734 |
+
f"Failed to join WAN queue: {join.text}"
|
| 735 |
+
)
|
| 736 |
+
|
| 737 |
+
for _ in range(120):
|
| 738 |
+
await asyncio.sleep(1)
|
| 739 |
+
|
| 740 |
+
poll = await client.get(
|
| 741 |
+
f"{WAN_API_BASE}/queue/data",
|
| 742 |
+
params={"session_hash": session_hash},
|
| 743 |
+
)
|
| 744 |
+
|
| 745 |
+
if poll.status_code != 200:
|
| 746 |
+
continue
|
| 747 |
+
|
| 748 |
+
data = poll.json()
|
| 749 |
+
|
| 750 |
+
if data.get("status") == "complete":
|
| 751 |
+
try:
|
| 752 |
+
video_url = data["data"][0]
|
| 753 |
+
except Exception:
|
| 754 |
+
raise HTTPException(
|
| 755 |
+
500,
|
| 756 |
+
"WAN completed but returned unexpected format"
|
| 757 |
+
)
|
| 758 |
+
|
| 759 |
+
# 3️⃣ Fetch video
|
| 760 |
+
video = await client.get(video_url)
|
| 761 |
+
|
| 762 |
+
if video.status_code != 200:
|
| 763 |
+
raise HTTPException(
|
| 764 |
+
502,
|
| 765 |
+
"Failed to fetch generated video"
|
| 766 |
+
)
|
| 767 |
+
|
| 768 |
+
return Response(
|
| 769 |
+
content=video.content,
|
| 770 |
+
media_type="video/mp4",
|
| 771 |
+
headers={
|
| 772 |
+
"Content-Length": str(len(video.content)),
|
| 773 |
+
"Accept-Ranges": "bytes",
|
| 774 |
+
}
|
| 775 |
+
)
|
| 776 |
+
|
| 777 |
+
if data.get("status") == "error":
|
| 778 |
+
raise HTTPException(
|
| 779 |
+
500,
|
| 780 |
+
f"WAN generation error: {data}"
|
| 781 |
+
)
|
| 782 |
+
|
| 783 |
+
raise HTTPException(
|
| 784 |
+
504,
|
| 785 |
+
"WAN video generation timed out"
|
| 786 |
)
|