AnshSrivastava003 commited on
Commit
811a06a
·
verified ·
1 Parent(s): 3096eb6

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +278 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import os
3
+ import gradio as gr
4
+ from google import genai
5
+ from google.genai import types
6
+ from google.genai.types import HarmBlockThreshold
7
+ from PIL import Image
8
+ from io import BytesIO
9
+ import tempfile
10
+ import warnings
11
+ import io
12
+
13
+ # Load environment variables from .env file
14
+
15
+ def swap_clothing(person_image, clothing_image):
16
+ """
17
+ Generate an image where the person from the first image is wearing clothing from the second image.
18
+
19
+ Args:
20
+ person_image: The image containing the person
21
+ clothing_image: The image containing the clothing to swap
22
+
23
+ Returns:
24
+ The generated image with the clothing swapped and any relevant messages
25
+ """
26
+ # Capture warnings in a string buffer
27
+ warning_buffer = io.StringIO()
28
+ warnings.filterwarnings('always') # Ensure all warnings are shown
29
+
30
+ # Initialize variables outside the try block
31
+ temp_files = []
32
+ uploaded_files = []
33
+ client = None
34
+ output_image = None
35
+ output_text = ""
36
+
37
+ with warnings.catch_warnings(record=True) as warning_list:
38
+ try:
39
+ # Check if both images are provided
40
+ if person_image is None or clothing_image is None:
41
+ return None, "Please upload both images."
42
+
43
+ # Get API key from environment variables
44
+ api_key = "AIzaSyCIrNCyWF0AO0EYVd7bJ37lBjPozQOrUjE"
45
+ if not api_key:
46
+ return None, "GEMINI_API_KEY not found in environment variables."
47
+
48
+ # Create a fresh client instance for each request
49
+ client = genai.Client(api_key=api_key)
50
+
51
+ # Save both uploaded images to temporary files
52
+ for img, prefix in [(person_image, "person"), (clothing_image, "clothing")]:
53
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_file:
54
+ img.save(temp_file.name)
55
+ temp_files.append(temp_file.name)
56
+
57
+ # Upload both files to Gemini with fresh file uploads
58
+ uploaded_files = [
59
+ client.files.upload(file=temp_files[0]), # person image
60
+ client.files.upload(file=temp_files[1]), # clothing image
61
+ ]
62
+
63
+ # Create the prompt
64
+ prompt = """
65
+ Perform a precise clothing swap between two images while maintaining strict fidelity to original elements:
66
+
67
+ 1. PERSON IMAGE (SOURCE TO KEEP):
68
+ - Retain EXACT pose, body proportions, and background
69
+ - Preserve 100% of facial features, hair, and skin details
70
+ - Maintain original lighting conditions and environment shadows
71
+
72
+ 2. CLOTHING IMAGE (TARGET TO TRANSFER):
73
+ - Extract clothing item with complete pattern/texture details
74
+ - Match garment cut/style exactly while maintaining fabric texture
75
+ - Preserve original color palette and material appearance
76
+
77
+ 3. OUTPUT REQUIREMENTS:
78
+ - Seamlessly overlay clothing from [Clothing Image] onto [Person Image]
79
+ - Perfectly align garment with body posture/muscle contours
80
+ - Maintain original image resolution and sharpness
81
+ - No alterations to facial features/body shape/background elements
82
+ - Ensure natural fold/wrinkle physics matching original pose
83
+ - Keep accessories/body jewelry unchanged unless covered by new clothing
84
+
85
+ 4. SPECIAL INSTRUCTIONS:
86
+ - Priority 1: Clothing accuracy from target image
87
+ - Priority 2: Person/image integrity from source photo
88
+ - Priority 3: Seamless visual integration
89
+ - Reject any style transfer that requires pose/background modification
90
+ """
91
+
92
+ contents = [
93
+ types.Content(
94
+ role="user",
95
+ parts=[
96
+ types.Part.from_text(text="This is the person image. Do not change the face or features of the person. Pay attention and retain the face, environment, background, pose, facial features."),
97
+ types.Part.from_uri(
98
+ file_uri=uploaded_files[0].uri,
99
+ mime_type=uploaded_files[0].mime_type,
100
+ ),
101
+ types.Part.from_text(text="This is the clothing image. Swap the clothing onto the person image."),
102
+ types.Part.from_uri(
103
+ file_uri=uploaded_files[1].uri,
104
+ mime_type=uploaded_files[1].mime_type,
105
+ ),
106
+ types.Part.from_text(text=prompt),
107
+ types.Part.from_uri(
108
+ file_uri=uploaded_files[0].uri,
109
+ mime_type=uploaded_files[0].mime_type,
110
+ ),
111
+ ],
112
+ ),
113
+ ]
114
+
115
+ generate_content_config = types.GenerateContentConfig(
116
+ temperature=0.099,
117
+ top_p=0.95,
118
+ top_k=40,
119
+ max_output_tokens=8192,
120
+ response_modalities=[
121
+ "image",
122
+ "text",
123
+ ],
124
+ safety_settings=[
125
+ types.SafetySetting(
126
+ category="HARM_CATEGORY_HARASSMENT",
127
+ threshold=HarmBlockThreshold.BLOCK_NONE,
128
+ ),
129
+ types.SafetySetting(
130
+ category="HARM_CATEGORY_HATE_SPEECH",
131
+ threshold=HarmBlockThreshold.BLOCK_NONE,
132
+ ),
133
+ types.SafetySetting(
134
+ category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
135
+ threshold=HarmBlockThreshold.BLOCK_NONE,
136
+ ),
137
+ types.SafetySetting(
138
+ category="HARM_CATEGORY_DANGEROUS_CONTENT",
139
+ threshold=HarmBlockThreshold.BLOCK_NONE,
140
+ ),
141
+ ],
142
+ response_mime_type="text/plain",
143
+ )
144
+
145
+ response = client.models.generate_content(
146
+ model="models/gemini-2.0-flash-exp",
147
+ contents=contents,
148
+ config=generate_content_config,
149
+ )
150
+
151
+ # Add any warnings to the output text
152
+ if warning_list:
153
+ output_text += "\nWarnings:\n"
154
+ for warning in warning_list:
155
+ output_text += f"- {warning.message}\n"
156
+
157
+ # Process the response
158
+ if response and hasattr(response, 'candidates') and response.candidates:
159
+ candidate = response.candidates[0]
160
+ if hasattr(candidate, 'content') and candidate.content:
161
+ for part in candidate.content.parts:
162
+ if part.text is not None:
163
+ output_text += part.text + "\n"
164
+ elif part.inline_data is not None:
165
+ try:
166
+ if isinstance(part.inline_data.data, bytes):
167
+ image_data = part.inline_data.data
168
+ else:
169
+ image_data = base64.b64decode(part.inline_data.data)
170
+
171
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
172
+ temp_file.write(image_data)
173
+ temp_file_path = temp_file.name
174
+
175
+ output_image = Image.open(temp_file_path)
176
+ os.unlink(temp_file_path)
177
+
178
+ except Exception as img_error:
179
+ output_text += f"Error processing image: {str(img_error)}\n"
180
+ else:
181
+ output_text = "The model did not generate a valid response. Please try again with different images."
182
+
183
+ except Exception as e:
184
+ error_details = f"Error: {str(e)}\n\nType: {type(e).__name__}"
185
+ if warning_list:
186
+ error_details += "\n\nWarnings:\n"
187
+ for warning in warning_list:
188
+ error_details += f"- {warning.message}\n"
189
+ print(f"Exception occurred: {error_details}")
190
+ return None
191
+
192
+ finally:
193
+ # Clean up all temporary files
194
+ for temp_file in temp_files:
195
+ if os.path.exists(temp_file):
196
+ os.unlink(temp_file)
197
+
198
+ # Clean up any uploaded files if possible
199
+ for uploaded_file in uploaded_files:
200
+ try:
201
+ if hasattr(client.files, 'delete') and uploaded_file:
202
+ client.files.delete(uploaded_file.uri)
203
+ except:
204
+ pass # Best effort cleanup
205
+
206
+ # Clear the client
207
+ client = None
208
+
209
+ return output_image
210
+
211
+ # Create the Gradio interface
212
+ def create_interface():
213
+
214
+ custom_css = """
215
+ @font-face {
216
+ font-family: "XKCD";
217
+ src: url("https://raw.githubusercontent.com/ipython/xkcd-font/refs/heads/master/xkcd-script/font/xkcd-script.ttf") format("opentype");
218
+ }
219
+
220
+ .gradio-container {
221
+ font-family: "XKCD", "Courier New", monospace;
222
+ }
223
+ """
224
+
225
+ with gr.Blocks(css = custom_css,title="Virtual Clothing Try-On", theme ='gstaff/xkcd') as app:
226
+ gr.Markdown("# Virtual Clothing Try-On 👕 🩳 🧢")
227
+ gr.Markdown("Upload a photo of yourself and a photo of clothing you'd like to try on!")
228
+
229
+ with gr.Row():
230
+ with gr.Column():
231
+ person_image = gr.Image(label="Your Photo", type="pil", image_mode="RGB", height=300)
232
+ person_examples = [
233
+ "https://i.postimg.cc/MGxQDGQP/440050401-46f62432-634e-49e6-b841-25d43945e4ed.png",
234
+ "https://i.postimg.cc/fyHC49xR/440050411-c3bc6a7c-496f-493f-aad7-2e434e32fb86.png",
235
+ "https://i.postimg.cc/cJNQbmVc/440050418-46dbca08-003b-4a14-8fcf-5a61b4c91e12.png",
236
+ "https://i.postimg.cc/SskfJrdK/440050443-2abac8ca-f5b9-4ba9-9437-36e5ccf027d5.png",
237
+ "https://i.postimg.cc/LXDBf1Q3/440050446-fc8c2be6-f33a-4ebb-a6a2-0a1d514a219c.png",
238
+ "https://i.postimg.cc/kXBF6DQW/440050457-318b1e52-46af-4b29-9b21-6281a6687302.png",
239
+ "https://i.postimg.cc/3xGX16bR/440050469-a5113e2c-a644-4484-a4de-2b6914796deb.png",
240
+ "https://i.postimg.cc/m25j87Ld/440050479-2bfaa190-8211-4e2f-a9f0-8b1263d22e3a.jpg"
241
+ ]
242
+
243
+
244
+
245
+ gr.Examples(examples=person_examples, inputs=person_image, label="Person Image Examples")
246
+
247
+ with gr.Column():
248
+ clothing_image = gr.Image(label="Clothing Photo", type="pil", image_mode="RGB", height=300)
249
+ clothing_examples = [
250
+ "https://i.postimg.cc/2SM7QWd4/0012.jpg",
251
+ "https://i.postimg.cc/TPbqCPQB/07-upper.png",
252
+ "https://i.postimg.cc/Znb8bxZh/440052371-e34d38d2-88cd-4ee9-a07d-57f544fcbab1.png",
253
+ "https://i.postimg.cc/c41h0048/440052384-aa986119-61ee-406e-a246-29ac83f323e6.png",
254
+ "https://i.postimg.cc/qq18z6M6/440052392-d63adf74-abe2-4f57-a3b7-5ce464824e54.jpg",
255
+ "https://i.postimg.cc/1tZ0TZjX/garment-1.png",
256
+ "https://i.postimg.cc/hjb8R3kr/garment-2.jpg",
257
+ "https://i.postimg.cc/SxJGYd9S/garment-3.jpg"
258
+ ]
259
+
260
+
261
+ gr.Examples(examples=clothing_examples, inputs=clothing_image, label="Garment Image Examples")
262
+
263
+
264
+ with gr.Column():
265
+ output_image = gr.Image(label="Result", type="pil")
266
+ submit_btn = gr.Button("Generate")
267
+
268
+ submit_btn.click(
269
+ fn=swap_clothing,
270
+ inputs=[person_image, clothing_image],
271
+ outputs=output_image
272
+ )
273
+
274
+ return app
275
+
276
+ if __name__ == "__main__":
277
+ app = create_interface()
278
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ google
2
+ google-genai
3
+ google-generativeai
4
+ gradio
5
+ python-dotenv
6
+ pillow