Spaces:
Runtime error
Runtime error
| 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) |