Lumi/plugins/lumi_ai/backend/hardware.js
2026-06-11 06:35:43 +02:00

48 lines
2.0 KiB
JavaScript

const os = require("os");
const fs = require("fs");
const { spawnSync } = require("child_process");
const { PLUGIN_DATA, PLUGIN_ROOT } = require("./paths");
function detectHardware(models) {
const freeDisk = getFreeDisk();
const totalRamMb = Math.floor(os.totalmem() / 1048576);
const availableRamMb = Math.floor(os.freemem() / 1048576);
const gpu = detectGpu();
const writable = testWritable();
const recommendation = [...models]
.filter((model) => model.ram_gb * 1024 <= totalRamMb && model.size / 1048576 <= freeDisk)
.sort((a, b) => b.ram_gb - a.ram_gb)[0]?.tier || "tiny";
return {
platform: os.platform(), architecture: os.arch(), cpu_threads: os.cpus().length,
total_ram_mb: totalRamMb, available_ram_mb: availableRamMb, free_disk_mb: freeDisk,
gpu, subprocess_allowed: true, plugin_writable: writable, recommended_tier: recommendation,
plugin_path: PLUGIN_ROOT, path_length: PLUGIN_ROOT.length,
long_path_warning: os.platform()==="win32" && PLUGIN_ROOT.length > 220,
network_path_warning: os.platform()==="win32" && PLUGIN_ROOT.startsWith("\\\\")
};
}
function getFreeDisk() {
try {
if (typeof fs.statfsSync === "function") {
const stat = fs.statfsSync(PLUGIN_DATA);
return Math.floor((Number(stat.bavail) * Number(stat.bsize)) / 1048576);
}
} catch {}
return 0;
}
function detectGpu() {
try {
const result = spawnSync("nvidia-smi", ["--query-gpu=name,memory.total", "--format=csv,noheader,nounits"], { encoding: "utf8", timeout: 3000 });
if (result.status === 0 && result.stdout.trim()) {
const [name, vram] = result.stdout.trim().split(",").map((v) => v.trim());
return { present: true, name, vram_mb: Number(vram) || null };
}
} catch {}
return { present: false, name: null, vram_mb: null };
}
function testWritable() {
try { const file = require("path").join(PLUGIN_DATA, ".write-test"); fs.writeFileSync(file, "ok"); fs.unlinkSync(file); return true; }
catch { return false; }
}
module.exports = { detectHardware };