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 ingestSourceRef = document.getElementById("ingestSourceRef"); const ingestMode = document.getElementById("ingestMode"); const ingestTags = document.getElementById("ingestTags"); 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 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) => `
${entry.role === "user" ? "Usuario" : "Modelo"}

${entry.content.replace(/

`).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"; } }); 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 { const data = await request("/ingest", { sourceType: ingestSourceType.value, sourceRef: ingestSourceRef.value, mode: ingestMode.value, tags: splitTags(ingestTags.value) }); ingestResult.textContent = format(data); await loadScopes(); } 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();