【Dueros技能开发】人人可做开发者——零基础如何从头开发一个自定义技能
蓝兰兰111 发布于2019-08-07 19:55 浏览:263 回复:1
1
收藏

准备工作

       开始开发一个技能要做的准备工作就是首先要在平台上选择一个技能类型,我们这里以自定义技能为演示说明:

       1.为技能起一个朗朗上口,突出内容的名称;

       2.在控制台中申请一个自定义技能;

       3.为自定义技能设置logo图标

设置意图

       创建了技能就可以为技能添加意图了,就像上篇文章说的,意图就像是一个一个执行函数,所以我们这里直接通过控制台来创建意图。以创建一个音乐播放技能为演示,我们需要创建的意图就是歌曲的切换、播放、暂停等。

       1.给意图添加名称和调用名称

       在这里我们要为意图设置一个标识名称和调用名称,调用名称是我们在代码中用来捕获意图使用的。

       

       2.添加槽位

       设置好意图之后,就需要为意图添加槽位,以及常用表达,并且在常用表达中标识出对应的槽位,上一篇文章也说了,槽位就是参数,如果是必要槽位,还可以在控制台中设置追问语句。

       

       3.添加词典

       如果多个槽位同属于一类,还可以建造词典,将同属于一类的槽位归属于同一个词典中,便于调用。

       

       添加好意图之后就可以在代码中开发,将不同的意图串联起来,共同实现技能中的各个功能。

代码说明

       代码的开发可以在部署服务中的代码编辑中直接粘贴代码,不需要手动部署,平台会自动部署,修改之后点击保存代码即可。这里选择的是基于node.js来开发的,擅长其他语言开发的同学,可以选择其他语言类型。

       

 

       1.引入bot-sdk

const Bot = require('bot-sdk');   

       2.初始化项目

const privateKey = require("./rsaKeys.js").privateKey;
class DuerOSBot extends Bot {
    constructor(postData) {
        super(postData);
        this.curIndex = 0;
        this.waitAnswer();
        this.addLaunchHandler(() => {
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                directives: [this.getDirective(0)],
                outputSpeech: '欢迎使用技能!',
            };
        });

        // 退出技能
        this.addSessionEndedHandler(() => {
            let directive = new Bot.Directive.AudioPlayer.Stop();
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                outputSpeech: '退出技能!'
            };
        });

        /**
         * 
         
         具体技能处理
         
         * 
         */

    } 
}


exports.handler = function(event, context, callback) {
    try {
        let b = new DuerOSBot(event);
        // 0: debug  1: online
        b.botMonitor.setEnvironmentInfo(privateKey, 0);
        b.run().then(function(result) {
            callback(null, result);
        }).catch(callback);
    } catch (e) {
        callback(e);
    }
}

       3.捕获意图

 //  开始播放
        this.addIntentHandler('audio_play_intent', () => {
            this.waitAnswer();  //不结束回话,即shouldEndSession为false。
            this.setExpectSpeech(false);  //端关闭麦克风,不继续监听
            return {
                directives: [this.getDirective(0), this.getTemplate2(musics[this.curIndex], 'play')],
                outputSpeech: `闭上眼睛,让我们一起来听${musics[this.curIndex].name}`
            };
        });

        // 默认意图
        this.addDefaultEventListener(event => {
            this.waitAnswer();  //不结束回话,即shouldEndSession为false。
            this.setExpectSpeech(false);  //端关闭麦克风,不继续监听
        });

        // 屏幕事件
        this.addEventListener('AudioPlayer.PlaybackStarted', event => {
            this.waitAnswer();
            this.setExpectSpeech(false);
            this.setSessionAttr(event);
        });

        this.addEventListener('AudioPlayer.PlaybackStopped', event => {
            this.waitAnswer();
            this.setExpectSpeech(false);
            this.setSessionAttr(event);
        });

        this.addEventListener('AudioPlayer.PlaybackFinished', event => {
            this.waitAnswer();
            this.setExpectSpeech(false);
            let token = this.getSessionAttribute('token');
            this.updateNextSingIndex(token);
            return {
                directives: [this.getDirective(0), this.getTemplate2(musics[this.curIndex], 'play')],
                shouldEndSession: true,
                outputSpeech: `${musics[this.curIndex].singer} 一起来听 ${musics[this.curIndex].name}`
            };
        });

        // 上一首
        this.addIntentHandler('ai.dueros.common.previous_intent', () => {
            this.waitAnswer();
            this.setExpectSpeech(false);
            let token = this.getSessionAttribute('token');
            this.updatePreviousSingIndex(token);
            return {
                directives: [this.getDirective(0), this.getTemplate2(musics[this.curIndex], 'play')],
                shouldEndSession: true,
                outputSpeech: `${musics[this.curIndex].singer} 一起来听${musics[this.curIndex].name}...`
            };
        });

        // 下一首
        this.addIntentHandler('ai.dueros.common.next_intent', () => {
            let token = this.getSessionAttribute('token');
            this.updateNextSingIndex(token);
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                directives: [this.getDirective(0), this.getTemplate2(musics[this.curIndex], 'play')],
                shouldEndSession: true,
                outputSpeech: `${musics[this.curIndex].singer} 一起来听 ${musics[this.curIndex].name}...`
            };
        });

        // 继续播放
        this.addIntentHandler('ai.dueros.common.continue_intent', () => {
            let token = this.getSessionAttribute('token');
            let offsetInMilliSeconds = this.getSessionAttribute('offsetInMilliSeconds');
            this.updateCurrentSingIndex(token);
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                directives: [this.getDirective(offsetInMilliSeconds), this.getTemplate2(musics[this.curIndex], 'play')],
                shouldEndSession: true,
                outputSpeech: `继续播放 ${musics[this.curIndex].name}`
            };
        });

        // 暂停播放
        this.addIntentHandler('ai.dueros.common.pause_intent', () => {
            let directive = new Bot.Directive.AudioPlayer.Stop();
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                directives: [directive, this.getTemplate2(musics[this.curIndex], 'pause')],
                shouldEndSession: true,
                outputSpeech: '暂停播放'
            };
        });

        // 开始播放
        this.addIntentHandler('playMusic', () => {
            let bodyTemplate = new Bot.Directive.Display.Template.BodyTemplate1();
            bodyTemplate.setToken("789789789"),
                bodyTemplate.setBackGroundImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1544247628800&di=94ed9e5ca8771d50a28da07d984d8a7a&imgtype=0&src=http%3A%2F%2Fphoto.orsoon.com%2F180128%2FCollection_of_beautiful%2FiI4zsOrFhE.jpg"),
                bodyTemplate.setTitle("音乐技能"),
                bodyTemplate.setPlainTextContent("欢迎来到音乐技能")

            let renderTemplate = new Bot.Directive.Display.RenderTemplate(bodyTemplate);
            return {
                directives: [renderTemplate],
                shouldEndSession: true,
                outputSpeech: '欢迎来到技能,请对我说开始播放'
            };
        });

        //  退出技能
        this.addIntentHandler('exit', () => {
            let directive = new Bot.Directive.AudioPlayer.Stop();
            this.waitAnswer();
            this.setExpectSpeech(false);
            return {
                directives: [directive, this.getTemplate2('退出音乐技能,欢迎下次再来!', 'pause')],
                outputSpeech: '退出音乐技能,欢迎下次再来!'
            };
        });

       4.处理意图

       可以在技能中调用一个独立方法,可以在定义的构造函数之外定义一些处理函数,然后在技能中调用。

/**
         *  更新下一曲的index
         *
         *  @param {string} token 歌曲的id
         */
    updateNextSingIndex(token) {
        let self = this;
        musics.map((music, i) => {
            if (music.token === token) {
                self.curIndex = parseInt(i, 10) + 1 <= musics.length - 1 ? parseInt(i, 10) + 1 : 0;
            }
            return null;
        });
    }

    /**
     *  更新上一首的index
     *
     *  @param {string} token 歌曲的id
     */
    updatePreviousSingIndex(token) {
        let self = this;
        musics.map((music, i) => {
            if (music.token === token) {
                self.curIndex = parseInt(i) - 1 >= 0 ? parseInt(i) - 1 : 0;
            }
            return null;
        });
    }

    /**
     *  更新当前正在播放歌曲的index
     *
     *  @param {string} token 歌曲的id
     */
    updateCurrentSingIndex(token) {
        let self = this;
        musics.map(function (music, i) {
            if (music.token === token) {
                self.curIndex = parseInt(i);
            }
            return null;
        });
    }

    /**
     *  获取歌曲播放指令
     *
     *  @param {number} offset 歌曲播放的进度
     *  @return {Bot.Directive.AudioPlayer.Play} Play指令
     */
    getDirective(offset = 0) {
        let directive = new Bot.Directive.AudioPlayer.Play(musics[this.curIndex].url);
        directive.setToken(musics[this.curIndex].token);
        this.setSessionAttribute('token', musics[this.curIndex].token);
        directive.setOffsetInMilliSeconds(offset);
        return directive;
    }

    /**
     *  获取上图下文模版
     *
     *  @param {Object} music 歌曲详情
     *  @return {RenderTemplate} 渲染模版
     */
    getTemplate2(music, status) {
        let bodyTemplate = new Bot.Directive.Display.Template.BodyTemplate2();
        bodyTemplate.setToken(music.token);
        bodyTemplate.setBackGroundImage(status == 'play' ? default_image : pause_image);
        bodyTemplate.setTitle(music.singer);
        bodyTemplate.setPlainContent(music.name);
        let renderTemplate = new Bot.Directive.Display.RenderTemplate(bodyTemplate);
        return renderTemplate;
    }

    /**
     *  获取文本展现模板
     *
     *  @param {string} text 歌曲详情
     *  @return {RenderTemplate} 渲染模版
     */
    getTemplate1(text) {
        let bodyTemplate = new Bot.Directive.Display.Template.BodyTemplate1();
        bodyTemplate.setPlainTextContent(text);
        let renderTemplate = new Bot.Directive.Display.RenderTemplate(bodyTemplate);
        return renderTemplate;
    }

    /**
     *  设置会话属性
     *
     *  @param {Object} event 客户端上报的事件,包含歌曲token和对应播放进度等信息
     */
    setSessionAttr(event) {
        this.setSessionAttribute('token', event.token);
        this.setSessionAttribute('offsetInMilliSeconds', event.offsetInMilliSeconds);
    }

       5.技能测试

       添加好技能之后就可以在控制台的模拟器上或者直接使用真机进行测试。

       

 

       测试通过之后,就可以申请上线了,发布自己的创建的一个小技能啦。

 

 

收藏
点赞
1
个赞
共1条回复 最后由DuerOS-首席布道师回复于2019-08-08 13:36
#2DuerOS-首席布道师回复于2019-08-08

不错,有心人

0
TOP