Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -51,7 +51,6 @@ def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
|
|
| 51 |
|
| 52 |
try:
|
| 53 |
results = model.predict(source=image, conf=conf_threshold, iou=0.45, imgsz=640, verbose=False, device='cpu', max_det=300)
|
| 54 |
-
|
| 55 |
annotated_array = results[0].plot()
|
| 56 |
annotated_image = Image.fromarray(annotated_array[..., ::-1])
|
| 57 |
|
|
@@ -62,7 +61,6 @@ def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
|
|
| 62 |
|
| 63 |
detections = []
|
| 64 |
gardiner_counts = {}
|
| 65 |
-
|
| 66 |
for box in results[0].boxes:
|
| 67 |
if box.cls.numel() > 0:
|
| 68 |
cls_id = int(box.cls[0])
|
|
@@ -85,18 +83,31 @@ def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
|
|
| 85 |
except Exception as e:
|
| 86 |
return None, {"error": str(e)}, f"System Failure: {str(e)}", None
|
| 87 |
|
| 88 |
-
# --- 3. UI STYLING &
|
| 89 |
|
| 90 |
-
# SVG Cursor:
|
| 91 |
-
cursor_url = "url('data:image/svg+xml;base64,
|
| 92 |
|
| 93 |
custom_css = f"""
|
| 94 |
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&display=swap');
|
| 95 |
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
|
| 96 |
|
| 97 |
-
/* --- THEME VARIABLES --- */
|
| 98 |
:root {{
|
| 99 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
--bg-gradient: linear-gradient(135deg, #f0e6d2 0%, #e6dcc3 100%);
|
| 101 |
--card-bg: rgba(255, 255, 255, 0.6);
|
| 102 |
--text-primary: #3d342b;
|
|
@@ -109,32 +120,36 @@ custom_css = f"""
|
|
| 109 |
--glow-color: rgba(139, 69, 19, 0.3);
|
| 110 |
}}
|
| 111 |
|
| 112 |
-
|
| 113 |
-
/* NIGHT MODE (Lapis Lazuli) */
|
| 114 |
-
--bg-gradient: radial-gradient(circle at 50% 0%, #0a0a2e 0%, #000000 100%);
|
| 115 |
-
--card-bg: rgba(15, 15, 35, 0.7);
|
| 116 |
-
--text-primary: #e0e7ff;
|
| 117 |
-
--text-accent: #d4af37;
|
| 118 |
-
--border-color: #d4af37;
|
| 119 |
-
--btn-grad: linear-gradient(135deg, #b8860b 0%, #d4af37 100%);
|
| 120 |
-
--btn-text: #000;
|
| 121 |
-
--info-bg: rgba(212, 175, 55, 0.08);
|
| 122 |
-
--info-border: #d4af37;
|
| 123 |
-
--glow-color: rgba(212, 175, 55, 0.4);
|
| 124 |
-
}}
|
| 125 |
-
|
| 126 |
-
/* --- GLOBAL --- */
|
| 127 |
body, .gradio-container {{
|
| 128 |
background: var(--bg-gradient) !important;
|
| 129 |
font-family: 'Cairo', sans-serif !important;
|
| 130 |
color: var(--text-primary) !important;
|
| 131 |
-
cursor: {cursor_url}
|
| 132 |
-webkit-font-smoothing: antialiased;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
}}
|
| 134 |
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
}}
|
| 139 |
|
| 140 |
/* --- CARDS --- */
|
|
@@ -172,34 +187,18 @@ button.primary-btn:hover {{
|
|
| 172 |
box-shadow: 0 0 25px var(--glow-color);
|
| 173 |
}}
|
| 174 |
|
| 175 |
-
/* Toggle Button
|
| 176 |
button.toggle-btn {{
|
| 177 |
background: transparent !important;
|
| 178 |
border: 1px solid var(--border-color) !important;
|
| 179 |
color: var(--text-accent) !important;
|
| 180 |
-
font-size: 14px !important;
|
| 181 |
padding: 5px 15px !important;
|
|
|
|
| 182 |
}}
|
| 183 |
button.toggle-btn:hover {{
|
| 184 |
background: var(--info-bg) !important;
|
| 185 |
}}
|
| 186 |
|
| 187 |
-
/* --- TYPOGRAPHY --- */
|
| 188 |
-
.card-title {{
|
| 189 |
-
font-family: 'Cairo', sans-serif;
|
| 190 |
-
font-size: 18px;
|
| 191 |
-
font-weight: 700;
|
| 192 |
-
color: var(--text-accent);
|
| 193 |
-
text-transform: uppercase;
|
| 194 |
-
letter-spacing: 2px;
|
| 195 |
-
border-bottom: 1px solid rgba(128,128,128, 0.2);
|
| 196 |
-
padding-bottom: 12px;
|
| 197 |
-
margin-bottom: 18px;
|
| 198 |
-
display: flex;
|
| 199 |
-
align-items: center;
|
| 200 |
-
gap: 8px;
|
| 201 |
-
}}
|
| 202 |
-
|
| 203 |
/* --- GUIDE BOXES --- */
|
| 204 |
.guide-step {{
|
| 205 |
background-color: var(--info-bg);
|
|
@@ -210,7 +209,9 @@ button.toggle-btn:hover {{
|
|
| 210 |
font-family: 'Space Mono', monospace;
|
| 211 |
font-size: 13px;
|
| 212 |
line-height: 1.6;
|
|
|
|
| 213 |
}}
|
|
|
|
| 214 |
.step-number {{
|
| 215 |
color: var(--text-accent);
|
| 216 |
font-weight: bold;
|
|
@@ -327,24 +328,73 @@ claude_json_content = """{
|
|
| 327 |
}"""
|
| 328 |
|
| 329 |
# --- 4. MAIN APP ASSEMBLY ---
|
| 330 |
-
|
| 331 |
-
|
|
|
|
| 332 |
() => {
|
| 333 |
-
|
| 334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
}
|
| 336 |
"""
|
| 337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
with gr.Blocks(title="Rosetta Decoder") as demo:
|
| 339 |
-
# Inject CSS
|
| 340 |
gr.HTML(f"<style>{custom_css}</style>")
|
|
|
|
| 341 |
|
| 342 |
-
# Top Section
|
| 343 |
with gr.Row(elem_classes="header-row"):
|
| 344 |
with gr.Column(scale=4):
|
| 345 |
gr.HTML(header_html)
|
| 346 |
with gr.Column(scale=1):
|
| 347 |
-
#
|
| 348 |
btn_toggle = gr.Button("🌗 Day / Night", elem_classes="toggle-btn")
|
| 349 |
|
| 350 |
gr.HTML(mission_html)
|
|
@@ -379,8 +429,9 @@ with gr.Blocks(title="Rosetta Decoder") as demo:
|
|
| 379 |
gr.Code(value=claude_json_content, language="json", label="claude_desktop_config.json", interactive=False, lines=15)
|
| 380 |
gr.HTML("</div>")
|
| 381 |
|
| 382 |
-
#
|
| 383 |
-
|
|
|
|
| 384 |
|
| 385 |
btn_upload.click(fn=detect_hieroglyphs, inputs=[img_upload, slider_upload], outputs=[out_image, out_json, out_report, btn_download])
|
| 386 |
btn_cam.click(fn=detect_hieroglyphs, inputs=[img_cam, slider_cam], outputs=[out_image, out_json, out_report, btn_download])
|
|
|
|
| 51 |
|
| 52 |
try:
|
| 53 |
results = model.predict(source=image, conf=conf_threshold, iou=0.45, imgsz=640, verbose=False, device='cpu', max_det=300)
|
|
|
|
| 54 |
annotated_array = results[0].plot()
|
| 55 |
annotated_image = Image.fromarray(annotated_array[..., ::-1])
|
| 56 |
|
|
|
|
| 61 |
|
| 62 |
detections = []
|
| 63 |
gardiner_counts = {}
|
|
|
|
| 64 |
for box in results[0].boxes:
|
| 65 |
if box.cls.numel() > 0:
|
| 66 |
cls_id = int(box.cls[0])
|
|
|
|
| 83 |
except Exception as e:
|
| 84 |
return None, {"error": str(e)}, f"System Failure: {str(e)}", None
|
| 85 |
|
| 86 |
+
# --- 3. UI STYLING & ANIMATION ---
|
| 87 |
|
| 88 |
+
# SVG Cursor: Eye of Horus
|
| 89 |
+
cursor_url = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KICA8ZyBmaWxsPSJub25lIiBzdHJva2U9IiNkNGFmMzciIHN0cm9rZS13aWR0aD0iMS41Ij4KICAgIDxwYXRoIGQ9Ik0xNiw4IEM2LDIwIDI2LDIwIDE2LDggWiIgZmlsbD0icmdiYSgyMTIsIDE3NSwgNTUsIDAuMSkiLz4KICAgIDxjaXJjbGUgY3g9IjE2IiBjeT0iMTUiIHI9IjMiIGZpbGw9IiNkNGFmMzciLz4KICAgIDxwYXRoIGQ9Ik0xNiwyMiBMMTYsMjggTDEwLDI4Ii8+CiAgPC9nPgo8L3N2Zz4=')"
|
| 90 |
|
| 91 |
custom_css = f"""
|
| 92 |
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&display=swap');
|
| 93 |
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap');
|
| 94 |
|
|
|
|
| 95 |
:root {{
|
| 96 |
+
/* --- DEFAULT: NIGHT MODE (Since your system is dark) --- */
|
| 97 |
+
--bg-gradient: radial-gradient(circle at 50% 0%, #0a0a2e 0%, #000000 100%);
|
| 98 |
+
--card-bg: rgba(15, 15, 35, 0.7);
|
| 99 |
+
--text-primary: #e0e7ff;
|
| 100 |
+
--text-accent: #d4af37; /* Gold */
|
| 101 |
+
--border-color: #d4af37;
|
| 102 |
+
--btn-grad: linear-gradient(135deg, #b8860b 0%, #d4af37 100%);
|
| 103 |
+
--btn-text: #000;
|
| 104 |
+
--info-bg: rgba(212, 175, 55, 0.08);
|
| 105 |
+
--info-border: #d4af37;
|
| 106 |
+
--glow-color: rgba(212, 175, 55, 0.4);
|
| 107 |
+
}}
|
| 108 |
+
|
| 109 |
+
/* --- LIGHT MODE OVERRIDE CLASS --- */
|
| 110 |
+
body.light-mode {{
|
| 111 |
--bg-gradient: linear-gradient(135deg, #f0e6d2 0%, #e6dcc3 100%);
|
| 112 |
--card-bg: rgba(255, 255, 255, 0.6);
|
| 113 |
--text-primary: #3d342b;
|
|
|
|
| 120 |
--glow-color: rgba(139, 69, 19, 0.3);
|
| 121 |
}}
|
| 122 |
|
| 123 |
+
/* --- GLOBAL SETTINGS --- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
body, .gradio-container {{
|
| 125 |
background: var(--bg-gradient) !important;
|
| 126 |
font-family: 'Cairo', sans-serif !important;
|
| 127 |
color: var(--text-primary) !important;
|
| 128 |
+
cursor: {cursor_url} 16 16, auto !important;
|
| 129 |
-webkit-font-smoothing: antialiased;
|
| 130 |
+
transition: background 0.5s ease; /* Smooth Theme Switch */
|
| 131 |
+
}}
|
| 132 |
+
|
| 133 |
+
button, a, .cursor-pointer {{
|
| 134 |
+
cursor: {cursor_url} 16 16, pointer !important;
|
| 135 |
+
}}
|
| 136 |
+
|
| 137 |
+
/* --- CURSOR TRAIL PARTICLES --- */
|
| 138 |
+
.gold-dust {{
|
| 139 |
+
position: fixed;
|
| 140 |
+
width: 6px;
|
| 141 |
+
height: 6px;
|
| 142 |
+
background: var(--text-accent);
|
| 143 |
+
border-radius: 50%;
|
| 144 |
+
pointer-events: none;
|
| 145 |
+
z-index: 9999;
|
| 146 |
+
animation: fadeDust 0.6s linear forwards;
|
| 147 |
+
box-shadow: 0 0 5px var(--text-accent);
|
| 148 |
}}
|
| 149 |
|
| 150 |
+
@keyframes fadeDust {{
|
| 151 |
+
0% {{ opacity: 1; transform: scale(1); }}
|
| 152 |
+
100% {{ opacity: 0; transform: scale(0); }}
|
| 153 |
}}
|
| 154 |
|
| 155 |
/* --- CARDS --- */
|
|
|
|
| 187 |
box-shadow: 0 0 25px var(--glow-color);
|
| 188 |
}}
|
| 189 |
|
| 190 |
+
/* Toggle Button */
|
| 191 |
button.toggle-btn {{
|
| 192 |
background: transparent !important;
|
| 193 |
border: 1px solid var(--border-color) !important;
|
| 194 |
color: var(--text-accent) !important;
|
|
|
|
| 195 |
padding: 5px 15px !important;
|
| 196 |
+
font-family: 'Space Mono', monospace;
|
| 197 |
}}
|
| 198 |
button.toggle-btn:hover {{
|
| 199 |
background: var(--info-bg) !important;
|
| 200 |
}}
|
| 201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
/* --- GUIDE BOXES --- */
|
| 203 |
.guide-step {{
|
| 204 |
background-color: var(--info-bg);
|
|
|
|
| 209 |
font-family: 'Space Mono', monospace;
|
| 210 |
font-size: 13px;
|
| 211 |
line-height: 1.6;
|
| 212 |
+
color: var(--text-primary);
|
| 213 |
}}
|
| 214 |
+
|
| 215 |
.step-number {{
|
| 216 |
color: var(--text-accent);
|
| 217 |
font-weight: bold;
|
|
|
|
| 328 |
}"""
|
| 329 |
|
| 330 |
# --- 4. MAIN APP ASSEMBLY ---
|
| 331 |
+
|
| 332 |
+
# JS: Toggle Theme AND Add Mouse Trail
|
| 333 |
+
js_code = """
|
| 334 |
() => {
|
| 335 |
+
// 1. Toggle Logic
|
| 336 |
+
const toggleTheme = () => {
|
| 337 |
+
document.body.classList.toggle('light-mode');
|
| 338 |
+
const container = document.querySelector('.gradio-container');
|
| 339 |
+
if (container) container.classList.toggle('light-mode');
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
// 2. Mouse Trail Logic
|
| 343 |
+
const addTrail = () => {
|
| 344 |
+
document.addEventListener('mousemove', function(e) {
|
| 345 |
+
// Rate limit to prevent too many elements
|
| 346 |
+
if (Math.random() > 0.5) return;
|
| 347 |
+
|
| 348 |
+
const dust = document.createElement('div');
|
| 349 |
+
dust.classList.add('gold-dust');
|
| 350 |
+
dust.style.left = e.clientX + 'px';
|
| 351 |
+
dust.style.top = e.clientY + 'px';
|
| 352 |
+
document.body.appendChild(dust);
|
| 353 |
+
|
| 354 |
+
// Remove after animation
|
| 355 |
+
setTimeout(() => {
|
| 356 |
+
dust.remove();
|
| 357 |
+
}, 600);
|
| 358 |
+
});
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
// Initialize
|
| 362 |
+
addTrail();
|
| 363 |
+
|
| 364 |
+
// Return the toggle function for the button click
|
| 365 |
+
return toggleTheme;
|
| 366 |
}
|
| 367 |
"""
|
| 368 |
|
| 369 |
+
# We need to run the trail logic on load, but Gradio JS usually runs on events.
|
| 370 |
+
# We will attach the trail logic to the body load via an HTML script injection.
|
| 371 |
+
trail_script = """
|
| 372 |
+
<script>
|
| 373 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 374 |
+
document.addEventListener('mousemove', (e) => {
|
| 375 |
+
if (Math.random() > 0.7) return; // limit density
|
| 376 |
+
const dust = document.createElement('div');
|
| 377 |
+
dust.classList.add('gold-dust');
|
| 378 |
+
dust.style.left = e.clientX + 'px';
|
| 379 |
+
dust.style.top = e.clientY + 'px';
|
| 380 |
+
document.body.appendChild(dust);
|
| 381 |
+
setTimeout(() => dust.remove(), 600);
|
| 382 |
+
});
|
| 383 |
+
});
|
| 384 |
+
</script>
|
| 385 |
+
"""
|
| 386 |
+
|
| 387 |
with gr.Blocks(title="Rosetta Decoder") as demo:
|
| 388 |
+
# Inject CSS & Trail Script
|
| 389 |
gr.HTML(f"<style>{custom_css}</style>")
|
| 390 |
+
gr.HTML(trail_script)
|
| 391 |
|
| 392 |
+
# Top Section
|
| 393 |
with gr.Row(elem_classes="header-row"):
|
| 394 |
with gr.Column(scale=4):
|
| 395 |
gr.HTML(header_html)
|
| 396 |
with gr.Column(scale=1):
|
| 397 |
+
# JS-based Toggle
|
| 398 |
btn_toggle = gr.Button("🌗 Day / Night", elem_classes="toggle-btn")
|
| 399 |
|
| 400 |
gr.HTML(mission_html)
|
|
|
|
| 429 |
gr.Code(value=claude_json_content, language="json", label="claude_desktop_config.json", interactive=False, lines=15)
|
| 430 |
gr.HTML("</div>")
|
| 431 |
|
| 432 |
+
# Wiring
|
| 433 |
+
# The toggle button triggers a JS function that adds the 'light-mode' class
|
| 434 |
+
btn_toggle.click(None, None, None, js="() => { document.body.classList.toggle('light-mode'); document.querySelector('.gradio-container').classList.toggle('light-mode'); }")
|
| 435 |
|
| 436 |
btn_upload.click(fn=detect_hieroglyphs, inputs=[img_upload, slider_upload], outputs=[out_image, out_json, out_report, btn_download])
|
| 437 |
btn_cam.click(fn=detect_hieroglyphs, inputs=[img_cam, slider_cam], outputs=[out_image, out_json, out_report, btn_download])
|