prithivMLmods commited on
Commit
0bb1bf4
Β·
verified Β·
1 Parent(s): 8df731e

update app

Browse files
Files changed (1) hide show
  1. app.py +115 -21
app.py CHANGED
@@ -236,20 +236,24 @@ footer{display:none!important}
236
  opacity:0.01;pointer-events:none;overflow:hidden;
237
  }
238
 
 
239
  .app-shell{
240
  background:#18181b;border:1px solid #27272a;border-radius:16px;
241
  margin:12px auto;max-width:1400px;overflow:hidden;
242
  box-shadow:0 25px 50px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.03);
243
  }
 
 
244
  .app-header{
245
  background:linear-gradient(135deg,#18181b,#1e1e24);border-bottom:1px solid #27272a;
246
- padding:14px 24px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;
 
247
  }
248
  .app-header-left{display:flex;align-items:center;gap:12px}
249
  .app-logo{
250
  width:36px;height:36px;background:linear-gradient(135deg,#1E90FF,#47A3FF,#7CB8FF);
251
  border-radius:10px;display:flex;align-items:center;justify-content:center;
252
- box-shadow:0 4px 12px rgba(30,144,255,.35);
253
  }
254
  .app-logo svg{width:20px;height:20px;fill:#fff;flex-shrink:0}
255
  .app-title{
@@ -262,6 +266,31 @@ footer{display:none!important}
262
  }
263
  .app-badge.fast{background:rgba(34,197,94,.12);color:#4ade80;border:1px solid rgba(34,197,94,.25)}
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  .app-toolbar{
266
  background:#18181b;border-bottom:1px solid #27272a;padding:8px 16px;
267
  display:flex;gap:4px;align-items:center;flex-wrap:wrap;
@@ -289,10 +318,12 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
289
  .gradio-container .modern-tb-btn,.gradio-container .modern-tb-btn *{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
290
  .gradio-container .modern-tb-btn .tb-svg,.gradio-container .modern-tb-btn .tb-svg *{stroke:#ffffff!important}
291
 
 
292
  .app-main-row{display:flex;gap:0;flex:1;overflow:hidden}
293
  .app-main-left{flex:1;display:flex;flex-direction:column;min-width:0;border-right:1px solid #27272a}
294
  .app-main-right{width:420px;display:flex;flex-direction:column;flex-shrink:0;background:#18181b}
295
 
 
296
  #gallery-drop-zone{position:relative;background:#09090b;min-height:440px;overflow:auto}
297
  #gallery-drop-zone.drag-over{outline:2px solid #1E90FF;outline-offset:-2px;background:rgba(30,144,255,.04)}
298
 
@@ -306,8 +337,9 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
306
  .upload-click-area:active{background:rgba(30,144,255,.12);transform:scale(.98)}
307
  .upload-click-area svg{width:80px;height:80px}
308
  .upload-main-text{color:#71717a;font-size:14px;font-weight:500;margin-top:4px}
309
- .upload-sub-text{color:#52525b;font-size:12px}
310
 
 
311
  .image-gallery-grid{
312
  display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));
313
  gap:12px;padding:16px;align-content:start;
@@ -339,6 +371,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
339
  .gallery-add-card .add-icon{font-size:28px;color:#71717a;font-weight:300}
340
  .gallery-add-card .add-text{font-size:12px;color:#71717a;font-weight:500}
341
 
 
342
  .hint-bar{
343
  background:rgba(30,144,255,.06);border-top:1px solid #27272a;border-bottom:1px solid #27272a;
344
  padding:10px 20px;font-size:13px;color:#a1a1aa;line-height:1.7;
@@ -349,6 +382,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
349
  border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:11px;color:#a1a1aa;
350
  }
351
 
 
352
  .suggestions-section{border-top:1px solid #27272a;padding:12px 16px}
353
  .suggestions-title,.examples-title{
354
  font-size:12px;font-weight:600;color:#71717a;text-transform:uppercase;
@@ -363,6 +397,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
363
  }
364
  .suggestion-chip:hover{background:rgba(30,144,255,.15);border-color:rgba(30,144,255,.35);color:#47A3FF;transform:translateY(-1px)}
365
 
 
366
  .examples-section{border-top:1px solid #27272a;padding:12px 16px}
367
  .examples-scroll{display:flex;gap:10px;overflow-x:auto;padding-bottom:8px}
368
  .examples-scroll::-webkit-scrollbar{height:6px}
@@ -391,6 +426,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
391
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
392
  }
393
 
 
394
  .panel-card{border-bottom:1px solid #27272a}
395
  .panel-card-title{
396
  padding:12px 20px;font-size:12px;font-weight:600;color:#71717a;
@@ -410,6 +446,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
410
  }
411
  @keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-4px)}40%,80%{transform:translateX(4px)}}
412
 
 
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;font-family:'Inter',sans-serif;
@@ -424,6 +461,7 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
424
  .toast-notification .toast-icon{font-size:16px;line-height:1}
425
  .toast-notification .toast-text{line-height:1.3}
426
 
 
427
  .btn-run{
428
  display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
429
  background:linear-gradient(135deg,#1E90FF,#1873CC);border:none;border-radius:10px;
@@ -450,6 +488,7 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
450
  .gradio-container .btn-run,.gradio-container .btn-run *,.gradio-container #custom-run-btn,
451
  .gradio-container #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important}
452
 
 
453
  .output-frame{border-bottom:1px solid #27272a;display:flex;flex-direction:column;position:relative}
454
  .output-frame .out-title{
455
  padding:10px 20px;font-size:13px;font-weight:700;color:#ffffff!important;
@@ -472,6 +511,7 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
472
  .out-download-btn.visible{display:inline-flex}
473
  .out-download-btn svg{width:12px;height:12px;fill:#7CB8FF}
474
 
 
475
  .modern-loader{
476
  display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(9,9,11,.92);
477
  z-index:15;flex-direction:column;align-items:center;justify-content:center;gap:16px;backdrop-filter:blur(4px);
@@ -490,6 +530,7 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
490
  }
491
  @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
492
 
 
493
  .settings-group{border:1px solid #27272a;border-radius:10px;margin:12px 16px;padding:0;overflow:hidden}
494
  .settings-group-title{
495
  font-size:12px;font-weight:600;color:#71717a;text-transform:uppercase;letter-spacing:.8px;
@@ -520,6 +561,7 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
520
  .checkbox-row input[type="checkbox"]{accent-color:#1E90FF;width:16px;height:16px;cursor:pointer}
521
  .checkbox-row label{color:#a1a1aa;font-size:13px;cursor:pointer}
522
 
 
523
  .app-statusbar{
524
  background:#18181b;border-top:1px solid #27272a;padding:6px 20px;
525
  display:flex;gap:12px;height:34px;align-items:center;font-size:12px;
@@ -533,10 +575,16 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
533
  padding:3px 12px;background:rgba(30,144,255,.08);border-radius:6px;color:#47A3FF;font-weight:500;
534
  }
535
 
536
- .exp-note{padding:10px 20px;font-size:12px;color:#52525b;border-top:1px solid #27272a;text-align:center}
 
 
 
 
 
537
  .exp-note a{color:#47A3FF;text-decoration:none}
538
  .exp-note a:hover{text-decoration:underline}
539
 
 
540
  .dark .app-shell{background:#18181b}
541
  .dark .upload-prompt-modern{background:transparent}
542
  .dark .panel-card{background:#18181b}
@@ -546,11 +594,13 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
546
  .dark .out-download-btn{color:#7CB8FF!important}
547
  .dark .out-download-btn:hover{color:#ffffff!important}
548
 
 
549
  ::-webkit-scrollbar{width:8px;height:8px}
550
  ::-webkit-scrollbar-track{background:#09090b}
551
  ::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
552
  ::-webkit-scrollbar-thumb:hover{background:#3f3f46}
553
 
 
554
  @media(max-width:840px){
555
  .app-main-row{flex-direction:column}
556
  .app-main-right{width:100%}
@@ -588,6 +638,28 @@ function init() {
588
  let selectedIdx = -1;
589
  let toastTimer = null;
590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  function showToast(message, type) {
592
  let toast = document.getElementById('app-toast');
593
  if (!toast) {
@@ -758,10 +830,8 @@ function init() {
758
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
759
  card.classList.add('loading');
760
  showToast('Loading example...', 'info');
761
-
762
  setGradioValue('example-result-data', '');
763
  setGradioValue('example-idx-input', idx);
764
-
765
  setTimeout(() => {
766
  const btn = document.getElementById('example-load-btn');
767
  if (btn) {
@@ -769,7 +839,6 @@ function init() {
769
  if (b) b.click(); else btn.click();
770
  }
771
  }, 150);
772
-
773
  setTimeout(() => card.classList.remove('loading'), 12000);
774
  });
775
  });
@@ -877,7 +946,11 @@ function watchOutputs() {
877
  if (resultImg && resultImg.src) {
878
  if (outPh) outPh.style.display = 'none';
879
  let existing = outBody.querySelector('img.modern-out-img');
880
- if (!existing) { existing = document.createElement('img'); existing.className = 'modern-out-img'; outBody.appendChild(existing); }
 
 
 
 
881
  if (existing.src !== resultImg.src) {
882
  existing.src = resultImg.src;
883
  if (dlBtn) dlBtn.classList.add('visible');
@@ -922,19 +995,16 @@ function watchExampleResults() {
922
  const data = JSON.parse(val);
923
  if (data.status === 'ok' && data.images && data.images.length > 0) {
924
  lastProcessed = val;
925
-
926
  if (window.__clearAll) window.__clearAll();
927
  if (window.__setPrompt && data.prompt) window.__setPrompt(data.prompt);
928
-
929
  data.images.forEach((b64, i) => {
930
  if (b64 && window.__addImage) {
931
  const name = (data.names && data.names[i]) ? data.names[i] : ('example_' + (i+1) + '.jpg');
932
  window.__addImage(b64, name);
933
  }
934
  });
935
-
936
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
937
- if (window.__showToast) window.__showToast('Example loaded β€” ' + data.images.length + ' image(s)', 'info');
938
  } else if (data.status === 'error') {
939
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
940
  if (window.__showToast) window.__showToast('Could not load example images', 'error');
@@ -952,6 +1022,7 @@ watchExampleResults();
952
  }
953
  """
954
 
 
955
  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>'
956
 
957
  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>'
@@ -960,8 +1031,11 @@ REMOVE_SVG = '<svg class="tb-svg" viewBox="0 0 24 24" fill="none" stroke="curren
960
 
961
  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>'
962
 
 
 
963
  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>'
964
 
 
965
  with gr.Blocks() as demo:
966
 
967
  hidden_images_b64 = gr.Textbox(value="[]", elem_id="hidden-images-b64", elem_classes="hidden-input", container=False)
@@ -979,6 +1053,7 @@ with gr.Blocks() as demo:
979
  gr.HTML(f"""
980
  <div class="app-shell">
981
 
 
982
  <div class="app-header">
983
  <div class="app-header-left">
984
  <div class="app-logo">{FIRE_LOGO_SVG}</div>
@@ -986,8 +1061,14 @@ with gr.Blocks() as demo:
986
  <span class="app-badge">v1.1</span>
987
  <span class="app-badge fast">4-Step Fast</span>
988
  </div>
 
 
 
 
 
989
  </div>
990
 
 
991
  <div class="app-toolbar">
992
  <button id="tb-upload" class="modern-tb-btn" title="Upload images">
993
  {UPLOAD_SVG}<span class="tb-label">Upload</span>
@@ -1002,15 +1083,21 @@ with gr.Blocks() as demo:
1002
  <span id="tb-image-count" class="tb-info">No images</span>
1003
  </div>
1004
 
 
1005
  <div class="app-main-row">
 
 
1006
  <div class="app-main-left">
1007
  <div id="gallery-drop-zone">
1008
  <div id="upload-prompt" class="upload-prompt-modern">
1009
  <div id="upload-click-area" class="upload-click-area">
1010
  <svg viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
1011
- <rect x="8" y="14" width="64" height="52" rx="6" fill="none" stroke="#1E90FF" stroke-width="2" stroke-dasharray="4 3"/>
1012
- <polygon points="12,62 30,40 42,50 54,34 68,62" fill="rgba(30,144,255,0.15)" stroke="#1E90FF" stroke-width="1.5"/>
1013
- <circle cx="28" cy="30" r="6" fill="rgba(30,144,255,0.2)" stroke="#1E90FF" stroke-width="1.5"/>
 
 
 
1014
  </svg>
1015
  <span class="upload-main-text">Click or drag images here</span>
1016
  <span class="upload-sub-text">Supports multiple images for reference-based editing and guided manipulation</span>
@@ -1050,25 +1137,29 @@ with gr.Blocks() as demo:
1050
  </div>
1051
 
1052
  <div class="examples-section">
1053
- <div class="examples-title">Quick Examples</div>
1054
  <div class="examples-scroll">
1055
  {EXAMPLE_CARDS_HTML}
1056
  </div>
1057
  </div>
1058
  </div>
1059
 
 
1060
  <div class="app-main-right">
1061
  <div class="panel-card">
1062
  <div class="panel-card-title">Edit Instruction</div>
1063
  <div class="panel-card-body">
1064
  <label class="modern-label" for="custom-prompt-input">Prompt</label>
1065
- <textarea id="custom-prompt-input" class="modern-textarea" rows="3" placeholder="e.g., transform into anime, upscale, change lighting..."></textarea>
 
1066
  </div>
1067
  </div>
1068
 
1069
  <div style="padding:12px 20px;">
1070
  <button id="custom-run-btn" class="btn-run">
1071
- <svg viewBox="0 0 24 24" 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>
 
 
1072
  <span id="run-btn-label">Edit Image</span>
1073
  </button>
1074
  </div>
@@ -1117,16 +1208,19 @@ with gr.Blocks() as demo:
1117
  </div>
1118
  </div>
1119
 
 
1120
  <div class="exp-note">
1121
- Experimental Space for <a href="https://huggingface.co/FireRedTeam/FireRed-Image-Edit-1.1" target="_blank">FireRed-Image-Edit-1.1</a>
1122
- &middot; Open on <a href="https://github.com/PRITHIVSAKTHIUR/FireRed-Image-Edit-1.0-Fast" target="_blank">GitHub</a>
1123
  </div>
1124
 
 
1125
  <div class="app-statusbar">
1126
  <div class="sb-section" id="sb-image-count">No images uploaded</div>
1127
  <div class="sb-section sb-fixed">Ready</div>
1128
  </div>
1129
- </div>
 
1130
  """)
1131
 
1132
  run_btn = gr.Button("Run", elem_id="gradio-run-btn")
 
236
  opacity:0.01;pointer-events:none;overflow:hidden;
237
  }
238
 
239
+ /* ── App shell ── */
240
  .app-shell{
241
  background:#18181b;border:1px solid #27272a;border-radius:16px;
242
  margin:12px auto;max-width:1400px;overflow:hidden;
243
  box-shadow:0 25px 50px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.03);
244
  }
245
+
246
+ /* ── Header ── */
247
  .app-header{
248
  background:linear-gradient(135deg,#18181b,#1e1e24);border-bottom:1px solid #27272a;
249
+ padding:14px 24px;display:flex;align-items:center;justify-content:space-between;
250
+ flex-wrap:wrap;gap:12px;
251
  }
252
  .app-header-left{display:flex;align-items:center;gap:12px}
253
  .app-logo{
254
  width:36px;height:36px;background:linear-gradient(135deg,#1E90FF,#47A3FF,#7CB8FF);
255
  border-radius:10px;display:flex;align-items:center;justify-content:center;
256
+ box-shadow:0 4px 12px rgba(30,144,255,.35);flex-shrink:0;
257
  }
258
  .app-logo svg{width:20px;height:20px;fill:#fff;flex-shrink:0}
259
  .app-title{
 
266
  }
267
  .app-badge.fast{background:rgba(34,197,94,.12);color:#4ade80;border:1px solid rgba(34,197,94,.25)}
268
 
269
+ /* ── GitHub button ── */
270
+ .gh-btn{
271
+ display:inline-flex!important;align-items:center!important;gap:7px!important;
272
+ padding:7px 16px!important;border-radius:8px!important;text-decoration:none!important;
273
+ font-family:'Inter',sans-serif!important;font-size:13px!important;font-weight:700!important;
274
+ letter-spacing:.1px!important;background:#1E90FF!important;
275
+ color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
276
+ border:1px solid rgba(255,255,255,.18)!important;
277
+ box-shadow:0 2px 10px rgba(30,144,255,.45),0 1px 0 rgba(255,255,255,.1) inset!important;
278
+ transition:transform .15s ease,box-shadow .15s ease,background .15s ease!important;
279
+ cursor:pointer!important;flex-shrink:0!important;
280
+ }
281
+ .gh-btn:hover{
282
+ background:#47A3FF!important;color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
283
+ transform:translateY(-1px)!important;
284
+ box-shadow:0 5px 18px rgba(30,144,255,.6),0 1px 0 rgba(255,255,255,.12) inset!important;
285
+ }
286
+ .gh-btn:active{
287
+ background:#1873CC!important;transform:translateY(0)!important;
288
+ box-shadow:0 1px 5px rgba(30,144,255,.35)!important;
289
+ }
290
+ .gh-btn svg{fill:#ffffff!important;flex-shrink:0;width:15px!important;height:15px!important}
291
+ .gh-btn span{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
292
+
293
+ /* ── Toolbar ── */
294
  .app-toolbar{
295
  background:#18181b;border-bottom:1px solid #27272a;padding:8px 16px;
296
  display:flex;gap:4px;align-items:center;flex-wrap:wrap;
 
318
  .gradio-container .modern-tb-btn,.gradio-container .modern-tb-btn *{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important}
319
  .gradio-container .modern-tb-btn .tb-svg,.gradio-container .modern-tb-btn .tb-svg *{stroke:#ffffff!important}
320
 
321
+ /* ── Main layout ── */
322
  .app-main-row{display:flex;gap:0;flex:1;overflow:hidden}
323
  .app-main-left{flex:1;display:flex;flex-direction:column;min-width:0;border-right:1px solid #27272a}
324
  .app-main-right{width:420px;display:flex;flex-direction:column;flex-shrink:0;background:#18181b}
325
 
326
+ /* ── Drop zone ── */
327
  #gallery-drop-zone{position:relative;background:#09090b;min-height:440px;overflow:auto}
328
  #gallery-drop-zone.drag-over{outline:2px solid #1E90FF;outline-offset:-2px;background:rgba(30,144,255,.04)}
329
 
 
337
  .upload-click-area:active{background:rgba(30,144,255,.12);transform:scale(.98)}
338
  .upload-click-area svg{width:80px;height:80px}
339
  .upload-main-text{color:#71717a;font-size:14px;font-weight:500;margin-top:4px}
340
+ .upload-sub-text{color:#52525b;font-size:12px;text-align:center;max-width:280px;line-height:1.5}
341
 
342
+ /* ── Gallery grid ── */
343
  .image-gallery-grid{
344
  display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));
345
  gap:12px;padding:16px;align-content:start;
 
371
  .gallery-add-card .add-icon{font-size:28px;color:#71717a;font-weight:300}
372
  .gallery-add-card .add-text{font-size:12px;color:#71717a;font-weight:500}
373
 
374
+ /* ── Hint bar ── */
375
  .hint-bar{
376
  background:rgba(30,144,255,.06);border-top:1px solid #27272a;border-bottom:1px solid #27272a;
377
  padding:10px 20px;font-size:13px;color:#a1a1aa;line-height:1.7;
 
382
  border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:11px;color:#a1a1aa;
383
  }
384
 
385
+ /* ── Suggestions ── */
386
  .suggestions-section{border-top:1px solid #27272a;padding:12px 16px}
387
  .suggestions-title,.examples-title{
388
  font-size:12px;font-weight:600;color:#71717a;text-transform:uppercase;
 
397
  }
398
  .suggestion-chip:hover{background:rgba(30,144,255,.15);border-color:rgba(30,144,255,.35);color:#47A3FF;transform:translateY(-1px)}
399
 
400
+ /* ── Examples ── */
401
  .examples-section{border-top:1px solid #27272a;padding:12px 16px}
402
  .examples-scroll{display:flex;gap:10px;overflow-x:auto;padding-bottom:8px}
403
  .examples-scroll::-webkit-scrollbar{height:6px}
 
426
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
427
  }
428
 
429
+ /* ── Right panel ── */
430
  .panel-card{border-bottom:1px solid #27272a}
431
  .panel-card-title{
432
  padding:12px 20px;font-size:12px;font-weight:600;color:#71717a;
 
446
  }
447
  @keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-4px)}40%,80%{transform:translateX(4px)}}
448
 
449
+ /* ── Toast ── */
450
  .toast-notification{
451
  position:fixed;top:24px;left:50%;transform:translateX(-50%) translateY(-120%);
452
  z-index:9999;padding:10px 24px;border-radius:10px;font-family:'Inter',sans-serif;
 
461
  .toast-notification .toast-icon{font-size:16px;line-height:1}
462
  .toast-notification .toast-text{line-height:1.3}
463
 
464
+ /* ── Run button ── */
465
  .btn-run{
466
  display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
467
  background:linear-gradient(135deg,#1E90FF,#1873CC);border:none;border-radius:10px;
 
488
  .gradio-container .btn-run,.gradio-container .btn-run *,.gradio-container #custom-run-btn,
489
  .gradio-container #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;fill:#ffffff!important}
490
 
491
+ /* ── Output ── */
492
  .output-frame{border-bottom:1px solid #27272a;display:flex;flex-direction:column;position:relative}
493
  .output-frame .out-title{
494
  padding:10px 20px;font-size:13px;font-weight:700;color:#ffffff!important;
 
511
  .out-download-btn.visible{display:inline-flex}
512
  .out-download-btn svg{width:12px;height:12px;fill:#7CB8FF}
513
 
514
+ /* ── Loader ── */
515
  .modern-loader{
516
  display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(9,9,11,.92);
517
  z-index:15;flex-direction:column;align-items:center;justify-content:center;gap:16px;backdrop-filter:blur(4px);
 
530
  }
531
  @keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
532
 
533
+ /* ── Settings ── */
534
  .settings-group{border:1px solid #27272a;border-radius:10px;margin:12px 16px;padding:0;overflow:hidden}
535
  .settings-group-title{
536
  font-size:12px;font-weight:600;color:#71717a;text-transform:uppercase;letter-spacing:.8px;
 
561
  .checkbox-row input[type="checkbox"]{accent-color:#1E90FF;width:16px;height:16px;cursor:pointer}
562
  .checkbox-row label{color:#a1a1aa;font-size:13px;cursor:pointer}
563
 
564
+ /* ── Status bar ── */
565
  .app-statusbar{
566
  background:#18181b;border-top:1px solid #27272a;padding:6px 20px;
567
  display:flex;gap:12px;height:34px;align-items:center;font-size:12px;
 
575
  padding:3px 12px;background:rgba(30,144,255,.08);border-radius:6px;color:#47A3FF;font-weight:500;
576
  }
577
 
578
+ /* ── Footer note ── */
579
+ .exp-note{
580
+ padding:10px 20px;font-size:12px;color:#52525b;
581
+ border-top:1px solid #27272a;text-align:center;font-weight:500;
582
+ background:#18181b;font-family:'Inter',sans-serif;
583
+ }
584
  .exp-note a{color:#47A3FF;text-decoration:none}
585
  .exp-note a:hover{text-decoration:underline}
586
 
587
+ /* ── Dark overrides ── */
588
  .dark .app-shell{background:#18181b}
589
  .dark .upload-prompt-modern{background:transparent}
590
  .dark .panel-card{background:#18181b}
 
594
  .dark .out-download-btn{color:#7CB8FF!important}
595
  .dark .out-download-btn:hover{color:#ffffff!important}
596
 
597
+ /* ── Scrollbars ── */
598
  ::-webkit-scrollbar{width:8px;height:8px}
599
  ::-webkit-scrollbar-track{background:#09090b}
600
  ::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
601
  ::-webkit-scrollbar-thumb:hover{background:#3f3f46}
602
 
603
+ /* ── Responsive ── */
604
  @media(max-width:840px){
605
  .app-main-row{flex-direction:column}
606
  .app-main-right{width:100%}
 
638
  let selectedIdx = -1;
639
  let toastTimer = null;
640
 
641
+ /* ── GitHub button hover ── */
642
+ function enforceGhBtn() {
643
+ const ghBtn = document.querySelector('.gh-btn');
644
+ if (ghBtn && !ghBtn.__hoverBound) {
645
+ ghBtn.__hoverBound = true;
646
+ ghBtn.addEventListener('mouseenter', () => {
647
+ ghBtn.style.setProperty('background','#47A3FF','important');
648
+ ghBtn.style.setProperty('transform','translateY(-1px)','important');
649
+ ghBtn.style.setProperty('box-shadow','0 5px 18px rgba(30,144,255,.6)','important');
650
+ });
651
+ ghBtn.addEventListener('mouseleave', () => {
652
+ ghBtn.style.setProperty('background','#1E90FF','important');
653
+ ghBtn.style.setProperty('transform','translateY(0)','important');
654
+ ghBtn.style.setProperty('box-shadow','0 2px 10px rgba(30,144,255,.45)','important');
655
+ });
656
+ ghBtn.addEventListener('mousedown', () => ghBtn.style.setProperty('background','#1873CC','important'));
657
+ ghBtn.addEventListener('mouseup', () => ghBtn.style.setProperty('background','#47A3FF','important'));
658
+ }
659
+ }
660
+ enforceGhBtn();
661
+ setInterval(enforceGhBtn, 1000);
662
+
663
  function showToast(message, type) {
664
  let toast = document.getElementById('app-toast');
665
  if (!toast) {
 
830
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
831
  card.classList.add('loading');
832
  showToast('Loading example...', 'info');
 
833
  setGradioValue('example-result-data', '');
834
  setGradioValue('example-idx-input', idx);
 
835
  setTimeout(() => {
836
  const btn = document.getElementById('example-load-btn');
837
  if (btn) {
 
839
  if (b) b.click(); else btn.click();
840
  }
841
  }, 150);
 
842
  setTimeout(() => card.classList.remove('loading'), 12000);
843
  });
844
  });
 
946
  if (resultImg && resultImg.src) {
947
  if (outPh) outPh.style.display = 'none';
948
  let existing = outBody.querySelector('img.modern-out-img');
949
+ if (!existing) {
950
+ existing = document.createElement('img');
951
+ existing.className = 'modern-out-img';
952
+ outBody.appendChild(existing);
953
+ }
954
  if (existing.src !== resultImg.src) {
955
  existing.src = resultImg.src;
956
  if (dlBtn) dlBtn.classList.add('visible');
 
995
  const data = JSON.parse(val);
996
  if (data.status === 'ok' && data.images && data.images.length > 0) {
997
  lastProcessed = val;
 
998
  if (window.__clearAll) window.__clearAll();
999
  if (window.__setPrompt && data.prompt) window.__setPrompt(data.prompt);
 
1000
  data.images.forEach((b64, i) => {
1001
  if (b64 && window.__addImage) {
1002
  const name = (data.names && data.names[i]) ? data.names[i] : ('example_' + (i+1) + '.jpg');
1003
  window.__addImage(b64, name);
1004
  }
1005
  });
 
1006
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
1007
+ if (window.__showToast) window.__showToast('Example loaded \u2014 ' + data.images.length + ' image(s)', 'info');
1008
  } else if (data.status === 'error') {
1009
  document.querySelectorAll('.example-card.loading').forEach(c => c.classList.remove('loading'));
1010
  if (window.__showToast) window.__showToast('Could not load example images', 'error');
 
1022
  }
1023
  """
1024
 
1025
+ # ── SVG assets ─────────────────────────────────────────────────────────────────
1026
  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>'
1027
 
1028
  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>'
 
1031
 
1032
  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>'
1033
 
1034
+ GITHUB_SVG = '<svg width="15" height="15" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>'
1035
+
1036
  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>'
1037
 
1038
+ # ── Gradio app ─────────────────────────────────────────────────────────────────
1039
  with gr.Blocks() as demo:
1040
 
1041
  hidden_images_b64 = gr.Textbox(value="[]", elem_id="hidden-images-b64", elem_classes="hidden-input", container=False)
 
1053
  gr.HTML(f"""
1054
  <div class="app-shell">
1055
 
1056
+ <!-- Header with GitHub top-right -->
1057
  <div class="app-header">
1058
  <div class="app-header-left">
1059
  <div class="app-logo">{FIRE_LOGO_SVG}</div>
 
1061
  <span class="app-badge">v1.1</span>
1062
  <span class="app-badge fast">4-Step Fast</span>
1063
  </div>
1064
+ <a href="https://github.com/PRITHIVSAKTHIUR/FireRed-Image-Edit-1.0-Fast"
1065
+ target="_blank" class="gh-btn">
1066
+ {GITHUB_SVG}
1067
+ <span>GitHub</span>
1068
+ </a>
1069
  </div>
1070
 
1071
+ <!-- Toolbar -->
1072
  <div class="app-toolbar">
1073
  <button id="tb-upload" class="modern-tb-btn" title="Upload images">
1074
  {UPLOAD_SVG}<span class="tb-label">Upload</span>
 
1083
  <span id="tb-image-count" class="tb-info">No images</span>
1084
  </div>
1085
 
1086
+ <!-- Main row -->
1087
  <div class="app-main-row">
1088
+
1089
+ <!-- Left panel -->
1090
  <div class="app-main-left">
1091
  <div id="gallery-drop-zone">
1092
  <div id="upload-prompt" class="upload-prompt-modern">
1093
  <div id="upload-click-area" class="upload-click-area">
1094
  <svg viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
1095
+ <rect x="8" y="14" width="64" height="52" rx="6" fill="none"
1096
+ stroke="#1E90FF" stroke-width="2" stroke-dasharray="4 3"/>
1097
+ <polygon points="12,62 30,40 42,50 54,34 68,62"
1098
+ fill="rgba(30,144,255,0.15)" stroke="#1E90FF" stroke-width="1.5"/>
1099
+ <circle cx="28" cy="30" r="6"
1100
+ fill="rgba(30,144,255,0.2)" stroke="#1E90FF" stroke-width="1.5"/>
1101
  </svg>
1102
  <span class="upload-main-text">Click or drag images here</span>
1103
  <span class="upload-sub-text">Supports multiple images for reference-based editing and guided manipulation</span>
 
1137
  </div>
1138
 
1139
  <div class="examples-section">
1140
+ <div class="examples-title">Quick Examples &mdash; click to load</div>
1141
  <div class="examples-scroll">
1142
  {EXAMPLE_CARDS_HTML}
1143
  </div>
1144
  </div>
1145
  </div>
1146
 
1147
+ <!-- Right panel -->
1148
  <div class="app-main-right">
1149
  <div class="panel-card">
1150
  <div class="panel-card-title">Edit Instruction</div>
1151
  <div class="panel-card-body">
1152
  <label class="modern-label" for="custom-prompt-input">Prompt</label>
1153
+ <textarea id="custom-prompt-input" class="modern-textarea" rows="3"
1154
+ placeholder="e.g., transform into anime, upscale, change lighting..."></textarea>
1155
  </div>
1156
  </div>
1157
 
1158
  <div style="padding:12px 20px;">
1159
  <button id="custom-run-btn" class="btn-run">
1160
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="18" height="18">
1161
+ <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" fill="white"/>
1162
+ </svg>
1163
  <span id="run-btn-label">Edit Image</span>
1164
  </button>
1165
  </div>
 
1208
  </div>
1209
  </div>
1210
 
1211
+ <!-- Footer: only model credit, no GitHub link -->
1212
  <div class="exp-note">
1213
+ Experimental Space for
1214
+ <a href="https://huggingface.co/FireRedTeam/FireRed-Image-Edit-1.1" target="_blank">FireRed-Image-Edit-1.1</a>
1215
  </div>
1216
 
1217
+ <!-- Status bar -->
1218
  <div class="app-statusbar">
1219
  <div class="sb-section" id="sb-image-count">No images uploaded</div>
1220
  <div class="sb-section sb-fixed">Ready</div>
1221
  </div>
1222
+
1223
+ </div><!-- /app-shell -->
1224
  """)
1225
 
1226
  run_btn = gr.Button("Run", elem_id="gradio-run-btn")