Spaces:
Sleeping
Sleeping
| from flask import Flask, request, jsonify, render_template | |
| from verifier import AIFRKTPVerification | |
| from deepface import DeepFace | |
| import cv2 | |
| import numpy as np | |
| import base64 | |
| import os | |
| import uuid | |
| # This is the line Gunicorn looks for. It must be named 'app'. | |
| app = Flask(__name__) | |
| # Initialize the verifier once when the server starts | |
| face_verifier = AIFRKTPVerification() | |
| def image_to_base64(img_stream): | |
| """Converts an image stream to a base64 string for embedding in HTML.""" | |
| return base64.b64encode(img_stream).decode('utf-8') | |
| # --- Web Demo Routes --- | |
| def similarity_demo(): | |
| """Handles the visual web demo for similarity checking.""" | |
| if request.method == 'POST': | |
| if 'ktp_image' not in request.files or 'selfie_image' not in request.files: | |
| return "Missing one or both images", 400 | |
| ktp_file, selfie_file = request.files['ktp_image'], request.files['selfie_image'] | |
| ktp_stream, selfie_stream = ktp_file.read(), selfie_file.read() | |
| ktp_img = cv2.imdecode(np.frombuffer(ktp_stream, np.uint8), cv2.IMREAD_COLOR) | |
| selfie_img = cv2.imdecode(np.frombuffer(selfie_stream, np.uint8), cv2.IMREAD_COLOR) | |
| if ktp_img is None or selfie_img is None: | |
| return "Could not decode one or both images.", 400 | |
| result = face_verifier.verify_with_images(ktp_img, selfie_img) | |
| ktp_base64 = image_to_base64(ktp_stream) | |
| selfie_base64 = image_to_base64(selfie_stream) | |
| return render_template( | |
| 'index.html', | |
| verification_result=result, | |
| ktp_image_url=f"data:image/jpeg;base64,{ktp_base64}", | |
| selfie_image_url=f"data:image/jpeg;base64,{selfie_base64}" | |
| ) | |
| return render_template('index.html') | |
| def liveness_demo(): | |
| """Handles the visual web demo for the liveness check.""" | |
| if request.method == 'POST': | |
| if 'liveness_image' not in request.files: | |
| return "Missing image file", 400 | |
| image_file = request.files['liveness_image'] | |
| image_stream = image_file.read() | |
| # Save temporarily for DeepFace, as it works best with a file path | |
| temp_filename = f"/tmp/{uuid.uuid4().hex}.jpg" | |
| with open(temp_filename, 'wb') as f: | |
| f.write(image_stream) | |
| try: | |
| face_objs = DeepFace.extract_faces( | |
| img_path=temp_filename, enforce_detection=False, | |
| detector_backend='opencv', anti_spoofing=True | |
| ) | |
| if not face_objs: | |
| return "No face detected in the image.", 400 | |
| is_real = face_objs[0]['is_real'] | |
| liveness_result = {'liveness_passed': bool(is_real)} | |
| image_base64 = image_to_base64(image_stream) | |
| return render_template( | |
| 'liveness.html', | |
| liveness_result=liveness_result, | |
| image_url=f"data:image/jpeg;base64,{image_base64}" | |
| ) | |
| finally: | |
| # Clean up the temporary file | |
| if os.path.exists(temp_filename): | |
| os.remove(temp_filename) | |
| return render_template('liveness.html') | |
| # --- API Routes for iOS App --- | |
| def api_verify(): | |
| """Handles the similarity check for the iOS app and returns JSON.""" | |
| if 'ktp_image' not in request.files or 'selfie_image' not in request.files: | |
| return jsonify({'error': 'Two images are required'}), 400 | |
| try: | |
| ktp_file = request.files['ktp_image'].read() | |
| selfie_file = request.files['selfie_image'].read() | |
| ktp_img = cv2.imdecode(np.frombuffer(ktp_file, np.uint8), cv2.IMREAD_COLOR) | |
| selfie_img = cv2.imdecode(np.frombuffer(selfie_file, np.uint8), cv2.IMREAD_COLOR) | |
| if ktp_img is None or selfie_img is None: | |
| return jsonify({'error': 'Could not decode images.'}), 400 | |
| result = face_verifier.verify_with_images(ktp_img, selfie_img) | |
| if 'error' in result: | |
| return jsonify(result), 400 | |
| return jsonify(result) | |
| except Exception as e: | |
| print(f"Error in /api/verify: {e}") | |
| return jsonify({'error': 'Internal server error.'}), 500 | |
| def api_liveness_check(): | |
| """Handles the liveness check for the iOS app and returns JSON.""" | |
| if 'image' not in request.files: | |
| return jsonify({'error': 'An image file is required.'}), 400 | |
| image_file = request.files['image'] | |
| temp_filename = f"/tmp/{uuid.uuid4().hex}.jpg" | |
| image_file.save(temp_filename) | |
| try: | |
| face_objs = DeepFace.extract_faces( | |
| img_path=temp_filename, enforce_detection=False, | |
| detector_backend='opencv', anti_spoofing=True | |
| ) | |
| if not face_objs: | |
| return jsonify({'error': 'No face detected in the image.'}), 400 | |
| is_real = face_objs[0]['is_real'] | |
| confidence = face_objs[0]['confidence'] | |
| return jsonify({'liveness_passed': bool(is_real), 'confidence': float(confidence)}) | |
| except Exception as e: | |
| print(f"Error in /api/liveness: {e}") | |
| return jsonify({'error': 'An internal error occurred.'}), 500 | |
| finally: | |
| if os.path.exists(temp_filename): | |
| os.remove(temp_filename) | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=5000) | |