Loading... ## 场景1:Pepper 说 ### 语言:Kotlin #### 参考代码: ```kotlin private fun initSay2(qiContext: QiContext?) { val phrase = Phrase("你好呀,我是Pepper") val say = SayBuilder.with(qiContext) .withResource(R.string.hello) //Say 内容 // .withText("你好呀,我是Pepper") //与上一行的最终实现相同 // .withPhrase(phrase) // 与上一行的最终实现相同 .build() //开始的监听 say.addOnStartedListener { } val futureSay = say.async().run() //Say过程被强制打断时的操作,一般是在onRobotFocusLost中调用 //say.removeAllOnStartedListeners() //futureSay.cancel(true) } ``` #### 注意: 1. withResource、withText、withPhrase写法没有区别,因最终实现在SayBuilder都是处理成了Phrase,建议使用withResource写法,方便String资源的管控。 2. 注意build()和buildAsync(),async().run()和run()的不同场景用法,参考:https://qisdk.softbankrobotics.com/sdk/doc/pepper-sdk/ch2_principles/sync_async.html。 Say完成后Action的处理请参考:https://qisdk.softbankrobotics.com/sdk/doc/pepper-sdk/ch2_principles/futures.html。 3. 同一时间只能一个Say任务执行。 ## 场景2:Pepper 听 Listen ### 识别固定关键字、词语 #### 语言:Kotlin #### 参考代码: ```kotlin private fun initListen(qiContext: QiContext?) { val phraseSet = PhraseSetBuilder.with(qiContext) .withTexts("你叫什么", "你的名字是什么") .build() val listen = ListenBuilder.with(qiContext) .withPhraseSet(phraseSet) //TODO 补充部分API .build() //Listen 开始的监听 listen.addOnStartedListener { } // Listen过程被强制打断时的操作,一般是在onRobotFocusLost中调用 // listen.removeAllOnStartedListeners() // futureListen.cancel(true) } ``` #### 注意: 1. withPhraseSets里填充的是PhraseSet的集合。 2. withLocale默认是设备的语音和地区。 3. withBodyLanguageOption可设置当Listen时是否展现相关拟人的肢体动作。 4. Phrase & PhraseSet适用: 1. Say 、所有的resource、text,最终都会转换为Phrase 2. Listen,Listen的PhraseSet只能识别已设置的词语进行匹配。 ## 场景3:Pepper 与人语音互动 下列两个方式里都未包含Pepper语音时的拟人动作搭配。因QiSDK默认是包含动作搭配的。 ### 方式1:Listen+Say实现 #### 语言:Kotlin #### 参考代码: ```kotlin private fun startListenAndSay(qiContext: QiContext?) { val phraseSet = PhraseSetBuilder.with(qiContext) .withTexts("你叫什么", "你的名字是什么") .build() val listen = ListenBuilder.with(qiContext) .withPhraseSet(phraseSet) .withPhraseSets() .build() val futureListen = listen.async().run() futureListen.thenConsume { startSay(qiContext) } } private fun startSay(qiContext: QiContext?) { val say = SayBuilder.with(qiContext) .withResource(R.string.hello) .build() val futureSay = say.async().run() futureSay.thenConsume { //继续写Listen... } } ``` #### 注意: 1. 一般开发不会使用方式1来实现,一是效率低,二是不便后期增删管理。 2. Say和Listen一般只适用一问一答。 ### 方式2:Topic+QiChatBot+Chat(可无网) 原理说明:QiChatBot通过加载本地的top文件,获取想要识别的Topic,并按照Topic的规则内容,给出语音交互回应。 #### top文件内容参考: ```php topic: ~hello() concept:(hello) ["你好" "你好呀" "嗨"] concept:(age_question) ["你多大了" "你几岁了" "你年龄多大"] concept:(age_answer) ["我今年5岁了呢,别看我年纪小,其实我懂得可多啦"] concept:(time_question) ["现在几点了" "现在的时间是多少"] concept:(time_answer) ["现在的时间是北京时间 ^currentTime"] concept:(food1) ["我想吃[苹果 香蕉 葡萄 荔枝 西瓜]"] concept:(food1_answer) ["好的 $askedFood=$1"] concept:(food1_answer2) ["你询问了一种新的水果"] u:(~hello) ~hello u:(~age_question) ~age_answer u:(~time_question) ~time_answer u:(~food1) ~food1_answer u:(e:askedFood)~food1_answer2 proposal: %weather 上海今天是晴天 concept:(weather1) ["今天上海出太阳了吗?"] concept:(weather1_answer) ["是的, ^enableThenGoto(weather)"] concept:(weather2) ["你确定吗?"] concept:(weather2_answer) ["非常确定,^enableThenGoto(weather)"] u:(~weather1) ~weather1_answer u:(~weather2) ~weather2_answer ``` 更多语法地址:https://qisdk.softbankrobotics.com/sdk/doc/pepper-sdk/ch4_api/conversation/qichat/qichat_syntax.html #### 语言:Kotlin #### 参考代码: ```kotlin private fun initChat2(qiContext: QiContext?) { val topic = TopicBuilder.with(qiContext).withResource(R.raw.hello).build() val qiChatbot = QiChatbotBuilder.with(qiContext).withTopic(topic).build() val chat = ChatBuilder.with(qiContext).withChatbot(qiChatbot).build() val futureChat = chat.async().run() chat.addOnStartedListener { Log.e(TAG, "addOnStartedListener") } //监听所有识别出来的文字内容 chat.addOnHeardListener { Log.e(TAG, "1-addOnHeardListener: it: ${it.text}") } //监听所有未识别出来 chat.addOnNoPhraseRecognizedListener { Log.e(TAG, "2-addOnNoPhraseRecognizedListener") } //监听所有已回复的文字内容 chat.addOnNormalReplyFoundForListener { Log.e(TAG, "3-addOnNormalReplyFoundForListener: it: ${it.text}") } //监听所有未回复的文字内容,包括未识别成功的空内容 chat.addOnNoReplyFoundForListener { Log.e(TAG, "4-addOnNoReplyFoundForListener: it: ${it.text}") } //监听所有回复的内容 chat.addOnSayingChangedListener { Log.e(TAG, "5-addOnSayingChangedListener: it: ${it.text}") } //监听所有听状态的改变 chat.addOnListeningChangedListener { Log.e(TAG, "6-addOnListeningChangedListener: it: $it") } //监听所有听状态的改变 chat.addOnHearingChangedListener { Log.e(TAG, "7-addOnHearingChangedListener: it: $it") } //Chat过程被强制打断时的操作,一般是在onRobotFocusLost中调用 //futureChat.cancel(true) } ``` #### 日志文件截图: <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAABS2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+IEmuOgAAAA1JREFUCJljOHz4cAMAB2ACypfyMOEAAAAASUVORK5CYII=" data-original="https://s2.ax1x.com/2019/10/09/u5tIvd.jpg" alt="WechatIMG256" /> #### 日志内容说明: 1. Saying和Listening是成对出现的,不论识别成功与否或回复成功与否,本次识别-回复流程结束后都会开始Hearing的监听。 2. 所有Chat内的监听,按需创建。 3. Q: 如果人没有说话Hearing是否会状态变更? #### 注意: 1. 方式2适用在谈话内容少,并网络不佳的场景,比如展会现场。 2. 2.9.3的Pepper对top语法的语言标准较2.9.1严格,比如在2.9.1Pepper的raw下的hello.top下写简体中文的问答是可以正常交互的,但是在2.9.3必须要将hello.top放置在raw-zh-rCN文件夹下,否则无法正常运行语音交互。 4. Topic 里面的字符串需要严格按照top语法。 ### 方式3:MyChatbotReaction(实现 BaseChatbotReaction)+ MyChatbot(实现 BaseChatbot)+ Chat #### 语言:Kotlin #### 参考代码: MyChatbotReaction.kt ```kotlin class MyChatbotReaction internal constructor(context: QiContext, private val answer: String) : BaseChatbotReaction(context) { private var fSay: Future<Void>? = null override fun runWith(speechEngine: SpeechEngine) { if (answer.isEmpty()) return val say = SayBuilder.with(speechEngine).withText(answer).build() fSay = say.async().run() try { fSay?.get() } catch (e: Exception) { e.printStackTrace() } } override fun stop() { fSay?.cancel(true) fSay?.requestCancellation() } } ``` MyChatBot.kt //TODO 修改位置 ```kotlin class MyChatBot(internal var qiContext: QiContext) : BaseChatbot(qiContext) { //处理回复的语义内容和其他逻辑 override fun replyTo(phrase: Phrase?, locale: Locale): StandardReplyReaction { val isNotReply = phrase == null || phrase.text.isNullOrEmpty() val reaction = MyChatbotReaction(qiContext, if (!isNotReply) "这是测试回复" else "识别内容为空,请重试") return StandardReplyReaction(reaction, ReplyPriority.NORMAL) } } ``` ```kotlin private fun initChat(qiContext: QiContext?) { val bot = MyChatBot(qiContext!!) val chat = ChatBuilder.with(qiContext).withChatbot(bot).build() val futureChat = chat.async().run() //Chat过程被强制打断时的操作,一般是在onRobotFocusLost中调用 //futureChat.cancel(true) } ``` #### 注意: 1. 方式3需要联网使用,在网络不好的情况下可考虑使用方式2。 2. MyChatbotReaction支持对接第三方语料库,可在runWith中处理第三方语义库的获取内容和相关逻辑处理。 讯飞语义参考:https://github.com/SoftbankRoboticsChina/nlp-demo ## 场景4:Pepper聊天回复时搭配指定动作 ### 方式1:BookMark+Topic+Animation mimic_animal.top ```php topic: ~mimic_animal() proposal: %mimic_proposal Say dog or elephant u1: (dog) OK, I've reached the dog bookmark %dog_mimic u1: (elephant) OK, I've reached the elephant bookmark %elephant_mimic ``` #### 语言:Kotlin #### 参考代码: ```kotlin private var qiChatbot: QiChatbot? = null private var chat: Chat? = null private var proposalBookmark: Bookmark? = null private var dogBookmarkStatus: BookmarkStatus? = null private var elephantBookmarkStatus: BookmarkStatus? = null //设置动作表演的参数以让动作转到对应的标签 private fun sayProposal() { qiChatbot?.goToBookmark(proposalBookmark, AutonomousReactionImportance.HIGH, AutonomousReactionValidity.IMMEDIATE) } override fun onRobotFocusGained(qiContext: QiContext?) { val topic = TopicBuilder.with(qiContext) .withResource(R.raw.mimic_animal) .build() qiChatbot = QiChatbotBuilder.with(qiContext) .withTopic(topic) .build() chat = ChatBuilder.with(qiContext) .withChatbot(qiChatbot) .build() chat?.addOnStartedListener(this::sayProposal); val bookmarks = topic.bookmarks //获取top文件内的mimic_proposal proposalBookmark = bookmarks["mimic_proposal"] val dogBookmark = bookmarks["dog_mimic"] val elephantBookmark = bookmarks["elephant_mimic"] dogBookmarkStatus = qiChatbot?.bookmarkStatus(dogBookmark) elephantBookmarkStatus = qiChatbot?.bookmarkStatus(elephantBookmark) //当语音回复成功后开始表演 dogBookmarkStatus?.addOnReachedListener { mimicDog(qiContext!!); } //当语音回复成功后开始表演 elephantBookmarkStatus?.addOnReachedListener { mimicElephant(qiContext!!) } chat?.async()?.run(); } override fun onRobotFocusLost() { super.onRobotFocusLost() chat?.removeAllOnStartedListeners() dogBookmarkStatus?.removeAllOnReachedListeners() elephantBookmarkStatus?.removeAllOnReachedListeners() } private fun mimicDog(qiContext: QiContext) { Log.i(TAG, "Dog mimic.") mimic(R.raw.dog_a001, qiContext) } private fun mimicElephant(qiContext: QiContext) { Log.i(TAG, "Elephant mimic.") mimic(R.raw.elephant_a001, qiContext) } private fun mimic(@RawRes mimicResource: Int?, qiContext: QiContext) { val animation = AnimationBuilder.with(qiContext) .withResources(mimicResource) .build() val animate = AnimateBuilder.with(qiContext) .withAnimation(animation) .build() animate.async().run() } ``` 注意: R.raw.elephant_a001和R.raw.dog_a001均来自Pepper SDK里的Animation Library ### 方式2:Say(或Chat)+Animation #### 原理说明: 使用异步或者andThenConsume #### 语言:Kotlin #### 参考代码: ```kotlin private fun startSay(qiContext: QiContext?) { val say = SayBuilder.with(qiContext).withText("请看我表演小狗呀").build() val futureSay = say.async().run() //Say和Animation同时进行 //mimic(R.raw.dog_a001, qiContext!!) //Say完成后再Animation futureSay.andThenConsume { mimic(R.raw.dog_a001, qiContext!!) } //Say过程被强制打断时的操作,一般是在onRobotFocusLost中调用 //futureSay.cancel(true) ``` Last modification:October 9th, 2019 at 03:56 pm © 允许规范转载 Support If you think my article is useful to you, please feel free to appreciate ×Close Appreciate the author Sweeping payments