Ezmary commited on
Commit
ac4201c
·
verified ·
1 Parent(s): 1404203

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -0
app.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import httpx
4
+ from fastapi import FastAPI, BackgroundTasks
5
+ from pydantic import BaseModel
6
+
7
+ app = FastAPI()
8
+
9
+ # آدرس اصلی API مدل Wan2.2
10
+ WAN_API_BASE = "https://wan-ai-wan2-2-s2v.ms.show/gradio_api"
11
+
12
+ class TaskPayload(BaseModel):
13
+ job_id: str
14
+ image_url: str
15
+ audio_url: str
16
+ resolution: str
17
+ callback_url: str
18
+
19
+ async def upload_file_from_url(client: httpx.AsyncClient, file_url: str, file_type: str):
20
+ """دانلود فایل از مدیر و آپلود به Wan2.2"""
21
+ print(f"Downloading {file_type} from {file_url}...")
22
+ # 1. دانلود فایل از اسپیس مدیر
23
+ file_resp = await client.get(file_url)
24
+ if file_resp.status_code != 200:
25
+ raise Exception(f"Failed to download {file_type}: {file_resp.status_code}")
26
+
27
+ file_bytes = file_resp.content
28
+ filename = file_url.split("/")[-1]
29
+
30
+ # 2. آپلود به Wan2.2
31
+ print(f"Uploading {filename} to Wan2.2...")
32
+ files = {'files': (filename, file_bytes)}
33
+ upload_resp = await client.post(f"{WAN_API_BASE}/upload", files=files)
34
+
35
+ if upload_resp.status_code != 200:
36
+ raise Exception(f"Failed to upload {file_type} to Wan2.2")
37
+
38
+ remote_path = upload_resp.json()[0]
39
+ print(f"Uploaded: {remote_path}")
40
+ return remote_path
41
+
42
+ async def process_task(payload: TaskPayload):
43
+ print(f"Processing Job {payload.job_id}")
44
+
45
+ async with httpx.AsyncClient(timeout=120.0) as client: # تایم‌اوت بالا
46
+ try:
47
+ # الف) آپلود فایل‌ها
48
+ img_remote = await upload_file_from_url(client, payload.image_url, "image")
49
+ aud_remote = await upload_file_from_url(client, payload.audio_url, "audio")
50
+
51
+ # ب) ارسال درخواست Predict
52
+ req_data = {
53
+ "data": [
54
+ {"path": img_remote, "meta": {"_type": "gradio.FileData"}},
55
+ {"path": aud_remote, "meta": {"_type": "gradio.FileData"}},
56
+ payload.resolution
57
+ ]
58
+ }
59
+
60
+ predict_resp = await client.post(f"{WAN_API_BASE}/call/predict", json=req_data)
61
+ if predict_resp.status_code != 200:
62
+ raise Exception(f"Predict call failed: {predict_resp.text}")
63
+
64
+ event_id = predict_resp.json().get("event_id")
65
+ print(f"Event ID: {event_id}")
66
+
67
+ # ج) گوش دادن به استریم (Polling the stream)
68
+ # در پایتون، به جای EventSource، می‌توانیم با یک لوپ ساده GET بزنیم یا stream کنیم
69
+ final_video_url = None
70
+
71
+ async with client.stream("GET", f"{WAN_API_BASE}/call/predict/{event_id}", headers={"Accept": "text/event-stream"}) as response:
72
+ async for line in response.aiter_lines():
73
+ if line.startswith("data: "):
74
+ try:
75
+ data = json.loads(line[6:])
76
+ # بررسی ساختار خروجی
77
+ if isinstance(data, list) and len(data) > 0:
78
+ result_item = data[0]
79
+ # پیدا کردن URL در ساختارهای مختلف
80
+ if isinstance(result_item, dict):
81
+ if "video" in result_item and "url" in result_item["video"]:
82
+ final_video_url = result_item["video"]["url"]
83
+ elif "url" in result_item:
84
+ final_video_url = result_item["url"]
85
+ elif "name" in result_item:
86
+ final_video_url = f"https://wan-ai-wan2-2-s2v.ms.show/file={result_item['name']}"
87
+ elif isinstance(result_item, str) and (result_item.endswith(".mp4") or "/file=" in result_item):
88
+ final_video_url = result_item
89
+
90
+ if final_video_url:
91
+ # اصلاح لینک نسبی
92
+ if final_video_url.startswith("/"):
93
+ final_video_url = f"https://wan-ai-wan2-2-s2v.ms.show{final_video_url}"
94
+ break
95
+ except:
96
+ pass
97
+
98
+ if final_video_url:
99
+ print(f"Success! Video: {final_video_url}")
100
+ # د) بازگرداندن نتیجه به مدیر
101
+ await client.post(payload.callback_url, json={
102
+ "job_id": payload.job_id,
103
+ "status": "COMPLETED",
104
+ "video_url": final_video_url
105
+ })
106
+ else:
107
+ raise Exception("Stream ended without video URL")
108
+
109
+ except Exception as e:
110
+ print(f"Task Failed: {e}")
111
+ await client.post(payload.callback_url, json={
112
+ "job_id": payload.job_id,
113
+ "status": "FAILED",
114
+ "message": str(e)
115
+ })
116
+
117
+ @app.post("/process")
118
+ async def accept_task(payload: TaskPayload, background_tasks: BackgroundTasks):
119
+ """تسک را می‌پذیرد و بلافاصله OK برمی‌گرداند تا تایم‌اوت نشود"""
120
+ background_tasks.add_task(process_task, payload)
121
+ return {"status": "accepted"}