From a1bc1af6466f0ca61a05baa8ab881f9623ed4e80 Mon Sep 17 00:00:00 2001 From: jaakko Date: Tue, 7 Apr 2026 09:18:00 +0300 Subject: [PATCH] Hardware API: Ollama-fallback kun wgpu ei tunnista GPU:ta Dockerissa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /api/v1/hardware tarkistaa nyt myös Ollaman tilan fallbackina. kpn models näyttää ladattujen mallien määrän ja ✓ oikein. Co-Authored-By: Claude Opus 4.6 (1M context) --- network-poc/hub/src/main.rs | 25 +++++++++++++++++++++---- network-poc/static/index.html | 9 +++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/network-poc/hub/src/main.rs b/network-poc/hub/src/main.rs index 12253a5..b8638fd 100644 --- a/network-poc/hub/src/main.rs +++ b/network-poc/hub/src/main.rs @@ -984,17 +984,34 @@ async fn api_hardware( s.get("node_type").and_then(|v| v.as_str()) == Some("native") }); - let (vram_mb, gpu_name, ram_mb) = if let Some(s) = native { + let (mut vram_mb, mut gpu_name, ram_mb) = if let Some(s) = native { let gpus = s.get("gpus").and_then(|v| v.as_array()); let gpu = gpus.and_then(|g| g.first()); let vram = gpu.and_then(|g| g.get("vram_total_mb")).and_then(|v| v.as_u64()).unwrap_or(0); - let name = gpu.and_then(|g| g.get("name")).and_then(|v| v.as_str()).unwrap_or("?"); + let name = gpu.and_then(|g| g.get("name")).and_then(|v| v.as_str()).unwrap_or("").to_string(); let ram = s.get("system").and_then(|v| v.get("ram_total_mb")).and_then(|v| v.as_u64()).unwrap_or(0); - (vram, name.to_string(), ram) + (vram, name, ram) } else { - (0, "ei natiivisolmua".to_string(), 0) + (0, String::new(), 0) }; + // Fallback: kysytään Ollamalta onko malleja ladattu (= Ollama on käynnissä) + if vram_mb == 0 { + let ollama_url = std::env::var("OLLAMA_URL").unwrap_or_else(|_| "http://ollama:11434".to_string()); + if let Ok(resp) = reqwest::get(format!("{}/api/tags", ollama_url)).await { + if let Ok(body) = resp.json::().await { + let models = body["models"].as_array().map(|a| a.len()).unwrap_or(0); + if models > 0 { + gpu_name = "Ollama (GPU/CPU)".to_string(); + // Natiivisolmun RAM fallbackina + vram_mb = if ram_mb > 0 { ram_mb } else { 0 }; + } + } + } + } + + if gpu_name.is_empty() { gpu_name = "ei natiivisolmua".to_string(); } + axum::Json(serde_json::json!({ "gpu_name": gpu_name, "vram_mb": vram_mb, diff --git a/network-poc/static/index.html b/network-poc/static/index.html index 5ce7496..f9714e0 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -2877,11 +2877,16 @@ ${generatedFiles['Dockerfile'] || '(puuttuu)'}`; const btn = document.getElementById('agent-compute-btn'); const wasmLoaded = btn?.dataset.state === 'ready'; if (hw.gpu_name && hw.gpu_name !== 'ei natiivisolmua') { - termLog(` GPU: ${hw.gpu_name} | VRAM: ${Math.round((hw.vram_mb||0)/1024)} GB`); + const vram = hw.vram_mb ? ` | VRAM: ${Math.round(hw.vram_mb/1024)} GB` : ''; + termLog(` ${hw.gpu_name}${vram}`); + } + if (loadedNames.length > 0) { + termLog(` Ollama: ${loadedNames.length} mallia ladattu`); } termLog(' Mallit (kpn load <numero>):', '#c9d1d9'); for (const m of allModels) { - const loaded = (m.id === '1' && wasmLoaded) || loadedNames.some(n => m.name.includes(n) || n.includes(m.name.split(':')[1])); + const nameBase = m.name.split(':')[1]; // "7b", "1.5b" etc + const loaded = (m.id === '1' && wasmLoaded) || loadedNames.some(n => n.includes(nameBase)); const status = loaded ? ' ✓ ladattu' : ''; termLog(` ${m.id} ${m.name} ${m.size} | ${m.type}${status}`); }