Hardware API: Ollama-fallback kun wgpu ei tunnista GPU:ta Dockerissa

/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) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 09:18:00 +03:00
parent 6b27cbbade
commit a1bc1af646
2 changed files with 28 additions and 6 deletions

View File

@@ -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::<serde_json::Value>().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,

View File

@@ -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(` <span style="color:#8b949e">GPU: ${hw.gpu_name} | VRAM: ${Math.round((hw.vram_mb||0)/1024)} GB</span>`);
const vram = hw.vram_mb ? ` | VRAM: ${Math.round(hw.vram_mb/1024)} GB` : '';
termLog(` <span style="color:#8b949e">${hw.gpu_name}${vram}</span>`);
}
if (loadedNames.length > 0) {
termLog(` <span style="color:#3fb950">Ollama: ${loadedNames.length} mallia ladattu</span>`);
}
termLog(' Mallit <span style="color:#8b949e">(kpn load &lt;numero&gt;)</span>:', '#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 ? ' <span style="color:#3fb950">✓ ladattu</span>' : '';
termLog(` <span style="color:#58a6ff">${m.id}</span> ${m.name} <span style="color:#8b949e">${m.size} | ${m.type}</span>${status}`);
}