hamzaanwar12 commited on
Commit
ead29aa
·
1 Parent(s): eb6abb5

some changes

Browse files
Files changed (1) hide show
  1. app.py +255 -242
app.py CHANGED
@@ -1,9 +1,3 @@
1
- # common
2
-
3
-
4
- # ====================================>GPT
5
-
6
-
7
  import os
8
  import sys
9
  import torch
@@ -21,23 +15,25 @@ import io
21
  from fastapi import FastAPI, HTTPException
22
  import uvicorn
23
  from pydantic import BaseModel
 
 
 
 
24
 
25
  # ===========================
26
- # ENVIRONMENT SETUP
27
  # ===========================
28
- # Disable telemetry and set environment
29
-
30
 
 
 
 
31
  os.environ['HF_HUB_DISABLE_TELEMETRY'] = '1'
32
  os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers_cache'
33
  os.environ['HF_HOME'] = '/tmp/huggingface_cache'
34
-
35
- # max_threads = min(multiprocessing.cpu_count(), 2)
36
- # os.environ["OMP_NUM_THREADS"] = str(max_threads)
37
- # os.environ["MKL_NUM_THREADS"] = str(max_threads)
38
- # os.environ["OPENBLAS_NUM_THREADS"] = str(max_threads)
39
-
40
-
41
 
42
  print("🚀 Starting CFLD Pose Transfer Application...")
43
  print(f"Python version: {sys.version}")
@@ -48,7 +44,7 @@ print(f"CUDA available: {torch.cuda.is_available()}")
48
  # IMPORTS (with error handling)
49
  # ===========================
50
  try:
51
- from huggingface_hub import snapshot_download
52
  from diffusers import DDPMScheduler
53
  print("✅ Core dependencies imported successfully")
54
  except ImportError as e:
@@ -80,6 +76,8 @@ class ModelState:
80
  self.model_dir = None
81
  self.is_loaded = False
82
  self.is_downloaded = False
 
 
83
 
84
  def reset(self):
85
  """Reset model state for memory management"""
@@ -138,123 +136,245 @@ def build_pose_img(annotation_file, img_path, device='cuda'):
138
  print(f"Error building pose image: {e}")
139
  raise
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # ===========================
142
- # MODEL DOWNLOADING (No GPU required)
143
  # ===========================
144
  def download_models():
145
- """Download models from Hugging Face Hub (no GPU required)"""
146
  global model_state
147
 
148
  if model_state.is_downloaded:
149
- print("✅ Models already downloaded")
150
- return True
151
 
152
  try:
 
153
  print("⏳ Downloading models & data from repository...")
 
154
  repo_id = "recky101/new_l_cfld_model"
155
- model_state.model_dir = snapshot_download(
156
- repo_id=repo_id,
157
- cache_dir="/tmp/model_cache",
158
- resume_download=True
159
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  print(f"📁 Downloaded to: {model_state.model_dir}")
161
 
 
 
 
 
 
 
162
  # Load dataset (doesn't require GPU)
 
163
  print("📊 Loading fashion dataset...")
164
- model_state.test_pairs = pd.read_csv(
165
- os.path.join(model_state.model_dir, "fashion", "fasion-resize-pairs-test.csv")
166
- )
167
- model_state.annotation_file = pd.read_csv(
168
- os.path.join(model_state.model_dir, "fashion", "fasion-resize-annotation-test.csv"),
169
- sep=":"
170
- )
171
- model_state.annotation_file = model_state.annotation_file.set_index("name")
 
 
 
 
 
172
 
173
  model_state.is_downloaded = True
 
 
174
  print("✅ All models downloaded successfully!")
175
  print(f"📈 Loaded {len(model_state.test_pairs)} test pairs")
176
 
177
- return True
 
 
 
178
 
179
  except Exception as e:
180
- print(f"❌ Error downloading models: {e}")
 
 
181
  traceback.print_exc()
182
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
  # ===========================
185
- # MODEL LOADING (GPU required)
186
  # ===========================
187
  def load_models_gpu():
188
  """Load models on GPU with proper memory management"""
189
  global model_state
190
 
191
  if model_state.is_loaded:
192
- return True
 
193
 
194
  # Ensure models are downloaded first
195
  if not model_state.is_downloaded:
196
- success = download_models()
197
- if not success:
198
- return False
 
 
199
 
200
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
 
201
  print(f"🔧 Loading models on device: {device}")
202
 
203
  try:
204
  with gpu_memory_guard():
205
  # Load scheduler
 
206
  print("🔧 Loading scheduler...")
207
  model_state.noise_scheduler = DDPMScheduler.from_pretrained(
208
  os.path.join(model_state.model_dir, "pretrained_models/scheduler")
209
  )
210
 
211
  # Load VAE
 
212
  print("🔧 Loading VAE...")
213
  model_state.vae = VariationalAutoencoder(
214
  pretrained_path=os.path.join(model_state.model_dir, "pretrained_models/vae")
215
  ).eval().requires_grad_(False).to(device)
216
 
217
  # Load main model
 
218
  print("🔧 Loading main model...")
219
- model_state.model = build_model(cfg).eval().requires_grad_(False).to(device)
 
 
 
 
 
 
 
 
 
 
 
220
 
221
  # Load UNet
 
222
  print("🔧 Loading UNet...")
223
  model_state.unet = UNet(cfg).eval().requires_grad_(False).to(device)
224
 
225
  # Load weights
 
226
  print("📦 Loading model weights...")
227
- model_weights = torch.load(
228
- os.path.join(model_state.model_dir, "checkpoints/pytorch_model.bin"),
229
- map_location=device
230
- )
 
 
 
 
 
 
231
  model_state.model.load_state_dict(model_weights, strict=False)
232
  del model_weights # Free memory
233
 
234
- unet_weights = torch.load(
235
- os.path.join(model_state.model_dir, "checkpoints/pytorch_model_1.bin"),
236
- map_location=device
237
- )
238
  model_state.unet.load_state_dict(unet_weights, strict=False)
239
  del unet_weights # Free memory
240
 
241
  model_state.is_loaded = True
 
242
  print("✅ All models loaded successfully!")
243
 
244
- return True
245
 
246
  except Exception as e:
247
- print(f"❌ Error loading models: {e}")
 
 
248
  traceback.print_exc()
249
  model_state.reset()
250
- return False
251
 
252
  # ===========================
253
  # INFERENCE FUNCTION
254
  # ===========================
255
- # ===========================
256
- # INFERENCE FUNCTION (Modified)
257
- # ===========================
258
  def perform_inference(img_from_array, pair_index=None):
259
  """Perform pose transfer inference using test pair reference"""
260
  global model_state
@@ -265,9 +385,9 @@ def perform_inference(img_from_array, pair_index=None):
265
  with gpu_memory_guard():
266
  # Ensure models are loaded
267
  if not model_state.is_loaded:
268
- success = load_models_gpu()
269
- if not success:
270
- return None, "Failed to load models", None, None
271
 
272
  # Convert numpy array back to PIL Image
273
  img_from = Image.fromarray(img_from_array.astype(np.uint8))
@@ -306,7 +426,7 @@ def perform_inference(img_from_array, pair_index=None):
306
 
307
  print("🚀 Running inference...")
308
 
309
- # Main inference (same as before)
310
  with torch.no_grad():
311
  c_new, down_block_additional_residuals, up_block_additional_residuals = model_state.model({
312
  "img_cond": img_from_tensor,
@@ -358,20 +478,20 @@ def perform_inference(img_from_array, pair_index=None):
358
  output_array = (sampling_imgs[0] * 255.).permute((1, 2, 0)).cpu().numpy().astype(np.uint8)
359
 
360
  print("✅ Inference completed successfully!")
361
- return output_array, f"Success! Used test pair: {pair_index}", ref_image, img_to_path
362
 
363
  except Exception as e:
364
  print(f"❌ Error in inference: {e}")
365
  traceback.print_exc()
366
- return None, f"Error: {str(e)}", None, None
367
 
368
  # ===========================
369
- # GRADIO INTERFACE FUNCTIONS (Modified)
370
  # ===========================
371
  def gradio_inference(img_from, pair_index):
372
  """Gradio-compatible inference function"""
373
  if img_from is None:
374
- return None, "❌ Please upload an image first!", None, None
375
 
376
  try:
377
  # Convert PIL to numpy for GPU function
@@ -379,7 +499,7 @@ def gradio_inference(img_from, pair_index):
379
  result_array, message, ref_image, ref_path = perform_inference(img_array, pair_index)
380
 
381
  if result_array is None:
382
- return None, message, None, None
383
 
384
  # Convert back to PIL for gradio display
385
  result_image = Image.fromarray(result_array)
@@ -390,99 +510,67 @@ def gradio_inference(img_from, pair_index):
390
  error_msg = f"❌ Inference failed: {str(e)}"
391
  print(error_msg)
392
  traceback.print_exc()
393
- return None, error_msg, None, None
394
-
395
- # ===========================
396
- # GRADIO INTERFACE (Modified)
397
- # ===========================
398
-
399
 
400
  def check_model_status():
401
- """Check if models are loaded"""
402
  if model_state.is_loaded:
403
- return "✅ **Status:** Models loaded and ready!"
404
  elif model_state.is_downloaded:
405
  return "🔄 **Status:** Models downloaded, ready to load on first inference"
 
 
406
  else:
407
- return "📥 **Status:** Models not downloaded. Click 'Download Models' first!"
408
 
409
- # ===========================
410
- # API FUNCTIONS
411
- # ===========================
412
- class PoseTransferRequest(BaseModel):
413
- image_base64: str
414
- pose_index: int = -1 # -1 for random
415
-
416
- class PoseTransferResponse(BaseModel):
417
- success: bool
418
- message: str
419
- image_base64: str = None
420
- pose_index: int = -1
421
-
422
- def base64_to_pil(image_base64):
423
- """Convert base64 image to PIL Image"""
424
  try:
425
- if image_base64.startswith('data:image'):
426
- # Remove data URL prefix if present
427
- image_base64 = image_base64.split(',', 1)[1]
 
 
 
 
 
 
428
 
429
- image_data = base64.b64decode(image_base64)
430
- image = Image.open(io.BytesIO(image_data))
431
- return image.convert('RGB')
 
 
 
 
432
  except Exception as e:
433
- raise ValueError(f"Invalid image data: {str(e)}")
434
-
435
- def pil_to_base64(image):
436
- """Convert PIL Image to base64"""
437
- buffered = io.BytesIO()
438
- image.save(buffered, format="JPEG")
439
- img_str = base64.b64encode(buffered.getvalue()).decode()
440
- return f"data:image/jpeg;base64,{img_str}"
441
 
442
- def api_inference(image_base64, pose_index=-1):
443
- """API inference function"""
 
 
 
444
  try:
445
- # Convert base64 to PIL image
446
- img_from = base64_to_pil(image_base64)
447
-
448
- # Convert PIL to numpy for inference function
449
- img_array = np.array(img_from)
450
- result_array, message, _ = perform_inference(img_array, pose_index)
451
-
452
- if result_array is None:
453
- return PoseTransferResponse(
454
- success=False,
455
- message=message,
456
- pose_index=pose_index
457
- )
458
-
459
- # Convert result to base64
460
- result_image = Image.fromarray(result_array)
461
- result_base64 = pil_to_base64(result_image)
462
-
463
- return PoseTransferResponse(
464
- success=True,
465
- message=message,
466
- image_base64=result_base64,
467
- pose_index=pose_index
468
- )
469
 
 
 
 
 
 
 
 
470
  except Exception as e:
471
- error_msg = f"Inference failed: {str(e)}"
472
- print(error_msg)
473
- traceback.print_exc()
474
- return PoseTransferResponse(
475
- success=False,
476
- message=error_msg,
477
- pose_index=pose_index
478
- )
479
 
480
  # ===========================
481
  # GRADIO INTERFACE
482
  # ===========================
483
  def create_interface():
484
  with gr.Blocks(
485
- title="🎭 CFLD Pose Transfer - Professional Demo",
486
  theme=gr.themes.Soft(),
487
  css="""
488
  .gradio-container {
@@ -503,9 +591,9 @@ def create_interface():
503
  ) as demo:
504
 
505
  gr.Markdown("""
506
- # 🎭 CFLD Pose Transfer - Professional Demo
507
 
508
- **Upload source image + select reference pose from test pairs**
509
 
510
  ---
511
  """)
@@ -514,21 +602,10 @@ def create_interface():
514
  with gr.Row():
515
  with gr.Column():
516
  status_display = gr.Markdown(
517
- "📥 **Status:** Ready to download models...",
518
  elem_classes=["status-box"]
519
  )
520
 
521
- # Model management buttons
522
- with gr.Row():
523
- download_btn = gr.Button(
524
- "📥 Download Models (No GPU)",
525
- variant="secondary"
526
- )
527
- load_btn = gr.Button(
528
- "🔧 Load Models (GPU Required)",
529
- variant="secondary"
530
- )
531
-
532
  with gr.Row(equal_height=True):
533
  # Input column
534
  with gr.Column(scale=1):
@@ -589,7 +666,8 @@ def create_interface():
589
 
590
  ref_path_display = gr.Textbox(
591
  label="Reference Image Path",
592
- interactive=False
 
593
  )
594
 
595
  gr.Markdown("""
@@ -598,40 +676,7 @@ def create_interface():
598
  The pose is selected based on the test pair index you provide.
599
  """)
600
 
601
- # Event handlers
602
- download_btn.click(
603
- fn=download_models,
604
- outputs=[status_display],
605
- show_progress=True
606
- )
607
-
608
- load_btn.click(
609
- fn=load_models_gpu,
610
- outputs=[status_display],
611
- show_progress=True
612
- )
613
-
614
- # Preview test pair
615
- def preview_test_pair(pair_index):
616
- """Preview the test pair without running inference"""
617
- try:
618
- if not model_state.is_downloaded:
619
- return None, "Download models first!", None
620
-
621
- pair_index = min(int(pair_index), len(model_state.test_pairs) - 1)
622
- pair = model_state.test_pairs.iloc[pair_index]
623
- img_to_path = pair["to"]
624
-
625
- ref_image_path = os.path.join(model_state.model_dir, "fashion", "test_highres", img_to_path)
626
- if os.path.exists(ref_image_path):
627
- ref_image = Image.open(ref_image_path).convert("RGB")
628
- return ref_image, f"Preview: Test pair {pair_index}", img_to_path
629
- else:
630
- return None, f"Reference image not found: {img_to_path}", None
631
-
632
- except Exception as e:
633
- return None, f"Preview error: {str(e)}", None
634
-
635
  preview_btn.click(
636
  fn=preview_test_pair,
637
  inputs=[pair_index],
@@ -650,41 +695,27 @@ def create_interface():
650
  demo.load(
651
  fn=check_model_status,
652
  outputs=[status_display],
653
- every=5
654
  )
655
 
656
  # Footer
657
  gr.Markdown("""
658
  ---
659
- **How it works:**
660
- 1. Upload your source image
661
- 2. Select a test pair index (0-4499) for reference pose
662
- 3. Click generate to transfer the pose
663
- 4. Use preview to see the reference pose first
 
 
 
 
 
 
664
  """)
665
 
666
  return demo
667
 
668
- # ===========================
669
- # FASTAPI SETUP
670
- # ===========================
671
- app = FastAPI(title="CFLD Pose Transfer API")
672
-
673
- @app.post("/api/pose-transfer", response_model=PoseTransferResponse)
674
- async def api_pose_transfer(request: PoseTransferRequest):
675
- """API endpoint for pose transfer"""
676
- return api_inference(request.image_base64, request.pose_index)
677
-
678
- @app.get("/health")
679
- async def health_check():
680
- """Health check endpoint"""
681
- return {
682
- "status": "healthy",
683
- "models_downloaded": model_state.is_downloaded,
684
- "models_loaded": model_state.is_loaded,
685
- "cuda_available": torch.cuda.is_available()
686
- }
687
-
688
  # ===========================
689
  # MAIN EXECUTION
690
  # ===========================
@@ -692,33 +723,15 @@ if __name__ == "__main__":
692
  print("🌟 Creating Gradio interface...")
693
  demo = create_interface()
694
 
695
- # Download models on startup (no GPU required)
696
- print("📥 Downloading models on startup...")
697
- download_models()
698
 
699
  print("🚀 Launching application...")
700
- # Run both Gradio and FastAPI
701
- # Note: In production, you might want to run these separately
702
- import threading
703
-
704
- def run_gradio():
705
- demo.launch(
706
- server_name="0.0.0.0",
707
- server_port=7860,
708
- show_error=True,
709
- share=False,
710
- debug=False
711
- )
712
-
713
- def run_api():
714
- uvicorn.run(app, host="0.0.0.0", port=8000)
715
-
716
- # Start both servers in separate threads
717
- gradio_thread = threading.Thread(target=run_gradio)
718
- api_thread = threading.Thread(target=run_api)
719
-
720
- gradio_thread.start()
721
- api_thread.start()
722
-
723
- gradio_thread.join()
724
- api_thread.join()
 
 
 
 
 
 
 
1
  import os
2
  import sys
3
  import torch
 
15
  from fastapi import FastAPI, HTTPException
16
  import uvicorn
17
  from pydantic import BaseModel
18
+ import threading
19
+ import logging
20
+ import requests
21
+ from pathlib import Path
22
 
23
  # ===========================
24
+ # LOGGING SETUP
25
  # ===========================
26
+ logging.basicConfig(level=logging.INFO)
27
+ logger = logging.getLogger(__name__)
28
 
29
+ # ===========================
30
+ # ENVIRONMENT SETUP
31
+ # ===========================
32
  os.environ['HF_HUB_DISABLE_TELEMETRY'] = '1'
33
  os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers_cache'
34
  os.environ['HF_HOME'] = '/tmp/huggingface_cache'
35
+ # Disable hf_transfer for more reliable downloads
36
+ os.environ['HF_HUB_ENABLE_HF_TRANSFER'] = '0'
 
 
 
 
 
37
 
38
  print("🚀 Starting CFLD Pose Transfer Application...")
39
  print(f"Python version: {sys.version}")
 
44
  # IMPORTS (with error handling)
45
  # ===========================
46
  try:
47
+ from huggingface_hub import snapshot_download, hf_hub_download
48
  from diffusers import DDPMScheduler
49
  print("✅ Core dependencies imported successfully")
50
  except ImportError as e:
 
76
  self.model_dir = None
77
  self.is_loaded = False
78
  self.is_downloaded = False
79
+ self.download_progress = ""
80
+ self.load_progress = ""
81
 
82
  def reset(self):
83
  """Reset model state for memory management"""
 
136
  print(f"Error building pose image: {e}")
137
  raise
138
 
139
+ def download_swin_pretrained():
140
+ """Download Swin transformer pretrained weights"""
141
+ swin_dir = "pretrained_models/swin"
142
+ os.makedirs(swin_dir, exist_ok=True)
143
+
144
+ swin_path = os.path.join(swin_dir, "swin_base_patch4_window12_384_22kto1k.pth")
145
+
146
+ if os.path.exists(swin_path):
147
+ print("✅ Swin pretrained model already exists")
148
+ return True
149
+
150
+ try:
151
+ print("📥 Downloading Swin pretrained model...")
152
+ # Alternative download URLs for Swin transformer
153
+ swin_urls = [
154
+ "https://github.com/SwinTransformer/storage/releases/download/v1.0.0/swin_base_patch4_window12_384_22kto1k.pth",
155
+ "https://download.pytorch.org/models/swin_b-68c6b09e.pth"
156
+ ]
157
+
158
+ for url in swin_urls:
159
+ try:
160
+ response = requests.get(url, stream=True)
161
+ response.raise_for_status()
162
+
163
+ with open(swin_path, 'wb') as f:
164
+ for chunk in response.iter_content(chunk_size=8192):
165
+ f.write(chunk)
166
+
167
+ print(f"✅ Downloaded Swin model from {url}")
168
+ return True
169
+
170
+ except Exception as e:
171
+ print(f"❌ Failed to download from {url}: {e}")
172
+ continue
173
+
174
+ print("❌ All Swin download URLs failed")
175
+ return False
176
+
177
+ except Exception as e:
178
+ print(f"❌ Error downloading Swin model: {e}")
179
+ return False
180
+
181
  # ===========================
182
+ # MODEL DOWNLOADING (Enhanced)
183
  # ===========================
184
  def download_models():
185
+ """Download models from Hugging Face Hub with better error handling"""
186
  global model_state
187
 
188
  if model_state.is_downloaded:
189
+ model_state.download_progress = "✅ Models already downloaded"
190
+ return "✅ Models already downloaded"
191
 
192
  try:
193
+ model_state.download_progress = "⏳ Starting model download..."
194
  print("⏳ Downloading models & data from repository...")
195
+
196
  repo_id = "recky101/new_l_cfld_model"
197
+ cache_dir = "/tmp/model_cache"
198
+
199
+ # Download with retries and better error handling
200
+ max_retries = 3
201
+ for attempt in range(max_retries):
202
+ try:
203
+ model_state.download_progress = f"⏳ Download attempt {attempt + 1}/{max_retries}..."
204
+ model_state.model_dir = snapshot_download(
205
+ repo_id=repo_id,
206
+ cache_dir=cache_dir,
207
+ resume_download=True,
208
+ local_files_only=False,
209
+ force_download=False
210
+ )
211
+ break
212
+ except Exception as e:
213
+ print(f"❌ Download attempt {attempt + 1} failed: {e}")
214
+ if attempt == max_retries - 1:
215
+ raise e
216
+ continue
217
+
218
+ model_state.download_progress = f"📁 Downloaded to: {model_state.model_dir}"
219
  print(f"📁 Downloaded to: {model_state.model_dir}")
220
 
221
+ # Download additional Swin pretrained model
222
+ model_state.download_progress = "📥 Downloading Swin pretrained model..."
223
+ swin_success = download_swin_pretrained()
224
+ if not swin_success:
225
+ print("⚠️ Warning: Swin model download failed, but continuing...")
226
+
227
  # Load dataset (doesn't require GPU)
228
+ model_state.download_progress = "📊 Loading fashion dataset..."
229
  print("📊 Loading fashion dataset...")
230
+
231
+ try:
232
+ model_state.test_pairs = pd.read_csv(
233
+ os.path.join(model_state.model_dir, "fashion", "fasion-resize-pairs-test.csv")
234
+ )
235
+ model_state.annotation_file = pd.read_csv(
236
+ os.path.join(model_state.model_dir, "fashion", "fasion-resize-annotation-test.csv"),
237
+ sep=":"
238
+ )
239
+ model_state.annotation_file = model_state.annotation_file.set_index("name")
240
+ except Exception as e:
241
+ print(f"❌ Error loading dataset: {e}")
242
+ raise e
243
 
244
  model_state.is_downloaded = True
245
+ model_state.download_progress = f"✅ All models downloaded successfully! Loaded {len(model_state.test_pairs)} test pairs"
246
+
247
  print("✅ All models downloaded successfully!")
248
  print(f"📈 Loaded {len(model_state.test_pairs)} test pairs")
249
 
250
+ # Print directory structure for debugging
251
+ print_directory_structure()
252
+
253
+ return model_state.download_progress
254
 
255
  except Exception as e:
256
+ error_msg = f"❌ Error downloading models: {str(e)}"
257
+ model_state.download_progress = error_msg
258
+ print(error_msg)
259
  traceback.print_exc()
260
+ return error_msg
261
+
262
+ def print_directory_structure():
263
+ """Print directory structure for debugging"""
264
+ if not model_state.model_dir:
265
+ return
266
+
267
+ print("\n📂 Downloaded directory structure:")
268
+ try:
269
+ for root, dirs, files in os.walk(model_state.model_dir):
270
+ level = root.replace(model_state.model_dir, '').count(os.sep)
271
+ indent = ' ' * 2 * level
272
+ print(f"{indent}{os.path.basename(root)}/")
273
+ subindent = ' ' * 2 * (level + 1)
274
+ for file in files[:5]: # Limit to first 5 files per directory
275
+ print(f"{subindent}{file}")
276
+ if len(files) > 5:
277
+ print(f"{subindent}... and {len(files) - 5} more files")
278
+ except Exception as e:
279
+ print(f"Error listing directory: {e}")
280
 
281
  # ===========================
282
+ # MODEL LOADING (Enhanced)
283
  # ===========================
284
  def load_models_gpu():
285
  """Load models on GPU with proper memory management"""
286
  global model_state
287
 
288
  if model_state.is_loaded:
289
+ model_state.load_progress = "✅ Models already loaded"
290
+ return "✅ Models already loaded"
291
 
292
  # Ensure models are downloaded first
293
  if not model_state.is_downloaded:
294
+ model_state.load_progress = "📥 Downloading models first..."
295
+ download_result = download_models()
296
+ if "❌" in download_result:
297
+ model_state.load_progress = "❌ Failed to download models"
298
+ return "❌ Failed to download models"
299
 
300
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
301
+ model_state.load_progress = f"🔧 Loading models on device: {device}..."
302
  print(f"🔧 Loading models on device: {device}")
303
 
304
  try:
305
  with gpu_memory_guard():
306
  # Load scheduler
307
+ model_state.load_progress = "🔧 Loading scheduler..."
308
  print("🔧 Loading scheduler...")
309
  model_state.noise_scheduler = DDPMScheduler.from_pretrained(
310
  os.path.join(model_state.model_dir, "pretrained_models/scheduler")
311
  )
312
 
313
  # Load VAE
314
+ model_state.load_progress = "🔧 Loading VAE..."
315
  print("🔧 Loading VAE...")
316
  model_state.vae = VariationalAutoencoder(
317
  pretrained_path=os.path.join(model_state.model_dir, "pretrained_models/vae")
318
  ).eval().requires_grad_(False).to(device)
319
 
320
  # Load main model
321
+ model_state.load_progress = "🔧 Loading main model..."
322
  print("🔧 Loading main model...")
323
+ try:
324
+ model_state.model = build_model(cfg).eval().requires_grad_(False).to(device)
325
+ except FileNotFoundError as e:
326
+ if "swin_base_patch4_window12_384_22kto1k.pth" in str(e):
327
+ print("⚠️ Swin pretrained model not found, attempting to download...")
328
+ swin_success = download_swin_pretrained()
329
+ if swin_success:
330
+ model_state.model = build_model(cfg).eval().requires_grad_(False).to(device)
331
+ else:
332
+ raise e
333
+ else:
334
+ raise e
335
 
336
  # Load UNet
337
+ model_state.load_progress = "🔧 Loading UNet..."
338
  print("🔧 Loading UNet...")
339
  model_state.unet = UNet(cfg).eval().requires_grad_(False).to(device)
340
 
341
  # Load weights
342
+ model_state.load_progress = "📦 Loading model weights..."
343
  print("📦 Loading model weights...")
344
+
345
+ model_weights_path = os.path.join(model_state.model_dir, "checkpoints/pytorch_model.bin")
346
+ unet_weights_path = os.path.join(model_state.model_dir, "checkpoints/pytorch_model_1.bin")
347
+
348
+ if not os.path.exists(model_weights_path):
349
+ raise FileNotFoundError(f"Model weights not found: {model_weights_path}")
350
+ if not os.path.exists(unet_weights_path):
351
+ raise FileNotFoundError(f"UNet weights not found: {unet_weights_path}")
352
+
353
+ model_weights = torch.load(model_weights_path, map_location=device)
354
  model_state.model.load_state_dict(model_weights, strict=False)
355
  del model_weights # Free memory
356
 
357
+ unet_weights = torch.load(unet_weights_path, map_location=device)
 
 
 
358
  model_state.unet.load_state_dict(unet_weights, strict=False)
359
  del unet_weights # Free memory
360
 
361
  model_state.is_loaded = True
362
+ model_state.load_progress = "✅ All models loaded successfully!"
363
  print("✅ All models loaded successfully!")
364
 
365
+ return model_state.load_progress
366
 
367
  except Exception as e:
368
+ error_msg = f"❌ Error loading models: {str(e)}"
369
+ model_state.load_progress = error_msg
370
+ print(error_msg)
371
  traceback.print_exc()
372
  model_state.reset()
373
+ return error_msg
374
 
375
  # ===========================
376
  # INFERENCE FUNCTION
377
  # ===========================
 
 
 
378
  def perform_inference(img_from_array, pair_index=None):
379
  """Perform pose transfer inference using test pair reference"""
380
  global model_state
 
385
  with gpu_memory_guard():
386
  # Ensure models are loaded
387
  if not model_state.is_loaded:
388
+ load_result = load_models_gpu()
389
+ if "❌" in load_result:
390
+ return None, f"Failed to load models: {load_result}", None, None
391
 
392
  # Convert numpy array back to PIL Image
393
  img_from = Image.fromarray(img_from_array.astype(np.uint8))
 
426
 
427
  print("🚀 Running inference...")
428
 
429
+ # Main inference
430
  with torch.no_grad():
431
  c_new, down_block_additional_residuals, up_block_additional_residuals = model_state.model({
432
  "img_cond": img_from_tensor,
 
478
  output_array = (sampling_imgs[0] * 255.).permute((1, 2, 0)).cpu().numpy().astype(np.uint8)
479
 
480
  print("✅ Inference completed successfully!")
481
+ return output_array, f"Success! Used test pair: {pair_index}", ref_image, img_to_path
482
 
483
  except Exception as e:
484
  print(f"❌ Error in inference: {e}")
485
  traceback.print_exc()
486
+ return None, f"Error: {str(e)}", None, None
487
 
488
  # ===========================
489
+ # GRADIO INTERFACE FUNCTIONS
490
  # ===========================
491
  def gradio_inference(img_from, pair_index):
492
  """Gradio-compatible inference function"""
493
  if img_from is None:
494
+ return None, "❌ Please upload an image first!", None, ""
495
 
496
  try:
497
  # Convert PIL to numpy for GPU function
 
499
  result_array, message, ref_image, ref_path = perform_inference(img_array, pair_index)
500
 
501
  if result_array is None:
502
+ return None, message, None, ""
503
 
504
  # Convert back to PIL for gradio display
505
  result_image = Image.fromarray(result_array)
 
510
  error_msg = f"❌ Inference failed: {str(e)}"
511
  print(error_msg)
512
  traceback.print_exc()
513
+ return None, error_msg, None, ""
 
 
 
 
 
514
 
515
  def check_model_status():
516
+ """Check model status and return appropriate message"""
517
  if model_state.is_loaded:
518
+ return "✅ **Status:** Models loaded and ready for inference!"
519
  elif model_state.is_downloaded:
520
  return "🔄 **Status:** Models downloaded, ready to load on first inference"
521
+ elif model_state.download_progress:
522
+ return f"📥 **Status:** {model_state.download_progress}"
523
  else:
524
+ return "📥 **Status:** Ready to download models"
525
 
526
+ def preview_test_pair(pair_index):
527
+ """Preview the test pair without running inference"""
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  try:
529
+ if not model_state.is_downloaded:
530
+ return None, "❌ Download models first!", ""
531
+
532
+ if pair_index is None:
533
+ pair_index = 0
534
+
535
+ pair_index = min(int(pair_index), len(model_state.test_pairs) - 1)
536
+ pair = model_state.test_pairs.iloc[pair_index]
537
+ img_to_path = pair["to"]
538
 
539
+ ref_image_path = os.path.join(model_state.model_dir, "fashion", "test_highres", img_to_path)
540
+ if os.path.exists(ref_image_path):
541
+ ref_image = Image.open(ref_image_path).convert("RGB")
542
+ return ref_image, f"✅ Preview: Test pair {pair_index}", img_to_path
543
+ else:
544
+ return None, f"❌ Reference image not found: {img_to_path}", ""
545
+
546
  except Exception as e:
547
+ return None, f" Preview error: {str(e)}", ""
 
 
 
 
 
 
 
548
 
549
+ # ===========================
550
+ # AUTO-DOWNLOAD FUNCTION
551
+ # ===========================
552
+ def auto_download_models():
553
+ """Automatically download models on startup"""
554
  try:
555
+ print("🚀 Auto-downloading models on startup...")
556
+ download_models()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
 
558
+ # Auto-load models if GPU is available
559
+ if torch.cuda.is_available():
560
+ print("🚀 Auto-loading models (GPU detected)...")
561
+ load_models_gpu()
562
+ else:
563
+ print("⚠️ No GPU detected, models will be loaded on first inference")
564
+
565
  except Exception as e:
566
+ print(f" Auto-download failed: {e}")
 
 
 
 
 
 
 
567
 
568
  # ===========================
569
  # GRADIO INTERFACE
570
  # ===========================
571
  def create_interface():
572
  with gr.Blocks(
573
+ title="🎭 CFLD Pose Transfer - Auto-Loading Demo",
574
  theme=gr.themes.Soft(),
575
  css="""
576
  .gradio-container {
 
591
  ) as demo:
592
 
593
  gr.Markdown("""
594
+ # 🎭 CFLD Pose Transfer - Auto-Loading Demo
595
 
596
+ **Models download and load automatically! Just upload an image and generate.**
597
 
598
  ---
599
  """)
 
602
  with gr.Row():
603
  with gr.Column():
604
  status_display = gr.Markdown(
605
+ "🚀 Starting up... Models will download automatically",
606
  elem_classes=["status-box"]
607
  )
608
 
 
 
 
 
 
 
 
 
 
 
 
609
  with gr.Row(equal_height=True):
610
  # Input column
611
  with gr.Column(scale=1):
 
666
 
667
  ref_path_display = gr.Textbox(
668
  label="Reference Image Path",
669
+ interactive=False,
670
+ value=""
671
  )
672
 
673
  gr.Markdown("""
 
676
  The pose is selected based on the test pair index you provide.
677
  """)
678
 
679
+ # Event handlers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
  preview_btn.click(
681
  fn=preview_test_pair,
682
  inputs=[pair_index],
 
695
  demo.load(
696
  fn=check_model_status,
697
  outputs=[status_display],
698
+ every=3
699
  )
700
 
701
  # Footer
702
  gr.Markdown("""
703
  ---
704
+ **Fully Automatic Setup:**
705
+ - Models download automatically on startup
706
+ - Models load automatically on first use
707
+ - No manual intervention required
708
+ - Full directory structure printed to console for debugging
709
+
710
+ **How to use:**
711
+ 1. Wait for models to download (automatic)
712
+ 2. Upload your source image
713
+ 3. Select a test pair index (0-4499) for reference pose
714
+ 4. Click generate to transfer the pose
715
  """)
716
 
717
  return demo
718
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719
  # ===========================
720
  # MAIN EXECUTION
721
  # ===========================
 
723
  print("🌟 Creating Gradio interface...")
724
  demo = create_interface()
725
 
726
+ # Start auto-download in background thread
727
+ download_thread = threading.Thread(target=auto_download_models, daemon=True)
728
+ download_thread.start()
729
 
730
  print("🚀 Launching application...")
731
+ demo.launch(
732
+ server_name="0.0.0.0",
733
+ server_port=7860,
734
+ show_error=True,
735
+ share=False,
736
+ debug=False
737
+ )