Cambios realizados v1.3.4 + v1.2.9:

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
This commit is contained in:
2025-12-05 06:11:46 -03:00
parent f73319046e
commit 7111550fb7
4 changed files with 29 additions and 46 deletions

View File

@@ -1,7 +1,7 @@
{ {
"name": "checklist-frontend", "name": "checklist-frontend",
"private": true, "private": true,
"version": "1.3.3", "version": "1.3.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,6 +1,6 @@
// Service Worker para PWA con detección de actualizaciones // Service Worker para PWA con detección de actualizaciones
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión // IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
const CACHE_NAME = 'ayutec-v1.3.3'; const CACHE_NAME = 'ayutec-v1.3.4';
const urlsToCache = [ const urlsToCache = [
'/', '/',
'/index.html' '/index.html'

View File

@@ -5593,20 +5593,11 @@ function AIAssistantChatModal({ question, inspection, allAnswers, messages, setM
const sendMessage = async () => { const sendMessage = async () => {
if ((!inputMessage.trim() && attachedFiles.length === 0) || loading) return if ((!inputMessage.trim() && attachedFiles.length === 0) || loading) return
const userMessage = { // Guardar datos antes de limpiar
role: 'user',
content: inputMessage || '📎 Archivos adjuntos',
timestamp: new Date().toISOString(),
files: attachedFiles.map(f => ({
name: f.name,
type: f.type,
size: f.size,
preview: f.preview // Guardar URL temporal para mostrar en chat
}))
}
setMessages(prev => [...prev, userMessage])
const currentFiles = attachedFiles const currentFiles = attachedFiles
const userMessageText = inputMessage || '📎 Archivos adjuntos'
// Limpiar inputs
setInputMessage('') setInputMessage('')
setAttachedFiles([]) setAttachedFiles([])
setLoading(true) setLoading(true)
@@ -5713,46 +5704,38 @@ function AIAssistantChatModal({ question, inspection, allAnswers, messages, setM
const data = await response.json() const data = await response.json()
console.log('📥 Respuesta de IA:', data) console.log('📥 Respuesta de IA:', data)
// Actualizar el mensaje del usuario con las URLs reales de S3 // Crear mensaje del usuario CON las URLs de S3 del servidor
if (data.attached_files && data.attached_files.length > 0) { const userMessage = {
setMessages(prev => { role: 'user',
const updated = [...prev] content: userMessageText,
const lastUserMsgIndex = updated.length - 1 timestamp: new Date().toISOString(),
if (updated[lastUserMsgIndex].role === 'user' && updated[lastUserMsgIndex].files) { files: (data.attached_files || []).map((serverFile, idx) => {
// Reemplazar blob URLs con URLs de S3 const originalFile = currentFiles[idx]
updated[lastUserMsgIndex].files = updated[lastUserMsgIndex].files.map((file, idx) => {
const serverFile = data.attached_files[idx] // Liberar blob URL si existe
if (serverFile?.url) { if (originalFile?.preview) {
// Liberar blob URL anterior URL.revokeObjectURL(originalFile.preview)
if (file.preview) {
URL.revokeObjectURL(file.preview)
} }
return { return {
...file, name: serverFile.filename || originalFile?.name || 'archivo',
preview: serverFile.url // Ahora es URL de S3 type: serverFile.type || originalFile?.type || 'application/octet-stream',
size: originalFile?.size || 0,
preview: serverFile.url || originalFile?.preview // Usar URL de S3, fallback a blob
} }
}
return file
})
}
return updated
}) })
} }
// Crear mensaje del asistente con archivos adjuntos (usando URLs del servidor) // Crear mensaje del asistente
const assistantMessage = { const assistantMessage = {
role: 'assistant', role: 'assistant',
content: data.response, content: data.response,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
confidence: data.confidence, confidence: data.confidence
attachedFiles: data.attached_files?.map(f => ({
filename: f.filename,
type: f.type,
url: f.url // URL de S3, no blob
})) || []
} }
setMessages(prev => [...prev, assistantMessage]) // Agregar ambos mensajes (usuario + asistente)
setMessages(prev => [...prev, userMessage, assistantMessage])
} catch (error) { } catch (error) {
console.error('Error al enviar mensaje:', error) console.error('Error al enviar mensaje:', error)

View File

@@ -153,7 +153,7 @@ export default function Sidebar({ user, activeTab, setActiveTab, sidebarOpen, se
className="w-10 h-10 object-contain bg-white rounded p-1" className="w-10 h-10 object-contain bg-white rounded p-1"
/> />
<p className="text-xs text-indigo-300 font-medium hover:text-indigo-200"> <p className="text-xs text-indigo-300 font-medium hover:text-indigo-200">
Ayutec v1.3.3 Ayutec v1.3.4
</p> </p>
</a> </a>
</div> </div>