import * as faceapi from '@vladmandic/face-api'; import sharp from 'sharp'; import pg from 'pg'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Disable certificate verification for CDN download if needed process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; const pool = new pg.Pool({ connectionString: 'postgresql://edumanager:EduManager2026!Seguro@150.230.87.131:5432/edumanager' }); async function run() { try { // 1. Initialize face-api environment for Node console.log('Inicializando face-api...'); // Tiny Face Detector, Face Landmark 68, and Face Recognition Nets const MODEL_URL = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model/'; console.log('Carregando modelos face-api do CDN...'); await Promise.all([ faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL), faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL), faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL) ]); console.log('Modelos carregados com sucesso!'); // 2. Fetch students and their face descriptors from DB console.log('Buscando alunos do banco de dados...'); const { rows: students } = await pool.query('SELECT id, nome, face_descriptor FROM alunos WHERE face_descriptor IS NOT NULL'); console.log(`Encontrados ${students.length} alunos com biometria no banco.`); // 3. Read downloaded photos from disk const photosDir = path.join(__dirname, 'photos'); const photoFiles = fs.readdirSync(photosDir).filter(f => f.endsWith('.webp')); console.log(`Encontradas ${photoFiles.length} fotos webp locais.`); const results = []; // 4. Process each photo, get its descriptor, and find best match for (const file of photoFiles) { const filePath = path.join(photosDir, file); console.log(`Processando ${file}...`); // Use sharp to convert webp to raw RGB buffer for face-api tensor const image = sharp(filePath); const metadata = await image.metadata(); const { data, info } = await image .raw() .toBuffer({ resolveWithObject: true }); // Create tensor from raw pixels const tensor = faceapi.tf.tensor3d( new Uint8Array(data), [info.height, info.width, 3], 'int32' ); // Detect face and extract descriptor const detection = await faceapi.detectSingleFace(tensor) .withFaceLandmarks() .withFaceDescriptor(); tensor.dispose(); if (!detection) { console.warn(`Nenhum rosto detectado na foto ${file}`); continue; } const imgDescriptor = detection.descriptor; // Compare with all students using Euclidean distance let bestMatch = null; let minDistance = Infinity; for (const s of students) { const dbDescriptorStr = typeof s.face_descriptor === 'string' ? s.face_descriptor : JSON.stringify(s.face_descriptor); const dbDescriptor = new Float32Array(JSON.parse(dbDescriptorStr)); const distance = faceapi.euclideanDistance(imgDescriptor, dbDescriptor); if (distance < minDistance) { minDistance = distance; bestMatch = s; } } console.log(`Foto: ${file} | Melhor Match: ${bestMatch?.nome} | Distância: ${minDistance.toFixed(4)}`); results.push({ file, studentId: bestMatch?.id, studentName: bestMatch?.nome, distance: minDistance }); } console.log('\n--- RESULTADO DE PROJEÇÃO DE CORRELAÇÃO DE BIOMETRIA ---'); results.forEach(r => { console.log(`Foto: ${r.file} -> Aluno: ${r.studentName} (ID: ${r.studentId}) | Distância: ${r.distance.toFixed(4)}`); }); } catch (err) { console.error('Erro na execução:', err); } finally { await pool.end(); } } run();