File size: 17,962 Bytes
7a629bd
 
 
 
 
 
 
 
 
 
 
 
ac72ab2
 
401d107
ac72ab2
 
7a629bd
 
 
 
 
 
 
 
 
401d107
7a629bd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
)