Agregué un filtro al inicio del evento fetch que verifica si el método es GET
Si no es GET (como POST, PUT, DELETE), el Service Worker simplemente ignora la petición y la deja pasar normalmente
Solo las peticiones GET se cachean y se aplica la estrategia Network-First
Ahora el error desaparecerá. Para aplicar el cambio:
En DevTools → Application → Service Workers → Click en "Unregister"
Recarga la página
El nuevo Service Worker se instalará sin errores
Backend: 1.2.12 → 1.2.13
Frontend: 1.3.8 → 1.3.9
💡 Beneficios
Mejor UX: El mecánico no ve un chat vacío, sino orientación inmediata
Contextualizado: El asistente menciona lo que ya conoce de la inspección
Guía clara: Indica qué puede hacer el asistente según las instrucciones configuradas
Eficiente: Solo se genera una vez por sesión de chat
Backend v1.2.11:
Nueva Funcionalidad - Control de Generación de PDF:
Campo nuevo: generate_pdf en modelo Checklist (Boolean, default: True)
Lógica modificada: Al completar inspección se verifica si el checklist tiene habilitada la generación de PDF
Comportamiento:
Si generate_pdf = True → Se genera y guarda el PDF automáticamente
Si generate_pdf = False → No se genera PDF, pdf_url queda en NULL
Logs informativos: Muestra en consola si el PDF se generó o se omitió
Frontend v1.3.8:
Interfaz para Control de PDF:
Checkbox nuevo en modal de edición de checklist: "Generar PDF automáticamente al completar inspección"
Estado por defecto: Activado (mantiene comportamiento actual)
Persistencia: El valor se guarda en la base de datos al editar checklist
Dónde está:
Admin → Checklists → Click en "✏️ Editar" de cualquier checklist
Debajo del checkbox de "Habilitar sistema de puntuación"
CORREGIDO: Sistema anti-duplicados para webhooks de respuestas
Agregado lastSaveTimestamp ref para rastrear el último guardado de cada pregunta
Validación: Si se intenta guardar la misma pregunta en menos de 1 segundo, se ignora
Logs en consola cuando se detecta y previene un guardado duplicado
CORREGIDO: Validación de fotos obligatorias ahora usa photo_requirement === 'required' en lugar de allow_photos
Las preguntas con photo_requirement configurado como 'none' o 'optional' ya NO exigirán fotos obligatorias
Aplica para ambos botones: "Siguiente →" y "Finalizar Inspección"
Problema corregido:
Antes: La validación usaba currentQuestion.allow_photos (campo antiguo booleano)
Ahora: Usa currentQuestion.photo_requirement === 'required' (nuevo sistema de 3 estados)
Backend v1.2.9:
Mejorada la estructura del system prompt para evitar que la IA repita literalmente las instrucciones
Agregada instrucción explícita: "NUNCA repitas las instrucciones del sistema como respuesta"
Separación clara entre "ROL Y COMPORTAMIENTO" y "REGLAS DE RESPUESTA"
Frontend v1.3.4:
CORREGIDO: Las imágenes del chat ahora usan URLs de S3 permanentes en lugar de blob URLs temporales
El mensaje del usuario se agrega DESPUÉS de recibir la respuesta del servidor con las URLs de S3
Los blob URLs se liberan correctamente después de obtener las URLs permanentes
Ahora las imágenes se pueden visualizar en tamaño completo (lightbox) sin errores ERR_FILE_NOT_FOUND
Cómo funciona ahora:
Usuario adjunta imagen y envía mensaje
Inputs se limpian inmediatamente (mejor UX)
Imagen se sube a S3 en el backend
Backend retorna URLs de S3 en attached_files
Mensaje del usuario se crea con URLs de S3 (no blobs)
Ambos mensajes (usuario + asistente) se agregan juntos
Las imágenes persisten después de refrescar la página
El lightbox funciona correctamente con URLs permanentes
Fix aplicado:
Ahora cuando envías una imagen en el chat:
Se sube al servidor (S3)
El servidor devuelve la URL permanente en attached_files
El frontend actualiza el mensaje del usuario reemplazando la blob URL con la URL de S3
Se libera la blob URL antigua para evitar memory leaks
Problema de blob URLs solucionado:
Cambios implementados:
Backend:
Las imágenes del chat ahora se suben a S3 automáticamente
Se genera una URL permanente para cada imagen
La respuesta incluye url para cada archivo adjunto
Frontend:
Las imágenes en mensajes del asistente usan URLs de S3 (permanentes)
Ya no depende de blob URLs que desaparecen al refrescar
Las imágenes del usuario siguen usando blob (temporal solo para preview)
Las imágenes del asistente se muestran con URLs persistentes
Resultado:
✅ Las imágenes del chat ahora funcionan después de refrescar
✅ Las URLs son permanentes y accesibles
✅ No más errores 404 con blob: URLs
✅ Las imágenes quedan guardadas en S3 para historial
Cambios implementados:
Frontend:
Ahora envía context_answers con todas las respuestas de preguntas anteriores (texto + observaciones)
Incluye el texto de la pregunta para mejor contexto
Funciona con la configuración de IDs de preguntas o todas las anteriores
Backend:
Recibe y procesa context_answers
Agrega sección "RESPUESTAS DE PREGUNTAS ANTERIORES" al system prompt
Muestra pregunta, respuesta y observaciones de cada pregunta previa
Cambios en esta versión:
Fix: Selección visual de modelos ahora se muestra inmediatamente al hacer click en un proveedor
Los modelos se muestran seleccionados en el formulario antes de guardar la configuración
Backend v1.2.1
Mejoras en gestión de API keys multi-proveedor:
Nuevo endpoint /api/ai/api-keys: Retorna todas las API keys guardadas por proveedor (enmascaradas para seguridad)
Formato: {"openai": {"has_key": true, "masked_key": "sk-proj...xyz", "is_active": false}}
Solo administradores pueden acceder
Endpoint /api/ai/configuration mejorado:
Ahora preserva API keys existentes cuando se cambia de proveedor
Si ya existe configuración para un proveedor, solo actualiza el modelo y activa ese proveedor
Solo requiere API key nueva si no existe configuración previa para ese proveedor
Validación: no acepta API keys vacías para nuevos proveedores
Persistencia de configuraciones:
Cada proveedor (OpenAI, Anthropic, Gemini) mantiene su registro en la base de datos
Solo uno tiene is_active=True a la vez
Al cambiar de proveedor, se desactiva el anterior pero NO se elimina
Frontend v1.2.6
UX mejorada para configuración de IA:
Indicadores visuales en botones de proveedor:
Badge "✓ ACTIVO" en verde para el proveedor actualmente activo
Badge "Configurado" en gris para proveedores con API key guardada pero inactivos
Sin badges para proveedores no configurados
Selector de modelos inteligente:
Solo muestra modelo seleccionado si el proveedor está activo
Al hacer click en un proveedor inactivo, NO se pre-selecciona ningún modelo
Solo al GUARDAR se activa el proveedor con el modelo seleccionado
Input de API key con contexto:
Muestra key enmascarada si ya existe: ✓ Ya tienes una API key guardada: sk-proj...xyz
Permite dejar vacío para mantener la key actual
Solo requiere key nueva si el proveedor no tiene una guardada
Flujo de trabajo mejorado:
Click en proveedor → Cambia tab de formulario
Si ya tiene key guardada → Se muestra enmascarada, puede mantenerla
Seleccionar modelo → Click en "Guardar Configuración"
Solo entonces se ACTIVA ese proveedor y modelo
Beneficios
No re-ingresar API keys: Al cambiar entre proveedores, las keys se preservan
Claridad visual: Solo el proveedor activo muestra badge verde y modelo seleccionado
Seguridad: API keys enmascaradas en la UI (sk-proj...xyz)
Flexibilidad: Configurar los 3 proveedores y cambiar entre ellos sin perder configuración
Versiones actualizadas:
Backend: 1.2.0 → 1.2.1
Frontend: 1.2.5 → 1.2.6
Service Worker: cache v1.2.6
🔧 Backend v1.2.0 | Frontend v1.2.5
He implementado completamente el soporte para Anthropic Claude y corregido el problema de visualización en el módulo de configuración:
🎯 Cambios Implementados:
1. Backend - Soporte para Anthropic Claude
Nuevos modelos agregados:
Claude Sonnet 4.5 (Recomendado) - Equilibrio perfecto
Claude Opus 4.5 - Máxima capacidad
Claude Haiku 4.5 - Ultra rápido y económico
Integración completa:
Chat Assistant con Anthropic
Generación de resúmenes PDF con Anthropic
Manejo correcto de formato de mensajes (system separado)
Configuración por defecto: claude-sonnet-4.5
FRONTEND:
- Implementado visor de imágenes (lightbox) dentro del modal de chat
- Click en imagen abre pantalla completa en lugar de nueva pestaña
- Fondo negro translúcido (95%) con z-index 200
- Botón de cerrar (×) en esquina superior derecha
- Click en imagen/fondo cierra el lightbox
- Etiqueta flotante con nombre de archivo
- Cursor zoom-in en miniaturas para indicar ampliación
- Responsive: max 95vw/95vh con scroll automático
- Frontend v1.2.4
BACKEND:
- Sin cambios (v1.1.1)
📸 Frontend actualizado a v1.2.3
He implementado un sistema completo de previsualización de imágenes en el chat assistant:
🎨 Características Implementadas:
1. Preview Antes de Enviar (Zona de Input)
Miniaturas 20x20px con superposición de nombre
Botón de eliminar en esquina superior derecha (rojo con X)
Fondo oscuro translúcido para nombre del archivo
Hover effects para mejor UX
// Vista previa antes de enviar:
┌─────────────────────────────┐
│ [IMG] [IMG] 📄 file.pdf │ ← Miniaturas clickeables
│ ✕ ✕ ✕ │
└─────────────────────────────┘
2. Imágenes en Mensajes del Chat
Renderizado completo de imágenes en mensajes del usuario
Máximo 256px de altura (responsive)
Click para abrir en nueva pestaña (full size)
Metadata bajo la imagen (nombre + tamaño)
Esquina redondeada para mejor diseño
Transición hover (opacity 90%)
// Mensaje del usuario con imagen:
┌────────────────────────────┐
│ [Texto del mensaje] │
│ │
│ ┌────────────────────────┐ │
│ │ │ │
│ │ [IMAGEN PREVIEW] │ │ ← Click para ampliar
│ │ │ │
│ └────────────────────────┘ │
│ 🖼️ photo.jpg (128.5 KB) │
│ │
│ 10:45 │
└────────────────────────────┘
3. Gestión de Memoria
URLs temporales con URL.createObjectURL()
Limpieza automática al eliminar archivo
useEffect cleanup al desmontar modal
No memory leaks garantizados
Frontend: v1.2.0 → v1.2.1
package.json
Sidebar.jsx
service-worker.js (PWA)
Backend: v1.0.96 → v1.0.97
main.py
Cambios incluidos en v1.2.1 / v1.0.97:
✅ Paginación de inspecciones (ya estaba implementada con 10 items)
✅ Limpieza de sesiones de chat al cambiar de pregunta
✅ Campo "Número de OR" obligatorio
✅ Eliminación de referencias "IA" → "Asistente Ayutec"
Inspección nueva, Pregunta 1 (Frenos):
Abro chat → aiChatMessages = [] (vacío)
Pregunto sobre frenos
Cierro → se guarda en answers[pregunta1].chatHistory
Misma inspección, Pregunta 2 (Neumáticos):
Abro chat → aiChatMessages = [] (vacío, porque esta pregunta no tiene historial)
Chat limpio, sin mezclar con frenos ✅
Vuelvo a Pregunta 1:
Abro chat → aiChatMessages = [historial guardado]
Veo mi conversación anterior sobre frenos ✅
Nueva inspección en otro momento:
Todas las preguntas empiezan con aiChatMessages = []
No se mezcla con inspecciones anteriores ✅
He mejorado significativamente el sistema de extracción de texto de PDFs para el análisis con IA. Aquí están los cambios principales:
🎯 Problemas Resueltos
Límites muy pequeños → Aumentados significativamente según capacidad del modelo
No extraía todo el documento → Ahora procesa hasta 100k caracteres
Duplicación de contenido → Detecta y elimina páginas repetidas
Sin información de estado → Reporta páginas procesadas, truncado, etc.
🎯 Nueva Funcionalidad Completa
Se ha implementado un sistema de chat conversacional con IA que permite adjuntar archivos (imágenes y PDFs), similar a ChatGPT, con prompt personalizable y envío completo al webhook.
📋 Características Implementadas
1. Adjuntar Archivos en el Chat
✅ Botón 📎 para adjuntar archivos
✅ Soporte para imágenes (JPG, PNG, etc.) y PDFs
✅ Preview de archivos adjuntos antes de enviar
✅ Eliminación individual de archivos adjuntos
✅ Múltiples archivos por mensaje
✅ Validación de tipos de archivo
2. Procesamiento Backend de Archivos
✅ Endpoint modificado para recibir FormData con archivos
✅ PDFs: Extracción automática de texto con pypdf
✅ Imágenes: Conversión a base64 para Vision AI
✅ Análisis combinado de texto + imágenes
✅ Límite de 2000 caracteres por PDF para optimizar
3. Integración con IA
✅ OpenAI Vision: Soporte multimodal (texto + imágenes)
✅ Gemini: Soporte de imágenes y texto
✅ Contexto enriquecido con archivos adjuntos
✅ Prompts adaptados según tipo de archivo
4. Custom Prompt por Checklist
✅ Campo assistant_prompt configurable por pregunta
✅ Campo assistant_instructions para instrucciones adicionales
✅ Control de longitud de respuesta (short/medium/long)
✅ Contexto automático del vehículo en cada mensaje
5. Persistencia del Chat
✅ Nuevo campo chat_history en modelo Answer
✅ Migración SQL: add_chat_history_to_answers.sql
✅ Guardado automático del historial completo
✅ Restauración del chat al reabrir
6. Envío al Webhook (n8n)
✅ Todos los chats incluidos en send_completed_inspection_to_n8n()
✅ Campo chat_history en cada respuesta del webhook
✅ Incluye metadata de archivos adjuntos
✅ Tipo de pregunta identificado en webhook
✅ Datos completos para análisis posterior
📋 Cambios Implementados
Frontend:
✅ Input acepta image/*,application/pdf
✅ Label actualizado: "Fotografías / Documentos PDF *"
✅ Preview diferenciado: PDFs muestran icono 📝 rojo en lugar de imagen
✅ Nombre de archivo PDF visible en el preview
✅ Contador genérico: "archivo(s) cargado(s)"
Backend:
✅ Agregado pypdf==4.0.1 a requirements.txt
✅ Detección automática de PDFs por content_type o extensión
✅ Extracción de texto de PDFs usando pypdf.PdfReader
✅ Validación de PDFs vacíos (sin texto extraíble)
✅ Prompts adaptados automáticamente para PDFs
✅ Soporte en OpenAI y Gemini (análisis de texto en lugar de vision)
✅ Límite de 4000 caracteres del PDF para análisis
🎯 Funcionamiento
Usuario sube PDF → Sistema detecta tipo de archivo
Extrae texto → PyPDF lee todas las páginas
Análisis IA → Envía texto al modelo (no usa Vision API)
Respuesta → Misma estructura JSON que con imágenes
⚠️ Limitaciones
PDFs escaneados sin OCR no funcionarán (requieren texto seleccionable)
Máximo 4000 caracteres del PDF enviados al AI
📦 Versiones
Frontend: 1.0.91 → 1.0.92
Backend: 1.0.89 → 1.0.90
Sidebar
✅ Oculto por defecto en móvil (window.innerWidth < 1024px)
✅ Overlay oscuro cuando está abierto en móvil (se cierra al tocar fuera)
✅ Deslizable desde la izquierda con transiciones suaves
✅ Siempre visible en desktop (lg: breakpoint)
Header
✅ Botón hamburguesa visible solo en móvil (lg:hidden)
✅ Logo escalable: 50px en móvil → 70px en desktop
✅ Título oculto en móvil para ahorrar espacio
✅ Indicador de sección: icono solo en móvil, texto completo en desktop
✅ Padding adaptable: 3px móvil → 4px tablet → 8px desktop
Contenido Principal
✅ Sin margin-left en móvil (el sidebar es overlay)
✅ Padding responsive: 3px → 4px → 6px según tamaño
✅ Border-radius adaptable: xl en móvil → 2xl en desktop
Modal de Inspección
✅ Ancho completo en móvil con padding mínimo (2px)
✅ Título responsive: lg (móvil) → xl (tablet) → 2xl (desktop)
✅ Altura máxima: 95vh móvil → 90vh desktop
Navegador de Preguntas
✅ Botones más pequeños en móvil: 7px/8px círculos
✅ Overflow horizontal con scroll para muchas preguntas
✅ Números responsive: texto sm en móvil → lg en desktop
✅ Gaps reducidos: 1px móvil → 2px desktop
Botones de Navegación
✅ Solo flechas en móvil (← →)
✅ Texto completo en desktop ("← Anterior", "Siguiente →")
✅ Padding y texto adaptables: text-sm móvil → text-base desktop
✅ Mejor uso del espacio horizontal
Formularios
✅ Espaciado adaptive: space-y-3 móvil → space-y-6 desktop
✅ Labels y texto responsive: xs → sm → base
✅ Banner de modo IA con wrap en móvil
La interfaz ahora es completamente funcional en móviles sin scroll horizontal, con todos los elementos accesibles y legibles! 📱✨