hwonder Claude Opus 4.5 commited on
Commit
b99fda7
·
1 Parent(s): 982cefe

Add 3D model (GLTF/GLB) support for Text to Image

Browse files

- Add Model3D output component for 3D format
- Toggle visibility between Image and Model3D based on format
- Handler returns (image_url, model_url, status) tuple
- 3D format uses generate_image_3d tool and renders as Model3D

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (3) hide show
  1. app.py +1 -0
  2. src/ui/handlers.py +21 -10
  3. src/ui/tabs.py +19 -3
app.py CHANGED
@@ -66,6 +66,7 @@ def create_demo():
66
  ],
67
  outputs=[
68
  tabs["text_to_image"]["output_image"],
 
69
  tabs["text_to_image"]["status"]
70
  ],
71
  api_name=None
 
66
  ],
67
  outputs=[
68
  tabs["text_to_image"]["output_image"],
69
+ tabs["text_to_image"]["output_model"],
70
  tabs["text_to_image"]["status"]
71
  ],
72
  api_name=None
src/ui/handlers.py CHANGED
@@ -185,12 +185,18 @@ class Handlers:
185
  prompt: str,
186
  format_type: str,
187
  api_key: str = ""
188
- ) -> Tuple[Optional[str], str]:
189
- """Handle text-to-image generation."""
 
 
 
 
 
 
190
  if not prompt.strip():
191
- return None, "Please enter a description for your image."
192
  if not api_key.strip():
193
- return None, "Please enter your API key in the Settings section."
194
 
195
  client = StackNetClient(api_key=api_key.strip())
196
  service = ImageService(client=client)
@@ -200,24 +206,29 @@ class Handlers:
200
  asyncio.set_event_loop(loop)
201
 
202
  try:
203
- images = loop.run_until_complete(
204
  service.generate_image(
205
  prompt=prompt,
206
  format_type=format_type
207
  )
208
  )
209
 
210
- if images:
211
- # Return URL directly - Gradio can display remote images
212
- return images[0].image_url, "Image generated successfully!"
 
 
 
 
 
213
  else:
214
- return None, "No image was generated. Please try a different prompt."
215
 
216
  finally:
217
  loop.close()
218
 
219
  except Exception as e:
220
- return None, format_error(e)
221
 
222
  finally:
223
  service.cleanup()
 
185
  prompt: str,
186
  format_type: str,
187
  api_key: str = ""
188
+ ) -> Tuple[Optional[str], Optional[str], str]:
189
+ """Handle text-to-image generation.
190
+
191
+ Returns:
192
+ Tuple of (image_url, model_url, status)
193
+ - For image/multi: (url, None, status)
194
+ - For 3d: (None, url, status)
195
+ """
196
  if not prompt.strip():
197
+ return None, None, "Please enter a description for your image."
198
  if not api_key.strip():
199
+ return None, None, "Please enter your API key in the Settings section."
200
 
201
  client = StackNetClient(api_key=api_key.strip())
202
  service = ImageService(client=client)
 
206
  asyncio.set_event_loop(loop)
207
 
208
  try:
209
+ results = loop.run_until_complete(
210
  service.generate_image(
211
  prompt=prompt,
212
  format_type=format_type
213
  )
214
  )
215
 
216
+ if results:
217
+ url = results[0].image_url
218
+ if format_type == "3d":
219
+ # Return as 3D model
220
+ return None, url, "3D model generated successfully!"
221
+ else:
222
+ # Return as image
223
+ return url, None, "Image generated successfully!"
224
  else:
225
+ return None, None, "No result was generated. Please try a different prompt."
226
 
227
  finally:
228
  loop.close()
229
 
230
  except Exception as e:
231
+ return None, None, format_error(e)
232
 
233
  finally:
234
  service.cleanup()
src/ui/tabs.py CHANGED
@@ -162,18 +162,34 @@ def create_text_to_image_tab():
162
  value="image"
163
  )
164
 
165
- generate_btn = gr.Button("Generate Image", variant="primary", size="lg")
166
 
167
  status = gr.Textbox(label="Status", interactive=False, visible=False)
168
 
169
- output_image = gr.Image(label="Generated Image", type="filepath")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  return {
172
  "prompt": prompt,
173
  "format_type": format_type,
174
  "generate_btn": generate_btn,
175
  "status": status,
176
- "output_image": output_image
 
177
  }
178
 
179
 
 
162
  value="image"
163
  )
164
 
165
+ generate_btn = gr.Button("Generate", variant="primary", size="lg")
166
 
167
  status = gr.Textbox(label="Status", interactive=False, visible=False)
168
 
169
+ # Image output (for image and multi formats)
170
+ output_image = gr.Image(label="Generated Image", type="filepath", visible=True)
171
+
172
+ # 3D Model output (for 3d format)
173
+ output_model = gr.Model3D(label="Generated 3D Model", visible=False)
174
+
175
+ # Toggle output visibility based on format selection
176
+ format_type.change(
177
+ fn=lambda fmt: (
178
+ gr.update(visible=(fmt != "3d")),
179
+ gr.update(visible=(fmt == "3d"))
180
+ ),
181
+ inputs=[format_type],
182
+ outputs=[output_image, output_model],
183
+ api_name=None
184
+ )
185
 
186
  return {
187
  "prompt": prompt,
188
  "format_type": format_type,
189
  "generate_btn": generate_btn,
190
  "status": status,
191
+ "output_image": output_image,
192
+ "output_model": output_model
193
  }
194
 
195