946f16a633
Introduce a full Vite/React UI for exams, auth, materials, images, generation, and export. Adapt backend for Sinbad2IA chat API, bcrypt passwords, CORS on port 5173, and schema migrations.
186 lines
5.2 KiB
Markdown
186 lines
5.2 KiB
Markdown
# GenExamenes IA
|
|
|
|
Backend para generar exámenes con IA, procesar la salida de un LLM y exportar preguntas a Moodle XML.
|
|
|
|
**Guía detallada de flujo, endpoints, ejemplos y errores:** [GUIA_API_Y_FLUJO.md](GUIA_API_Y_FLUJO.md)
|
|
|
|
El proyecto está centrado en backend. La carpeta `frontend` se mantiene vacía a nivel de aplicación, aunque existe un servicio en Docker Compose para reservar el despliegue futuro.
|
|
|
|
## Stack
|
|
|
|
- FastAPI
|
|
- PostgreSQL
|
|
- SQLAlchemy
|
|
- Cliente LLM para Sinbad2IA UJA (`POST /api/chat`, modelo `qwen3.5:35b`)
|
|
- Docker Compose con servicios `backend`, `frontend` y `db`
|
|
|
|
## Puesta en Marcha
|
|
|
|
Copia el ejemplo de variables dentro de la carpeta del backend:
|
|
|
|
```bash
|
|
cp backend/.env.example backend/.env
|
|
```
|
|
|
|
Después levanta los servicios:
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
La API queda disponible en:
|
|
|
|
```text
|
|
http://localhost:8000
|
|
```
|
|
|
|
## Configuración
|
|
|
|
El archivo de entorno debe estar en `backend/.env`.
|
|
|
|
Variables principales:
|
|
|
|
- `JWT_SECRET_KEY`: secreto para firmar tokens JWT (mínimo 32 caracteres).
|
|
- `JWT_EXPIRE_MINUTES`: duración del token de acceso.
|
|
- `GOOGLE_CLIENT_ID`: Client ID de OAuth 2.0 en Google Cloud Console (para `/auth/google`).
|
|
- `DATABASE_URL`: conexión PostgreSQL usada por el backend.
|
|
- `LLM_BASE_URL`: URL base del servidor (por defecto ``; el cliente usa `/api/chat`).
|
|
- `LLM_MODEL`: modelo (por defecto `qwen3.5:35b`).
|
|
- `LLM_TIMEOUT_SECONDS`: tiempo máximo de espera (por defecto 180 s).
|
|
- `LLM_API_KEY`: opcional, solo si el servidor exige autenticación.
|
|
- `ALLOWED_ORIGINS`: orígenes permitidos por CORS.
|
|
- `MAX_STORAGE_BYTES_PER_TEMPLATE`: cupo total de almacenamiento por examen (materiales + imágenes).
|
|
|
|
Todas las rutas bajo `/exam` requieren autenticación de usuario con:
|
|
|
|
```http
|
|
Authorization: Bearer <access_token>
|
|
```
|
|
|
|
Si ya tenías una base de datos creada antes de añadir usuarios, recrea el volumen:
|
|
|
|
```bash
|
|
docker compose down -v
|
|
docker compose up --build
|
|
```
|
|
|
|
## Flujo de Usuario
|
|
|
|
1. Registrarse o iniciar sesión.
|
|
2. Crear una plantilla de examen (queda asociada al usuario).
|
|
3. Subir materiales de referencia (PDF, DOCX, TXT, PNG, JPG…) a la plantilla.
|
|
4. Generar un prompt guiado para el LLM (incluye el texto extraído de los ficheros).
|
|
5. Generar preguntas automáticamente con el LLM o parsear una salida externa en JSON/TXT.
|
|
6. Guardar las preguntas validadas en PostgreSQL.
|
|
7. Consultar el historial de exámenes creados.
|
|
8. Exportar el examen a Moodle XML, TXT o JSON.
|
|
|
|
## Endpoints
|
|
|
|
`GET /health`
|
|
|
|
Comprueba que la API está levantada.
|
|
|
|
`POST /auth/register`
|
|
|
|
Registra un usuario con email y contraseña.
|
|
|
|
`POST /auth/login`
|
|
|
|
Devuelve un token JWT para usar en las rutas protegidas.
|
|
|
|
`POST /auth/google`
|
|
|
|
Recibe el `id_token` de Google (Sign in with Google en el frontend), verifica la cuenta y devuelve el mismo JWT de la API.
|
|
|
|
`GET /auth/me`
|
|
|
|
Devuelve los datos del usuario autenticado.
|
|
|
|
`GET /exam/history`
|
|
|
|
Lista el historial de exámenes del usuario (plantillas, preguntas y exportaciones).
|
|
|
|
`POST /exam/templates/{template_id}/materials`
|
|
|
|
Sube un fichero (`multipart/form-data`, campo `file`). Formatos: PDF, DOCX, TXT, MD, PNG, JPG, WEBP. Extrae texto y lo guarda como contexto.
|
|
|
|
`GET /exam/templates/{template_id}/materials`
|
|
|
|
Lista los materiales subidos a una plantilla.
|
|
|
|
`DELETE /exam/templates/{template_id}/materials/{material_id}`
|
|
|
|
Elimina un material.
|
|
|
|
`POST /exam/templates/{template_id}/images`
|
|
|
|
Sube una imagen para preguntas visuales (`file`, opcional `caption`). No se usa OCR: la imagen se muestra en el examen y se embebe en el XML de Moodle.
|
|
|
|
`GET /exam/templates/{template_id}/images`
|
|
|
|
Lista las imágenes de la plantilla.
|
|
|
|
`GET /exam/images/{image_id}/content`
|
|
|
|
Devuelve la imagen (requiere JWT). Para previsualizar en el frontend o en Moodle tras importar.
|
|
|
|
`DELETE /exam/templates/{template_id}/images/{image_id}`
|
|
|
|
Elimina una imagen.
|
|
|
|
`PATCH /exam/questions/{question_id}/image`
|
|
|
|
Vincula o desvincula una imagen a una pregunta existente (`{"image_id": "uuid"}` o `null`).
|
|
|
|
`POST /exam/templates`
|
|
|
|
Crea una plantilla con materia, nivel educativo, tipos de pregunta, puntuación, penalización y dificultad.
|
|
|
|
`GET /exam/templates`
|
|
|
|
Lista las plantillas del usuario autenticado.
|
|
|
|
`GET /exam/templates/{template_id}`
|
|
|
|
Obtiene una plantilla concreta.
|
|
|
|
`GET /exam/templates/{template_id}/storage`
|
|
|
|
Muestra cuánto espacio usa el examen (materiales + imágenes) y el límite configurado.
|
|
|
|
`POST /exam/prompts/{template_id}`
|
|
|
|
Genera un prompt estructurado para IA.
|
|
|
|
`POST /exam/generate`
|
|
|
|
Llama al LLM configurado, parsea la respuesta y guarda las preguntas.
|
|
|
|
`POST /exam/parse`
|
|
|
|
Procesa una salida externa de IA en formato `json` o `txt`.
|
|
|
|
`GET /exam/export/xml/{template_id}`
|
|
|
|
Exporta las preguntas en Moodle XML.
|
|
|
|
`GET /exam/export/txt/{template_id}`
|
|
|
|
Exporta las preguntas en texto plano.
|
|
|
|
`GET /exam/export/json/{template_id}`
|
|
|
|
Exporta las preguntas en JSON.
|
|
|
|
## Seguridad
|
|
|
|
- Registro e inicio de sesión con contraseña hasheada (bcrypt).
|
|
- Autenticación JWT por usuario.
|
|
- Cada examen pertenece a un único usuario; no se puede acceder al de otro.
|
|
- Rate limiting por cliente.
|
|
- Límite de tamaño de petición.
|
|
- Validación de entrada con Pydantic.
|
|
- Manejo uniforme de errores HTTP.
|
|
- Sanitización básica de prompts y respuestas antes de persistir/exportar.
|