youkii-xr commited on
Commit
3d7bbf9
·
verified ·
1 Parent(s): de27937

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -125
app.py CHANGED
@@ -4,14 +4,16 @@ from PIL import Image
4
  import os
5
  from huggingface_hub import hf_hub_download
6
  import numpy as np
 
7
 
8
  # --- 1. SETUP & MODEL LOADING ---
9
  MODEL_REPO = "youkii-xr/hieroglyphic-detection"
10
  MODEL_FILENAME = "best.pt"
 
11
  os.environ["YOLO_CONFIG_DIR"] = "/tmp/Ultralytics"
12
 
13
  try:
14
- print("System: Downloading model weights...")
15
  model_path = hf_hub_download(
16
  repo_id=MODEL_REPO,
17
  filename=MODEL_FILENAME,
@@ -23,37 +25,48 @@ except Exception as e:
23
  print(f"Error: {e}")
24
  model = None
25
 
26
- # --- 2. LOGIC ---
27
  def generate_human_report(detections, counts):
 
28
  if not detections:
29
- return "The system detects no intelligible glyphs in this image."
30
 
31
  total = len(detections)
32
  sorted_counts = sorted(counts.items(), key=lambda item: item[1], reverse=True)
33
 
34
- report = f"🔎 ANALYSIS COMPLETE\n"
35
- report += f"-----------------------------------\n"
36
- report += f"Total Glyphs Detected: {total}\n\n"
37
- report += "📝 SYMBOL INVENTORY:\n"
 
38
  for code, count in sorted_counts:
39
- report += f"• Gardiner Code '{code}': {count} instance(s)\n"
40
- report += f"\n-----------------------------------\n"
41
- report += f"CONFIDENCE ASSESSMENT: High\n"
42
- report += f"TRANSLATION STATUS: Ready for context analysis."
 
43
  return report
44
 
45
  def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
46
  if image is None:
47
- return None, None, "Please provide an image input."
48
  if model is None:
49
- return None, {"error": "Model failed"}, "System Error: Model not loaded."
50
 
51
  try:
52
  results = model.predict(source=image, conf=conf_threshold, iou=0.45, imgsz=640, verbose=False, device='cpu', max_det=300)
53
 
 
54
  annotated_array = results[0].plot()
55
  annotated_image = Image.fromarray(annotated_array[..., ::-1])
56
 
 
 
 
 
 
 
 
57
  detections = []
58
  gardiner_counts = {}
59
 
@@ -74,44 +87,54 @@ def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
74
  }
75
 
76
  text_report = generate_human_report(detections, gardiner_counts)
77
- return annotated_image, summary_json, text_report
 
 
78
 
79
  except Exception as e:
80
- return None, {"error": str(e)}, f"Critical Error: {str(e)}"
81
 
82
- # --- 3. THE MYSTICAL UI (CSS) ---
83
 
84
- # Eye of Horus Cursor (SVG Base64)
85
- cursor_url = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KICA8ZyBmaWxsPSJub25lIiBzdHJva2U9IiNkNGFmMzciIHN0cm9rZS13aWR0aD0iMiI+CiAgICA8cGF0aCBkPSZNMTYsOCBDNiwyMCAyNiwyMCAxNiw4IFoiIGZpbGw9InJnYmEoMjEyLCAxNzUsIDU1LCAwLjEpIi8+CiAgICA8cGF0aCBkPSZNMTYsMjIgTDEwLDI4IEwyMiwyOCIvPgogICAgPGNpcmNsZSBjeD0iMTYiIGN5PSIxNSIgcj0iMyIgZmlsbD0iI2Q0YWYzNyIvPgogIDwvZz4KPC9zdmc+')"
86
 
87
  custom_css = f"""
88
  @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap');
89
- @import url('https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap');
90
 
91
- /* --- THEME VARIABLES (DAY vs NIGHT) --- */
92
  :root {{
93
- /* DAY MODE (PAPYRUS) */
94
- --bg-gradient: linear-gradient(135deg, #fdf6e3 0%, #f5e6d3 100%);
95
  --card-bg: rgba(255, 255, 255, 0.6);
96
- --text-primary: #5c4033;
97
- --text-accent: #b8860b;
98
- --border-color: #d4af37;
99
- --warning-bg: rgba(255, 0, 0, 0.05);
100
- --warning-border: #cc0000;
 
 
 
 
101
  }}
102
 
103
  .dark {{
104
- /* NIGHT MODE (LAPIS) */
105
- --bg-gradient: radial-gradient(circle at 50% 0%, #1a1f35 0%, #050510 100%);
106
- --card-bg: rgba(10, 15, 30, 0.7);
107
- --text-primary: #e0e7ff;
108
- --text-accent: #ffd700;
109
  --border-color: #d4af37;
110
- --warning-bg: rgba(255, 99, 71, 0.1);
111
- --warning-border: #ff6b6b;
 
 
 
 
112
  }}
113
 
114
- /* --- GLOBAL --- */
115
  body, .gradio-container {{
116
  background: var(--bg-gradient) !important;
117
  font-family: 'Cinzel', serif !important;
@@ -123,70 +146,84 @@ button, a, .cursor-pointer {{
123
  cursor: {cursor_url} 16 16, pointer !important;
124
  }}
125
 
126
- /* --- CARDS & ANIMATIONS --- */
127
  .card {{
128
  background: var(--card-bg) !important;
129
- border: 1px solid rgba(212, 175, 55, 0.3) !important;
130
- border-radius: 15px;
131
- padding: 20px;
132
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
133
- backdrop-filter: blur(10px);
134
- margin-bottom: 20px;
135
- transition: all 0.4s ease;
136
  }}
137
 
138
- /* HOVER EFFECT: Pulse */
139
  .card:hover {{
140
- transform: translateY(-5px);
141
  border-color: var(--border-color) !important;
142
- box-shadow: 0 0 25px rgba(212, 175, 55, 0.3);
143
- }}
144
-
145
- .card-title {{
146
- font-size: 16px;
147
- font-weight: 700;
148
- color: var(--text-accent);
149
- text-transform: uppercase;
150
- letter-spacing: 2px;
151
- border-bottom: 1px solid rgba(212, 175, 55, 0.2);
152
- padding-bottom: 8px;
153
- margin-bottom: 15px;
154
  }}
155
 
156
  /* --- BUTTONS --- */
157
  button.primary-btn {{
158
- background: linear-gradient(135deg, #b8860b 0%, #d4af37 100%) !important;
159
- border: 1px solid #ffd700 !important;
160
- color: #fff !important;
161
- font-weight: bold !important;
162
- font-family: 'Cinzel', serif !important;
163
  text-transform: uppercase;
164
- letter-spacing: 1px;
165
  transition: all 0.3s ease;
166
  }}
167
-
168
  button.primary-btn:hover {{
169
- transform: scale(1.05);
170
- box-shadow: 0 0 30px rgba(212, 175, 55, 0.8);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }}
172
 
173
- /* --- WARNING BOXES --- */
174
- .warning-box {{
175
- background-color: var(--warning-bg);
176
- border-left: 5px solid var(--warning-border);
177
- padding: 15px;
178
- margin: 10px 0;
179
- border-radius: 0 10px 10px 0;
180
- font-family: 'Courier Prime', monospace;
181
  font-size: 13px;
 
 
 
 
 
 
 
 
 
 
 
182
  }}
183
 
184
- .path-box {{
185
- background: rgba(128, 128, 128, 0.2);
186
  padding: 2px 6px;
187
  border-radius: 4px;
188
- font-weight: bold;
189
  color: var(--text-accent);
 
190
  }}
191
 
192
  /* UI CLEANUP */
@@ -194,53 +231,70 @@ button.primary-btn:hover {{
194
  .report-box textarea {{
195
  background-color: rgba(0,0,0,0.2) !important;
196
  border: 1px solid var(--border-color) !important;
197
- font-family: 'Courier Prime', monospace !important;
198
  color: var(--text-accent) !important;
 
199
  }}
200
  """
201
 
202
  header_html = """
203
- <div style="display: flex; align-items: center; gap: 20px; padding: 20px 0;">
204
- <div style="font-size: 40px;">👁️</div>
205
- <div>
206
- <h1 style="margin: 0; font-size: 32px; color: var(--text-accent);">HORUS VISION</h1>
207
- <p style="margin: 0; font-size: 12px; letter-spacing: 2px; opacity: 0.8;">HIEROGLYPHIC TRANSLATION & PRESERVATION</p>
 
 
 
 
 
 
 
 
208
  </div>
209
  </div>
210
  """
211
 
212
  mission_html = """
213
  <div class="card">
214
- <div class="card-title">📜 MISSION BRIEF</div>
215
- <p style="opacity: 0.9; font-size: 14px; line-height: 1.6;">
216
- <b>To preserve the past is to save the future.</b><br>
217
- This tool uses AI to digitize Ancient Egyptian inscriptions.
218
- <span style="font-size:12px; float:right;">(Hover over cards to see the aura)</span>
 
219
  </p>
220
  </div>
221
  """
222
 
223
  guide_instructions_html = """
224
- <div class="card" style="border-color: var(--warning-border) !important;">
225
- <div class="card-title" style="color: var(--warning-border);">🤖 CLAUDE DESKTOP CONFIGURATION</div>
226
 
227
- <div class="warning-box">
228
- <strong style="font-size:14px; display:block; margin-bottom:5px; color: var(--warning-border);">⚠️ STEP 1: IMAGE FOLDER (CRITICAL)</strong>
229
- Claude Desktop is "sandboxed" (isolated). It cannot see your Desktop or Downloads.<br><br>
230
- 1. Create this EXACT folder: <span class="path-box">C:\\Claude_Work</span><br>
231
- 2. Put your images INSIDE it.<br>
232
- 3. <b>Prompting:</b> "Analyze the image at C:\\Claude_Work\\my_image.jpg"
233
  </div>
234
 
235
- <div class="warning-box" style="border-color: var(--text-accent);">
236
- <strong style="font-size:14px; display:block; margin-bottom:5px; color: var(--text-accent);">🐍 STEP 2: PYTHON PATH</strong>
237
- The code below assumes Python is at <code>C:\\Python313\\python.exe</code>.<br>
238
- If your Python is installed elsewhere, you must change this line in the JSON.<br>
239
- <i>(Run <code>where python</code> in CMD to find your real path).</i>
240
  </div>
241
 
242
- <div style="margin-top: 15px; opacity: 0.9; font-size: 13px;">
243
- <b>FINAL STEP:</b> Copy the JSON below into <code>%APPDATA%\\Claude\\claude_desktop_config.json</code> and RESTART Claude.
 
 
 
 
 
 
 
 
244
  </div>
245
  """
246
 
@@ -268,49 +322,64 @@ claude_json_content = """{
268
  }
269
  }"""
270
 
271
- # --- 4. MAIN APP ---
272
- # NOTE: removed 'theme' argument to prevent errors. Styling is handled by custom_css.
273
- with gr.Blocks(title="Horus Vision") as demo:
274
-
275
- # Inject CSS
276
  gr.HTML(f"<style>{custom_css}</style>")
277
 
278
- # Header
279
  gr.HTML(header_html)
280
  gr.HTML(mission_html)
281
 
282
  # Workspace
283
  with gr.Row():
 
284
  with gr.Column(scale=1):
285
- gr.HTML('<div class="card"><div class="card-title">SOURCE ARTIFACT</div>')
286
  with gr.Tabs():
287
- with gr.TabItem("📜 Upload Scroll"):
288
- img_upload = gr.Image(type="pil", sources=["upload", "clipboard"], label="Upload", height=300)
289
- slider_upload = gr.Slider(0.1, 1.0, 0.25, label="Confidence")
290
- btn_upload = gr.Button("🔮 DECIPHER SCROLL", elem_classes="primary-btn")
291
 
292
- with gr.TabItem("👁️ Divine Sight"):
293
- img_cam = gr.Image(type="pil", sources=["webcam"], label="Camera", height=300)
294
- slider_cam = gr.Slider(0.1, 1.0, 0.25, label="Confidence")
295
- btn_cam = gr.Button("🔮 DECIPHER VISION", elem_classes="primary-btn")
296
  gr.HTML('</div>')
297
 
 
298
  with gr.Column(scale=1):
299
- gr.HTML('<div class="card"><div class="card-title">INTERPRETATION</div>')
300
- out_image = gr.Image(label="Annotated Artifact", interactive=False)
301
- out_report = gr.Textbox(label="Scribe's Report", lines=6, elem_classes="report-box", placeholder="Awaiting input...")
 
 
 
 
302
  with gr.Accordion("Raw Glyph Data (JSON)", open=False):
303
  out_json = gr.JSON(label="JSON Data")
304
  gr.HTML('</div>')
305
 
306
- # Config Section (Footer)
307
  gr.HTML(guide_instructions_html)
308
  gr.Code(value=claude_json_content, language="json", label="claude_desktop_config.json", interactive=False, lines=15)
309
  gr.HTML("</div>")
310
 
311
- # Wiring
312
- btn_upload.click(fn=detect_hieroglyphs, inputs=[img_upload, slider_upload], outputs=[out_image, out_json, out_report])
313
- btn_cam.click(fn=detect_hieroglyphs, inputs=[img_cam, slider_cam], outputs=[out_image, out_json, out_report])
 
 
 
 
 
 
 
 
 
 
 
314
 
315
  if __name__ == "__main__":
316
  demo.launch(mcp_server=True, ssr_mode=False, allowed_paths=["/tmp"])
 
4
  import os
5
  from huggingface_hub import hf_hub_download
6
  import numpy as np
7
+ import tempfile
8
 
9
  # --- 1. SETUP & MODEL LOADING ---
10
  MODEL_REPO = "youkii-xr/hieroglyphic-detection"
11
  MODEL_FILENAME = "best.pt"
12
+ # Fix for the Ultralytics config warning in containers
13
  os.environ["YOLO_CONFIG_DIR"] = "/tmp/Ultralytics"
14
 
15
  try:
16
+ print("System: Initializing Rosetta Decoder Core...")
17
  model_path = hf_hub_download(
18
  repo_id=MODEL_REPO,
19
  filename=MODEL_FILENAME,
 
25
  print(f"Error: {e}")
26
  model = None
27
 
28
+ # --- 2. LOGIC: DECODING & REPORTING ---
29
  def generate_human_report(detections, counts):
30
+ """Generates a natural language summary of the findings."""
31
  if not detections:
32
+ return "Rosetta Decoder detects no identifiable Gardiner codes in this image."
33
 
34
  total = len(detections)
35
  sorted_counts = sorted(counts.items(), key=lambda item: item[1], reverse=True)
36
 
37
+ report = f"🔓 DECODING SEQUENCE COMPLETE\n"
38
+ report += f"===================================\n"
39
+ report += f"Glyph Density: {total} Symbols Identified\n\n"
40
+ report += "🔣 GARDINER CODE INVENTORY:\n"
41
+
42
  for code, count in sorted_counts:
43
+ report += f"• Code [{code}]: {count} instance(s)\n"
44
+
45
+ report += f"\n===================================\n"
46
+ report += f"CONFIDENCE: High\n"
47
+ report += f"STATUS: Digitized & Ready for Translation."
48
  return report
49
 
50
  def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
51
  if image is None:
52
+ return None, None, "Input source required.", None
53
  if model is None:
54
+ return None, {"error": "Model failed"}, "Critical Error: Weights not loaded.", None
55
 
56
  try:
57
  results = model.predict(source=image, conf=conf_threshold, iou=0.45, imgsz=640, verbose=False, device='cpu', max_det=300)
58
 
59
+ # Visual
60
  annotated_array = results[0].plot()
61
  annotated_image = Image.fromarray(annotated_array[..., ::-1])
62
 
63
+ # Save for Download Button
64
+ # We create a temp file so the download button can find it
65
+ temp_dir = tempfile.gettempdir()
66
+ save_path = os.path.join(temp_dir, "rosetta_decoded_result.jpg")
67
+ annotated_image.save(save_path)
68
+
69
+ # Data
70
  detections = []
71
  gardiner_counts = {}
72
 
 
87
  }
88
 
89
  text_report = generate_human_report(detections, gardiner_counts)
90
+
91
+ # Return: Image, JSON, Text, FilePath (for download)
92
+ return annotated_image, summary_json, text_report, save_path
93
 
94
  except Exception as e:
95
+ return None, {"error": str(e)}, f"System Failure: {str(e)}", None
96
 
97
+ # --- 3. UI STYLING (HTML/CSS INJECTION) ---
98
 
99
+ # SVG Cursor: A stylized "Lens"
100
+ cursor_url = "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KICA8ZyBmaWxsPSJub25lIiBzdHJva2U9IiNkNGFmMzciIHN0cm9rZS13aWR0aD0iMS41Ij4KICAgIDxjaXJjbGUgY3g9IjE2IiBjeT0iMTYiIHI9IjgiIGZpbGw9InJnYmEoMjEyLCAxNzUsIDU1LCAwLjEpIi8+CiAgICA8cGF0aCBkPSZNMTYsNCBMMTYsOCIvPgogICAgPHBhdGggZD0iTTE2LDI0IEwxNiwyOCIvPgogICAgPHBhdGggZD0iTTQsMTYgTDgsMTYiLz4KICAgIDxwYXRoIGQ9Ik0yNCwxNiBMMjgsMTYiLz4KICAgIDxjaXJjbGUgY3g9IjE2IiBjeT0iMTYiIHI9IjIiIGZpbGw9IiNkNGFmMzciLz4KICA8L2c+Cjwvc3ZnPg==')"
101
 
102
  custom_css = f"""
103
  @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap');
104
+ @import url('https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');
105
 
106
+ /* --- THEME VARIABLES --- */
107
  :root {{
108
+ /* DAY MODE */
109
+ --bg-gradient: linear-gradient(135deg, #f0e6d2 0%, #e6dcc3 100%);
110
  --card-bg: rgba(255, 255, 255, 0.6);
111
+ --text-primary: #3d342b;
112
+ --text-accent: #8b4513; /* Saddle Brown */
113
+ --border-color: #8b4513;
114
+ --btn-grad: linear-gradient(135deg, #cd853f 0%, #8b4513 100%);
115
+ --btn-text: #fff;
116
+ --glow-color: rgba(139, 69, 19, 0.3);
117
+ /* Guide Box Colors (Golden/Info) */
118
+ --info-bg: rgba(212, 175, 55, 0.1);
119
+ --info-border: #d4af37;
120
  }}
121
 
122
  .dark {{
123
+ /* DARK MODE */
124
+ --bg-gradient: radial-gradient(circle at 50% 0%, #1c1c1c 0%, #0a0a0a 100%);
125
+ --card-bg: rgba(30, 30, 30, 0.7);
126
+ --text-primary: #dcdcdc;
127
+ --text-accent: #d4af37; /* Gold */
128
  --border-color: #d4af37;
129
+ --btn-grad: linear-gradient(135deg, #b8860b 0%, #d4af37 100%);
130
+ --btn-text: #000;
131
+ --glow-color: rgba(212, 175, 55, 0.4);
132
+ /* Guide Box Colors (Golden/Info) */
133
+ --info-bg: rgba(212, 175, 55, 0.1);
134
+ --info-border: #d4af37;
135
  }}
136
 
137
+ /* --- GLOBAL SETTINGS --- */
138
  body, .gradio-container {{
139
  background: var(--bg-gradient) !important;
140
  font-family: 'Cinzel', serif !important;
 
146
  cursor: {cursor_url} 16 16, pointer !important;
147
  }}
148
 
149
+ /* --- ANIMATED CARDS --- */
150
  .card {{
151
  background: var(--card-bg) !important;
152
+ border: 1px solid rgba(128, 128, 128, 0.2) !important;
153
+ border-radius: 12px;
154
+ padding: 24px;
155
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
156
+ backdrop-filter: blur(12px);
157
+ margin-bottom: 24px;
158
+ transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
159
  }}
160
 
 
161
  .card:hover {{
162
+ transform: translateY(-4px);
163
  border-color: var(--border-color) !important;
164
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3), 0 0 15px var(--glow-color);
 
 
 
 
 
 
 
 
 
 
 
165
  }}
166
 
167
  /* --- BUTTONS --- */
168
  button.primary-btn {{
169
+ background: var(--btn-grad) !important;
170
+ border: 1px solid var(--border-color) !important;
171
+ color: var(--btn-text) !important;
172
+ font-weight: 700 !important;
173
+ font-family: 'Space Mono', monospace !important;
174
  text-transform: uppercase;
175
+ letter-spacing: 2px;
176
  transition: all 0.3s ease;
177
  }}
 
178
  button.primary-btn:hover {{
179
+ transform: scale(1.02);
180
+ box-shadow: 0 0 20px var(--glow-color);
181
+ }}
182
+
183
+ /* --- TYPOGRAPHY --- */
184
+ .card-title {{
185
+ font-family: 'Space Mono', monospace;
186
+ font-size: 14px;
187
+ font-weight: 700;
188
+ color: var(--text-accent);
189
+ text-transform: uppercase;
190
+ letter-spacing: 3px;
191
+ border-bottom: 1px solid rgba(128,128,128, 0.2);
192
+ padding-bottom: 12px;
193
+ margin-bottom: 18px;
194
+ display: flex;
195
+ align-items: center;
196
+ gap: 8px;
197
  }}
198
 
199
+ /* --- GOLDEN GUIDE BOXES --- */
200
+ .guide-step {{
201
+ background-color: var(--info-bg);
202
+ border-left: 4px solid var(--info-border);
203
+ padding: 16px;
204
+ margin: 12px 0;
205
+ border-radius: 0 8px 8px 0;
206
+ font-family: 'Space Mono', monospace;
207
  font-size: 13px;
208
+ line-height: 1.6;
209
+ }}
210
+
211
+ .step-number {{
212
+ color: var(--text-accent);
213
+ font-weight: bold;
214
+ text-transform: uppercase;
215
+ display: block;
216
+ margin-bottom: 6px;
217
+ font-size: 11px;
218
+ letter-spacing: 1px;
219
  }}
220
 
221
+ .path-highlight {{
222
+ background: rgba(128,128,128,0.2);
223
  padding: 2px 6px;
224
  border-radius: 4px;
 
225
  color: var(--text-accent);
226
+ font-weight: bold;
227
  }}
228
 
229
  /* UI CLEANUP */
 
231
  .report-box textarea {{
232
  background-color: rgba(0,0,0,0.2) !important;
233
  border: 1px solid var(--border-color) !important;
234
+ font-family: 'Space Mono', monospace !important;
235
  color: var(--text-accent) !important;
236
+ font-size: 13px !important;
237
  }}
238
  """
239
 
240
  header_html = """
241
+ <div style="padding: 20px 0; border-bottom: 1px solid rgba(128,128,128,0.1); margin-bottom: 20px;">
242
+ <div style="display: flex; align-items: center; gap: 15px;">
243
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="var(--text-accent)" stroke-width="2">
244
+ <rect x="3" y="3" width="18" height="18" rx="2" />
245
+ <path d="M7 7h10" />
246
+ <path d="M7 12h10" />
247
+ <path d="M7 17h10" />
248
+ <circle cx="12" cy="12" r="3" stroke="var(--text-accent)" fill="none"/>
249
+ </svg>
250
+ <div>
251
+ <h1 style="margin: 0; font-size: 28px; font-family: 'Cinzel', serif; letter-spacing: 1px; color: var(--text-primary);">ROSETTA DECODER</h1>
252
+ <p style="margin: 0; font-family: 'Space Mono', monospace; font-size: 11px; color: var(--text-accent); letter-spacing: 3px;">AI HIEROGLYPHIC TRANSLATION SYSTEM</p>
253
+ </div>
254
  </div>
255
  </div>
256
  """
257
 
258
  mission_html = """
259
  <div class="card">
260
+ <div class="card-title">📡 VISION STATEMENT</div>
261
+ <p style="opacity: 0.9; font-size: 15px; line-height: 1.8;">
262
+ <b>Bridging the Ancient and the Digital.</b><br>
263
+ The Rosetta Decoder project utilizes advanced computer vision to identify and catalog Ancient Egyptian hieroglyphs.
264
+ By automating the detection of Gardiner codes, we are creating a digital bridge that will eventually allow for instant,
265
+ context-aware translation of Pharaonic wisdom, making the voices of the past accessible to everyone.
266
  </p>
267
  </div>
268
  """
269
 
270
  guide_instructions_html = """
271
+ <div class="card" style="border-color: var(--info-border) !important;">
272
+ <div class="card-title" style="color: var(--info-border) !important;">🤖 CLAUDE DESKTOP SETUP GUIDE</div>
273
 
274
+ <div class="guide-step">
275
+ <span class="step-number">STEP 1: PREPARE WORKSPACE</span>
276
+ Claude is sandboxed. It cannot see your Desktop. You must create a bridge.<br>
277
+ 1. Create this EXACT folder on your PC: <span class="path-highlight">C:\\Claude_Work</span><br>
278
+ 2. Move your hieroglyph images <b>INSIDE</b> this folder.
 
279
  </div>
280
 
281
+ <div class="guide-step">
282
+ <span class="step-number">STEP 2: VERIFY PYTHON</span>
283
+ The code below assumes Python is at: <code>C:\\Python313\\python.exe</code><br>
284
+ <b>Check your path:</b> Open CMD and type <code>where python</code>.<br>
285
+ <i>Note: If your path is different, replace the path in the JSON code block below before copying.</i>
286
  </div>
287
 
288
+ <div class="guide-step">
289
+ <span class="step-number">STEP 3: CONFIGURE CLAUDE</span>
290
+ 1. Open Config: <code>%APPDATA%\\Claude\\claude_desktop_config.json</code><br>
291
+ 2. Paste the JSON below into the <code>"mcpServers"</code> section.<br>
292
+ 3. <b>IMPORTANT:</b> Close Claude from the System Tray (near the clock) and restart it.
293
+ </div>
294
+
295
+ <div class="guide-step">
296
+ <span class="step-number">STEP 4: USAGE</span>
297
+ Prompt Claude: <i>"Analyze the image at C:\\Claude_Work\\my_tablet.jpg"</i>
298
  </div>
299
  """
300
 
 
322
  }
323
  }"""
324
 
325
+ # --- 4. MAIN APP ASSEMBLY ---
326
+ with gr.Blocks(title="Rosetta Decoder") as demo:
327
+ # Inject Styles
 
 
328
  gr.HTML(f"<style>{custom_css}</style>")
329
 
330
+ # Top Section
331
  gr.HTML(header_html)
332
  gr.HTML(mission_html)
333
 
334
  # Workspace
335
  with gr.Row():
336
+ # INPUT COLUMN
337
  with gr.Column(scale=1):
338
+ gr.HTML('<div class="card"><div class="card-title">INPUT IMAGE</div>')
339
  with gr.Tabs():
340
+ with gr.TabItem("📜 Upload File"):
341
+ img_upload = gr.Image(type="pil", sources=["upload", "clipboard"], label="Upload", height=320)
342
+ slider_upload = gr.Slider(0.1, 1.0, 0.25, label="Scan Sensitivity")
343
+ btn_upload = gr.Button("🔍 START DECODING", elem_classes="primary-btn")
344
 
345
+ with gr.TabItem("🎥 Live Camera"):
346
+ img_cam = gr.Image(type="pil", sources=["webcam"], label="Camera", height=320)
347
+ slider_cam = gr.Slider(0.1, 1.0, 0.25, label="Scan Sensitivity")
348
+ btn_cam = gr.Button("🔍 LIVE DECODE", elem_classes="primary-btn")
349
  gr.HTML('</div>')
350
 
351
+ # OUTPUT COLUMN
352
  with gr.Column(scale=1):
353
+ gr.HTML('<div class="card"><div class="card-title">AI ANALYSIS RESULTS</div>')
354
+ out_image = gr.Image(label="Decoded Result", interactive=False)
355
+
356
+ # Download Button (Standard Gradio Component)
357
+ btn_download = gr.DownloadButton("💾 DOWNLOAD RESULT", visible=True)
358
+
359
+ out_report = gr.Textbox(label="Analysis Log", lines=6, elem_classes="report-box", placeholder="Waiting for data stream...")
360
  with gr.Accordion("Raw Glyph Data (JSON)", open=False):
361
  out_json = gr.JSON(label="JSON Data")
362
  gr.HTML('</div>')
363
 
364
+ # Footer Section
365
  gr.HTML(guide_instructions_html)
366
  gr.Code(value=claude_json_content, language="json", label="claude_desktop_config.json", interactive=False, lines=15)
367
  gr.HTML("</div>")
368
 
369
+ # Event Wiring
370
+ # Note: detect_hieroglyphs now returns 4 values: Image, JSON, Text, FilePath
371
+
372
+ btn_upload.click(
373
+ fn=detect_hieroglyphs,
374
+ inputs=[img_upload, slider_upload],
375
+ outputs=[out_image, out_json, out_report, btn_download]
376
+ )
377
+
378
+ btn_cam.click(
379
+ fn=detect_hieroglyphs,
380
+ inputs=[img_cam, slider_cam],
381
+ outputs=[out_image, out_json, out_report, btn_download]
382
+ )
383
 
384
  if __name__ == "__main__":
385
  demo.launch(mcp_server=True, ssr_mode=False, allowed_paths=["/tmp"])