diff --git a/backend/app/main.py b/backend/app/main.py index 16b9ff8..6353575 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1520,6 +1520,7 @@ def delete_ai_configuration( async def analyze_image( file: UploadFile = File(...), question_id: int = None, + inspection_id: int = None, custom_prompt: str = None, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user) @@ -1527,6 +1528,7 @@ async def analyze_image( """ Analiza una imagen usando IA para sugerir respuestas Usa la configuración de IA activa (OpenAI o Gemini) + Incluye contexto del vehículo si se proporciona inspection_id """ # Obtener configuración de IA activa ai_config = db.query(models.AIConfiguration).filter( @@ -1550,6 +1552,22 @@ async def analyze_image( if question_id: question_obj = db.query(models.Question).filter(models.Question.id == question_id).first() + # Obtener contexto del vehículo si se proporciona inspection_id + vehicle_context = "" + if inspection_id: + inspection = db.query(models.Inspection).filter(models.Inspection.id == inspection_id).first() + if inspection: + vehicle_context = f""" +INFORMACIÓN DEL VEHÍCULO INSPECCIONADO: +- Marca: {inspection.vehicle_brand} +- Modelo: {inspection.vehicle_model} +- Año: {inspection.vehicle_year or 'No especificado'} +- Placa: {inspection.vehicle_plate} +- Kilometraje: {inspection.mileage} km +- Cliente: {inspection.client_name} +- OR/Orden: {inspection.or_number} +""" + try: # Construir prompt dinámico basado en la pregunta específica if question_obj: @@ -1558,6 +1576,8 @@ async def analyze_image( # Prompt 100% personalizado por el administrador system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular. +{vehicle_context} + INSTRUCCIONES ESPECÍFICAS PARA ESTA PREGUNTA: {custom_prompt} @@ -1565,6 +1585,7 @@ PREGUNTA A RESPONDER: "{question_obj.text}" Sección: {question_obj.section} Analiza la imagen siguiendo EXACTAMENTE las instrucciones proporcionadas arriba. +Considera el kilometraje, marca y modelo del vehículo para dar un análisis más preciso. VALIDACIÓN DE IMAGEN: - Si la imagen NO corresponde al contexto de la pregunta (por ejemplo, si piden luces pero muestran motor), indica en "recommendation" que deben cambiar la foto @@ -1573,7 +1594,7 @@ VALIDACIÓN DE IMAGEN: Responde en formato JSON: {{ "status": "ok|minor|critical", - "observations": "Análisis específico según el prompt personalizado", + "observations": "Análisis específico según el prompt personalizado, considerando el vehículo {inspection.vehicle_brand if inspection_id else ''}", "recommendation": "Si la imagen no es apropiada, indica 'Por favor tome una foto de [componente correcto]'. Si es apropiada, da recomendación técnica.", "confidence": 0.0-1.0 }}""" @@ -1585,11 +1606,14 @@ Responde en formato JSON: system_prompt = f"""Eres un mecánico experto realizando una inspección vehicular. +{vehicle_context} + PREGUNTA ESPECÍFICA A RESPONDER: "{question_text}" Sección: {section} Analiza la imagen ÚNICAMENTE para responder esta pregunta específica. Sé directo y enfócate solo en lo que la pregunta solicita. +Considera el kilometraje y características del vehículo para contextualizar tu análisis. VALIDACIÓN DE IMAGEN: - Si la imagen NO corresponde al contexto de la pregunta, indica en "recommendation" que deben cambiar la foto @@ -1613,19 +1637,23 @@ IMPORTANTE: user_message = f"Inspecciona la imagen y responde específicamente: {question_obj.text}" else: # Fallback para análisis general - system_prompt = """Eres un experto mecánico automotriz. Analiza la imagen y proporciona: + system_prompt = f"""Eres un experto mecánico automotriz. + +{vehicle_context} + +Analiza la imagen y proporciona: 1. Estado del componente (bueno/regular/malo) 2. Nivel de criticidad (ok/minor/critical) 3. Observaciones técnicas breves 4. Recomendación de acción Responde en formato JSON: -{ +{{ "status": "ok|minor|critical", "observations": "descripción técnica", "recommendation": "acción sugerida", "confidence": 0.0-1.0 -}""" +}}""" user_message = "Analiza este componente del vehículo para la inspección general." if ai_config.provider == "openai": diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index e16d982..2144a7f 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -3069,6 +3069,11 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { formData.append('file', file) formData.append('question_id', question.id.toString()) + // Include inspection_id for vehicle context + if (inspectionId) { + formData.append('inspection_id', inspectionId.toString()) + } + // Include custom prompt if available if (question.ai_prompt) { formData.append('custom_prompt', question.ai_prompt) diff --git a/migrations/add_ai_analysis_if_not_exists.sql b/migrations/add_ai_analysis_if_not_exists.sql new file mode 100644 index 0000000..e38ccb2 --- /dev/null +++ b/migrations/add_ai_analysis_if_not_exists.sql @@ -0,0 +1,28 @@ +-- Migración: Asegurar que ai_analysis existe en la tabla answers +-- Fecha: 2025-11-26 +-- Descripción: Agrega la columna ai_analysis si no existe (para guardar el resultado del análisis de IA) + +-- Agregar columna ai_analysis si no existe +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'answers' + AND column_name = 'ai_analysis' + ) THEN + ALTER TABLE answers ADD COLUMN ai_analysis JSONB; + COMMENT ON COLUMN answers.ai_analysis IS 'Resultado del análisis de IA: {status, observations, recommendation, confidence, model, provider}'; + END IF; +END $$; + +-- Verificar que la columna existe +SELECT + column_name, + data_type, + is_nullable, + column_default +FROM information_schema.columns +WHERE table_name = 'answers' +AND column_name = 'ai_analysis'; + +SELECT '✅ Columna ai_analysis verificada/creada en tabla answers' as status;