Update app.py

#3
by ysharma HF staff - opened
Files changed (1) hide show
  1. app.py +322 -38
app.py CHANGED
@@ -95,63 +95,345 @@ def process_image_and_prompt(composite_pil, prompt, gemini_api_key):
95
  except Exception as e:
96
  raise gr.Error(f"Error Getting {e}", duration=5)
97
 
98
- # Build a Blocks-based interface with a custom HTML header.
99
- with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  gr.HTML(
101
  """
102
- <div style='display: flex; align-items: center; justify-content: center; gap: 20px'>
103
- <div style="background-color: var(--block-background-fill); border-radius: 8px">
104
- <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
105
  </div>
106
  <div>
107
- <h1>Gen AI Image Editing</h1>
108
- <p>Gemini for Image Editing</p>
109
- <p>Powered by <a href="https://gradio.app/">Gradio</a> ⚑️</p>
110
- <p>Duplicate Repo <a href="https://huggingface.co/spaces/ameerazam08/Gemini-Image-Edit?duplicate=true">Duplicate</a></p>
111
- <p>Get an API Key <a href="https://aistudio.google.com/apikey">here</a></p>
112
- <p>Follow me on Twitter: <a href="https://x.com/Ameerazam18">Ameerazam18</a></p>
113
  </div>
114
  </div>
115
  """
116
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- gr.Markdown("""
119
- ## ⚠️ API Configuration ⚠️
120
- - **Issue:** ❗ Sometimes the model returns text instead of an image.
121
- ### πŸ”§ Steps to Address:
122
- 1. **πŸ› οΈ Duplicate the Repository**
123
- - Create a separate copy for modifications.
124
- 2. **πŸ”‘ Use Your Own Gemini API Key**
125
- - You **must** configure your own Gemini key for generation!
126
- ---
127
- ### πŸ“Œ Usage
128
- - Upload an image and enter a prompt to generate outputs.
129
- - If text is returned instead of an image, it will appear in the text output.
130
- - Upload Only PNG Image
131
- - ❌ **Do not use NSFW images!**
132
- """)
133
-
134
- with gr.Row():
135
- with gr.Column():
136
  image_input = gr.Image(
137
  type="pil",
138
  label="Upload Image",
139
- image_mode="RGBA"
 
 
140
  )
141
  gemini_api_key = gr.Textbox(
142
  lines=1,
143
  placeholder="Enter Gemini API Key (optional)",
144
- label="Gemini API Key (optional)"
 
145
  )
146
  prompt_input = gr.Textbox(
147
  lines=2,
148
  placeholder="Enter prompt here...",
149
- label="Prompt"
 
 
 
 
 
 
 
 
 
 
150
  )
151
- submit_btn = gr.Button("Generate")
152
- with gr.Column():
153
- output_gallery = gr.Gallery(label="Generated Outputs")
154
- output_text = gr.Textbox(label="Gemini Output", placeholder="Text response will appear here if no image is generated.")
155
 
156
  # Set up the interaction with two outputs.
157
  submit_btn.click(
@@ -160,6 +442,8 @@ with gr.Blocks() as demo:
160
  outputs=[output_gallery, output_text],
161
  )
162
 
 
 
163
  examples = [
164
  ["data/1.webp", 'change text to "AMEER"', ""],
165
  ["data/2.webp", "remove the spoon from hand only", ""],
@@ -174,7 +458,7 @@ with gr.Blocks() as demo:
174
  gr.Examples(
175
  examples=examples,
176
  inputs=[image_input, prompt_input, gemini_api_key],
177
- label="Try these examples"
178
  )
179
 
180
- demo.queue(max_size=500).launch()
 
95
  except Exception as e:
96
  raise gr.Error(f"Error Getting {e}", duration=5)
97
 
98
+ # Custom CSS for a more modern UI
99
+ custom_css = """
100
+ /* Modern UI for Gemini Image Editing App */
101
+
102
+ /* Global Styles */
103
+ :root {
104
+ --primary-color: #4f46e5;
105
+ --primary-light: #6366f1;
106
+ --primary-dark: #3730a3;
107
+ --secondary-color: #9333ea;
108
+ --accent-color: #ec4899;
109
+ --text-color: #0f172a;
110
+ --text-light: #64748b;
111
+ --bg-color: #f8fafc;
112
+ --card-bg: #ffffff;
113
+ --border-color: #e2e8f0;
114
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
115
+ --transition: all 0.3s ease;
116
+ --radius: 12px;
117
+ }
118
+
119
+ /* Base container styling */
120
+ .gradio-container {
121
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
122
+ background-color: var(--bg-color);
123
+ color: var(--text-color);
124
+ max-width: 1200px;
125
+ margin: 0 auto;
126
+ padding: 2rem;
127
+ box-shadow: var(--shadow);
128
+ border-radius: var(--radius);
129
+ }
130
+
131
+ /* Header styling */
132
+ .header-container {
133
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
134
+ border-radius: var(--radius);
135
+ padding: 2rem;
136
+ margin-bottom: 2rem;
137
+ box-shadow: var(--shadow);
138
+ color: white;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ gap: 20px;
143
+ }
144
+
145
+ .header-container img {
146
+ width: 100px;
147
+ height: 100px;
148
+ filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5));
149
+ transition: var(--transition);
150
+ }
151
+
152
+ .header-container img:hover {
153
+ transform: scale(1.05) rotate(5deg);
154
+ }
155
+
156
+ .header-container h1 {
157
+ font-size: 2.5rem;
158
+ font-weight: 700;
159
+ margin-bottom: 0.5rem;
160
+ background: linear-gradient(45deg, #fff, #f0f0ff);
161
+ -webkit-background-clip: text;
162
+ background-clip: text;
163
+ color: transparent;
164
+ display: inline-block;
165
+ }
166
+
167
+ .header-container a {
168
+ color: white;
169
+ text-decoration: none;
170
+ font-weight: 600;
171
+ border-bottom: 2px solid rgba(255, 255, 255, 0.5);
172
+ transition: var(--transition);
173
+ padding-bottom: 2px;
174
+ }
175
+
176
+ .header-container a:hover {
177
+ border-color: white;
178
+ }
179
+
180
+ /* Accordion styling */
181
+ .gr-accordion {
182
+ border: none !important;
183
+ background: var(--card-bg);
184
+ border-radius: var(--radius);
185
+ overflow: hidden;
186
+ box-shadow: var(--shadow);
187
+ margin-bottom: 1.5rem;
188
+ transition: var(--transition);
189
+ }
190
+
191
+ .gr-accordion:hover {
192
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
193
+ }
194
+
195
+ .gr-accordion-title {
196
+ background-color: var(--primary-color);
197
+ color: white !important;
198
+ padding: 1rem 1.5rem;
199
+ font-weight: 600;
200
+ cursor: pointer;
201
+ }
202
+
203
+ /* Image upload area */
204
+ .upload-box {
205
+ background-color: var(--card-bg);
206
+ border: 2px dashed var(--primary-light);
207
+ border-radius: var(--radius);
208
+ transition: var(--transition);
209
+ cursor: pointer;
210
+ height: 300px;
211
+ }
212
+
213
+ .upload-box:hover {
214
+ border-color: var(--primary-color);
215
+ background-color: rgba(79, 70, 229, 0.05);
216
+ }
217
+
218
+ /* Input fields */
219
+ .gr-input, .gr-textarea {
220
+ width: 100%;
221
+ padding: 0.75rem 1rem;
222
+ border: 1px solid var(--border-color);
223
+ border-radius: var(--radius);
224
+ background-color: var(--card-bg);
225
+ transition: var(--transition);
226
+ font-size: 1rem;
227
+ }
228
+
229
+ .gr-input:focus, .gr-textarea:focus {
230
+ border-color: var(--primary-color);
231
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2);
232
+ outline: none;
233
+ }
234
+
235
+ .gr-form .gr-form-label {
236
+ font-weight: 600;
237
+ color: var(--text-color);
238
+ margin-bottom: 0.5rem;
239
+ }
240
+
241
+ /* Generate button */
242
+ .gr-button.gr-button-primary {
243
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
244
+ color: white;
245
+ border: none;
246
+ border-radius: var(--radius);
247
+ padding: 0.75rem 1.5rem;
248
+ font-size: 1rem;
249
+ font-weight: 600;
250
+ cursor: pointer;
251
+ transition: var(--transition);
252
+ width: 100%;
253
+ text-transform: uppercase;
254
+ letter-spacing: 1px;
255
+ box-shadow: 0 4px 6px -1px rgba(79, 70, 229, 0.4);
256
+ }
257
+
258
+ .gr-button.gr-button-primary:hover {
259
+ transform: translateY(-2px);
260
+ box-shadow: 0 10px 15px -3px rgba(79, 70, 229, 0.4);
261
+ }
262
+
263
+ .gr-button.gr-button-primary:active {
264
+ transform: translateY(1px);
265
+ }
266
+
267
+ /* Gallery output */
268
+ .gr-gallery {
269
+ background-color: var(--card-bg);
270
+ border-radius: var(--radius);
271
+ padding: 1rem;
272
+ box-shadow: var(--shadow);
273
+ min-height: 300px;
274
+ }
275
+
276
+ .gr-gallery img {
277
+ border-radius: calc(var(--radius) - 4px);
278
+ transition: var(--transition);
279
+ }
280
+
281
+ .gr-gallery img:hover {
282
+ transform: scale(1.02);
283
+ }
284
+
285
+ /* Output text area */
286
+ .output-text {
287
+ background-color: var(--card-bg);
288
+ border-radius: var(--radius);
289
+ padding: 1.5rem;
290
+ box-shadow: var(--shadow);
291
+ line-height: 1.6;
292
+ min-height: 100px;
293
+ }
294
+
295
+ /* Examples section */
296
+ .gr-examples-header {
297
+ font-weight: 600;
298
+ margin: 2rem 0 1rem;
299
+ padding-bottom: 0.5rem;
300
+ border-bottom: 2px solid var(--primary-light);
301
+ color: var(--primary-dark);
302
+ }
303
+
304
+ .gr-examples {
305
+ display: grid;
306
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
307
+ gap: 1rem;
308
+ margin-top: 1.5rem;
309
+ }
310
+
311
+ .gr-sample {
312
+ background-color: var(--card-bg);
313
+ border-radius: var(--radius);
314
+ overflow: hidden;
315
+ box-shadow: var(--shadow);
316
+ transition: var(--transition);
317
+ cursor: pointer;
318
+ }
319
+
320
+ .gr-sample:hover {
321
+ transform: translateY(-2px);
322
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
323
+ }
324
+
325
+ .gr-sample img {
326
+ width: 100%;
327
+ height: 150px;
328
+ object-fit: cover;
329
+ }
330
+
331
+ /* Responsive adjustments */
332
+ @media (max-width: 768px) {
333
+ .gradio-container {
334
+ padding: 1rem;
335
+ }
336
+
337
+ .header-container {
338
+ flex-direction: column;
339
+ text-align: center;
340
+ padding: 1.5rem;
341
+ }
342
+
343
+ .header-container h1 {
344
+ font-size: 2rem;
345
+ }
346
+ }
347
+
348
+ /* Custom scrollbar */
349
+ ::-webkit-scrollbar {
350
+ width: 8px;
351
+ height: 8px;
352
+ }
353
+
354
+ ::-webkit-scrollbar-track {
355
+ background: var(--bg-color);
356
+ }
357
+
358
+ ::-webkit-scrollbar-thumb {
359
+ background: var(--primary-light);
360
+ border-radius: 4px;
361
+ }
362
+
363
+ ::-webkit-scrollbar-thumb:hover {
364
+ background: var(--primary-color);
365
+ }
366
+ """
367
+
368
+ # Build a Blocks-based interface with a custom HTML header and CSS
369
+ with gr.Blocks(css=custom_css) as demo:
370
+ # Custom HTML header with proper class for styling
371
  gr.HTML(
372
  """
373
+ <div class="header-container">
374
+ <div>
375
+ <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" alt="Gemini logo">
376
  </div>
377
  <div>
378
+ <h1>Gemini for Image Editing</h1>
379
+ <p>Powered by <a href="https://gradio.app/">Gradio</a>⚑️|
380
+ <a href="https://huggingface.co/spaces/ameerazam08/Gemini-Image-Edit?duplicate=true">Duplicate</a> this Repo |
381
+ <a href="https://aistudio.google.com/apikey">Get an API Key</a> |
382
+ Follow me on Twitter: <a href="https://x.com/Ameerazam18">Ameerazam18</a></p>
 
383
  </div>
384
  </div>
385
  """
386
  )
387
+
388
+ with gr.Accordion("⚠️ API Configuration ⚠️", open=False, elem_classes="config-accordion"):
389
+ gr.Markdown("""
390
+ - **Issue:** ❗ Sometimes the model returns text instead of an image.
391
+ ### πŸ”§ Steps to Address:
392
+ 1. **πŸ› οΈ Duplicate the Repository**
393
+ - Create a separate copy for modifications.
394
+ 2. **πŸ”‘ Use Your Own Gemini API Key**
395
+ - You **must** configure your own Gemini key for generation!
396
+ """)
397
+
398
+ with gr.Accordion("πŸ“Œ Usage Instructions", open=False, elem_classes="instructions-accordion"):
399
+ gr.Markdown("""
400
+ ### πŸ“Œ Usage
401
+ - Upload an image and enter a prompt to generate outputs.
402
+ - If text is returned instead of an image, it will appear in the text output.
403
+ - Upload Only PNG Image
404
+ - ❌ **Do not use NSFW images!**
405
+ """)
406
 
407
+ with gr.Row(elem_classes="main-content"):
408
+ with gr.Column(elem_classes="input-column"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  image_input = gr.Image(
410
  type="pil",
411
  label="Upload Image",
412
+ image_mode="RGBA",
413
+ elem_id="image-input",
414
+ elem_classes="upload-box"
415
  )
416
  gemini_api_key = gr.Textbox(
417
  lines=1,
418
  placeholder="Enter Gemini API Key (optional)",
419
+ label="Gemini API Key (optional)",
420
+ elem_classes="api-key-input"
421
  )
422
  prompt_input = gr.Textbox(
423
  lines=2,
424
  placeholder="Enter prompt here...",
425
+ label="Prompt",
426
+ elem_classes="prompt-input"
427
+ )
428
+ submit_btn = gr.Button("Generate", elem_classes="generate-btn")
429
+
430
+ with gr.Column(elem_classes="output-column"):
431
+ output_gallery = gr.Gallery(label="Generated Outputs", elem_classes="output-gallery")
432
+ output_text = gr.Textbox(
433
+ label="Gemini Output",
434
+ placeholder="Text response will appear here if no image is generated.",
435
+ elem_classes="output-text"
436
  )
 
 
 
 
437
 
438
  # Set up the interaction with two outputs.
439
  submit_btn.click(
 
442
  outputs=[output_gallery, output_text],
443
  )
444
 
445
+ gr.Markdown("## Try these examples", elem_classes="gr-examples-header")
446
+
447
  examples = [
448
  ["data/1.webp", 'change text to "AMEER"', ""],
449
  ["data/2.webp", "remove the spoon from hand only", ""],
 
458
  gr.Examples(
459
  examples=examples,
460
  inputs=[image_input, prompt_input, gemini_api_key],
461
+ elem_id="examples-grid"
462
  )
463
 
464
+ demo.queue(max_size=500).launch()