{"id":30950749,"url":"https://github.com/jokenwang/bot-sdk-python","last_synced_at":"2026-02-26T23:01:42.717Z","repository":{"id":57424510,"uuid":"115860874","full_name":"jokenwang/bot-sdk-python","owner":"jokenwang","description":null,"archived":false,"fork":false,"pushed_at":"2020-08-30T08:21:54.000Z","size":18522,"stargazers_count":65,"open_issues_count":5,"forks_count":26,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-09-30T15:02:27.666Z","etag":null,"topics":["bot","dueros","python3"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jokenwang.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-31T12:08:29.000Z","updated_at":"2024-05-13T09:46:48.000Z","dependencies_parsed_at":"2022-09-07T03:40:32.645Z","dependency_job_id":null,"html_url":"https://github.com/jokenwang/bot-sdk-python","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/jokenwang/bot-sdk-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jokenwang%2Fbot-sdk-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jokenwang%2Fbot-sdk-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jokenwang%2Fbot-sdk-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jokenwang%2Fbot-sdk-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jokenwang","download_url":"https://codeload.github.com/jokenwang/bot-sdk-python/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jokenwang%2Fbot-sdk-python/sbom","scorecard":{"id":529508,"data":{"date":"2025-08-11","repo":{"name":"github.com/jokenwang/bot-sdk-python","commit":"d10d681f08777fac4ccf011427efe3f121185b7f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-j225-cvw7-qrx7","Warn: Project is vulnerable to: PYSEC-2018-24 / GHSA-2rcm-phc9-3945","Warn: Project is vulnerable to: PYSEC-2013-31 / GHSA-6748-36qp-fx6r","Warn: Project is vulnerable to: PYSEC-2018-23 / GHSA-p28m-34f6-967q","Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h","Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T05:22:17.995Z","repository_id":57424510,"created_at":"2025-08-20T05:22:17.995Z","updated_at":"2025-08-20T05:22:17.995Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29876340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T22:37:10.609Z","status":"ssl_error","status_checked_at":"2026-02-26T22:37:09.019Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","dueros","python3"],"created_at":"2025-09-11T05:18:39.607Z","updated_at":"2026-02-26T23:01:42.703Z","avatar_url":"https://github.com/jokenwang.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bot-sdk\n\n\n# 自愿资助\n* 如果感觉还不错，可以用微信扫码请我喝杯咖啡，谢谢！\n* ![image](http://www.aiaibot.xyz/WX_SK.png)\n\n### SDK结构介绍\n* Bot.py为SDK的入口，用于接收DuerOS请求并返回结果\n* Nlu.py负责对请求关键信息的提取，如槽位、意图信息等\n* Request.py技能接收到DuerOS的数据全部交给Request进行处理，Request再委托Nlu、Session对数据做处理\n* Response.py技能数据处理完后交由Response封装结果返回DuerOS\n* Session.py处理会话信息\n* Certificate.py封装DuerOS和技能通信认证\n* card目录处理展示卡片相关\n* directive目录生成指令相关比如：浏览器指令、音频指令、DPL指令\n* tests 目录存放本地测试代码\n* samples 示例demo，其中包括guess_num、audio_play、personal_income_tax\n* 新增Docker镜像\n\n\n\n###\n**注意:Bot内的属性变为私有，无法再通过self获取request、nlu等属性，对应\n的方法统一通过self.方法来调用**\n\n### 安装、使用BOT SDK进行开发\n\n1、 通过pip进行安装   \n\n```\npip install dueros-bot\n```\n  \n2、 下载源码安装\n    \n* 通过GitHub获取最新源码\n```\ngit clone https://github.com/jokenwang/bot-sdk-python.git\n```\n\n* 通过Pypi获取最新发布版本源码\n\n    * dueros-bot-2.1.2 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/2.1.2)\n    * dueros-bot-2.0.0 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/2.0.0)\n    * dueros-bot-1.1.0 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/1.1)\n    * dueros-bot-0.2.4 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/0.2.4)\n    * dueros-bot-0.2.3 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/0.2.3)\n    * dueros-bot-0.2.2 [Pypi地址](https://pypi.python.org/pypi/dueros-bot/0.2.2)\n\n下载bot-sdk代码后，可以使用如下命令安装:\n```python\npython setup.py install\n```\n\n3、sh start.sh 运行，如出现问题请参考[常见问题](#常见问题)\n\n4、运行tests目录下的 \n```bash\nsh postData.sh json/xxx.json\n```\n\n将xxx.json文件内容发送模拟数据到服务器\n\n5、开发教程\n\n为了开始使用BOT SDK，你需要先新建一个python文件，比如文件名是Bot.py,该文件需要继承sdk/Bot.py。下一步，我们处理意图，Bot-sdk提供个函数来handle这些意图,例如继承sdk/Bot.py中的add_intent_handler函数，添加一个意图处理函数，比如，为新建闹钟，创建一个handler，在构造函数中添加：\n\n```python\nself.add_intent_handler('remind', self.createRemind)\ndef createRemind(self):\n    remindTime = self.get_slots('remindTime')\n    if remindTime:\n        card = new TextCard('创建中')\n        return {\n            'card': card,\n        }\n```\n第一个参数代表意图名称，第二个参数代表意图命中后的回调函数，这里addHandler可以用来建立intent和handler的映射，第一个参数意图名称是条件，如果满足则执行对应的回调函数(第二个参数)。 其中回调函数中，self指向当前的Bot，getSlots继承自父类Bot，通过slot名字来获取对应的槽位值。回调函数返回值是一个字典，可以包含多个字段，比如：card、directives、outputSpeech、reprompt等,下面会一一给出示例。\n\n\n### Docker镜像\n```\ndocker pull tokensss/dueros:v1.0\n```\n\n### 设备相关(Bot方法)\n* 客户端是否支持屏幕展示\n```python\n    bot.is_support_display()\n```\n\n* 客户端是否支持音频播放\n```python\n    bot.is_support_audio_player()\n```\n\n* 客户端是否支持视频播放\n```python\n    bot.is_support_audio_player()\n```\n\n### card展示卡片\n* 文本卡片:TextCard\n```python\ncard = TextCard('content')\nor \ncard = TextCard()\n//设置链接\ncard.set_anchor('http://www.baidu.com')\n//设置cueWords\ncard.add_cue_words('hint1')\n```\n* 标准卡片 StandardCard\n```python\ncard = StandardCard()\ncard.set_title('title')\ncard.set_content('content')\ncard.set_image('http://www...')\ncard.set_anchor('http://www.baidu.com')\n```\n* 列表卡片ListCard\n```python\ncard = new ListCard()\nitem = new ListCardItem()\nitem.set_title('title')\nitem.set_content('content')\nitem.set_url('http://www')\nitem.set_image('http://www.png')\ncard.add_item(item)\n```\n* 图片卡片ImageCard\n```python\ncard = ImageCard()\ncard.add_item('http://src.image', 'http://thumbnail.image');\n```\n\n* 用户授权LinkAccountCard\n```python\ncard = LinkAccountCard()\n```\n\n### 文本展现模板\n* BodyTemplate1\n```python\n\nbodyTemplate = BodyTemplate1()\nbodyTemplate.set_token('token')\n#设置模版背景图片\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nbodyTemplate.set_title('托尔斯泰的格言')\n#设置模版plain类型的文本\nbodyTemplate.set_plain_text_content('拖尔斯泰-理想的书籍是智慧的钥匙') \n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是BodyTemplate1模板'\n}\n```\n### 上图下文模版\n* BodyTemplate2\n```python\nbodyTemplate = BodyTemplate2()\n#设置模版token\nbodyTemplate.set_token('token')\n#设置模版展示图片\nbodyTemplate.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版背景图片\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nbodyTemplate.set_title('托尔斯泰的格言')\n#设置模版plain类型的文本结构\nbodyTemplate.set_plain_content('拖尔斯泰-理想的书籍是智慧的钥匙') \n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives':[directive],\n    'outputSpeech': '这是BodyTemplate2模板'\n}\n\n```\n\n### 左图右文模版\n* BodyTemplate3\n```python\nbodyTemplate = BodyTemplate3()\n#设置模版token\nbodyTemplate.set_token('token')\n#设置模版展示图片\nbodyTemplate.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版背景图片\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nbodyTemplate.set_title('托尔斯泰的格言')\n#设置模版plain类型的文本结构\nbodyTemplate.set_plain_content('拖尔斯泰-理想的书籍是智慧的钥匙')  \n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech' : '这是BodyTemplate3模板'\n}\n```\n\n### 右图左文\n* BodyTemplate4\n```python\nbodyTemplate = BodyTemplate4()\nbodyTemplate.set_token('token')\n#设置模版展示图片\nbodyTemplate.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版背景图片\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nbodyTemplate.set_title('托尔斯泰的格言')\n#设置模版plain类型的文本结构\nbodyTemplate.set_plain_content('拖尔斯泰-理想的书籍是智慧的钥匙') \n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是BodyTemplate4模板'\n}\n```\n\n### 图片模板\n* BodyTemplate5\n```python\nbodyTemplate = BodyTemplate5()\n#设置模版token\nbodyTemplate.set_token('token')\n#模版图片数组添加一张图片\nbodyTemplate.add_images('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版背景图片\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nbodyTemplate.set_title('托尔斯泰的格言')\n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是BodyTemplate5模板'\n}\n```\n\n### 上图下文模版类\n```python\nbodyTemplate = BodyTemplate6()\nbodyTemplate.set_token('token')\nbodyTemplate.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nbodyTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nbodyTemplate.set_title('托尔斯泰的格言')\nbodyTemplate.set_plain_content('拖尔斯泰-理想的书籍是智慧的钥匙')\n#定义RenderTemplate指令\ndirective = RenderTemplate(bodyTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是BodyTemplate6模板'\n}\n```\n\n### 横向列表模板\n* ListTemplate1\n```python\nlistTemplate = ListTemplate1()\n#设置模板token\nlistTemplate.set_token('token')\n#设置模板背景图\nlistTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nlistTemplate.set_title('托尔斯泰的格言')\n\n#设置模版列表数组listItems其中一项，即列表的一个元素\nlistTemplateItem = ListTemplateItem()\nlistTemplateItem.set_token('token')\nlistTemplateItem.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nlistTemplateItem.set_plain_primary_text('一级标题')\nlistTemplateItem.set_plain_secondary_text('二级标题')\n\n#把listTemplateItem添加到模版listItems\nlistTemplate.add_item(listTemplateItem)\n#定义RenderTemplate指令\ndirective = RenderTemplate(listTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是ListTemplate1模板'\n}\n```\n\n### 纵向列表模板\n* ListTemplate2\n```python\nlistTemplate = ListTemplate2()\n#设置模板token\nlistTemplate.set_token('token')\n#设置模板背景图\nlistTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nlistTemplate.set_title('托尔斯泰的格言')\n\n#设置模版列表数组listItems其中一项，即列表的一个元素\nlistTemplateItem = ListTemplateItem()\nlistTemplateItem.set_token('token')\nlistTemplateItem.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nlistTemplateItem.set_plain_primary_text('一级标题')\nlistTemplateItem.set_plain_secondary_text('二级标题')\n\n#把listTemplateItem添加到模版listItems\nlistTemplate.add_item(listTemplateItem)\n#定义RenderTemplate指令\ndirective = RenderTemplate(listTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是ListTemplate2模板'\n}\n```\n\n### 横向列表\n* ListTemplate3\n```python\nlistTemplate = ListTemplate3()\n#设置模板token\nlistTemplate.set_token('token')\n#设置模板背景图\nlistTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nlistTemplate.set_title('托尔斯泰的格言')\n\n#设置模版列表数组listItems其中一项，即列表的一个元素\nlistTemplateItem = ListTemplateItem()\nlistTemplateItem.set_token('token')\nlistTemplateItem.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nlistTemplateItem.set_plain_primary_text('一级标题')\nlistTemplateItem.set_plain_secondary_text('二级标题')\n\n#把listTemplateItem添加到模版listItems\nlistTemplate.add_item(listTemplateItem)\n#定义RenderTemplate指令\ndirective = RenderTemplate(listTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是ListTemplate3模板'\n}\n```\n\n### 纵向列表\n* ListTemplate4\n```python\nlistTemplate = ListTemplate4()\n#设置模板token\nlistTemplate.set_token('token')\n#设置模板背景图\nlistTemplate.set_background_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\n#设置模版标题\nlistTemplate.set_title('托尔斯泰的格言')\n\n#设置模版列表数组listItems其中一项，即列表的一个元素\nlistTemplateItem = ListTemplateItem()\nlistTemplateItem.set_token('token')\nlistTemplateItem.set_image('https://skillstore.cdn.bcebos.com/icon/100/c709eed1-c07a-be4a-b242-0b0d8b777041.jpg')\nlistTemplateItem.set_plain_primary_text('一级标题')\nlistTemplateItem.set_plain_secondary_text('二级标题')\n\n#把listTemplateItem添加到模版listItems\nlistTemplate.add_item(listTemplateItem)\n#定义RenderTemplate指令\ndirective = RenderTemplate(listTemplate)\nreturn {\n    'directives': [directive],\n    'outputSpeech': '这是ListTemplate4模板'\n}\n```\n\n### Tag标签\n* [Tag](https://github.com/jokenwang/bot-sdk-python/tree/master_alpha/dueros/directive/Display/tag) 标签用在List模板的每个Item上(显示在每个item的右下角)，比如:付费、免费、最新、VIP、限时、已购、最热以及自定义标签内容等\nPayTag、FreeTag、NewTag、HotTag、VipTag、TimeTag、PurchasedTag、HotTag、CustomTag、AmountTag、AuditionTag\n\n```python\nlistTemplate = ListTemplate4()\nitem = ListTemplateItem()\n#添加tag \nitem.set_image_tags(HotTag())\nlistTemplate.add_item(item)\n\n```\n\n### 音频播放\n* 音频播放 \n```python\ndirective = Play('http://www.baidu.com')\n#设置音频格式\ndirective.set_stream_format('AUDIO_M3U8')\n#上一首\nprevious = PreviousButton()\nprevious.set_selected(True)\n# 创建暂停按钮\nplaypause = PlayPauseButton()\n#下一首\nnext = NextButton()\n#可以添加多个button  比如:收藏、喜欢、播放列表等\ncontrols = [previous, playpause, NextButton()]\nplayerInfo = PlayerInfo('周杰伦 七里香', controls)\nplayerInfo.set_title('周杰伦')\nplayerInfo.set_title_subtext1('七里香')\nplayerInfo.set_art('http://adfadfa')\n# 设置Play指令的PlayerInfo\ndirective.set_player_info(playerInfo)\nreturn{\n    'directives': [directive]\n}\n```\n\n* 视频播放\n```python\ndirective = VideoPlayer('video_url', PlayBehaviorEnum.REPLACE_ENQUEUED)\ndirective.set_offset_in_milliseconds(121321)\ndirective.set_expiry_time('123213223')\ndirective.set_expected_previous_token('asdsd-1233-dsew-39FG')\ndirective.set_report_delay_in_ms(1234.12212)\ndirective.set_report_interval_in_ms(123)\ndirective.set_token('AGDG-SAHSHD_ASDS_123')\ndirective.set_url('http://set-url.com')\nreturn{\n    'directives': [directive]\n}\n```\n\n### 音频、视频播放列表\n\n* RenderAudioList 用于渲染音频播放列表。当在播放页面，点击播放列表按钮,可返回RenderAudioList用于渲染UI\n\n* RenderVideoList 用于渲染视频播放列表。当在播放页面，点击播放列表按钮,可返回RenderVideoList用于渲染UI\n\n### 页面栈 \n* PushStack 提供页面栈逻辑\n\n1、当技能开启，当前的页面为A，此时页面栈为空。   \n2、当通过语音或触控返回新的页面B,则A页面压栈，B为当前页面。    \n3、当点击屏幕返回按钮，此时B页面销毁，A页面从栈中弹出，成为当前展示页面。  \n4、以此类推，当栈中没有任何可弹出的页面时推出应用。      \n```python\n    pushStack = PushStack()\n    return{\n    'directives':[自己用来渲染页面的directive, pushStack]\n    }\n\n```\n    \n### 权限申请\n1、AskForPermission 当技能需要获取用户权限:用户信息、位置信息等, 需要向用户进行权限申请。目前只支持用户权限的申请\n2、 比如获取用户信息权限如下\n```python\ndirective = AskForPermissionsConsent()\ndirective.add_permission(PermissionEnum.READ_USER_PROFILE)\n\n```\n3、 添加事件回调处理\n```python\n#用户允许授权 回调\nself.add_permission_granted_event(func)\n#表示用户拒绝授权\nself.add_permission_rejected_event(func)\n#表示用户同意授权，但是由于其他原因导致授权失败\nself.add_permission_grant_failed_event(func)\n```\n4、获取用户信息, 如果用户允许获取权限那么可以在回调方法中去获取用户的信息  \n```python\ncurl -X GET \\\n  https://xiaodu.baidu.com/saiya/v1/user/profile \\\n  -H 'authorization: bearer {apiAccessToken}'\n```\n或通过urlib发起GET请求发送数据, 将authorization字段放到请求的header中   \n注意:apiAccessToken从Launchrequest请求中获取, 通过下面方式可获取到   \n```python\nself.get_api_access_token()\n```\n如果返回成功，会获得用户的信息   \n```python\n{\n\t\"status\": 0,\n\t\"msg\": \"ok\",\n\t\"data\": {\n\t\t\"nickname\": \"\",\n\t\t\"phone\": \"xxxx\",\n\t\t\"email\": \"xxx\",\n\t\t\"portrait\": \"xxx\"\n\t},\n\t\"logId\": \"xxxx\"\n}\n```\nstatus 字段详见[Dueros文档](https://developer.dueros.baidu.com/doc/dueros-bot-platform/dbp-user-info/request-customer-information-api_markdown)  \n5、注：如果懒省事的话,可以实现Bot的permission_granted(self, user_info) 方法，SDK会自己完成授权操作，  \n并回调permission_granted方法，将用户信息返回。\n\n\n### directive指令\n* 播放指令 AudioPlayer.Play\n```python\ndirectives = []\ndirective = Play('http://www.music', PlayBehaviorEnum.REPLACE_ALL)\ndirectives.append(directive)\nreturn {\n    'directives': directives,\n    'outputSpeech': '正在为你播放歌曲',\n}\n```\n* 停止端上的播放音频 AudioPlayer.Stop\n```python\ndirectives = []\ndirective = Stop()\ndirectives.append(directive)\nreturn {\n    'directives': directives,\n    'outputSpeech': '已停止播放',\n}\n```\n设置好handler之后，就可以实例化刚刚定义的Bot，在webserver中接受DuerOS来的请求。例如samples中的文件。\n### 返回speech\n* outputSpeech\n上面例子，除了返回card之外，还可以返回outputSpeech，让客户端播报tts：\n```python\nreturn {\n    'outputSpeech': '请问你要干啥呢',\n    'outputSpeech': '\u003cspeak\u003e请问你要干啥呢\u003c/speak\u003e'\n}\n```\n* reprompt\n当客户端响应用户后，用户可能会一段时间不说话，如果你返回了reprompt，客户端会提示用户输入\n```python\nreturn {\n    'reprompt': '请问你要干啥呢',\n    #或者ssml\n    'reprompt': '\u003cspeak\u003e请问你要干啥呢\u003c/speak\u003e'\n}\n```\n### Lanuch \u0026 SessionEnd\n* bot开始服务\n当bot被@（通过bot唤醒名打开时），DuerOS会发送LanuchRequest给bot，此时，bot可以返回欢迎语或者操作提示：\n```python\ndef launchRequest(self):\n    return {\n        'outputSpeech': r'欢迎进入'\n    }\n\nself.add_launch_handler(self.launchRequest)\n```\n* bot 结束服务\n当用户表达退出bot时，DuerOS会发送SessionEndedRequest：\n```python\ndef endRequest(self):\n    ```\n    清空状态，结束会话\n    ```\nself.add_session_ended_handler(self.endRequest)\n```\n### 使多轮对话管理更加简单\n往往用户一次表达的需求，信息不一定完整，比如：'给我创建一个闹钟'，由于query中没有提醒的时间，一个好的bot实现会问用户：'我应该什么时候提醒你呢？'，这时用户说明天上午8点，这样bot就能获取设置时间，可以为用户创建一个闹钟。比如，你可以这样来实现：\n```python\ndef getRemindSlot(self):\n    remindTime = self.getSlots('remind_time');\n    if remindTime:\n        return 返回设置闹钟指令\n    self.ask('remind_time')\n    return {\n        'outputSpeech': r'要几点的闹钟呢?'\n    }\nself.add_launch_handler(self.getRemindSlot)\n```\n\n### 事件Events\n* Display.ElementSelected  展示列表的item被选中会触发此事件，端点会上送此事件\n\n* Display.ButtonClicked    展示类型的Button被点击,端点会上送此事件\n\n* Form.ButtonClicked       音频或视频播放页面按钮被点击(上一个、下一个、重复、收藏、收藏列表、播放列表)，端点会上送此事件\n\n* AudioPlayer 、VideoPlayer 播放也有对应事件，详看官方文档\n\n### 监听Events\n```python\ndef dealAlertEvent(self, event):\n    card = TextCard('闹钟创建成功')\n    return {\n        'card': card,\n    }\nself.add_event_listener('Alerts.SetAlertSucceeded', self.dealAlertEvent)\n```\nevent就是上送给技能的事件，里面包含事件类型、token等信息,可以通过event数据来做对应的业务。\n\nBot-sdk会根据通过add_event_listener添加的event handler来匹配对应的事件类型。\n\nBot-sdk会根据通过add_intent_handler添加handler的顺序来遍历所有的检查条件，寻找条件满足的handler来执行回调，并且当回调函数返回值不是None时结束遍历，将这个不为None的值返回。\n\nNLU会维护slot的值，merge每次对话解析出的slot，你可以不用自己来处理，DuerOS每次请求Bot时会将merge的slot都下发。session内的数据完全由你来维护，你可以用来存储一些状态，比如打车Bot会用来存储当前的订单状态。你可以通过如下接口来使用slot和session：\n```python\nget_slot('slot name')\nset_slot('slot name', 'slot value'); #如果没有找到对应的slot，会自动新增一个slot\n#session\nget_session_attribute('key')\nset_session_attribute('key', 'value')\n#or\nset_session_attribute('key.key1', 'value')\nget_session_attribute('key.key1')\n#清空session\nclear()\n```\n你的Bot可以订阅端上触发的事件，通过接口add_event_listener实现，比如端上设置闹钟成功后，会下发SetAlertSucceeded的事件，Bot通过注册事件处理函数，进行相关的操作。\n\n### NLU交互协议\n在DuerOS Bot Platform平台，可以通过nlu工具，添加了针对槽位询问的配置，包括：\n1、是否必选，对应询问的默认话术\n2、是否需要用户确认槽位内容，以及对应的话术\n3、是否需要用户在执行动作前，对所有的槽位确认一遍，以及对应的话术\n针对填槽多轮，Bot发起对用户收集、确认槽位（如果针对特定槽位有设置确认选项，就进行确认）、确认意图(如果有设置确认选项)的询问，bot-sdk提供了方便的快捷函数支持：\n注意：一次返回的对话directive，只有一个，如果多次设置，只有最后一次的生效\n\n* ask\n多轮对话的bot，会通过询问用户来收集完成任务所需要的槽位信息，询问用户的特点总结为3点，ask：问一个特定的槽位。比如，打车服务收到用户的打车意图的时候，发现没有提供目的地，就可以ask destination(目的地的槽位名)：\n```python\n#命中打车意图rent_car.book，但是没有提供目的地\ndef RentCar(self):\n    destination = self.get_slots('destination')\n    if not destination:\n        self.ask('destination')\n        card = TextCard('打车去哪呢')\n        return {\n            'card': card,\n        }\nself.add_intent_handler('rent_car.book', self.RentCar)\n```\n* delegate\n将处理交给DuerOS的对话管理模块DM（Dialog Management）,按事先配置的顺序，包括对缺失槽位的询问，槽位值的确认（如果设置了槽位需要确认，以及确认的话术）,整个意图的确认（如果设置了意图需要确认，以及确认的话术。比如可以将收集的槽位依次列出，等待用户确认）\n```python\nreturn self.set_delegate()\n```\n* confirm slot\n主动发起对一个槽位的确认，此时还需同时返回询问的outputSpeach。主动发起的确认，DM不会使用默认配置的话术。\n```python\nself.set_confirm_slot('money')\nreturn {\n    'outputSpeech': '你确认充话费：10000000000',\n    }\n```\n* confirm intent\n主动发起对一个意图的确认，此时还需同时返回询问的outputSpeach。主动发起的确认，DM不会使用默认配置的话术。一般当槽位填槽完毕，在进行下一步操作之前，一次性的询问各个槽位，是否符合用户预期。\n```python\nmoney = self.get_slots('money')\nphone = self.get_slots('phone')\nif money and phone:\n    self.set_confirm_intent()\n    return {\n        'outputSpeech': '你确认充话费：' + money + '，充值手机：' + phone,\n    }\n```\n\n### 第三方授权(有屏设备)\n当需要第三方资源,比如访问新浪微博资源时，需要用户授权才能访问第三方资源，此时就需要\n用户授权此应用可以访问自己在新浪微博上的资源。\n**注意注意：debug模式下，在第三方配置的回调地址要写成:https://xiaodu-dbp.baidu.com/saiya/auth/xxxx**\n```python\ncard = LinkAccountCard()\nreturn {\n    'card': card\n}\n\n```\n\n返回card后会在屏幕展示一张二维码，通过手机扫码即可完成授权。有屏设备再完成授权后会发送授权事件:Connections.Response\n数据格式如下：\n```\n{\n    'dialogRequestId': '',\n    'name': 'LinkAccountSucceeded', \n    'timestamp': 'xxxx',\n    'token': 'xxxx', //第三方授权成功返回的token\n    'requestId': 'xxxx',\n    'type': 'Connections.Response'\n}\n```\n\n### 插件\n\n可以使用如下命令安装:你还可以写插件(拦截器Intercept),干预对话流程、干预返回结果。比如，用户没有通过百度帐号登录，bot直接让用户去登录，不响应意图，可以使用LoginIntercept:\n```python\nloginIntercept = LoginIntercept()\nself.add_intercept(loginIntercept)\n```\n开发自己的拦截器，继承Intercept,通过重载preprocess，能够在处理通过addHandler、addEventListener添加的回调之前，定义一些逻辑。通过重载postprocess能够对回调函数的返回值，进行统一的处理：\n```python\nclass YourIntercept(Intercept):\n    def preprocess(self, bot):\n        '''\n        bot: 你的bot实例化对象\n        '''\n\n    def postprocess(self, bot, result):\n        '''\n        maybe format result \n        '''\n        return result\n```\nintercept可以定义多个，执行顺序，以调用addIntercept的顺序来执行\n\n### 技能数据验证\nBot技能支持数据验证(默认数据验证是关闭的)，确保数据的来源的可靠性。(确保已经在技能平台配置了公钥)\n* 初始化数据校验\n```python\nself.init_certificate(environ, private_key='')\n```\n* 开启数据验证\n```python\nself.enable_verify_request_sign()\n```\n详见文档[通信认证](https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-deploy/authentication.md)\n\n### 技能数据统计\nBot默认开启技能数据统计功能(确保已经在技能平台配置了公钥),关闭需要调用\n```python\nself.set_monitor_enabled(False)\n\n```\n之后设置自己的私钥和环境(0:Debug模式, 1:online模式)\n```python\nself.set_environment_info(private_key, environment=0)\n```\n**重要的事情来三遍**  \n**注意注意注意：模式不匹配会影响数据统计，技能审核通过后一定要配置成1**  \n**注意注意注意：模式不匹配会影响数据统计，技能审核通过后一定要配置成1**  \n**注意注意注意：模式不匹配会影响数据统计，技能审核通过后一定要配置成1**  \n\n默认将数据上送到百度, 你也可以自建数据统计，只需要设置数据上传地址：\n``` python\nbot.set_monitor_url(第三方数据统计平台地址)\n```\n并在自己的数据平台进行数据解析即可。   \n统计数据步骤：   \n1、将原始数据进行base64 \n```python\n{\n  'serviceData': {\n      'sdkType': '',\n      'sdkVersion': '',\n      'requestId': '',\n      'query': '',\n      'reason': '',\n      'deviceId': '',\n      'requestType': '',\n      'userId': '',\n      'intentName': '',\n      'sessionId': '',\n      'location': '',\n      'slotToElicit': '',\n      'shouldEndSession': '',\n      'outputSpeech': '',\n      'reprompt': '',\n      'audioUrl': '',\n      'appInfo': {\n          'appName': '',\n          'packageName': '',\n          'deepLink': ''\n      },\n      'requestStartTime': '',\n      'requestEndTime': '',\n      'timestamp': '',\n      'sysEvent': '',\n      'userEvent': ''\n    }\n}\n```\n2、用技能的私钥计算数据签名    \nsignature = sign(base64 + bot_id + timestamp + pkversion)\n\n3、POST 方式上送base64后的数据    \n在请求header中会设置几个字段   \n```python\nheaders = {\n   'Content-Type': 'application/x-www-form-urlencoded',\n   'Content-Length': 'base64后的数据长度',\n   'SIGNATURE': '数据签名',\n   'botId': 'bot_id',\n   'timestamp': 'timestamp',\n   'pkversion': 'pkversion'\n}\n```\n4、如果是自己的数据平台，使用公钥验数据，还原数据即可获得统计数据明文。\n\n### \u003cspan id = \"question\"\u003e常见问题\u003c/span\u003e\n* 运行sh start.sh 出现 ImportError: No module named OpenSSL\n执行下面命令\n```\nsudo pip install pyOpenSSL\n```\n\n* ImportError: No module named Crypto.PublicKey\n执行下面命令\n```\nsudo pip install pycrypto\n```\n\n* ImportError: No module named requests\n执行下面命令\n```\nsudo pip install requests\n```\n或者在根目录执行下面命令解决全部问题\n```\npip install -r requirements.txt\n```\n# 技能调试\n为了避免每次调试都要部署到服务器可以使用[ngrok](https://ngrok.com/)将请求数据转发到自己的机器上(注意:ngrok访问比较慢,有时会链接超时)\n\n# 变更记录\n\n* 版本变更详见变更记录 CHANGELOG.md\n\n# Known Users\n按照登记顺序排序，更多接入技能，欢迎在 https://github.com/jokenwang/bot-sdk-python/issues/16 登记（仅供用户参考）\n\n## 鸣谢\n[@gongqingliang821](https://github.com/gongqingliang821)\n\n### 免责声明\n\n* 此SDK非官网提供，纯属个人学习研究，如因使用此SDK导致的任何损失，本人概不负责。\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjokenwang%2Fbot-sdk-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjokenwang%2Fbot-sdk-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjokenwang%2Fbot-sdk-python/lists"}