Discuss


level_1 - [Deprecated: use Chat with a QiChatbot instead]


Goal - Give Pepper the ability to discuss around a topic.

// Create a topic.
val topic: Topic = TopicBuilder.with(qiContext)
                          .withResource(R.raw.animals)
                          .build()

// Build the action.
val discuss: Discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build()

// Run the action asynchronously.
discuss.async().run()
// Create a topic.
Topic topic = TopicBuilder.with(qiContext)
                          .withResource(R.raw.animals)
                          .build();

// Build the action.
Discuss discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build();

// Run the action asynchronously.
discuss.async().run();

Typical usage - You want Pepper to have an elaborate conversation with someone.


How it works

Discuss with topics

To build a Discuss, you use Topics:

A Topic is made of rules that describe the logic of the conversation. It mostly contains what Pepper should answer when someone talks to him.

Typically, a Topic is created from a topic file (.top), and uses QiChat syntax.

See also QiChat Language.

Preparing a discuss

You want Pepper to be able to discuss around a topic.

val topic: Topic = TopicBuilder.with(qiContext)
                      .withResource(R.raw.animals)
                      .build()

val discuss: Discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build()

discuss.async().run()
Topic topic = TopicBuilder.with(qiContext)
                          .withResource(R.raw.animals)
                          .build();

Discuss discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build();

discuss.async().run();

Managing discuss end

You want to handle the different cases leading to the end of the discuss.

val topic: Topic = TopicBuilder.with(qiContext)
                      .withResource(R.raw.game)
                      .build()

val discuss: Discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build()

val endReason: String = discuss.run()
when (endReason) {
    "sword" -> buySword()
    "bow" -> buyBow()
}
Topic topic = TopicBuilder.with(qiContext)
                          .withResource(R.raw.game)
                          .build();

Discuss discuss = DiscussBuilder.with(qiContext)
                                .withTopic(topic)
                                .build();

String endReason = discuss.run();
switch (endReason) {
    case "sword":
        buySword();
        break;
    case "bow":
        buyBow();
        break;
}

game.top content:

topic: ~game()

u: (buy) Do you want to buy a sword or a bow?
    u1: (sword) This is a really sharp sword. ^endDiscuss(sword)
    u1: (bow) This bow can draw arrows far away. ^endDiscuss(bow)

Retrieving recommendations

Recommendations give you access to the verbal inputs available to the user to interact with the robot when a Discuss action is running.

The Discuss action provides 3 different recommendation types:

  • global recommendations,
  • focused topic recommendations,
  • scope recommendations.

Global recommendations:

Global recommendations correspond to all the activated u: rules loaded in the Discuss action.

val globalRecommendations: PhraseSet = discuss.globalRecommendations()
PhraseSet globalRecommendations = discuss.globalRecommendations();

Focused topic recommendations:

Focused topic recommendations correspond to all the activated u: rules in the currently focused topic.

val focusedTopicRecommendations: PhraseSet = discuss.focusedTopicRecommendations()
PhraseSet focusedTopicRecommendations = discuss.focusedTopicRecommendations();

Scope recommendations:

Scope recommendations correspond to all the activated sub-rules of the current scope.

val scopeRecommendations: PhraseSet = discuss.scopeRecommendations()
PhraseSet scopeRecommendations = discuss.scopeRecommendations();

Example:

top1.top:

topic: ~top1()

u:(color) what's your favourite color
    u1:(blue) marine blue or sky blue
        u2:(marine) Oh, like the sea then $color=marineblue
        u2:(sky) Oh, like the sky then $color=skyblue
    u1:(yellow) Oh, like the sand then $color=yellow
    u1:(green) Oh, like the grass then $color=green

top2.top:

topic: ~top2()

u:(dogs) so you want to speak about dogs?
u:(cats) so you want to speak about cats?

Recommendation results:

// Discuss is running

discuss.globalRecommendations().phrases // ["color", "dogs", "cats"]

// User says "color"

discuss.globalRecommendations().phrases // ["color", "dogs", "cats"]
discuss.focusedTopicRecommendations().phrases // ["color"]
discuss.scopeRecommendations().phrases // ["yellow", "blue", "green"]

// User says "dogs"

discuss.globalRecommendations().phrases // ["color", "dogs", "cats"]
discuss.focusedTopicRecommendations().phrases // ["dogs", "cats"]
discuss.scopeRecommendations().phrases // []
// Discuss is running

discuss.globalRecommendations().getPhrases(); // ["color", "dogs", "cats"]

// User says "color"

discuss.globalRecommendations().getPhrases(); // ["color", "dogs", "cats"]
discuss.focusedTopicRecommendations().getPhrases(); // ["color"]
discuss.scopeRecommendations().getPhrases(); // ["yellow", "blue", "green"]

// User says "dogs"

discuss.globalRecommendations().getPhrases(); // ["color", "dogs", "cats"]
discuss.focusedTopicRecommendations().getPhrases(); // ["dogs", "cats"]
discuss.scopeRecommendations().getPhrases(); // []

Observing the Discuss states

Listening

To be understood, the user should only speak to the robot when the Discuss is in a listening state.

The listening state of the Discuss is accessible at any time, via the getListening method:

val isListening: Boolean = discuss.listening
Boolean isListening = discuss.getListening();

And a listener:

discuss.addOnListeningChangedListener { listening ->
    // Called when the listening state changes.
}
discuss.addOnListeningChangedListener( listening -> {
    // Called when the listening state changes.
});

Hearing

You can be notified when the robot hears human voice via the getHearing method:

val isHearing: Boolean = discuss.hearing
Boolean isHearing = discuss.getHearing();

And a listener:

discuss.addOnHearingChangedListener { hearing ->
    // Called when the hearing state changes.
}
discuss.addOnHearingChangedListener(hearing -> {
    // Called when the hearing state changes.
});

Saying

The phrase the robot is saying is accessible via the getSaying method:

val saying: Phrase? = discuss.saying
Phrase saying = discuss.getSaying();

And a listener:

discuss.addOnSayingChangedListener { sayingPhrase ->
    // Called when the robot speaks.
}
discuss.addOnSayingChangedListener(sayingPhrase -> {
    // Called when the robot speaks.
});

When the robot is not saying anything, the String contained in the Phrase is empty.

Observing the user input

You can observe what the robot hears via a listener:

discuss.addOnHeardListener { heardPhrase ->
    // Called when a phrase was recognized.
}
discuss.addOnHeardListener(heardPhrase -> {
    // Called when a phrase was recognized.
});

Sometimes the robot detects human voice but cannot determine the content of the phrase said:

discuss.addOnNoPhraseRecognizedListener {
    // Called when no phrase was recognized.
}
discuss.addOnNoPhraseRecognizedListener(() -> {
    // Called when no phrase was recognized.
});

Observing the reply type

After the robot heard human speech, there can be 3 different cases:

  • Normal reply
  • Fallback reply
  • No reply

Normal reply

The type of the reply is normal when the robot provides a provides an answer provided by any rule except fallback rules.

my_topic.top:

topic: ~normal_topic()

u: (hello) Hello!

It is accessible via a listener:

discuss.addOnNormalReplyFoundForListener { input ->
    // Called when the reply has a normal type.
}
discuss.addOnNormalReplyFoundForListener(input -> {
    // Called when the reply has a normal type.
});

Fallback reply

The type of the reply is fallback when a phrase was heard but the robot cannot provide a good answer, for example it matches a rule containing a e:Dialog/NotUnderstood:

fallback_reply.top:

topic: ~fallback_reply()

u: (e:Dialog/NotUnderstood) I don't understand

In the case where the robot determined the content of the phrase said, the input parameter will contain the phrase, otherwise, it will be empty.

discuss.addOnFallbackReplyFoundForListener { input -> {
    // Called when the reply has a fallback type.
}
discuss.addOnFallbackReplyFoundForListener(input -> {
    // Called when the reply has a fallback type.
});

No reply

If the user input doesn’t match a rule and there is no fallback reply, the robot will not reply.

In the case where the robot determined the content of the phrase said, the input parameter will contain the phrase, otherwise, it will be empty.

discuss.addOnNoReplyFoundForListener { input -> {
    // Called when no reply was found for the input.
}
discuss.addOnNoReplyFoundForListener(input -> {
    // Called when no reply was found for the input.
});

Performance & Limitations

Discuss or Say/Listen?

Using Discuss is relevant when you want Pepper to be able to answer with relevance to a human input. If you want Pepper to ultimately say something specific or listen to a precise human input, you should use Say and Listen instead.

Exclusions with other actions

Do not start a Discuss while a Chat, Say or a Listen is running: the Discuss would fail.