prithivMLmods commited on
Commit
d0c65d0
·
verified ·
1 Parent(s): f78f9c4

update app - [cleaned]

Browse files
Files changed (1) hide show
  1. app.py +355 -48
app.py CHANGED
@@ -169,8 +169,9 @@ footer{display:none!important}
169
  width:36px;height:36px;
170
  background:linear-gradient(135deg,#FF4500,#FF6633,#FF8C66);
171
  border-radius:10px;display:flex;align-items:center;justify-content:center;
172
- font-size:18px;color:#fff;box-shadow:0 4px 12px rgba(255,69,0,.35);
173
  }
 
174
  .app-title{
175
  font-size:18px;font-weight:700;
176
  background:linear-gradient(135deg,#e4e4e7,#a1a1aa);
@@ -208,13 +209,30 @@ footer{display:none!important}
208
  background:rgba(255,69,0,.25);color:#ffffff!important;
209
  -webkit-text-fill-color:#ffffff!important;border-color:rgba(255,69,0,.45);
210
  }
211
- .modern-tb-btn .tb-icon{font-size:15px;line-height:1;color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
212
  .modern-tb-btn .tb-label{font-size:13px;color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;font-weight:600}
 
 
 
 
213
  .tb-info{
214
  font-family:'JetBrains Mono',monospace;font-size:12px;
215
  color:#71717a;padding:0 8px;display:flex;align-items:center;
216
  }
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  /* ── Main Layout ── */
219
  .app-main-row{display:flex;gap:0;flex:1;overflow:hidden}
220
  .app-main-left{
@@ -321,6 +339,49 @@ footer{display:none!important}
321
  color:#FF6633;transform:translateY(-1px);
322
  }
323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  /* ── Right Panel Cards ── */
325
  .panel-card{border-bottom:1px solid #27272a}
326
  .panel-card-title{
@@ -337,8 +398,46 @@ footer{display:none!important}
337
  }
338
  .modern-textarea:focus{border-color:#FF4500;box-shadow:0 0 0 3px rgba(255,69,0,.15)}
339
  .modern-textarea::placeholder{color:#3f3f46}
340
-
341
- /* ── Primary Button — White text+SVG in ALL themes ── */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  .btn-run{
343
  display:flex;align-items:center;justify-content:center;gap:8px;
344
  width:100%;background:linear-gradient(135deg,#FF4500,#E63E00);
@@ -360,14 +459,8 @@ footer{display:none!important}
360
  .btn-run:focus{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
361
  .btn-run svg{width:18px;height:18px;fill:#ffffff!important;color:#ffffff!important}
362
  .btn-run svg path{fill:#ffffff!important;color:#ffffff!important}
363
- .btn-run span,
364
- .btn-run #run-btn-label,
365
- #run-btn-label{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
366
-
367
- /* Force white on run button — every selector/theme */
368
- #custom-run-btn,#custom-run-btn *,#custom-run-btn span,
369
- #custom-run-btn svg,#custom-run-btn svg *,#custom-run-btn svg path,
370
- #custom-run-btn #run-btn-label,.btn-run *{
371
  color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important;
372
  }
373
  body:not(.dark) .btn-run,body:not(.dark) .btn-run *,body:not(.dark) #custom-run-btn,
@@ -383,17 +476,6 @@ body:not(.dark) #custom-run-btn *,body:not(.dark) #run-btn-label{
383
  color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important;
384
  }
385
 
386
- /* ── Toolbar btn white in all themes ── */
387
- body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
388
- color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
389
- }
390
- .dark .modern-tb-btn,.dark .modern-tb-btn *{
391
- color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
392
- }
393
- .gradio-container .modern-tb-btn,.gradio-container .modern-tb-btn *{
394
- color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
395
- }
396
-
397
  /* ── Output Frames ── */
398
  .output-frame{
399
  border-bottom:1px solid #27272a;display:flex;flex-direction:column;position:relative;
@@ -412,7 +494,6 @@ body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
412
  }
413
  .output-frame .out-body img{max-width:100%;max-height:460px;image-rendering:auto}
414
  .output-frame .out-placeholder{color:#3f3f46;font-size:13px;text-align:center;padding:20px}
415
-
416
  .out-download-btn{
417
  display:none;align-items:center;justify-content:center;
418
  background:rgba(255,69,0,.1);border:1px solid rgba(255,69,0,.2);
@@ -501,7 +582,6 @@ body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
501
  opacity:0.01;pointer-events:none;overflow:hidden;
502
  }
503
 
504
- /* ── Experimental Note ── */
505
  .exp-note{
506
  padding:10px 20px;font-size:12px;color:#52525b;border-top:1px solid #27272a;
507
  text-align:center;
@@ -509,7 +589,6 @@ body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
509
  .exp-note a{color:#FF6633;text-decoration:none}
510
  .exp-note a:hover{text-decoration:underline}
511
 
512
- /* ── Dark mode extras ── */
513
  .dark .app-shell{background:#18181b}
514
  .dark .upload-prompt-modern{background:transparent}
515
  .dark .panel-card{background:#18181b}
@@ -519,13 +598,11 @@ body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
519
  .dark .out-download-btn{color:#FF8C66!important}
520
  .dark .out-download-btn:hover{color:#ffffff!important}
521
 
522
- /* ── Scrollbar ── */
523
  ::-webkit-scrollbar{width:8px;height:8px}
524
  ::-webkit-scrollbar-track{background:#09090b}
525
  ::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
526
  ::-webkit-scrollbar-thumb:hover{background:#3f3f46}
527
 
528
- /* ── Responsive ── */
529
  @media(max-width:840px){
530
  .app-main-row{flex-direction:column}
531
  .app-main-right{width:100%}
@@ -561,6 +638,37 @@ function init() {
561
  let images = [];
562
  window.__uploadedImages = images;
563
  let selectedIdx = -1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
 
565
  function setGradioValue(containerId, value) {
566
  const container = document.getElementById(containerId);
@@ -600,6 +708,7 @@ function init() {
600
  renderGallery();
601
  syncImagesToGradio();
602
  }
 
603
 
604
  function removeImage(idx) {
605
  images.splice(idx, 1);
@@ -616,6 +725,7 @@ function init() {
616
  renderGallery();
617
  syncImagesToGradio();
618
  }
 
619
 
620
  function selectImage(idx) {
621
  selectedIdx = (selectedIdx === idx) ? -1 : idx;
@@ -698,6 +808,91 @@ function init() {
698
  if (promptInput) { promptInput.value = text; syncPromptToGradio(); }
699
  };
700
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
701
  function syncSlider(customId, gradioId) {
702
  const slider = document.getElementById(customId);
703
  const valSpan = document.getElementById(customId + '-val');
@@ -745,7 +940,28 @@ function init() {
745
  window.__showLoader = showLoader;
746
  window.__hideLoader = hideLoader;
747
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
748
  window.__clickGradioRunBtn = function() {
 
749
  syncPromptToGradio();
750
  syncImagesToGradio();
751
  showLoader();
@@ -834,6 +1050,14 @@ watchSeed();
834
 
835
  DOWNLOAD_SVG = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 16l-5-5h3V4h4v7h3l-5 5z"/><path d="M20 18H4v2h16v-2z"/></svg>'
836
 
 
 
 
 
 
 
 
 
837
  with gr.Blocks() as demo:
838
 
839
  hidden_images_b64 = gr.Textbox(
@@ -868,32 +1092,32 @@ with gr.Blocks() as demo:
868
  gr.HTML(f"""
869
  <div class="app-shell">
870
 
871
- <!-- ══ Header ══ -->
872
  <div class="app-header">
873
  <div class="app-header-left">
874
- <div class="app-logo">🔥</div>
875
  <span class="app-title">FireRed-Image-Edit</span>
876
  <span class="app-badge">v1.1</span>
877
  <span class="app-badge fast">4-Step Fast</span>
878
  </div>
879
  </div>
880
 
881
- <!-- ══ Toolbar ══ -->
882
  <div class="app-toolbar">
883
  <button id="tb-upload" class="modern-tb-btn" title="Upload images">
884
- <span class="tb-icon">📁</span><span class="tb-label">Upload</span>
885
  </button>
886
  <button id="tb-remove" class="modern-tb-btn" title="Remove selected image">
887
- <span class="tb-icon">✕</span><span class="tb-label">Remove</span>
888
  </button>
889
  <button id="tb-clear" class="modern-tb-btn" title="Clear all images">
890
- <span class="tb-icon">✖</span><span class="tb-label">Clear All</span>
891
  </button>
892
  <div class="tb-sep"></div>
893
  <span id="tb-image-count" class="tb-info">No images</span>
894
  </div>
895
 
896
- <!-- ══ Main ══ -->
897
  <div class="app-main-row">
898
 
899
  <!-- Left: Gallery -->
@@ -924,16 +1148,95 @@ with gr.Blocks() as demo:
924
  <div class="suggestions-section">
925
  <div class="suggestions-title">Quick Prompts</div>
926
  <div class="suggestions-wrap">
927
- <button class="suggestion-chip" onclick="window.__setPrompt('Transform the image into a dotted cartoon style.')">🎨 Cartoon</button>
928
- <button class="suggestion-chip" onclick="window.__setPrompt('Convert it to black and white.')"> B&amp;W</button>
929
- <button class="suggestion-chip" onclick="window.__setPrompt('Add cinematic lighting with warm orange tones and film grain.')">🎬 Cinematic</button>
930
- <button class="suggestion-chip" onclick="window.__setPrompt('Transform into anime style illustration.')">Anime</button>
931
- <button class="suggestion-chip" onclick="window.__setPrompt('Apply oil painting effect with visible brush strokes.')">🖌️ Oil Paint</button>
932
- <button class="suggestion-chip" onclick="window.__setPrompt('Enhance and upscale with more detail and clarity.')">🔍 Enhance</button>
933
- <button class="suggestion-chip" onclick="window.__setPrompt('Make it look like a watercolor painting with soft edges.')">💧 Watercolor</button>
934
- <button class="suggestion-chip" onclick="window.__setPrompt('Add dramatic sunset sky and warm lighting.')">🌅 Sunset</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935
  </div>
936
  </div>
 
937
  </div>
938
 
939
  <!-- Right: Controls & Output -->
@@ -964,7 +1267,7 @@ with gr.Blocks() as demo:
964
  <div class="out-body" id="output-image-container">
965
  <div class="modern-loader" id="output-loader">
966
  <div class="loader-spinner"></div>
967
- <div class="loader-text">Processing image</div>
968
  <div class="loader-bar-track"><div class="loader-bar-fill"></div></div>
969
  </div>
970
  <div class="out-placeholder" id="output-placeholder">Result will appear here</div>
@@ -999,13 +1302,13 @@ with gr.Blocks() as demo:
999
  </div>
1000
  </div>
1001
 
1002
- <!-- ══ Note ══ -->
1003
  <div class="exp-note">
1004
  Experimental Space for <a href="https://huggingface.co/FireRedTeam/FireRed-Image-Edit-1.1" target="_blank">FireRed-Image-Edit-1.1</a>
1005
- · Open on <a href="https://github.com/PRITHIVSAKTHIUR/FireRed-Image-Edit-1.0-Fast" target="_blank">GitHub</a>
1006
  </div>
1007
 
1008
- <!-- ══ Status Bar ══ -->
1009
  <div class="app-statusbar">
1010
  <div class="sb-section" id="sb-image-count">No images uploaded</div>
1011
  <div class="sb-section sb-fixed">Ready</div>
@@ -1035,5 +1338,9 @@ with gr.Blocks() as demo:
1035
 
1036
  if __name__ == "__main__":
1037
  demo.queue(max_size=30).launch(
1038
- css=css, mcp_server=True, ssr_mode=False, show_error=True
 
 
 
 
1039
  )
 
169
  width:36px;height:36px;
170
  background:linear-gradient(135deg,#FF4500,#FF6633,#FF8C66);
171
  border-radius:10px;display:flex;align-items:center;justify-content:center;
172
+ box-shadow:0 4px 12px rgba(255,69,0,.35);
173
  }
174
+ .app-logo svg{width:20px;height:20px;fill:#fff;flex-shrink:0}
175
  .app-title{
176
  font-size:18px;font-weight:700;
177
  background:linear-gradient(135deg,#e4e4e7,#a1a1aa);
 
209
  background:rgba(255,69,0,.25);color:#ffffff!important;
210
  -webkit-text-fill-color:#ffffff!important;border-color:rgba(255,69,0,.45);
211
  }
 
212
  .modern-tb-btn .tb-label{font-size:13px;color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;font-weight:600}
213
+ .modern-tb-btn .tb-svg{
214
+ width:15px;height:15px;flex-shrink:0;
215
+ stroke:#ffffff!important;color:#ffffff!important;
216
+ }
217
  .tb-info{
218
  font-family:'JetBrains Mono',monospace;font-size:12px;
219
  color:#71717a;padding:0 8px;display:flex;align-items:center;
220
  }
221
 
222
+ /* Force toolbar white in all themes */
223
+ body:not(.dark) .modern-tb-btn,body:not(.dark) .modern-tb-btn *{
224
+ color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
225
+ }
226
+ body:not(.dark) .modern-tb-btn .tb-svg{stroke:#ffffff!important}
227
+ .dark .modern-tb-btn,.dark .modern-tb-btn *{
228
+ color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
229
+ }
230
+ .dark .modern-tb-btn .tb-svg{stroke:#ffffff!important}
231
+ .gradio-container .modern-tb-btn,.gradio-container .modern-tb-btn *{
232
+ color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
233
+ }
234
+ .gradio-container .modern-tb-btn .tb-svg{stroke:#ffffff!important}
235
+
236
  /* ── Main Layout ── */
237
  .app-main-row{display:flex;gap:0;flex:1;overflow:hidden}
238
  .app-main-left{
 
339
  color:#FF6633;transform:translateY(-1px);
340
  }
341
 
342
+ /* ── Quick Examples ── */
343
+ .examples-section{border-top:1px solid #27272a;padding:12px 16px}
344
+ .examples-title{
345
+ font-size:12px;font-weight:600;color:#71717a;text-transform:uppercase;
346
+ letter-spacing:.8px;margin-bottom:10px;
347
+ }
348
+ .examples-scroll{
349
+ display:flex;gap:10px;overflow-x:auto;padding-bottom:8px;
350
+ }
351
+ .examples-scroll::-webkit-scrollbar{height:6px}
352
+ .examples-scroll::-webkit-scrollbar-track{background:#09090b;border-radius:3px}
353
+ .examples-scroll::-webkit-scrollbar-thumb{background:#27272a;border-radius:3px}
354
+ .examples-scroll::-webkit-scrollbar-thumb:hover{background:#3f3f46}
355
+ .example-card{
356
+ flex-shrink:0;width:210px;background:#09090b;border:1px solid #27272a;
357
+ border-radius:10px;overflow:hidden;cursor:pointer;transition:all .2s ease;
358
+ }
359
+ .example-card:hover{
360
+ border-color:#FF4500;transform:translateY(-2px);
361
+ box-shadow:0 4px 12px rgba(255,69,0,.15);
362
+ }
363
+ .example-card.loading{opacity:.6;pointer-events:none}
364
+ .example-thumbs{display:flex;height:110px;overflow:hidden;background:#18181b}
365
+ .example-thumbs img{
366
+ flex:1;object-fit:cover;min-width:0;
367
+ border-bottom:1px solid #27272a;
368
+ }
369
+ .example-thumb-placeholder{
370
+ flex:1;display:flex;align-items:center;justify-content:center;
371
+ background:#18181b;color:#3f3f46;font-size:11px;min-width:0;
372
+ }
373
+ .example-meta{padding:6px 10px;display:flex;align-items:center;gap:6px}
374
+ .example-badge{
375
+ display:inline-flex;padding:2px 7px;
376
+ background:rgba(255,69,0,.1);border-radius:4px;
377
+ font-size:10px;font-weight:600;color:#FF6633;
378
+ font-family:'JetBrains Mono',monospace;white-space:nowrap;
379
+ }
380
+ .example-prompt-text{
381
+ padding:0 10px 8px;font-size:11px;color:#a1a1aa;line-height:1.4;
382
+ display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
383
+ }
384
+
385
  /* ── Right Panel Cards ── */
386
  .panel-card{border-bottom:1px solid #27272a}
387
  .panel-card-title{
 
398
  }
399
  .modern-textarea:focus{border-color:#FF4500;box-shadow:0 0 0 3px rgba(255,69,0,.15)}
400
  .modern-textarea::placeholder{color:#3f3f46}
401
+ .modern-textarea.error-flash{
402
+ border-color:#ef4444!important;
403
+ box-shadow:0 0 0 3px rgba(239,68,68,.2)!important;
404
+ animation:shake .4s ease;
405
+ }
406
+ @keyframes shake{
407
+ 0%,100%{transform:translateX(0)}
408
+ 20%,60%{transform:translateX(-4px)}
409
+ 40%,80%{transform:translateX(4px)}
410
+ }
411
+
412
+ /* ── Toast ── */
413
+ .toast-notification{
414
+ position:fixed;top:24px;left:50%;transform:translateX(-50%) translateY(-120%);
415
+ z-index:9999;padding:10px 24px;border-radius:10px;
416
+ font-family:'Inter',sans-serif;font-size:14px;font-weight:600;
417
+ display:flex;align-items:center;gap:8px;
418
+ box-shadow:0 8px 24px rgba(0,0,0,.5);
419
+ transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .35s ease;
420
+ opacity:0;pointer-events:none;
421
+ }
422
+ .toast-notification.visible{
423
+ transform:translateX(-50%) translateY(0);opacity:1;pointer-events:auto;
424
+ }
425
+ .toast-notification.error{
426
+ background:linear-gradient(135deg,#dc2626,#b91c1c);
427
+ color:#fff;border:1px solid rgba(255,255,255,.15);
428
+ }
429
+ .toast-notification.warning{
430
+ background:linear-gradient(135deg,#d97706,#b45309);
431
+ color:#fff;border:1px solid rgba(255,255,255,.15);
432
+ }
433
+ .toast-notification.info{
434
+ background:linear-gradient(135deg,#2563eb,#1d4ed8);
435
+ color:#fff;border:1px solid rgba(255,255,255,.15);
436
+ }
437
+ .toast-notification .toast-icon{font-size:16px;line-height:1}
438
+ .toast-notification .toast-text{line-height:1.3}
439
+
440
+ /* ── Primary Button ── */
441
  .btn-run{
442
  display:flex;align-items:center;justify-content:center;gap:8px;
443
  width:100%;background:linear-gradient(135deg,#FF4500,#E63E00);
 
459
  .btn-run:focus{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
460
  .btn-run svg{width:18px;height:18px;fill:#ffffff!important;color:#ffffff!important}
461
  .btn-run svg path{fill:#ffffff!important;color:#ffffff!important}
462
+ .btn-run span,#run-btn-label{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
463
+ #custom-run-btn,#custom-run-btn *,.btn-run *{
 
 
 
 
 
 
464
  color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important;
465
  }
466
  body:not(.dark) .btn-run,body:not(.dark) .btn-run *,body:not(.dark) #custom-run-btn,
 
476
  color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important;
477
  }
478
 
 
 
 
 
 
 
 
 
 
 
 
479
  /* ── Output Frames ── */
480
  .output-frame{
481
  border-bottom:1px solid #27272a;display:flex;flex-direction:column;position:relative;
 
494
  }
495
  .output-frame .out-body img{max-width:100%;max-height:460px;image-rendering:auto}
496
  .output-frame .out-placeholder{color:#3f3f46;font-size:13px;text-align:center;padding:20px}
 
497
  .out-download-btn{
498
  display:none;align-items:center;justify-content:center;
499
  background:rgba(255,69,0,.1);border:1px solid rgba(255,69,0,.2);
 
582
  opacity:0.01;pointer-events:none;overflow:hidden;
583
  }
584
 
 
585
  .exp-note{
586
  padding:10px 20px;font-size:12px;color:#52525b;border-top:1px solid #27272a;
587
  text-align:center;
 
589
  .exp-note a{color:#FF6633;text-decoration:none}
590
  .exp-note a:hover{text-decoration:underline}
591
 
 
592
  .dark .app-shell{background:#18181b}
593
  .dark .upload-prompt-modern{background:transparent}
594
  .dark .panel-card{background:#18181b}
 
598
  .dark .out-download-btn{color:#FF8C66!important}
599
  .dark .out-download-btn:hover{color:#ffffff!important}
600
 
 
601
  ::-webkit-scrollbar{width:8px;height:8px}
602
  ::-webkit-scrollbar-track{background:#09090b}
603
  ::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
604
  ::-webkit-scrollbar-thumb:hover{background:#3f3f46}
605
 
 
606
  @media(max-width:840px){
607
  .app-main-row{flex-direction:column}
608
  .app-main-right{width:100%}
 
638
  let images = [];
639
  window.__uploadedImages = images;
640
  let selectedIdx = -1;
641
+ let toastTimer = null;
642
+
643
+ /* ── Toast ── */
644
+ function showToast(message, type) {
645
+ let toast = document.getElementById('app-toast');
646
+ if (!toast) {
647
+ toast = document.createElement('div');
648
+ toast.id = 'app-toast';
649
+ toast.className = 'toast-notification';
650
+ toast.innerHTML = '<span class="toast-icon"></span><span class="toast-text"></span>';
651
+ document.body.appendChild(toast);
652
+ }
653
+ const icon = toast.querySelector('.toast-icon');
654
+ const text = toast.querySelector('.toast-text');
655
+ toast.className = 'toast-notification ' + (type || 'error');
656
+ if (type === 'warning') icon.textContent = '\u26A0';
657
+ else if (type === 'info') icon.textContent = '\u2139';
658
+ else icon.textContent = '\u2717';
659
+ text.textContent = message;
660
+ if (toastTimer) clearTimeout(toastTimer);
661
+ void toast.offsetWidth;
662
+ toast.classList.add('visible');
663
+ toastTimer = setTimeout(() => toast.classList.remove('visible'), 3500);
664
+ }
665
+
666
+ function flashPromptError() {
667
+ if (!promptInput) return;
668
+ promptInput.classList.add('error-flash');
669
+ promptInput.focus();
670
+ setTimeout(() => promptInput.classList.remove('error-flash'), 800);
671
+ }
672
 
673
  function setGradioValue(containerId, value) {
674
  const container = document.getElementById(containerId);
 
708
  renderGallery();
709
  syncImagesToGradio();
710
  }
711
+ window.__addImage = addImage;
712
 
713
  function removeImage(idx) {
714
  images.splice(idx, 1);
 
725
  renderGallery();
726
  syncImagesToGradio();
727
  }
728
+ window.__clearAll = clearAll;
729
 
730
  function selectImage(idx) {
731
  selectedIdx = (selectedIdx === idx) ? -1 : idx;
 
808
  if (promptInput) { promptInput.value = text; syncPromptToGradio(); }
809
  };
810
 
811
+ /* ── Example Loading ── */
812
+ const EXAMPLES = [
813
+ {
814
+ images: ["examples/1.jpg"],
815
+ prompt: "cinematic polaroid with soft grain subtle vignette gentle lighting white frame handwritten photographed 'Fire-Edit' preserving realistic texture and details."
816
+ },
817
+ {
818
+ images: ["examples/2.jpg"],
819
+ prompt: "Transform the image into a dotted cartoon style."
820
+ },
821
+ {
822
+ images: ["examples/3.jpeg"],
823
+ prompt: "Convert it to black and white."
824
+ },
825
+ {
826
+ images: ["examples/4.jpg", "examples/5.jpg"],
827
+ prompt: "Replace her glasses with the new glasses from image 1."
828
+ },
829
+ {
830
+ images: ["examples/8.jpg", "examples/9.png"],
831
+ prompt: "Replace the current clothing with the clothing from the reference image 2. Keep the person's face, hairstyle, body pose, background, lighting, and camera angle unchanged. Ensure the new outfit fits naturally with realistic fabric texture, proper shadows, folds, and accurate proportions. Match the lighting, color tone, and overall style for a seamless and high-quality result."
832
+ },
833
+ {
834
+ images: ["examples/10.jpg", "examples/11.png"],
835
+ prompt: "Replace the current clothing with the clothing from the reference image 2. Keep the person's face, hairstyle, body pose, background, lighting, and camera angle unchanged. Ensure the new outfit fits naturally with realistic fabric texture, proper shadows, folds, and accurate proportions. Match the lighting, color tone, and overall style for a seamless and high-quality result."
836
+ }
837
+ ];
838
+
839
+ async function fetchImageAsBase64(path) {
840
+ const urls = ['/file=' + path, 'file/' + path, path, './' + path];
841
+ for (const url of urls) {
842
+ try {
843
+ const resp = await fetch(url);
844
+ if (resp.ok && resp.headers.get('content-type') &&
845
+ resp.headers.get('content-type').startsWith('image')) {
846
+ const blob = await resp.blob();
847
+ return await new Promise((resolve) => {
848
+ const reader = new FileReader();
849
+ reader.onload = () => resolve(reader.result);
850
+ reader.readAsDataURL(blob);
851
+ });
852
+ }
853
+ } catch (e) {}
854
+ }
855
+ return null;
856
+ }
857
+
858
+ async function loadExample(idx) {
859
+ if (idx < 0 || idx >= EXAMPLES.length) return;
860
+ const ex = EXAMPLES[idx];
861
+
862
+ const card = document.querySelector('.example-card[data-idx="' + idx + '"]');
863
+ if (card) card.classList.add('loading');
864
+
865
+ showToast('Loading example...', 'info');
866
+
867
+ clearAll();
868
+
869
+ if (promptInput) { promptInput.value = ex.prompt; syncPromptToGradio(); }
870
+
871
+ for (const path of ex.images) {
872
+ const b64 = await fetchImageAsBase64(path);
873
+ if (b64) {
874
+ addImage(b64, path.split('/').pop());
875
+ } else {
876
+ console.warn('Could not load example image:', path);
877
+ }
878
+ }
879
+
880
+ if (card) card.classList.remove('loading');
881
+
882
+ if (images.length > 0) {
883
+ showToast('Example loaded — ' + images.length + ' image(s)', 'info');
884
+ } else {
885
+ showToast('Could not load example images', 'warning');
886
+ }
887
+ }
888
+ window.__loadExample = loadExample;
889
+
890
+ document.querySelectorAll('.example-card[data-idx]').forEach(card => {
891
+ card.addEventListener('click', () => {
892
+ loadExample(parseInt(card.getAttribute('data-idx')));
893
+ });
894
+ });
895
+
896
  function syncSlider(customId, gradioId) {
897
  const slider = document.getElementById(customId);
898
  const valSpan = document.getElementById(customId + '-val');
 
940
  window.__showLoader = showLoader;
941
  window.__hideLoader = hideLoader;
942
 
943
+ function validateBeforeRun() {
944
+ const promptVal = promptInput ? promptInput.value.trim() : '';
945
+ const hasImages = images.length > 0;
946
+ if (!hasImages && !promptVal) {
947
+ showToast('Please upload an image and enter a prompt', 'error');
948
+ flashPromptError();
949
+ return false;
950
+ }
951
+ if (!hasImages) {
952
+ showToast('Please upload at least one image', 'error');
953
+ return false;
954
+ }
955
+ if (!promptVal) {
956
+ showToast('Please enter an edit prompt', 'warning');
957
+ flashPromptError();
958
+ return false;
959
+ }
960
+ return true;
961
+ }
962
+
963
  window.__clickGradioRunBtn = function() {
964
+ if (!validateBeforeRun()) return;
965
  syncPromptToGradio();
966
  syncImagesToGradio();
967
  showLoader();
 
1050
 
1051
  DOWNLOAD_SVG = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 16l-5-5h3V4h4v7h3l-5 5z"/><path d="M20 18H4v2h16v-2z"/></svg>'
1052
 
1053
+ UPLOAD_SVG = '<svg class="tb-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>'
1054
+
1055
+ REMOVE_SVG = '<svg class="tb-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'
1056
+
1057
+ CLEAR_SVG = '<svg class="tb-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>'
1058
+
1059
+ FIRE_LOGO_SVG = '<svg viewBox="0 0 24 24" fill="white" xmlns="http://www.w3.org/2000/svg"><path d="M12 23c-3.6 0-8-2.69-8-7.5 0-3.5 3-6.5 4.5-8 .27-.27.75-.08.75.28v2.44c0 .42.5.63.72.28C12.28 7.5 13 3 13 1c0-.42.48-.64.8-.35C18 4.5 20 9 20 12c0 5.5-3.5 11-8 11z"/></svg>'
1060
+
1061
  with gr.Blocks() as demo:
1062
 
1063
  hidden_images_b64 = gr.Textbox(
 
1092
  gr.HTML(f"""
1093
  <div class="app-shell">
1094
 
1095
+ <!-- Header -->
1096
  <div class="app-header">
1097
  <div class="app-header-left">
1098
+ <div class="app-logo">{FIRE_LOGO_SVG}</div>
1099
  <span class="app-title">FireRed-Image-Edit</span>
1100
  <span class="app-badge">v1.1</span>
1101
  <span class="app-badge fast">4-Step Fast</span>
1102
  </div>
1103
  </div>
1104
 
1105
+ <!-- Toolbar -->
1106
  <div class="app-toolbar">
1107
  <button id="tb-upload" class="modern-tb-btn" title="Upload images">
1108
+ {UPLOAD_SVG}<span class="tb-label">Upload</span>
1109
  </button>
1110
  <button id="tb-remove" class="modern-tb-btn" title="Remove selected image">
1111
+ {REMOVE_SVG}<span class="tb-label">Remove</span>
1112
  </button>
1113
  <button id="tb-clear" class="modern-tb-btn" title="Clear all images">
1114
+ {CLEAR_SVG}<span class="tb-label">Clear All</span>
1115
  </button>
1116
  <div class="tb-sep"></div>
1117
  <span id="tb-image-count" class="tb-info">No images</span>
1118
  </div>
1119
 
1120
+ <!-- Main -->
1121
  <div class="app-main-row">
1122
 
1123
  <!-- Left: Gallery -->
 
1148
  <div class="suggestions-section">
1149
  <div class="suggestions-title">Quick Prompts</div>
1150
  <div class="suggestions-wrap">
1151
+ <button class="suggestion-chip" onclick="window.__setPrompt('Transform the image into a dotted cartoon style.')">Cartoon Style</button>
1152
+ <button class="suggestion-chip" onclick="window.__setPrompt('Convert it to black and white.')">Black and White</button>
1153
+ <button class="suggestion-chip" onclick="window.__setPrompt('Add cinematic lighting with warm orange tones and film grain.')">Cinematic</button>
1154
+ <button class="suggestion-chip" onclick="window.__setPrompt('Transform into anime style illustration.')">Anime Style</button>
1155
+ <button class="suggestion-chip" onclick="window.__setPrompt('Apply oil painting effect with visible brush strokes.')">Oil Painting</button>
1156
+ <button class="suggestion-chip" onclick="window.__setPrompt('Enhance and upscale with more detail and clarity.')">Enhance</button>
1157
+ <button class="suggestion-chip" onclick="window.__setPrompt('Make it look like a watercolor painting with soft edges.')">Watercolor</button>
1158
+ <button class="suggestion-chip" onclick="window.__setPrompt('Add dramatic sunset sky and warm lighting.')">Sunset Glow</button>
1159
+ <button class="suggestion-chip" onclick="window.__setPrompt('Convert to detailed pencil sketch with cross-hatching and shading.')">Pencil Sketch</button>
1160
+ <button class="suggestion-chip" onclick="window.__setPrompt('Apply pop art style with bold colors and halftone patterns.')">Pop Art</button>
1161
+ <button class="suggestion-chip" onclick="window.__setPrompt('Apply a vintage retro film look with faded colors and light leaks.')">Vintage Retro</button>
1162
+ <button class="suggestion-chip" onclick="window.__setPrompt('Add neon glow effects with vibrant colors against a dark background.')">Neon Glow</button>
1163
+ <button class="suggestion-chip" onclick="window.__setPrompt('Convert to pixel art style with a retro 16-bit aesthetic.')">Pixel Art</button>
1164
+ <button class="suggestion-chip" onclick="window.__setPrompt('Simplify into a clean minimalist illustration with flat colors.')">Minimalist</button>
1165
+ <button class="suggestion-chip" onclick="window.__setPrompt('Convert to low poly 3D geometric art style.')">Low Poly 3D</button>
1166
+ <button class="suggestion-chip" onclick="window.__setPrompt('Transform into comic book style with bold outlines and cel shading.')">Comic Book</button>
1167
+ </div>
1168
+ </div>
1169
+
1170
+ <div class="examples-section">
1171
+ <div class="examples-title">Quick Examples</div>
1172
+ <div class="examples-scroll">
1173
+
1174
+ <div class="example-card" data-idx="0">
1175
+ <div class="example-thumbs">
1176
+ <img src="/file=examples/1.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1177
+ </div>
1178
+ <div class="example-meta">
1179
+ <span class="example-badge">1 image</span>
1180
+ </div>
1181
+ <div class="example-prompt-text">Cinematic polaroid with soft grain, subtle vignette, gentle lighting...</div>
1182
+ </div>
1183
+
1184
+ <div class="example-card" data-idx="1">
1185
+ <div class="example-thumbs">
1186
+ <img src="/file=examples/2.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1187
+ </div>
1188
+ <div class="example-meta">
1189
+ <span class="example-badge">1 image</span>
1190
+ </div>
1191
+ <div class="example-prompt-text">Transform the image into a dotted cartoon style.</div>
1192
+ </div>
1193
+
1194
+ <div class="example-card" data-idx="2">
1195
+ <div class="example-thumbs">
1196
+ <img src="/file=examples/3.jpeg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1197
+ </div>
1198
+ <div class="example-meta">
1199
+ <span class="example-badge">1 image</span>
1200
+ </div>
1201
+ <div class="example-prompt-text">Convert it to black and white.</div>
1202
+ </div>
1203
+
1204
+ <div class="example-card" data-idx="3">
1205
+ <div class="example-thumbs">
1206
+ <img src="/file=examples/4.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1207
+ <img src="/file=examples/5.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1208
+ </div>
1209
+ <div class="example-meta">
1210
+ <span class="example-badge">2 images</span>
1211
+ </div>
1212
+ <div class="example-prompt-text">Replace her glasses with the new glasses from image 1.</div>
1213
+ </div>
1214
+
1215
+ <div class="example-card" data-idx="4">
1216
+ <div class="example-thumbs">
1217
+ <img src="/file=examples/8.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1218
+ <img src="/file=examples/9.png" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1219
+ </div>
1220
+ <div class="example-meta">
1221
+ <span class="example-badge">2 images</span>
1222
+ </div>
1223
+ <div class="example-prompt-text">Replace clothing with reference. Keep face, pose, and background unchanged...</div>
1224
+ </div>
1225
+
1226
+ <div class="example-card" data-idx="5">
1227
+ <div class="example-thumbs">
1228
+ <img src="/file=examples/10.jpg" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1229
+ <img src="/file=examples/11.png" onerror="this.parentElement.innerHTML='<div class=example-thumb-placeholder>Preview</div>'" alt="">
1230
+ </div>
1231
+ <div class="example-meta">
1232
+ <span class="example-badge">2 images</span>
1233
+ </div>
1234
+ <div class="example-prompt-text">Replace clothing with reference. Keep face, pose, and background unchanged...</div>
1235
+ </div>
1236
+
1237
  </div>
1238
  </div>
1239
+
1240
  </div>
1241
 
1242
  <!-- Right: Controls & Output -->
 
1267
  <div class="out-body" id="output-image-container">
1268
  <div class="modern-loader" id="output-loader">
1269
  <div class="loader-spinner"></div>
1270
+ <div class="loader-text">Processing image...</div>
1271
  <div class="loader-bar-track"><div class="loader-bar-fill"></div></div>
1272
  </div>
1273
  <div class="out-placeholder" id="output-placeholder">Result will appear here</div>
 
1302
  </div>
1303
  </div>
1304
 
1305
+ <!-- Note -->
1306
  <div class="exp-note">
1307
  Experimental Space for <a href="https://huggingface.co/FireRedTeam/FireRed-Image-Edit-1.1" target="_blank">FireRed-Image-Edit-1.1</a>
1308
+ &middot; Open on <a href="https://github.com/PRITHIVSAKTHIUR/FireRed-Image-Edit-1.0-Fast" target="_blank">GitHub</a>
1309
  </div>
1310
 
1311
+ <!-- Status Bar -->
1312
  <div class="app-statusbar">
1313
  <div class="sb-section" id="sb-image-count">No images uploaded</div>
1314
  <div class="sb-section sb-fixed">Ready</div>
 
1338
 
1339
  if __name__ == "__main__":
1340
  demo.queue(max_size=30).launch(
1341
+ css=css,
1342
+ mcp_server=True,
1343
+ ssr_mode=False,
1344
+ show_error=True,
1345
+ allowed_paths=["examples"],
1346
  )