AI Zone Admin Forum Add your forum

CHATBOT MEETUP CHATBOT MEETUP CHATBOT MEETUP CHATBOT CHATBOT MEETUP CHATBOT MEETUP CHATBOT MEETUP CHATBOT MEETUP

On Wed 31th, 2017 we're organizing a Chatbot Meetup in Amsterdam, The Netherlands. Feel free to join!'

yes/no questions
 
 

questions and answers are a very common pattern in dlalogs, and I am not sure about the “best practice” in doting this with ChatScript.

version #1
The first option is to use rejoinders, such as:

s: (tell me a joke) Do you want a funny joke?
  
a: (yesOKhere is a funny joke...
  
a: (no)   OKhere is an unfunny joke... 

version #2
Usually, the user can achieve the same effect without being asked. To prevent duplication, we can use labels::

sFUNNYJOKE (tell me a funny jokeOKhere is a funny joke...
sUNFUNNYJOKE (tell me an unfunny joke)   OKhere is an unfunny joke...
s: (tell me a joke) Do you want a funny joke?
  
a: (~yes) ^reuse(FUNNYJOKE)
  
a: (~no)   ^reuse(UNFUNNYJOKE

But this will not work if the user says “tell me a funny joke” right after the bot asks him the question! to handle this, we need to add two more rules:
version #3

sFUNNYJOKE (tell me a funny jokeOKhere is a funny joke...
sUNFUNNYJOKE (tell me an unfunny joke)   OKhere is an unfunny joke...
s: (tell me a joke) Do you want a funny joke?
  
a: (~yes) ^reuse(FUNNYJOKE)
  
a: (~no)   ^reuse(UNFUNNYJOKE)
  
a: (tell me a funny joke) ^reuse(FUNNYJOKE)
  
a: (tell me an unfunny joke)   ^reuse(UNFUNNYJOKE

That’s seven lines for each yes/no question. Is there a better way to do this, maybe with some macro? I have in mind something like this:

s: (tell me a funny jokeOKhere is a funny joke...
s: (tell me an unfunny joke)   OKhere is an unfunny joke...
s: (tell me a joke) ^yesnoquestion ("Do you want a funny joke?""tell me a funny joke""tell me an unfunny joke"

The first 2 lines are identical to above. The ^yesnoquestion has 3 parameters: the question text, the “yes” equivalent, and the “no” equivalent.

The only problem is, I don’t know how to build this macro to make these 3 lines equivalent to the above 7 lines…

 

 

 
  [ # 1 ]

A shortcoming of my suggestion is that it does not address other types of questions besides yes/no, for example:

s: (tell me a joke) Do you want a short joke or a long one?
  
a: (short) ^reuse(SHORTJOKE)
  
a: (long)   ^reuse(LONGJOKE

 

 

 
  [ # 2 ]

a good analysis, Erel.  A couple of points…
First, Version 1 should use ~yes and ~no, which you did for Version 2.

Second, Version 2 DOES work as it stands, because if the chatbot asks if you want a funny joke and the user does not reply yes or no but replies “tell me a funny joke”, then both rejoinders fail and the system goes matches the original FUNNYJOKE statement above. Therefore version 3 is superfluous and doesnt need its last 2 rejoinders.

Now, if you want to create common code within a single rule, the macro is the way to go. But you want a series of rules as your structure, which means it must be a topic itself. And if you are varying your patterns based on passed in arguments, you are trying to be super sophisticated, which means you need to evaluate a dynamic pattern. This means using the ^match() function, which I discover is not documented in the manual. I will rectify this in the next couple of days with a new release. You would use the macro to accept arguments, they would be stored onto temporary variables, and then a special topic called that does the dynamic evaluation and has all your rejoinder structure.

 

 
  [ # 3 ]

^match( what) - takes a pattern to match current input against and either fails or succeeds.  Typically “what” is a variable reference, because if you are doing some static expression you probably could have just put that in a normal rule.  E.g.,

if (^match($myexpress)) {... do this when it matches }

if (^match(~bunchofkeywordstomatch)) {.. do this when it matches }

 

 
  [ # 4 ]

I didn’t understand how I can use ^match for the rejoinder structure. Here is what I tried:

sFUNNYJOKE (tell me a funny jokeOKhere is a funny joke...
sUNFUNNYJOKE (tell me an unfunny joke)   OKhere is an unfunny joke...
s: (tell me a joke) Do you want a funny joke
  if (^
match(~yes)) ^reuse(FUNNYJOKE}
  
if (^match(~no)) ^reuse(UNFUNNYJOKE

Obviously it doesn’t work because the “^match” operates on the current input and not on the next input. How can I create a structure that includes two volleys instead of just the current one?

 

 

 
  [ # 5 ]

The goal was a general reusable structure to handle patterns of things you gave above. Here is an approproximate untested script to convey the intent….

topic: ~generic ()
s: ($generalPrompt) $generalprompt
$generalprompt = null
a: (~yes) ^reuse(YESANSWER)
a: (~no)  ^reuse(NOANSWER)
s: YESANSWER($question1) $answer1
s: NOANSWER($question2) $answer2

outputmacro: ^stdinput(^prompt1 ^prompt2 ^generalPrompt ^answer1 ^answer2)
$question1 = ^prompt1
$question2 = ^prompt2
$answer1 = ^answer1
$answer2 = ^answer2
$generalprompt = ^generalprompt
^respond(~generic)

topic: ~joke()
s: (tell me a joke) stdinput(“tell me a short joke” “tell me a long joke”
“do you want a short joke?”
“this is a short joke”
“this is a long joke” )
s: (tell me a joke) stdinput(“tell me a funny joke” “tell me an unfunny joke”
“do you want a funny joke?”
“this is a funny joke”
“this is an unfunny joke”)

 

 
  [ # 6 ]

but that doesnt actually handle indirection… that just indicates what I am aiming toward. Indirection requires the match function.

topic: ~generic()
s: ( ^match($generalprompt)) ...
  a: (~yes) ...
  a: (~no) ...
s: YESANSWER( ^match($question1)) ...
s: NOANSWER (^match($question2)) ...

This might work (untested)

 

 
  [ # 7 ]

the above leaves out details ( ^noerase and maybe whether or not you have to convert from a quoted string to its literal content when storing on a variable).

But back to your original example…. I don’t expect the user to out-of-the-blue say tell me a funny joke. Maybe when you prompt him, so I’d wrap that all into the rejoinder as follows:
s: (tell me a joke) Do you want a funny joke?
  a: ([~yes funny]) OK, here is a funny joke…
  a: ([~no boring unfunny])  OK, here is an unfunny joke… 

And then… if you have a lot of these things, I might consider building them as a table of data and extracting out all the individual statement rules into a common query into the database of these things…. but that is going farther and farther from what you started with

 

 
  [ # 8 ]
Bruce Wilcox - Jun 21, 2011:

but that doesnt actually handle indirection… that just indicates what I am aiming toward. Indirection requires the match function.

topic: ~generic()
s: ( ^match($generalprompt)) ...
  a: (~yes) ...
  a: (~no) ...
s: YESANSWER( ^match($question1)) ...
s: NOANSWER (^match($question2)) ...

This might work (untested)

Ah, now I see what you mean. The rule:

sYESANSWER($question1

will match whenever the variable “$question1” is defined, regardless of the input, while the rule:

sYESANSWER(^match($question1)) 

will match only when the variable “$question1” is defined AND matches the input.

However, I don’t understand why you need ^match at the first line ^match($generalprompt)? It seems this is a prompt said by the bot, not an input pattern!

 

 
  [ # 9 ]

yes, sorry… I got carried away… You want to remove the ^match from the first rule.  you DO want it to fire because the general prompt has been set (thus emitting the prompt) and then erasing it so it doesnt fire again.

 

 
  [ # 10 ]

Hi sirs,

Erel Segal Halevi - Jun 20, 2011:
s: (tell me a joke) Do you want a funny joke?
  
a: (yesOKhere is a funny joke...
  
a: (no)   OKhere is an unfunny joke... 
Bruce Wilcox - Jun 20, 2011:

First, Version 1 should use ~yes and ~no, which you did for Version 2.


in facts seems to me that rule

a: (yesOKhere is a funny joke... 

do not fire if user state “yes”

Why?


thanks
giorgio (http://www.convcomp2017.it)

 

 
  [ # 11 ]
Giorgio Robino - Mar 6, 2017:

Hi sirs,

Erel Segal Halevi - Jun 20, 2011:
s: (tell me a joke) Do you want a funny joke?
  
a: (yesOKhere is a funny joke...
  
a: (no)   OKhere is an unfunny joke... 
Bruce Wilcox - Jun 20, 2011:

First, Version 1 should use ~yes and ~no, which you did for Version 2.


in facts seems to me that rule

a: (yesOKhere is a funny joke... 

do not fire if user state “yes”

Why?


thanks
giorgio (http://www.convcomp2017.it)

Because if you haven’t disabled interjections it gets cut off and replaced with ~yes.

 

 
  [ # 12 ]

may you please clarify ?

I see here:

https://github.com/bwilcox-1234/ChatScript/blob/master/LIVEDATA/ENGLISH/SUBSTITUTES/interjections.txt#L692

that

yes 
is part engine concept:
~yes 

but i do not understand why

yes 

can’t match in a pattern like

u: (yes

 

 
  [ # 13 ]

Read the “Interjections, “discourse acts”, and concept sets” of the basic user manual.

This is just how the engine works. It looks for those interjections from the text file you mentioned, cuts them off from the sentence and replaces them with the concept listed. It’s not the same as wordnet concepts.

So no matter which case, you will never be able to write a pattern for any of those things listed in interjections.txt, unless you disable interjections via token control.

Type in “:prepare yes” and you will see what the engine will try to match your pattern against.

 

 
  [ # 14 ]

more clear for me now, thanks Tobias.

 

 
  login or register to react