/
REM11
/
FaceAccess
Обзор
Документация
Войти
/
REM11
/
FaceAccess
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
static/index.html
342 строки
16 KB
soval
-
14 дек 2025, 17:04
14 дек 2025, 17:04
b7874d0
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="en" class="h-full"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Face Access Control | Secure Entry</title> <script src="https://cdn.tailwindcss.com"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.0/dist/cdn.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <style> .gradient-bg { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } .glass-effect { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); } </style> </head> <body class="h-full gradient-bg"> <div x-data="faceRecognitionApp()" x-init="init()" class="min-h-screen flex flex-col items-center justify-center p-4"> <!-- Header --> <header class="w-full max-w-4xl mb-8"> <div class="flex justify-between items-center"> <div> <h1 class="text-3xl md:text-4xl font-bold text-white"> <i class="fas fa-lock mr-3"></i>Face Access Control </h1> <p class="text-gray-200 mt-2">Secure biometric entry system</p> </div> </div> </header> <!-- Main Card --> <main class="w-full max-w-4xl"> <div class="glass-effect rounded-2xl shadow-2xl overflow-hidden"> <div class="p-6 md:p-8"> <!-- Status Indicators --> <div class="flex flex-wrap gap-4 mb-8"> <div class="flex items-center bg-white/10 rounded-lg px-4 py-2"> <div class="w-3 h-3 rounded-full bg-green-400 mr-3 animate-pulse"></div> <span class="text-white font-medium">Camera Ready</span> </div> <div class="flex items-center bg-white/10 rounded-lg px-4 py-2"> <div class="w-3 h-3 rounded-full bg-blue-400 mr-3"></div> <span class="text-white font-medium">System Online</span> </div> <div class="flex items-center bg-white/10 rounded-lg px-4 py-2"> <i class="fas fa-users text-white mr-3"></i> <span class="text-white font-medium" x-text="stats.total_users ? stats.total_users + ' Users' : 'Loading...'"></span> </div> </div> <!-- Camera Section --> <div class="mb-8"> <h2 class="text-2xl font-bold text-white mb-4">Face Recognition</h2> <!-- Camera Container --> <div class="relative rounded-xl overflow-hidden bg-black/20 mb-6"> <video id="cameraFeed" autoplay playsinline class="w-full h-64 md:h-96 object-cover" :class="{ 'hidden': showResult }" ></video> <!-- Face Overlay Guide --> <div class="absolute inset-0 flex items-center justify-center pointer-events-none"> <div class="w-64 h-64 border-2 border-white/30 rounded-full animate-pulse"></div> </div> <!-- Result Display --> <template x-if="showResult"> <div class="w-full h-64 md:h-96 flex flex-col items-center justify-center bg-gradient-to-br from-gray-900 to-black text-white p-8" > <div class="text-5xl mb-6" :class="recognitionResult.status === 'success' ? 'text-green-400' : 'text-red-400'" > <i :class="recognitionResult.status === 'success' ? 'fas fa-check-circle' : 'fas fa-times-circle'" ></i> </div> <h3 class="text-2xl font-bold mb-2" x-text="recognitionResult.message || 'Processing...'"></h3> <template x-if="recognitionResult.user_id"> <p class="text-lg mb-1"> User: <span x-text="recognitionResult.full_name" class="font-semibold"></span> </p> </template> <template x-if="recognitionResult.confidence"> <p class="text-gray-300"> Confidence: <span x-text="Math.round(recognitionResult.confidence * 100) + '%'" class="font-semibold"></span> </p> </template> </div> </template> </div> <!-- Camera Controls --> <div class="flex flex-wrap gap-4 justify-center mb-6"> <button @click="startCamera()" :disabled="cameraActive" :class="{ 'hidden': cameraActive }" class="flex items-center gap-2 px-6 py-3 bg-blue-500 hover:bg-blue-600 text-white rounded-lg font-semibold transition disabled:opacity-50" > <i class="fas fa-video"></i> Start Camera </button> <button @click="stopCamera()" :disabled="!cameraActive" :class="{ 'hidden': !cameraActive }" class="flex items-center gap-2 px-6 py-3 bg-red-500 hover:bg-red-600 text-white rounded-lg font-semibold transition disabled:opacity-50" > <i class="fas fa-stop"></i> Stop Camera </button> <button @click="captureAndRecognize()" :disabled="!cameraActive || showResult" class="flex items-center gap-2 px-6 py-3 bg-purple-500 hover:bg-purple-600 text-white rounded-lg font-semibold transition disabled:opacity-50" > <i class="fas fa-user-check"></i> Scan Face </button> <button @click="resetRecognition()" x-show="showResult" class="flex items-center gap-2 px-6 py-3 bg-gray-600 hover:bg-gray-700 text-white rounded-lg font-semibold transition" > <i class="fas fa-redo"></i> Scan Again </button> </div> <!-- Auto-scan toggle --> <div class="flex items-center justify-center mb-8"> <div class="flex items-center bg-white/10 rounded-full p-1"> <span class="text-white px-4">Auto-scan</span> <button @click="toggleAutoScan()" class="w-14 h-8 flex items-center rounded-full p-1 transition" :class="autoScan ? 'bg-green-500 justify-end' : 'bg-gray-600 justify-start'" > <div class="bg-white w-6 h-6 rounded-full shadow"></div> </button> </div> </div> </div> <!-- Quick Stats --> <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <div class="bg-white/10 rounded-xl p-6 text-center"> <i class="fas fa-door-open text-3xl text-green-300 mb-3"></i> <h3 class="text-2xl font-bold text-white" x-text="stats.success || 0"></h3> <p class="text-gray-200">Successful Entries</p> </div> <div class="bg-white/10 rounded-xl p-6 text-center"> <i class="fas fa-exclamation-triangle text-3xl text-yellow-300 mb-3"></i> <h3 class="text-2xl font-bold text-white" x-text="stats.failure || 0"></h3> <p class="text-gray-200">Failed Attempts</p> </div> <div class="bg-white/10 rounded-xl p-6 text-center"> <i class="fas fa-chart-line text-3xl text-blue-300 mb-3"></i> <h3 class="text-2xl font-bold text-white" x-text="stats.success_rate ? stats.success_rate + '%' : '0%'"></h3> <p class="text-gray-200">Success Rate</p> </div> </div> </div> </div> <!-- Navigation Links --> <div class="mt-8 flex flex-wrap justify-center gap-4"> <a href="/register.html" class="flex items-center gap-2 glass-effect px-6 py-3 rounded-lg text-white hover:bg-white/20 transition"> <i class="fas fa-user-plus"></i> Register New User </a> <a href="/users.html" class="flex items-center gap-2 glass-effect px-6 py-3 rounded-lg text-white hover:bg-white/20 transition"> <i class="fas fa-users-cog"></i> Manage Users </a> <a href="/logs.html" class="flex items-center gap-2 glass-effect px-6 py-3 rounded-lg text-white hover:bg-white/20 transition"> <i class="fas fa-history"></i> View Access Logs </a> </div> </main> <!-- Footer --> <footer class="mt-12 text-center text-gray-300"> <p class="mb-2">Face Access Control System v1.0</p> <p class="text-sm opacity-75">Secure biometric authentication powered by AI</p> </footer> </div> <script> function faceRecognitionApp() { return { cameraActive: false, autoScan: false, showResult: false, recognitionResult: {}, stats: {}, cameraStream: null, autoScanInterval: null, async init() { await this.loadStats(); }, async startCamera() { try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user', width: { ideal: 1280 }, height: { ideal: 720 } } }); const video = document.getElementById('cameraFeed'); video.srcObject = stream; this.cameraActive = true; this.cameraStream = stream; if (this.autoScan) { this.startAutoScan(); } } catch (error) { console.error('Camera error:', error); alert('Cannot access camera. Please check permissions.'); } }, stopCamera() { if (this.cameraStream) { this.cameraStream.getTracks().forEach(track => track.stop()); this.cameraActive = false; this.cameraStream = null; } if (this.autoScanInterval) { clearInterval(this.autoScanInterval); this.autoScanInterval = null; } }, async captureAndRecognize() { if (!this.cameraActive) return; try { const video = document.getElementById('cameraFeed'); const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0); const imageData = canvas.toDataURL('image/jpeg', 0.8); // Show loading this.showResult = true; this.recognitionResult = { message: 'Processing face...' }; const response = await fetch('/api/v1/auth/recognize', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ image_data: imageData }) }); if (!response.ok) { throw new Error('Recognition request failed'); } this.recognitionResult = await response.json(); // Load updated stats await this.loadStats(); // Auto reset after 3 seconds if auto-scan is off if (!this.autoScan) { setTimeout(() => { this.resetRecognition(); }, 3000); } } catch (error) { console.error('Recognition error:', error); this.recognitionResult = { status: 'error', message: 'Recognition failed: ' + error.message }; } }, toggleAutoScan() { this.autoScan = !this.autoScan; if (this.autoScan && this.cameraActive) { this.startAutoScan(); } else { if (this.autoScanInterval) { clearInterval(this.autoScanInterval); this.autoScanInterval = null; } } }, startAutoScan() { if (this.autoScanInterval) { clearInterval(this.autoScanInterval); } this.autoScanInterval = setInterval(() => { if (!this.showResult) { this.captureAndRecognize(); } }, 3000); }, resetRecognition() { this.showResult = false; this.recognitionResult = {}; }, async loadStats() { try { const response = await fetch('/api/v1/logs/stats'); if (response.ok) { this.stats = await response.json(); } } catch (error) { console.error('Error loading stats:', error); } } } } </script> </body> </html>