Adzacam commited on
Commit
d923814
·
1 Parent(s): 452cdbb

Fix: Eliminar importación no utilizada de engine para estabilizar ASGI

Browse files
Files changed (1) hide show
  1. app.py +91 -0
app.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import logging
3
+ from typing import List
4
+ from fastapi import FastAPI, Depends, HTTPException, status
5
+ from pydantic import BaseModel
6
+ from sqlalchemy.orm import Session
7
+ from database import get_db, DimEstudiante, FactRendimientoAcademico
8
+ from ner_engine import ner_engine
9
+
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ app = FastAPI(
14
+ title="GiraGroup BI Backend Cloud",
15
+ description="API para Tecnologías Emergentes II con BETO y Supabase",
16
+ version="1.0.0"
17
+ )
18
+
19
+ # El resto del código de ProcessSheetPayload y endpoints se mantiene exactamente igual...
20
+
21
+ class ProcessSheetPayload(BaseModel):
22
+ texto_celda: str
23
+ nota_detectada: float
24
+ asistencia: float
25
+ incumplimiento_tareas: float
26
+ id_docente: int
27
+ id_modulo: int
28
+ id_tiempo: int
29
+ id_documento: int
30
+ id_usuario: int
31
+
32
+ @app.get("/")
33
+ def read_root():
34
+ return {
35
+ "status": "healthy",
36
+ "service": "GiraGroup BI Backend API Cloud",
37
+ "ner_initialized": ner_engine._initialized or ner_engine.pipeline is not None
38
+ }
39
+
40
+ @app.post("/api/v1/ingesta/tabular", status_code=status.HTTP_201_CREATED)
41
+ def procesar_registro_tabular(payload: ProcessSheetPayload, db: Session = Depends(get_db)):
42
+ entidades = ner_engine.extract_entities(payload.texto_celda)
43
+ confianza_ia = sum([e["score"] for e in entidades]) / len(entidades) if entidades else 1.0
44
+
45
+ forzar_revision = False
46
+ if confianza_ia < 0.60:
47
+ forzar_revision = True
48
+
49
+ nombre_resuelto = payload.texto_celda.strip()
50
+ estudiante = db.query(DimEstudiante).filter(DimEstudiante.nombre_completo == nombre_resuelto).first()
51
+
52
+ if not estudiante:
53
+ estudiante = DimEstudiante(nombre_completo=nombre_resuelto)
54
+ db.add(estudiante)
55
+ db.commit()
56
+ db.refresh(estudiante)
57
+
58
+ alertas_disparadas = []
59
+ if payload.nota_detectada <= 70.0:
60
+ alertas_disparadas.append("RIESGO_ACADEMICO_CRITICO")
61
+ if payload.asistencia < 70.0 or payload.incumplimiento_tareas > 30.0:
62
+ alertas_disparadas.append("RIESGO_DESERCION_ALTA")
63
+
64
+ try:
65
+ nuevo_hecho = FactRendimientoAcademico(
66
+ id_estudiante=estudiante.id_estudiante,
67
+ id_docente=payload.id_docente,
68
+ id_modulo=payload.id_modulo,
69
+ id_tiempo=payload.id_tiempo,
70
+ id_documento=payload.id_documento,
71
+ id_usuario_carga=payload.id_usuario,
72
+ nota_final=payload.nota_detectada,
73
+ asistencia_pct=payload.asistencia,
74
+ incumplimiento_actividades_pct=payload.incumplimiento_tareas,
75
+ nivel_confianza_ia=confianza_ia,
76
+ requiere_revision=forzar_revision
77
+ )
78
+ db.add(nuevo_hecho)
79
+ db.commit()
80
+
81
+ return {
82
+ "status": "processed",
83
+ "id_estudiante_asignado": estudiante.id_estudiante,
84
+ "confianza_modelo_beto": round(confianza_ia, 4),
85
+ "requiere_auditoria_humana": forzar_revision,
86
+ "alertas_estrategicas": alertas_disparadas
87
+ }
88
+ except Exception as err:
89
+ db.rollback()
90
+ logger.error(f"Fallo en persistencia: {err}")
91
+ raise HTTPException(status_code=500, detail="Error al escribir en Supabase.")