opc-agent 4.1.3 → 4.1.4
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/dist/cli.js +81 -45
- package/dist/cli.js.map +1 -1
- package/dist/core/model-recommender.d.ts +40 -0
- package/dist/core/model-recommender.d.ts.map +1 -0
- package/dist/core/model-recommender.js +186 -0
- package/dist/core/model-recommender.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/models.json +164 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -37,10 +37,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
37
37
|
const commander_1 = require("commander");
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
|
-
const os = __importStar(require("os"));
|
|
41
40
|
const yaml = __importStar(require("js-yaml"));
|
|
42
41
|
const readline = __importStar(require("readline"));
|
|
43
42
|
const runtime_1 = require("./core/runtime");
|
|
43
|
+
const model_recommender_1 = require("./core/model-recommender");
|
|
44
44
|
const customer_service_1 = require("./templates/customer-service");
|
|
45
45
|
const sales_assistant_1 = require("./templates/sales-assistant");
|
|
46
46
|
const knowledge_base_1 = require("./templates/knowledge-base");
|
|
@@ -366,32 +366,9 @@ export class EchoSkill extends BaseSkill {
|
|
|
366
366
|
template = await select('Select a template:', Object.entries(TEMPLATES).map(([value, { label }]) => ({ value, label })));
|
|
367
367
|
}
|
|
368
368
|
// ── 硬件检测 + 智能模型推荐 ──
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
const
|
|
372
|
-
const MODEL_RECOMMENDATIONS = [
|
|
373
|
-
// Tier 1: 超轻量 (≤4GB RAM)
|
|
374
|
-
{ name: 'qwen2.5:0.5b', size: '0.4GB', minRAM: 2, desc: '超轻量,适合低配机器', priority: 1 },
|
|
375
|
-
{ name: 'qwen2.5:1.5b', size: '1.0GB', minRAM: 4, desc: '轻量但更智能', priority: 2 },
|
|
376
|
-
// Tier 2: 轻量 (4-8GB RAM)
|
|
377
|
-
{ name: 'qwen2.5:3b', size: '2.0GB', minRAM: 6, desc: '性价比最优', priority: 3 },
|
|
378
|
-
{ name: 'llama3.2:3b', size: '2.0GB', minRAM: 6, desc: 'Meta 最新轻量模型', priority: 3 },
|
|
379
|
-
{ name: 'phi3:mini', size: '2.3GB', minRAM: 6, desc: '微软高效小模型', priority: 3 },
|
|
380
|
-
// Tier 3: 标准 (8-16GB RAM)
|
|
381
|
-
{ name: 'qwen2.5:7b', size: '4.7GB', minRAM: 8, desc: '推荐:中文最强 7B', priority: 4 },
|
|
382
|
-
{ name: 'llama3.1:8b', size: '4.7GB', minRAM: 8, desc: 'Meta 通用 8B', priority: 4 },
|
|
383
|
-
{ name: 'mistral:7b', size: '4.1GB', minRAM: 8, desc: 'Mistral 经典 7B', priority: 4 },
|
|
384
|
-
{ name: 'gemma2:9b', size: '5.4GB', minRAM: 10, desc: 'Google 高效 9B', priority: 4 },
|
|
385
|
-
// Tier 4: 高配 (16-32GB RAM)
|
|
386
|
-
{ name: 'qwen2.5:14b', size: '9.0GB', minRAM: 16, desc: '中文强力 14B', priority: 5 },
|
|
387
|
-
{ name: 'deepseek-coder-v2:16b', size: '9.0GB', minRAM: 16, desc: '编程专用', priority: 5 },
|
|
388
|
-
// Tier 5: 旗舰 (32GB+ RAM)
|
|
389
|
-
{ name: 'qwen2.5:32b', size: '20GB', minRAM: 32, desc: '接近 GPT-4 水平', priority: 6 },
|
|
390
|
-
{ name: 'llama3.1:70b', size: '40GB', minRAM: 64, desc: '开源最强', priority: 7 },
|
|
391
|
-
];
|
|
392
|
-
// 根据可用内存筛选合适的模型
|
|
393
|
-
const suitableModels = MODEL_RECOMMENDATIONS.filter(m => m.minRAM <= freeMem + 2); // +2GB 容差
|
|
394
|
-
const bestRec = suitableModels.length > 0 ? suitableModels[suitableModels.length - 1] : MODEL_RECOMMENDATIONS[0];
|
|
369
|
+
// ── 硬件检测 + 远程模型推荐 ──
|
|
370
|
+
const sys = (0, model_recommender_1.detectSystem)();
|
|
371
|
+
const allModels = await (0, model_recommender_1.fetchModelList)();
|
|
395
372
|
// ── LLM Provider 选择(Ollama-first)──
|
|
396
373
|
let llmProvider = 'ollama';
|
|
397
374
|
let llmModel = 'qwen2.5';
|
|
@@ -409,20 +386,23 @@ export class EchoSkill extends BaseSkill {
|
|
|
409
386
|
modelNames = (ollamaData.models || []).map((m) => m.name || m.model);
|
|
410
387
|
ollamaRunning = true;
|
|
411
388
|
if (opts.yes && modelNames.length > 0) {
|
|
412
|
-
|
|
413
|
-
|
|
389
|
+
const rec = (0, model_recommender_1.recommendModels)(allModels, sys, modelNames);
|
|
390
|
+
// --yes: prefer best installed recommended model
|
|
391
|
+
const bestInstalled = rec.installed.length > 0 ? rec.installed[rec.installed.length - 1] : null;
|
|
414
392
|
llmModel = bestInstalled ? bestInstalled.name : modelNames[0];
|
|
415
393
|
}
|
|
416
394
|
}
|
|
417
395
|
catch {
|
|
418
396
|
ollamaRunning = false;
|
|
419
397
|
}
|
|
398
|
+
// Compute recommendation (used by both interactive branches)
|
|
399
|
+
const rec = (0, model_recommender_1.recommendModels)(allModels, sys, modelNames);
|
|
420
400
|
if (!opts.yes) {
|
|
421
401
|
if (ollamaRunning) {
|
|
422
402
|
console.log(`\n ${icon.info} ${color.dim('正在检测 Ollama...')}`);
|
|
423
403
|
console.log(` ${icon.success} Ollama 已运行,发现 ${modelNames.length} 个模型`);
|
|
424
|
-
console.log(` ${icon.info} 系统: ${totalRAM}GB RAM (${
|
|
425
|
-
console.log(` ${icon.info} 推荐模型: ${color.cyan(
|
|
404
|
+
console.log(` ${icon.info} 系统: ${sys.totalRAM}GB RAM (${sys.freeRAM}GB 可用), ${sys.cpuCount} CPU cores`);
|
|
405
|
+
console.log(` ${icon.info} 推荐模型: ${color.cyan(rec.best.name)} (${rec.best.size}) - ${rec.best.desc}`);
|
|
426
406
|
// 选择 provider
|
|
427
407
|
llmProvider = await select('选择 LLM 引擎:', [
|
|
428
408
|
{ value: 'ollama', label: '🟢 Ollama (免费本地,推荐) - 已检测到运行中' },
|
|
@@ -433,16 +413,14 @@ export class EchoSkill extends BaseSkill {
|
|
|
433
413
|
]);
|
|
434
414
|
if (llmProvider === 'ollama') {
|
|
435
415
|
// 已有模型 + 推荐未下载的模型
|
|
436
|
-
const existingSet = new Set(modelNames);
|
|
437
|
-
const recommendedNotInstalled = suitableModels.filter(m => !existingSet.has(m.name)).slice(-3); // 推荐最多3个未下载的
|
|
438
416
|
const modelOptions = [
|
|
439
|
-
...
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
const isBest = m === bestRec.name ? ' ⭐推荐' : '';
|
|
443
|
-
return { value: m, label: `${m}${recLabel}${isBest} [已安装]` };
|
|
417
|
+
...rec.installed.map((m) => {
|
|
418
|
+
const isBest = m.name === rec.best.name ? ' ⭐推荐' : '';
|
|
419
|
+
return { value: m.name, label: `${m.name} (${m.size}, ${m.desc})${isBest} [已安装]` };
|
|
444
420
|
}),
|
|
445
|
-
|
|
421
|
+
// Also show installed models not in recommendation list
|
|
422
|
+
...modelNames.filter(n => !rec.installed.find(m => m.name === n)).map(n => ({ value: n, label: `${n} [已安装]` })),
|
|
423
|
+
...rec.toDownload.map((m) => ({
|
|
446
424
|
value: `pull:${m.name}`,
|
|
447
425
|
label: `${m.name} (${m.size}, ${m.desc}) [需下载]`,
|
|
448
426
|
})),
|
|
@@ -463,11 +441,11 @@ export class EchoSkill extends BaseSkill {
|
|
|
463
441
|
else {
|
|
464
442
|
// 没有本地模型,推荐下载
|
|
465
443
|
console.log(` ${color.yellow('⚠️')} 没有发现已下载的模型`);
|
|
466
|
-
console.log(` ${icon.info} 根据你的硬件 (${
|
|
467
|
-
for (const m of
|
|
444
|
+
console.log(` ${icon.info} 根据你的硬件 (${sys.freeRAM}GB 可用),推荐下载:`);
|
|
445
|
+
for (const m of rec.suitable.slice(-3)) {
|
|
468
446
|
console.log(` ${color.cyan(`ollama pull ${m.name}`)} (${m.size}, ${m.desc})`);
|
|
469
447
|
}
|
|
470
|
-
llmModel =
|
|
448
|
+
llmModel = rec.best.name;
|
|
471
449
|
}
|
|
472
450
|
}
|
|
473
451
|
}
|
|
@@ -485,12 +463,12 @@ export class EchoSkill extends BaseSkill {
|
|
|
485
463
|
if (llmProvider === 'ollama') {
|
|
486
464
|
console.log(`\n ${icon.info} Ollama 安装指南:`);
|
|
487
465
|
console.log(` 1. 访问 ${color.cyan('https://ollama.ai')} 下载并安装`);
|
|
488
|
-
console.log(` ${icon.info} 根据你的硬件 (${totalRAM}GB RAM, ${
|
|
489
|
-
for (const m of
|
|
466
|
+
console.log(` ${icon.info} 根据你的硬件 (${sys.totalRAM}GB RAM, ${sys.freeRAM}GB 可用),推荐:`);
|
|
467
|
+
for (const m of rec.suitable.slice(-3)) {
|
|
490
468
|
console.log(` ${color.cyan(`ollama pull ${m.name}`)} (${m.size}, ${m.desc})`);
|
|
491
469
|
}
|
|
492
470
|
console.log(` 3. 然后 ${color.cyan('opc run')} 即可开始对话\n`);
|
|
493
|
-
llmModel =
|
|
471
|
+
llmModel = rec.best.name;
|
|
494
472
|
}
|
|
495
473
|
}
|
|
496
474
|
// 商业模型需要 API key
|
|
@@ -2436,6 +2414,64 @@ program
|
|
|
2436
2414
|
await voice.start();
|
|
2437
2415
|
`));
|
|
2438
2416
|
});
|
|
2417
|
+
// ── Models command ──────────────────────────────────────────────
|
|
2418
|
+
program
|
|
2419
|
+
.command('models')
|
|
2420
|
+
.description('Show recommended Ollama models for your system')
|
|
2421
|
+
.option('--refresh', 'Force refresh model list from remote')
|
|
2422
|
+
.option('--json', 'Output as JSON')
|
|
2423
|
+
.action(async (opts) => {
|
|
2424
|
+
if (opts.refresh) {
|
|
2425
|
+
(0, model_recommender_1.clearModelCache)();
|
|
2426
|
+
console.log(`${icon.success} 模型推荐缓存已清除`);
|
|
2427
|
+
}
|
|
2428
|
+
const sys = (0, model_recommender_1.detectSystem)();
|
|
2429
|
+
const models = await (0, model_recommender_1.fetchModelList)();
|
|
2430
|
+
const cache = (0, model_recommender_1.cacheInfo)();
|
|
2431
|
+
// Detect Ollama
|
|
2432
|
+
let installedModels = [];
|
|
2433
|
+
try {
|
|
2434
|
+
const ctrl = new AbortController();
|
|
2435
|
+
const t = setTimeout(() => ctrl.abort(), 3000);
|
|
2436
|
+
const res = await fetch('http://localhost:11434/api/tags', { signal: ctrl.signal });
|
|
2437
|
+
clearTimeout(t);
|
|
2438
|
+
const data = await res.json();
|
|
2439
|
+
installedModels = (data.models || []).map((m) => m.name || m.model);
|
|
2440
|
+
}
|
|
2441
|
+
catch { /* Ollama not running */ }
|
|
2442
|
+
const rec = (0, model_recommender_1.recommendModels)(models, sys, installedModels);
|
|
2443
|
+
if (opts.json) {
|
|
2444
|
+
console.log(JSON.stringify({ system: sys, cache, recommendation: rec }, null, 2));
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
console.log(`\n${icon.rocket} ${color.bold('OPC 模型推荐')}\n`);
|
|
2448
|
+
console.log(` 系统: ${sys.totalRAM}GB RAM (${sys.freeRAM}GB 可用), ${sys.cpuCount} cores, ${sys.platform}/${sys.arch}`);
|
|
2449
|
+
if (cache.exists) {
|
|
2450
|
+
console.log(` 推荐列表: v${cache.version} (${cache.age})`);
|
|
2451
|
+
}
|
|
2452
|
+
else {
|
|
2453
|
+
console.log(` 推荐列表: 内置 (运行 ${color.cyan('opc models --refresh')} 获取最新)`);
|
|
2454
|
+
}
|
|
2455
|
+
console.log(` Ollama: ${installedModels.length > 0 ? color.green(`运行中, ${installedModels.length} 个模型`) : color.yellow('未运行')}`);
|
|
2456
|
+
console.log(`\n ${color.bold('⭐ 推荐:')} ${color.cyan(rec.best.name)} (${rec.best.size}) - ${rec.best.desc}\n`);
|
|
2457
|
+
// Table
|
|
2458
|
+
console.log(` ${'模型'.padEnd(28)} ${'大小'.padEnd(8)} ${'最低RAM'.padEnd(8)} ${'状态'.padEnd(10)} 说明`);
|
|
2459
|
+
console.log(` ${'─'.repeat(28)} ${'─'.repeat(8)} ${'─'.repeat(8)} ${'─'.repeat(10)} ${'─'.repeat(20)}`);
|
|
2460
|
+
for (const m of rec.suitable) {
|
|
2461
|
+
const installed = installedModels.includes(m.name);
|
|
2462
|
+
const isBest = m.name === rec.best.name;
|
|
2463
|
+
const status = installed ? color.green('已安装') : color.dim('未安装');
|
|
2464
|
+
const star = isBest ? ' ⭐' : (m.recommended ? ' 💎' : '');
|
|
2465
|
+
console.log(` ${(m.name + star).padEnd(28)} ${m.size.padEnd(8)} ${(m.minRAM + 'GB').padEnd(8)} ${status.padEnd(10)} ${m.desc}`);
|
|
2466
|
+
}
|
|
2467
|
+
if (rec.toDownload.length > 0) {
|
|
2468
|
+
console.log(`\n ${color.bold('推荐下载:')}`);
|
|
2469
|
+
for (const m of rec.toDownload) {
|
|
2470
|
+
console.log(` ${color.cyan(`ollama pull ${m.name}`)} (${m.size}, ${m.desc})`);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
console.log();
|
|
2474
|
+
});
|
|
2439
2475
|
program.parse();
|
|
2440
2476
|
// ── Keys command ──────────────────────────────────────────────
|
|
2441
2477
|
const keys_1 = require("./security/keys");
|