diagnostic / vibia_ai /predict_category.py
vibiatest's picture
Upload 12 files
35abf28 verified
Raw
History Blame Contribute Delete
4.89 kB
from collections import Counter
import json
def predict_category(new_incident, k=3, supabase=None, embed_text=None):
"""
Predice la categoría de un nuevo incidente basándose en similitudes con embeddings
almacenados en Supabase. Retorna los niveles de clasificación, el id_case más similar
y el tareas_json completo asociado.
"""
if supabase is None or embed_text is None:
raise ValueError("Debes proporcionar los parámetros 'supabase' y 'embed_text'.")
# Obtener embedding del nuevo incidente
query_emb = embed_text(new_incident)
# Llamada al procedimiento remoto en Supabase
result = supabase.rpc("match_case_email", {
"query_embedding": query_emb,
"match_count": k
}).execute()
matches = result.data
if not matches:
return {
"niveles": None,
"id_case": None,
"tareas_json": None
}
# Mostrar matches y validar tareas_json
for i, m in enumerate(matches):
print(f"\n🔍 Match #{i+1} - ID_CASE: {m['id_case']} - Similaridad: {m['similarity']:.2f}")
if m.get("tareas_json"):
print("🧠 tareas_json detectado ✅")
print(str(m["tareas_json"])[:500]) # solo muestra primeros 500 caracteres
else:
print("⚠️ tareas_json está vacío o es None ❌")
# Clasificación por mayoría (niveles)
niveles = {}
for lvl in ["case_level_0", "case_level_1", "case_level_2", "case_level_3"]:
valores = [m[lvl] for m in matches if m.get(lvl)]
niveles[lvl.replace("case_", "nivel_")] = Counter(valores).most_common(1)[0][0] if valores else None
print("\n📥 Input del cliente:")
print(new_incident)
print("\n🔎 Casos similares:")
for m in matches:
print(
f" ({m['similarity']:.2f}) [{m['id_case']}] {m['description_context']} → "
f"{m['case_level_0']} / {m['case_level_1']} / {m['case_level_2']} / {m['case_level_3']}"
)
print("\n📊 Clasificación:")
for key, val in niveles.items():
print(f" {key.capitalize()}: {val}")
# Obtener el match con mayor similarity (siempre, tenga o no tareas_json)
match_mas_similar = matches[0] if matches else None
# Obtener el match con tareas_json válido y mejor similarity
match_con_tareas = next(
(m for m in sorted(matches, key=lambda x: x["similarity"], reverse=True)
if m.get("tareas_json")),
None
)
if not match_con_tareas:
print("❌ Ningún match tiene tareas_json válido.")
resumen = (
f"📥 **Correo contextualizado:**\n{new_incident}\n\n"
"🔎 **Casos similares encontrados (sin tareas_json):**\n"
+ "\n".join([
f"({m['similarity']:.2f}) [ID_CASE {m['id_case']}] {m['description_context']} → "
f"{m['case_level_0']} / {m['case_level_1']} / {m['case_level_2']} / {m['case_level_3']}"
for m in matches
])
)
return {
"niveles": niveles,
"id_case": None,
"tareas_json": None,
"resumen": resumen
}
# Extraer el tareas_json completo (sin cortar)
tareas_json = match_con_tareas["tareas_json"]
id_case_con_tareas = match_con_tareas["id_case"]
id_case_mas_similar = match_mas_similar["id_case"]
# Extraer la clasificación del caso más similar (real)
nivel_0 = match_mas_similar.get("case_level_0")
nivel_1 = match_mas_similar.get("case_level_1")
nivel_2 = match_mas_similar.get("case_level_2")
nivel_3 = match_mas_similar.get("case_level_3")
print(f"\n✅ Retornando tareas_json del caso más similar (ID_CASE: {id_case_mas_similar})")
# 🔹 Construir resumen legible para interfaz
resumen = f"📥 Interpretación del correo:\n{new_incident}\n\n"
resumen += "🔎 Casos similares de Product Issues en Vibia encontrados desde Julio 2025:\n"
for m in matches[:3]:
resumen += (
f" 🎯 Caso Nº {m['id_case']} (score: {m['similarity']:.2f}) : {m['description_context'][:400]}...\n"
f" Clasificación → {m['case_level_0']} / {m['case_level_1']} / {m['case_level_2']} / {m['case_level_3']}\n\n"
)
resumen += (
f"🧠 Clasificación recomendada (basada en el caso más similar Nº {id_case_mas_similar})\n"
f" Level 0: {nivel_0}\n"
f" Level 1: {nivel_1}\n"
f" Level 2: {nivel_2}\n"
f" Level 3: {nivel_3}\n\n"
)
# ✅ Retornar ambos: resumen legible + datos técnicos
return {
"resumen": resumen,
"niveles": niveles,
"id_case": id_case_con_tareas,
"tareas_json": tareas_json
}