求助:为Dialogflow ES聊天机器人添加数据存储与展示功能
一、存储用户聊天信息(基于Cloud Functions + Firestore)
因为你已经在用Cloud Functions做fulfillment,直接在现有代码里扩展即可,推荐用Google Cloud Firestore作为存储服务(和Cloud Functions集成便捷,适合小型项目):
启用Firestore数据库
登录Google Cloud控制台,找到Firestore服务,选择「原生模式」,设置合适的区域(建议和Cloud Functions同区域)完成创建。修改Cloud Functions代码
在Dialogflow的fulfillment inline editor中,引入Firestore并添加存储逻辑。每次用户发送消息时,将用户输入、会话ID、时间戳等信息存入Firestore:const { WebhookClient } = require('dialogflow-fulfillment'); const { Firestore } = require('@google-cloud/firestore'); const functions = require('firebase-functions'); const firestore = new Firestore(); exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); // 提取会话ID(从Dialogflow的session字段中截取) const sessionId = agent.session.split('/').pop(); const userInput = agent.query; const timestamp = new Date().toISOString(); const intentName = agent.intent; // 将消息追加到对应会话的聊天记录中 const chatLogRef = firestore.collection('chatLogs').doc(sessionId); chatLogRef.set({ messages: firestore.FieldValue.arrayUnion({ userInput: userInput, timestamp: timestamp, intent: intentName }) }, { merge: true }); // 合并现有数据,避免覆盖历史消息 // 保留你原有的Intent处理逻辑 function welcome(agent) { agent.add('欢迎使用我的聊天机器人!'); } // ...其他Intent处理函数 let intentMap = new Map(); intentMap.set('Default Welcome Intent', welcome); // ...映射其他Intent agent.handleRequest(intentMap); });这样每次用户的消息都会被存入
chatLogs集合,用会话ID作为文档ID,方便后续按会话查询。配置Firestore安全规则
为了保证数据安全,在Firestore控制台设置安全规则,允许Cloud Functions写入数据,同时控制读取权限:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /chatLogs/{sessionId} { // 允许Cloud Functions(服务账号)写入 allow create, update: if request.auth.token.email_verified; // 测试阶段可临时开放读取,上线后需根据需求限制 allow read: if true; } } }
二、聊天结束后在后续页面展示存储的信息
需要在网页端管理会话ID,并通过会话ID从Firestore拉取数据展示:
网页端自定义会话ID
嵌入Dialogflow网页演示iframe时,不要用默认会话,自己生成唯一会话ID(比如UUID),并存入本地存储:<!-- 引入UUID库(从CDN获取) --> <script src="https://cdn.jsdelivr.net/npm/uuid@9.0.0/dist/umd/uuidv4.min.js"></script> <script> // 生成唯一会话ID const sessionId = uuidv4(); // 存入localStorage,供后续页面使用 localStorage.setItem('chatSessionId', sessionId); // 动态设置iframe的src,传入会话ID document.getElementById('chat-iframe').src = `https://console.dialogflow.com/api-client/demo/embedded/[你的代理ID]?sessionId=${sessionId}`; </script> <iframe id="chat-iframe" width="350" height="430" frameborder="0" scrolling="no"></iframe>后续页面拉取并展示聊天记录
可以选择两种方式:直接用Firebase Web SDK读取,或通过Cloud Functions封装接口读取。方式一:用Firebase Web SDK直接读取
在后续页面引入Firebase SDK,配置后读取对应会话的记录:
<div id="chat-history"></div> <script type="module"> import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js"; import { getFirestore, doc, getDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js"; // 你的Firebase配置(从Google Cloud控制台获取) const firebaseConfig = { apiKey: "[你的API_KEY]", authDomain: "[你的AUTH_DOMAIN]", projectId: "[你的PROJECT_ID]", storageBucket: "[你的STORAGE_BUCKET]", messagingSenderId: "[你的SENDER_ID]", appId: "[你的APP_ID]" }; const app = initializeApp(firebaseConfig); const db = getFirestore(app); // 获取本地存储的会话ID const sessionId = localStorage.getItem('chatSessionId'); if (sessionId) { const chatLogRef = doc(db, 'chatLogs', sessionId); const docSnap = await getDoc(chatLogRef); if (docSnap.exists()) { const chatData = docSnap.data(); const chatContainer = document.getElementById('chat-history'); // 渲染聊天记录 chatData.messages.forEach(msg => { const msgElement = document.createElement('div'); msgElement.innerHTML = ` <p><strong>用户输入:</strong> ${msg.userInput}</p> <small>时间: ${new Date(msg.timestamp).toLocaleString()}</small> <hr> `; chatContainer.appendChild(msgElement); }); } else { document.getElementById('chat-history').innerHTML = '<p>暂无聊天记录</p>'; } } </script>方式二:通过Cloud Functions接口读取
如果不想在前端暴露Firebase配置,可以写一个Cloud Functions HTTP接口:
exports.getChatHistory = functions.https.onRequest(async (req, res) => { const sessionId = req.query.sessionId; if (!sessionId) { return res.status(400).send('缺少sessionId参数'); } const chatLogRef = firestore.collection('chatLogs').doc(sessionId); const docSnap = await getDoc(chatLogRef); if (docSnap.exists()) { res.status(200).json(docSnap.data()); } else { res.status(404).json({ message: '聊天记录不存在' }); } });然后在后续页面用fetch调用接口:
<div id="chat-history"></div> <script> const sessionId = localStorage.getItem('chatSessionId'); if (sessionId) { fetch(`https://[你的Cloud Functions区域]-[项目ID].cloudfunctions.net/getChatHistory?sessionId=${sessionId}`) .then(res => res.json()) .then(data => { const chatContainer = document.getElementById('chat-history'); if (data.messages) { data.messages.forEach(msg => { const msgElement = document.createElement('div'); msgElement.innerHTML = ` <p><strong>用户输入:</strong> ${msg.userInput}</p> <small>时间: ${new Date(msg.timestamp).toLocaleString()}</small> <hr> `; chatContainer.appendChild(msgElement); }); } else { chatContainer.innerHTML = '<p>暂无聊天记录</p>'; } }) .catch(err => console.error('获取记录失败:', err)); } </script>
内容的提问来源于stack exchange,提问作者김연우

