OnceDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Pierrot-01/Hackathon_epis_2026/llms.txt
Use this file to discover all available pages before exploring further.
classifier.py has determined a student’s risk level, backend/ia_client.py takes over to generate the human-readable content that the teacher actually reads. This module calls Google Gemini 2.0 Flash with a strict system prompt and a per-student user prompt, then parses the JSON response into an explanation and a recommendation. If the API is unavailable or times out, the module falls back to pre-generated cached responses, ensuring teachers always see useful content — never a raw error message.
Model Configuration
| Parameter | Value | Rationale |
|---|---|---|
| Model | gemini-2.0-flash | Low latency, sufficient quality for 2–3 sentence outputs |
| Max output tokens | 300 | Each of explicacion and recomendacion should be 2–3 sentences |
| Timeout | 10 seconds | Rural schools may have slow connections; breaching triggers fallback |
| Temperature | 0.7 | Allows variation between students while keeping outputs coherent |
System Prompt (§5.2) — The 8 Non-Negotiable Language Rules
The system prompt is fixed at specification time and encodes Article IV of the project constitution: all AI-generated text must be constructive, respectful, and non-stigmatising. It is sent with every Gemini request.User Prompt Construction (§5.3)
construir_user_prompt() builds the per-student prompt from the classifier’s output. It passes the human-readable motives list — not the raw numeric values — so Gemini can reference specific observations without needing access to the original dataset.
generar_explicacion() — Full Signature
The Three origen_ia States
Every response from generar_explicacion() includes an origen_ia field. The frontend uses this tag to show the teacher where the content came from.
| Value | Meaning | When it occurs |
|---|---|---|
"vivo" | Live Gemini API response | API key configured, call succeeded within 10 s |
"fallback" | Pre-generated cache hit | API failed/timed out AND cache/respuestas_ia.json has an entry for this student |
"error_sin_cache" | No API, no cache | API failed AND no cache entry exists — last-resort response shown |
"no_aplica" | Not applicable | Student’s risk level is ⚪ — no AI response is needed |
"no_aplica" is returned immediately before any API call is made. The ⚪ level means all three data variables are missing, so there are no concrete motives for Gemini to explain.Special Case: ⚪ Level
Students classified asNIVEL_INSUFICIENTE are skipped entirely:
Resilience Flow
Check for API key
If
GEMINI_API_KEY is not set in the environment (loaded from backend/.env), the module skips the API call entirely and goes straight to the fallback cache lookup.Call Gemini with strict timeout
The API call is wrapped in
asyncio.wait_for(..., timeout=TIMEOUT_SEGUNDOS). The call is run via run_in_executor so it doesn’t block the FastAPI event loop while other students are being processed in parallel.Strip Markdown fences and parse JSON
Gemini sometimes wraps its response in a
```json code block despite Rule 6. The module strips any leading ``` and trailing ``` before calling json.loads().On any error → fallback cache
asyncio.TimeoutError and all other exceptions are caught in a single except block. The module then calls obtener_fallback(id_estudiante) from fallback.py. If a cache entry exists, it is returned with origen_ia = "fallback".Sample Gemini Response
When the model follows Rule 6 correctly, the raw API response text looks like:json.loads(), the explicacion and recomendacion fields are extracted, validated as non-empty strings, and returned alongside origen_ia: "vivo". The disk cache is populated separately — generar_cache.py calls guardar_en_cache() during pre-generation; ia_client.py itself does not write to disk after a live response.
Integration with the Session Cache
main.py wraps every processed student result in _resultados_cache (an in-memory dict keyed by student ID). On subsequent requests to GET /api/estudiantes, cached results are returned directly without re-calling generar_explicacion(). This avoids repeated Gemini charges during a demo session and keeps response times fast.
?force_refresh=true to any endpoint to bypass both the session cache and re-run the full classify + AI pipeline.