千家信息网

如何使用nodejs BOT SDK开发问答类技能模板

发表于:2025-02-05 作者:千家信息网编辑
千家信息网最后更新 2025年02月05日,这篇文章给大家介绍如何使用nodejs BOT SDK开发问答类技能模板,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。问答技能模板问答技能模板是针对问答类技能设计的模板,如知识问
千家信息网最后更新 2025年02月05日如何使用nodejs BOT SDK开发问答类技能模板

这篇文章给大家介绍如何使用nodejs BOT SDK开发问答类技能模板,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

问答技能模板

问答技能模板是针对问答类技能设计的模板,如知识问答、生活常识问题等。本文从问答类技能交互、部署讲述如何快速搭建问答类技能。

问答技能模板的交互模型

问答类技能与用户的交互方式是技能从题库列表中选出一道题,并提供四个选项,其中有一个选项是正确的。用户通过说出正确选项的顺序来答题。

下面以古诗问答技能为例,描述问答类技能与用户交互过程。技能从古诗列表中选取一首诗让用户说出诗的作者,并依次读出四个作者选项。用户说出正确的作者的选项顺序,回答正确后技能会记录用户得分。技能交互过程如下:

用户:打开古诗问答

技能:[技能欢迎语]。开始答题。第一题:离离原上草 一岁一枯荣的作者是谁。 1,李白 2,白居易 3,杜甫 4,柳宗元

用户:第二个

技能:回答正确,得一分。目前的积分是1分。第二题。。。

技能从题库中选取问题,可以杜绝题目重复和答案排列顺序重复的问题。开发者只需要更新题目列表和相应的技能配置信息,即可生成新的技能并在DuerOS DBP平台上发布。题库的存储方式如下,其中正确答案需要放在答案的第一个位置,格式如下。

{  '题目': [    '正确答案',    '错误答案',    '错误答案',    '错误答案',  ],},

上面古诗问答的例子在题库中的展现形式是:

{  '第一题:离离原上草 一岁一枯荣的作者是谁。': [    '白居易',    '李白',    '杜甫',    '柳宗元',  ],  '第二题:白日依山尽,黄河入海流,出自那首诗。': [    '登鹳雀楼',    '...',    '...',    '...',  ],},

其中正确答案"白居易"和"登鹳雀楼"放在第一个位置,但是在给用户出题时,选项的顺序会调整。

模板的使用说明

答案中必须有一个正确答案。

每道题的答案选项可以是3个,4个,5个,选项总数不收限制。

每个题目必须通过选项序号来作答,如用户必须说"第一个"、"第二个",不能使用"是"、"对"、"错"、"不是"等进行回答。

使用模板开发技能的流程

请注意,下面的新建技能和配置意图过程可以通过在技能平台-->创建技能-->引用技能-->导入技能页面导入 http://dbp-cfc.cdn.bcebos.com/download/trivia.zip 实现。

新建技能

新建技能详情请参阅自定义技能创建

配置意图

意图配置详情请参阅意图、常用表达和槽位

问答技能模板需要创建两个意图,分别是回答问题意图和重新开始问答意图。 回答问题意图如下图所示:

重新开始问答意图如下图所示:

配置技能服务部署

问答技能模板使用CFC部署技能服务。使用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开发问答类技能模板就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0