Spaces:
Running
Running
| 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 | |