首先,非常感谢这个出色的社区。我必须说我对编程非常新手(我更像是一名统计学家),但到目前为止,这似乎既具有挑战性又有趣!最近,我一直在挑战自己,尝试创建一个从数据库中检索数据的Dialogflow代理。我使用的是Node.js。当然,为了构建,我尝试在网上查看代码,并根据我的需求进行连贯的修改,但三天以来我一直卡住了!
我搞不清楚问题出在哪里,请帮帮我!!!
请查看下面的代码:
'use strict';const functions = require( 'firebase-functions' );const mysql = require( 'mysql' );const {WebhookClient} = require( 'dialogflow-fulfillment' );const {Text, Card, Image, Suggestion, Payload} = require( 'dialogflow-fulfillment' );process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements// Wikipedia link and image URLsconst mysiteurl = 'site URL';exports.dialogflowFirebaseFulfillment = functions.https.onRequest( ( request, response ) =>{ const agent = new WebhookClient( {request, response} ); console.log( 'Dialogflow Request headers: ' + JSON.stringify( request.headers ) ); console.log( 'Dialogflow Request body: ' + JSON.stringify( request.body ) ); function welcome( agent ){ agent.add( `Welcome to infohub personal assistant, my name is Isobel` ); agent.add( new Card( { title: `mysite`, imageUrl: mysiteurl, text: `Did you know already mysite if not visit it now! `, buttonText: 'mysite', buttonUrl: mysiteurl } ) ); agent.add( `I can help you get information already contained in mysite` ); agent.add( new Suggestion( `population` ) ); agent.add( new Suggestion( `avgincome` ) ); agent.add( new Suggestion( `thisyeargdp` ) ); } function getinfo( agent ){ // Get parameters from Dialogflow to convert const country = agent.parameters.country; const info = agent.parameters.info; console.log( `User requested to get info on ${info} in ${country}` ); if( action === 'get.data' ){ //Call the callDBJokes method output = callDB().then( ( output ) =>{ // Return the results of the weather API to API.AI response.setHeader( 'Content-Type', 'application/json' ); response.send( JSON.stringify( output ) ); } ).catch( ( error ) =>{ // If there is an error let the user know response.setHeader( 'Content-Type', 'application/json' ); response.send( JSON.stringify( error ) ); } ); } // Sent the context to store the parameter information // and make sure the followup agent.setContext( { name: 'info', lifespan: 1, parameters: {country: country, info: info} } ); // Compile and send response agent.add( ` ${info} in ${country} is ${output}` ); agent.add( `Would you like to know something else?` ); agent.add( new Suggestion( `population` ) ); agent.add( new Suggestion( `avgincome` ) ); agent.add( new Suggestion( `thisyeargdp` ) ); } function fallback( agent ){ agent.add( `I didn't get that, can you try again?` ); } function callDB( info, country ){ return new Promise( ( resolve, reject ) =>{ try{ var connection = mysql.createConnection( { host: "sql7.freemysqlhosting.net", user: "sql7243950", password: "XXXXXXXX", database: "sql7243950" } ); connection.query( 'SELECT' + info + 'FROM mocktable WHERE country=' + country, function( error, results, fields ){ if( !error ){ let response = "The solution is: " + results[0]; response = response.toString(); let output = {'speech': response, 'displayText': response}; console.log( output ); resolve( output ); } else{ let output = { 'speech': 'Error. Query Failed.', 'displayText': 'Error. Query Failed.' }; console.log( output ); reject( output ); } } ); connection.end(); } catch ( err ){ let output = { 'speech': 'try-cacth block error', 'displayText': 'try-cacth block error' }; console.log( output ); reject( output ); } } ) ; } let intentMap = new Map(); // Map functions to Dialogflow intent names intentMap.set( 'Default Welcome Intent', welcome ); intentMap.set( 'get info about mycountry', getinfo ); intentMap.set( 'Default Fallback Intent', fallback ); agent.handleRequest( intentMap );} );
回答:
这里有几个问题,有些相关,有些不相关。让我们逐一分析一些问题。
首先,你有一个比较
if( action === 'get.data' ){
但’action’在任何地方都没有定义或赋值。所以这个块永远不会被执行(看起来也不会调用数据库)。
你进行一些赋值的方式不太清楚。当你获取查询的输出时,你的代码行是
output = callDB().then( ( output ) =>{
这似乎是混合了获取Promise和尝试使用Promise完成的结果。我怀疑你想要的是第二个”output”而不是第一个,原因我希望在稍后会更清楚一些。
在那个then()
子句中,你发送回JSON,但随后(在then()
子句之外)尝试使用Dialogflow库来设置上下文、设置回复和提供建议芯片。混合使用这两种方法是行不通的 – 要么发送JSON,要么使用库。
这进一步复杂化,因为callDB()
(你在then()
之前调用的)生成要发送回的JSON。再次强调 – 选择一种方法。我认为更好的方法是让callDB()
实际调用数据库,并可能处理和返回一个Promise,包含结果供调用方法格式化为用户希望听到/看到的内容。
说到Promise,callDB()
返回一个Promise是好的。然而,你在两个方面没有正确处理这个Promise:
首先,由于getInfo()
调用异步运行的东西(即对callDB()
的调用),它也必须返回一个Promise。这就是为什么你可能不想像我上面提到的那样捕获callDB()
的结果。实现这一点的最简单方法是让你的代码做类似的事情
return callDB().then( output => { // 输出一切正常。}).catch( err => { // 输出世界末日。};
处理Promise的第二个问题是,你当前的getInfo()
实现在这个块之后还有代码。这里是你进行所有agent.setContext()
和agent.add()
调用的地方。这些必须在then()
块内。(在我的“一切正常”评论上方的地方。)