JAAK Visage SDK
Manual Completo para Implementación de Detección Facial con el Componente Web @jaak.ai/visage
⏱️ Tiempo estimado: 30-45 minutos para configuración completa
🎯 ¿Qué aprenderás en este manual?
Este manual te enseñará a implementar y usar el componente web @jaak.ai/visage para detección facial en tiempo real desde cero. No necesitas conocimientos técnicos avanzados - solo sigue los pasos.
🎮 Demo en Vivo
Antes de empezar con la implementación, puedes probar el componente en funcionamiento:
¿Qué puedes hacer en el demo?
- ✅ Probar detección facial en tiempo real
- ✅ Ver el comportamiento del componente
- ✅ Verificar compatibilidad con tu dispositivo
- ✅ Hacer debugg en tiempo real
📋 Antes de Empezar - Lista de Verificación
Asegúrate de tener estos elementos listos:
- Node.js 16.0+ instalado (para proyectos npm)
- Navegador moderno (Chrome 88+, Firefox 85+, Safari 14+)
- Conexión HTTPS (requerida para acceso a cámara)
- Editor de código
- Acceso a cámara web funcional
🗂️ Índice de Contenidos
Sección | Qué harás | Tiempo |
---|---|---|
Paso 1 | Instalar y configurar el componente | 5 min |
Paso 2 | Implementación básica en HTML | 15 min |
Paso 3 | Configurar eventos correctos | 10 min |
Paso 4 | Implementar en frameworks | 10 min |
Paso 5 | Probar funcionamiento | 5 min |
PASO 1: Instalar y Configurar el Componente
🎯 Objetivo
Instalar el componente @jaak.ai/visage e configurar el entorno.
✅ Métodos de Instalación
1.1 Instalación vía NPM (Recomendado)
npm install @jaak.ai/visage
1.2 Instalación vía CDN
<script type="module" src="https://unpkg.com/@jaak.ai/visage/dist/jaak-visage-webcomponent/jaak-visage-webcomponent.esm.js"></script>
1.3 Requisitos Técnicos
Requisito | Versión | ¿Obligatorio? |
---|---|---|
Navegadores | Chrome 88+, Firefox 85+, Safari 14+ | Sí |
HTTPS | Protocolo seguro | Sí (en producción) |
JavaScript | ES2017+ | Sí |
PASO 2: Implementación Básica en HTML
🎯 Objetivo
Crear tu primera implementación funcional del componente.
2.1 HTML Completo Funcional
<!DOCTYPE html>
<html dir="ltr" lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JAAK Visage - Detección Facial</title>
<script type="module" src="https://unpkg.com/@jaak.ai/visage/dist/jaak-visage-webcomponent/jaak-visage-webcomponent.esm.js"></script>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.status {
padding: 15px;
margin: 10px 0;
border-radius: 8px;
background: #e3f2fd;
}
.status.success { background: #e8f5e8; }
.status.error { background: #ffebee; }
.controls {
margin: 20px 0;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
button {
padding: 12px 24px;
border: none;
border-radius: 6px;
background: #2196f3;
color: white;
cursor: pointer;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
jaak-visage {
width: 100%;
max-width: 640px;
display: block;
margin: 20px auto;
border-radius: 10px;
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<h1>🎥 Detector Facial JAAK Visage</h1>
<div class="status" id="statusDiv">
<strong>Estado:</strong> <span id="statusText">Inicializando...</span>
</div>
<div class="controls">
<button id="startBtn" disabled>🚀 Iniciar</button>
<button id="stopBtn" disabled>⏹️ Detener</button>
<button id="helpBtn" disabled>❓ Ayuda</button>
</div>
<jaak-visage
id="faceDetector"
debug="true"
camera="auto">
</jaak-visage>
<div id="results" style="display: none;">
<h3>📊 Resultados</h3>
<div id="captureData"></div>
</div>
</div>
<script>
// Variables globales
let jaakVisage = null;
let isComponentReady = false;
// Referencias DOM
const statusText = document.getElementById('statusText');
const statusDiv = document.getElementById('statusDiv');
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const helpBtn = document.getElementById('helpBtn');
// Función para actualizar estado
function updateStatus(message, type = 'info') {
statusText.textContent = message;
statusDiv.className = `status ${type}`;
}
// Función para habilitar botones
function updateButtons() {
startBtn.disabled = !isComponentReady;
stopBtn.disabled = !isComponentReady;
helpBtn.disabled = !isComponentReady;
}
// Inicializar componente correctamente
async function initializeJaakVisage() {
// ✅ IMPORTANTE: Esperar a que el componente esté definido
await customElements.whenDefined('jaak-visage');
jaakVisage = document.getElementById('faceDetector');
if (!jaakVisage) {
updateStatus('Error: No se encontró el componente', 'error');
return;
}
jaakVisage.addEventListener('statusUpdated', handleStatusUpdated);
jaakVisage.addEventListener('captureCompleted', handleCaptureCompleted);
jaakVisage.addEventListener('error', handleError);
// 🔍 Debug: Interceptar todos los eventos
const originalDispatchEvent = jaakVisage.dispatchEvent.bind(jaakVisage);
jaakVisage.dispatchEvent = function(event) {
console.log('Evento desde jaak-visage:', event.type, event.detail);
return originalDispatchEvent(event);
};
// Event listeners de botones
startBtn.addEventListener('click', handleStart);
stopBtn.addEventListener('click', handleStop);
helpBtn.addEventListener('click', handleShowHelp);
updateStatus('Componente inicializado', 'info');
}
// ✅ MANEJADOR CORRECTO para statusUpdated
function handleStatusUpdated(event) {
const { status, message } = event.detail;
console.log('Status actualizado:', status, message);
// Estados posibles: 'inactive', 'ready', 'active', etc.
if (status === 'ready' || status === 'inactive') {
isComponentReady = true;
updateStatus('✅ Componente listo para usar', 'success');
updateButtons();
} else if (status === 'active') {
updateStatus('🎥 Detector activo', 'info');
} else if (status === 'error') {
updateStatus(`❌ Error: ${message}`, 'error');
}
}
function handleCaptureCompleted(event) {
const data = event.detail;
updateStatus('✅ Captura completada', 'success');
displayResults(data);
}
function handleError(event) {
const error = event.detail;
updateStatus(`❌ Error: ${error.message || 'Error desconocido'}`, 'error');
}
// Manejadores de botones
async function handleStart() {
try {
updateStatus('🚀 Iniciando detector...', 'info');
await jaakVisage.start();
} catch (error) {
updateStatus(`❌ Error: ${error.message}`, 'error');
}
}
async function handleStop() {
try {
updateStatus('⏹️ Deteniendo...', 'info');
await jaakVisage.stop();
document.getElementById('results').style.display = 'none';
} catch (error) {
updateStatus(`❌ Error: ${error.message}`, 'error');
}
}
async function handleShowHelp() {
try {
await jaakVisage.showHelp();
} catch (error) {
updateStatus(`❌ Error: ${error.message}`, 'error');
}
}
function displayResults(data) {
const resultsDiv = document.getElementById('results');
const captureDataDiv = document.getElementById('captureData');
let html = `
<p><strong>Timestamp:</strong> ${new Date(data.timestamp).toLocaleString()}</p>
<p><strong>Confianza:</strong> ${(data.confidence * 100).toFixed(2)}%</p>
`;
if (data.imageData) {
html += `
<p><strong>Imagen:</strong></p>
<img src="${data.imageData}" alt="Captura" style="max-width: 300px; border-radius: 8px;">
`;
}
captureDataDiv.innerHTML = html;
resultsDiv.style.display = 'block';
}
// ✅ Inicializar cuando la página se carga
window.addEventListener('load', initializeJaakVisage);
</script>
</body>
</html>
PASO 3: Configurar Eventos Correctos
🎯 Objetivo
Configurar correctamente los eventos reales que emite el componente.
📝 Eventos Reales del Componente
3.1 Evento Principal: statusUpdated
jaakVisage.addEventListener('statusUpdated', (event) => {
const { status, message } = event.detail;
// Estados posibles:
switch(status) {
case 'ready':
case 'inactive':
// Componente listo para usar
enableControls();
break;
case 'active':
// Detector funcionando
showActiveState();
break;
case 'error':
// Error ocurrido
showError(message);
break;
}
});
3.2 Otros Eventos Disponibles
// Captura completada
jaakVisage.addEventListener('captureCompleted', (event) => {
const data = event.detail;
});
// Errores
jaakVisage.addEventListener('error', (event) => {
const error = event.detail;
console.error('Error:', error.message);
});
3.3 Inicialización Correcta
async function initializeComponent() {
// ✅ IMPORTANTE: Esperar a que el componente esté definido
await customElements.whenDefined('jaak-visage');
const jaakVisage = document.querySelector('jaak-visage');
// Ahora es seguro agregar event listeners
jaakVisage.addEventListener('statusUpdated', handleStatusUpdated);
}
PASO 4: Implementar en Frameworks
📍 React
import React, { useRef, useEffect, useState } from 'react';
import { defineCustomElements } from '@jaak.ai/visage/loader';
defineCustomElements();
const FaceDetector = () => {
const jaakVisageRef = useRef(null);
const [isReady, setIsReady] = useState(false);
const [capturedData, setCapturedData] = useState(null);
useEffect(() => {
const initComponent = async () => {
// ✅ Esperar a que esté definido
await customElements.whenDefined('jaak-visage');
const component = jaakVisageRef.current;
component.addEventListener('statusUpdated', (event) => {
const { status } = event.detail;
if (status === 'ready' || status === 'inactive') {
setIsReady(true);
}
});
component.addEventListener('captureCompleted', (event) => {
setCapturedData(event.detail);
});
};
initComponent();
}, []);
const handleStart = async () => {
try {
await jaakVisageRef.current.start();
} catch (error) {
console.error('Error:', error);
}
};
return (
<div>
<h2>Detector Facial React</h2>
<button onClick={handleStart} disabled={!isReady}>
Iniciar
</button>
<jaak-visage
ref={jaakVisageRef}
debug="false"
camera="auto">
</jaak-visage>
{capturedData && (
<div>
<h3>Resultado</h3>
<img src={capturedData.imageData} alt="Captura" />
</div>
)}
</div>
);
};
export default FaceDetector;
📍 Angular
// Component
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { defineCustomElements } from '@jaak.ai/visage/loader';
defineCustomElements();
@Component({
selector: 'app-face-detector',
template: `
<div>
<h2>Detector Facial Angular</h2>
<button (click)="start()" [disabled]="!isReady">
Iniciar
</button>
<jaak-visage #jaakVisage debug="false" camera="auto">
</jaak-visage>
<div *ngIf="capturedData">
<h3>Resultado</h3>
<img [src]="capturedData.imageData" alt="Captura">
</div>
</div>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class FaceDetectorComponent implements AfterViewInit {
@ViewChild('jaakVisage') jaakVisage!: ElementRef;
isReady = false;
capturedData: any = null;
async ngAfterViewInit() {
// ✅ Esperar a que esté definido
await customElements.whenDefined('jaak-visage');
const component = this.jaakVisage.nativeElement;
component.addEventListener('statusUpdated', (event: any) => {
const { status } = event.detail;
if (status === 'ready' || status === 'inactive') {
this.isReady = true;
}
});
component.addEventListener('captureCompleted', (event: any) => {
this.capturedData = event.detail;
});
}
async start() {
try {
await this.jaakVisage.nativeElement.start();
} catch (error) {
console.error('Error:', error);
}
}
}
PASO 5: Probar Funcionamiento
🎯 Objetivo
Verificar que todo funciona correctamente.
✅ Lista de Verificación
Elemento | ✅ | Descripción |
---|---|---|
Componente carga | ☐ | Elemento aparece en DOM |
Event statusUpdated | ☐ | Se dispara correctamente |
Permisos cámara | ☐ | Navegador solicita permisos |
Detección facial | ☐ | Detecta y captura rostros |
🔍 Debug y Troubleshooting
Verificar eventos
// Interceptar todos los eventos del componente
const jaakVisage = document.querySelector('jaak-visage');
const originalDispatchEvent = jaakVisage.dispatchEvent.bind(jaakVisage);
jaakVisage.dispatchEvent = function(event) {
console.log('📡 Evento:', event.type, event.detail);
return originalDispatchEvent(event);
};
Problemas comunes
Problema | Solución |
---|---|
Eventos no se disparan | ✅ Usar await customElements.whenDefined('jaak-visage') |
isReady no funciona | ✅ Cambiar a statusUpdated |
Cámara no funciona | ✅ Verificar HTTPS y permisos |
📚 Referencia
🔧 Métodos Principales
Método | Descripción | Ejemplo |
---|---|---|
start() | Inicia el detector | await jaakVisage.start() |
stop() | Detiene el detector | await jaakVisage.stop() |
showHelp() | Muestra ayuda | await jaakVisage.showHelp() |
📡 Eventos
Evento | Datos (event.detail) | Cuándo se dispara |
---|---|---|
statusUpdated | {status, message} | Cambio de estado del componente |
captureCompleted | {timestamp, confidence, imageData} | Captura exitosa |
error | {message, code?} | Error en operación |
⚙️ Propiedades
Propiedad | Tipo | Defecto | Ejemplo |
---|---|---|---|
debug | boolean | false | debug="true" |
camera | string | "auto" | camera="front" |
🛠️ Solución de Problemas
🚨 Problemas Frecuentes
El componente no responde
// ✅ Solución: Esperar definición
async function fixComponentIssue() {
await customElements.whenDefined('jaak-visage');
// Ahora es seguro usar el componente
}
Eventos no funcionan
// ❌ Incorrecto
jaakVisage.addEventListener('isReady', handler); // Este evento NO existe
// ✅ Correcto
jaakVisage.addEventListener('statusUpdated', (event) => {
const { status } = event.detail;
if (status === 'ready') {
// Componente listo
}
});
Cámara no se activa
Causa | Solución |
---|---|
HTTP en producción | ✅ Usar HTTPS |
Permisos bloqueados | ✅ Verificar configuración del navegador |
Cámara ocupada | ✅ Cerrar otras aplicaciones |
📞 ¿Necesitas Ayuda?
🆘 Información para soporte
- Descripción del problema: Qué intentas hacer vs qué sucede
- Código relevante: Fragmentos de implementación
- Consola del navegador: Screenshots de errores
- Entorno: Navegador, versión, dispositivo
🔍 Debug avanzado
// Herramientas de debugging
function enableDebugMode() {
const jaakVisage = document.querySelector('jaak-visage');
// Habilitar logs
jaakVisage.setAttribute('debug', 'true');
// Interceptar eventos
const events = ['statusUpdated', 'captureCompleted', 'error'];
events.forEach(eventName => {
jaakVisage.addEventListener(eventName, (event) => {
console.log(`🔍 [${eventName}]:`, event.detail);
});
});
// Información del sistema
console.log('📱 UserAgent:', navigator.userAgent);
console.log('📹 MediaDevices:', 'mediaDevices' in navigator);
console.log('🔧 WebComponents:', 'customElements' in window);
}
enableDebugMode();
¡Listo! 🎉
Has implementado exitosamente el componente de detección facial JAAK Visage con la configuración correcta de eventos y mejores prácticas.
Updated 17 days ago