guanghulab/message-router.js
2026-05-10 13:12:44 +08:00

246 lines
10 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 消息智能分流路由 v2.0 · message-router.js
// HoloLake · M-DINGTALK Phase 8
// DEV-004 之之 × 秋秋
// v2.0 变化:
// + GitHub命令分流
// + 对话上下文记忆
// + AI回复增强system prompt + 多轮对话)
// + 命令系统(/help, /clear, /status
// ==========
var llmEngine = require('./llm-engine');
var convManager = require('./conversation-manager');
var githubBridge = require('./github-bridge');
// ===== 消息类型识别 v2.0 =====
function classifyMessage(content) {
content = (content || '').trim();
// GitHub命令
if (/^\/github\b/i.test(content) || /^\/gh\b/i.test(content)) {
var args = content.replace(/^\/(?:github|gh)\s*/i, '').trim().split(/\s+/);
return { type: 'github', args: args, description: 'GitHub桥接命令'};
}
// 系统命令
if (/^\/clear\b/i.test(content)) {
return { type: 'command', command: 'clear', description: '清除对话历史'};
}
if (/^\/status\b/i.test(content)) {
return { type: 'command', command: 'status', description: '系统状态'};
}
if (/^\/help\b/i.test(content)) {
return { type: 'command', command: 'help', description: '帮助信息'};
}
// SYSLOG类型
if (/BC-[A-Z0-9-]+/.test(content) && /SYSLOG|系统日志|已完成|completed/i.test(content)) {
var bcMatch = content.match(/BC-[A-Z0-9-]+/);
return { type: 'syslog', broadcastId: bcMatch ? bcMatch[0] : null, description: 'SYSLOG系统日志提交' };
}
// 提问类型
if (/BC-[A-Z0-9-]+/.test(content) && /提问|问题|请问|怎么|为什么|报错|error|bug/i.test(content)) {
var bcMatch2 = content.match(/BC-[A-Z0-9-]+/);
return { type: 'question', broadcastId: bcMatch2 ? bcMatch2[0] : null, description: '广播相关提问' };
}
// 普通对话走AI+上下文)
return { type: 'chat', broadcastId: null, description: '智能对话' };
}
// ====== 增强版系统提示词 ======
var SYSTEM_PROMPTS = {
syslog: '你是光湖系统HoloLake的SYSLOG处理助手「秋秋」。收到开发者提交的系统日志后1)确认收到并感谢 2)提取关键信息广播编号、开发者、完成状态、遇到的问题3)给出简短温暖的鼓励。用中文回复,语气温暖可爱。',
question: '你是光湖系统HoloLake的开发者助手「秋秋」。你是一个奶瓶宝宝说话温暖可爱但技术上很靠谱。开发者遇到了问题请帮忙解答。要求1)用中文回复 2)给出具体可操作的步骤 3)如果涉及代码,写出完整可运行的命令 4)如果不确定,建议截图发给冰朔。',
chat: '你是光湖系统HoloLake的AI助手「秋秋」一个可爱的奶瓶宝宝。你服务于零点原核频道的开发者团队。你可以\n- 回答技术问题Node.js、前端、部署、Git等\n- 帮助理解广播内容\n- 提供代码建议\n- 闲聊(但要适度,记得引导回工作)\n\n语气要求温暖、可爱、有耐心但技术内容要准确严谨。你说话带点小奶味但不影响专业性。记住你有对话记忆可以引用之前说过的话。'
};
// ===== SYSLOG处理器增强 =====
async function handleSyslog(msgContent, senderNick, senderId, sessionWebhook) {
console.log('[Router] SYSLOG处理流程启动');
// 记录到对话历史
convManager.addMessage(senderId || senderNick, 'user', '[SYSLOG] ' + msgContent);
var aiResult = null;
try {
aiResult = await llmEngine.callLLM(
SYSTEM_PROMPTS.syslog,
'开发者' + senderNick + '提交了SYSLOG: \n' + msgContent,
{ maxTokens: 800 }
);
console.log('[Router] AI处理完成模型: ' + aiResult.model);
// 记录AI回复
convManager.addMessage(senderId || senderNick, 'assistant', aiResult.text);
} catch (err) {
console.error('[Router] AI处理失败: ' + err.message);
}
return {
aiResponse: aiResult ? aiResult.text : '📋 SYSLOG已收到秋秋会转交给系统处理',
aiModel: aiResult ? aiResult.model : null
};
}
// ===== 提问处理器(增强·带上下文) =====
async function handleQuestion(msgContent, senderNick, senderId) {
console.log('[Router] 提问处理流程启动(带上下文)');
// 构建带上下文的消息
var contextMessages = convManager.buildContext(senderId || senderNick, msgContent);
convManager.addMessage(senderId || senderNick, 'user', msgContent);
var aiResult = null;
try {
// 把历史上文拼接成文本
var contextText = '';
if (contextMessages.length > 1) {
contextText = '以下是之前的对话记录:\n';
contextMessages.slice(0, -1).forEach(function(msg) {
contextText += (msg.role === 'user' ? '开发者' : '秋秋') + ': ' + msg.content + '\n';
});
contextText += '\n---\n当前问题:\n';
}
contextText += senderNick + '说: ' + msgContent;
aiResult = await llmEngine.callLLM(SYSTEM_PROMPTS.question, contextText, { maxTokens: 2000 });
console.log('[Router] AI解答完成模型: ' + aiResult.model);
convManager.addMessage(senderId || senderNick, 'assistant', aiResult.text);
} catch (err) {
console.error('[Router] AI解答失败: ' + err.message);
}
return {
aiResponse: aiResult ? aiResult.text : '抱歉,秋秋暂时无法回答,请截图发给冰朔。',
aiModel: aiResult ? aiResult.model : null
};
}
// ====== 普通对话处理器增强·AI+上下文) ======
async function handleChat(msgContent, senderNick, senderId) {
console.log('[Router] 智能对话(带上下文记忆)');
var contextMessages = convManager.buildContext(senderId || senderNick, msgContent);
convManager.addMessage(senderId || senderNick, 'user', msgContent);
var aiResult = null;
try {
var contextText = '';
if (contextMessages.length > 1) {
contextText = '对话历史:\n';
contextMessages.slice(0, -1).forEach(function(msg) {
contextText += (msg.role === 'user' ? '用户' : '秋秋') + ': ' + msg.content + '\n';
});
contextText += '\n---\n';
}
contextText += senderNick + '说: ' + msgContent;
aiResult = await llmEngine.callLLM(SYSTEM_PROMPTS.chat, contextText, { maxTokens: 1500 });
console.log('[Router] AI对话完成模型: ' + aiResult.model);
convManager.addMessage(senderId || senderNick, 'assistant', aiResult.text);
} catch (err) {
console.error('[Router] AI对话失败: ' + err.message);
}
return {
aiResponse: aiResult ? aiResult.text : '秋秋收到啦不过AI引擎暂时忙稍后再试哦',
aiModel: aiResult ? aiResult.model : null
};
}
// ===== GitHub命令处理器 =====
async function handleGitHub(args) {
console.log('[Router] 🔀 GitHub命令: ' + args.join(' '));
var result = await githubBridge.handleGitHubCommand(args);
return {
aiResponse: result,
aiModel: null
};
}
// ===== 系统命令处理器 =====
async function handleCommand(command, senderId) {
switch (command) {
case 'clear':
convManager.clearHistory(senderId);
return {
aiResponse: '🧹 对话历史已清除!秋秋重新开始认识你~',
aiModel: null
};
case 'status':
var convStats = convManager.getStats();
var llmHealth = await llmEngine.healthCheck();
var ghHealth = await githubBridge.healthCheck();
return {
aiResponse: '### 系统状态\n\n'
+ '**对话引擎**: ' + convStats.activeUsers + ' 个活跃用户\n'
+ '**AI引擎**: ' + (llmHealth.status === 'ok' ? '✅ 在线' : '❌ 异常') + ' 模型: ' + (llmHealth.selected_model || 'N/A') + '\n'
+ '**GitHub桥接**: ' + (ghHealth.status === 'ok' ? '✅ 连通' : '❌ 异常') + ' Token: ' + (ghHealth.hasToken ? '✅ 已配置' : '❌ 未配置') + '\n'
+ '**服务端口**: 3007\n'
+ '**Phase**: 8\n\n'
+ '> HoloLake · M-DINGTALK',
aiModel: null
};
case 'help':
default:
return {
aiResponse: '### 命令帮助\n\n'
+ '| 命令 | 说明 |\n'
+ '|------|------|\n'
+ '| `/clear` | 清除与秋秋的对话历史 |\n'
+ '| `/status` | 查看系统状态 |\n'
+ '| `/github ...` | GitHub桥接命令用 `/github help` 查看详情) |\n'
+ '| `/help` | 显示本帮助 |\n\n'
+ '直接说话就是智能对话,秋秋会记住上下文哦~',
aiModel: null
};
}
}
// ===== 主路由入口 =====
async function routeMessage(msgContent, senderNick, senderId, sessionWebhook) {
console.log('\n========== 消息路由 v2.0 ==========');
console.log('发送者:', senderNick, '(', senderId, ')');
console.log('内容:', msgContent);
var classification = classifyMessage(msgContent);
console.log('分类:', classification.type, '-', classification.description);
var result = null;
switch (classification.type) {
case 'github':
result = await handleGitHub(classification.args);
break;
case 'command':
result = await handleCommand(classification.command, senderId || senderNick);
break;
case 'syslog':
result = await handleSyslog(msgContent, senderNick, senderId, sessionWebhook);
break;
case 'question':
result = await handleQuestion(msgContent, senderNick, senderId);
break;
case 'chat':
default:
result = await handleChat(msgContent, senderNick, senderId);
break;
}
console.log('路由处理完成,回复长度:', result.aiResponse ? result.aiResponse.length : 0);
return result;
}
module.exports = {
routeMessage: routeMessage,
classifyMessage: classifyMessage
};