如何用Node.js在Bot Emulator启动时加载SQL Server中的历史对话?
实现Node.js Bot在Emulator启动时加载SQL Server历史对话记录
我来一步步帮你搞定这个需求,核心思路就是从SQL Server读取历史对话数据,转换成Bot Framework能识别的格式,再在Emulator连接会话时把这些历史消息“还原”出来,让用户能无缝衔接之前的对话。
1. 安装必要依赖
首先得搞定Node.js和SQL Server的连接,以及Bot Framework的核心工具,直接装这两个包就行:
npm install mssql botbuilder restify
2. 配置SQL Server连接
先写个数据库连接模块db-connection.js,专门处理和SQL Server的连接逻辑:
const sql = require('mssql'); // 替换成你的SQL Server配置 const sqlConfig = { user: '你的SQL用户名', password: '你的SQL密码', server: 'localhost', // 比如本地服务器地址 database: '你的对话记录数据库名', options: { encrypt: false, // 本地测试一般关,Azure SQL需要开 trustServerCertificate: true // 本地测试可开启,生产环境不建议 } }; async function getSqlPool() { try { const pool = await sql.connect(sqlConfig); return pool; } catch (err) { console.error('SQL连接失败:', err); throw err; } } module.exports = { getSqlPool };
3. 编写历史对话查询逻辑
创建conversation-history.js模块,负责从SQL读取并转换历史对话:
const { getSqlPool } = require('./db-connection'); async function fetchHistoryByConversationId(conversationId) { const pool = await getSqlPool(); try { // 假设你的对话表名为ConversationLogs,字段和Bot Activity结构对应 const result = await pool.request() .input('conversationId', sql.NVarChar, conversationId) .query(`SELECT * FROM ConversationLogs WHERE conversationId = @conversationId ORDER BY timestamp ASC`); // 把SQL记录转换成Bot标准的Activity对象 return result.recordset.map(record => ({ type: record.type || 'message', id: record.activityId, conversation: { id: record.conversationId }, from: { id: record.fromId, name: record.fromName }, recipient: { id: record.recipientId, name: record.recipientName }, text: record.text, timestamp: new Date(record.timestamp), channelId: 'emulator' // 指定为Emulator渠道,确保显示正确 })); } finally { await pool.close(); } } module.exports = { fetchHistoryByConversationId };
⚠️ 注意:如果你的SQL表结构和Bot Activity字段不匹配,要调整查询和转换逻辑,保证输出是标准的Activity对象,否则Emulator没法正确渲染消息。
4. 在Bot中加载并发送历史记录
修改你的Bot主文件bot.js,在会话启动时(比如Emulator连接、用户发第一条消息时)加载历史并发送:
const { ActivityHandler } = require('botbuilder'); const { fetchHistoryByConversationId } = require('./conversation-history'); class HistoryLoadedBot extends ActivityHandler { constructor() { super(); // 处理会话更新事件(Emulator连接时触发) this.onConversationUpdate(async (context, next) => { const conversationState = context.turnState.get('ConversationState'); const botState = await conversationState.createProperty('BotSessionState').get(context, {}); // 只有第一次启动会话时加载历史,避免重复发送 if (!botState.historyLoaded && context.activity.membersAdded.some(m => m.id === context.activity.recipient.id)) { const conversationId = context.activity.conversation.id; const historyLogs = await fetchHistoryByConversationId(conversationId); // 逐条发送历史消息到Emulator for (const activity of historyLogs) { await context.sendActivity(activity); } // 标记历史已加载 botState.historyLoaded = true; await conversationState.saveChanges(context); } await next(); }); // 处理用户实时消息 this.onMessage(async (context, next) => { await context.sendActivity(`收到你的消息:${context.activity.text}`); await next(); }); } } module.exports.HistoryLoadedBot = HistoryLoadedBot;
5. 配置会话状态管理
在入口文件index.js中,配置ConversationState来跟踪历史是否已加载,避免重复发送:
const { BotFrameworkAdapter, ConversationState, MemoryStorage } = require('botbuilder'); const { HistoryLoadedBot } = require('./bot'); const restify = require('restify'); // 创建服务器 const server = restify.createServer(); server.listen(process.env.PORT || 3978, () => { console.log(`\n${server.name} 运行在 ${server.url}`); }); // 创建Bot适配器 const adapter = new BotFrameworkAdapter({ appId: process.env.MICROSOFT_APP_ID || '', appPassword: process.env.MICROSOFT_APP_PASSWORD || '' }); // 用内存存储会话状态(生产环境建议用Azure Blob/SQL存储) const memoryStorage = new MemoryStorage(); const conversationState = new ConversationState(memoryStorage); // 初始化Bot const bot = new HistoryLoadedBot(); // 处理消息请求 server.post('/api/messages', (req, res) => { adapter.processActivity(req, res, async (context) => { context.turnState.set('ConversationState', conversationState); await bot.run(context); }); });
关键注意事项
- 会话ID匹配:Emulator每次重启可能生成新会话ID,如果想加载特定用户的历史,建议用用户ID筛选,或者在Emulator设置中固定会话ID。
- 性能优化:如果历史记录很多,不要一次性全发,可以分页加载最近的N条,避免Emulator卡顿。
- 数据一致性:确保SQL中存储的对话记录和Bot Activity结构一致,尤其是
from、recipient、timestamp这些核心字段,否则消息显示会错乱。
这样配置后,启动Bot再打开Emulator连接,就能自动看到SQL Server里存储的过往对话记录了。
内容的提问来源于stack exchange,提问作者Arvind
相关产品推荐
相关产品推荐

