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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -295
app.py CHANGED
@@ -1,306 +1,35 @@
1
- import gradio as gr
2
- import replicate
3
  import os
4
- from PIL import Image
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
12
- HAIRCUT_OPTIONS = [
13
- "Crew Cut", "Faux Hawk", "Slicked Back", "Side-Parted", "Center-Parted",
14
- "Blunt Bangs", "Side-Swept Bangs", "Shag", "Lob", "Angled Bob",
15
- "A-Line Bob", "Asymmetrical Bob", "Graduated Bob", "Inverted Bob", "Layered Shag",
16
- "Choppy Layers", "Razor Cut", "Perm", "Ombré", "Straightened",
17
- "Soft Waves", "Glamorous Waves", "Hollywood Waves", "Finger Waves", "Tousled",
18
- "Feathered", "Pageboy", "Pigtails", "Pin Curls", "Rollerset",
19
- "Twist Out", "Bantu Knots", "Dreadlocks", "Cornrows", "Box Braids",
20
- "Crochet Braids", "Double Dutch Braids", "French Fishtail Braid", "Waterfall Braid", "Rope Braid",
21
- "Heart Braid", "Halo Braid", "Crown Braid", "Braided Crown", "Bubble Braid",
22
- "Bubble Ponytail", "Ballerina Braids", "Milkmaid Braids", "Bohemian Braids", "Flat Twist",
23
- "Crown Twist", "Twisted Bun", "Twisted Half-Updo", "Twist and Pin Updo", "Chignon",
24
- "Simple Chignon", "Messy Chignon", "French Twist", "French Twist Updo", "French Roll",
25
- "Updo", "Messy Updo", "Knotted Updo", "Ballerina Bun", "Banana Clip Updo",
26
- "Beehive", "Bouffant", "Hair Bow", "Half-Up Top Knot", "Half-Up, Half-Down",
27
- "Messy Bun with a Headband", "Messy Bun with a Scarf", "Messy Fishtail Braid", "Sideswept Pixie", "Mohawk Fade",
28
- "Straight", "Wavy", "Curly", "Bob", "Pixie Cut",
29
- "Layered", "Messy Bun", "High Ponytail", "Low Ponytail", "Braided Ponytail",
30
- "French Braid", "Dutch Braid", "Fishtail Braid", "Space Buns", "Top Knot",
31
- "Undercut", "Mohawk"
32
- ]
33
-
34
- # Hair color options with color codes
35
- HAIR_COLOR_OPTIONS = {
36
- "Blonde": "#F4E4C1",
37
- "Brunette": "#6F4E37",
38
- "Black": "#1C1C1C",
39
- "Dark Brown": "#3B2F2F",
40
- "Medium Brown": "#8B4513",
41
- "Light Brown": "#A0826D",
42
- "Auburn": "#A52A2A",
43
- "Copper": "#B87333",
44
- "Red": "#DC143C",
45
- "Strawberry Blonde": "#FFB6C1",
46
- "Platinum Blonde": "#FAFAD2",
47
- "Silver": "#C0C0C0",
48
- "White": "#FFFFFF",
49
- "Blue": "#4169E1",
50
- "Purple": "#9370DB",
51
- "Pink": "#FF69B4",
52
- "Green": "#228B22",
53
- "Blue-Black": "#1C1C3D",
54
- "Golden Blonde": "#FFD700",
55
- "Honey Blonde": "#F0E68C",
56
- "Caramel": "#C68E17",
57
- "Chestnut": "#954535",
58
- "Mahogany": "#C04000",
59
- "Burgundy": "#800020",
60
- "Jet Black": "#0A0A0A",
61
- "Ash Brown": "#8B7355",
62
- "Ash Blonde": "#D3D3D3",
63
- "Titanium": "#878787",
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
131
- if input_image is None:
132
- return None, "Please upload an image first."
133
 
134
- # Ensure we have a valid color
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)
143
 
144
- # Call Replicate API
145
- output = replicate_client.run(
146
- "flux-kontext-apps/change-haircut",
147
- input={
148
- "haircut": haircut_style,
149
- "hair_color": hair_color,
150
- "input_image": open(temp_path, "rb")
151
- }
152
- )
153
-
154
- # Process results
155
- if output:
156
- # If output is URL
157
- if isinstance(output, str):
158
- response = requests.get(output)
159
- result_image = Image.open(BytesIO(response.content))
160
- # If output is file object
161
- else:
162
- result_image = Image.open(BytesIO(output.read()))
163
-
164
- # Clean up temporary file
165
- if os.path.exists(temp_path):
166
- os.remove(temp_path)
167
-
168
- return result_image, f"Successfully applied {haircut_style} style with {hair_color} color!"
169
- else:
170
- return None, "Processing error occurred."
171
 
172
  except Exception as e:
173
- # Clean up temporary file on error
174
- if os.path.exists(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):
188
- # Input section
189
- input_image = gr.Image(
190
- label="Upload Your Photo",
191
- type="pil",
192
- height=400
193
- )
194
-
195
- with gr.Group():
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",
213
- variant="primary",
214
- size="lg"
215
- )
216
-
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
231
- output_image = gr.Image(
232
- label="Result",
233
- type="pil",
234
- height=400
235
- )
236
-
237
- status_text = gr.Textbox(
238
- label="Status",
239
- interactive=False,
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__":
294
- # Check API key
295
- if not os.getenv("RAPI_TOKEN"):
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
306
- )
 
 
 
1
  import os
2
+ import sys
3
+ import streamlit as st
4
+ from tempfile import NamedTemporaryFile
5
 
6
+ def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  try:
8
+ # Get the code from secrets
9
+ code = os.environ.get("MAIN_CODE")
 
10
 
11
+ if not code:
12
+ st.error("⚠️ The application code wasn't found in secrets. Please add the MAIN_CODE secret.")
13
+ return
14
 
15
+ # Create a temporary Python file
16
+ with NamedTemporaryFile(suffix='.py', delete=False, mode='w') as tmp:
17
+ tmp.write(code)
18
+ tmp_path = tmp.name
19
 
20
+ # Execute the code
21
+ exec(compile(code, tmp_path, 'exec'), globals())
 
22
 
23
+ # Clean up the temporary file
24
+ try:
25
+ os.unlink(tmp_path)
26
+ except:
27
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  except Exception as e:
30
+ st.error(f"⚠️ Error loading or executing the application: {str(e)}")
31
+ import traceback
32
+ st.code(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
 
34
  if __name__ == "__main__":
35
+ main()