ginipick commited on
Commit
14af22f
·
verified ·
1 Parent(s): d3fd436

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -122
app.py CHANGED
@@ -5,8 +5,7 @@ from PIL import Image
5
  import requests
6
  from io import BytesIO
7
 
8
- # Replicate API client setup
9
- # Set environment variable: export RAPI_TOKEN="your_token_here"
10
  replicate_client = replicate.Client(api_token=os.getenv("RAPI_TOKEN"))
11
 
12
  # Comprehensive hairstyle options - All 93 styles
@@ -65,9 +64,67 @@ HAIR_COLOR_OPTIONS = {
65
  "Rose Gold": "#E0BFB8"
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  def change_haircut(input_image, haircut_style, hair_color):
69
  """
70
- Process image through RAPI to change hairstyle
71
  """
72
  try:
73
  # Check if image is provided
@@ -78,6 +135,8 @@ def change_haircut(input_image, haircut_style, hair_color):
78
  if not hair_color or hair_color not in HAIR_COLOR_OPTIONS:
79
  hair_color = "Black"
80
 
 
 
81
  # Save PIL Image to temporary file
82
  temp_path = "temp_input.png"
83
  input_image.save(temp_path)
@@ -116,13 +175,13 @@ def change_haircut(input_image, haircut_style, hair_color):
116
  os.remove(temp_path)
117
  return None, f"Error: {str(e)}"
118
 
119
- def update_color_display(color):
120
- """Update the color display text"""
121
- return f"**Selected Color:** {color}"
122
-
123
  # Create Gradio interface
124
  with gr.Blocks(title="AI Hairstyle Changer", theme=gr.themes.Soft()) as demo:
125
-
 
 
 
 
126
 
127
  with gr.Row():
128
  with gr.Column(scale=1):
@@ -137,22 +196,17 @@ with gr.Blocks(title="AI Hairstyle Changer", theme=gr.themes.Soft()) as demo:
137
  gr.Markdown("### Select Hair Color")
138
  selected_color_display = gr.Markdown(value="**Selected Color:** Black")
139
 
140
- # Create color buttons in a grid
141
- color_buttons = []
142
- with gr.Column():
143
- # Create rows of color buttons
144
- for i in range(0, len(HAIR_COLOR_OPTIONS), 5):
145
- with gr.Row():
146
- for color_name, color_code in list(HAIR_COLOR_OPTIONS.items())[i:i+5]:
147
- btn = gr.Button(
148
- value=color_name,
149
- elem_classes="color-button",
150
- elem_id=f"color-{color_name.replace(' ', '-')}"
151
- )
152
- color_buttons.append((btn, color_name, color_code))
153
 
154
- # Hidden textbox to store selected color
155
- selected_color = gr.Textbox(value="Black", visible=False)
 
156
 
157
  submit_btn = gr.Button(
158
  "🎨 Apply Hairstyle",
@@ -163,15 +217,14 @@ with gr.Blocks(title="AI Hairstyle Changer", theme=gr.themes.Soft()) as demo:
163
  with gr.Column(scale=2):
164
  # Hairstyle selection with scrollable radio buttons
165
  with gr.Group():
166
- gr.Markdown(f"### Select Hairstyle (Total: {len(HAIRCUT_OPTIONS)} styles)")
167
- with gr.Column(elem_classes="hairstyle-container"):
168
- haircut_radio = gr.Radio(
169
- choices=HAIRCUT_OPTIONS,
170
- value="Bob",
171
- label="Hairstyle Options",
172
- info="Browse and select from 93 hairstyle options",
173
- elem_classes="hairstyle-radio"
174
- )
175
 
176
  with gr.Column(scale=1):
177
  # Output section
@@ -187,110 +240,54 @@ with gr.Blocks(title="AI Hairstyle Changer", theme=gr.themes.Soft()) as demo:
187
  value="Upload a photo and select a hairstyle to begin."
188
  )
189
 
190
- # Custom CSS with dynamic color styling
191
- custom_css = """
192
- .hairstyle-container {
193
- max-height: 600px;
194
- overflow-y: auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  padding: 10px;
196
  border: 1px solid #e0e0e0;
197
  border-radius: 8px;
198
  background-color: #f9f9f9;
199
  }
200
 
201
- .hairstyle-radio label {
202
- display: block;
203
- padding: 8px 12px;
204
- margin: 4px 0;
205
- border-radius: 6px;
206
- cursor: pointer;
207
- transition: all 0.2s ease;
 
208
  }
209
 
210
- .hairstyle-radio label:hover {
211
- background-color: #e8e8e8;
212
  }
213
 
214
- .color-button {
215
- min-height: 50px !important;
216
- margin: 2px !important;
217
- border: 3px solid transparent !important;
218
- border-radius: 8px !important;
219
- font-weight: bold !important;
220
  color: white !important;
221
- text-shadow: 1px 1px 2px rgba(0,0,0,0.7) !important;
222
- transition: all 0.3s ease !important;
223
- position: relative !important;
224
- }
225
-
226
- .color-button:hover {
227
- transform: translateY(-2px) !important;
228
- box-shadow: 0 4px 10px rgba(0,0,0,0.3) !important;
229
  }
230
-
231
- .color-button.selected {
232
- border-color: #2196F3 !important;
233
- transform: scale(1.05) !important;
234
- box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.3) !important;
235
- }
236
- """
237
-
238
- # Add dynamic CSS for each color button
239
- for color_name, color_code in HAIR_COLOR_OPTIONS.items():
240
- custom_css += f"""
241
- #color-{color_name.replace(' ', '-')} > button {{
242
- background-color: {color_code} !important;
243
- }}
244
  """
245
 
246
- demo.css = custom_css
247
-
248
- # Connect color button clicks
249
- for btn, color_name, color_code in color_buttons:
250
- btn.click(
251
- fn=lambda c=color_name: (c, update_color_display(c)),
252
- outputs=[selected_color, selected_color_display],
253
- js=f"""(x) => {{
254
- // Remove selected class from all buttons
255
- document.querySelectorAll('.color-button').forEach(b => b.classList.remove('selected'));
256
- // Add selected class to clicked button
257
- document.querySelector('#color-{color_name.replace(' ', '-')} > button').classList.add('selected');
258
- return '{color_name}';
259
- }}"""
260
- )
261
-
262
- # Button click event
263
- submit_btn.click(
264
- fn=change_haircut,
265
- inputs=[input_image, haircut_radio, selected_color],
266
- outputs=[output_image, status_text]
267
- )
268
-
269
- # Set initial selection
270
- demo.load(
271
- js="""() => {
272
- document.querySelector('#color-Black > button').classList.add('selected');
273
- }"""
274
- )
275
-
276
- # Additional information
277
- gr.Markdown(
278
- """
279
- ### 📚 Hairstyle Categories
280
- - **Short Styles**: Pixie Cut, Crew Cut, Undercut, Mohawk
281
- - **Medium Styles**: Bob, Lob, Shag, Layered
282
- - **Long Styles**: Straight, Wavy, Curly
283
- - **Braided Styles**: French Braid, Dutch Braid, Fishtail Braid, Box Braids
284
- - **Updo Styles**: Chignon, French Twist, Messy Bun, Top Knot
285
- - **Special Styles**: Space Buns, Dreadlocks, Cornrows, Beehive
286
-
287
- ### 🎨 Hair Color Categories
288
- - **Natural Colors**: Black, Browns, Blonde variations
289
- - **Red Tones**: Red, Auburn, Copper, Mahogany, Burgundy
290
- - **Cool Tones**: Silver, Ash Blonde, Ash Brown, Titanium
291
- - **Fashion Colors**: Blue, Purple, Pink, Green, Rose Gold
292
- """
293
- )
294
 
295
  # Run the app
296
  if __name__ == "__main__":
@@ -299,6 +296,10 @@ if __name__ == "__main__":
299
  print("⚠️ Warning: RAPI_TOKEN environment variable not set!")
300
  print("Set it using: export RAPI_TOKEN='your_token'")
301
 
 
 
 
 
302
  demo.launch(
303
  share=True, # Create shareable link
304
  debug=True # Debug mode
 
5
  import requests
6
  from io import BytesIO
7
 
8
+
 
9
  replicate_client = replicate.Client(api_token=os.getenv("RAPI_TOKEN"))
10
 
11
  # Comprehensive hairstyle options - All 93 styles
 
64
  "Rose Gold": "#E0BFB8"
65
  }
66
 
67
+ def create_color_palette_html():
68
+ """Create HTML for visual color palette"""
69
+ html = '''
70
+ <style>
71
+ .color-grid {
72
+ display: grid;
73
+ grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
74
+ gap: 8px;
75
+ padding: 10px;
76
+ max-height: 300px;
77
+ overflow-y: auto;
78
+ border: 1px solid #e0e0e0;
79
+ border-radius: 8px;
80
+ background-color: #f9f9f9;
81
+ }
82
+ .color-cell {
83
+ aspect-ratio: 1;
84
+ border-radius: 8px;
85
+ cursor: pointer;
86
+ transition: all 0.3s ease;
87
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
88
+ display: flex;
89
+ align-items: flex-end;
90
+ justify-content: center;
91
+ overflow: hidden;
92
+ border: 3px solid transparent;
93
+ }
94
+ .color-cell:hover {
95
+ transform: translateY(-2px);
96
+ box-shadow: 0 4px 10px rgba(0,0,0,0.3);
97
+ }
98
+ .color-label {
99
+ width: 100%;
100
+ background-color: rgba(0,0,0,0.7);
101
+ color: white;
102
+ font-size: 9px;
103
+ padding: 2px;
104
+ text-align: center;
105
+ font-weight: bold;
106
+ }
107
+ </style>
108
+ <div class="color-grid">
109
+ '''
110
+
111
+ for color_name, color_code in HAIR_COLOR_OPTIONS.items():
112
+ html += f'''
113
+ <div class="color-cell" style="background-color: {color_code};" title="{color_name}">
114
+ <span class="color-label">{color_name}</span>
115
+ </div>
116
+ '''
117
+
118
+ html += '</div>'
119
+ return html
120
+
121
+ def update_selected_color(color_name):
122
+ """Update the selected color display"""
123
+ return f"**Selected Color:** {color_name}", color_name
124
+
125
  def change_haircut(input_image, haircut_style, hair_color):
126
  """
127
+ Process image through API to change hairstyle
128
  """
129
  try:
130
  # Check if image is provided
 
135
  if not hair_color or hair_color not in HAIR_COLOR_OPTIONS:
136
  hair_color = "Black"
137
 
138
+ print(f"Processing with hairstyle: {haircut_style}, color: {hair_color}")
139
+
140
  # Save PIL Image to temporary file
141
  temp_path = "temp_input.png"
142
  input_image.save(temp_path)
 
175
  os.remove(temp_path)
176
  return None, f"Error: {str(e)}"
177
 
 
 
 
 
178
  # Create Gradio interface
179
  with gr.Blocks(title="AI Hairstyle Changer", theme=gr.themes.Soft()) as demo:
180
+ gr.Markdown(
181
+ """
182
+ # 🎨 AI Hairstyle Changer
183
+ """
184
+ )
185
 
186
  with gr.Row():
187
  with gr.Column(scale=1):
 
196
  gr.Markdown("### Select Hair Color")
197
  selected_color_display = gr.Markdown(value="**Selected Color:** Black")
198
 
199
+ # Dropdown for color selection (functional)
200
+ hair_color_dropdown = gr.Dropdown(
201
+ choices=list(HAIR_COLOR_OPTIONS.keys()),
202
+ value="Black",
203
+ label="Choose Hair Color",
204
+ info="Select from dropdown for color"
205
+ )
 
 
 
 
 
 
206
 
207
+ # Visual color palette (for reference)
208
+ gr.Markdown("**Color Palette Reference:**")
209
+ color_palette_display = gr.HTML(create_color_palette_html())
210
 
211
  submit_btn = gr.Button(
212
  "🎨 Apply Hairstyle",
 
217
  with gr.Column(scale=2):
218
  # Hairstyle selection with scrollable radio buttons
219
  with gr.Group():
220
+ gr.Markdown(f"### Select Hairstyle ({len(HAIRCUT_OPTIONS)} total styles)")
221
+ gr.Markdown("*Scroll down to see all 93 hairstyle options*")
222
+ haircut_radio = gr.Radio(
223
+ choices=HAIRCUT_OPTIONS,
224
+ value="Bob",
225
+ label="Hairstyle Options",
226
+ info="Scroll to browse all 93 hairstyle options"
227
+ )
 
228
 
229
  with gr.Column(scale=1):
230
  # Output section
 
240
  value="Upload a photo and select a hairstyle to begin."
241
  )
242
 
243
+ # Update color display when dropdown changes
244
+ hair_color_dropdown.change(
245
+ fn=update_selected_color,
246
+ inputs=[hair_color_dropdown],
247
+ outputs=[selected_color_display, gr.State()]
248
+ )
249
+
250
+ # Button click event
251
+ submit_btn.click(
252
+ fn=change_haircut,
253
+ inputs=[input_image, haircut_radio, hair_color_dropdown],
254
+ outputs=[output_image, status_text]
255
+ )
256
+
257
+ # Style customization
258
+ demo.css = """
259
+ /* Radio button container */
260
+ #component-8 > div.wrap > div {
261
+ max-height: 600px !important;
262
+ overflow-y: auto !important;
263
  padding: 10px;
264
  border: 1px solid #e0e0e0;
265
  border-radius: 8px;
266
  background-color: #f9f9f9;
267
  }
268
 
269
+ /* Style radio button options */
270
+ label.svelte-1gfkn6j {
271
+ display: block !important;
272
+ padding: 8px 12px !important;
273
+ margin: 4px 0 !important;
274
+ border-radius: 6px !important;
275
+ cursor: pointer !important;
276
+ transition: all 0.2s ease !important;
277
  }
278
 
279
+ label.svelte-1gfkn6j:hover {
280
+ background-color: #e8e8e8 !important;
281
  }
282
 
283
+ /* Selected radio option */
284
+ label.svelte-1gfkn6j.selected {
285
+ background-color: #2196F3 !important;
 
 
 
286
  color: white !important;
 
 
 
 
 
 
 
 
287
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  """
289
 
290
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
 
292
  # Run the app
293
  if __name__ == "__main__":
 
296
  print("⚠️ Warning: RAPI_TOKEN environment variable not set!")
297
  print("Set it using: export RAPI_TOKEN='your_token'")
298
 
299
+ # Verify all styles are loaded
300
+ print(f"✅ Loaded {len(HAIRCUT_OPTIONS)} hairstyle options")
301
+ print(f"✅ Loaded {len(HAIR_COLOR_OPTIONS)} hair color options")
302
+
303
  demo.launch(
304
  share=True, # Create shareable link
305
  debug=True # Debug mode