297 lines
14 KiB
HTML
297 lines
14 KiB
HTML
<!doctype html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>RAG Playground</title>
|
|
<link rel="stylesheet" href="/playground/styles.css" />
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<main class="layout">
|
|
<header class="hero">
|
|
<div class="hero-brand">
|
|
<img class="brand-logo" src="https://por-correo.com/templates/yootheme/cache/e5/logo_por-correo-e574d3f1.webp" alt="POR-CORREO" />
|
|
<div>
|
|
<p class="eyebrow">RAG Playground</p>
|
|
<h1>Laboratorio de pruebas sistema RAG</h1>
|
|
<p class="lead">Prueba ingesta, bootstrap y chat con contexto visible para evaluar el RAG como si estuviera integrado en una app o agente real. Incluye comparacion con y sin RAG, seleccion de modelos, logs automáticos y logs solicitados por el usuario para analizar fallos, carencias y mejoras.</p>
|
|
</div>
|
|
</div>
|
|
<div class="hero-side">
|
|
<div class="log-counter" id="logCounterCard">
|
|
<span class="log-counter-value" id="logCounterValue">0</span>
|
|
<span class="log-counter-label">logs detectados</span>
|
|
</div>
|
|
<button id="healthButton" class="secondary">Comprobar health</button>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="tabs">
|
|
<button class="tab-button active" data-tab="ingest">Ingesta</button>
|
|
<button class="tab-button" data-tab="cleanup">Limpieza</button>
|
|
<button class="tab-button" data-tab="bootstrap">Bootstrap</button>
|
|
<button class="tab-button" data-tab="chat">Chat</button>
|
|
</section>
|
|
|
|
<section id="tab-ingest" class="tab-panel active">
|
|
<article class="panel">
|
|
<h2>Ingesta</h2>
|
|
<div class="grid single-grid">
|
|
<label>Crear scope aislado
|
|
<select id="ingestScopeMode">
|
|
<option value="existing">usar generacion automatica</option>
|
|
<option value="custom">definir sourceId propio</option>
|
|
</select>
|
|
</label>
|
|
<label id="ingestSourceIdWrapper">Source ID / scope custom
|
|
<input id="ingestSourceId" placeholder="ej: src:cliente-a:manual:pdf-tecnico" />
|
|
</label>
|
|
<label>Tipo de fuente
|
|
<select id="ingestSourceType">
|
|
<option value="folder">folder</option>
|
|
<option value="file">file</option>
|
|
</select>
|
|
</label>
|
|
<label>Ruta de la fuente (remota en servidor)
|
|
<input id="ingestSourceRef" value="/home/pancho/Documentos/Empresa/Desarrollo/IA/docs" />
|
|
</label>
|
|
<label>Subida directa (sobreescribe la ruta de la fuente)
|
|
<div style="display: flex; gap: 8px; margin-top: 4px; align-items: center;">
|
|
<button id="btnUploadFile" class="secondary" style="flex: 1;">Archivo suelto</button>
|
|
<button id="btnUploadFolder" class="secondary" style="flex: 1;">Carpeta local</button>
|
|
<button id="btnClearUpload" style="background: transparent; color: var(--danger); border: 1px solid var(--danger); display: none;" title="Cancelar subida local">❌</button>
|
|
</div>
|
|
<input id="ingestUploadFile" type="file" accept=".pdf,.md,.txt,.ts,.tsx,.js,.jsx,.mjs,.cjs,.py,.json,.yml,.yaml" style="display: none;" />
|
|
<input id="ingestUploadFolder" type="file" webkitdirectory directory multiple style="display: none;" />
|
|
<span id="uploadStatusText" style="display: block; margin-top: 8px; font-size: 13px; color: var(--accent);">Ningún elemento seleccionado</span>
|
|
</label>
|
|
<label>Modo de ingesta
|
|
<select id="ingestMode">
|
|
<option value="mechanical">mechanical</option>
|
|
<option value="interactive">interactive</option>
|
|
</select>
|
|
</label>
|
|
<label>Tags (coma separada)
|
|
<input id="ingestTags" value="workspace,global-docs" />
|
|
</label>
|
|
</div>
|
|
<p class="helper" id="ingestModeHint">Si seleccionas un archivo local, el playground usara upload directo y podras aislarlo con un `sourceId` propio para no mezclarlo con otros scopes.</p>
|
|
<div class="actions">
|
|
<button id="ingestButton">Lanzar ingesta</button>
|
|
</div>
|
|
<pre id="ingestResult">Sin ejecutar aun.</pre>
|
|
</article>
|
|
</section>
|
|
|
|
<section id="tab-cleanup" class="tab-panel">
|
|
<article class="panel">
|
|
<h2>Limpieza controlada</h2>
|
|
<p class="helper">Permite eliminar contexto ya ingerido del RAG antes de reingestar una fuente, para evitar duplicados y versiones mezcladas.</p>
|
|
<div class="grid single-grid">
|
|
<label>Scope disponible a limpiar
|
|
<select id="cleanupScopeSelect">
|
|
<option value="">Cargando scopes...</option>
|
|
</select>
|
|
</label>
|
|
<label>Source ID (obligatorio si no hay Source Ref)
|
|
<input id="cleanupSourceId" readonly />
|
|
</label>
|
|
<label>Source Ref (obligatorio si no hay Source ID)
|
|
<input id="cleanupSourceRef" readonly />
|
|
</label>
|
|
<label>Tags asociados (informativo)
|
|
<input id="cleanupTags" readonly />
|
|
</label>
|
|
</div>
|
|
<div class="actions">
|
|
<button id="cleanupButton" style="background: var(--danger); color: white;" title="Borrar de Qdrant los vectores del scope seleccionado" aria-label="Eliminar scope de Qdrant">Eliminar contexto seleccionado</button>
|
|
</div>
|
|
<pre id="cleanupResult">Selecciona un scope y pulsa el boton para eliminarlo.</pre>
|
|
</article>
|
|
</section>
|
|
|
|
<section id="tab-bootstrap" class="tab-panel">
|
|
<article class="panel">
|
|
<h2>Bootstrap de sesion</h2>
|
|
<div class="grid single-grid">
|
|
<label>Scope disponible
|
|
<select id="scopePresetSelect">
|
|
<option value="">Cargando scopes...</option>
|
|
</select>
|
|
</label>
|
|
<label>Source ID seleccionado
|
|
<input id="selectedSourceId" readonly />
|
|
</label>
|
|
<label>Scope por sourceRef
|
|
<input id="scopeSourceRef" value="/home/pancho/Documentos/Empresa/Desarrollo/IA/docs" />
|
|
</label>
|
|
<label>Tags (coma separada)
|
|
<input id="scopeTags" value="" />
|
|
</label>
|
|
<label>Modo del bootstrap
|
|
<select id="bootstrapMode">
|
|
<option value="documental">documental</option>
|
|
<option value="codigo">codigo</option>
|
|
<option value="auto">auto</option>
|
|
</select>
|
|
</label>
|
|
<label>Edicion manual del scope
|
|
<select id="scopeEditMode">
|
|
<option value="locked">bloqueado al scope seleccionado</option>
|
|
<option value="manual">editar manualmente</option>
|
|
</select>
|
|
</label>
|
|
<label>Modelo para sintetizar bootstrap
|
|
<select id="answerModel">
|
|
<option value="openai/gpt-4.1-mini">openai/gpt-4.1-mini</option>
|
|
</select>
|
|
</label>
|
|
<label>Consulta bootstrap
|
|
<textarea id="bootstrapQuery" rows="4">dame un mapa inicial del workspace, sus lineas de trabajo principales, reglas, documentacion base y puntos importantes a tener presentes</textarea>
|
|
</label>
|
|
</div>
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="useModelInRetrieve" checked />
|
|
Usar un modelo para sintetizar el bootstrap recuperado
|
|
</label>
|
|
<div class="actions">
|
|
<button
|
|
id="bootstrapButton"
|
|
title="Ejecutar bootstrap y cargar contexto inicial"
|
|
aria-label="Ejecutar bootstrap y cargar contexto inicial"
|
|
>Cargar bootstrap</button>
|
|
<button
|
|
id="replaceBootstrapButton"
|
|
class="secondary"
|
|
title="Reemplazar el contexto activo por un nuevo bootstrap"
|
|
aria-label="Reemplazar el contexto activo por un nuevo bootstrap"
|
|
>Reemplazar contexto</button>
|
|
<button
|
|
id="clearBootstrapButton"
|
|
class="secondary"
|
|
title="Vaciar el contexto bootstrap activo"
|
|
aria-label="Vaciar el contexto bootstrap activo"
|
|
>Vaciar contexto</button>
|
|
<button
|
|
id="presetDocs"
|
|
class="secondary"
|
|
title="Aplicar preset para la documentacion global del workspace"
|
|
aria-label="Aplicar preset para la documentacion global del workspace"
|
|
>Preset docs</button>
|
|
<button
|
|
id="presetRagDocs"
|
|
class="secondary"
|
|
title="Aplicar preset para la documentacion del modulo RAG"
|
|
aria-label="Aplicar preset para la documentacion del modulo RAG"
|
|
>Preset RAG docs</button>
|
|
<button
|
|
id="presetCode"
|
|
class="secondary"
|
|
title="Aplicar preset para el codigo fuente del modulo RAG"
|
|
aria-label="Aplicar preset para el codigo fuente del modulo RAG"
|
|
>Preset codigo</button>
|
|
</div>
|
|
<div class="bootstrap-help" aria-label="Ayuda de uso de botones bootstrap">
|
|
<p class="helper bootstrap-help-summary">Los presets solo preparan la configuracion recomendada. Para cargar realmente el contexto en la sesion debes pulsar <code>Cargar bootstrap</code>. Si ya hay un contexto activo y quieres sustituirlo, usa <code>Reemplazar contexto</code>. Si quieres eliminarlo por completo, usa <code>Vaciar contexto</code>.</p>
|
|
<div class="bootstrap-help-grid">
|
|
<p><strong>Cargar bootstrap:</strong> Carga el contexto inicial del scope seleccionado para que el chat pueda trabajar con una panoramica del contenido.</p>
|
|
<p><strong>Reemplazar contexto:</strong> Recalcula el bootstrap y reemplaza el contexto cargado por uno nuevo usando la configuracion actual.</p>
|
|
<p><strong>Vaciar contexto:</strong> Borra el contexto precargado de la sesion para probar el chat sin bootstrap.</p>
|
|
<p><strong>Preset docs:</strong> Prepara el formulario para trabajar con la documentacion global del workspace. Despues pulsa <code>Cargar bootstrap</code> si quieres cargar ese contexto.</p>
|
|
<p><strong>Preset RAG docs:</strong> Prepara el formulario para trabajar con la documentacion del modulo RAG. Despues pulsa <code>Cargar bootstrap</code> si quieres cargar ese contexto.</p>
|
|
<p><strong>Preset codigo:</strong> Prepara el formulario para trabajar con el codigo del RAG en modo <code>codigo</code>. Despues pulsa <code>Cargar bootstrap</code> si quieres cargar ese contexto.</p>
|
|
</div>
|
|
</div>
|
|
<pre id="bootstrapResult">Sin ejecutar aun.</pre>
|
|
</article>
|
|
</section>
|
|
|
|
<section id="tab-chat" class="tab-panel">
|
|
<div class="grid chat-grid">
|
|
<article class="panel context-panel">
|
|
<h2>Estado del contexto</h2>
|
|
<div class="context-status" id="contextStatusCard">
|
|
<span id="contextIndicator" class="indicator indicator-off"></span>
|
|
<div>
|
|
<strong id="contextStatusText">Sin contexto cargado</strong>
|
|
<p id="contextScopeText">No hay bootstrap activo.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Scope activo para chat
|
|
<input id="chatScopeInfo" readonly />
|
|
</label>
|
|
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="reuseBootstrapContext" checked />
|
|
Reutilizar bootstrap como contexto base
|
|
</label>
|
|
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="allowAdditionalRetrieve" checked />
|
|
Permitir que el modelo haga consultas adicionales al RAG durante la conversacion
|
|
</label>
|
|
|
|
<label>Modo de chat
|
|
<select id="chatMode">
|
|
<option value="documental">documental</option>
|
|
<option value="codigo">codigo</option>
|
|
<option value="auto">auto</option>
|
|
</select>
|
|
</label>
|
|
|
|
<h3>Contexto bootstrap cargado</h3>
|
|
<pre id="bootstrapContextResult">Aun no hay bootstrap cargado.</pre>
|
|
</article>
|
|
|
|
<article class="panel chat-panel">
|
|
<h2>Chat con el modelo</h2>
|
|
<div id="chatMessages" class="chat-messages">
|
|
<p class="empty-chat">Aun no hay conversacion. Carga un bootstrap y empieza a preguntar.</p>
|
|
</div>
|
|
|
|
<label>Tu mensaje
|
|
<textarea id="chatInput" rows="4">que tenemos pendiente por hacer en este workspace</textarea>
|
|
</label>
|
|
|
|
<div class="actions">
|
|
<button id="sendChatButton">Enviar mensaje</button>
|
|
<button id="clearChatButton" class="secondary">Limpiar chat</button>
|
|
</div>
|
|
|
|
<label>Nota opcional para log manual
|
|
<textarea id="manualLogNote" rows="3" placeholder="Ejemplo: la respuesta no usa bien el contexto del libro y parece demasiado generica"></textarea>
|
|
</label>
|
|
|
|
<div class="actions">
|
|
<button id="manualLogButton" class="secondary">Registrar esta consulta en logs</button>
|
|
</div>
|
|
|
|
<h3>Ultima respuesta estructurada</h3>
|
|
<pre id="mainResult">Sin ejecutar aun.</pre>
|
|
|
|
<h3>Comparacion sin RAG</h3>
|
|
<label class="checkbox">
|
|
<input type="checkbox" id="compareWithoutRag" />
|
|
Comparar tambien con respuesta sin RAG
|
|
</label>
|
|
<pre id="compareResult">Desactivada.</pre>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Estado / health</h2>
|
|
<pre id="healthResult">Sin comprobar.</pre>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Logs recientes</h2>
|
|
<pre id="logsResult">Sin cargar aun.</pre>
|
|
</section>
|
|
</main>
|
|
|
|
<script src="/playground/app.js" type="module"></script>
|
|
</body>
|
|
</html>
|