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.
- package/LICENSE +21 -0
- package/README.md +418 -0
- package/analyzer/compatibility.js +584 -0
- package/analyzer/performance.js +505 -0
- package/bin/CLAUDE.md +12 -0
- package/bin/enhanced_cli.js +3118 -0
- package/bin/test-deterministic.js +41 -0
- package/package.json +96 -0
- package/src/CLAUDE.md +12 -0
- package/src/ai/intelligent-selector.js +615 -0
- package/src/ai/model-selector.js +312 -0
- package/src/ai/multi-objective-selector.js +820 -0
- package/src/commands/check.js +58 -0
- package/src/data/CLAUDE.md +11 -0
- package/src/data/model-database.js +637 -0
- package/src/data/sync-manager.js +279 -0
- package/src/hardware/CLAUDE.md +12 -0
- package/src/hardware/backends/CLAUDE.md +11 -0
- package/src/hardware/backends/apple-silicon.js +318 -0
- package/src/hardware/backends/cpu-detector.js +490 -0
- package/src/hardware/backends/cuda-detector.js +417 -0
- package/src/hardware/backends/intel-detector.js +436 -0
- package/src/hardware/backends/rocm-detector.js +440 -0
- package/src/hardware/detector.js +573 -0
- package/src/hardware/pc-optimizer.js +635 -0
- package/src/hardware/specs.js +286 -0
- package/src/hardware/unified-detector.js +442 -0
- package/src/index.js +2289 -0
- package/src/models/CLAUDE.md +17 -0
- package/src/models/ai-check-selector.js +806 -0
- package/src/models/catalog.json +426 -0
- package/src/models/deterministic-selector.js +1145 -0
- package/src/models/expanded_database.js +1142 -0
- package/src/models/intelligent-selector.js +532 -0
- package/src/models/requirements.js +310 -0
- package/src/models/scoring-config.js +57 -0
- package/src/models/scoring-engine.js +715 -0
- package/src/ollama/.cache/README.md +33 -0
- package/src/ollama/CLAUDE.md +24 -0
- package/src/ollama/client.js +438 -0
- package/src/ollama/enhanced-client.js +113 -0
- package/src/ollama/enhanced-scraper.js +634 -0
- package/src/ollama/manager.js +357 -0
- package/src/ollama/native-scraper.js +776 -0
- package/src/plugins/CLAUDE.md +11 -0
- package/src/plugins/examples/custom_model_plugin.js +87 -0
- package/src/plugins/index.js +295 -0
- package/src/utils/CLAUDE.md +11 -0
- package/src/utils/config.js +359 -0
- package/src/utils/formatter.js +315 -0
- package/src/utils/logger.js +272 -0
- package/src/utils/model-classifier.js +167 -0
- 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;
|