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
68 lines
1.9 KiB
JavaScript
68 lines
1.9 KiB
JavaScript
// Service Worker para PWA con detección de actualizaciones
|
|
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
|
|
const CACHE_NAME = 'ayutec-v1.2.6';
|
|
const urlsToCache = [
|
|
'/',
|
|
'/index.html'
|
|
];
|
|
|
|
// Instalación del service worker
|
|
self.addEventListener('install', (event) => {
|
|
console.log('Service Worker: Installing version', CACHE_NAME);
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME)
|
|
.then((cache) => {
|
|
console.log('Service Worker: Caching files');
|
|
return cache.addAll(urlsToCache);
|
|
})
|
|
// NO hacer skipWaiting automáticamente - esperar a que el usuario lo active
|
|
);
|
|
});
|
|
|
|
// Activación del service worker
|
|
self.addEventListener('activate', (event) => {
|
|
console.log('Service Worker: Activating...');
|
|
event.waitUntil(
|
|
caches.keys().then((cacheNames) => {
|
|
return Promise.all(
|
|
cacheNames.map((cacheName) => {
|
|
if (cacheName !== CACHE_NAME) {
|
|
console.log('Service Worker: Deleting old cache:', cacheName);
|
|
return caches.delete(cacheName);
|
|
}
|
|
})
|
|
);
|
|
})
|
|
// NO hacer claim automáticamente - solo cuando el usuario actualice manualmente
|
|
);
|
|
});
|
|
|
|
// Estrategia: Network First, fallback to Cache
|
|
self.addEventListener('fetch', (event) => {
|
|
event.respondWith(
|
|
fetch(event.request)
|
|
.then((response) => {
|
|
// Clone la respuesta
|
|
const responseToCache = response.clone();
|
|
|
|
// Actualizar cache con la nueva respuesta
|
|
caches.open(CACHE_NAME).then((cache) => {
|
|
cache.put(event.request, responseToCache);
|
|
});
|
|
|
|
return response;
|
|
})
|
|
.catch(() => {
|
|
// Si falla la red, usar cache
|
|
return caches.match(event.request);
|
|
})
|
|
);
|
|
});
|
|
|
|
// Mensaje para notificar actualización
|
|
self.addEventListener('message', (event) => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
self.skipWaiting();
|
|
}
|
|
});
|