Ali Mohsin commited on
Commit
dc16471
Β·
1 Parent(s): 0c55bf3

some fixes

Browse files
Files changed (2) hide show
  1. GRADIO_API_CLIENT_GUIDE.md +355 -0
  2. app.py +28 -5
GRADIO_API_CLIENT_GUIDE.md ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gradio API Client Usage Guide
2
+
3
+ ## Problem: File Type Validation Error
4
+
5
+ When using the Gradio Client API, you may encounter:
6
+ ```
7
+ gradio.exceptions.Error: "Invalid file type. Please upload a file that is one of these formats: ['.jpg', '.jpeg', '.png', ...]"
8
+ ```
9
+
10
+ ## Solution
11
+
12
+ The file type restriction has been removed from the Gradio interface to allow API client flexibility. File validation is now handled by our internal image loading utilities.
13
+
14
+ ## Using Gradio Client API
15
+
16
+ ### Method 1: Using File Paths (Recommended)
17
+
18
+ ```python
19
+ import gradio_client as grc
20
+
21
+ # Connect to your Gradio server
22
+ client = grc.Client("http://your-server:7860")
23
+
24
+ # Prepare file paths (must be accessible from the server)
25
+ file_paths = [
26
+ "/path/to/image1.jpg",
27
+ "/path/to/image2.png",
28
+ "/path/to/image3.webp"
29
+ ]
30
+
31
+ # Call the API
32
+ result = client.predict(
33
+ files=file_paths,
34
+ occasion="casual",
35
+ weather="warm",
36
+ num_outfits=3,
37
+ outfit_style="casual",
38
+ color_preference=None,
39
+ fit_preference=None,
40
+ material_preference=None,
41
+ season=None,
42
+ time_of_day=None,
43
+ budget=None,
44
+ personal_style=None,
45
+ api_name="/gradio_recommend"
46
+ )
47
+
48
+ # Result contains:
49
+ # - result[0]: List of stitched outfit images (PIL Images)
50
+ # - result[1]: JSON dict with outfit details
51
+ images, json_data = result
52
+ ```
53
+
54
+ ### Method 2: Using Temporary Files
55
+
56
+ If you have image data in memory, save to temporary files first:
57
+
58
+ ```python
59
+ import gradio_client as grc
60
+ import tempfile
61
+ from PIL import Image
62
+ import os
63
+
64
+ # Connect to server
65
+ client = grc.Client("http://your-server:7860")
66
+
67
+ # Your image data (e.g., from requests, base64, etc.)
68
+ image_data_list = [...] # Your image bytes or PIL Images
69
+
70
+ # Save to temporary files
71
+ temp_files = []
72
+ for i, img_data in enumerate(image_data_list):
73
+ if isinstance(img_data, bytes):
74
+ # If bytes, save directly
75
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
76
+ temp_file.write(img_data)
77
+ temp_file.close()
78
+ temp_files.append(temp_file.name)
79
+ elif isinstance(img_data, Image.Image):
80
+ # If PIL Image, save to temp file
81
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
82
+ img_data.save(temp_file.name)
83
+ temp_file.close()
84
+ temp_files.append(temp_file.name)
85
+ else:
86
+ # Assume it's a file path
87
+ temp_files.append(img_data)
88
+
89
+ # Call API
90
+ result = client.predict(
91
+ files=temp_files,
92
+ occasion="formal",
93
+ weather="cool",
94
+ num_outfits=5,
95
+ outfit_style="formal",
96
+ api_name="/gradio_recommend"
97
+ )
98
+
99
+ # Clean up temp files
100
+ for temp_file in temp_files:
101
+ if os.path.exists(temp_file):
102
+ os.unlink(temp_file)
103
+ ```
104
+
105
+ ### Method 3: Using Base64 (Convert to Files)
106
+
107
+ ```python
108
+ import gradio_client as grc
109
+ import base64
110
+ import tempfile
111
+ from io import BytesIO
112
+ from PIL import Image
113
+
114
+ def base64_to_temp_file(base64_string, suffix='.jpg'):
115
+ """Convert base64 string to temporary file"""
116
+ image_data = base64.b64decode(base64_string)
117
+ img = Image.open(BytesIO(image_data))
118
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
119
+ img.save(temp_file.name)
120
+ temp_file.close()
121
+ return temp_file.name
122
+
123
+ # Your base64 image strings
124
+ base64_images = [
125
+ "iVBORw0KGgoAAAANSUhEUgAA...", # Base64 encoded image 1
126
+ "iVBORw0KGgoAAAANSUhEUgAA...", # Base64 encoded image 2
127
+ ]
128
+
129
+ # Convert to temp files
130
+ file_paths = [base64_to_temp_file(img) for img in base64_images]
131
+
132
+ # Use with Gradio client
133
+ client = grc.Client("http://your-server:7860")
134
+ result = client.predict(
135
+ files=file_paths,
136
+ occasion="casual",
137
+ weather="warm",
138
+ num_outfits=3,
139
+ api_name="/gradio_recommend"
140
+ )
141
+ ```
142
+
143
+ ## Alternative: Use FastAPI Endpoints Instead
144
+
145
+ For better API integration, consider using the FastAPI endpoints directly:
146
+
147
+ ### Option 1: `/compose/upload` (Multipart Form-Data)
148
+
149
+ ```python
150
+ import requests
151
+
152
+ url = "http://your-server:8000/compose/upload"
153
+
154
+ # Prepare files
155
+ files = [
156
+ ('files', ('image1.jpg', open('image1.jpg', 'rb'), 'image/jpeg')),
157
+ ('files', ('image2.png', open('image2.png', 'rb'), 'image/png')),
158
+ ]
159
+
160
+ # Prepare form data
161
+ data = {
162
+ 'occasion': 'casual',
163
+ 'weather': 'warm',
164
+ 'style': 'casual',
165
+ 'num_outfits': 3,
166
+ 'color_preference': None,
167
+ # ... other optional tags
168
+ }
169
+
170
+ # Make request
171
+ response = requests.post(url, files=files, data=data)
172
+ result = response.json()
173
+ ```
174
+
175
+ ### Option 2: `/compose` (JSON with Base64)
176
+
177
+ ```python
178
+ import requests
179
+ import base64
180
+
181
+ def image_to_base64(image_path):
182
+ with open(image_path, 'rb') as f:
183
+ return base64.b64encode(f.read()).decode('utf-8')
184
+
185
+ url = "http://your-server:8000/compose"
186
+
187
+ # Prepare items with base64 images
188
+ items = [
189
+ {
190
+ "id": "item_0",
191
+ "image_base64": image_to_base64("image1.jpg"),
192
+ "category": None # Auto-detected
193
+ },
194
+ {
195
+ "id": "item_1",
196
+ "image_base64": image_to_base64("image2.png"),
197
+ "category": None
198
+ }
199
+ ]
200
+
201
+ # Prepare request
202
+ payload = {
203
+ "items": items,
204
+ "occasion": "casual",
205
+ "weather": "warm",
206
+ "style": "casual",
207
+ "num_outfits": 3,
208
+ "color_preference": None,
209
+ # ... other optional tags
210
+ }
211
+
212
+ # Make request
213
+ response = requests.post(url, json=payload)
214
+ result = response.json()
215
+ ```
216
+
217
+ ## Supported Image Formats
218
+
219
+ The system supports all major image formats:
220
+ - **JPEG/JPG** (`.jpg`, `.jpeg`)
221
+ - **PNG** (`.png`)
222
+ - **WEBP** (`.webp`)
223
+ - **GIF** (`.gif`)
224
+ - **BMP** (`.bmp`)
225
+ - **TIFF** (`.tiff`, `.tif`)
226
+
227
+ Images are automatically:
228
+ - Validated for format
229
+ - Converted to RGB mode
230
+ - Handled for transparency (PNG/GIF)
231
+ - Processed for model compatibility
232
+
233
+ ## Troubleshooting
234
+
235
+ ### Error: "Could not load images"
236
+
237
+ **Possible causes:**
238
+ 1. Files don't exist at the specified paths
239
+ 2. Files are not valid image formats
240
+ 3. Files are corrupted
241
+ 4. Permission issues accessing files
242
+
243
+ **Solutions:**
244
+ 1. Verify file paths are correct and accessible
245
+ 2. Check file extensions match actual format
246
+ 3. Try opening files with PIL/Pillow to verify they're valid
247
+ 4. Ensure server has read permissions for files
248
+
249
+ ### Error: "No files uploaded"
250
+
251
+ **Possible causes:**
252
+ 1. Empty file list passed
253
+ 2. Files parameter not provided correctly
254
+
255
+ **Solutions:**
256
+ 1. Ensure at least 2 files are provided
257
+ 2. Check file paths are in a list format: `["file1.jpg", "file2.png"]`
258
+
259
+ ### Error: File type validation (if still occurring)
260
+
261
+ **Solution:**
262
+ - The file type restriction has been removed. If you still see this error:
263
+ 1. Update to the latest version of the code
264
+ 2. Restart the Gradio server
265
+ 3. Ensure you're not using an old cached version
266
+
267
+ ## Best Practices
268
+
269
+ 1. **Use FastAPI endpoints for production**: More reliable and flexible than Gradio Client API
270
+ 2. **Validate images before sending**: Check that files are valid images
271
+ 3. **Handle errors gracefully**: Check response for error messages
272
+ 4. **Use appropriate image formats**: JPG for photos, PNG for transparency, WEBP for web
273
+ 5. **Clean up temp files**: If using temporary files, delete them after use
274
+
275
+ ## Example: Complete Client Script
276
+
277
+ ```python
278
+ import gradio_client as grc
279
+ import os
280
+
281
+ def recommend_outfits(
282
+ image_paths: list,
283
+ occasion: str = "casual",
284
+ weather: str = "warm",
285
+ num_outfits: int = 3,
286
+ outfit_style: str = "casual",
287
+ **optional_tags
288
+ ):
289
+ """Complete example of using Gradio API for recommendations"""
290
+
291
+ # Validate inputs
292
+ if not image_paths or len(image_paths) < 2:
293
+ raise ValueError("At least 2 images required")
294
+
295
+ for path in image_paths:
296
+ if not os.path.exists(path):
297
+ raise FileNotFoundError(f"Image not found: {path}")
298
+
299
+ # Connect to server
300
+ client = grc.Client("http://localhost:7860")
301
+
302
+ # Prepare parameters
303
+ params = {
304
+ "files": image_paths,
305
+ "occasion": occasion,
306
+ "weather": weather,
307
+ "num_outfits": num_outfits,
308
+ "outfit_style": outfit_style,
309
+ **{k: v for k, v in optional_tags.items() if v is not None}
310
+ }
311
+
312
+ # Make request
313
+ try:
314
+ result = client.predict(api_name="/gradio_recommend", **params)
315
+ images, json_data = result
316
+
317
+ # Check for errors
318
+ if "error" in json_data:
319
+ raise RuntimeError(f"API Error: {json_data['error']}")
320
+
321
+ return images, json_data["outfits"]
322
+
323
+ except Exception as e:
324
+ raise RuntimeError(f"Failed to get recommendations: {str(e)}")
325
+
326
+ # Usage
327
+ if __name__ == "__main__":
328
+ images, outfits = recommend_outfits(
329
+ image_paths=["shirt.jpg", "pants.jpg", "shoes.jpg"],
330
+ occasion="formal",
331
+ weather="cool",
332
+ num_outfits=5,
333
+ outfit_style="formal",
334
+ color_preference="neutral",
335
+ fit_preference="tailored"
336
+ )
337
+
338
+ print(f"Generated {len(outfits)} outfits")
339
+ for i, outfit in enumerate(outfits):
340
+ print(f"Outfit {i+1}: {outfit['item_ids']}")
341
+ ```
342
+
343
+ ## API Endpoints Summary
344
+
345
+ | Endpoint | Method | Use Case |
346
+ |----------|--------|----------|
347
+ | `/compose` | POST | JSON API with base64 images |
348
+ | `/compose/upload` | POST | Multipart form-data with files |
349
+ | `/tags` | GET | Get all available tag options |
350
+ | `/image-formats` | GET | Get supported image formats |
351
+ | `/health` | GET | Check model status |
352
+ | Gradio `/gradio_recommend` | POST | Gradio Client API (file paths) |
353
+
354
+ For production use, prefer FastAPI endpoints (`/compose` or `/compose/upload`) over Gradio Client API for better reliability and error handling.
355
+
app.py CHANGED
@@ -822,9 +822,30 @@ def gradio_recommend(
822
  # Return stitched outfit images and a JSON with details
823
  if not files:
824
  return [], {"error": "No files uploaded"}
825
- images = _load_images_from_files(files)
826
- if not images:
827
- return [], {"error": "Could not load images"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828
 
829
  # Build comprehensive context with all tags
830
  context = {
@@ -1213,8 +1234,9 @@ with gr.Blocks(fill_height=True, title="Dressify - Advanced Outfit Recommendatio
1213
 
1214
  inp2 = gr.Files(
1215
  label="Upload wardrobe images",
1216
- file_types=[".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff", ".tif"],
1217
  file_count="multiple"
 
 
1218
  )
1219
 
1220
  with gr.Accordion("🎯 Primary Tags (Required)", open=True):
@@ -1601,8 +1623,9 @@ with gr.Blocks(fill_height=True, title="Dressify - Advanced Outfit Recommendatio
1601
  with gr.Tab("πŸ“Š Embed (Debug)"):
1602
  inp = gr.Files(
1603
  label="Upload Items (multiple images)",
1604
- file_types=[".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff", ".tif"],
1605
  file_count="multiple"
 
 
1606
  )
1607
  out = gr.Textbox(label="Embeddings (JSON)")
1608
  btn = gr.Button("Compute Embeddings")
 
822
  # Return stitched outfit images and a JSON with details
823
  if not files:
824
  return [], {"error": "No files uploaded"}
825
+
826
+ # Debug: Log file information for API troubleshooting
827
+ file_info = []
828
+ for f in files:
829
+ if isinstance(f, str):
830
+ file_info.append(f"Path: {f}")
831
+ else:
832
+ file_info.append(f"Type: {type(f).__name__}, Value: {str(f)[:100]}")
833
+
834
+ try:
835
+ images = _load_images_from_files(files)
836
+ if not images:
837
+ error_msg = "Could not load images from uploaded files.\n\n"
838
+ error_msg += f"Files received: {len(files)}\n"
839
+ error_msg += f"File details: {', '.join(file_info[:3])}\n\n"
840
+ error_msg += f"Supported formats: {', '.join(get_supported_extensions())}\n"
841
+ error_msg += "Please ensure files are valid image files (JPG, PNG, WEBP, GIF, BMP, TIFF, etc.)"
842
+ return [], {"error": error_msg, "files_received": len(files), "file_info": file_info[:5]}
843
+ except Exception as e:
844
+ error_msg = f"Error processing files: {str(e)}\n\n"
845
+ error_msg += f"Files received: {len(files)}\n"
846
+ error_msg += f"File details: {', '.join(file_info[:3])}\n\n"
847
+ error_msg += "Please check that files are valid image files."
848
+ return [], {"error": error_msg, "exception": str(e), "files_received": len(files)}
849
 
850
  # Build comprehensive context with all tags
851
  context = {
 
1234
 
1235
  inp2 = gr.Files(
1236
  label="Upload wardrobe images",
 
1237
  file_count="multiple"
1238
+ # Note: file_types removed to allow API client flexibility
1239
+ # Validation is handled by our image_utils.load_images_from_files()
1240
  )
1241
 
1242
  with gr.Accordion("🎯 Primary Tags (Required)", open=True):
 
1623
  with gr.Tab("πŸ“Š Embed (Debug)"):
1624
  inp = gr.Files(
1625
  label="Upload Items (multiple images)",
 
1626
  file_count="multiple"
1627
+ # Note: file_types removed to allow API client flexibility
1628
+ # Validation is handled by our image_utils.load_images_from_files()
1629
  )
1630
  out = gr.Textbox(label="Embeddings (JSON)")
1631
  btn = gr.Button("Compute Embeddings")