anttirauhala commited on
Commit
7a629bd
·
verified ·
1 Parent(s): 38ab9e6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -20
app.py CHANGED
@@ -1,20 +1,248 @@
1
- import express from 'express';
2
- import dotenv from 'dotenv';
3
- import signatureRoutes from './routes/signatureRoutes';
4
-
5
- // Load environment variables from .env file
6
- dotenv.config();
7
-
8
- const app = express();
9
- const port = process.env.PORT || 3000;
10
-
11
- // Add middleware
12
- app.use(express.json());
13
- app.use(express.static('src/public')); // Serve static files
14
- app.use('/api', signatureRoutes);
15
-
16
- // Start the server
17
- app.listen(port, () => {
18
- console.log(`Server is running on port ${port}`);
19
- console.log(`API endpoint available at: http://localhost:${port}/api/detect-signature`);
20
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import io
3
+ import gradio as gr
4
+ from ultralytics import YOLO
5
+ import numpy as np
6
+ import cv2
7
+ from PIL import Image
8
+ import traceback
9
+ import json
10
+ import os
11
+ from huggingface_hub import hf_hub_download
12
+
13
+ # In a Hugging Face Space, authentication is handled by the environment
14
+ # No need to explicitly set a token in the Space environment
15
+ try:
16
+ # Try to download the model from Hugging Face Hub
17
+ print("Downloading model from Hugging Face Hub...")
18
+ try:
19
+ # First try with force_download
20
+ model_path = hf_hub_download(repo_id="tech4humans/yolov8s-signature-detector",
21
+ filename="yolov8s.pt",
22
+ force_download=True) # Force download for Space environment
23
+ except Exception as force_error:
24
+ print(f"Force download failed: {str(force_error)}")
25
+ # Try again without force_download
26
+ model_path = hf_hub_download(repo_id="tech4humans/yolov8s-signature-detector",
27
+ filename="yolov8s.pt",
28
+ force_download=False)
29
+
30
+ # Load the model from the downloaded path
31
+ model = YOLO(model_path)
32
+ print(f"Signature detector model loaded successfully from: {model_path}")
33
+ except Exception as e:
34
+ print(f"Error downloading/loading model: {str(e)}")
35
+ print("Falling back to default YOLOv8 model...")
36
+ try:
37
+ # Fallback to standard model
38
+ model = YOLO("yolov8s.pt")
39
+ print("Standard YOLOv8 model loaded successfully as fallback!")
40
+ except Exception as fallback_error:
41
+ print(f"Error loading fallback model: {str(fallback_error)}")
42
+ traceback.print_exc()
43
+ raise
44
+
45
+ def preprocess_image(image):
46
+ """Convert image to correct format for YOLO."""
47
+ if image is None:
48
+ # Return a blank image if None is provided
49
+ blank_image = np.zeros((100, 100, 3), dtype=np.uint8)
50
+ return blank_image
51
+ elif isinstance(image, str):
52
+ # If image is a file path
53
+ return cv2.imread(image)
54
+ elif isinstance(image, np.ndarray):
55
+ # If image is already a numpy array
56
+ if len(image.shape) == 2: # Grayscale
57
+ return cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
58
+ elif image.shape[2] == 4: # RGBA
59
+ return cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
60
+ return image
61
+ elif isinstance(image, Image.Image):
62
+ # If image is a PIL Image
63
+ return np.array(image)
64
+ # Added support for base64 encoded images
65
+ elif isinstance(image, str) and image.startswith('data:image'):
66
+ try:
67
+ # Extract base64 part
68
+ encoded_data = image.split(',')[1]
69
+ binary_data = base64.b64decode(encoded_data)
70
+ image = Image.open(io.BytesIO(binary_data))
71
+ return np.array(image)
72
+ except Exception as e:
73
+ print(f"Error decoding base64 image: {str(e)}")
74
+ raise
75
+ else:
76
+ raise ValueError(f"Unsupported image type: {type(image)}")
77
+
78
+ def detect_signature(image):
79
+ try:
80
+ if image is None:
81
+ # Return empty results for None input
82
+ blank_image = np.zeros((100, 100, 3), dtype=np.uint8)
83
+ return blank_image, []
84
+
85
+ # Handle both regular images and base64 encoded ones
86
+ processed_image = preprocess_image(image)
87
+
88
+ # Save the processed image to a temporary file if it's not already a file path
89
+ image_path = None
90
+ if not isinstance(image, str) or not image.startswith('http'):
91
+ temp_img = Image.fromarray(processed_image)
92
+ image_path = 'temp_image.jpg'
93
+ temp_img.save(image_path)
94
+ else:
95
+ image_path = image
96
+
97
+ # Run prediction using the direct approach
98
+ results = model.predict(source=image_path, save=False, verbose=False)
99
+
100
+ if not results or len(results) == 0:
101
+ return processed_image, []
102
+
103
+ # Process results
104
+ result = results[0]
105
+ output = []
106
+
107
+ if hasattr(result, 'boxes'):
108
+ for box in result.boxes:
109
+ try:
110
+ conf = float(box.conf[0])
111
+ cls = int(box.cls[0])
112
+ class_name = model.names[cls]
113
+
114
+ if conf > 0.3: # Confidence threshold
115
+ output.append({
116
+ "confidence": round(conf, 3),
117
+ "label": class_name
118
+ })
119
+ except Exception as e:
120
+ print(f"Error processing box: {str(e)}")
121
+ traceback.print_exc()
122
+ continue
123
+
124
+ # Use the plotted image with annotations
125
+ annotated_image = result.plot()
126
+
127
+ return annotated_image, output
128
+ except Exception as e:
129
+ print(f"Error in detect_signature: {str(e)}")
130
+ traceback.print_exc()
131
+ # Return original image and empty results in case of error
132
+ if image is None:
133
+ return np.zeros((100, 100, 3), dtype=np.uint8), []
134
+ return image, []
135
+
136
+ # Add a direct API endpoint for our Node.js server
137
+ def api_detect_signature(image_data):
138
+ """API endpoint for direct signature detection without UI"""
139
+ try:
140
+ # Handle None input
141
+ if image_data is None:
142
+ return {"success": False, "error": "No image data provided"}
143
+
144
+ # If data is base64 encoded
145
+ if isinstance(image_data, str) and image_data.startswith('data:image'):
146
+ # Use the existing function
147
+ result_img, detections = detect_signature(image_data)
148
+
149
+ # Convert result image to base64 for API response
150
+ buffered = io.BytesIO()
151
+ Image.fromarray(result_img).save(buffered, format="JPEG")
152
+ img_str = base64.b64encode(buffered.getvalue()).decode()
153
+
154
+ return {
155
+ "success": True,
156
+ "detections": detections,
157
+ "annotated_image": f"data:image/jpeg;base64,{img_str}"
158
+ }
159
+ else:
160
+ return {"success": False, "error": "Invalid image format. Send base64 encoded image."}
161
+ except Exception as e:
162
+ print(f"Error in api_detect_signature: {str(e)}")
163
+ traceback.print_exc()
164
+ return {"success": False, "error": str(e)}
165
+
166
+ # Create Gradio interface
167
+ interface = gr.Interface(
168
+ fn=detect_signature,
169
+ inputs=gr.Image(type="filepath", label="Upload an image"),
170
+ outputs=[
171
+ gr.Image(label="Detected Signatures"),
172
+ gr.JSON(label="Detection Results")
173
+ ],
174
+ title="Signature Detector",
175
+ description="Upload an image to detect signatures",
176
+ examples=[
177
+ ["temp_image.jpg"] if os.path.exists("temp_image.jpg") else None
178
+ ],
179
+ flagging_mode="never",
180
+ cache_examples=True
181
+ )
182
+
183
+ # Create a dedicated API endpoint for direct access
184
+ api_interface = gr.Interface(
185
+ fn=api_detect_signature,
186
+ inputs=gr.Textbox(label="Base64 Image", placeholder="data:image/jpeg;base64,..."),
187
+ outputs=gr.JSON(label="API Response"),
188
+ title="Signature Detection API",
189
+ description="For programmatic access",
190
+ flagging_mode="never",
191
+ examples=[
192
+ ["data:image/jpeg;base64,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"] if os.path.exists("temp_image.jpg") else None
193
+ ]
194
+ )
195
+
196
+ # Create a Gradio Blocks app that includes both interfaces
197
+ with gr.Blocks() as app:
198
+ gr.Markdown("# Signature Detection Demo")
199
+
200
+ with gr.Tab("Interactive Demo"):
201
+ interface.render()
202
+
203
+ with gr.Tab("API Access"):
204
+ api_interface.render()
205
+ gr.Markdown("""
206
+ ## API Usage Instructions
207
+
208
+ You can use this API endpoint from your applications by sending a POST request:
209
+
210
+ ### Method 1 (Latest Gradio API, recommended):
211
+ ```
212
+ POST /predict
213
+
214
+ {
215
+ "data": ["data:image/jpeg;base64,your_base64_encoded_image"]
216
+ }
217
+ ```
218
+
219
+ ### Method 2 (Standard API):
220
+ ```
221
+ POST /api/predict
222
+
223
+ {
224
+ "data": ["data:image/jpeg;base64,your_base64_encoded_image"]
225
+ }
226
+ ```
227
+
228
+ ### Method 3 (Legacy format):
229
+ ```
230
+ POST /run/predict
231
+
232
+ {
233
+ "fn_index": 0,
234
+ "data": ["data:image/jpeg;base64,your_base64_encoded_image"]
235
+ }
236
+ ```
237
+
238
+ The response will contain detection results and an annotated image.
239
+ See README-API.md for more details.
240
+ """)
241
+
242
+ # Launch with specific configs for API access
243
+ # In Hugging Face Spaces, use Gradio's default launcher settings
244
+ app.launch(
245
+ server_name="0.0.0.0", # Bind to all network interfaces
246
+ show_api=True, # Enable API endpoints
247
+ allowed_paths=["*.jpg", "*.png", "*.jpeg"] # Allow access to image files
248
+ )