Files changed (1) hide show
  1. app.py +103 -87
app.py CHANGED
@@ -20,9 +20,10 @@ client = Client(
20
 
21
  def generate_outfit(model_image, garment_image, n_samples=1, n_steps=20, image_scale=2, seed=-1):
22
  if model_image is None or garment_image is None:
 
23
  return None, "Please upload both model and garment images"
24
-
25
- max_retries = 3
26
  for attempt in range(max_retries):
27
  try:
28
  # Use the client to predict
@@ -35,117 +36,132 @@ def generate_outfit(model_image, garment_image, n_samples=1, n_steps=20, image_s
35
  seed=seed,
36
  api_name="/process_hd"
37
  )
38
-
39
- # If result is a list, get the first item
40
- if isinstance(result, list):
41
- result = result[0]
42
-
43
- # If result is a dictionary, try to get the image path
44
- if isinstance(result, dict):
45
- if 'image' in result:
46
- return result['image'], None
47
- else:
48
- return None, "API returned unexpected format"
49
-
50
- return result, None
51
-
 
 
 
 
 
 
 
 
 
 
 
 
52
  except Exception as e:
53
  error_msg = str(e)
54
- if "exceeded your GPU quota" in error_msg:
55
- wait_time_match = re.search(r'retry in (\d+:\d+:\d+)', error_msg)
56
- wait_time = wait_time_match.group(1) if wait_time_match else "60:00" # Default to 1 hour
57
- wait_seconds = sum(int(x) * 60 ** i for i, x in enumerate(reversed(wait_time.split(':')))) # Convert wait time to seconds
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  if attempt < max_retries - 1:
59
- time.sleep(wait_seconds) # Wait before retrying
60
- return None, f"GPU quota exceeded. Please wait {wait_time} before trying again."
 
 
 
 
61
  else:
62
- return None, f"Error: {str(e)}"
 
 
 
 
 
 
 
63
 
64
  # Create Gradio interface
65
  with gr.Blocks() as demo:
66
  gr.Markdown("""
67
  ## Outfit Diffusion - Try On Virtual Outfits
68
 
69
- ⚠️ **Note**: This demo uses free GPU quota which is limited. To avoid errors:
70
- - Use lower values for Steps (10-15) and Scale (1-2)
71
- - Wait between attempts if you get a quota error
72
- - Sign up for a Hugging Face account for more quota
73
 
74
-
75
  """)
76
 
77
  with gr.Row():
78
- with gr.Column():
79
  model_image = gr.Image(
80
- label="Upload Model Image (person wearing clothes)",
81
  type="filepath",
82
- height=300
83
-
84
  )
85
- model_examples = [
86
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/ba5ba7978e7302e8ab5eb733cc7221394c4e6faf/model_5.png",
87
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/40dade4a04a827c0fdf63c6c70b42ef26480f391/01861_00.jpg",
88
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/3c4639c5fab3cdcd3239609dca5afee7b0677286/model_6.png",
89
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/0089171df270f4532eec3d80a8f36cc8218c6840/01008_00.jpg"
90
- ]
91
- gr.Examples(examples=model_examples, inputs=model_image)
92
 
93
  garment_image = gr.Image(
94
- label="Upload Garment Image (clothing item)",
95
  type="filepath",
96
- height=300
97
  )
98
- garment_examples = [
99
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/180d4e2a1139071a8685a5edee7ab24bcf1639f5/03244_00.jpg",
100
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/584dda2c5ee1d8271a6cd06225c07db89c79ca03/04825_00.jpg",
101
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/a51938ec99f13e548d365a9ca6d794b6fe7462af/049949_1.jpg",
102
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/2d64241101189251ce415df84dc9205cda9a36ca/03032_00.jpg",
103
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/44aee6b576cae51eeb979311306375b56b7e0d8b/02305_00.jpg",
104
- "https://levihsu-ootdiffusion.hf.space/file=/tmp/gradio/578dfa869dedb649e91eccbe566fc76435bb6bbe/049920_1.jpg"
105
- ]
106
- gr.Examples(examples=garment_examples, inputs=garment_image)
107
-
108
-
109
- with gr.Column():
110
- output_image = gr.Image(label="Generated Output")
111
- error_text = gr.Markdown() # Add error display
112
-
113
  with gr.Row():
114
- with gr.Column():
115
- n_samples = gr.Slider(
116
- label="Number of Samples",
117
- minimum=1,
118
- maximum=5,
119
- step=1,
120
- value=1
121
- )
122
- n_steps = gr.Slider(
123
- label="Steps (lower = faster, try 10-15)",
124
- minimum=1,
125
- maximum=50,
126
- step=1,
127
- value=10 # Reduced default
128
- )
129
- image_scale = gr.Slider(
130
- label="Scale (lower = faster, try 1-2)",
131
- minimum=1,
132
- maximum=5,
133
- step=1,
134
- value=1 # Reduced default
135
- )
136
- seed = gr.Number(
137
- label="Random Seed (-1 for random)",
138
- value=-1
139
- )
140
-
141
- generate_button = gr.Button("Generate Outfit")
142
 
143
  # Set up the action for the button
144
  generate_button.click(
145
  fn=generate_outfit,
146
  inputs=[model_image, garment_image, n_samples, n_steps, image_scale, seed],
147
- outputs=[output_image, error_text]
148
  )
149
 
150
- # Launch the app
151
- demo.launch()
 
20
 
21
  def generate_outfit(model_image, garment_image, n_samples=1, n_steps=20, image_scale=2, seed=-1):
22
  if model_image is None or garment_image is None:
23
+ # Return None for the image output and the error message for the text output
24
  return None, "Please upload both model and garment images"
25
+
26
+ max_retries = 3 # You might want to adjust retries, but 3 is reasonable
27
  for attempt in range(max_retries):
28
  try:
29
  # Use the client to predict
 
36
  seed=seed,
37
  api_name="/process_hd"
38
  )
39
+
40
+ # --- Improved Result Handling ---
41
+ output_image_path = None
42
+ if isinstance(result, (list, tuple)) and len(result) > 0:
43
+ # Often results are tuples/lists; assume the image path is the first element
44
+ potential_path = result[0]
45
+ if isinstance(potential_path, str) and os.path.exists(potential_path): # Check if it looks like a valid path returned by the client
46
+ output_image_path = potential_path
47
+ elif isinstance(potential_path, dict) and 'image' in potential_path: # Handle dict case
48
+ output_image_path = potential_path['image']
49
+
50
+ elif isinstance(result, dict) and 'image' in result:
51
+ output_image_path = result['image']
52
+ elif isinstance(result, str) and os.path.exists(result): # Handle direct string path case
53
+ output_image_path = result
54
+
55
+ if output_image_path:
56
+ # Return the image path and None for the error message
57
+ return output_image_path, None
58
+ else:
59
+ # Log the unexpected result format for debugging if needed
60
+ print(f"Warning: Unexpected result format from API: {result}")
61
+ # Return None for image, and an informative error
62
+ return None, f"API returned unexpected format: {type(result)}"
63
+ # --- End Improved Result Handling ---
64
+
65
  except Exception as e:
66
  error_msg = str(e)
67
+ # Check for quota error specifically
68
+ if "exceeded your GPU quota" in error_msg or "queue is full" in error_msg.lower():
69
+ # Try to extract wait time, provide default if not found
70
+ wait_time_match = re.search(r'retry in (\d+:\d+:\d+|\d+\.?\d*\s*s)', error_msg) # Handle seconds too
71
+ wait_time_str = "an unknown period (try again in 5-10 mins)"
72
+ wait_seconds = 300 # Default 5 mins
73
+
74
+ if wait_time_match:
75
+ wait_time_str = wait_time_match.group(1)
76
+ try:
77
+ if 's' in wait_time_str:
78
+ wait_seconds = int(float(wait_time_str.replace('s','').strip()))
79
+ else:
80
+ # Convert HH:MM:SS to seconds
81
+ parts = list(map(int, wait_time_str.split(':')))
82
+ wait_seconds = sum(p * 60**i for i, p in enumerate(reversed(parts)))
83
+ except ValueError:
84
+ pass # Keep default wait_seconds
85
+
86
+ # Only sleep if it's not the last attempt
87
  if attempt < max_retries - 1:
88
+ print(f"GPU/Queue issue detected. Waiting {wait_seconds} seconds before retry {attempt + 2}/{max_retries}...")
89
+ time.sleep(wait_seconds + 2) # Add a small buffer
90
+ continue # Go to the next attempt
91
+ else:
92
+ # Return None for image, and the specific quota error on last attempt
93
+ return None, f"GPU quota exceeded or queue full. Please wait ~{wait_time_str} before trying again."
94
  else:
95
+ # For any other exception, return None for image and the general error message
96
+ print(f"An unexpected error occurred: {error_msg}") # Log the full error server-side
97
+ # Return a user-friendly error and None for the image path
98
+ return None, f"An error occurred processing the request. Details: {error_msg}"
99
+
100
+ # If all retries fail (e.g., due to persistent quota issues)
101
+ return None, "Failed to generate outfit after multiple retries due to server issues."
102
+
103
 
104
  # Create Gradio interface
105
  with gr.Blocks() as demo:
106
  gr.Markdown("""
107
  ## Outfit Diffusion - Try On Virtual Outfits
108
 
109
+ ⚠️ **Note**: This demo uses a free, shared GPU resource which has limits. Errors can occur due to high demand or temporary issues on the service.
110
+ - **Try lower settings:** Use Steps (e.g., 10-20) and Scale (e.g., 1-3) for faster processing and lower resource use.
111
+ - **Be patient:** If you get quota/queue errors, wait the suggested time before retrying.
112
+ - **Check the Space:** You can visit the [OOTDiffusion Space](https://huggingface.co/spaces/levihsu/OOTDiffusion) directly to check its status.
113
 
 
114
  """)
115
 
116
  with gr.Row():
117
+ with gr.Column(scale=1):
118
  model_image = gr.Image(
119
+ label="Model Image (Person)",
120
  type="filepath",
121
+ height=400 # Adjusted height slightly
 
122
  )
123
+ # (Keep examples)
124
+ model_examples = [...]
125
+ gr.Examples(examples=model_examples, inputs=model_image, label="Model Examples")
126
+
 
 
 
127
 
128
  garment_image = gr.Image(
129
+ label="Garment Image (Clothing)",
130
  type="filepath",
131
+ height=400 # Adjusted height slightly
132
  )
133
+ # (Keep examples)
134
+ garment_examples = [...]
135
+ gr.Examples(examples=garment_examples, inputs=garment_image, label="Garment Examples")
136
+
137
+
138
+ with gr.Column(scale=1): # Give equal space initially
139
+ output_image = gr.Image(label="Generated Output", height=400) # Match height
140
+ error_text = gr.Markdown(value="") # Display errors here, start empty
141
+
 
 
 
 
 
 
142
  with gr.Row():
143
+ # Group controls together
144
+ n_samples = gr.Slider(
145
+ label="Number of Samples", minimum=1, maximum=4, step=1, value=1 # Max 4 recommended by space
146
+ )
147
+ n_steps = gr.Slider(
148
+ label="Steps", minimum=10, maximum=40, step=1, value=20 # Adjusted default/range
149
+ )
150
+ image_scale = gr.Slider(
151
+ label="Guidance Scale", minimum=1.0, maximum=5.0, step=0.5, value=2.0 # Adjusted default/range
152
+ )
153
+ seed = gr.Number(
154
+ label="Seed (-1 for random)", value=-1, precision=0 # Ensure integer seed
155
+ )
156
+
157
+ generate_button = gr.Button("Generate Outfit", variant="primary") # Make button stand out
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  # Set up the action for the button
160
  generate_button.click(
161
  fn=generate_outfit,
162
  inputs=[model_image, garment_image, n_samples, n_steps, image_scale, seed],
163
+ outputs=[output_image, error_text] # Map outputs correctly
164
  )
165
 
166
+ # Launch the app with error visibility enabled
167
+ demo.launch(show_error=True, debug=True) # Added debug=True for potentially more local logs too