feat: IA configurable — probar conexión, activar/inactivar

- Toggle activo/inactivo en configuración → guarda ia_activa en lab_config
- Botón "Probar" llama api/lab/test_gemini.php con la clave actual
- test_gemini.php envía pregunta mínima a Gemini y confirma respuesta
- Dashboard oculta botón y panel IA cuando ia_activa != '1'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-23 23:16:06 -05:00
co-authored by Claude Sonnet 4.6
parent 3b5c26214c
commit cd3d3bb9c0
4 changed files with 92 additions and 2 deletions
+43 -2
View File
@@ -167,7 +167,14 @@ require_once __DIR__ . '/shared/components/sidebar.php';
<!-- ── Inteligencia Artificial ────────────────────────── -->
<div class="section-card">
<h6><i class="fas fa-robot me-1"></i>Inteligencia Artificial — Google Gemini</h6>
<div class="d-flex align-items-center justify-content-between mb-2">
<h6 class="mb-0"><i class="fas fa-robot me-1"></i>Inteligencia Artificial — Google Gemini</h6>
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" id="c-ia-activa" role="switch"
<?= !empty($cfg['ia_activa']) && $cfg['ia_activa'] === '1' ? 'checked' : '' ?>>
<label class="form-check-label small fw-semibold" for="c-ia-activa">Activo</label>
</div>
</div>
<p class="text-muted small mb-3">
El asistente IA del turnero usa Google Gemini Flash para responder preguntas
sobre el estado del día. Genera tu clave en
@@ -184,8 +191,11 @@ require_once __DIR__ . '/shared/components/sidebar.php';
onclick="this.previousElementSibling.type = this.previousElementSibling.type === 'password' ? 'text' : 'password'">
<i class="fas fa-eye"></i>
</button>
<button class="btn btn-outline-primary" type="button" id="btn-probar-ia" onclick="probarIA()">
<i class="fas fa-plug me-1"></i>Probar
</button>
</div>
<div class="form-text">El token se guarda cifrado y nunca se expone al navegador.</div>
<div id="ia-test-result" class="form-text mt-1"></div>
</div>
</div>
@@ -311,6 +321,7 @@ async function guardar() {
doc_logo_base64: $('c-logo-base64').value,
doc_pie_pagina: $('c-doc-pie').value.trim(),
gemini_api_key: $('c-gemini-key').value.trim(),
ia_activa: $('c-ia-activa').checked ? '1' : '0',
};
if (!payload.empresa_nombre) {
@@ -342,6 +353,36 @@ async function guardar() {
btn.innerHTML = '<i class="fas fa-save me-2"></i>Guardar configuración';
}
}
async function probarIA() {
const key = $('c-gemini-key').value.trim();
const res = document.getElementById('ia-test-result');
const btn = document.getElementById('btn-probar-ia');
if (!key) { res.innerHTML = '<span class="text-danger">Ingresa el token primero.</span>'; return; }
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
res.innerHTML = '';
try {
const r = await fetch('api/lab/test_gemini.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key }),
});
const d = await r.json();
if (d.ok) {
res.innerHTML = '<span class="text-success"><i class="fas fa-check-circle me-1"></i>Conexión exitosa — ' + (d.modelo || 'Gemini') + '</span>';
} else {
res.innerHTML = '<span class="text-danger"><i class="fas fa-times-circle me-1"></i>' + (d.error || 'Error de conexión') + '</span>';
}
} catch(_) {
res.innerHTML = '<span class="text-danger"><i class="fas fa-times-circle me-1"></i>No se pudo conectar.</span>';
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-plug me-1"></i>Probar';
}
}
</script>
<script src="assets/js/lab-sidebar.js"></script>
</body>