anttirauhala's picture
Update app.py
401d107 verified
import base64
import io
import gradio as gr
from ultralytics import YOLO
import numpy as np
import cv2
from PIL import Image
import traceback
import json
import os
from huggingface_hub import hf_hub_download
from huggingface_hub import login
login(token = os.environ["HUGGINGFACE_TOKEN"],add_to_git_credential=True)
# In a Hugging Face Space, authentication is handled by the environment
# No need to explicitly set a token in the Space environment
try:
# Try to download the model from Hugging Face Hub
print("Downloading model from Hugging Face Hub...")
try:
# First try with force_download
model_path = hf_hub_download(repo_id="tech4humans/yolov8s-signature-detector",
filename="yolov8s.pt",
force_download=True) # Force download for Space environment
except Exception as force_error:
print(f"Force download failed: {str(force_error)}")
# Try again without force_download
model_path = hf_hub_download(repo_id="tech4humans/yolov8s-signature-detector",
filename="yolov8s.pt",
force_download=False)
# Load the model from the downloaded path
model = YOLO(model_path)
print(f"Signature detector model loaded successfully from: {model_path}")
except Exception as e:
print(f"Error downloading/loading model: {str(e)}")
print("Falling back to default YOLOv8 model...")
try:
# Fallback to standard model
model = YOLO("yolov8s.pt")
print("Standard YOLOv8 model loaded successfully as fallback!")
except Exception as fallback_error:
print(f"Error loading fallback model: {str(fallback_error)}")
traceback.print_exc()
raise
def preprocess_image(image):
"""Convert image to correct format for YOLO."""
if image is None:
# Return a blank image if None is provided
blank_image = np.zeros((100, 100, 3), dtype=np.uint8)
return blank_image
elif isinstance(image, str):
# If image is a file path
return cv2.imread(image)
elif isinstance(image, np.ndarray):
# If image is already a numpy array
if len(image.shape) == 2: # Grayscale
return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
elif image.shape[2] == 4: # RGBA
return cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
return image
elif isinstance(image, Image.Image):
# If image is a PIL Image
return np.array(image)
# Added support for base64 encoded images
elif isinstance(image, str) and image.startswith('data:image'):
try:
# Extract base64 part
encoded_data = image.split(',')[1]
binary_data = base64.b64decode(encoded_data)
image = Image.open(io.BytesIO(binary_data))
return np.array(image)
except Exception as e:
print(f"Error decoding base64 image: {str(e)}")
raise
else:
raise ValueError(f"Unsupported image type: {type(image)}")
def detect_signature(image):
try:
if image is None:
# Return empty results for None input
blank_image = np.zeros((100, 100, 3), dtype=np.uint8)
return blank_image, []
# Handle both regular images and base64 encoded ones
processed_image = preprocess_image(image)
# Save the processed image to a temporary file if it's not already a file path
image_path = None
if not isinstance(image, str) or not image.startswith('http'):
temp_img = Image.fromarray(processed_image)
image_path = 'temp_image.jpg'
temp_img.save(image_path)
else:
image_path = image
# Run prediction using the direct approach
results = model.predict(source=image_path, save=False, verbose=False)
if not results or len(results) == 0:
return processed_image, []
# Process results
result = results[0]
output = []
if hasattr(result, 'boxes'):
for box in result.boxes:
try:
conf = float(box.conf[0])
cls = int(box.cls[0])
class_name = model.names[cls]
if conf > 0.3: # Confidence threshold
output.append({
"confidence": round(conf, 3),
"label": class_name
})
except Exception as e:
print(f"Error processing box: {str(e)}")
traceback.print_exc()
continue
# Use the plotted image with annotations
annotated_image = result.plot()
return annotated_image, output
except Exception as e:
print(f"Error in detect_signature: {str(e)}")
traceback.print_exc()
# Return original image and empty results in case of error
if image is None:
return np.zeros((100, 100, 3), dtype=np.uint8), []
return image, []
# Add a direct API endpoint for our Node.js server
def api_detect_signature(image_data):
"""API endpoint for direct signature detection without UI"""
try:
# Handle None input
if image_data is None:
return {"success": False, "error": "No image data provided"}
# If data is base64 encoded
if isinstance(image_data, str) and image_data.startswith('data:image'):
# Use the existing function
result_img, detections = detect_signature(image_data)
# Convert result image to base64 for API response
buffered = io.BytesIO()
Image.fromarray(result_img).save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return {
"success": True,
"detections": detections,
"annotated_image": f"data:image/jpeg;base64,{img_str}"
}
else:
return {"success": False, "error": "Invalid image format. Send base64 encoded image."}
except Exception as e:
print(f"Error in api_detect_signature: {str(e)}")
traceback.print_exc()
return {"success": False, "error": str(e)}
# Create Gradio interface
interface = gr.Interface(
fn=detect_signature,
inputs=gr.Image(type="filepath", label="Upload an image"),
outputs=[
gr.Image(label="Detected Signatures"),
gr.JSON(label="Detection Results")
],
title="Signature Detector",
description="Upload an image to detect signatures",
examples=[
["temp_image.jpg"] if os.path.exists("temp_image.jpg") else None
],
flagging_mode="never",
cache_examples=True
)
# Create a dedicated API endpoint for direct access
api_interface = gr.Interface(
fn=api_detect_signature,
inputs=gr.Textbox(label="Base64 Image", placeholder="data:image/jpeg;base64,..."),
outputs=gr.JSON(label="API Response"),
title="Signature Detection API",
description="For programmatic access",
flagging_mode="never",
examples=[
["data:image/jpeg;base64,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"] if os.path.exists("temp_image.jpg") else None
]
)
# Create a Gradio Blocks app that includes both interfaces
with gr.Blocks() as app:
gr.Markdown("# Signature Detection Demo")
with gr.Tab("Interactive Demo"):
interface.render()
with gr.Tab("API Access"):
api_interface.render()
gr.Markdown("""
## API Usage Instructions
You can use this API endpoint from your applications by sending a POST request:
### Method 1 (Latest Gradio API, recommended):
```
POST /predict
{
"data": ["data:image/jpeg;base64,your_base64_encoded_image"]
}
```
### Method 2 (Standard API):
```
POST /api/predict
{
"data": ["data:image/jpeg;base64,your_base64_encoded_image"]
}
```
### Method 3 (Legacy format):
```
POST /run/predict
{
"fn_index": 0,
"data": ["data:image/jpeg;base64,your_base64_encoded_image"]
}
```
The response will contain detection results and an annotated image.
See README-API.md for more details.
""")
# Launch with specific configs for API access
# In Hugging Face Spaces, use Gradio's default launcher settings
app.launch(
server_name="0.0.0.0", # Bind to all network interfaces
show_api=True, # Enable API endpoints
allowed_paths=["*.jpg", "*.png", "*.jpeg"] # Allow access to image files
)