Simulador local de entrevistas técnicas con IA. Practica entrevistas orales conversacionales, casos de diseño y ejercicios técnicos cortos desde el navegador.
Sin backend propio más allá de un servidor estático en Node: tus perfiles, handbooks y claves API se quedan en tu máquina.
- Simulador oral — entrevista conversacional con un perfil de entrevistador configurable y contexto de handbook.
- Casos prácticos — escenarios de diseño (pedidos, auth, APIs, stock, reservas, pagos, etc.).
- Simulador técnico — drills cortos con comprobación por palabras clave.
- Varios proveedores de IA — OpenRouter, NVIDIA NIM y Gemini (con proxy local para evitar CORS).
- Dictado por voz — Web Speech API en español (
es-ES). - PWA — instalable en móvil; layout responsive con menú lateral.
- HTTPS local — certificado autofirmado para usar el micrófono desde el móvil en la LAN.
- Node.js 18+ (usa
fetchnativo enserver.js) - Windows con PowerShell (scripts
start.ps1/stop.ps1; en otros SO puedes usarnode server.jsdirectamente) - Clave API de al menos un proveedor soportado
git clone https://github.com/Pacoaldev/TrainerExpert.git
cd TrainerExpert
Copy-Item .env.example .env
Copy-Item candidate.example.md candidate.md
Copy-Item interviewer.example.md interviewer.md- Edita
.envy añade tus claves API. - Opcional: personaliza
candidate.md,interviewer.mdy añade handbooks enhandbooks/(parte dehandbooks/handbook.example.md). - Arranca el servidor:
.\start.ps1- Abre
http://localhost:8080, elige un caso en Inicio y empieza la entrevista.
Para detener el servidor sin cerrar el navegador:
.\stop.ps1O usa Apagar Aplicación en la interfaz (detiene Node e intenta cerrar solo la pestaña actual).
| Variable | Proveedor | Notas |
|---|---|---|
OPENROUTER_API_KEYS |
OpenRouter | Varias claves separadas por coma o una por línea |
NVIDIA_API_KEYS |
NVIDIA NIM | Pasa por el proxy local (/api/proxy/chat) |
GEMINI_API_KEYS |
Google Gemini | Igual; modelo por defecto gemini-3.5-flash |
También puedes pegar una clave manualmente en el panel Configuración. Las claves del .env tienen prioridad; si una falla por cuota o auth, rota a la siguiente.
| Archivo | Uso |
|---|---|
candidate.md |
Perfil del candidato (tú). Gitignored. |
interviewer.md |
Tono y criterio del entrevistador. Gitignored. |
handbooks/*.md |
Contexto de producto/dominio para el prompt. Gitignored salvo handbook.example.md. |
Los archivos *.example.* son plantillas de referencia; cópialos y renómbralos para tu uso local.
| Proveedor | Modelo por defecto | Proxy local |
|---|---|---|
| OpenRouter | openrouter/free |
No |
| NVIDIA NIM | meta/llama-3.1-8b-instruct |
Sí |
| Gemini | gemini-3.5-flash |
Sí |
NVIDIA y Gemini llaman a ./api/proxy/chat en server.js para evitar bloqueos CORS desde el navegador.
Chrome bloquea el micrófono en http://192.168.x.x. En LAN hace falta HTTPS.
- Genera el certificado (solo la primera vez):
powershell -ExecutionPolicy Bypass -File .\scripts\generate-certs.ps1(start.ps1 también lo genera si falta certs/dev.pfx.)
-
Arranca el servidor. Debe escuchar:
http://localhost:8080https://0.0.0.0:8443
-
En el móvil (misma Wi‑Fi):
https://<tu-IP>:8443
(ipconfig en Windows para ver tu IP.)
- Acepta el aviso del certificado autofirmado (Avanzado → Continuar).
- Permite el micrófono cuando Chrome lo pida.
- Opcional: Añadir a pantalla de inicio (PWA).
Si usas http://<tu-IP>:8080, el micrófono no funcionará aunque des permisos en Android.
Si no carga desde el móvil, permite Node en los puertos 8080 y 8443 (regla TCP entrante).
TrainerExpert/
├── app.js # Lógica de la app (chat, perfiles, drills)
├── server.js # Servidor estático + proxy API + shutdown
├── scenarios.js # Casos de entrevista y drills técnicos
├── index.html / style.css
├── sw.js # Service worker (PWA)
├── vendor/ # Dependencias locales (marked)
├── start.ps1 / stop.ps1
├── scripts/generate-certs.ps1
├── handbooks/ # Tus handbooks locales (gitignored)
├── .env.example # Plantilla de claves
├── candidate.example.md
└── interviewer.example.md
Mejoras de seguridad y rendimiento aplicadas al servidor y la app:
- Path traversal corregido en
server.js— la validación anterior constartsWith(__dirname)era vulnerable a..URL‑encoded. Ahora se decodifica la URL, se resuelve conpath.resolvey se verifica que el resultado sigue dentro del directorio del proyecto. - Archivos sensibles bloqueados —
/.env,/candidate.mde/interviewer.mddevuelven403. Las claves ya no se sirven por HTTP plano. - Lectura del
.envdesde el backend — nuevo endpointGET /api/env-keys?provider=Xque parsea el.envuna sola vez al arrancar (cache en memoria) y devuelve solo el array de claves del proveedor solicitado. El navegador deja de hacerfetch('./.env'). - Caché HTTP deshabilitada — todas las respuestas estáticas llevan
Cache-Control: no-storepara evitar que el navegador o el service worker retengan claves o perfiles. - Mejor rendimiento al escribir la API key — antes, cada pulsación de tecla disparaba un
fetchal.envy lo re‑parseaba. Ahora solo se actualiza el override manual. markedlocal — el renderizador de Markdown se sirve desdevendor/marked.min.jsen lugar dehttps://esm.run/marked. Sin dependencia de red en el arranque ni bloqueos si el CDN está caído.
.env,candidate.md,interviewer.mdyhandbooks/(salvo el ejemplo) están en.gitignore.- Las peticiones a la IA salen desde tu navegador o el proxy local de tu PC; no hay servidor central de TrainerExpert.
- No subas claves API ni datos personales al repositorio.
Revisa REGLAS.md antes de proponer cambios. Resumen: diff mínimo, sin secretos en git, sin commits automáticos sin acuerdo.
MIT — Copyright (c) 2026 Pacoaldev
