${entry.content.replace(/
const healthButton = document.getElementById("healthButton"); const ingestButton = document.getElementById("ingestButton"); const bootstrapButton = document.getElementById("bootstrapButton"); const replaceBootstrapButton = document.getElementById("replaceBootstrapButton"); const clearBootstrapButton = document.getElementById("clearBootstrapButton"); const sendChatButton = document.getElementById("sendChatButton"); const clearChatButton = document.getElementById("clearChatButton"); const presetDocs = document.getElementById("presetDocs"); const presetRagDocs = document.getElementById("presetRagDocs"); const presetCode = document.getElementById("presetCode"); const healthResult = document.getElementById("healthResult"); const ingestResult = document.getElementById("ingestResult"); const bootstrapResult = document.getElementById("bootstrapResult"); const mainResult = document.getElementById("mainResult"); const compareResult = document.getElementById("compareResult"); const bootstrapContextResult = document.getElementById("bootstrapContextResult"); const chatMessages = document.getElementById("chatMessages"); const contextIndicator = document.getElementById("contextIndicator"); const contextStatusText = document.getElementById("contextStatusText"); const contextScopeText = document.getElementById("contextScopeText"); const ingestSourceType = document.getElementById("ingestSourceType"); const ingestSourceId = document.getElementById("ingestSourceId"); const ingestSourceRef = document.getElementById("ingestSourceRef"); const ingestUploadFile = document.getElementById("ingestUploadFile"); const ingestMode = document.getElementById("ingestMode"); const ingestTags = document.getElementById("ingestTags"); const ingestModeHint = document.getElementById("ingestModeHint"); const bootstrapQuery = document.getElementById("bootstrapQuery"); const bootstrapMode = document.getElementById("bootstrapMode"); const answerModel = document.getElementById("answerModel"); const useModelInRetrieve = document.getElementById("useModelInRetrieve"); const reuseBootstrapContext = document.getElementById("reuseBootstrapContext"); const allowAdditionalRetrieve = document.getElementById("allowAdditionalRetrieve"); const scopePresetSelect = document.getElementById("scopePresetSelect"); const scopeSourceRef = document.getElementById("scopeSourceRef"); const scopeTags = document.getElementById("scopeTags"); const compareWithoutRag = document.getElementById("compareWithoutRag"); const chatMode = document.getElementById("chatMode"); const chatInput = document.getElementById("chatInput"); let lastBootstrapContext = null; let chatHistory = []; function format(value) { return JSON.stringify(value, null, 2); } function splitTags(value) { return value.split(",").map((entry) => entry.trim()).filter(Boolean); } function buildScopeLabel(scope) { const modes = scope.chunkModes.join(", ") || "sin modo"; return `${scope.sourceRef} [${modes}]`; } function updateIngestUiState() { const hasUpload = Boolean(ingestUploadFile.files && ingestUploadFile.files[0]); ingestSourceType.value = hasUpload ? "file" : ingestSourceType.value; ingestSourceType.disabled = hasUpload; ingestSourceRef.disabled = hasUpload; if (hasUpload) { ingestModeHint.textContent = `Upload directo activo: se ingerira el archivo local "${ingestUploadFile.files[0].name}" y se ignorara la ruta manual.`; ingestModeHint.classList.add("strong"); } else { ingestModeHint.textContent = "Si seleccionas un archivo local, el playground usara upload directo y podras aislarlo con un `sourceId` propio para no mezclarlo con otros scopes."; ingestModeHint.classList.remove("strong"); } } function request(url, payload, method = "POST") { return fetch(url, { method, headers: { "Content-Type": "application/json" }, body: payload ? JSON.stringify(payload) : undefined }).then(async (response) => { const data = await response.json(); if (!response.ok) { throw new Error(data.error || `HTTP ${response.status}`); } return data; }); } function renderBootstrapContext() { if (!lastBootstrapContext) { bootstrapContextResult.textContent = "Aun no hay bootstrap cargado."; contextIndicator.className = "indicator indicator-off"; contextStatusText.textContent = "Sin contexto cargado"; contextScopeText.textContent = "No hay bootstrap activo."; return; } bootstrapContextResult.textContent = format(lastBootstrapContext); contextIndicator.className = "indicator indicator-on"; contextStatusText.textContent = "Contexto bootstrap activo"; contextScopeText.textContent = lastBootstrapContext.scope?.sourceRef || "Scope no especificado"; } function renderChatHistory() { if (chatHistory.length === 0) { chatMessages.innerHTML = '
Aun no hay conversacion. Carga un bootstrap y empieza a preguntar.
'; return; } chatMessages.innerHTML = chatHistory.map((entry) => ` `).join(""); chatMessages.scrollTop = chatMessages.scrollHeight; } function buildScopeFromInputs() { return { sourceRef: scopeSourceRef.value, tags: splitTags(scopeTags.value) }; } function applyPreset(mode, query, sourceRef, useRetrieveModel = false) { bootstrapMode.value = mode; chatMode.value = mode; bootstrapQuery.value = query; scopeSourceRef.value = sourceRef; useModelInRetrieve.checked = useRetrieveModel; } async function loadScopes() { try { const scopes = await fetch("/sources").then((response) => response.json()); scopePresetSelect.innerHTML = ""; const placeholder = document.createElement("option"); placeholder.value = ""; placeholder.textContent = "Selecciona un scope disponible"; scopePresetSelect.appendChild(placeholder); for (const scope of scopes) { const option = document.createElement("option"); option.value = JSON.stringify(scope); option.textContent = buildScopeLabel(scope); scopePresetSelect.appendChild(option); } if (scopes.length === 0) { placeholder.textContent = "No hay scopes detectados"; } } catch (error) { scopePresetSelect.innerHTML = ``; } } async function loadAnswerModels() { try { const payload = await fetch("/models/answer").then((response) => response.json()); answerModel.innerHTML = ""; for (const model of payload.models || []) { const option = document.createElement("option"); option.value = model; option.textContent = model; answerModel.appendChild(option); } if (payload.defaultModel) { answerModel.value = payload.defaultModel; } } catch { answerModel.innerHTML = ''; } } document.querySelectorAll(".tab-button").forEach((button) => { button.addEventListener("click", () => { document.querySelectorAll(".tab-button").forEach((entry) => entry.classList.remove("active")); document.querySelectorAll(".tab-panel").forEach((panel) => panel.classList.remove("active")); button.classList.add("active"); document.getElementById(`tab-${button.dataset.tab}`).classList.add("active"); }); }); scopePresetSelect.addEventListener("change", () => { if (!scopePresetSelect.value) { return; } const scope = JSON.parse(scopePresetSelect.value); scopeSourceRef.value = scope.sourceRef || ""; scopeTags.value = (scope.tags || []).join(", "); if (scope.chunkModes.includes("codigo")) { bootstrapMode.value = "codigo"; chatMode.value = "codigo"; } else if (scope.chunkModes.includes("documental")) { bootstrapMode.value = "documental"; chatMode.value = "documental"; } }); ingestUploadFile.addEventListener("change", updateIngestUiState); healthButton.addEventListener("click", async () => { healthResult.textContent = "Comprobando..."; try { const data = await fetch("/health").then((response) => response.json()); healthResult.textContent = format(data); } catch (error) { healthResult.textContent = String(error); } }); ingestButton.addEventListener("click", async () => { ingestResult.textContent = "Ejecutando ingesta..."; try { let data; if (ingestUploadFile.files && ingestUploadFile.files[0]) { const formData = new FormData(); formData.append("file", ingestUploadFile.files[0]); formData.append("mode", ingestMode.value); formData.append("tags", splitTags(ingestTags.value).join(",")); if (ingestSourceId.value.trim()) { formData.append("sourceId", ingestSourceId.value.trim()); } const response = await fetch("/ingest/upload", { method: "POST", body: formData }); data = await response.json(); if (!response.ok) { throw new Error(data.error || `HTTP ${response.status}`); } } else { data = await request("/ingest", { sourceId: ingestSourceId.value.trim() || undefined, sourceType: ingestSourceType.value, sourceRef: ingestSourceRef.value, mode: ingestMode.value, tags: splitTags(ingestTags.value) }); } ingestResult.textContent = format(data); await loadScopes(); updateIngestUiState(); } catch (error) { ingestResult.textContent = String(error); } }); async function executeBootstrap() { bootstrapResult.textContent = "Cargando bootstrap..."; try { const data = await request("/retrieve", { mode: bootstrapMode.value, intent: "bootstrap", query: bootstrapQuery.value, model: answerModel.value, useModelInRetrieve: useModelInRetrieve.checked, scope: buildScopeFromInputs() }); lastBootstrapContext = data; bootstrapResult.textContent = format(data); renderBootstrapContext(); } catch (error) { bootstrapResult.textContent = String(error); } } bootstrapButton.addEventListener("click", executeBootstrap); replaceBootstrapButton.addEventListener("click", executeBootstrap); clearBootstrapButton.addEventListener("click", () => { lastBootstrapContext = null; renderBootstrapContext(); }); sendChatButton.addEventListener("click", async () => { const message = chatInput.value.trim(); if (!message) { return; } chatHistory.push({ role: "user", content: message }); renderChatHistory(); mainResult.textContent = "Consultando..."; compareResult.textContent = compareWithoutRag.checked ? "Comparando..." : "Desactivada."; try { const response = await request("/chat", { message, history: chatHistory, mode: chatMode.value, model: answerModel.value, preloadedContext: reuseBootstrapContext.checked && lastBootstrapContext ? (lastBootstrapContext.modelSummary || lastBootstrapContext.summary || "") : undefined, allowAdditionalRetrieve: allowAdditionalRetrieve.checked, scope: buildScopeFromInputs() }); chatHistory.push({ role: "assistant", content: response.answer }); renderChatHistory(); mainResult.textContent = format(response); if (compareWithoutRag.checked) { const comparison = await request("/answer/direct", { query: message, model: answerModel.value, preloadedContext: reuseBootstrapContext.checked && lastBootstrapContext ? (lastBootstrapContext.modelSummary || lastBootstrapContext.summary || "") : undefined }); compareResult.textContent = format(comparison); } chatInput.value = ""; } catch (error) { mainResult.textContent = String(error); compareResult.textContent = compareWithoutRag.checked ? String(error) : "Desactivada."; } }); clearChatButton.addEventListener("click", () => { chatHistory = []; renderChatHistory(); mainResult.textContent = "Sin ejecutar aun."; compareResult.textContent = "Desactivada."; }); presetDocs.addEventListener("click", () => { applyPreset( "documental", "dame un mapa inicial del workspace, sus lineas de trabajo principales, reglas, documentacion base y puntos importantes a tener presentes", "/home/pancho/Documentos/Empresa/Desarrollo/IA/docs", true ); }); presetRagDocs.addEventListener("click", () => { applyPreset( "documental", "dame un mapa inicial del modulo RAG, su arquitectura, decisiones, estado actual y documentos clave", "/home/pancho/Documentos/Empresa/Desarrollo/IA/RAG/docs", true ); }); presetCode.addEventListener("click", () => { applyPreset( "codigo", "dame un mapa inicial del codigo del modulo RAG, sus modulos principales, flujo interno y piezas clave", "/home/pancho/Documentos/Empresa/Desarrollo/IA/RAG/src", true ); }); loadScopes(); loadAnswerModels(); renderBootstrapContext(); renderChatHistory(); updateIngestUiState();