File size: 4,777 Bytes
9a1014e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import json
from pydantic import BaseModel, Field
from typing import List, Dict, Any, Optional
from hf_qwen_client import generate_response
from rag_context import retrieve_document_context
from chat_history import list_conversations, list_messages, format_history

class AnalisisIA(BaseModel):
    redaccion_tecnica: str = Field(..., description="Análisis técnico detallado basado en las micrografías y contexto de la muestra. Máximo 3 párrafos.")
    resumen_ejecutivo: str = Field(..., description="Resumen conciso y al grano para el cliente final sobre los resultados.")
    conformidad_norma: bool = Field(..., description="¿Cumple la muestra con los estándares ASTM E112 en base a los datos proporcionados?")
    observaciones: str = Field(..., description="Observaciones adicionales relevantes.")
    analisis_regiones: Dict[str, str] = Field(
        default_factory=dict,
        description="Breve análisis o comentario de no más de 1 párrafo para cada región identificada en la muestra, usando el nombre de la región como clave."
    )
    conclusion: str = Field(..., description="Conclusión final y de cierre del reporte. Debe ser un párrafo contundente.")

def get_chat_context(user_id: int) -> str:
    try:
        conversations = list_conversations(user_id)
        if not conversations:
            return "No hay conversaciones previas del usuario."
        
        # Tomamos la ultima conversacion del usuario
        latest_conv_id = conversations[0]["id"]
        messages = list_messages(latest_conv_id, user_id, limit=20)
        history = format_history(messages)
        return history
    except Exception as e:
        print(f"Error fetching chat history: {e}")
        return "No se pudo recuperar el historial de chat."

def generate_agentic_report(report_id: int, muestra_id: int, user_id: int, raw_data: dict) -> dict:
    
    chat_context = get_chat_context(user_id)
    
    # RAG: Retrieve ASTM document context
    # Create a search query based on the data
    material = raw_data.get('muestra', {}).get('material', 'metal')
    rag_query = f"norma ASTM E112 tamaño de grano {material}"
    astm_context = retrieve_document_context(rag_query, k=3)
    
    system_prompt = f"""Eres un experto metalurgista especializado en la norma ASTM E112.
Tu tarea es analizar los datos de mediciones de tamaño de grano de una muestra y generar conclusiones técnicas de alto valor.

CONTEXTO NORMATIVO (ASTM):
{astm_context}

CONTEXTO ADICIONAL DEL CLIENTE (Chat reciente):
{chat_context}

Debes proporcionar un JSON válido con el análisis de la muestra que respete estrictamente el esquema solicitado.
Claves requeridas: "redaccion_tecnica", "resumen_ejecutivo", "conformidad_norma" (boolean), "observaciones", "analisis_regiones" (diccionario de region -> texto), "conclusion".
Mantén la redacción técnica precisa pero limitada a 3 párrafos como máximo.
"""

    import copy
    clean_data = copy.deepcopy(raw_data)
    
    # Remove heavy arrays and URLs to avoid exceeding context limits on free API
    if 'material' in clean_data:
        clean_data['material'].pop('muestra_image_url', None)
        clean_data['material'].pop('quality_hist_path', None)
        if 'region_data' in clean_data['material']:
            for region_name, rdata in clean_data['material']['region_data'].items():
                rdata.pop('imagen', None)
                rdata.pop('hist_path', None)
                for micro in rdata.get('micrografias', []):
                    micro.pop('imagen', None)
                    micro.pop('measure_imagen', None)
                    micro.pop('distribution_um', None)

    user_prompt = f"Genera el análisis técnico en JSON puro (sin Markdown) para la siguiente muestra:\n{json.dumps(clean_data, ensure_ascii=False)}"

    try:
        content = generate_response(
            f"{system_prompt}\n\n{user_prompt}",
            max_new_tokens=1500,
        )
        content = content.strip()
        if content.startswith("```json"):
            content = content[7:-3].strip()
        elif content.startswith("```"):
            content = content[3:-3].strip()
            
        analisis = json.loads(content)
        validated_analisis = AnalisisIA(**analisis)
        
        raw_data["analisis_ia"] = validated_analisis.model_dump()
        return raw_data
        
    except Exception as e:
        print(f"Error calling LLM: {e}")
        raw_data["analisis_ia"] = {
            "redaccion_tecnica": "No se pudo generar el análisis automático.",
            "resumen_ejecutivo": "Error en el agente de IA.",
            "conformidad_norma": False,
            "observaciones": str(e),
            "conclusion": "No se pudo generar la conclusión."
        }
        return raw_data