Adzacam commited on
Commit
68485d3
1 Parent(s): 5f553ce

feat: integrate MLOps memory lookup and fuzzy matching into nlp analysis endpoint

Browse files
Files changed (1) hide show
  1. app.py +40 -3
app.py CHANGED
@@ -342,15 +342,48 @@ def procesar_registro_tabular(payload: ProcessSheetPayload, db: Session = Depend
342
  raise HTTPException(status_code=500, detail=str(err))
343
 
344
  @app.post("/api/v1/nlp/analyze")
345
- def analyze_nlp_only(payload: ProcessSheetPayload):
346
  """
347
  Fase 1: Solo ejecuta el modelo NLP (BETO) sobre el texto y devuelve las m茅tricas.
348
  NO inserta en la base de datos. Usado para el Staging area en el Frontend.
349
  """
350
  entidades = ner_engine.extract_entities(payload.texto_celda)
351
  confianza_ia = sum([e["score"] for e in entidades]) / len(entidades) if entidades else 1.0
352
- forzar_revision = confianza_ia < 0.60
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  alertas_disparadas = []
355
  if payload.nota_detectada <= 70.0:
356
  alertas_disparadas.append("RIESGO_ACADEMICO_CRITICO")
@@ -361,7 +394,11 @@ def analyze_nlp_only(payload: ProcessSheetPayload):
361
  "status": "analyzed",
362
  "confianza_modelo_beto": round(confianza_ia, 4),
363
  "requiere_auditoria_humana": forzar_revision,
364
- "alertas_estrategicas": alertas_disparadas
 
 
 
 
365
  }
366
 
367
  @app.post("/api/v1/nlp/quality-check")
 
342
  raise HTTPException(status_code=500, detail=str(err))
343
 
344
  @app.post("/api/v1/nlp/analyze")
345
+ def analyze_nlp_only(payload: ProcessSheetPayload, db: Session = Depends(get_db)):
346
  """
347
  Fase 1: Solo ejecuta el modelo NLP (BETO) sobre el texto y devuelve las m茅tricas.
348
  NO inserta en la base de datos. Usado para el Staging area en el Frontend.
349
  """
350
  entidades = ner_engine.extract_entities(payload.texto_celda)
351
  confianza_ia = sum([e["score"] for e in entidades]) / len(entidades) if entidades else 1.0
352
+ nombre_resuelto = payload.texto_celda[:200].strip()
353
 
354
+ # 1. Consultar log_auditoria_nlp (MLOps Memory)
355
+ log_memoria = db.query(LogAuditoriaNlp).filter(
356
+ LogAuditoriaNlp.texto_original == nombre_resuelto
357
+ ).order_by(LogAuditoriaNlp.created_at.desc()).first()
358
+
359
+ candidatos_difusos = []
360
+ regla_aplicada = False
361
+
362
+ if log_memoria:
363
+ # BETO "recuerda" la decisi贸n humana previa
364
+ nombre_resuelto = log_memoria.correccion_humana
365
+ confianza_ia = 1.0
366
+ forzar_revision = False
367
+ regla_aplicada = True
368
+ else:
369
+ # Fuzzy Matching
370
+ estudiantes_existentes = db.query(DimEstudiante).all()
371
+ best_match, score = find_best_match(nombre_resuelto, estudiantes_existentes)
372
+
373
+ # Generar Top 3 candidatos para el dropdown de resoluci贸n
374
+ from rapidfuzz import fuzz
375
+ for est in estudiantes_existentes:
376
+ s = fuzz.token_sort_ratio(nombre_resuelto.lower(), est.nombre_completo.lower()) / 100.0
377
+ if s > 0.4:
378
+ candidatos_difusos.append({"id": est.id_estudiante, "nombre": est.nombre_completo, "score": round(s, 2)})
379
+
380
+ candidatos_difusos = sorted(candidatos_difusos, key=lambda x: x["score"], reverse=True)[:3]
381
+
382
+ if score > 0.8:
383
+ confianza_ia = score
384
+
385
+ forzar_revision = confianza_ia < 0.60
386
+
387
  alertas_disparadas = []
388
  if payload.nota_detectada <= 70.0:
389
  alertas_disparadas.append("RIESGO_ACADEMICO_CRITICO")
 
394
  "status": "analyzed",
395
  "confianza_modelo_beto": round(confianza_ia, 4),
396
  "requiere_auditoria_humana": forzar_revision,
397
+ "alertas_estrategicas": alertas_disparadas,
398
+ "entidades_nlp": entidades,
399
+ "candidatos_difusos": candidatos_difusos,
400
+ "regla_memoria_aplicada": regla_aplicada,
401
+ "nombre_resuelto": nombre_resuelto
402
  }
403
 
404
  @app.post("/api/v1/nlp/quality-check")