Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -34,6 +34,9 @@ def query_api(payload, progress_callback=None):
|
|
34 |
del payload["image_bytes"]
|
35 |
|
36 |
# Submit the job
|
|
|
|
|
|
|
37 |
response = requests.post(API_URL, headers=headers, json=payload)
|
38 |
|
39 |
if response.status_code != 200:
|
@@ -41,10 +44,8 @@ def query_api(payload, progress_callback=None):
|
|
41 |
|
42 |
# Debug the response
|
43 |
print(f"Response status: {response.status_code}")
|
44 |
-
print(f"Response headers: {dict(response.headers)}")
|
45 |
print(f"Response content type: {response.headers.get('content-type', 'unknown')}")
|
46 |
print(f"Response content length: {len(response.content)}")
|
47 |
-
print(f"First 500 chars of response: {response.content[:500]}")
|
48 |
|
49 |
# Check if response is JSON (queue status) or binary (direct image)
|
50 |
content_type = response.headers.get('content-type', '').lower()
|
@@ -57,103 +58,36 @@ def query_api(payload, progress_callback=None):
|
|
57 |
|
58 |
# Check if job was queued
|
59 |
if json_response.get("status") == "IN_QUEUE":
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
63 |
|
64 |
-
#
|
65 |
-
|
66 |
-
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
time.sleep(5) # Wait 5 seconds between polls
|
73 |
-
|
74 |
-
# Check status using HF router format
|
75 |
-
status_url = f"https://router.huggingface.co/fal-ai/fal-ai/flux-kontext/dev/requests/{request_id}/status"
|
76 |
-
status_response = requests.get(status_url, headers=headers)
|
77 |
-
|
78 |
-
if status_response.status_code != 200:
|
79 |
-
print(f"Status response: {status_response.status_code} - {status_response.text}")
|
80 |
-
# Continue polling even if status check fails temporarily
|
81 |
-
attempt += 1
|
82 |
-
continue
|
83 |
-
|
84 |
-
try:
|
85 |
-
status_data = status_response.json()
|
86 |
-
print(f"Status check {attempt + 1}: {status_data}")
|
87 |
-
|
88 |
-
if status_data.get("status") == "COMPLETED":
|
89 |
-
# Job completed, get the result
|
90 |
-
result_url = f"https://router.huggingface.co/fal-ai/fal-ai/flux-kontext/dev/requests/{request_id}"
|
91 |
-
result_response = requests.get(result_url, headers=headers)
|
92 |
-
|
93 |
-
if result_response.status_code != 200:
|
94 |
-
print(f"Result response: {result_response.status_code} - {result_response.text}")
|
95 |
-
raise gr.Error(f"Failed to get result: {result_response.status_code}")
|
96 |
-
|
97 |
-
# Check if result is direct image bytes or JSON
|
98 |
-
result_content_type = result_response.headers.get('content-type', '').lower()
|
99 |
-
if 'image/' in result_content_type:
|
100 |
-
# Direct image bytes
|
101 |
-
return result_response.content
|
102 |
-
else:
|
103 |
-
# Try to parse as JSON for image URL or base64
|
104 |
-
try:
|
105 |
-
result_data = result_response.json()
|
106 |
-
print(f"Result data: {result_data}")
|
107 |
-
|
108 |
-
# Look for images in various formats
|
109 |
-
if 'images' in result_data and len(result_data['images']) > 0:
|
110 |
-
image_info = result_data['images'][0]
|
111 |
-
if isinstance(image_info, dict) and 'url' in image_info:
|
112 |
-
# Download the image
|
113 |
-
img_response = requests.get(image_info['url'])
|
114 |
-
return img_response.content
|
115 |
-
elif isinstance(image_info, str):
|
116 |
-
# Base64 encoded
|
117 |
-
return base64.b64decode(image_info)
|
118 |
-
elif 'image' in result_data:
|
119 |
-
# Single image field
|
120 |
-
if isinstance(result_data['image'], str):
|
121 |
-
return base64.b64decode(result_data['image'])
|
122 |
-
else:
|
123 |
-
# Maybe it's direct image bytes
|
124 |
-
return result_response.content
|
125 |
-
|
126 |
-
except requests.exceptions.JSONDecodeError:
|
127 |
-
# Result might be direct image bytes
|
128 |
-
return result_response.content
|
129 |
-
|
130 |
-
elif status_data.get("status") == "FAILED":
|
131 |
-
error_msg = status_data.get("error", "Unknown error")
|
132 |
-
raise gr.Error(f"Job failed: {error_msg}")
|
133 |
-
|
134 |
-
# Still processing, continue polling
|
135 |
-
attempt += 1
|
136 |
-
|
137 |
-
except requests.exceptions.JSONDecodeError:
|
138 |
-
print("Failed to parse status response, continuing...")
|
139 |
-
attempt += 1
|
140 |
-
continue
|
141 |
-
|
142 |
-
raise gr.Error("Job timed out after 5 minutes")
|
143 |
|
144 |
elif json_response.get("status") == "COMPLETED":
|
145 |
# Job completed immediately
|
146 |
if 'images' in json_response and len(json_response['images']) > 0:
|
147 |
image_info = json_response['images'][0]
|
148 |
if isinstance(image_info, dict) and 'url' in image_info:
|
|
|
|
|
149 |
img_response = requests.get(image_info['url'])
|
150 |
return img_response.content
|
151 |
elif isinstance(image_info, str):
|
|
|
152 |
return base64.b64decode(image_info)
|
153 |
elif 'image' in json_response:
|
154 |
return base64.b64decode(json_response['image'])
|
155 |
else:
|
156 |
-
raise gr.Error(f"No images found in
|
157 |
|
158 |
else:
|
159 |
raise gr.Error(f"Unexpected response status: {json_response.get('status', 'unknown')}")
|
@@ -163,11 +97,24 @@ def query_api(payload, progress_callback=None):
|
|
163 |
|
164 |
elif 'image/' in content_type:
|
165 |
# Response is direct image bytes
|
|
|
|
|
166 |
return response.content
|
167 |
|
168 |
else:
|
169 |
-
# Unknown content type, try to handle as bytes
|
170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
|
172 |
def upload_image_to_fal(image_bytes):
|
173 |
"""Upload image to fal.ai and return the URL"""
|
|
|
34 |
del payload["image_bytes"]
|
35 |
|
36 |
# Submit the job
|
37 |
+
if progress_callback:
|
38 |
+
progress_callback(0.1, "Submitting request...")
|
39 |
+
|
40 |
response = requests.post(API_URL, headers=headers, json=payload)
|
41 |
|
42 |
if response.status_code != 200:
|
|
|
44 |
|
45 |
# Debug the response
|
46 |
print(f"Response status: {response.status_code}")
|
|
|
47 |
print(f"Response content type: {response.headers.get('content-type', 'unknown')}")
|
48 |
print(f"Response content length: {len(response.content)}")
|
|
|
49 |
|
50 |
# Check if response is JSON (queue status) or binary (direct image)
|
51 |
content_type = response.headers.get('content-type', '').lower()
|
|
|
58 |
|
59 |
# Check if job was queued
|
60 |
if json_response.get("status") == "IN_QUEUE":
|
61 |
+
# For HF router, we should wait and let it handle the queue
|
62 |
+
# The router should eventually return the result automatically
|
63 |
+
if progress_callback:
|
64 |
+
progress_callback(0.5, "Processing in queue...")
|
65 |
|
66 |
+
# Wait a bit and try to get the response again
|
67 |
+
import time
|
68 |
+
time.sleep(10) # Wait 10 seconds for processing
|
69 |
|
70 |
+
# Make another request to check if it's ready
|
71 |
+
# But based on the error, we shouldn't poll manually
|
72 |
+
# Instead, let's return an error asking user to try again
|
73 |
+
raise gr.Error("Request is queued for processing. Please try again in a few moments.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
|
75 |
elif json_response.get("status") == "COMPLETED":
|
76 |
# Job completed immediately
|
77 |
if 'images' in json_response and len(json_response['images']) > 0:
|
78 |
image_info = json_response['images'][0]
|
79 |
if isinstance(image_info, dict) and 'url' in image_info:
|
80 |
+
if progress_callback:
|
81 |
+
progress_callback(0.9, "Downloading result...")
|
82 |
img_response = requests.get(image_info['url'])
|
83 |
return img_response.content
|
84 |
elif isinstance(image_info, str):
|
85 |
+
# Base64 encoded image
|
86 |
return base64.b64decode(image_info)
|
87 |
elif 'image' in json_response:
|
88 |
return base64.b64decode(json_response['image'])
|
89 |
else:
|
90 |
+
raise gr.Error(f"No images found in response: {json_response}")
|
91 |
|
92 |
else:
|
93 |
raise gr.Error(f"Unexpected response status: {json_response.get('status', 'unknown')}")
|
|
|
97 |
|
98 |
elif 'image/' in content_type:
|
99 |
# Response is direct image bytes
|
100 |
+
if progress_callback:
|
101 |
+
progress_callback(1.0, "Complete!")
|
102 |
return response.content
|
103 |
|
104 |
else:
|
105 |
+
# Unknown content type, but try to handle as image bytes
|
106 |
+
# This might be the case where the router returns the image directly
|
107 |
+
if len(response.content) > 1000: # Likely an image if it's substantial
|
108 |
+
if progress_callback:
|
109 |
+
progress_callback(1.0, "Complete!")
|
110 |
+
return response.content
|
111 |
+
else:
|
112 |
+
# Small response, probably an error
|
113 |
+
try:
|
114 |
+
error_response = response.json()
|
115 |
+
raise gr.Error(f"API Error: {error_response}")
|
116 |
+
except:
|
117 |
+
raise gr.Error(f"Unexpected response: {response.content.decode()[:500]}")
|
118 |
|
119 |
def upload_image_to_fal(image_bytes):
|
120 |
"""Upload image to fal.ai and return the URL"""
|