Remove API documentation from frontend and delete Swagger UI

This commit is contained in:
Aherobo Ovie Victor
2025-07-11 21:36:12 +01:00
parent b54da61121
commit 7b9de2b833
4 changed files with 1 additions and 297 deletions
-245
View File
@@ -1,245 +0,0 @@
#!/usr/bin/env python3
"""
Swagger UI API Documentation for Memory Module Detection
This creates a separate API documentation interface using Flask-RESTX
"""
from flask import Flask, request, jsonify
from flask_restx import Api, Resource, fields, reqparse
from flask_cors import CORS
from werkzeug.datastructures import FileStorage
import os
from inference_utils import MemoryModuleDetector
# Initialize Flask app with Swagger
app = Flask(__name__)
CORS(app)
# Configure Swagger UI
api = Api(
app,
version='1.0.0',
title='Memory Module Detection API',
description='AI-powered memory module detection in motherboard images using YOLOv8',
doc='/docs/', # Swagger UI will be available at /docs/
prefix='/api/v1'
)
# Create namespaces
ns_health = api.namespace('health', description='System health and status')
ns_detect = api.namespace('detect', description='Memory module detection operations')
# Initialize detector
MODEL_PATH = 'runs/detect/memory_module_detection/weights/best.pt'
detector = MemoryModuleDetector(MODEL_PATH)
# Define models for Swagger documentation
detection_model = api.model('Detection', {
'bbox': fields.List(fields.Float, description='Bounding box coordinates [x1, y1, x2, y2]'),
'confidence': fields.Float(description='Detection confidence score (0.0-1.0)'),
'class': fields.Integer(description='Class ID (0 for memory_module)'),
'class_name': fields.String(description='Class name (memory_module)')
})
detection_response = api.model('DetectionResponse', {
'success': fields.Boolean(description='Whether detection was successful'),
'detections': fields.List(fields.Nested(detection_model), description='List of detected memory modules'),
'num_detections': fields.Integer(description='Number of memory modules detected'),
'annotated_image': fields.String(description='Base64 encoded annotated image'),
'confidence_threshold': fields.Float(description='Confidence threshold used'),
'original_filename': fields.String(description='Original filename (for uploads)')
})
health_response = api.model('HealthResponse', {
'status': fields.String(description='System health status'),
'model_loaded': fields.Boolean(description='Whether the AI model is loaded'),
'model_path': fields.String(description='Path to the AI model file')
})
error_response = api.model('ErrorResponse', {
'success': fields.Boolean(description='Always false for errors'),
'error': fields.String(description='Error message')
})
# Health endpoint
@ns_health.route('/')
class Health(Resource):
@ns_health.doc('health_check')
@ns_health.marshal_with(health_response)
def get(self):
"""Check system health and model status"""
return {
'status': 'healthy',
'model_loaded': detector.model is not None,
'model_path': MODEL_PATH
}
# File upload parser
upload_parser = reqparse.RequestParser()
upload_parser.add_argument('image', location='files', type=FileStorage, required=True,
help='Motherboard image file (PNG, JPG, JPEG, GIF, BMP)')
upload_parser.add_argument('confidence', type=float, default=0.8,
help='Confidence threshold (0.1-1.0, default: 0.8)')
@ns_detect.route('/upload')
class DetectUpload(Resource):
@ns_detect.doc('detect_upload')
@ns_detect.expect(upload_parser)
@ns_detect.marshal_with(detection_response, code=200)
@ns_detect.marshal_with(error_response, code=400)
@ns_detect.marshal_with(error_response, code=500)
def post(self):
"""Upload and analyze motherboard image for memory modules"""
try:
if detector.model is None:
return {'success': False, 'error': 'Model not loaded'}, 500
args = upload_parser.parse_args()
file = args['image']
confidence = args['confidence']
if not file:
return {'success': False, 'error': 'No image file provided'}, 400
# Save file temporarily
temp_path = f"temp_{file.filename}"
file.save(temp_path)
try:
# Run detection
detections, annotated_image = detector.detect(temp_path, conf_threshold=confidence)
# Convert annotated image to base64
import io
import base64
buffer = io.BytesIO()
annotated_image.save(buffer, format='PNG')
annotated_base64 = base64.b64encode(buffer.getvalue()).decode()
return {
'success': True,
'detections': detections,
'num_detections': len(detections),
'annotated_image': annotated_base64,
'confidence_threshold': confidence,
'original_filename': file.filename
}
finally:
# Clean up
if os.path.exists(temp_path):
os.remove(temp_path)
except Exception as e:
return {'success': False, 'error': str(e)}, 500
# Hardcoded image parser
hardcoded_parser = reqparse.RequestParser()
hardcoded_parser.add_argument('confidence', type=float, default=0.8, location='args',
help='Confidence threshold (0.1-1.0, default: 0.8)')
@ns_detect.route('/hardcoded')
class DetectHardcoded(Resource):
@ns_detect.doc('detect_hardcoded')
@ns_detect.expect(hardcoded_parser)
@ns_detect.marshal_with(detection_response, code=200)
@ns_detect.marshal_with(error_response, code=404)
@ns_detect.marshal_with(error_response, code=500)
def get(self):
"""Analyze predefined test image for memory modules"""
try:
if detector.model is None:
return {'success': False, 'error': 'Model not loaded'}, 500
args = hardcoded_parser.parse_args()
confidence = args['confidence']
test_image_path = 'training/memory/out1.png'
if not os.path.exists(test_image_path):
return {'success': False, 'error': f'Test image not found at {test_image_path}'}, 404
# Run detection
detections, annotated_image = detector.detect(test_image_path, conf_threshold=confidence)
# Convert annotated image to base64
import io
import base64
buffer = io.BytesIO()
annotated_image.save(buffer, format='PNG')
annotated_base64 = base64.b64encode(buffer.getvalue()).decode()
return {
'success': True,
'detections': detections,
'num_detections': len(detections),
'annotated_image': annotated_base64,
'confidence_threshold': confidence,
'test_image_path': test_image_path
}
except Exception as e:
return {'success': False, 'error': str(e)}, 500
# Base64 image model
base64_model = api.model('Base64Request', {
'image': fields.String(required=True, description='Base64 encoded image data'),
'confidence': fields.Float(default=0.8, description='Confidence threshold (0.1-1.0)')
})
@ns_detect.route('/base64')
class DetectBase64(Resource):
@ns_detect.doc('detect_base64')
@ns_detect.expect(base64_model)
@ns_detect.marshal_with(detection_response, code=200)
@ns_detect.marshal_with(error_response, code=400)
@ns_detect.marshal_with(error_response, code=500)
def post(self):
"""Analyze base64 encoded image for memory modules"""
try:
if detector.model is None:
return {'success': False, 'error': 'Model not loaded'}, 500
data = request.get_json()
if not data or 'image' not in data:
return {'success': False, 'error': 'No base64 image data provided'}, 400
confidence = data.get('confidence', 0.8)
# Decode base64 image
import base64
import io
from PIL import Image
import numpy as np
try:
img_data = base64.b64decode(data['image'])
image = Image.open(io.BytesIO(img_data))
except Exception as e:
return {'success': False, 'error': f'Invalid base64 image data: {str(e)}'}, 400
# Run detection
detections, annotated_image = detector.detect_from_array(np.array(image), conf_threshold=confidence)
# Convert annotated image to base64
buffer = io.BytesIO()
annotated_image.save(buffer, format='PNG')
annotated_base64 = base64.b64encode(buffer.getvalue()).decode()
return {
'success': True,
'detections': detections,
'num_detections': len(detections),
'annotated_image': annotated_base64,
'confidence_threshold': confidence
}
except Exception as e:
return {'success': False, 'error': str(e)}, 500
if __name__ == '__main__':
print("Starting Memory Module Detection API with Swagger UI...")
print(f"Model path: {MODEL_PATH}")
print(f"Model loaded: {detector.model is not None}")
print("Swagger UI available at: http://localhost:5003/docs/")
app.run(host='0.0.0.0', port=5003, debug=True)
+1 -48
View File
@@ -88,63 +88,16 @@ def api_info():
'endpoints': { 'endpoints': {
'/': 'GET - Frontend interface or API information', '/': 'GET - Frontend interface or API information',
'/api': 'GET - API information (JSON)', '/api': 'GET - API information (JSON)',
'/docs': 'GET - API documentation (Swagger UI)',
'/detect': 'POST - Upload image for memory module detection', '/detect': 'POST - Upload image for memory module detection',
'/detect/hardcoded': 'GET - Process hardcoded test image', '/detect/hardcoded': 'GET - Process hardcoded test image',
'/detect/base64': 'POST - Process base64 encoded image', '/detect/base64': 'POST - Process base64 encoded image',
'/health': 'GET - Health check' '/health': 'GET - Health check'
}, },
'model_loaded': detector.model is not None, 'model_loaded': detector.model is not None,
'supported_formats': list(ALLOWED_EXTENSIONS), 'supported_formats': list(ALLOWED_EXTENSIONS)
'swagger_ui': 'http://localhost:5003/docs/ (run: python3 api_docs.py)'
}) })
@app.route('/docs')
def api_docs():
"""Redirect to API documentation."""
return """
<!DOCTYPE html>
<html>
<head>
<title>API Documentation</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; background: #f5f5f5; }
.container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.btn { display: inline-block; padding: 12px 24px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; margin: 10px; }
.btn:hover { background: #0056b3; }
.code { background: #f8f9fa; padding: 10px; border-radius: 5px; margin: 20px 0; font-family: monospace; }
</style>
</head>
<body>
<div class="container">
<h1>🚀 Memory Module Detection API Documentation</h1>
<p>Interactive Swagger UI documentation for all API endpoints</p>
<h3>📖 Access Swagger UI:</h3>
<div class="code">
<strong>Step 1:</strong> Start API docs server<br>
<code>python3 api_docs.py</code><br><br>
<strong>Step 2:</strong> Open Swagger UI<br>
<code>http://localhost:5003/docs/</code>
</div>
<a href="http://localhost:5003/docs/" class="btn" target="_blank">
📚 Open Swagger UI (if running)
</a>
<h3>📋 Quick API Reference:</h3>
<ul style="text-align: left;">
<li><strong>POST /detect</strong> - Upload image for detection</li>
<li><strong>GET /detect/hardcoded</strong> - Test with predefined image</li>
<li><strong>POST /detect/base64</strong> - Process base64 encoded image</li>
<li><strong>GET /health</strong> - System health check</li>
</ul>
<p><a href="/">← Back to Main Interface</a></p>
</div>
</body>
</html>
"""
@app.route('/health', methods=['GET']) @app.route('/health', methods=['GET'])
def health_check(): def health_check():
-1
View File
@@ -8,7 +8,6 @@ Pillow==10.0.1
# Web Framework # Web Framework
Flask==2.3.3 Flask==2.3.3
Flask-CORS==4.0.0 Flask-CORS==4.0.0
Flask-RESTX==1.3.0
Werkzeug==2.3.7 Werkzeug==2.3.7
# Data Processing # Data Processing
-3
View File
@@ -39,9 +39,6 @@
<button class="btn btn-info" onclick="runAllTests()"> <button class="btn btn-info" onclick="runAllTests()">
<i class="fas fa-play"></i> Run All Tests <i class="fas fa-play"></i> Run All Tests
</button> </button>
<a href="/docs" class="btn btn-outline" target="_blank">
<i class="fas fa-book"></i> API Documentation
</a>
</div> </div>
</section> </section>