Spaces:
Running on Zero
Running on Zero
update app [examples] ✅
#3
by prithivMLmods - opened
app.py
CHANGED
|
@@ -614,6 +614,97 @@ footer{display:none!important}
|
|
| 614 |
color:#FF69B4;
|
| 615 |
}
|
| 616 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
/* ── JSON Panel ── */
|
| 618 |
.json-panel{
|
| 619 |
background:#18181b;
|
|
@@ -723,7 +814,7 @@ footer{display:none!important}
|
|
| 723 |
80%{transform:translateX(3px)}
|
| 724 |
}
|
| 725 |
|
| 726 |
-
/* ── Primary Button
|
| 727 |
.btn-run{
|
| 728 |
display:flex;align-items:center;justify-content:center;gap:8px;
|
| 729 |
width:100%;
|
|
@@ -822,7 +913,7 @@ footer{display:none!important}
|
|
| 822 |
fill:#ffffff!important;
|
| 823 |
}
|
| 824 |
|
| 825 |
-
/* ── Comprehensive white-force for run button
|
| 826 |
#custom-run-btn,
|
| 827 |
#custom-run-btn *,
|
| 828 |
#custom-run-btn span,
|
|
@@ -836,7 +927,7 @@ footer{display:none!important}
|
|
| 836 |
fill:#ffffff!important;
|
| 837 |
}
|
| 838 |
|
| 839 |
-
/* ── Mode button active state
|
| 840 |
.mode-btn.active,
|
| 841 |
.mode-btn.active *,
|
| 842 |
.mode-btn.active span,
|
|
@@ -1134,9 +1225,9 @@ footer{display:none!important}
|
|
| 1134 |
::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
|
| 1135 |
::-webkit-scrollbar-thumb:hover{background:#3f3f46}
|
| 1136 |
|
| 1137 |
-
/* ══════════════════════════════════════════════
|
| 1138 |
-
FORCE WHITE on Run Button + Mode Buttons
|
| 1139 |
-
══════════════════════════════════════════════
|
| 1140 |
|
| 1141 |
body:not(.dark) .btn-run,
|
| 1142 |
body:not(.dark) .btn-run *,
|
|
@@ -1235,6 +1326,9 @@ body:not(.dark) #mode-mover.active *{
|
|
| 1235 |
.app-main-right{width:100%}
|
| 1236 |
.app-main-left{border-right:none;border-bottom:1px solid #27272a}
|
| 1237 |
.mode-switcher{flex-wrap:wrap}
|
|
|
|
|
|
|
|
|
|
| 1238 |
}
|
| 1239 |
"""
|
| 1240 |
|
|
@@ -1645,6 +1739,23 @@ function initCanvasBbox() {
|
|
| 1645 |
}
|
| 1646 |
function hideStatus() { status.style.display = 'none'; }
|
| 1647 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1648 |
function resetCanvas() {
|
| 1649 |
baseImg = null;
|
| 1650 |
boxes.length = 0;
|
|
@@ -1800,20 +1911,7 @@ function initCanvasBbox() {
|
|
| 1800 |
if (!file || !file.type.startsWith('image/')) return;
|
| 1801 |
const reader = new FileReader();
|
| 1802 |
reader.onload = (event) => {
|
| 1803 |
-
|
| 1804 |
-
const img = new window.Image();
|
| 1805 |
-
img.crossOrigin = 'anonymous';
|
| 1806 |
-
img.onload = () => {
|
| 1807 |
-
baseImg = img;
|
| 1808 |
-
boxes.length = 0;
|
| 1809 |
-
window.__bboxBoxes = boxes;
|
| 1810 |
-
selectedIdx = -1;
|
| 1811 |
-
fitSize(img.naturalWidth, img.naturalHeight);
|
| 1812 |
-
syncToGradio(); redraw(); hideStatus();
|
| 1813 |
-
uploadPrompt.style.display = 'none';
|
| 1814 |
-
syncImageToGradio(dataUrl);
|
| 1815 |
-
};
|
| 1816 |
-
img.src = dataUrl;
|
| 1817 |
};
|
| 1818 |
reader.readAsDataURL(file);
|
| 1819 |
}
|
|
@@ -2021,6 +2119,54 @@ function initCanvasBbox() {
|
|
| 2021 |
});
|
| 2022 |
}
|
| 2023 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2024 |
new ResizeObserver(() => {
|
| 2025 |
if (baseImg) { fitSize(baseImg.naturalWidth, baseImg.naturalHeight); redraw(); }
|
| 2026 |
}).observe(wrap);
|
|
@@ -2300,6 +2446,34 @@ with gr.Blocks() as demo:
|
|
| 2300 |
<kbd>Reset</kbd> removes image
|
| 2301 |
</div>
|
| 2302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2303 |
<div class="json-panel">
|
| 2304 |
<div class="json-panel-title">Bounding Boxes</div>
|
| 2305 |
<div class="json-panel-content" id="bbox-json-content">[
|
|
@@ -2435,5 +2609,8 @@ with gr.Blocks() as demo:
|
|
| 2435 |
if __name__ == "__main__":
|
| 2436 |
demo.launch(
|
| 2437 |
css=css,
|
| 2438 |
-
mcp_server=True,
|
|
|
|
|
|
|
|
|
|
| 2439 |
)
|
|
|
|
| 614 |
color:#FF69B4;
|
| 615 |
}
|
| 616 |
|
| 617 |
+
/* ── Examples Section ── */
|
| 618 |
+
.examples-section{
|
| 619 |
+
background:#141416;
|
| 620 |
+
border-top:1px solid #27272a;
|
| 621 |
+
padding:12px 16px 14px;
|
| 622 |
+
}
|
| 623 |
+
.examples-title{
|
| 624 |
+
font-size:12px;
|
| 625 |
+
font-weight:600;
|
| 626 |
+
color:#71717a;
|
| 627 |
+
text-transform:uppercase;
|
| 628 |
+
letter-spacing:.8px;
|
| 629 |
+
margin-bottom:10px;
|
| 630 |
+
display:flex;
|
| 631 |
+
align-items:center;
|
| 632 |
+
gap:8px;
|
| 633 |
+
}
|
| 634 |
+
.examples-title::before{
|
| 635 |
+
content:'\u25c6';
|
| 636 |
+
color:#FF1493;
|
| 637 |
+
font-size:10px;
|
| 638 |
+
}
|
| 639 |
+
.examples-grid{
|
| 640 |
+
display:flex;
|
| 641 |
+
gap:10px;
|
| 642 |
+
overflow-x:auto;
|
| 643 |
+
padding-bottom:4px;
|
| 644 |
+
}
|
| 645 |
+
.examples-grid::-webkit-scrollbar{height:4px}
|
| 646 |
+
.examples-grid::-webkit-scrollbar-track{background:transparent}
|
| 647 |
+
.examples-grid::-webkit-scrollbar-thumb{background:#27272a;border-radius:2px}
|
| 648 |
+
.example-card{
|
| 649 |
+
flex:0 0 auto;
|
| 650 |
+
width:120px;
|
| 651 |
+
cursor:pointer;
|
| 652 |
+
border-radius:10px;
|
| 653 |
+
border:2px solid #27272a;
|
| 654 |
+
overflow:hidden;
|
| 655 |
+
background:#09090b;
|
| 656 |
+
transition:all .2s ease;
|
| 657 |
+
display:flex;
|
| 658 |
+
flex-direction:column;
|
| 659 |
+
user-select:none;
|
| 660 |
+
}
|
| 661 |
+
.example-card:hover{
|
| 662 |
+
border-color:#FF1493;
|
| 663 |
+
transform:translateY(-2px);
|
| 664 |
+
box-shadow:0 6px 20px rgba(255,20,147,.25);
|
| 665 |
+
}
|
| 666 |
+
.example-card:active{
|
| 667 |
+
transform:translateY(0);
|
| 668 |
+
border-color:#FF69B4;
|
| 669 |
+
}
|
| 670 |
+
.example-card.loading{
|
| 671 |
+
opacity:0.5;
|
| 672 |
+
pointer-events:none;
|
| 673 |
+
}
|
| 674 |
+
.example-card.loading .example-label{
|
| 675 |
+
color:#FF69B4;
|
| 676 |
+
}
|
| 677 |
+
.example-card .example-thumb{
|
| 678 |
+
width:100%;
|
| 679 |
+
height:80px;
|
| 680 |
+
object-fit:cover;
|
| 681 |
+
display:block;
|
| 682 |
+
background:#09090b;
|
| 683 |
+
}
|
| 684 |
+
.example-card .example-thumb-placeholder{
|
| 685 |
+
width:100%;
|
| 686 |
+
height:80px;
|
| 687 |
+
display:flex;
|
| 688 |
+
align-items:center;
|
| 689 |
+
justify-content:center;
|
| 690 |
+
background:linear-gradient(135deg,#1a1a20 0%,#0f0f13 100%);
|
| 691 |
+
color:#3f3f46;
|
| 692 |
+
font-size:24px;
|
| 693 |
+
}
|
| 694 |
+
.example-card .example-label{
|
| 695 |
+
display:block;
|
| 696 |
+
padding:6px 8px;
|
| 697 |
+
font-size:11px;
|
| 698 |
+
font-weight:600;
|
| 699 |
+
color:#a1a1aa;
|
| 700 |
+
text-align:center;
|
| 701 |
+
white-space:nowrap;
|
| 702 |
+
overflow:hidden;
|
| 703 |
+
text-overflow:ellipsis;
|
| 704 |
+
border-top:1px solid #27272a;
|
| 705 |
+
background:#0d0d10;
|
| 706 |
+
}
|
| 707 |
+
|
| 708 |
/* ── JSON Panel ── */
|
| 709 |
.json-panel{
|
| 710 |
background:#18181b;
|
|
|
|
| 814 |
80%{transform:translateX(3px)}
|
| 815 |
}
|
| 816 |
|
| 817 |
+
/* ── Primary Button ── */
|
| 818 |
.btn-run{
|
| 819 |
display:flex;align-items:center;justify-content:center;gap:8px;
|
| 820 |
width:100%;
|
|
|
|
| 913 |
fill:#ffffff!important;
|
| 914 |
}
|
| 915 |
|
| 916 |
+
/* ── Comprehensive white-force for run button ── */
|
| 917 |
#custom-run-btn,
|
| 918 |
#custom-run-btn *,
|
| 919 |
#custom-run-btn span,
|
|
|
|
| 927 |
fill:#ffffff!important;
|
| 928 |
}
|
| 929 |
|
| 930 |
+
/* ── Mode button active state ── */
|
| 931 |
.mode-btn.active,
|
| 932 |
.mode-btn.active *,
|
| 933 |
.mode-btn.active span,
|
|
|
|
| 1225 |
::-webkit-scrollbar-thumb{background:#27272a;border-radius:4px}
|
| 1226 |
::-webkit-scrollbar-thumb:hover{background:#3f3f46}
|
| 1227 |
|
| 1228 |
+
/* ══════════════════════════════════════════════
|
| 1229 |
+
FORCE WHITE on Run Button + Mode Buttons
|
| 1230 |
+
══════════════════════════════════════════════ */
|
| 1231 |
|
| 1232 |
body:not(.dark) .btn-run,
|
| 1233 |
body:not(.dark) .btn-run *,
|
|
|
|
| 1326 |
.app-main-right{width:100%}
|
| 1327 |
.app-main-left{border-right:none;border-bottom:1px solid #27272a}
|
| 1328 |
.mode-switcher{flex-wrap:wrap}
|
| 1329 |
+
.examples-grid{gap:8px}
|
| 1330 |
+
.example-card{width:100px}
|
| 1331 |
+
.example-card .example-thumb{height:64px}
|
| 1332 |
}
|
| 1333 |
"""
|
| 1334 |
|
|
|
|
| 1739 |
}
|
| 1740 |
function hideStatus() { status.style.display = 'none'; }
|
| 1741 |
|
| 1742 |
+
/* ── Shared image loader (used by file input, drag-drop, examples) ── */
|
| 1743 |
+
function loadImageFromDataUrl(dataUrl) {
|
| 1744 |
+
const img = new window.Image();
|
| 1745 |
+
img.crossOrigin = 'anonymous';
|
| 1746 |
+
img.onload = () => {
|
| 1747 |
+
baseImg = img;
|
| 1748 |
+
boxes.length = 0;
|
| 1749 |
+
window.__bboxBoxes = boxes;
|
| 1750 |
+
selectedIdx = -1;
|
| 1751 |
+
fitSize(img.naturalWidth, img.naturalHeight);
|
| 1752 |
+
syncToGradio(); redraw(); hideStatus();
|
| 1753 |
+
uploadPrompt.style.display = 'none';
|
| 1754 |
+
syncImageToGradio(dataUrl);
|
| 1755 |
+
};
|
| 1756 |
+
img.src = dataUrl;
|
| 1757 |
+
}
|
| 1758 |
+
|
| 1759 |
function resetCanvas() {
|
| 1760 |
baseImg = null;
|
| 1761 |
boxes.length = 0;
|
|
|
|
| 1911 |
if (!file || !file.type.startsWith('image/')) return;
|
| 1912 |
const reader = new FileReader();
|
| 1913 |
reader.onload = (event) => {
|
| 1914 |
+
loadImageFromDataUrl(event.target.result);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1915 |
};
|
| 1916 |
reader.readAsDataURL(file);
|
| 1917 |
}
|
|
|
|
| 2119 |
});
|
| 2120 |
}
|
| 2121 |
|
| 2122 |
+
/* ── Example Cards Click Handler ── */
|
| 2123 |
+
function loadExampleFromUrl(url, cardEl) {
|
| 2124 |
+
if (cardEl) {
|
| 2125 |
+
cardEl.classList.add('loading');
|
| 2126 |
+
const lbl = cardEl.querySelector('.example-label');
|
| 2127 |
+
if (lbl) lbl.textContent = 'Loading\u2026';
|
| 2128 |
+
}
|
| 2129 |
+
showStatus('Loading example\u2026');
|
| 2130 |
+
|
| 2131 |
+
fetch(url)
|
| 2132 |
+
.then(r => {
|
| 2133 |
+
if (!r.ok) throw new Error('HTTP ' + r.status);
|
| 2134 |
+
return r.blob();
|
| 2135 |
+
})
|
| 2136 |
+
.then(blob => {
|
| 2137 |
+
const reader = new FileReader();
|
| 2138 |
+
reader.onload = (event) => {
|
| 2139 |
+
loadImageFromDataUrl(event.target.result);
|
| 2140 |
+
if (cardEl) {
|
| 2141 |
+
cardEl.classList.remove('loading');
|
| 2142 |
+
const lbl = cardEl.querySelector('.example-label');
|
| 2143 |
+
if (lbl) lbl.textContent = cardEl.getAttribute('data-label') || 'Example';
|
| 2144 |
+
}
|
| 2145 |
+
showStatus('Example loaded');
|
| 2146 |
+
setTimeout(hideStatus, 1500);
|
| 2147 |
+
window.showToast('Example image loaded. Draw bounding boxes and click Run.', 'success', 'Image Ready');
|
| 2148 |
+
};
|
| 2149 |
+
reader.readAsDataURL(blob);
|
| 2150 |
+
})
|
| 2151 |
+
.catch(err => {
|
| 2152 |
+
console.error('Failed to load example:', err);
|
| 2153 |
+
if (cardEl) {
|
| 2154 |
+
cardEl.classList.remove('loading');
|
| 2155 |
+
const lbl = cardEl.querySelector('.example-label');
|
| 2156 |
+
if (lbl) lbl.textContent = cardEl.getAttribute('data-label') || 'Example';
|
| 2157 |
+
}
|
| 2158 |
+
hideStatus();
|
| 2159 |
+
window.showToast('Could not load example image. Make sure example files exist in the <b>examples/</b> folder.', 'error', 'Load Failed');
|
| 2160 |
+
});
|
| 2161 |
+
}
|
| 2162 |
+
|
| 2163 |
+
document.querySelectorAll('.example-card').forEach(card => {
|
| 2164 |
+
card.addEventListener('click', () => {
|
| 2165 |
+
const src = card.getAttribute('data-src');
|
| 2166 |
+
if (src) loadExampleFromUrl(src, card);
|
| 2167 |
+
});
|
| 2168 |
+
});
|
| 2169 |
+
|
| 2170 |
new ResizeObserver(() => {
|
| 2171 |
if (baseImg) { fitSize(baseImg.naturalWidth, baseImg.naturalHeight); redraw(); }
|
| 2172 |
}).observe(wrap);
|
|
|
|
| 2446 |
<kbd>Reset</kbd> removes image
|
| 2447 |
</div>
|
| 2448 |
|
| 2449 |
+
<!-- ── Quick Examples Section ── -->
|
| 2450 |
+
<div class="examples-section">
|
| 2451 |
+
<div class="examples-title">Quick Examples — Click to Load</div>
|
| 2452 |
+
<div class="examples-grid">
|
| 2453 |
+
<div class="example-card" data-src="/file=examples/1.jpg" data-label="Example 1">
|
| 2454 |
+
<img class="example-thumb" src="/file=examples/1.jpg" alt="Example 1" loading="lazy"
|
| 2455 |
+
onerror="this.style.display='none';this.nextElementSibling.style.display='flex'"
|
| 2456 |
+
/>
|
| 2457 |
+
<div class="example-thumb-placeholder" style="display:none">\U0001f5bc</div>
|
| 2458 |
+
<span class="example-label">Example 1</span>
|
| 2459 |
+
</div>
|
| 2460 |
+
<div class="example-card" data-src="/file=examples/2.jpg" data-label="Example 2">
|
| 2461 |
+
<img class="example-thumb" src="/file=examples/2.jpg" alt="Example 2" loading="lazy"
|
| 2462 |
+
onerror="this.style.display='none';this.nextElementSibling.style.display='flex'"
|
| 2463 |
+
/>
|
| 2464 |
+
<div class="example-thumb-placeholder" style="display:none">\U0001f5bc</div>
|
| 2465 |
+
<span class="example-label">Example 2</span>
|
| 2466 |
+
</div>
|
| 2467 |
+
<div class="example-card" data-src="/file=examples/3.jpg" data-label="Example 3">
|
| 2468 |
+
<img class="example-thumb" src="/file=examples/3.jpg" alt="Example 3" loading="lazy"
|
| 2469 |
+
onerror="this.style.display='none';this.nextElementSibling.style.display='flex'"
|
| 2470 |
+
/>
|
| 2471 |
+
<div class="example-thumb-placeholder" style="display:none">\U0001f5bc</div>
|
| 2472 |
+
<span class="example-label">Example 3</span>
|
| 2473 |
+
</div>
|
| 2474 |
+
</div>
|
| 2475 |
+
</div>
|
| 2476 |
+
|
| 2477 |
<div class="json-panel">
|
| 2478 |
<div class="json-panel-title">Bounding Boxes</div>
|
| 2479 |
<div class="json-panel-content" id="bbox-json-content">[
|
|
|
|
| 2609 |
if __name__ == "__main__":
|
| 2610 |
demo.launch(
|
| 2611 |
css=css,
|
| 2612 |
+
mcp_server=True,
|
| 2613 |
+
ssr_mode=False,
|
| 2614 |
+
show_error=True,
|
| 2615 |
+
allowed_paths=["examples"],
|
| 2616 |
)
|