llm-checker
Version:
Intelligent CLI tool with AI-powered model selection that analyzes your hardware and recommends optimal LLM models for your system
351 lines (294 loc) • 12.2 kB
JavaScript
const si = require('systeminformation');
class HardwareDetector {
constructor() {
this.cache = null;
this.cacheExpiry = 5 * 60 * 1000;
this.cacheTime = 0;
}
async getSystemInfo() {
if (this.cache && (Date.now() - this.cacheTime < this.cacheExpiry)) {
return this.cache;
}
try {
const [cpu, memory, graphics, system, osInfo] = await Promise.all([
si.cpu(),
si.mem(),
si.graphics(),
si.system(),
si.osInfo()
]);
const systemInfo = {
cpu: this.processCPUInfo(cpu),
memory: this.processMemoryInfo(memory),
gpu: this.processGPUInfo(graphics),
system: this.processSystemInfo(system),
os: this.processOSInfo(osInfo),
timestamp: Date.now()
};
this.cache = systemInfo;
this.cacheTime = Date.now();
return systemInfo;
} catch (error) {
throw new Error(`Failed to detect hardware: ${error.message}`);
}
}
processCPUInfo(cpu) {
return {
brand: cpu.brand || 'Unknown',
manufacturer: cpu.manufacturer || 'Unknown',
family: cpu.family || 'Unknown',
model: cpu.model || 'Unknown',
speed: cpu.speed || 0,
speedMax: cpu.speedMax || cpu.speed || 0,
cores: cpu.cores || 1,
physicalCores: cpu.physicalCores || cpu.cores || 1,
processors: cpu.processors || 1,
cache: {
l1d: cpu.cache?.l1d || 0,
l1i: cpu.cache?.l1i || 0,
l2: cpu.cache?.l2 || 0,
l3: cpu.cache?.l3 || 0
},
architecture: this.detectArchitecture(cpu),
score: this.calculateCPUScore(cpu)
};
}
processMemoryInfo(memory) {
const totalGB = Math.round(memory.total / (1024 ** 3));
const freeGB = Math.round(memory.free / (1024 ** 3));
const usedGB = totalGB - freeGB;
return {
total: totalGB,
free: freeGB,
used: usedGB,
available: Math.round(memory.available / (1024 ** 3)),
usagePercent: Math.round((usedGB / totalGB) * 100),
swapTotal: Math.round(memory.swaptotal / (1024 ** 3)),
swapUsed: Math.round(memory.swapused / (1024 ** 3)),
score: this.calculateMemoryScore(totalGB, freeGB)
};
}
processGPUInfo(graphics) {
const controllers = graphics.controllers || [];
const displays = graphics.displays || [];
const dedicatedGPU = controllers.find(gpu => {
const model = (gpu.model || '').toLowerCase();
// Check for dedicated GPU indicators - improved detection for NVIDIA RTX cards
const isDedicated = !this.isIntegratedGPU(gpu.model) && (
gpu.vram > 0 || // Has dedicated VRAM
model.includes('rtx') || // NVIDIA RTX series
model.includes('gtx') || // NVIDIA GTX series
model.includes('radeon rx') || // AMD RX series
model.includes('tesla') || // NVIDIA Tesla
model.includes('quadro') // NVIDIA Quadro
);
return isDedicated;
});
const integratedGPU = controllers.find(gpu =>
this.isIntegratedGPU(gpu.model)
);
const primaryGPU = dedicatedGPU || integratedGPU || controllers[0];
if (!primaryGPU) {
return {
model: 'No GPU detected',
vendor: 'Unknown',
vram: 0,
dedicated: false,
score: 0
};
}
// Enhanced VRAM detection
let vram = primaryGPU.vram || 0;
// For Windows, sometimes VRAM is reported in bytes instead of MB
if (vram > 100000) {
vram = Math.round(vram / (1024 * 1024)); // Convert bytes to MB
}
// Convert MB to GB
vram = Math.round(vram / 1024);
// If VRAM is still 0, try to estimate based on model or handle unified memory
if (vram === 0 && primaryGPU.model) {
const modelLower = primaryGPU.model.toLowerCase();
if (modelLower.includes('apple') || modelLower.includes('unified')) {
// Apple Silicon uses unified memory - return 0 to indicate this
vram = 0;
} else {
vram = this.estimateVRAMFromModel(primaryGPU.model);
}
}
return {
model: primaryGPU.model || 'Unknown GPU',
vendor: primaryGPU.vendor || 'Unknown',
vram: vram,
vramDynamic: primaryGPU.vramDynamic || false,
dedicated: !this.isIntegratedGPU(primaryGPU.model),
driverVersion: primaryGPU.driverVersion || 'Unknown',
all: controllers.map(gpu => {
let gpuVram = gpu.vram || 0;
if (gpuVram > 100000) {
gpuVram = Math.round(gpuVram / (1024 * 1024));
}
return {
model: gpu.model,
vram: Math.round(gpuVram / 1024),
vendor: gpu.vendor
};
}),
displays: displays.length,
score: this.calculateGPUScore(primaryGPU)
};
}
processSystemInfo(system) {
return {
manufacturer: system.manufacturer || 'Unknown',
model: system.model || 'Unknown',
version: system.version || 'Unknown',
serial: system.serial || 'Unknown',
uuid: system.uuid || 'Unknown',
sku: system.sku || 'Unknown'
};
}
processOSInfo(osInfo) {
return {
platform: osInfo.platform || process.platform,
distro: osInfo.distro || 'Unknown',
release: osInfo.release || 'Unknown',
codename: osInfo.codename || 'Unknown',
kernel: osInfo.kernel || 'Unknown',
arch: osInfo.arch || process.arch,
hostname: osInfo.hostname || 'Unknown',
logofile: osInfo.logofile || ''
};
}
detectArchitecture(cpu) {
const brand = (cpu.brand || '').toLowerCase();
const model = (cpu.model || '').toLowerCase();
const manufacturer = (cpu.manufacturer || '').toLowerCase();
if (manufacturer.includes('apple') || brand.includes('apple') || brand.includes('m1') || brand.includes('m2') || brand.includes('m3') || brand.includes('m4')) {
return 'Apple Silicon';
} else if (brand.includes('intel')) {
return 'x86_64';
} else if (brand.includes('amd')) {
return 'x86_64';
} else if (process.arch === 'arm64') {
return 'ARM64';
} else {
return process.arch || 'Unknown';
}
}
isIntegratedGPU(model) {
if (!model) return false;
const modelLower = model.toLowerCase();
return modelLower.includes('intel') && !modelLower.includes('arc') ||
modelLower.includes('amd') && modelLower.includes('graphics') && !modelLower.includes(' rx ') ||
modelLower.includes('radeon') && modelLower.includes('graphics') ||
modelLower.includes('iris') ||
modelLower.includes('uhd') ||
modelLower.includes('hd graphics') ||
modelLower.includes('apple');
}
estimateVRAMFromModel(model) {
if (!model) return 0;
const modelLower = model.toLowerCase();
// NVIDIA RTX 40 series
if (modelLower.includes('rtx 4090')) return 24;
if (modelLower.includes('rtx 4080')) return 16;
if (modelLower.includes('rtx 4070 ti')) return 12;
if (modelLower.includes('rtx 4070')) return 12;
if (modelLower.includes('rtx 4060 ti')) return 16;
if (modelLower.includes('rtx 4060')) return 8;
// NVIDIA RTX 30 series
if (modelLower.includes('rtx 3090')) return 24;
if (modelLower.includes('rtx 3080 ti')) return 12;
if (modelLower.includes('rtx 3080')) return 10;
if (modelLower.includes('rtx 3070')) return 8;
if (modelLower.includes('rtx 3060 ti')) return 8;
if (modelLower.includes('rtx 3060')) return 12;
// AMD RX 7000 series
if (modelLower.includes('rx 7900')) return 24;
if (modelLower.includes('rx 7800')) return 16;
if (modelLower.includes('rx 7700')) return 12;
if (modelLower.includes('rx 7600')) return 8;
// Generic estimates
if (modelLower.includes('rtx')) return 8; // Default for RTX
if (modelLower.includes('gtx')) return 4; // Default for GTX
if (modelLower.includes('rx ')) return 8; // Default for AMD RX
return 0; // Unknown or integrated
}
calculateCPUScore(cpu) {
let score = 0;
// Base score por número de cores
score += (cpu.cores || 1) * 5;
score += (cpu.physicalCores || cpu.cores || 1) * 3;
// Score por velocidad
const speed = cpu.speedMax || cpu.speed || 0;
score += speed * 10;
// Bonus por arquitectura moderna
const brand = (cpu.brand || '').toLowerCase();
if (brand.includes('apple m')) {
score += 20; // Apple Silicon bonus
} else if (brand.includes('intel') && speed > 3.0) {
score += 15;
} else if (brand.includes('amd') && speed > 3.0) {
score += 15;
}
return Math.min(Math.round(score), 100);
}
calculateMemoryScore(totalGB, freeGB) {
let score = 0;
// Score basado en RAM total
if (totalGB >= 64) score += 40;
else if (totalGB >= 32) score += 35;
else if (totalGB >= 16) score += 25;
else if (totalGB >= 8) score += 15;
else score += totalGB * 2;
// Score basado en RAM disponible
const freePercent = (freeGB / totalGB) * 100;
if (freePercent > 50) score += 20;
else if (freePercent > 30) score += 15;
else if (freePercent > 20) score += 10;
else score += 5;
return Math.min(Math.round(score), 100);
}
calculateGPUScore(gpu) {
if (!gpu || !gpu.model) return 0;
let score = 0;
const model = gpu.model.toLowerCase();
const vram = gpu.vram || 0;
score += vram * 8;
if (!this.isIntegratedGPU(gpu.model)) {
score += 20;
}
// Bonus por marcas/modelos específicos
if (model.includes('rtx 4090')) score += 25;
else if (model.includes('rtx 4080')) score += 22;
else if (model.includes('rtx 4070')) score += 20;
else if (model.includes('rtx 30')) score += 18;
else if (model.includes('rtx 20')) score += 15;
else if (model.includes('gtx 16')) score += 12;
else if (model.includes('apple m')) score += 15;
return Math.min(Math.round(score), 100);
}
async runQuickBenchmark() {
const start = process.hrtime.bigint();
let cpuResult = 0;
for (let i = 0; i < 1000000; i++) {
cpuResult += Math.sqrt(i);
}
const end = process.hrtime.bigint();
const cpuTime = Number(end - start) / 1000000; // ms
const memStart = process.hrtime.bigint();
const largeArray = new Array(1000000).fill(0).map((_, i) => i);
largeArray.sort((a, b) => b - a);
const memEnd = process.hrtime.bigint();
const memTime = Number(memEnd - memStart) / 1000000;
return {
cpu: Math.max(0, Math.min(100, 100 - (cpuTime / 100))),
memory: Math.max(0, Math.min(100, 100 - (memTime / 50))),
overall: Math.round((
Math.max(0, Math.min(100, 100 - (cpuTime / 100))) +
Math.max(0, Math.min(100, 100 - (memTime / 50)))
) / 2)
};
}
}
module.exports = HardwareDetector;