Spaces:
Sleeping
Sleeping
| 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 | |
| } | |