llm-checker 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -0
  3. package/analyzer/compatibility.js +584 -0
  4. package/analyzer/performance.js +505 -0
  5. package/bin/CLAUDE.md +12 -0
  6. package/bin/enhanced_cli.js +3118 -0
  7. package/bin/test-deterministic.js +41 -0
  8. package/package.json +96 -0
  9. package/src/CLAUDE.md +12 -0
  10. package/src/ai/intelligent-selector.js +615 -0
  11. package/src/ai/model-selector.js +312 -0
  12. package/src/ai/multi-objective-selector.js +820 -0
  13. package/src/commands/check.js +58 -0
  14. package/src/data/CLAUDE.md +11 -0
  15. package/src/data/model-database.js +637 -0
  16. package/src/data/sync-manager.js +279 -0
  17. package/src/hardware/CLAUDE.md +12 -0
  18. package/src/hardware/backends/CLAUDE.md +11 -0
  19. package/src/hardware/backends/apple-silicon.js +318 -0
  20. package/src/hardware/backends/cpu-detector.js +490 -0
  21. package/src/hardware/backends/cuda-detector.js +417 -0
  22. package/src/hardware/backends/intel-detector.js +436 -0
  23. package/src/hardware/backends/rocm-detector.js +440 -0
  24. package/src/hardware/detector.js +573 -0
  25. package/src/hardware/pc-optimizer.js +635 -0
  26. package/src/hardware/specs.js +286 -0
  27. package/src/hardware/unified-detector.js +442 -0
  28. package/src/index.js +2289 -0
  29. package/src/models/CLAUDE.md +17 -0
  30. package/src/models/ai-check-selector.js +806 -0
  31. package/src/models/catalog.json +426 -0
  32. package/src/models/deterministic-selector.js +1145 -0
  33. package/src/models/expanded_database.js +1142 -0
  34. package/src/models/intelligent-selector.js +532 -0
  35. package/src/models/requirements.js +310 -0
  36. package/src/models/scoring-config.js +57 -0
  37. package/src/models/scoring-engine.js +715 -0
  38. package/src/ollama/.cache/README.md +33 -0
  39. package/src/ollama/CLAUDE.md +24 -0
  40. package/src/ollama/client.js +438 -0
  41. package/src/ollama/enhanced-client.js +113 -0
  42. package/src/ollama/enhanced-scraper.js +634 -0
  43. package/src/ollama/manager.js +357 -0
  44. package/src/ollama/native-scraper.js +776 -0
  45. package/src/plugins/CLAUDE.md +11 -0
  46. package/src/plugins/examples/custom_model_plugin.js +87 -0
  47. package/src/plugins/index.js +295 -0
  48. package/src/utils/CLAUDE.md +11 -0
  49. package/src/utils/config.js +359 -0
  50. package/src/utils/formatter.js +315 -0
  51. package/src/utils/logger.js +272 -0
  52. package/src/utils/model-classifier.js +167 -0
  53. package/src/utils/verbose-progress.js +266 -0
@@ -0,0 +1,584 @@
1
+ const { getLogger } = require('../src/utils/logger');
2
+
3
+ class CompatibilityAnalyzer {
4
+ constructor() {
5
+ this.compatibilityThresholds = {
6
+ excellent: 90,
7
+ good: 75,
8
+ marginal: 60,
9
+ poor: 40,
10
+ incompatible: 0
11
+ };
12
+
13
+ this.logger = getLogger().createChild('CompatibilityAnalyzer');
14
+
15
+ this.ollamaOptimizations = {
16
+ quantizationBonuses: {
17
+ 'Q2_K': 0.4,
18
+ 'Q3_K_M': 0.5,
19
+ 'Q4_0': 0.6,
20
+ 'Q4_K_M': 0.7,
21
+ 'Q5_0': 0.8,
22
+ 'Q5_K_M': 0.85,
23
+ 'Q6_K': 0.9,
24
+ 'Q8_0': 0.95
25
+ },
26
+ hardwareOptimizations: {
27
+ 'Apple Silicon': {
28
+ metalBonus: 1.15,
29
+ unifiedMemoryBonus: 1.1
30
+ },
31
+ 'x86_64': {
32
+ avxBonus: 1.05,
33
+ vectorBonus: 1.02
34
+ }
35
+ }
36
+ };
37
+ }
38
+
39
+ analyzeCompatibility(hardware, models, options = {}) {
40
+ this.logger.info('Starting compatibility analysis', {
41
+ data: {
42
+ modelCount: models.length,
43
+ hardwareTier: this.getHardwareTier(hardware),
44
+ includeOllama: options.includeOllamaOptimizations !== false
45
+ }
46
+ });
47
+
48
+ const results = {
49
+ compatible: [],
50
+ marginal: [],
51
+ incompatible: [],
52
+ recommendations: []
53
+ };
54
+
55
+ models.forEach(model => {
56
+ const compatibility = this.calculateModelCompatibility(hardware, model, options);
57
+ const enrichedModel = {
58
+ ...model,
59
+ score: compatibility.score,
60
+ issues: compatibility.issues,
61
+ notes: compatibility.notes,
62
+ recommendations: compatibility.modelSpecificRecommendations
63
+ };
64
+
65
+ if (compatibility.score >= this.compatibilityThresholds.good) {
66
+ results.compatible.push(enrichedModel);
67
+ } else if (compatibility.score >= this.compatibilityThresholds.marginal) {
68
+ results.marginal.push(enrichedModel);
69
+ } else {
70
+ results.incompatible.push(enrichedModel);
71
+ }
72
+
73
+ this.logger.debug(`Model compatibility: ${model.name} - Score: ${compatibility.score}`);
74
+ });
75
+
76
+ results.compatible.sort((a, b) => b.score - a.score);
77
+ results.marginal.sort((a, b) => b.score - a.score);
78
+ results.incompatible.sort((a, b) => b.score - a.score);
79
+
80
+ results.recommendations = this.generateRecommendations(hardware, results, options);
81
+
82
+ this.logger.info('Compatibility analysis completed', {
83
+ data: {
84
+ compatible: results.compatible.length,
85
+ marginal: results.marginal.length,
86
+ incompatible: results.incompatible.length
87
+ }
88
+ });
89
+
90
+ return results;
91
+ }
92
+
93
+ calculateModelCompatibility(hardware, model, options = {}) {
94
+ if (model.type === 'cloud') {
95
+ return {
96
+ score: 100,
97
+ issues: [],
98
+ notes: ['Requires internet connection and API key'],
99
+ modelSpecificRecommendations: ['Ensure stable internet connection', 'Configure API key']
100
+ };
101
+ }
102
+
103
+ let score = 100;
104
+ const issues = [];
105
+ const notes = [];
106
+ const modelSpecificRecommendations = [];
107
+
108
+ const ramAnalysis = this.analyzeRAMCompatibility(hardware.memory, model.requirements);
109
+ score *= ramAnalysis.factor;
110
+ issues.push(...ramAnalysis.issues);
111
+ notes.push(...ramAnalysis.notes);
112
+
113
+ const gpuAnalysis = this.analyzeGPUCompatibility(hardware.gpu, model.requirements);
114
+ score *= gpuAnalysis.factor;
115
+ issues.push(...gpuAnalysis.issues);
116
+ notes.push(...gpuAnalysis.notes);
117
+
118
+ const cpuAnalysis = this.analyzeCPUCompatibility(hardware.cpu, model.requirements);
119
+ score *= cpuAnalysis.factor;
120
+ issues.push(...cpuAnalysis.issues);
121
+ notes.push(...cpuAnalysis.notes);
122
+
123
+ const archAnalysis = this.analyzeArchitectureOptimizations(hardware, model);
124
+ score *= archAnalysis.factor;
125
+ notes.push(...archAnalysis.notes);
126
+
127
+ const quantAnalysis = this.analyzeQuantizationOptions(model, hardware);
128
+ score *= quantAnalysis.factor;
129
+ notes.push(...quantAnalysis.notes);
130
+ modelSpecificRecommendations.push(...quantAnalysis.recommendations);
131
+
132
+ if (options.includeOllamaOptimizations !== false && model.frameworks?.includes('ollama')) {
133
+ const ollamaAnalysis = this.analyzeOllamaOptimizations(hardware, model);
134
+ score *= ollamaAnalysis.factor;
135
+ notes.push(...ollamaAnalysis.notes);
136
+ modelSpecificRecommendations.push(...ollamaAnalysis.recommendations);
137
+ }
138
+
139
+ const edgeAnalysis = this.analyzeEdgeCases(hardware, model);
140
+ score *= edgeAnalysis.factor;
141
+ if (edgeAnalysis.warning) {
142
+ issues.push(edgeAnalysis.warning);
143
+ }
144
+
145
+ // NEW: Penalize models that underutilize high-end hardware
146
+ const sizeMatchAnalysis = this.analyzeHardwareSizeMatch(hardware, model);
147
+ score *= sizeMatchAnalysis.factor;
148
+ notes.push(...sizeMatchAnalysis.notes);
149
+
150
+ return {
151
+ score: Math.round(Math.max(0, Math.min(100, score))),
152
+ issues: issues.filter(Boolean),
153
+ notes: notes.filter(Boolean),
154
+ modelSpecificRecommendations: modelSpecificRecommendations.filter(Boolean)
155
+ };
156
+ }
157
+
158
+ analyzeRAMCompatibility(memory, requirements) {
159
+ const analysis = { factor: 1.0, issues: [], notes: [] };
160
+ const totalRAM = memory.total;
161
+ const availableRAM = memory.free; // Solo para mostrar info, no para lógica
162
+ const requiredRAM = requirements.ram;
163
+ const recommendedRAM = requirements.recommended_ram || requiredRAM * 1.5;
164
+
165
+ if (totalRAM < requiredRAM) {
166
+ analysis.factor = 0.1;
167
+ analysis.issues.push(`Critical: ${totalRAM}GB total RAM < ${requiredRAM}GB required`);
168
+ } else if (totalRAM < recommendedRAM) {
169
+ analysis.factor = 0.75;
170
+ analysis.notes.push(`Consider upgrading to ${recommendedRAM}GB for optimal performance`);
171
+ } else {
172
+ analysis.factor = 1.0;
173
+ analysis.notes.push('✅ RAM requirements fully satisfied');
174
+
175
+
176
+ if (totalRAM >= recommendedRAM * 2) {
177
+ analysis.factor = 1.05;
178
+ analysis.notes.push('Abundant RAM allows multiple models simultaneously');
179
+ }
180
+ }
181
+
182
+ // Informational note about current memory usage (not affecting compatibility score)
183
+ if (totalRAM >= requiredRAM && availableRAM < requiredRAM) {
184
+ analysis.notes.push(`Info: Currently ${availableRAM}GB free RAM - you may need to close other applications before running this model`);
185
+ }
186
+
187
+ return analysis;
188
+ }
189
+
190
+ analyzeGPUCompatibility(gpu, requirements) {
191
+ const analysis = { factor: 1.0, issues: [], notes: [] };
192
+ const availableVRAM = gpu.vram || 0;
193
+ const requiredVRAM = requirements.vram || 0;
194
+
195
+ if (requiredVRAM === 0) {
196
+ analysis.notes.push('Model runs on CPU - GPU not required');
197
+ return analysis;
198
+ }
199
+
200
+ if (!gpu.dedicated && requiredVRAM > 0) {
201
+ analysis.factor = 0.6;
202
+ analysis.notes.push('⚠️ Integrated GPU - consider CPU-only mode');
203
+ }
204
+
205
+ if (availableVRAM < requiredVRAM) {
206
+ if (requiredVRAM <= 4) {
207
+ analysis.factor = 0.3;
208
+ analysis.issues.push(`Low VRAM: ${availableVRAM}GB < ${requiredVRAM}GB required`);
209
+ analysis.notes.push('💡 Model will fallback to CPU (slower)');
210
+ } else {
211
+ analysis.factor = 0.1;
212
+ analysis.issues.push(`Critical VRAM shortage: ${availableVRAM}GB << ${requiredVRAM}GB`);
213
+ analysis.notes.push('🔧 Use heavy quantization or CPU-only mode');
214
+ }
215
+ } else {
216
+ analysis.factor = 1.0;
217
+ analysis.notes.push('✅ VRAM requirements satisfied');
218
+
219
+ if (availableVRAM >= requiredVRAM * 2) {
220
+ analysis.factor = 1.1;
221
+ analysis.notes.push('🎮 Excellent VRAM headroom for acceleration');
222
+ }
223
+ }
224
+
225
+ if (gpu.vendor === 'NVIDIA' && gpu.dedicated) {
226
+ analysis.factor *= 1.05;
227
+ analysis.notes.push('🟢 NVIDIA GPU - excellent CUDA support');
228
+ } else if (gpu.vendor === 'AMD' && gpu.dedicated) {
229
+ analysis.factor *= 1.02;
230
+ analysis.notes.push('🔴 AMD GPU - ROCm support available');
231
+ }
232
+
233
+ return analysis;
234
+ }
235
+
236
+ analyzeCPUCompatibility(cpu, requirements) {
237
+ const analysis = { factor: 1.0, issues: [], notes: [] };
238
+ const cores = cpu.cores;
239
+ const requiredCores = requirements.cpu_cores || 4;
240
+ const cpuSpeed = cpu.speedMax || cpu.speed || 2.0;
241
+
242
+ if (cores < requiredCores) {
243
+ analysis.factor = Math.max(0.5, cores / requiredCores);
244
+ analysis.issues.push(`Limited cores: ${cores} available, ${requiredCores} recommended`);
245
+ } else if (cores >= requiredCores * 2) {
246
+ analysis.factor = 1.05;
247
+ analysis.notes.push('Abundant CPU cores for parallel processing');
248
+ }
249
+
250
+ if (cpuSpeed >= 3.5) {
251
+ analysis.factor *= 1.1;
252
+ analysis.notes.push('High CPU speed boosts inference performance');
253
+ } else if (cpuSpeed < 2.0) {
254
+ analysis.factor *= 0.85;
255
+ analysis.notes.push('⚠️ Low CPU speed may impact performance');
256
+ }
257
+
258
+ if (cpu.score) {
259
+ if (cpu.score >= 80) {
260
+ analysis.factor *= 1.05;
261
+ analysis.notes.push('💪 High-performance CPU detected');
262
+ } else if (cpu.score < 40) {
263
+ analysis.factor *= 0.9;
264
+ analysis.notes.push('🐌 CPU performance may be limiting factor');
265
+ }
266
+ }
267
+
268
+ return analysis;
269
+ }
270
+
271
+ analyzeArchitectureOptimizations(hardware, model) {
272
+ const analysis = { factor: 1.0, notes: [] };
273
+ const arch = hardware.cpu.architecture;
274
+
275
+ switch (arch) {
276
+ case 'Apple Silicon':
277
+ if (model.frameworks?.includes('llama.cpp')) {
278
+ analysis.factor = this.ollamaOptimizations.hardwareOptimizations['Apple Silicon'].metalBonus;
279
+ analysis.notes.push('Apple Silicon with Metal acceleration');
280
+ }
281
+
282
+ if (model.requirements?.vram === 0) {
283
+ analysis.factor *= this.ollamaOptimizations.hardwareOptimizations['Apple Silicon'].unifiedMemoryBonus;
284
+ analysis.notes.push('🔄 Unified memory architecture advantage');
285
+ }
286
+ break;
287
+
288
+ case 'x86_64':
289
+ if (hardware.cpu.features?.includes('AVX2')) {
290
+ analysis.factor = this.ollamaOptimizations.hardwareOptimizations['x86_64'].avxBonus;
291
+ analysis.notes.push('🏃‍♂️ AVX2 vector optimizations available');
292
+ }
293
+ break;
294
+
295
+ case 'ARM64':
296
+ analysis.factor = 0.95;
297
+ analysis.notes.push('🔧 ARM64 - good efficiency, some optimizations available');
298
+ break;
299
+
300
+ default:
301
+ analysis.notes.push('❓ Unknown architecture - performance may vary');
302
+ }
303
+
304
+ return analysis;
305
+ }
306
+
307
+ analyzeQuantizationOptions(model, hardware) {
308
+ const analysis = { factor: 1.0, notes: [], recommendations: [] };
309
+
310
+ if (!model.quantization || model.quantization.length === 0) {
311
+ return analysis;
312
+ }
313
+
314
+ const totalRAM = hardware.memory.total;
315
+ const vram = hardware.gpu.vram || 0;
316
+
317
+ let recommendedQuant = null;
318
+ let quantBonus = 1.0;
319
+
320
+ if (totalRAM >= 32 && vram >= 16) {
321
+ if (model.quantization.includes('Q8_0')) {
322
+ recommendedQuant = 'Q8_0';
323
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q8_0'];
324
+ analysis.recommendations.push('Use Q8_0 for highest quality');
325
+ } else if (model.quantization.includes('Q6_K')) {
326
+ recommendedQuant = 'Q6_K';
327
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q6_K'];
328
+ analysis.recommendations.push('Use Q6_K for excellent quality');
329
+ }
330
+ } else if (totalRAM >= 16 && vram >= 8) {
331
+ if (model.quantization.includes('Q5_K_M')) {
332
+ recommendedQuant = 'Q5_K_M';
333
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q5_K_M'];
334
+ analysis.recommendations.push('Use Q5_K_M for good quality balance');
335
+ } else if (model.quantization.includes('Q4_K_M')) {
336
+ recommendedQuant = 'Q4_K_M';
337
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q4_K_M'];
338
+ analysis.recommendations.push('Use Q4_K_M for balanced performance');
339
+ }
340
+ } else if (totalRAM >= 8) {
341
+ if (model.quantization.includes('Q4_0')) {
342
+ recommendedQuant = 'Q4_0';
343
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q4_0'];
344
+ analysis.recommendations.push('Use Q4_0 for your hardware tier');
345
+ } else if (model.quantization.includes('Q3_K_M')) {
346
+ recommendedQuant = 'Q3_K_M';
347
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q3_K_M'];
348
+ analysis.recommendations.push('Use Q3_K_M to reduce memory usage');
349
+ }
350
+ } else {
351
+ if (model.quantization.includes('Q2_K')) {
352
+ recommendedQuant = 'Q2_K';
353
+ quantBonus = this.ollamaOptimizations.quantizationBonuses['Q2_K'];
354
+ analysis.recommendations.push('Use Q2_K for minimal memory usage');
355
+ }
356
+ }
357
+
358
+ if (recommendedQuant) {
359
+ analysis.factor = quantBonus;
360
+ analysis.notes.push(`Recommended quantization: ${recommendedQuant}`);
361
+ } else {
362
+ analysis.notes.push('⚠️ Limited quantization options for your hardware');
363
+ }
364
+
365
+ return analysis;
366
+ }
367
+
368
+ analyzeOllamaOptimizations(hardware, model) {
369
+ const analysis = { factor: 1.0, notes: [], recommendations: [] };
370
+
371
+ if (!model.frameworks?.includes('ollama')) {
372
+ return analysis;
373
+ }
374
+
375
+ analysis.factor = 1.05;
376
+ analysis.notes.push('Native Ollama support');
377
+
378
+ if (model.name.includes('Llama')) {
379
+ analysis.factor *= 1.02;
380
+ analysis.notes.push('Llama models are well-optimized in Ollama');
381
+ }
382
+
383
+ if (model.name.includes('Mistral')) {
384
+ analysis.factor *= 1.02;
385
+ analysis.notes.push('Mistral models have excellent Ollama integration');
386
+ }
387
+
388
+ if (hardware.gpu.dedicated && hardware.gpu.vram >= 8) {
389
+ analysis.recommendations.push('Enable GPU acceleration in Ollama');
390
+ }
391
+
392
+ if (hardware.cpu.architecture === 'Apple Silicon') {
393
+ analysis.recommendations.push('Ollama will use Metal acceleration automatically');
394
+ }
395
+
396
+ analysis.recommendations.push('Use ollama run for interactive sessions');
397
+ analysis.recommendations.push('Monitor with ollama ps for resource usage');
398
+
399
+ return analysis;
400
+ }
401
+
402
+ analyzeEdgeCases(hardware, model) {
403
+ const analysis = { factor: 1.0, warning: null };
404
+
405
+ const modelSizeGB = this.parseModelSize(model.size);
406
+ if (modelSizeGB > hardware.memory.total * 0.8) {
407
+ analysis.factor = 0.2;
408
+ analysis.warning = `Model size (${modelSizeGB}GB) near total RAM limit`;
409
+ }
410
+
411
+ if (hardware.cpu.year && hardware.cpu.year < 2015) {
412
+ analysis.factor *= 0.8;
413
+ analysis.warning = 'Very old CPU may have compatibility issues';
414
+ }
415
+
416
+ if (hardware.memory.usagePercent > 90) {
417
+ analysis.factor *= 0.6;
418
+ analysis.warning = 'Very high memory usage - close applications first';
419
+ }
420
+
421
+ return analysis;
422
+ }
423
+
424
+ parseModelSize(sizeString) {
425
+ const match = sizeString.match(/(\d+\.?\d*)[BM]/i);
426
+ if (!match) return 1;
427
+
428
+ const num = parseFloat(match[1]);
429
+ const unit = match[0].slice(-1).toUpperCase();
430
+
431
+ return unit === 'B' ? num : num / 1000;
432
+ }
433
+
434
+ getHardwareTier(hardware) {
435
+ // Special handling for Apple Silicon with unified memory
436
+ if (hardware.cpu.architecture === 'Apple Silicon' && hardware.gpu.model && hardware.gpu.model.toLowerCase().includes('apple')) {
437
+ if (hardware.memory.total >= 64) return 'ultra_high';
438
+ if (hardware.memory.total >= 32) return 'high';
439
+ if (hardware.memory.total >= 16) return 'medium';
440
+ if (hardware.memory.total >= 8) return 'low';
441
+ return 'ultra_low';
442
+ }
443
+
444
+ // Traditional dedicated VRAM-based classification
445
+ if (hardware.memory.total >= 64 && hardware.gpu.vram >= 32) return 'ultra_high';
446
+ if (hardware.memory.total >= 32 && hardware.gpu.vram >= 16) return 'high';
447
+ if (hardware.memory.total >= 16 && hardware.gpu.vram >= 8) return 'medium';
448
+ if (hardware.memory.total >= 8) return 'low';
449
+ return 'ultra_low';
450
+ }
451
+
452
+ generateRecommendations(hardware, results, options = {}) {
453
+ const recommendations = [];
454
+ const tier = this.getHardwareTier(hardware);
455
+
456
+ if (hardware.memory.total < 16) {
457
+ recommendations.push('💾 Upgrade to 16GB+ RAM for better compatibility');
458
+ }
459
+
460
+ if (!hardware.gpu.dedicated && hardware.memory.total >= 16) {
461
+ recommendations.push('🎮 Consider dedicated GPU for significant speedup');
462
+ }
463
+
464
+ if (results.compatible.length === 0) {
465
+ recommendations.push('🔧 No compatible models - try ultra-small models like TinyLlama');
466
+ recommendations.push('☁️ Consider cloud-based models for complex tasks');
467
+ } else if (results.compatible.length < 3) {
468
+ recommendations.push('📈 Limited options - hardware upgrade recommended');
469
+ }
470
+
471
+ switch (tier) {
472
+ case 'ultra_low':
473
+ recommendations.push('🐣 Focus on ultra-small models (0.5B-1B parameters)');
474
+ recommendations.push('🔧 Use Q2_K quantization for minimum memory usage');
475
+ break;
476
+
477
+ case 'low':
478
+ recommendations.push('Small models (1B-3B) work well on your system');
479
+ recommendations.push('Use Q4_0 quantization for good balance');
480
+ break;
481
+
482
+ case 'medium':
483
+ recommendations.push('Medium models (3B-8B) are ideal for your hardware');
484
+ recommendations.push('Use Q5_K_M for high quality');
485
+ break;
486
+
487
+ case 'high':
488
+ recommendations.push('Large models (8B-30B) run excellently');
489
+ recommendations.push('Use Q6_K or Q8_0 for maximum quality');
490
+ break;
491
+
492
+ case 'ultra_high':
493
+ recommendations.push('Any model size supported - try the largest available');
494
+ recommendations.push('Consider running multiple models simultaneously');
495
+ break;
496
+ }
497
+
498
+ if (options.includeOllamaOptimizations !== false) {
499
+ recommendations.push('Install Ollama for easy model management');
500
+
501
+ if (hardware.cpu.architecture === 'Apple Silicon') {
502
+ recommendations.push('Ollama will use Metal acceleration automatically');
503
+ }
504
+
505
+ if (results.compatible.length > 0) {
506
+ const topModel = results.compatible[0];
507
+ const ollamaCmd = this.getOllamaCommand(topModel.name);
508
+ if (ollamaCmd) {
509
+ recommendations.push(`Try: ${ollamaCmd}`);
510
+ }
511
+ }
512
+ }
513
+
514
+ return recommendations;
515
+ }
516
+
517
+ getOllamaCommand(modelName) {
518
+ const mapping = {
519
+ 'TinyLlama 1.1B': 'ollama pull tinyllama:1.1b',
520
+ 'Qwen 0.5B': 'ollama pull qwen:0.5b',
521
+ 'Gemma 2B': 'ollama pull gemma2:2b',
522
+ 'Phi-3 Mini 3.8B': 'ollama pull phi3:mini',
523
+ 'Llama 3.2 3B': 'ollama pull llama3.2:3b',
524
+ 'Llama 3.1 8B': 'ollama pull llama3.1:8b',
525
+ 'Mistral 7B v0.3': 'ollama pull mistral:7b',
526
+ 'CodeLlama 7B': 'ollama pull codellama:7b',
527
+ 'Qwen 2.5 7B': 'ollama pull qwen2.5:7b'
528
+ };
529
+
530
+ return mapping[modelName] || null;
531
+ }
532
+
533
+ analyzeHardwareSizeMatch(hardware, model) {
534
+ const analysis = { factor: 1.0, notes: [] };
535
+
536
+ // Get hardware tier and model size
537
+ const hardwareTier = this.getHardwareTier(hardware);
538
+ const totalRAM = hardware.memory.total;
539
+ const modelSizeGB = this.parseModelSize(model.size);
540
+
541
+ // Define optimal model sizes for each hardware tier
542
+ const optimalSizes = {
543
+ 'ultra_high': { min: 13, max: 70, sweet: 20 }, // 64+ GB: 13B-70B models
544
+ 'high': { min: 7, max: 30, sweet: 13 }, // 16-32 GB: 7B-30B models
545
+ 'medium': { min: 3, max: 13, sweet: 7 }, // 8-16 GB: 3B-13B models
546
+ 'low': { min: 1, max: 7, sweet: 3 }, // 4-8 GB: 1B-7B models
547
+ 'ultra_low': { min: 0.1, max: 3, sweet: 1 } // <4 GB: <3B models
548
+ };
549
+
550
+ const optimal = optimalSizes[hardwareTier] || optimalSizes['medium'];
551
+
552
+ // Calculate penalty/bonus based on model size vs optimal range
553
+ if (modelSizeGB < optimal.min) {
554
+ // Model too small for hardware - penalize significantly
555
+ const underutilization = optimal.min / modelSizeGB;
556
+ if (underutilization >= 10) {
557
+ analysis.factor = 0.3; // Major penalty for extreme underutilization
558
+ analysis.notes.push(`Model (${model.size}) significantly underutilizes your ${hardwareTier.replace('_', ' ')} hardware`);
559
+ } else if (underutilization >= 5) {
560
+ analysis.factor = 0.5; // Moderate penalty
561
+ analysis.notes.push(`Model (${model.size}) underutilizes your hardware - consider larger models`);
562
+ } else {
563
+ analysis.factor = 0.7; // Small penalty
564
+ analysis.notes.push(`Model smaller than optimal for your ${totalRAM}GB system`);
565
+ }
566
+ } else if (modelSizeGB > optimal.max) {
567
+ // Model too large for hardware - already handled by RAM analysis
568
+ analysis.factor = 1.0; // No additional penalty (RAM analysis covers this)
569
+ } else {
570
+ // Model in good range - give bonus for sweet spot
571
+ const distanceFromSweet = Math.abs(modelSizeGB - optimal.sweet) / optimal.sweet;
572
+ if (distanceFromSweet <= 0.3) {
573
+ analysis.factor = 1.1; // 10% bonus for sweet spot
574
+ analysis.notes.push(`Excellent size match for your ${hardwareTier.replace('_', ' ')} hardware`);
575
+ } else {
576
+ analysis.factor = 1.0; // No penalty, good range
577
+ }
578
+ }
579
+
580
+ return analysis;
581
+ }
582
+ }
583
+
584
+ module.exports = CompatibilityAnalyzer;