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,312 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+ const IntelligentModelSelector = require('./intelligent-selector');
4
+
5
+ class AIModelSelector {
6
+ constructor() {
7
+ this.aiSelectorPath = path.join(__dirname, '../../ml-model/js');
8
+ this.isAvailable = this.checkAvailability();
9
+ this.intelligentSelector = new IntelligentModelSelector();
10
+ }
11
+
12
+ checkAvailability() {
13
+ try {
14
+ const indexPath = path.join(this.aiSelectorPath, 'index.js');
15
+ return fs.existsSync(indexPath);
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ async initialize() {
22
+ if (!this.isAvailable) {
23
+ throw new Error('AI Model Selector not available. Please train the model first.');
24
+ }
25
+
26
+ try {
27
+ const AISelector = require(path.join(this.aiSelectorPath, 'index.js'));
28
+ this.selector = new AISelector();
29
+ await this.selector.initialize();
30
+ return true;
31
+ } catch (error) {
32
+ throw new Error(`Failed to initialize AI selector: ${error.message}`);
33
+ }
34
+ }
35
+
36
+ async selectBestModel(candidateModels, systemSpecs = null, userPreference = 'general') {
37
+ try {
38
+ // Para ai-run: usar TODOS los modelos de la base de datos para encontrar el mejor
39
+ // y luego verificar si está instalado localmente
40
+ console.log('🔍 Using comprehensive model database for selection...');
41
+
42
+ // Obtener todos los modelos de la base de datos de Ollama
43
+ const { OllamaNativeScraper } = require('../ollama/native-scraper');
44
+ const scraper = new OllamaNativeScraper();
45
+ const allModelData = await scraper.scrapeAllModels(false);
46
+ const allAvailableModels = allModelData.models || [];
47
+
48
+ console.log(`Evaluating against ${allAvailableModels.length} models from database`);
49
+
50
+ // Usar el selector inteligente con TODOS los modelos disponibles
51
+ const result = this.intelligentSelector.selectBestModels(
52
+ systemSpecs,
53
+ allAvailableModels.map(m => m.model_identifier), // Solo los identificadores
54
+ userPreference,
55
+ Math.min(10, allAvailableModels.length) // Más opciones para evaluar
56
+ );
57
+
58
+ if (result.best_model) {
59
+ // Verificar si el modelo recomendado está instalado localmente
60
+ const recommendedId = result.best_model.modelId;
61
+ const isLocallyInstalled = candidateModels.some(local =>
62
+ local.toLowerCase().includes(recommendedId.toLowerCase()) ||
63
+ recommendedId.toLowerCase().includes(local.toLowerCase())
64
+ );
65
+
66
+ let finalModel = recommendedId;
67
+ let confidence = result.best_model.confidence;
68
+ let reason = result.best_model.reasoning;
69
+
70
+ if (!isLocallyInstalled) {
71
+ console.log(`Best model ${recommendedId} not installed locally`);
72
+
73
+ // Buscar el mejor modelo entre los instalados localmente
74
+ const localResult = this.intelligentSelector.selectBestModels(
75
+ systemSpecs,
76
+ candidateModels,
77
+ userPreference,
78
+ candidateModels.length
79
+ );
80
+
81
+ if (localResult.best_model) {
82
+ finalModel = localResult.best_model.modelId;
83
+ confidence = localResult.best_model.confidence * 0.9; // Reducir confianza
84
+ reason = `${localResult.best_model.reasoning} (Locally installed alternative to recommended ${recommendedId})`;
85
+
86
+ console.log(`🔄 Using best local alternative: ${finalModel}`);
87
+ }
88
+ }
89
+
90
+ return {
91
+ bestModel: finalModel,
92
+ confidence: confidence,
93
+ score: result.best_model.score,
94
+ reasoning: reason,
95
+ recommendedFromDatabase: recommendedId,
96
+ isRecommendedInstalled: isLocallyInstalled,
97
+ allPredictions: result.recommendations.map(r => ({
98
+ model: r.modelId,
99
+ score: r.confidence,
100
+ reasoning: r.reasoning,
101
+ isInstalled: candidateModels.some(local =>
102
+ local.toLowerCase().includes(r.modelId.toLowerCase()) ||
103
+ r.modelId.toLowerCase().includes(local.toLowerCase())
104
+ )
105
+ })),
106
+ method: 'intelligent_database_comprehensive',
107
+ systemSpecs: systemSpecs,
108
+ hardware_analysis: result.hardware_analysis,
109
+ totalModelsEvaluated: allAvailableModels.length,
110
+ localModelsCount: candidateModels.length
111
+ };
112
+ }
113
+ } catch (error) {
114
+ console.warn(`Comprehensive database selection failed: ${error.message}`);
115
+
116
+ // Fallback al método anterior con solo modelos locales
117
+ try {
118
+ const result = this.intelligentSelector.selectBestModels(
119
+ systemSpecs,
120
+ candidateModels,
121
+ userPreference,
122
+ Math.min(5, candidateModels.length)
123
+ );
124
+
125
+ if (result.best_model) {
126
+ return {
127
+ bestModel: result.best_model.modelId,
128
+ confidence: result.best_model.confidence,
129
+ score: result.best_model.score,
130
+ reasoning: result.best_model.reasoning + " (Local models only)",
131
+ allPredictions: result.recommendations.map(r => ({
132
+ model: r.modelId,
133
+ score: r.confidence,
134
+ reasoning: r.reasoning
135
+ })),
136
+ method: 'intelligent_mathematical_local_fallback',
137
+ systemSpecs: systemSpecs,
138
+ hardware_analysis: result.hardware_analysis
139
+ };
140
+ }
141
+ } catch (localError) {
142
+ console.warn(`Local intelligent selection also failed: ${localError.message}`);
143
+ }
144
+ }
145
+
146
+ // Fallback to ONNX if available
147
+ if (this.isAvailable) {
148
+ try {
149
+ if (!this.selector) {
150
+ await this.initialize();
151
+ }
152
+
153
+ const result = await this.selector.predictBestModel(candidateModels, systemSpecs);
154
+
155
+ return {
156
+ bestModel: result.bestModel,
157
+ confidence: result.allPredictions[0]?.score || 0,
158
+ allPredictions: result.allPredictions,
159
+ method: 'onnx_ai',
160
+ systemSpecs: result.systemSpecs
161
+ };
162
+
163
+ } catch (error) {
164
+ console.warn(`ONNX AI selection failed: ${error.message}`);
165
+ }
166
+ }
167
+
168
+ // Final fallback to simple heuristic
169
+ return this.fallbackSelection(candidateModels, systemSpecs);
170
+ }
171
+
172
+ fallbackSelection(candidateModels, systemSpecs = null) {
173
+ if (!systemSpecs) {
174
+ systemSpecs = {
175
+ total_ram_gb: 8,
176
+ gpu_vram_gb: 0,
177
+ cpu_cores: 4,
178
+ gpu_model_normalized: 'cpu_only'
179
+ };
180
+ }
181
+
182
+ console.log('🔄 Using fallback heuristic selection...');
183
+
184
+ // Use intelligent selector with basic heuristic mode
185
+ try {
186
+ const basicResult = this.intelligentSelector.selectBestModels(
187
+ systemSpecs,
188
+ candidateModels,
189
+ 'general',
190
+ 1
191
+ );
192
+
193
+ if (basicResult.best_model) {
194
+ return {
195
+ bestModel: basicResult.best_model.modelId,
196
+ confidence: Math.min(0.8, basicResult.best_model.confidence),
197
+ score: basicResult.best_model.score,
198
+ method: 'heuristic_intelligent',
199
+ reason: basicResult.best_model.reasoning,
200
+ systemSpecs,
201
+ hardware_analysis: basicResult.hardware_analysis
202
+ };
203
+ }
204
+ } catch (error) {
205
+ console.warn(`Intelligent fallback failed: ${error.message}`);
206
+ }
207
+
208
+ // Ultimate fallback: simple memory-based selection
209
+ const availableMemory = systemSpecs.gpu_vram_gb > 0 ?
210
+ systemSpecs.gpu_vram_gb :
211
+ systemSpecs.total_ram_gb * 0.7;
212
+
213
+ const modelSizes = candidateModels.map(model => ({
214
+ model,
215
+ size: this.estimateModelSize(model),
216
+ memoryReq: this.estimateModelSize(model) * 1.2
217
+ }));
218
+
219
+ const suitableModels = modelSizes
220
+ .filter(m => m.memoryReq <= availableMemory)
221
+ .sort((a, b) => b.size - a.size);
222
+
223
+ const bestModel = suitableModels.length > 0 ?
224
+ suitableModels[0].model :
225
+ modelSizes.reduce((a, b) => a.size < b.size ? a : b).model;
226
+
227
+ return {
228
+ bestModel,
229
+ confidence: suitableModels.length > 0 ? 0.7 : 0.4,
230
+ method: 'simple_heuristic',
231
+ reason: suitableModels.length > 0 ?
232
+ 'Best fitting model for available memory' :
233
+ 'Smallest available model (safety fallback)',
234
+ systemSpecs
235
+ };
236
+ }
237
+
238
+ estimateModelSize(modelId) {
239
+ const sizeMatch = modelId.match(/(\d+\.?\d*)[kmb]/i);
240
+ if (sizeMatch) {
241
+ const num = parseFloat(sizeMatch[1]);
242
+ const unit = sizeMatch[0].slice(-1).toLowerCase();
243
+
244
+ if (unit === 'k') return num / 1000;
245
+ if (unit === 'm') return num / 1000;
246
+ if (unit === 'b') return num;
247
+ }
248
+
249
+ // Default sizes for common model names
250
+ if (modelId.includes('mini')) return 3.8;
251
+ if (modelId.includes('7b')) return 7;
252
+ if (modelId.includes('13b')) return 13;
253
+ if (modelId.includes('70b')) return 70;
254
+
255
+ return 7; // Safe default
256
+ }
257
+
258
+ async benchmarkModel(modelId) {
259
+ // This would interface with the Python benchmarking script
260
+ const { spawn } = require('child_process');
261
+
262
+ return new Promise((resolve, reject) => {
263
+ const benchmark = spawn('python', [
264
+ path.join(__dirname, '../../ml-model/python/benchmark_collector.py'),
265
+ '--single-model', modelId
266
+ ]);
267
+
268
+ let output = '';
269
+ let error = '';
270
+
271
+ benchmark.stdout.on('data', (data) => output += data);
272
+ benchmark.stderr.on('data', (data) => error += data);
273
+
274
+ benchmark.on('close', (code) => {
275
+ if (code === 0) {
276
+ resolve({ success: true, data: output });
277
+ } else {
278
+ reject(new Error(`Benchmark failed: ${error}`));
279
+ }
280
+ });
281
+ });
282
+ }
283
+
284
+ getTrainingStatus() {
285
+ const modelPath = path.join(__dirname, '../../ml-model/trained/model_quantized.onnx');
286
+ const metadataPath = path.join(__dirname, '../../ml-model/trained/metadata.json');
287
+
288
+ const hasModel = fs.existsSync(modelPath);
289
+ const hasMetadata = fs.existsSync(metadataPath);
290
+
291
+ if (hasModel && hasMetadata) {
292
+ try {
293
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
294
+ const modelStats = fs.statSync(modelPath);
295
+
296
+ return {
297
+ status: 'trained',
298
+ modelSize: Math.round(modelStats.size / 1024), // KB
299
+ version: metadata.model_version || '1.0',
300
+ features: metadata.feature_count || 0,
301
+ lastUpdated: modelStats.mtime.toISOString()
302
+ };
303
+ } catch {
304
+ return { status: 'corrupted' };
305
+ }
306
+ }
307
+
308
+ return { status: 'not_trained' };
309
+ }
310
+ }
311
+
312
+ module.exports = AIModelSelector;