重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章给大家介绍如何使用nodejs BOT SDK开发问答类技能模板,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
创新互联公司于2013年创立,是专业互联网技术服务公司,拥有项目成都网站设计、网站制作网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元晋城做网站,已为上家服务,为晋城各地企业和个人服务,联系电话:18980820575
问答技能模板是针对问答类技能设计的模板,如知识问答、生活常识问题等。本文从问答类技能交互、部署讲述如何快速搭建问答类技能。
问答类技能与用户的交互方式是技能从题库列表中选出一道题,并提供四个选项,其中有一个选项是正确的。用户通过说出正确选项的顺序来答题。
下面以古诗问答
技能为例,描述问答类技能与用户交互过程。技能从古诗列表中选取一首诗让用户说出诗的作者,并依次读出四个作者选项。用户说出正确的作者的选项顺序,回答正确后技能会记录用户得分。技能交互过程如下:
用户:打开古诗问答
技能:[技能欢迎语]。开始答题。第一题:离离原上草 一岁一枯荣的作者是谁。 1,李白 2,白居易 3,杜甫 4,柳宗元
用户:第二个
技能:回答正确,得一分。目前的积分是1分。第二题。。。
技能从题库中选取问题,可以杜绝题目重复和答案排列顺序重复的问题。开发者只需要更新题目列表和相应的技能配置信息,即可生成新的技能并在DuerOS DBP平台上发布。题库的存储方式如下,其中正确答案需要放在答案的第一个位置,格式如下。
{ '题目': [ '正确答案', '错误答案', '错误答案', '错误答案', ], },
上面古诗问答的例子在题库中的展现形式是:
{ '第一题:离离原上草 一岁一枯荣的作者是谁。': [ '白居易', '李白', '杜甫', '柳宗元', ], '第二题:白日依山尽,黄河入海流,出自那首诗。': [ '登鹳雀楼', '...', '...', '...', ], },
其中正确答案“白居易”和“登鹳雀楼”放在第一个位置,但是在给用户出题时,选项的顺序会调整。
模板的使用说明:
答案中必须有一个正确答案。
每道题的答案选项可以是3个,4个,5个,选项总数不收限制。
每个题目必须通过选项序号来作答,如用户必须说“第一个”、“第二个”,不能使用“是”、“对”、“错”、“不是”等进行回答。
请注意,下面的新建技能和配置意图过程可以通过在技能平台-->创建技能-->引用技能-->导入技能页面导入 http://dbp-cfc.cdn.bcebos.com/download/trivia.zip 实现。
新建技能详情请参阅自定义技能创建
意图配置详情请参阅意图、常用表达和槽位
问答技能模板需要创建两个意图,分别是回答问题意图和重新开始问答意图。 回答问题意图如下图所示:
重新开始问答意图如下图所示:
问答技能模板使用CFC部署技能服务。使用CFC部署技能服务详情请参阅 百度云CFC
问答技能模板使用questions.js配置题库。开发者需要下载技能CFC函数完整zip程序包到本地进行开发,开发完成后上传函数zip包进行发布。具体流程如下:
在CFC控制台通过模板创建函数, 选择node.js DuerOS Bot SDK模板
函数生成后,在函数控制台点击点击下载完整 ZIP 程序包
链接下载程序包
在本地解压程序包
将https://github.com/dueros/bot-sdk-node.js/blob/master/samples/trivia/questions.js文件拷贝到程序包文件夹中
使用https://github.com/dueros/bot-sdk-node.js/blob/master/samples/trivia/index.js替换程序包文件夹中的index.js文件
将程序包文件夹中的所有文件重新打包成zip文件
在函数控制台上传zip程序包并保存
CFC操作说明请参阅函数计算 CFC
const Bot = require('bot-sdk'); const privateKey = require("./rsaKeys.js").privateKey; const question_list = [ { '远上还山石径斜,白云深处有人家': [ '正确的', '杜甫', '白居易', '李白', ], }, { '离离原上草,一岁一枯荣': [ '正确的', '杜甫', '白居易', '李白', ], }, { '举头望明月,低头思故乡': [ '正确的', '杜甫', '白居易', '李白', ], }, { '锄禾日当午 汗滴禾下土': [ '正确的', '杜甫', '白居易', '李白', ], }, { '白日依山尽,黄河入海流': [ '正确的', '杜甫', '白居易', '李白', ], }, { '李白乘舟将欲行,忽闻岸上踏歌声': [ '正确的', '杜甫', '白居易', '李白', ], }, { '横看成岭侧成峰,远近高低各不同': [ '正确的', '杜甫', '白居易', '李白', ], }, { '人生自古谁无死,留取丹心照汗青': [ '文天祥', '杜甫', '白居易', '李白', ], } ]; //定义一轮问答中的问题数量 const GAME_LENGTH = 5; //定义每个问题的答案数量 const ANSWER_COUNT = 3; class InquiryBot extends Bot { constructor(postData) { super(postData); this.addLaunchHandler(() => { this.waitAnswer(); let speechOutput = '欢迎来到古诗问答。我将念两句古诗并给你三个诗人的名字。需要你告诉我哪一个是正确的作者。'; //初始化一轮中的问题列表和第一题的话术 let repromptText = this.startNewGame(); let card = new Bot.Card.TextCard(repromptText); return { card: card, outputSpeech: speechOutput + repromptText }; }); this.addSessionEndedHandler(() => { this.endSession(); return { outputSpeech: '谢谢使用!' }; }); this.addIntentHandler('answer_intent', () => { this.waitAnswer(); //确保获取到了用户的回答 let theAnswer = this.getSlot('theAnswer'); if (!theAnswer) { this.nlu.ask('theAnswer'); return { outputSpeech: '您的答案是哪个?' }; } //获取session中相关信息 let questionsList = this.getSessionAttribute('questionsList'); let score = this.getSessionAttribute('score'); let currentQuestionIndex = this.getSessionAttribute('currentQuestionIndex'); let correctAnswerIndex = this.getSessionAttribute('correctAnswerIndex'); let gameQuestions = this.getSessionAttribute('gameQuestions'); let correctAnswerText = this.getSessionAttribute('correctAnswerText'); let speechOutput = ''; if (theAnswer == correctAnswerIndex){ score += 1; speechOutput = '回答正确,得一分。目前得分:' + score + '分。'; }else{ speechOutput = '很遗憾,回答错误。正确答案是' + correctAnswerText + '.目前得分:' + score + '分。'; } //到达最后一题,用户选择重新开始一轮或者退出技能 if (currentQuestionIndex == GAME_LENGTH - 1){ speechOutput += '已经是最后一题了。您可以说重新开始来继续答题,或者说退出来退出技能。' return { outputSpeech: speechOutput }; } //获取下一题信息 currentQuestionIndex += 1; correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT)); let spokenQuestion = Object.keys(questionsList[gameQuestions[currentQuestionIndex]])[0]; let roundAnswers = this.populateRoundAnswers(gameQuestions, currentQuestionIndex,correctAnswerIndex,questionsList); let questionIndexForSpeech = currentQuestionIndex + 1; let repromptText = '第' + questionIndexForSpeech + '题:\n' + spokenQuestion + '\n'; for (let i = 0; i < ANSWER_COUNT; i += 1) { repromptText += `${i + 1}. ${roundAnswers[i]}. `; } speechOutput += repromptText; let currentQuestion = questionsList[gameQuestions[currentQuestionIndex]]; this.setSessionAttribute('speechOutput',speechOutput); this.setSessionAttribute('currentQuestionIndex',currentQuestionIndex); this.setSessionAttribute('correctAnswerIndex',correctAnswerIndex + 1); this.setSessionAttribute('gameQuestions',gameQuestions); this.setSessionAttribute('questionsList',questionsList); this.setSessionAttribute('score',score); this.setSessionAttribute('correctAnswerText',currentQuestion[Object.keys(currentQuestion)[0]][0]); let card = new Bot.Card.TextCard(repromptText); return { card: card, outputSpeech: speechOutput }; }); //重新开始答题,得分清零 this.addIntentHandler('newGame_intent', () => { this.waitAnswer(); //初始化一轮中的问题列表和第一题的话术 let repromptText = this.startNewGame(); let card = new Bot.Card.TextCard(repromptText); return { card: card, outputSpeech: '好的,重新开始。' + repromptText }; }); /* * 获取没有被意图解析的用户输入,并进行相关处理 * 缺省意图 https://developer.dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-nlu/defaultIntent_markdown */ this.addIntentHandler('ai.dueros.common.default_intent', () => { this.waitAnswer(); return { outputSpeech: '您可以对我说第几个来告诉我您的答案。您也可以说重新开始重新玩,或者说退出来退出游戏。' }; }); } /** * 获取新一轮问题列表和相应的信息,并将信息存入session中 * * @return 新一轮答题话术 */ startNewGame() { let questionsList = question_list; let gameQuestions = this.populateGameQuestions(questionsList); let correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT)); console.log(correctAnswerIndex); let roundAnswers = this.populateRoundAnswers(gameQuestions, 0,correctAnswerIndex,questionsList); let currentQuestionIndex = 0; let spokenQuestion = Object.keys(questionsList[gameQuestions[currentQuestionIndex]])[0]; let repromptText = '第1题:\n' + spokenQuestion + '\n'; for (let i = 0; i < ANSWER_COUNT; i += 1) { repromptText += `${i + 1}. ${roundAnswers[i]}. `; } let currentQuestion = questionsList[gameQuestions[currentQuestionIndex]]; this.setSessionAttribute('currentQuestionIndex',currentQuestionIndex); this.setSessionAttribute('correctAnswerIndex',correctAnswerIndex + 1); this.setSessionAttribute('gameQuestions',gameQuestions); this.setSessionAttribute('questionsList',questionsList); this.setSessionAttribute('score',0); this.setSessionAttribute('correctAnswerText',currentQuestion[Object.keys(currentQuestion)[0]][0]); return repromptText; } /** * 从问题列表中随机抽取问题。问题个数由变量GAME_LENGTH定义 * @param {list} translatedQuestions 所有问题列表 * @return 问题id列表 */ populateGameQuestions(translatedQuestions) { let gameQuestions = []; let indexList = []; let index = translatedQuestions.length; if (GAME_LENGTH > index) { throw new Error('Invalid Game Length.'); } for (let i = 0; i < translatedQuestions.length; i += 1) { indexList.push(i); } for (let j = 0; j < GAME_LENGTH; j += 1) { let rand = Math.floor(Math.random() * index); index -= 1; let temp = indexList[index]; indexList[index] = indexList[rand]; indexList[rand] = temp; gameQuestions.push(indexList[index]); } return gameQuestions; } /** * 从问题列表中随机抽取问题。问题个数由变量GAME_LENGTH定义 * @param {list} gameQuestionIndexes 一轮问答中问题id列表 * @param {int} currentQuestionIndex 当前问题Index * @param {int} correctAnswerTargetLocation 当前问题答案Index * @param {list} translatedQuestions 所有问题列表 * @return 当前问题答案选项列表 */ populateRoundAnswers(gameQuestionIndexes,currentQuestionIndex,correctAnswerTargetLocation,translatedQuestions) { const answers = []; const translatedQuestion = translatedQuestions[gameQuestionIndexes[currentQuestionIndex]]; const answersCopy = translatedQuestion[Object.keys(translatedQuestion)[0]].slice(); let index = answersCopy.length; if (index < ANSWER_COUNT) { throw new Error('Not enough answers for question.'); } // 打乱当前问题答案列表顺序 for (let j = 1; j < answersCopy.length; j += 1) { const rand = Math.floor(Math.random() * (index - 1)) + 1; index -= 1; const swapTemp1 = answersCopy[index]; answersCopy[index] = answersCopy[rand]; answersCopy[rand] = swapTemp1; } // 将正确答案放置到correctAnswerTargetLocation的位置 for (let i = 0; i < ANSWER_COUNT; i += 1) { answers[i] = answersCopy[i]; } const swapTemp2 = answers[0]; answers[0] = answers[correctAnswerTargetLocation]; answers[correctAnswerTargetLocation] = swapTemp2; return answers; } } exports.handler = function(event, context, callback) { try { let b = new InquiryBot(event); // 0: debug 1: online b.botMonitor.setEnvironmentInfo(privateKey, 0); b.run().then(function(result) { callback(null, result); }).catch(callback); } catch (e) { callback(e); } }
至此,问答技能就开发完成了。开发者可以在技能开放平台的模拟测试页面对技能进行测试。
关于如何使用nodejs BOT SDK开发问答类技能模板就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。