diwash-barla1 commited on
Commit
4e4abcd
·
verified ·
1 Parent(s): 5bcde8c

Update comfy_engine.py

Browse files
Files changed (1) hide show
  1. comfy_engine.py +55 -59
comfy_engine.py CHANGED
@@ -1,35 +1,39 @@
1
- import json
2
- import uuid
3
- import os
4
- import asyncio
5
  import httpx
6
  import websockets
7
  from urllib.parse import urlencode
8
 
9
  COMFY_HOST = os.getenv("COMFY_HOST", "134.199.132.159")
10
 
11
- # वर्कफ़्लो लोड करें
12
  with open("workflow.json", "r", encoding="utf-8") as f:
13
  WORKFLOW_TEMPLATE = json.load(f)
14
 
 
 
 
 
 
 
 
15
  def inject_params(req: dict) -> dict:
16
  p = json.loads(json.dumps(WORKFLOW_TEMPLATE))
17
- # Text Prompts
 
18
  p["89"]["inputs"]["text"] = req.get("prompt", "")
19
- if req.get("negative"):
20
- p["72"]["inputs"]["text"] = req.get("negative")
21
 
22
- # Video Settings
23
- p["74"]["inputs"]["width"] = req.get("width", 640)
24
- p["74"]["inputs"]["height"] = req.get("height", 640)
25
- p["74"]["inputs"]["length"] = req.get("frames", 81)
26
- p["88"]["inputs"]["fps"] = req.get("fps", 16)
27
 
28
- # Seed Configuration
29
- seed = req.get("seed")
30
- if seed:
31
- p["81"]["inputs"]["noise_seed"] = seed
32
- p["78"]["inputs"]["noise_seed"] = seed
 
 
 
33
 
34
  return p
35
 
@@ -41,8 +45,7 @@ def extract_video_url(history: dict, token: str) -> str:
41
  it = node_out[key][0]
42
  if all(k in it for k in ("filename", "subfolder", "type")):
43
  q = urlencode(it)
44
- # 🔴 Proxy URL (No Mixed Content Error)
45
- return f"/api/video?{q}&token={token}"
46
  raise RuntimeError("No video file found in history")
47
 
48
  async def generate_video_stream(req: dict):
@@ -50,62 +53,55 @@ async def generate_video_stream(req: dict):
50
  client_id = str(uuid.uuid4())
51
  prompt = inject_params(req)
52
 
53
- # 1. API को प्रॉम्प्ट भेजें
54
  async with httpx.AsyncClient() as client:
55
  resp = await client.post(f"http://{COMFY_HOST}/prompt?token={token}", json={"prompt": prompt, "client_id": client_id}, timeout=60.0)
56
  data = resp.json()
57
- if "prompt_id" not in data:
58
- yield f"data: {json.dumps({'error': 'Failed to queue prompt'})}\n\n"
 
59
  return
60
- prompt_id = data["prompt_id"]
61
 
62
  total_nodes = max(1, len(prompt))
63
  seen = set()
 
 
64
 
65
- # 2. WebSocket से लाइव प्रोग्रेस ट्रैक करें (With Ping to keep alive)
66
  ws_url = f"ws://{COMFY_HOST}/ws?clientId={client_id}&token={token}"
67
  try:
68
- async with websockets.connect(ws_url, ping_interval=20, ping_timeout=120) as ws:
69
  while True:
70
  out = await ws.recv()
 
 
 
 
 
 
 
 
 
71
  if isinstance(out, str):
72
  msg = json.loads(out)
73
  if msg.get("type") == "executing":
74
- data = msg.get("data", {})
75
- if data.get("prompt_id") != prompt_id:
76
- continue
77
- node = data.get("node")
78
  if node is None:
79
- break # रेंरिंग पूरी हो गई!
80
  if node not in seen:
81
  seen.add(node)
82
- progress = min(99, int((len(seen) / total_nodes) * 100))
83
- yield f"data: {json.dumps({'progress': progress, 'status': 'rendering'})}\n\n"
 
84
  except Exception as e:
85
- # अगर तार टूट गया, तो एरर नहीं देंगे, बस "Finalizing" बोलेंगे
86
- print(f"⚠️ WebSocket Disconnected: {e}. Switching to polling mode...")
87
- yield f"data: {json.dumps({'progress': 99, 'status': 'Finalizing Video...'})}\n\n"
88
-
89
- # 3. बैकअप प्लान (Fallback Polling) - अगर WS टूट गया तो इतिहास चेक करेंगे
90
- max_retries = 60 # 60 * 3 = 180 seconds (3 mins max wait)
91
- for _ in range(max_retries):
92
- await asyncio.sleep(3) # 3 सेकंड रुकें
93
- try:
94
- async with httpx.AsyncClient() as client:
95
- hist_resp = await client.get(f"http://{COMFY_HOST}/history/{prompt_id}?token={token}", timeout=30.0)
96
- if hist_resp.status_code == 200:
97
- history_data = hist_resp.json()
98
- if prompt_id in history_data:
99
- history = history_data[prompt_id]
100
- try:
101
- final_url = extract_video_url(history, token)
102
- yield f"data: {json.dumps({'progress': 100, 'status': 'done', 'url': final_url})}\n\n"
103
- return # काम खतम!
104
- except Exception:
105
- pass # अभी वीडियो फाइल सेव हो रही है
106
- except Exception as e:
107
- print(f"Polling error: {e}")
108
- pass # नेटवर्क ग्लिच, इग्नोर करें और फिर ट्राई करें
109
 
110
- yield f"data: {json.dumps({'error': 'Timeout: Rendering took too long.'})}\n\n"
111
-
 
 
 
 
 
 
 
 
 
 
1
+ import json, uuid, os, asyncio, time
 
 
 
2
  import httpx
3
  import websockets
4
  from urllib.parse import urlencode
5
 
6
  COMFY_HOST = os.getenv("COMFY_HOST", "134.199.132.159")
7
 
 
8
  with open("workflow.json", "r", encoding="utf-8") as f:
9
  WORKFLOW_TEMPLATE = json.load(f)
10
 
11
+ # 🧠 स्मार्ट रेसोल्यूशन डिक्शनरी (मल्टीपल्स ऑफ़ 16)
12
+ RESOLUTIONS = {
13
+ "360p": {"16:9": (640, 360), "9:16": (360, 640), "1:1": (512, 512)},
14
+ "480p": {"16:9": (848, 480), "9:16": (480, 848), "1:1": (640, 640)},
15
+ "720p": {"16:9": (1280, 720), "9:16": (720, 1280), "1:1": (768, 768)}
16
+ }
17
+
18
  def inject_params(req: dict) -> dict:
19
  p = json.loads(json.dumps(WORKFLOW_TEMPLATE))
20
+
21
+ # प्रॉम्प्ट
22
  p["89"]["inputs"]["text"] = req.get("prompt", "")
 
 
23
 
24
+ # स्मार्ट डायमेंशन्स कैलकुलेशन
25
+ ratio = req.get("aspect_ratio", "16:9")
26
+ quality = req.get("quality", "480p")
27
+ width, height = RESOLUTIONS.get(quality, {}).get(ratio, (848, 480))
 
28
 
29
+ p["74"]["inputs"]["width"] = width
30
+ p["74"]["inputs"]["height"] = height
31
+
32
+ # फिक्स और हार्डकोडेड सेटिंग्स (बेस्ट क्वालिटी के लिए)
33
+ p["74"]["inputs"]["length"] = 81 # 81 फ्रेम्स
34
+ p["88"]["inputs"]["fps"] = 16 # 16 FPS (Smooth Slow-mo)
35
+ p["78"]["inputs"]["steps"] = 4 # 4 Steps
36
+ p["78"]["inputs"]["cfg"] = 5.0 # 5.0 CFG
37
 
38
  return p
39
 
 
45
  it = node_out[key][0]
46
  if all(k in it for k in ("filename", "subfolder", "type")):
47
  q = urlencode(it)
48
+ return f"/api/video?{q}&token={token}" # Proxy URL
 
49
  raise RuntimeError("No video file found in history")
50
 
51
  async def generate_video_stream(req: dict):
 
53
  client_id = str(uuid.uuid4())
54
  prompt = inject_params(req)
55
 
 
56
  async with httpx.AsyncClient() as client:
57
  resp = await client.post(f"http://{COMFY_HOST}/prompt?token={token}", json={"prompt": prompt, "client_id": client_id}, timeout=60.0)
58
  data = resp.json()
59
+ prompt_id = data.get("prompt_id")
60
+ if not prompt_id:
61
+ yield f"data: {json.dumps({'error': 'Failed'})}\n\n"
62
  return
 
63
 
64
  total_nodes = max(1, len(prompt))
65
  seen = set()
66
+ start_time = time.time()
67
+ p_fake = 0
68
 
 
69
  ws_url = f"ws://{COMFY_HOST}/ws?clientId={client_id}&token={token}"
70
  try:
71
+ async with websockets.connect(ws_url, ping_interval=20) as ws:
72
  while True:
73
  out = await ws.recv()
74
+
75
+ # 🚀 THE MAGIC HACK (Bytes Handling from your Gradio code)
76
+ if isinstance(out, (bytes, bytearray)):
77
+ if p_fake < 95 and time.time() - start_time > 2:
78
+ p_fake = min(95, p_fake + 1)
79
+ yield f"data: {json.dumps({'progress': p_fake, 'status': 'rendering'})}\n\n"
80
+ continue
81
+
82
+ # Normal JSON handling
83
  if isinstance(out, str):
84
  msg = json.loads(out)
85
  if msg.get("type") == "executing":
86
+ node = msg.get("data", {}).get("node")
 
 
 
87
  if node is None:
88
+ break # ड!
89
  if node not in seen:
90
  seen.add(node)
91
+ p_real = min(99, int((len(seen) / total_nodes) * 100))
92
+ p_fake = max(p_fake, p_real) # जो भी ज़्यादा हो वो दिखाओ
93
+ yield f"data: {json.dumps({'progress': p_fake, 'status': 'rendering'})}\n\n"
94
  except Exception as e:
95
+ print(f"WS Disconnected: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ # हिस्ट्री से वीडियो निकालें
98
+ await asyncio.sleep(2)
99
+ async with httpx.AsyncClient() as client:
100
+ hist_resp = await client.get(f"http://{COMFY_HOST}/history/{prompt_id}?token={token}", timeout=60.0)
101
+ history = hist_resp.json().get(prompt_id, {})
102
+
103
+ try:
104
+ final_url = extract_video_url(history, token)
105
+ yield f"data: {json.dumps({'progress': 100, 'status': 'done', 'url': final_url})}\n\n"
106
+ except Exception as e:
107
+ yield f"data: {json.dumps({'error': str(e)})}\n\n"