From cd3d3bb9c030c712a459f343895fbffd5debdf60 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:16:06 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20IA=20configurable=20=E2=80=94=20probar?= =?UTF-8?q?=20conexi=C3=B3n,=20activar/inactivar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- api/lab/save_config.php | 1 + api/lab/test_gemini.php | 40 +++++++++++++++++++++++++ lab_configuracion.php | 45 +++++++++++++++++++++++++++-- modules/turnero/views/dashboard.php | 8 +++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 api/lab/test_gemini.php diff --git a/api/lab/save_config.php b/api/lab/save_config.php index 5e9ea52..42fb5c7 100644 --- a/api/lab/save_config.php +++ b/api/lab/save_config.php @@ -17,6 +17,7 @@ $permitidas = [ 'empresa_telefono', 'empresa_email', 'empresa_ciudad', 'doc_color', 'doc_logo_base64', 'doc_pie_pagina', 'gemini_api_key', + 'ia_activa', ]; $guardadas = 0; diff --git a/api/lab/test_gemini.php b/api/lab/test_gemini.php new file mode 100644 index 0000000..e5cce29 --- /dev/null +++ b/api/lab/test_gemini.php @@ -0,0 +1,40 @@ + [['role' => 'user', 'parts' => [['text' => 'Responde solo con la palabra: OK']]]], + 'generationConfig' => ['maxOutputTokens' => 10, 'temperature' => 0], +], JSON_UNESCAPED_UNICODE); + +$ch = curl_init("https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={$key}"); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $payload, + CURLOPT_HTTPHEADER => ['Content-Type: application/json'], + CURLOPT_TIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => true, +]); +$raw = curl_exec($ch); +$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +if (!$raw) jsonError('Sin respuesta del servidor de Google.', 502); + +$gemini = json_decode($raw, true); +if ($code !== 200) { + jsonError($gemini['error']['message'] ?? "Error HTTP {$code}", 502); +} + +jsonOk(['modelo' => 'gemini-2.0-flash', 'respuesta' => $gemini['candidates'][0]['content']['parts'][0]['text'] ?? '']); diff --git a/lab_configuracion.php b/lab_configuracion.php index 5be4a92..c84bb6c 100644 --- a/lab_configuracion.php +++ b/lab_configuracion.php @@ -167,7 +167,14 @@ require_once __DIR__ . '/shared/components/sidebar.php';
-
Inteligencia Artificial — Google Gemini
+
+
Inteligencia Artificial — Google Gemini
+
+ > + +
+

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'"> +

-
El token se guarda cifrado y nunca se expone al navegador.
+
@@ -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 = '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 = 'Ingresa el token primero.'; return; } + + btn.disabled = true; + btn.innerHTML = ''; + 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 = 'Conexión exitosa — ' + (d.modelo || 'Gemini') + ''; + } else { + res.innerHTML = '' + (d.error || 'Error de conexión') + ''; + } + } catch(_) { + res.innerHTML = 'No se pudo conectar.'; + } finally { + btn.disabled = false; + btn.innerHTML = 'Probar'; + } +} diff --git a/modules/turnero/views/dashboard.php b/modules/turnero/views/dashboard.php index 25e19a1..d189731 100644 --- a/modules/turnero/views/dashboard.php +++ b/modules/turnero/views/dashboard.php @@ -7,6 +7,12 @@ require_once APP_ROOT . '/config/config.php'; if (!isUserLoggedIn()) { header('Location: ' . BASE_URL . 'login.php'); exit; } +$_iaActiva = false; +try { + $_cfgIA = Database::getInstance()->fetch("SELECT valor FROM lab_config WHERE clave = 'ia_activa'"); + $_iaActiva = ($_cfgIA['valor'] ?? '0') === '1'; +} catch (\Throwable $_) {} + Layout::open('Dashboard Turnero', 'fas fa-chart-bar'); ?>