LIA: historial de conversación y prompt que no fuerza brevedad

Cada pregunta se enviaba sola, sin los intercambios previos, así que un
seguimiento del tipo "¿y de esos cuántos en la mañana?" no tenía contexto.
Ahora el dashboard acumula los últimos 4 intercambios y los envía; el
backend los valida y antepone a la pregunta actual (recortados para no
inflar el consumo).

El prompt pedía "responde de forma concisa" en todos los casos, lo que
sumado al tope de tokens producía respuestas cortadas. Ahora ajusta el
detalle a lo que pide la pregunta y sabe que tiene historial disponible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-03 15:03:43 -05:00
co-authored by Claude Opus 5
parent b1a8b1abf8
commit 25a099c6ef
2 changed files with 24 additions and 6 deletions
+18 -5
View File
@@ -1,7 +1,7 @@
<?php
/**
* modules/turnero/api/ai_chat.php
* POST { pregunta: string }
* POST { pregunta: string, historial?: [{rol:'user'|'model', texto:string}, ...] }
* Llama a Gemini Flash con contexto completo del turnero del día.
*/
require_once __DIR__ . '/_helpers.php';
@@ -14,6 +14,17 @@ $pregunta = trim($body['pregunta'] ?? '');
if ($pregunta === '') jsonError('Pregunta vacía', 400);
if (mb_strlen($pregunta) > 800) jsonError('Pregunta demasiado larga', 400);
// Historial de la conversación, para que LIA entienda preguntas de seguimiento
// ("¿y de esos cuántos fueron en la mañana?"). Se limita a los últimos turnos
// para no inflar el consumo de tokens en cada llamada.
$historial = [];
foreach (array_slice(is_array($body['historial'] ?? null) ? $body['historial'] : [], -8) as $h) {
$rol = ($h['rol'] ?? '') === 'model' ? 'model' : 'user';
$texto = trim((string)($h['texto'] ?? ''));
if ($texto === '') continue;
$historial[] = ['role' => $rol, 'parts' => [['text' => mb_substr($texto, 0, 2000)]]];
}
define('LIA_TOKENS_MAX', 1_000_000);
$pdo = db();
@@ -173,9 +184,11 @@ if (!$ses) {
// ── Prompt ────────────────────────────────────────────────────
$systemPrompt = <<<PROMPT
Eres el asistente inteligente del sistema de turnero del Laboratorio Clínico.
Responde de forma concisa y útil en español. Puedes analizar: tiempos de espera y servicio por paciente, recepcionista o bacteriólogo; facturación del día; exámenes solicitados; franjas horarias con mayor demanda; buscar pacientes por nombre o cédula.
Eres LIA, la asistente inteligente del sistema de turnero del Laboratorio Clínico.
Responde en español, con el detalle que la pregunta requiera: si te piden un dato puntual sé breve, pero si te piden un listado, un análisis o una comparación, desarróllalo completo. Usa tablas o viñetas cuando ayuden a leer los datos.
Puedes analizar: tiempos de espera y servicio por paciente, recepcionista o bacteriólogo; facturación del día; exámenes solicitados; franjas horarias con mayor demanda; buscar pacientes por nombre o cédula.
Solo usa la información del contexto proporcionado. Si no tienes el dato, dilo claramente.
Tienes el historial de esta conversación: si el usuario pregunta algo que se refiere a tu respuesta anterior, respóndelo sin pedir que repita el contexto.
CONTEXTO DEL DÍA:
{$ctx}
@@ -184,9 +197,9 @@ PROMPT;
// ── Llamada a Gemini Flash ────────────────────────────────────
$payload = json_encode([
'system_instruction' => ['parts' => [['text' => $systemPrompt]]],
'contents' => [
'contents' => array_merge($historial, [
['role' => 'user', 'parts' => [['text' => $pregunta]]]
],
]),
'generationConfig' => [
'temperature' => 0.3,
// 600 cortaba a media frase las respuestas largas (listados de turnos,
+6 -1
View File
@@ -393,6 +393,7 @@ const API = '<?= BASE_URL ?>modules/turnero/api/';
const BASE_WA = '<?= BASE_URL ?>';
let _turnos = []; // cache para búsqueda local
let _autoReloadId = null;
let _liaHistorial = []; // últimos intercambios con LIA (contexto de seguimiento)
// ── Entrada ──────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
@@ -874,13 +875,17 @@ async function enviarIA() {
const res = await fetch(`${API}ai_chat.php`, {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({ pregunta }),
body: JSON.stringify({ pregunta, historial: _liaHistorial }),
});
const d = await res.json();
typing.className = 'ai-msg bot';
if (d.ok) {
typing.innerHTML = mdToHtml(d.respuesta);
hablarIA(d.respuesta);
// Guardar el intercambio para que las preguntas de seguimiento tengan contexto
_liaHistorial.push({ rol: 'user', texto: pregunta });
_liaHistorial.push({ rol: 'model', texto: d.respuesta });
if (_liaHistorial.length > 8) _liaHistorial = _liaHistorial.slice(-8);
if (d.tokens_max) _actualizarTokens(d.tokens_usados, d.tokens_max);
} else {
typing.textContent = d.error || 'Error al conectar con la IA';