From dc1a3f8badae9c52af9c444517a402d934516cd2 Mon Sep 17 00:00:00 2001 From: Marcos Date: Sun, 22 Mar 2026 15:35:33 -0300 Subject: [PATCH] feat: Add Orchestrator LLM config to web interface - Add section to configure Planner (Gemini, OpenAI, Anthropic, Ollama) - Add section to configure Executor (Ollama, Gemini) - Auto-discover Ollama models - Add Orchestrator status display - Add Sync Credentials button - Load models dynamically based on provider selection --- templates/index.html | 223 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/templates/index.html b/templates/index.html index e50e204..6f532a7 100644 --- a/templates/index.html +++ b/templates/index.html @@ -795,6 +795,75 @@ + +
Orquestrador AI (Planner + Executor)
+
+
+ Status: Carregando... + +
+ +
+ +
+

+ + Planner (Planejador) +

+
+ + +
+
+ + +
+
+ + +
+

+ + Executor (Executor) +

+
+ + +
+
+ + +
+
+
+ +
+ +
+
+
Terminal & Insights da IA
@@ -897,6 +966,10 @@ function initDashboard() { fetchStats(); loadConfig(); + loadOrchestratorStatus(); + loadLLMModels().then(function() { + loadLLMConfig(); + }); } // Theme management @@ -1111,6 +1184,156 @@ } } + // ================== ORCHESTRATOR LLM CONFIG ================== + + let availableModels = {}; + + async function loadOrchestratorStatus() { + try { + const res = await apiFetch('/api/orchestrator-status'); + const data = await res.json(); + + const statusEl = document.getElementById('orchestrator-status'); + if (statusEl) { + statusEl.innerHTML = 'Planner: ' + data.planner.name + ' | Executor: ' + data.executor.name + ' | Ferramentas: ' + data.available_tools; + } + } catch (e) { + const statusEl = document.getElementById('orchestrator-status'); + if (statusEl) statusEl.textContent = 'Erro ao carregar'; + } + } + + async function loadLLMModels() { + try { + const res = await apiFetch('/api/llm-models'); + availableModels = await res.json(); + } catch (e) { + console.error('Erro ao carregar modelos:', e); + } + } + + async function loadLLMConfig() { + try { + const res = await apiFetch('/api/llm-config'); + const data = await res.json(); + + // Planner + const plannerProvider = document.getElementById('planner_provider'); + const plannerModel = document.getElementById('planner_model'); + if (plannerProvider) plannerProvider.value = data.planner.provider; + await loadPlannerModels(); + if (plannerModel && data.planner.model) { + plannerModel.value = data.planner.model; + } + + // Executor + const executorProvider = document.getElementById('executor_provider'); + const executorModel = document.getElementById('executor_model'); + if (executorProvider) executorProvider.value = data.executor.provider; + await loadExecutorModels(); + if (executorModel && data.executor.model) { + executorModel.value = data.executor.model; + } + } catch (e) { + console.error('Erro ao carregar config LLM:', e); + } + } + + function populateModelSelect(selectEl, models) { + if (!selectEl) return; + selectEl.innerHTML = ''; + + if (!models || models.length === 0) { + selectEl.innerHTML = ''; + return; + } + + models.forEach(function(model) { + const opt = document.createElement('option'); + opt.value = model; + opt.textContent = model; + selectEl.appendChild(opt); + }); + } + + async function loadPlannerModels() { + const provider = document.getElementById('planner_provider')?.value; + const modelSelect = document.getElementById('planner_model'); + if (!modelSelect) return; + + modelSelect.innerHTML = ''; + + if (provider === 'ollama') { + const models = availableModels.models?.find(function(p) { return p.provider === 'ollama'; })?.models || []; + populateModelSelect(modelSelect, models.length > 0 ? models : ['qwen2.5-coder:1.5b', 'llama3.1:8b', 'codellama:13b']); + } else { + const fixedModels = { + gemini: ['gemini-2.5-flash', 'gemini-2.0-pro', 'gemini-1.5-flash'], + openai: ['gpt-4o', 'gpt-4-turbo', 'gpt-3.5-turbo'], + anthropic: ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'] + }; + populateModelSelect(modelSelect, fixedModels[provider] || []); + } + } + + async function loadExecutorModels() { + const provider = document.getElementById('executor_provider')?.value; + const modelSelect = document.getElementById('executor_model'); + if (!modelSelect) return; + + modelSelect.innerHTML = ''; + + if (provider === 'ollama') { + const models = availableModels.models?.find(function(p) { return p.provider === 'ollama'; })?.models || []; + populateModelSelect(modelSelect, models.length > 0 ? models : ['qwen2.5-coder:1.5b', 'llama3.1:8b', 'codellama:13b']); + } else if (provider === 'gemini') { + populateModelSelect(modelSelect, ['gemini-2.5-flash', 'gemini-2.0-pro']); + } else { + populateModelSelect(modelSelect, []); + } + } + + async function saveLLMConfig() { + const plannerProvider = document.getElementById('planner_provider')?.value; + const plannerModel = document.getElementById('planner_model')?.value; + const executorProvider = document.getElementById('executor_provider')?.value; + const executorModel = document.getElementById('executor_model')?.value; + + try { + const res = await apiFetch('/api/llm-config', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + planner_provider: plannerProvider, + planner_model: plannerModel, + executor_provider: executorProvider, + executor_model: executorModel + }) + }); + + if (res.ok) { + showToast('Config LLM salva! Planner: ' + plannerProvider + ', Executor: ' + executorProvider); + loadOrchestratorStatus(); + } else { + throw new Error(); + } + } catch (e) { + showToast('Erro ao salvar config LLM.', true); + } + } + + async function syncCredentials() { + try { + const res = await apiFetch('/api/sync-credentials', { + method: 'POST' + }); + const data = await res.json(); + showToast('Credenciais sincronizadas! Services: ' + Object.keys(data.services || {}).length); + } catch (e) { + showToast('Erro ao sincronizar.', true); + } + } + async function testLLMSpeed() { const btn = document.getElementById('btn-test-llm'); const originalContent = btn.innerHTML;