File size: 3,752 Bytes
af7647d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import gradio as gr
from ultralytics import YOLO
from PIL import Image
import os
from huggingface_hub import hf_hub_download
import numpy as np

# --- 1. SETUP & MODEL LOADING ---
# We download the model securely at startup
MODEL_REPO = "youkii-xr/hieroglyphic-detection" # <--- REPLACE THIS
MODEL_FILENAME = "best.pt"

print(f"Attempting to download {MODEL_FILENAME} from {MODEL_REPO}...")

try:
    model_path = hf_hub_download(
        repo_id=MODEL_REPO,
        filename=MODEL_FILENAME,
        token=os.environ.get("HF_TOKEN") # Needs 'HF_TOKEN' secret in Space settings
    )
    print(f"Model downloaded to: {model_path}")
    model = YOLO(model_path)
except Exception as e:
    print(f"CRITICAL ERROR loading model: {e}")
    model = None

# --- 2. DETECTION LOGIC ---
# NOTE: Type hints (image: Image.Image) and Docstrings are MANDATORY for MCP
def detect_hieroglyphs(image: Image.Image, conf_threshold: float = 0.25):
    """
    Detects Egyptian hieroglyph symbols in an image.
    
    Args:
        image: The image to analyze (uploaded file).
        conf_threshold: Confidence threshold for detection (default 0.25).
    
    Returns:
        A tuple containing the annotated image with bounding boxes and a JSON summary of findings.
    """
    if image is None:
        return None, {"error": "No image provided"}
    
    if model is None:
        return None, {"error": "Model failed to load on server."}

    try:
        # Run Inference
        results = model.predict(
            source=image,
            conf=conf_threshold,
            iou=0.45,
            imgsz=640,
            verbose=False,
            device='cpu', # Spaces usually run on CPU unless you pay for GPU
            max_det=300
        )
        
        # 1. Generate Visual Output
        # plot() returns BGR numpy array, convert to RGB PIL
        annotated_array = results[0].plot() 
        annotated_image = Image.fromarray(annotated_array[..., ::-1])
        
        # 2. Generate Data Output (JSON)
        detections = []
        gardiner_counts = {}
        
        for box in results[0].boxes:
            if box.cls.numel() > 0:
                cls_id = int(box.cls[0])
                if 0 <= cls_id < len(model.names):
                    code = model.names[cls_id]
                    conf = float(box.conf[0])
                    
                    if code not in gardiner_counts: gardiner_counts[code] = 0
                    gardiner_counts[code] += 1
                    
                    detections.append({
                        "code": code,
                        "confidence": round(conf, 2),
                        # Convert bbox to list for JSON serialization
                        "box": [round(x, 1) for x in box.xyxy[0].cpu().numpy().tolist()]
                    })

        summary = {
            "status": "success",
            "total_detected": len(detections),
            "unique_symbols": list(gardiner_counts.keys()),
            "counts": gardiner_counts
        }
        
        return annotated_image, summary

    except Exception as e:
        print(f"Error during inference: {e}")
        return None, {"error": str(e)}

# --- 3. INTERFACE & SERVER ---
# mcp_server=True creates the endpoint automatically
demo = gr.Interface(
    fn=detect_hieroglyphs,
    inputs=[
        gr.Image(type="pil", label="Upload Image"),
        gr.Number(value=0.25, label="Confidence Threshold")
    ],
    outputs=[
        gr.Image(label="Annotated Result"),
        gr.JSON(label="Detection Data")
    ],
    title="Egyptian Hieroglyph MCP Server",
    description="MCP-compatible server for Hieroglyph Detection. Connect this to Claude Desktop."
)

if __name__ == "__main__":
    demo.launch(mcp_server=True)