anvilinteractiv commited on
Commit
eace0d4
·
verified ·
1 Parent(s): cd0663c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -176
app.py CHANGED
@@ -11,15 +11,9 @@ from torchvision import transforms
11
  from huggingface_hub import hf_hub_download, snapshot_download
12
  import subprocess
13
  import shutil
14
- from fastapi import FastAPI, HTTPException, Depends, File, UploadFile
15
- from fastapi.security import APIKeyHeader
16
- from fastapi.staticfiles import StaticFiles
17
- from pydantic import BaseModel
18
- import uvicorn
19
 
20
  # Install additional dependencies
21
  subprocess.run("pip install spandrel==0.4.1 --no-deps", shell=True, check=True)
22
- subprocess.run("pip install fastapi uvicorn", shell=True, check=True)
23
 
24
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
25
  DTYPE = torch.float16
@@ -51,112 +45,6 @@ sys.path.append(os.path.join(TRIPOSG_CODE_DIR, "scripts"))
51
  sys.path.append(MV_ADAPTER_CODE_DIR)
52
  sys.path.append(os.path.join(MV_ADAPTER_CODE_DIR, "scripts"))
53
 
54
- # Initialize FastAPI app
55
- app = FastAPI()
56
-
57
- # Mount static files for serving generated models
58
- app.mount("/files", StaticFiles(directory=TMP_DIR), name="files")
59
-
60
- # API key authentication
61
- api_key_header = APIKeyHeader(name="X-API-Key")
62
- VALID_API_KEY = os.getenv("POLYGENIX_API_KEY", "your-secret-api-key") # Set in Hugging Face Space secrets
63
-
64
- async def verify_api_key(api_key: str = Depends(api_key_header)):
65
- if api_key != VALID_API_KEY:
66
- raise HTTPException(status_code=401, detail="Invalid API key")
67
- return api_key
68
-
69
- # API request model
70
- class GenerateRequest(BaseModel):
71
- seed: int = 0
72
- num_inference_steps: int = 50
73
- guidance_scale: float = 7.5
74
- simplify: bool = True
75
- target_face_num: int = DEFAULT_FACE_NUMBER
76
-
77
- HEADER = """
78
- # 🌌 PolyGenixAI: Craft 3D Worlds with Cosmic Precision
79
- ## Unleash Infinite Creativity with AI-Powered 3D Generation by AnvilInteractive Solutions
80
- <p style="font-size: 1.1em; color: #A78BFA;">By <a href="https://www.anvilinteractive.com/" style="color: #A78BFA; text-decoration: none; font-weight: bold;">AnvilInteractive Solutions</a></p>
81
- ## 🚀 Launch Your Creation:
82
- 1. **Upload an Image** (clear, single-object images shine brightest)
83
- 2. **Choose a Style Filter** to infuse your unique vision
84
- 3. Click **Generate 3D Model** to sculpt your mesh
85
- 4. Click **Apply Texture** to bring your model to life
86
- 5. **Download GLB** to share your masterpiece
87
- <p style="font-size: 0.9em; margin-top: 10px; color: #D1D5DB;">Powered by cutting-edge AI and multi-view technology from AnvilInteractive Solutions. Join our <a href="https://www.anvilinteractive.com/community" style="color: #A78BFA; text-decoration: none;">PolyGenixAI Community</a> to connect with creators and spark inspiration.</p>
88
- <style>
89
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
90
- body {
91
- background-color: #1A1A1A !important;
92
- font-family: 'Inter', sans-serif !important;
93
- color: #D1D5DB !important;
94
- }
95
- .gr-panel {
96
- background-color: #2D2D2D !important;
97
- border: 1px solid #7C3AED !important;
98
- border-radius: 12px !important;
99
- padding: 20px !important;
100
- box-shadow: 0 4px 10px rgba(124, 58, 237, 0.2) !important;
101
- }
102
- .gr-button-primary {
103
- background: linear-gradient(45deg, #7C3AED, #A78BFA) !important;
104
- color: white !important;
105
- border: none !important;
106
- border-radius: 8px !important;
107
- padding: 12px 24px !important;
108
- font-weight: 600 !important;
109
- transition: transform 0.2s, box-shadow 0.2s !important;
110
- }
111
- .gr-button-primary:hover {
112
- transform: translateY(-2px) !important;
113
- box-shadow: 0 4px 12px rgba(124, 58, 237, 0.5) !important;
114
- }
115
- .gr-button-secondary {
116
- background-color: #4B4B4B !important;
117
- color: #D1D5DB !important;
118
- border: 1px solid #A78BFA !important;
119
- border-radius: 8px !important;
120
- padding: 10px 20px !important;
121
- transition: transform 0.2s !important;
122
- }
123
- .gr-button-secondary:hover {
124
- transform: translateY(-1px) !important;
125
- background-color: #6B6B6B !important;
126
- }
127
- .gr-accordion {
128
- background-color: #2D2D2D !important;
129
- border-radius: 8px !important;
130
- border: 1px solid #7C3AED !important;
131
- }
132
- .gr-tab {
133
- background-color: #2D2D2D !important;
134
- color: #A78BFA !important;
135
- border: 1px solid #7C3AED !important;
136
- border-radius: 8px !important;
137
- margin: 5px !important;
138
- }
139
- .gr-tab:hover, .gr-tab-selected {
140
- background: linear-gradient(45deg, #7C3AED, #A78BFA) !important;
141
- color: white !important;
142
- }
143
- .gr-slider input[type=range]::-webkit-slider-thumb {
144
- background-color: #7C3AED !important;
145
- border: 2px solid #A78BFA !important;
146
- }
147
- .gr-dropdown {
148
- background-color: #2D2D2D !important;
149
- color: #D1D5DB !important;
150
- border: 1px solid #A78BFA !important;
151
- border-radius: 8px !important;
152
- }
153
- h1, h3 {
154
- color: #A78BFA !important;
155
- text-shadow: 0 0 10px rgba(124, 58, 237, 0.5) !important;
156
- }
157
- </style>
158
- """
159
-
160
  # triposg
161
  from image_process import prepare_image
162
  from briarmbg import BriaRMBG
@@ -184,9 +72,8 @@ mv_adapter_pipe = prepare_pipeline(
184
  dtype=torch.float16,
185
  )
186
  birefnet = AutoModelForImageSegmentation.from_pretrained(
187
- "ZhengPeng7/BiRefNet", trust_remote_code=True
188
- )
189
- birefnet.to(DEVICE)
190
  transform_image = transforms.Compose(
191
  [
192
  transforms.Resize((1024, 1024)),
@@ -201,33 +88,13 @@ if not os.path.exists("checkpoints/RealESRGAN_x2plus.pth"):
201
  if not os.path.exists("checkpoints/big-lama.pt"):
202
  subprocess.run("wget -P checkpoints/ https://github.com/Sanster/models/releases/download/add_big_lama/big-lama.pt", shell=True, check=True)
203
 
204
- def start_session(req: gr.Request):
205
- save_dir = os.path.join(TMP_DIR, str(req.session_hash))
206
- os.makedirs(save_dir, exist_ok=True)
207
- print("start session, mkdir", save_dir)
208
-
209
- def end_session(req: gr.Request):
210
- save_dir = os.path.join(TMP_DIR, str(req.session_hash))
211
- shutil.rmtree(save_dir)
212
-
213
  def get_random_hex():
214
  random_bytes = os.urandom(8)
215
  random_hex = random_bytes.hex()
216
  return random_hex
217
 
218
- def get_random_seed(randomize_seed, seed):
219
- if randomize_seed:
220
- seed = random.randint(0, MAX_SEED)
221
- return seed
222
-
223
  @spaces.GPU(duration=180)
224
- def run_full(image: str, req: gr.Request):
225
- seed = 0
226
- num_inference_steps = 50
227
- guidance_scale = 7.5
228
- simplify = True
229
- target_face_num = DEFAULT_FACE_NUMBER
230
-
231
  image_seg = prepare_image(image, bg_color=np.array([1.0, 1.0, 1.0]), rmbg_net=rmbg_net)
232
 
233
  outputs = triposg_pipe(
@@ -253,7 +120,6 @@ def run_full(image: str, req: gr.Request):
253
  torch.cuda.empty_cache()
254
 
255
  height, width = 768, 768
256
- # Prepare cameras
257
  cameras = get_orthogonal_camera(
258
  elevation_deg=[0, 0, 0, 0, 89.99, -89.99],
259
  distance=[1.8] * NUM_VIEWS,
@@ -337,30 +203,33 @@ def run_full(image: str, req: gr.Request):
337
 
338
  return image_seg, mesh_path, textured_glb_path
339
 
340
- # FastAPI endpoint for generating 3D models
341
- @app.post("/api/generate")
342
- async def generate_3d_model(request: GenerateRequest, image: UploadFile = File(...), api_key: str = Depends(verify_api_key)):
343
- try:
344
- # Save uploaded image to temporary directory
345
- session_hash = get_random_hex()
346
- save_dir = os.path.join(TMP_DIR, session_hash)
347
- os.makedirs(save_dir, exist_ok=True)
348
- image_path = os.path.join(save_dir, f"input_{get_random_hex()}.png")
349
- with open(image_path, "wb") as f:
350
- f.write(await image.read())
351
-
352
- # Run the full pipeline
353
- image_seg, mesh_path, textured_glb_path = run_full(image_path, req=None)
354
-
355
- # Return the file URL for the textured GLB
356
- file_url = f"/files/{session_hash}/{os.path.basename(textured_glb_path)}"
357
- return {"file_url": file_url}
358
- except Exception as e:
359
- raise HTTPException(status_code=500, detail=str(e))
360
- finally:
361
- # Clean up temporary directory
362
- if os.path.exists(save_dir):
363
- shutil.rmtree(save_dir)
 
 
 
364
 
365
  @spaces.GPU()
366
  @torch.no_grad()
@@ -406,7 +275,6 @@ def image_to_3d(
406
  @torch.no_grad()
407
  def run_texture(image: Image, mesh_path: str, seed: int, req: gr.Request):
408
  height, width = 768, 768
409
- # Prepare cameras
410
  cameras = get_orthogonal_camera(
411
  elevation_deg=[0, 0, 0, 0, 89.99, -89.99],
412
  distance=[1.8] * NUM_VIEWS,
@@ -467,7 +335,6 @@ def run_texture(image: Image, mesh_path: str, seed: int, req: gr.Request):
467
 
468
  torch.cuda.empty_cache()
469
 
470
- save_dir = os.path.join(TMP_DIR, str(req.session_hash))
471
  mv_image_path = os.path.join(save_dir, f"polygenixai_mv_{get_random_hex()}.png")
472
  make_image_grid(images, rows=1).save(mv_image_path)
473
 
@@ -491,14 +358,92 @@ def run_texture(image: Image, mesh_path: str, seed: int, req: gr.Request):
491
 
492
  return textured_glb_path
493
 
494
- # Gradio interface (unchanged)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  with gr.Blocks(title="PolyGenixAI", css="body { background-color: #1A1A1A; } .gr-panel { background-color: #2D2D2D; }") as demo:
496
  gr.Markdown(HEADER)
497
-
498
- @app.get("/api/test")
499
- async def test_endpoint():
500
- return {"message": "FastAPI is running"}
501
-
502
  with gr.Tabs(elem_classes="gr-tab"):
503
  with gr.Tab("Create 3D Model"):
504
  with gr.Row():
@@ -551,12 +496,10 @@ with gr.Blocks(title="PolyGenixAI", css="body { background-color: #1A1A1A; } .gr
551
  )
552
  gen_button = gr.Button("Generate 3D Model", variant="primary", elem_classes="gr-button-primary")
553
  gen_texture_button = gr.Button("Apply Texture", variant="secondary", interactive=False, elem_classes="gr-button-secondary")
554
-
555
  with gr.Column(scale=1):
556
  model_output = gr.Model3D(label="3D Model Preview", interactive=False, height=400, elem_classes="gr-panel")
557
  textured_model_output = gr.Model3D(label="Textured 3D Model", interactive=False, height=400, elem_classes="gr-panel")
558
  download_button = gr.Button("Download GLB", variant="secondary", elem_classes="gr-button-secondary")
559
-
560
  with gr.Tab("Cosmic Gallery"):
561
  gr.Markdown("### Discover Stellar Creations")
562
  gr.Examples(
@@ -570,7 +513,6 @@ with gr.Blocks(title="PolyGenixAI", css="body { background-color: #1A1A1A; } .gr
570
  cache_examples=True,
571
  )
572
  gr.Markdown("Connect with creators in our <a href='https://www.anvilinteractive.com/community' style='color: #A78BFA; text-decoration: none;'>PolyGenixAI Cosmic Community</a>!")
573
-
574
  gen_button.click(
575
  run_segmentation,
576
  inputs=[image_prompts],
@@ -591,16 +533,174 @@ with gr.Blocks(title="PolyGenixAI", css="body { background-color: #1A1A1A; } .gr
591
  ],
592
  outputs=[model_output]
593
  ).then(lambda: gr.Button(interactive=True), outputs=[gen_texture_button])
594
-
595
  gen_texture_button.click(
596
  run_texture,
597
  inputs=[image_prompts, model_output, seed],
598
  outputs=[textured_model_output]
599
  )
600
-
601
  demo.load(start_session)
602
  demo.unload(end_session)
603
 
604
- # Run both Gradio and FastAPI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
  if __name__ == "__main__":
606
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
11
  from huggingface_hub import hf_hub_download, snapshot_download
12
  import subprocess
13
  import shutil
 
 
 
 
 
14
 
15
  # Install additional dependencies
16
  subprocess.run("pip install spandrel==0.4.1 --no-deps", shell=True, check=True)
 
17
 
18
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
19
  DTYPE = torch.float16
 
45
  sys.path.append(MV_ADAPTER_CODE_DIR)
46
  sys.path.append(os.path.join(MV_ADAPTER_CODE_DIR, "scripts"))
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  # triposg
49
  from image_process import prepare_image
50
  from briarmbg import BriaRMBG
 
72
  dtype=torch.float16,
73
  )
74
  birefnet = AutoModelForImageSegmentation.from_pretrained(
75
+ "ZhengPeng7/BiRefNet", trust_remote_code=True
76
+ ).to(DEVICE)
 
77
  transform_image = transforms.Compose(
78
  [
79
  transforms.Resize((1024, 1024)),
 
88
  if not os.path.exists("checkpoints/big-lama.pt"):
89
  subprocess.run("wget -P checkpoints/ https://github.com/Sanster/models/releases/download/add_big_lama/big-lama.pt", shell=True, check=True)
90
 
 
 
 
 
 
 
 
 
 
91
  def get_random_hex():
92
  random_bytes = os.urandom(8)
93
  random_hex = random_bytes.hex()
94
  return random_hex
95
 
 
 
 
 
 
96
  @spaces.GPU(duration=180)
97
+ def run_full(image: str, seed: int = 0, num_inference_steps: int = 50, guidance_scale: float = 7.5, simplify: bool = True, target_face_num: int = DEFAULT_FACE_NUMBER, req=None):
 
 
 
 
 
 
98
  image_seg = prepare_image(image, bg_color=np.array([1.0, 1.0, 1.0]), rmbg_net=rmbg_net)
99
 
100
  outputs = triposg_pipe(
 
120
  torch.cuda.empty_cache()
121
 
122
  height, width = 768, 768
 
123
  cameras = get_orthogonal_camera(
124
  elevation_deg=[0, 0, 0, 0, 89.99, -89.99],
125
  distance=[1.8] * NUM_VIEWS,
 
203
 
204
  return image_seg, mesh_path, textured_glb_path
205
 
206
+ def gradio_generate(image: str, seed: int = 0, num_inference_steps: int = 50, guidance_scale: float = 7.5, simplify: bool = True, target_face_num: int = DEFAULT_FACE_NUMBER):
207
+ if not image or not os.path.exists(image):
208
+ raise ValueError("Invalid or missing image file")
209
+
210
+ # Verify API key
211
+ api_key = os.getenv("POLYGENIX_API_KEY", "your-secret-api-key")
212
+ request = gr.Request()
213
+ if not request.headers.get("x-api-key") == api_key:
214
+ raise ValueError("Invalid API key")
215
+
216
+ image_seg, mesh_path, textured_glb_path = run_full(image, seed, num_inference_steps, guidance_scale, simplify, target_face_num, req=None)
217
+ session_hash = os.path.basename(os.path.dirname(textured_glb_path))
218
+ return {"file_url": f"/files/{session_hash}/{os.path.basename(textured_glb_path)}"}
219
+
220
+ def start_session(req: gr.Request):
221
+ save_dir = os.path.join(TMP_DIR, str(req.session_hash))
222
+ os.makedirs(save_dir, exist_ok=True)
223
+ print("start session, mkdir", save_dir)
224
+
225
+ def end_session(req: gr.Request):
226
+ save_dir = os.path.join(TMP_DIR, str(req.session_hash))
227
+ shutil.rmtree(save_dir)
228
+
229
+ def get_random_seed(randomize_seed, seed):
230
+ if randomize_seed:
231
+ seed = random.randint(0, MAX_SEED)
232
+ return seed
233
 
234
  @spaces.GPU()
235
  @torch.no_grad()
 
275
  @torch.no_grad()
276
  def run_texture(image: Image, mesh_path: str, seed: int, req: gr.Request):
277
  height, width = 768, 768
 
278
  cameras = get_orthogonal_camera(
279
  elevation_deg=[0, 0, 0, 0, 89.99, -89.99],
280
  distance=[1.8] * NUM_VIEWS,
 
335
 
336
  torch.cuda.empty_cache()
337
 
 
338
  mv_image_path = os.path.join(save_dir, f"polygenixai_mv_{get_random_hex()}.png")
339
  make_image_grid(images, rows=1).save(mv_image_path)
340
 
 
358
 
359
  return textured_glb_path
360
 
361
+ HEADER = """
362
+ # 🌌 PolyGenixAI: Craft 3D Worlds with Cosmic Precision
363
+ ## Unleash Infinite Creativity with AI-Powered 3D Generation by AnvilInteractive Solutions
364
+ <p style="font-size: 1.1em; color: #A78BFA;">By <a href="https://www.anvilinteractive.com/" style="color: #A78BFA; text-decoration: none; font-weight: bold;">AnvilInteractive Solutions</a></p>
365
+ ## 🚀 Launch Your Creation:
366
+ 1. **Upload an Image** (clear, single-object images shine brightest)
367
+ 2. **Choose a Style Filter** to infuse your unique vision
368
+ 3. Click **Generate 3D Model** to sculpt your mesh
369
+ 4. Click **Apply Texture** to bring your model to life
370
+ 5. **Download GLB** to share your masterpiece
371
+ <p style="font-size: 0.9em; margin-top: 10px; color: #D1D5DB;">Powered by cutting-edge AI and multi-view technology from AnvilInteractive Solutions. Join our <a href="https://www.anvilinteractive.com/community" style="color: #A78BFA; text-decoration: none;">PolyGenixAI Community</a> to connect with creators and spark inspiration.</p>
372
+ <style>
373
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
374
+ body {
375
+ background-color: #1A1A1A !important;
376
+ font-family: 'Inter', sans-serif !important;
377
+ color: #D1D5DB !important;
378
+ }
379
+ .gr-panel {
380
+ background-color: #2D2D2D !important;
381
+ border: 1px solid #7C3AED !important;
382
+ border-radius: 12px !important;
383
+ padding: 20px !important;
384
+ box-shadow: 0 4px 10px rgba(124, 58, 237, 0.2) !important;
385
+ }
386
+ .gr-button-primary {
387
+ background: linear-gradient(45deg, #7C3AED, #A78BFA) !important;
388
+ color: white !important;
389
+ border: none !important;
390
+ border-radius: 8px !important;
391
+ padding: 12px 24px !important;
392
+ font-weight: 600 !important;
393
+ transition: transform 0.2s, box-shadow 0.2s !important;
394
+ }
395
+ .gr-button-primary:hover {
396
+ transform: translateY(-2px) !important;
397
+ box-shadow: 0 4px 12px rgba(124, 58, 237, 0.5) !important;
398
+ }
399
+ .gr-button-secondary {
400
+ background-color: #4B4B4B !important;
401
+ color: #D1D5DB !important;
402
+ border: 1px solid #A78BFA !important;
403
+ border-radius: 8px !important;
404
+ padding: 10px 20px !important;
405
+ transition: transform 0.2s !important;
406
+ }
407
+ .gr-button-secondary:hover {
408
+ transform: translateY(-1px) !important;
409
+ background-color: #6B6B6B !important;
410
+ }
411
+ .gr-accordion {
412
+ background-color: #2D2D2D !important;
413
+ border-radius: 8px !important;
414
+ border: 1px solid #7C3AED !important;
415
+ }
416
+ .gr-tab {
417
+ background-color: #2D2D2D !important;
418
+ color: #A78BFA !important;
419
+ border: 1px solid #7C3AED !important;
420
+ border-radius: 8px !important;
421
+ margin: 5px !important;
422
+ }
423
+ .gr-tab:hover, .gr-tab-selected {
424
+ background: linear-gradient(45deg, #7C3AED, #A78BFA) !important;
425
+ color: white !important;
426
+ }
427
+ .gr-slider input[type=range]::-webkit-slider-thumb {
428
+ background-color: #7C3AED !important;
429
+ border: 2px solid #A78BFA !important;
430
+ }
431
+ .gr-dropdown {
432
+ background-color: #2D2D2D !important;
433
+ color: #D1D5DB !important;
434
+ border: 1px solid #A78BFA !important;
435
+ border-radius: 8px !important;
436
+ }
437
+ h1, h3 {
438
+ color: #A78BFA !important;
439
+ text-shadow: 0 0 10px rgba(124, 58, 237, 0.5) !important;
440
+ }
441
+ </style>
442
+ """
443
+
444
+ # Gradio interface
445
  with gr.Blocks(title="PolyGenixAI", css="body { background-color: #1A1A1A; } .gr-panel { background-color: #2D2D2D; }") as demo:
446
  gr.Markdown(HEADER)
 
 
 
 
 
447
  with gr.Tabs(elem_classes="gr-tab"):
448
  with gr.Tab("Create 3D Model"):
449
  with gr.Row():
 
496
  )
497
  gen_button = gr.Button("Generate 3D Model", variant="primary", elem_classes="gr-button-primary")
498
  gen_texture_button = gr.Button("Apply Texture", variant="secondary", interactive=False, elem_classes="gr-button-secondary")
 
499
  with gr.Column(scale=1):
500
  model_output = gr.Model3D(label="3D Model Preview", interactive=False, height=400, elem_classes="gr-panel")
501
  textured_model_output = gr.Model3D(label="Textured 3D Model", interactive=False, height=400, elem_classes="gr-panel")
502
  download_button = gr.Button("Download GLB", variant="secondary", elem_classes="gr-button-secondary")
 
503
  with gr.Tab("Cosmic Gallery"):
504
  gr.Markdown("### Discover Stellar Creations")
505
  gr.Examples(
 
513
  cache_examples=True,
514
  )
515
  gr.Markdown("Connect with creators in our <a href='https://www.anvilinteractive.com/community' style='color: #A78BFA; text-decoration: none;'>PolyGenixAI Cosmic Community</a>!")
 
516
  gen_button.click(
517
  run_segmentation,
518
  inputs=[image_prompts],
 
533
  ],
534
  outputs=[model_output]
535
  ).then(lambda: gr.Button(interactive=True), outputs=[gen_texture_button])
 
536
  gen_texture_button.click(
537
  run_texture,
538
  inputs=[image_prompts, model_output, seed],
539
  outputs=[textured_model_output]
540
  )
 
541
  demo.load(start_session)
542
  demo.unload(end_session)
543
 
544
+ # Gradio API endpoint
545
+ gr.Interface(
546
+ fn=gradio_generate,
547
+ inputs=[
548
+ gr.Image(type="filepath", label="Image"),
549
+ gr.Number(label="Seed", value=0, precision=0),
550
+ gr.Number(label="Inference Steps", value=50, precision=0),
551
+ gr.Number(label="Guidance Scale", value=7.5),
552
+ gr.Checkbox(label="Simplify Mesh", value=True),
553
+ gr.Number(label="Target Face Number", value=DEFAULT_FACE_NUMBER, precision=0)
554
+ ],
555
+ outputs="json",
556
+ api_name="/api/generate"
557
+ )
558
+
559
+ if __name__ == "__main__":
560
+ demo.launch(server_name="0.0.0.0", server_port=7860)
561
+ ```
562
+
563
+ #### Updated `polygenix_connector.py`
564
+ This Blender addon is modified to send a multipart/form-data request to the Gradio API endpoint `/api/generate`, including the image file and parameters, with the API key in the headers. Since Gradio’s API typically expects a JSON payload but can handle file uploads, we’ll use a multipart request to align with the original FastAPI endpoint’s behavior, ensuring compatibility with the `run_full` function.
565
+
566
+ <xaiArtifact artifact_id="abd5354a-b0dd-402a-ac97-da6758e80d6e" artifact_version_id="294e2e52-e5ab-4c63-9067-5cc5b60ac63f" title="polygenix_connector.py" contentType="text/python">
567
+ ```python
568
+ import bpy
569
+ import requests
570
+ import os
571
+ from bpy.types import Operator, Panel
572
+ from bpy.props import StringProperty, IntProperty, FloatProperty, BoolProperty
573
+
574
+ class PolyGenixAIOperator(Operator):
575
+ bl_idname = "polygenixai.generate_model"
576
+ bl_label = "Generate Model"
577
+ bl_description = "Generate a 3D model from an image using PolyGenixAI6.0 API"
578
+
579
+ image_path: StringProperty(
580
+ name="Image",
581
+ description="Path to the input image",
582
+ subtype='FILE_PATH'
583
+ )
584
+ seed: IntProperty(
585
+ name="Seed",
586
+ description="Random seed for generation",
587
+ default=0,
588
+ min=0
589
+ )
590
+ num_inference_steps: IntProperty(
591
+ name="Inference Steps",
592
+ description="Number of inference steps",
593
+ default=50,
594
+ min=8,
595
+ max=50
596
+ )
597
+ guidance_scale: FloatProperty(
598
+ name="Guidance Scale",
599
+ description="Guidance scale for generation",
600
+ default=7.5,
601
+ min=0.0,
602
+ max=20.0
603
+ )
604
+ simplify_mesh: BoolProperty(
605
+ name="Simplify Mesh",
606
+ description="Simplify the generated mesh",
607
+ default=True
608
+ )
609
+ target_face_num: IntProperty(
610
+ name="Target Face Number",
611
+ description="Target number of faces for simplified mesh",
612
+ default=100000,
613
+ min=10000,
614
+ max=1000000
615
+ )
616
+
617
+ def execute(self, context):
618
+ self.report({'INFO'}, "Generating model, please wait up to 3 minutes...")
619
+ api_url = "https://anvilinteractiv-polygenixai60.hf.space/api/generate"
620
+ api_key = "2065d2dc-d0d4-4432-8279-58d720bf2a72"
621
+
622
+ if not self.image_path:
623
+ self.report({'ERROR'}, "Please select an image file")
624
+ return {'CANCELLED'}
625
+
626
+ if not os.path.exists(self.image_path):
627
+ self.report({'ERROR'}, f"Image file not found: {self.image_path}")
628
+ return {'CANCELLED'}
629
+
630
+ try:
631
+ with open(self.image_path, 'rb') as image_file:
632
+ files = {'data[0]': (os.path.basename(self.image_path), image_file, 'image/jpeg')}
633
+ data = {
634
+ 'data[1]': str(self.seed),
635
+ 'data[2]': str(self.num_inference_steps),
636
+ 'data[3]': str(self.guidance_scale),
637
+ 'data[4]': str(self.simplify_mesh).lower(),
638
+ 'data[5]': str(self.target_face_num)
639
+ }
640
+ headers = {'X-API-Key': api_key}
641
+
642
+ response = requests.post(api_url, files=files, data=data, headers=headers, timeout=300)
643
+
644
+ if response.status_code == 200:
645
+ result = response.json()
646
+ glb_url = result.get('data', {}).get('file_url')
647
+ if not glb_url:
648
+ self.report({'ERROR'}, "No file URL returned from API")
649
+ return {'CANCELLED'}
650
+
651
+ # Download the GLB file
652
+ full_glb_url = f"https://anvilinteractiv-polygenixai60.hf.space{glb_url}"
653
+ glb_response = requests.get(full_glb_url, timeout=60)
654
+
655
+ if glb_response.status_code != 200:
656
+ self.report({'ERROR'}, f"Failed to download GLB file: {glb_response.status_code}")
657
+ return {'CANCELLED'}
658
+
659
+ # Save GLB to temporary file
660
+ temp_glb_path = os.path.join(bpy.app.tempdir, f"polygenix_model_{os.urandom(8).hex()}.glb")
661
+ with open(temp_glb_path, 'wb') as f:
662
+ f.write(glb_response.content)
663
+
664
+ # Import GLB into Blender
665
+ bpy.ops.import_scene.gltf(filepath=temp_glb_path)
666
+
667
+ # Clean up temporary file
668
+ os.remove(temp_glb_path)
669
+
670
+ self.report({'INFO'}, "Model generated and imported successfully")
671
+ return {'FINISHED'}
672
+ else:
673
+ self.report({'ERROR'}, f"API Error: {response.status_code} - {response.text}")
674
+ return {'CANCELLED'}
675
+
676
+ except requests.exceptions.RequestException as e:
677
+ self.report({'ERROR'}, f"Request failed: {str(e)}")
678
+ return {'CANCELLED'}
679
+ except Exception as e:
680
+ self.report({'ERROR'}, f"Unexpected error: {str(e)}")
681
+ return {'CANCELLED'}
682
+
683
+ def invoke(self, context, event):
684
+ return context.window_manager.invoke_props_dialog(self)
685
+
686
+ class PolyGenixAIPanel(Panel):
687
+ bl_label = "PolyGenixAI6.0 Connector"
688
+ bl_idname = "PT_PolyGenixAI"
689
+ bl_space_type = 'VIEW_3D'
690
+ bl_region_type = 'UI'
691
+ bl_category = 'PolyGenix'
692
+
693
+ def draw(self, context):
694
+ layout = self.layout
695
+ layout.operator("polygenixai.generate_model")
696
+
697
+ def register():
698
+ bpy.utils.register_class(PolyGenixAIOperator)
699
+ bpy.utils.register_class(PolyGenixAIPanel)
700
+
701
+ def unregister():
702
+ bpy.utils.unregister_class(PolyGenixAIOperator)
703
+ bpy.utils.unregister_class(PolyGenixAIPanel)
704
+
705
  if __name__ == "__main__":
706
+ register()