diff --git a/__LOCAL_LLMs/dashboard/src/app/api/system/route.ts b/__LOCAL_LLMs/dashboard/src/app/api/system/route.ts index eb4c3e94..04f7881a 100644 --- a/__LOCAL_LLMs/dashboard/src/app/api/system/route.ts +++ b/__LOCAL_LLMs/dashboard/src/app/api/system/route.ts @@ -2,12 +2,36 @@ import { NextResponse } from 'next/server'; import { exec, execFile } from 'child_process'; import { promisify } from 'util'; import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; import os from 'os'; const execAsync = promisify(exec); const execFileAsync = promisify(execFile); const IS_MAC = process.platform === 'darwin'; +const IS_WSL = + process.platform === 'linux' && + (() => { + try { + return readFileSync('/proc/version', 'utf-8').toLowerCase().includes('microsoft'); + } catch { + return false; + } + })(); + +async function readWindowsCommand(command: string): Promise { + try { + const { stdout } = await execFileAsync( + 'powershell.exe', + ['-NoProfile', '-Command', command], + { timeout: 4000 } + ); + const value = stdout.replace(/\r/g, '').trim(); + return value || null; + } catch { + return null; + } +} // Cache slow commands with TTL let staticCache: { @@ -29,6 +53,12 @@ async function getChipInfo(): Promise { ); return stdout.trim(); } + if (IS_WSL) { + const winCpu = await readWindowsCommand( + '(Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Name)' + ); + if (winCpu) return winCpu; + } // Linux / WSL2 const { stdout } = await execAsync( "lscpu 2>/dev/null | grep 'Model name' | sed 's/.*:\\s*//' || cat /proc/cpuinfo | grep 'model name' | head -1 | sed 's/.*: //'" @@ -110,17 +140,60 @@ async function getBrewPackages(): Promise&1 | head -1`, { timeout: 3000 }); - if (stdout.trim()) { - results.push({ name: pkg, version: stdout.trim() }); + if (pkg === 'ffmpeg') { + const { stdout } = await execAsync('ffmpeg -version 2>/dev/null | head -1', { + timeout: 3000, + }); + if (stdout.trim()) { + results.push({ name: pkg, version: stdout.trim() }); + } + continue; + } + + if (pkg === 'whisper-cpp') { + const { stdout } = await execAsync('command -v whisper-cli 2>/dev/null', { timeout: 2000 }); + const path = stdout.trim(); + if (path) { + results.push({ name: pkg, version: `installed (${path})` }); + } + continue; + } + + // ollama on Linux/WSL may be a Windows-hosted daemon; prefer API version if reachable. + if (pkg === 'ollama') { + const ollamaUrl = process.env.OLLAMA_URL || process.env.OLLAMA_HOST || 'http://localhost:11434'; + const normalized = ollamaUrl.startsWith('http') ? ollamaUrl : `http://${ollamaUrl}`; + try { + const res = await fetch(`${normalized.replace(/\/+$/, '')}/api/version`, { + cache: 'no-store', + signal: AbortSignal.timeout(2500), + }); + if (res.ok) { + const data = (await res.json()) as { version?: string }; + if (data.version) { + results.push({ name: pkg, version: data.version }); + continue; + } + } + } catch { + // fall through to local binary check + } + + const { stdout } = await execAsync('command -v ollama 2>/dev/null', { timeout: 2000 }); + const path = stdout.trim(); + if (path) { + const { stdout: ver } = await execAsync('ollama --version 2>/dev/null | head -1', { + timeout: 2000, + }); + const v = ver.trim(); + results.push({ name: pkg, version: v || `installed (${path})` }); + } } } catch { - // not installed + // skip unavailable tool } } } @@ -204,6 +277,17 @@ async function getAccurateMemory(): Promise<{ const ratio = appMemory / total; const pressure = ratio > 0.85 ? 'critical' : ratio > 0.7 ? 'warning' : 'normal'; + if (IS_WSL) { + const winTotalRaw = await readWindowsCommand( + '[string](Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory' + ); + const winTotal = winTotalRaw ? Number.parseInt(winTotalRaw.replace(/\D/g, ''), 10) : 0; + if (Number.isFinite(winTotal) && winTotal > total) { + // Keep WSL usage metrics, but report host RAM capacity for Mission Control display. + return { total: winTotal, appMemory, cached, free, pressure }; + } + } + return { total, appMemory, cached, free, pressure }; } catch { // fall through to generic fallback @@ -240,7 +324,7 @@ export async function GET() { ollamaDiskUsage: ollamaDisk, cpuCores: cpuCount, uptime, - platform: `${os.type()} ${os.release()}`, + platform: IS_WSL ? 'Windows (via WSL2)' : `${os.type()} ${os.release()}`, arch: os.arch(), nodeVersion: process.version, brewPackages: staticInfo.brewPackages, diff --git a/__LOCAL_LLMs/dashboard/src/app/api/whisper/route.ts b/__LOCAL_LLMs/dashboard/src/app/api/whisper/route.ts index 81e92d7b..b5e6b17c 100644 --- a/__LOCAL_LLMs/dashboard/src/app/api/whisper/route.ts +++ b/__LOCAL_LLMs/dashboard/src/app/api/whisper/route.ts @@ -13,21 +13,23 @@ async function getWhisperBinaries(): Promise { try { if (IS_MAC) { const { stdout } = await execAsync('ls /opt/homebrew/bin/whisper-* 2>/dev/null'); - return stdout + const bins = stdout .trim() .split('\n') .filter(Boolean) .map(p => p.split('/').pop() || p); + return Array.from(new Set(bins)); } // Linux / WSL2 — check common locations const { stdout } = await execAsync( 'ls /usr/local/bin/whisper-* /usr/bin/whisper-* 2>/dev/null || which whisper-cli 2>/dev/null' ); - return stdout + const bins = stdout .trim() .split('\n') .filter(Boolean) .map(p => p.split('/').pop() || p); + return Array.from(new Set(bins)); } catch { return []; } @@ -70,8 +72,9 @@ async function getWhisperModels(): Promise<{ async function getWhisperVersion(): Promise { try { - const { stdout } = await execAsync('whisper-cli --version 2>&1 || echo "unknown"'); - return stdout.trim(); + const { stdout } = await execAsync('whisper-cli -h 2>&1 | head -1'); + const line = stdout.trim(); + return line || 'installed'; } catch { return 'unknown'; }