From 66d1e8c4b141c0e41d8dd21933d3c8e141a7fea2 Mon Sep 17 00:00:00 2001 From: jaakko Date: Tue, 7 Apr 2026 08:57:48 +0300 Subject: [PATCH] Ollama-kutsut hubin kautta: ei mixed content HTTPS-sivulla MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lisätty GET /api/v1/ollama/tags proxy-endpoint hubiin. Poistettu suorat http://hostname:11434 -kutsut frontendistä. Hub välittää Ollama-kutsut sisäisessä Docker-verkossa. Co-Authored-By: Claude Opus 4.6 (1M context) --- network-poc/hub/Cargo.toml | 1 + network-poc/hub/src/main.rs | 15 +++++++++++++++ network-poc/static/index.html | 20 ++++++-------------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/network-poc/hub/Cargo.toml b/network-poc/hub/Cargo.toml index bfbc84a..040b09e 100644 --- a/network-poc/hub/Cargo.toml +++ b/network-poc/hub/Cargo.toml @@ -16,3 +16,4 @@ futures = "0.3" rusqlite = { version = "0.31", features = ["bundled"] } chrono = "0.4" base64 = "0.22" +reqwest = { version = "0.12", features = ["json"] } diff --git a/network-poc/hub/src/main.rs b/network-poc/hub/src/main.rs index 985d559..12253a5 100644 --- a/network-poc/hub/src/main.rs +++ b/network-poc/hub/src/main.rs @@ -386,6 +386,7 @@ async fn main() { .route("/api/v1/chat/completions", axum::routing::post(api_chat_completions)) .route("/api/v1/model", axum::routing::post(api_change_model)) .route("/api/v1/hardware", get(api_hardware)) + .route("/api/v1/ollama/tags", get(api_ollama_tags)) .route("/admin", get(admin_page)) .nest_service("/", { let static_dir = std::env::var("STATIC_DIR").unwrap_or_else(|_| "../static".to_string()); @@ -960,6 +961,20 @@ struct ChatCompletionResponse { tokens_generated: u64, } +async fn api_ollama_tags() -> axum::response::Response { + let ollama_url = std::env::var("OLLAMA_URL").unwrap_or_else(|_| "http://ollama:11434".to_string()); + match reqwest::get(format!("{}/api/tags", ollama_url)).await { + Ok(resp) => { + if let Ok(body) = resp.json::().await { + axum::Json(body).into_response() + } else { + axum::Json(serde_json::json!({ "models": [] })).into_response() + } + } + Err(_) => axum::Json(serde_json::json!({ "models": [] })).into_response(), + } +} + async fn api_hardware( axum::extract::State(state): axum::extract::State>, ) -> axum::response::Response { diff --git a/network-poc/static/index.html b/network-poc/static/index.html index 03396fa..7556153 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -2830,19 +2830,11 @@ ${generatedFiles['Dockerfile'] || '(puuttuu)'}`; if (content) content.textContent = spinFrames[spinIdx] + ' Ladataan ' + selected.name + '...'; }, 100); // Vaihdetaan malli hubille + Ollama pull - Promise.all([ - fetch('/api/v1/model', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ model: selected.name }), - }).then(r => r.json()), - // Suora pull Ollamasta — odotetaan kunnes malli on ladattu - fetch('http://' + window.location.hostname + ':11434/api/pull', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: selected.name, stream: false }), - }).then(r => r.json()).catch(() => ({ status: 'ok' })), - ]).then(([hubData, _]) => { + fetch('/api/v1/model', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ model: selected.name }), + }).then(r => r.json()).then(hubData => { clearInterval(spinTimer); pullLine.remove(); if (hubData.status === 'ok') { @@ -2878,7 +2870,7 @@ ${generatedFiles['Dockerfile'] || '(puuttuu)'}`; // Haetaan ladatut mallit Ollamasta Promise.all([ fetch('/api/v1/hardware').then(r => r.json()).catch(() => ({})), - fetch('http://' + window.location.hostname + ':11434/api/tags').then(r => r.json()).catch(() => ({ models: [] })), + fetch('/api/v1/ollama/tags').then(r => r.json()).catch(() => ({ models: [] })), ]).then(([hw, ollama]) => { const loadedNames = (ollama.models || []).map(m => m.name.replace(':latest', '')); const btn = document.getElementById('agent-compute-btn');