✅ Validación de Coherencia IA Implementada
Cambios en el Backend (v1.0.96) Nuevo campo expected_answer en el análisis de IA: La IA ahora retorna cuál debería ser la respuesta correcta según lo que observa en la imagen Se incluyen las opciones de respuesta disponibles en el prompt para que la IA elija la correcta Extracción de opciones de pregunta: El sistema extrae las opciones disponibles (Buen Estado, Mal Estado, etc.) Las envía a la IA para que determine cuál es la respuesta esperada Cambios en el Frontend Validación antes de continuar: Cuando el mecánico intenta avanzar a la siguiente pregunta o firmar El sistema compara su respuesta con expected_answer del análisis de IA Si NO coinciden, aparece un popup con:
This commit is contained in:
@@ -276,7 +276,7 @@ def extract_pdf_text_smart(pdf_content: bytes, max_chars: int = None) -> dict:
|
||||
}
|
||||
|
||||
|
||||
BACKEND_VERSION = "1.0.95"
|
||||
BACKEND_VERSION = "1.0.96"
|
||||
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
|
||||
|
||||
# S3/MinIO configuration
|
||||
@@ -1807,8 +1807,8 @@ def generate_inspection_pdf(inspection_id: int, db: Session) -> str:
|
||||
elements.append(Spacer(1, 3*mm))
|
||||
|
||||
# Cuadro de métricas con diseño moderno
|
||||
metric_label = ParagraphStyle('metric_label', parent=small_style, fontSize=9, textColor=colors.HexColor('#64748b'), alignment=TA_CENTER)
|
||||
metric_value = ParagraphStyle('metric_value', parent=info_style, fontSize=16, fontName='Helvetica-Bold', alignment=TA_CENTER)
|
||||
metric_label = ParagraphStyle('metric_label', parent=small_style, fontSize=10, textColor=colors.HexColor('#64748b'), alignment=TA_CENTER)
|
||||
metric_value = ParagraphStyle('metric_value', parent=info_style, fontSize=18, fontName='Helvetica-Bold', alignment=TA_CENTER)
|
||||
|
||||
metrics_data = [
|
||||
[Paragraph("Puntuación", metric_label), Paragraph("Ítems Críticos", metric_label)],
|
||||
@@ -1818,13 +1818,13 @@ def generate_inspection_pdf(inspection_id: int, db: Session) -> str:
|
||||
]
|
||||
]
|
||||
|
||||
score_table = Table(metrics_data, colWidths=[90*mm, 90*mm])
|
||||
score_table = Table(metrics_data, colWidths=[90*mm, 90*mm], rowHeights=[12*mm, 18*mm])
|
||||
score_table.setStyle(TableStyle([
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#f8fafc')),
|
||||
('BACKGROUND', (0, 1), (-1, -1), colors.white),
|
||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
||||
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
||||
('PADDING', (0, 0), (-1, -1), 12),
|
||||
('PADDING', (0, 0), (-1, -1), 16),
|
||||
('BOX', (0, 0), (-1, -1), 2, score_color),
|
||||
('LINEABOVE', (0, 1), (-1, 1), 1.5, score_color),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor('#e2e8f0')),
|
||||
@@ -2733,12 +2733,19 @@ async def analyze_image(
|
||||
|
||||
# Obtener contexto de la pregunta si se proporciona
|
||||
question_obj = None
|
||||
question_options = []
|
||||
if question_id:
|
||||
question_obj = db.query(models.Question).filter(models.Question.id == question_id).first()
|
||||
print(f"📋 Pregunta encontrada:")
|
||||
print(f" - ID: {question_obj.id}")
|
||||
print(f" - Texto: {question_obj.text}")
|
||||
print(f" - Tipo: {question_obj.options.get('type') if question_obj.options else 'N/A'}")
|
||||
print(f" - ai_prompt en DB: {question_obj.ai_prompt[:100] if question_obj.ai_prompt else 'NO TIENE'}")
|
||||
|
||||
# Extraer opciones de respuesta si existen
|
||||
if question_obj.options and 'options' in question_obj.options:
|
||||
question_options = question_obj.options['options']
|
||||
print(f" - Opciones disponibles: {question_options}")
|
||||
|
||||
# Si no se proporciona custom_prompt en el Form, usar el de la pregunta
|
||||
if not custom_prompt and question_obj and question_obj.ai_prompt:
|
||||
@@ -2774,6 +2781,11 @@ INFORMACIÓN DEL VEHÍCULO INSPECCIONADO:
|
||||
try:
|
||||
# Construir prompt dinámico basado en la pregunta específica
|
||||
if question_obj:
|
||||
# Agregar información de opciones de respuesta al prompt
|
||||
options_context = ""
|
||||
if question_options:
|
||||
options_context = f"\n\nOPCIONES DE RESPUESTA DISPONIBLES:\n{', '.join(question_options)}\n\nEn el campo 'expected_answer', indica cuál de estas opciones es la más apropiada según lo que observas en la imagen."
|
||||
|
||||
# Usar prompt personalizado si está disponible
|
||||
if custom_prompt:
|
||||
# Prompt personalizado - DIRECTO Y SIMPLE
|
||||
@@ -2782,13 +2794,14 @@ INFORMACIÓN DEL VEHÍCULO INSPECCIONADO:
|
||||
{vehicle_context}
|
||||
|
||||
TAREA ESPECÍFICA:
|
||||
{custom_prompt}
|
||||
{custom_prompt}{options_context}
|
||||
|
||||
Responde SOLO en formato JSON válido (sin markdown, sin ```json):
|
||||
{{
|
||||
"status": "ok",
|
||||
"observations": "Describe lo que observas en la imagen en relación a la tarea solicitada",
|
||||
"recommendation": "Acción sugerida basada en lo observado",
|
||||
"expected_answer": "La respuesta que debería seleccionar el mecánico según lo observado (si hay opciones disponibles)",
|
||||
"confidence": 0.85,
|
||||
"context_match": true
|
||||
}}
|
||||
@@ -2818,7 +2831,7 @@ IMPORTANTE:
|
||||
{vehicle_context}
|
||||
|
||||
PREGUNTA ESPECÍFICA A RESPONDER: "{question_text}"
|
||||
Sección: {section}
|
||||
Sección: {section}{options_context}
|
||||
|
||||
Analiza la imagen ÚNICAMENTE para responder esta pregunta específica.
|
||||
Sé directo y enfócate solo en lo que la pregunta solicita.
|
||||
@@ -2833,6 +2846,7 @@ Responde SOLO en formato JSON válido (sin markdown, sin ```json):
|
||||
"status": "ok",
|
||||
"observations": "Respuesta técnica específica a: {question_text}",
|
||||
"recommendation": "Acción técnica recomendada o mensaje si la foto no es apropiada",
|
||||
"expected_answer": "La respuesta correcta que debería seleccionar según lo observado",
|
||||
"confidence": 0.85,
|
||||
"context_match": true
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user