- assistantProfileConfig: KB answer prompt改为分层策略(严格产品信息+灵活常识补充) - nativeVoiceGateway: S2S upstream自动重连(最多50次)、event 351字幕debounce(800ms取最长文本) - toolExecutor: 确定性query改写增强、KB查询传递session上下文 - contextKeywordTracker: 支持KB话题记忆优先enrichment - contentSafeGuard: 新增品牌安全内容过滤服务 - assistantProfileService: 新增助手配置CRUD服务 - routes/assistantProfile: 新增助手配置API路由 - knowledgeKeywords: 扩展KB关键词词典 - fastAsrCorrector: ASR纠错规则更新 - tests/: KB prompt测试、保护窗口测试、Viking性能测试 - docs/: 助手配置API文档、系统提示词目录
96 lines
3.4 KiB
JavaScript
96 lines
3.4 KiB
JavaScript
const { Client } = require('ssh2');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const SERVER = { host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' };
|
||
const REMOTE_DIR = '/www/wwwroot/demo.tensorgrove.com.cn/server';
|
||
|
||
const FILES = [
|
||
{
|
||
local: path.join(__dirname, '..', 'services', 'assistantProfileConfig.js'),
|
||
remote: REMOTE_DIR + '/services/assistantProfileConfig.js',
|
||
},
|
||
];
|
||
|
||
function sshExec(client, cmd) {
|
||
return new Promise((resolve, reject) => {
|
||
client.exec(cmd, (err, stream) => {
|
||
if (err) return reject(err);
|
||
let out = '', errOut = '';
|
||
stream.on('data', (d) => (out += d.toString()));
|
||
stream.stderr.on('data', (d) => (errOut += d.toString()));
|
||
stream.on('close', (code) => resolve({ out: out.trim(), err: errOut.trim(), code }));
|
||
});
|
||
});
|
||
}
|
||
|
||
function sshUpload(client, localPath, remotePath) {
|
||
return new Promise((resolve, reject) => {
|
||
client.sftp((err, sftp) => {
|
||
if (err) return reject(err);
|
||
sftp.fastPut(localPath, remotePath, (err) => {
|
||
if (err) return reject(err);
|
||
resolve();
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
async function deploy() {
|
||
const client = new Client();
|
||
client.on('ready', async () => {
|
||
try {
|
||
console.log('✅ SSH connected\n');
|
||
const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||
|
||
// 1. 先查看服务器当前prompt
|
||
console.log('📋 服务器当前prompt:');
|
||
const before = await sshExec(client, `grep -n 'buildKnowledgeAnswerPrompt\\|知识库涵盖\\|产品用法' ${REMOTE_DIR}/services/assistantProfileConfig.js | head -5`);
|
||
console.log(' ' + (before.out || '(not found)') + '\n');
|
||
|
||
// 2. 备份 + 上传
|
||
for (const { local, remote } of FILES) {
|
||
const name = path.basename(remote);
|
||
await sshExec(client, `cp ${remote} ${remote}.bak_${ts}`);
|
||
console.log('📦 Backup: ' + name);
|
||
await sshUpload(client, local, remote);
|
||
console.log('📤 Uploaded: ' + name);
|
||
const syntax = await sshExec(client, `node -c ${remote}`);
|
||
if (syntax.code !== 0) {
|
||
console.error('❌ Syntax error in ' + name + '! Rolling back...');
|
||
await sshExec(client, `cp ${remote}.bak_${ts} ${remote}`);
|
||
client.end();
|
||
return;
|
||
}
|
||
console.log('🔍 Syntax OK: ' + name + '\n');
|
||
}
|
||
|
||
// 3. 重启PM2
|
||
const pm2Result = await sshExec(client, `cd ${REMOTE_DIR} && pm2 restart all --update-env`);
|
||
console.log('🔄 PM2 restarted');
|
||
if (pm2Result.out) console.log(' ' + pm2Result.out.split('\n').slice(0, 3).join('\n '));
|
||
await new Promise(r => setTimeout(r, 5000));
|
||
|
||
// 4. 验证新prompt已生效
|
||
console.log('\n📋 服务器新prompt:');
|
||
const after = await sshExec(client, `grep -n '知识库涵盖\\|产品常有别名\\|不得编造' ${REMOTE_DIR}/services/assistantProfileConfig.js | head -5`);
|
||
console.log(' ' + (after.out || '(not found)'));
|
||
|
||
// 5. PM2 状态
|
||
const status = await sshExec(client, 'pm2 status');
|
||
console.log('\n📊 PM2 Status:');
|
||
console.log(' ' + status.out.split('\n').slice(0, 6).join('\n '));
|
||
|
||
console.log('\n✅ 部署完成!KB answer prompt 已更新为优化版本');
|
||
} catch (e) {
|
||
console.error('❌ Error:', e.message);
|
||
} finally {
|
||
client.end();
|
||
}
|
||
});
|
||
client.on('error', (err) => console.error('❌ SSH Error:', err.message));
|
||
client.connect(SERVER);
|
||
}
|
||
|
||
deploy();
|