youkii-xr commited on
Commit
af7647d
·
verified ·
1 Parent(s): bd4a78d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -0
app.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from ultralytics import YOLO
3
+ 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
+ # We download the model securely at startup
10
+ MODEL_REPO = "youkii-xr/hieroglyphic-detection" # <--- REPLACE THIS
11
+ MODEL_FILENAME = "best.pt"
12
+
13
+ print(f"Attempting to download {MODEL_FILENAME} from {MODEL_REPO}...")
14
+
15
+ try:
16
+ model_path = hf_hub_download(
17
+ repo_id=MODEL_REPO,
18
+ filename=MODEL_FILENAME,
19
+ token=os.environ.get("HF_TOKEN") # Needs 'HF_TOKEN' secret in Space settings
20
+ )
21
+ print(f"Model downloaded to: {model_path}")
22
+ model = YOLO(model_path)
23
+ except Exception as e:
24
+ print(f"CRITICAL ERROR loading model: {e}")
25
+ model = None
26
+
27
+ # --- 2. DETECTION LOGIC ---
28
+ # NOTE: Type hints (image: Image.Image) and Docstrings are MANDATORY for MCP
29
+ def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
30
+ """
31
+ Detects Egyptian hieroglyph symbols in an image.
32
+
33
+ Args:
34
+ image: The image to analyze (uploaded file).
35
+ conf_threshold: Confidence threshold for detection (default 0.25).
36
+
37
+ Returns:
38
+ A tuple containing the annotated image with bounding boxes and a JSON summary of findings.
39
+ """
40
+ if image is None:
41
+ return None, {"error": "No image provided"}
42
+
43
+ if model is None:
44
+ return None, {"error": "Model failed to load on server."}
45
+
46
+ try:
47
+ # Run Inference
48
+ results = model.predict(
49
+ source=image,
50
+ conf=conf_threshold,
51
+ iou=0.45,
52
+ imgsz=640,
53
+ verbose=False,
54
+ device='cpu', # Spaces usually run on CPU unless you pay for GPU
55
+ max_det=300
56
+ )
57
+
58
+ # 1. Generate Visual Output
59
+ # plot() returns BGR numpy array, convert to RGB PIL
60
+ annotated_array = results[0].plot()
61
+ annotated_image = Image.fromarray(annotated_array[..., ::-1])
62
+
63
+ # 2. Generate Data Output (JSON)
64
+ detections = []
65
+ gardiner_counts = {}
66
+
67
+ for box in results[0].boxes:
68
+ if box.cls.numel() > 0:
69
+ cls_id = int(box.cls[0])
70
+ if 0 <= cls_id < len(model.names):
71
+ code = model.names[cls_id]
72
+ conf = float(box.conf[0])
73
+
74
+ if code not in gardiner_counts: gardiner_counts[code] = 0
75
+ gardiner_counts[code] += 1
76
+
77
+ detections.append({
78
+ "code": code,
79
+ "confidence": round(conf, 2),
80
+ # Convert bbox to list for JSON serialization
81
+ "box": [round(x, 1) for x in box.xyxy[0].cpu().numpy().tolist()]
82
+ })
83
+
84
+ summary = {
85
+ "status": "success",
86
+ "total_detected": len(detections),
87
+ "unique_symbols": list(gardiner_counts.keys()),
88
+ "counts": gardiner_counts
89
+ }
90
+
91
+ return annotated_image, summary
92
+
93
+ except Exception as e:
94
+ print(f"Error during inference: {e}")
95
+ return None, {"error": str(e)}
96
+
97
+ # --- 3. INTERFACE & SERVER ---
98
+ # mcp_server=True creates the endpoint automatically
99
+ demo = gr.Interface(
100
+ fn=detect_hieroglyphs,
101
+ inputs=[
102
+ gr.Image(type="pil", label="Upload Image"),
103
+ gr.Number(value=0.25, label="Confidence Threshold")
104
+ ],
105
+ outputs=[
106
+ gr.Image(label="Annotated Result"),
107
+ gr.JSON(label="Detection Data")
108
+ ],
109
+ title="Egyptian Hieroglyph MCP Server",
110
+ description="MCP-compatible server for Hieroglyph Detection. Connect this to Claude Desktop."
111
+ )
112
+
113
+ if __name__ == "__main__":
114
+ demo.launch(mcp_server=True)