youkii-xr commited on
Commit
149ef76
·
verified ·
1 Parent(s): 305c4ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -19
app.py CHANGED
@@ -54,24 +54,31 @@ def create_labeled_zip(image, detections):
54
  zip_path = os.path.join(tempfile.gettempdir(), "rosetta_glyphs.zip")
55
 
56
  try:
 
57
  try:
 
58
  font = ImageFont.truetype("arial.ttf", 16)
59
  except IOError:
60
  font = ImageFont.load_default()
61
 
62
  for i, d in enumerate(detections):
 
63
  box = d['box']
64
  crop = image.crop((box[0], box[1], box[2], box[3]))
65
 
 
66
  label_text = f"{d['code']} {int(d['confidence']*100)}%"
67
  draw = ImageDraw.Draw(crop)
68
 
 
69
  left, top, right, bottom = draw.textbbox((0, 0), label_text, font=font)
70
  text_w = right - left
71
  text_h = bottom - top
72
 
73
  img_w, img_h = crop.size
74
 
 
 
75
  if img_w > text_w and img_h > text_h:
76
  rect_x0 = img_w - text_w - 4
77
  rect_y0 = img_h - text_h - 4
@@ -81,9 +88,11 @@ def create_labeled_zip(image, detections):
81
  draw.rectangle([rect_x0, rect_y0, rect_x1, rect_y1], fill="black")
82
  draw.text((rect_x0 + 2, rect_y0), label_text, fill="white", font=font)
83
 
 
84
  filename = f"{d['code']}_{i}.png"
85
  crop.save(os.path.join(zip_dir, filename))
86
 
 
87
  shutil.make_archive(zip_path.replace('.zip', ''), 'zip', zip_dir)
88
  return zip_path
89
 
@@ -113,6 +122,7 @@ def core_detect(image, conf_threshold):
113
  conf = float(box.conf[0])
114
  xyxy = box.xyxy[0].tolist()
115
 
 
116
  detection = {
117
  "code": code,
118
  "description": gardiner_map.get(code, "Unknown"),
@@ -120,6 +130,8 @@ def core_detect(image, conf_threshold):
120
  "box": xyxy
121
  }
122
  detections.append(detection)
 
 
123
  crop_img = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
124
  crops.append((crop_img, f"{code}\n({int(conf*100)}%)"))
125
 
@@ -227,9 +239,11 @@ def process_pipeline(image, conf_threshold):
227
  annotated_img, detections, crops = core_detect(image, conf_threshold)
228
 
229
  # 2. Prepare Downloads
 
230
  ann_path = os.path.join(tempfile.gettempdir(), "annotated_hieroglyphs.jpg")
231
  annotated_img.save(ann_path)
232
 
 
233
  zip_path = create_labeled_zip(image, detections)
234
 
235
  # 3. Extract Keywords & Translate
@@ -251,18 +265,16 @@ def process_pipeline(image, conf_threshold):
251
  print(f"Pipeline Error: {e}")
252
  return None, None, None, f"System Failure: {str(e)}", "", None, str(e), None, []
253
 
254
- # --- 6. MCP API FUNCTIONS (RENAMED FOR CLAUDE) ---
255
 
256
- def detect_glyphs(image: Image.Image, conf: float = 0.25) -> Tuple[str, Dict[str, Any]]:
257
- """Detects hieroglyphs in an image. Returns path to annotated image and JSON data."""
258
  ann_img, dets, _ = core_detect(image, conf)
259
  with tempfile.NamedTemporaryFile(dir="/tmp/gradio_results", suffix=".jpg", delete=False) as t:
260
  ann_img.save(t.name)
261
  path = t.name
262
  return path, {"count": len(dets), "detections": dets}
263
 
264
- def translate_story(keywords_text: str) -> Tuple[str, str]:
265
- """Translates a list of codes or keywords into a mystical story and academic text."""
266
  if isinstance(keywords_text, str):
267
  keywords = [k.strip() for k in keywords_text.split(',')]
268
  else:
@@ -271,8 +283,7 @@ def translate_story(keywords_text: str) -> Tuple[str, str]:
271
  clean_mystical = re.sub('<[^<]+?>', '', mystical)
272
  return clean_mystical, academic
273
 
274
- def get_stats(json_data: Dict[str, Any]) -> str:
275
- """Generates analytics charts from detection JSON. Returns path to chart image."""
276
  dets = json_data.get("detections", [])
277
  fig = core_analytics(dets, 640, 640)
278
  if fig is None: return "No data."
@@ -282,8 +293,7 @@ def get_stats(json_data: Dict[str, Any]) -> str:
282
  plt.close(fig)
283
  return path
284
 
285
- def list_codes() -> Dict[str, Any]:
286
- """Returns the full dictionary of supported Gardiner codes and descriptions."""
287
  return gardiner_data
288
 
289
  # --- 7. HTML GENERATORS ---
@@ -392,18 +402,18 @@ guide_html = """
392
  <div class="card-title" style="color: #d4af37;">🤖 CLAUDE DESKTOP SETUP GUIDE</div>
393
  <div class="guide-step"><span class="step-title">STEP 0: PREREQUISITE</span><p>Ensure you have <b>Node.js</b> installed.</p></div>
394
  <div class="guide-step"><span class="step-title">STEP 1: PREPARE WORKSPACE</span>1. Create: <span class="path-highlight">C:\\Claude_Work</span><br>2. Move images inside.</div>
395
- <div class="guide-step"><span class="step-title">STEP 2: CONFIGURE CLAUDE</span>1. Edit: <code>%APPDATA%\\Claude\\claude_desktop_config.json</code><br>2. Paste the JSON below.<br>3. Restart Claude (make sure to completely close from task manager or system tray)</div>
396
  </div>
397
  """
398
 
399
- # CHANGED: "gradio" key changed to "Rosetta Decoder"
400
  claude_json_content = """{
401
  "mcpServers": {
402
- "Rosetta Decoder": {
403
  "command": "npx",
404
  "args": [
405
  "mcp-remote",
406
- "https://mcp-1st-birthday-rosetta-decoder.hf.space/gradio_api/mcp/",
407
  "--transport",
408
  "streamable-http"
409
  ]
@@ -414,7 +424,7 @@ claude_json_content = """{
414
  "-m",
415
  "gradio",
416
  "upload-mcp",
417
- "https://mcp-1st-birthday-rosetta-decoder.hf.space/",
418
  "C:\\\\Claude_Work"
419
  ]
420
  }
@@ -430,19 +440,18 @@ with gr.Blocks(title="Rosetta Decoder Ultimate") as demo:
430
  gr.HTML(trail_script)
431
 
432
  # --- MCP TOOL REGISTRATION LAYER (Hidden) ---
433
- # CHANGED: Renamed API names to be short verbs (detect, translate, etc.)
434
  with gr.Row(visible=False):
435
  btn_detect = gr.Button("Detect")
436
- btn_detect.click(fn=detect_glyphs, inputs=[gr.Image(label="img"), gr.Number(label="conf")], outputs=[gr.Textbox(label="path"), gr.JSON(label="json")], api_name="detect")
437
 
438
  btn_trans = gr.Button("Translate")
439
- btn_trans.click(fn=translate_story, inputs=[gr.Textbox(label="text")], outputs=[gr.Textbox(label="mystic"), gr.Textbox(label="academic")], api_name="translate")
440
 
441
  btn_anal = gr.Button("Analytics")
442
- btn_anal.click(fn=get_stats, inputs=[gr.JSON(label="data")], outputs=[gr.Textbox(label="chart_path")], api_name="analyze")
443
 
444
  btn_list = gr.Button("List")
445
- btn_list.click(fn=list_codes, inputs=[], outputs=[gr.JSON(label="data")], api_name="list_codes")
446
 
447
  # --- Visible UI ---
448
  with gr.Row(elem_classes="header-row"):
 
54
  zip_path = os.path.join(tempfile.gettempdir(), "rosetta_glyphs.zip")
55
 
56
  try:
57
+ # Load a font (try-except block for system compatibility)
58
  try:
59
+ # Try loading a standard font, fallback to default if fails
60
  font = ImageFont.truetype("arial.ttf", 16)
61
  except IOError:
62
  font = ImageFont.load_default()
63
 
64
  for i, d in enumerate(detections):
65
+ # Crop
66
  box = d['box']
67
  crop = image.crop((box[0], box[1], box[2], box[3]))
68
 
69
+ # Prepare Label
70
  label_text = f"{d['code']} {int(d['confidence']*100)}%"
71
  draw = ImageDraw.Draw(crop)
72
 
73
+ # Calculate text size using textbbox (newer PIL versions)
74
  left, top, right, bottom = draw.textbbox((0, 0), label_text, font=font)
75
  text_w = right - left
76
  text_h = bottom - top
77
 
78
  img_w, img_h = crop.size
79
 
80
+ # Draw background rectangle (bottom right)
81
+ # Check if image is too small for label, if so, skip drawing to avoid crash
82
  if img_w > text_w and img_h > text_h:
83
  rect_x0 = img_w - text_w - 4
84
  rect_y0 = img_h - text_h - 4
 
88
  draw.rectangle([rect_x0, rect_y0, rect_x1, rect_y1], fill="black")
89
  draw.text((rect_x0 + 2, rect_y0), label_text, fill="white", font=font)
90
 
91
+ # Save crop
92
  filename = f"{d['code']}_{i}.png"
93
  crop.save(os.path.join(zip_dir, filename))
94
 
95
+ # Create Zip
96
  shutil.make_archive(zip_path.replace('.zip', ''), 'zip', zip_dir)
97
  return zip_path
98
 
 
122
  conf = float(box.conf[0])
123
  xyxy = box.xyxy[0].tolist()
124
 
125
+ # Create detection object
126
  detection = {
127
  "code": code,
128
  "description": gardiner_map.get(code, "Unknown"),
 
130
  "box": xyxy
131
  }
132
  detections.append(detection)
133
+
134
+ # Create crop (Clean crop for Gallery display)
135
  crop_img = image.crop((xyxy[0], xyxy[1], xyxy[2], xyxy[3]))
136
  crops.append((crop_img, f"{code}\n({int(conf*100)}%)"))
137
 
 
239
  annotated_img, detections, crops = core_detect(image, conf_threshold)
240
 
241
  # 2. Prepare Downloads
242
+ # A. Annotated Image
243
  ann_path = os.path.join(tempfile.gettempdir(), "annotated_hieroglyphs.jpg")
244
  annotated_img.save(ann_path)
245
 
246
+ # B. Zip File with Labels
247
  zip_path = create_labeled_zip(image, detections)
248
 
249
  # 3. Extract Keywords & Translate
 
265
  print(f"Pipeline Error: {e}")
266
  return None, None, None, f"System Failure: {str(e)}", "", None, str(e), None, []
267
 
268
+ # --- 6. MCP API FUNCTIONS ---
269
 
270
+ def detect_hieroglyphs_api(image: Image.Image, conf: float = 0.25) -> Tuple[str, Dict[str, Any]]:
 
271
  ann_img, dets, _ = core_detect(image, conf)
272
  with tempfile.NamedTemporaryFile(dir="/tmp/gradio_results", suffix=".jpg", delete=False) as t:
273
  ann_img.save(t.name)
274
  path = t.name
275
  return path, {"count": len(dets), "detections": dets}
276
 
277
+ def translate_codes_api(keywords_text: str) -> Tuple[str, str]:
 
278
  if isinstance(keywords_text, str):
279
  keywords = [k.strip() for k in keywords_text.split(',')]
280
  else:
 
283
  clean_mystical = re.sub('<[^<]+?>', '', mystical)
284
  return clean_mystical, academic
285
 
286
+ def get_analytics_chart_api(json_data: Dict[str, Any]) -> str:
 
287
  dets = json_data.get("detections", [])
288
  fig = core_analytics(dets, 640, 640)
289
  if fig is None: return "No data."
 
293
  plt.close(fig)
294
  return path
295
 
296
+ def list_all_codes_api() -> Dict[str, Any]:
 
297
  return gardiner_data
298
 
299
  # --- 7. HTML GENERATORS ---
 
402
  <div class="card-title" style="color: #d4af37;">🤖 CLAUDE DESKTOP SETUP GUIDE</div>
403
  <div class="guide-step"><span class="step-title">STEP 0: PREREQUISITE</span><p>Ensure you have <b>Node.js</b> installed.</p></div>
404
  <div class="guide-step"><span class="step-title">STEP 1: PREPARE WORKSPACE</span>1. Create: <span class="path-highlight">C:\\Claude_Work</span><br>2. Move images inside.</div>
405
+ <div class="guide-step"><span class="step-title">STEP 2: CONFIGURE CLAUDE</span>1. Edit: <code>%APPDATA%\\Claude\\claude_desktop_config.json</code><br>2. Paste the JSON below.<br>3. Restart Claude.</div>
406
  </div>
407
  """
408
 
409
+ # URL UPDATED TO: youkii-xr/hieroglyph-mcp-server
410
  claude_json_content = """{
411
  "mcpServers": {
412
+ "gradio": {
413
  "command": "npx",
414
  "args": [
415
  "mcp-remote",
416
+ "https://youkii-xr-hieroglyph-mcp-server.hf.space/gradio_api/mcp/",
417
  "--transport",
418
  "streamable-http"
419
  ]
 
424
  "-m",
425
  "gradio",
426
  "upload-mcp",
427
+ "https://youkii-xr-hieroglyph-mcp-server.hf.space/",
428
  "C:\\\\Claude_Work"
429
  ]
430
  }
 
440
  gr.HTML(trail_script)
441
 
442
  # --- MCP TOOL REGISTRATION LAYER (Hidden) ---
 
443
  with gr.Row(visible=False):
444
  btn_detect = gr.Button("Detect")
445
+ btn_detect.click(fn=detect_hieroglyphs_api, inputs=[gr.Image(label="img"), gr.Number(label="conf")], outputs=[gr.Textbox(label="path"), gr.JSON(label="json")], api_name="detect")
446
 
447
  btn_trans = gr.Button("Translate")
448
+ btn_trans.click(fn=translate_codes_api, inputs=[gr.Textbox(label="text")], outputs=[gr.Textbox(label="mystic"), gr.Textbox(label="academic")], api_name="translate")
449
 
450
  btn_anal = gr.Button("Analytics")
451
+ btn_anal.click(fn=get_analytics_chart_api, inputs=[gr.JSON(label="data")], outputs=[gr.Textbox(label="chart_path")], api_name="analytics")
452
 
453
  btn_list = gr.Button("List")
454
+ btn_list.click(fn=list_all_codes_api, inputs=[], outputs=[gr.JSON(label="data")], api_name="list_codes")
455
 
456
  # --- Visible UI ---
457
  with gr.Row(elem_classes="header-row"):