7f32380e0a
Configure GitLab deploy pipeline for this app and switch backend/frontend endpoint defaults from localhost to sinbad2.ujaen.es, including Docker, env files, API client, CORS, and docs.
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://sinbad2.ujaen.es:8074
|
|
```
|
|
|
|
## 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.
|