abritez
abritez

Reputation: 2626

Bot Framework: Multi step waterfall

I'd like to send a bot something similar to this

"[Person] wants to meet at [Place] at [Date]"

however, if the person misses some pieces of information I want the bot to ask for it piece by piece.

So for example if a person writes:

"Let's meet!"

The bot would ask a series of questions to fulfill all the data requirements. Something like:

  1. Whom will I be meeting?
  2. Where should they meet?
  3. What date and time?

If the person ask something like:

"Alex would like to meet tomorrow"

Then the bot would only ask

"Where should they meet?"

Once all the required data it complete it would send a response like:

"Great, I will meet [Person] in [Location] at [DateTime]"

I've been trying approaches like this with little luck and getting a "Too many calls to session.EndDialog()" error:

dialog.on('Meeting', [
    function (session, results, next) {
        var person = builder.EntityRecognizer.findEntity(results.entities, 'Person');
        if(!person){
            builder.Prompts.text(session, prompts.meetingPersonMissing); 
        } else {
            next({ response: {
                    person: person.entity
                }
            });
        }
    },
    function (session, results, next) {
        var location = builder.EntityRecognizer.findEntity(results.entities, 'location');
        if(!location){
            builder.Prompts.text(session, prompts.meetingLocationMissing); 
        } else {
            // Pass title to next step.
            next({ response: {
                    person: results.person,
                    location: location.entity
                }
            });
        }
    },
    function (session, results, next) {
        var time = builder.EntityRecognizer.findEntity(results.entities, 'builtin.datetime.date');
        if(!time){
            builder.Prompts.text(session, prompts.meetingTimeMissing); 
        } else {
            next({ response: {
                    person: results.person,
                    location: results.location,
                    time: time.entity
                }
            });
        }
    },
    function (session, results) {
        if (results.response) {
           session.send(prompts.meetingSubmited);
        } else {
            session.send(prompts.canceled);
        }
    }
]);

Unsuccessful Attempt #2 (no longer passing data from 'next()'). This results in same EndDialog error

dialog.on('Meeting', [
    function (session, results, next) {
        var person = builder.EntityRecognizer.findEntity(results.entities, 'Person');
        var location = builder.EntityRecognizer.findEntity(results.entities, 'location');
        var time = builder.EntityRecognizer.findEntity(results.entities, 'builtin.datetime');

        session.messageData = {
            person: person || null,
            location: location || null,
            time: time || null
        }

        if(!session.messageData.person){
            builder.Prompts.text(session.messageData.person, prompts.meetingPersonMissing); 
        } else {
            next();
        }
    },
    function (session, results, next) {    
        if(!session.messageData.location){
            builder.Prompts.text(session.messageData.location, prompts.meetingLocationMissing); 
        } else {
            next();
        }
    },
    function (session, results, next) {
        if(!session.messageData.time){
            builder.Prompts.text(session.messageData.time, prompts.meetingTimeMissing); 
        } else {
            next();
        }
    },
    function (session, results) {
        debugger;
        if (results.response) {
           session.send('Meeting scheduled');
        } else {
            session.send(prompts.canceled);
        }
    }
]);

Update #3: In this version it works well if the utterance doesn't contain any relevant entities. For example "Could we meet?" works fine.

The issue with this version is when I try "Could we meet tomorrow?". Tomorrow is successfully identified as a datetime entity, however once it hits the next() in this block:

 function getDate(session, results){
    session.dialogData.topic = results.response;

    if(session.dialogData.date){
        next();   
     }else{
        builder.Prompts.time(session, "What date would you like to meet?");   
     }

}

It fails and gives me the same Too many calls to to session.EndDialog() issues

dialog.on('Meeting', [meetingQuery, getDate, getTime, respondMeeting]);

function meetingQuery(session, results){

    if (results.response) {
        session.dialogData.date = builder.EntityRecognizer.resolveTime([results.response]);
    }


    session.userData = {
        person: session.message.from.name
    }

    builder.Prompts.text(session, "Hi "+ session.userData.person +"!\n\n What is the meeting in reference too?");

}

function getDate(session, results){
    session.dialogData.topic = results.response;

    if(session.dialogData.date){
        next();   
     }else{
        builder.Prompts.time(session, "What date would you like to meet?");   
     }

}

function getTime(session, results){
    if (results.response) {
        session.dialogData.date = builder.EntityRecognizer.resolveTime([results.response]);
    }


     if(session.dialogData.time){
        next();   
     }else{
        builder.Prompts.choice(session, "Your professor has the follow times availeble?", ["1pm", "2pm", "3pm"]);   
     }
}

function respondMeeting(session, results){
    var time = results.response;
    session.send("Your meeting has been schedueld for " + session.dialogData.date + " at " + time.entity + ". Check your email for the invite.");
}

Upvotes: 2

Views: 1321

Answers (3)

krazy
krazy

Reputation: 11

I think you should access

results.response.person 

instead of

results.person 

same applies for other closures for this waterfall.

Upvotes: 0

Try this instead, it works on my bot.

dialog.on('QuieroQueMeLlamen', [
    function (session, args) {
    	var Telefono = builder.EntityRecognizer.findEntity(args.entities, 'Usuario::Telefono');
        
        if(!Telefono){
        	builder.Prompts.number(session, "Dame un número telefónico donde pueda llamarte una de nuestras enfermeras (sin espacios ni caracteres: ej: 3206907529)");
        }      
        
    },
    function (session, results) {
        if (results.response) {
        	//IF STRLEN es un celular entonces:
            session.send("Te estamos llamando al número %s, por favor contesta", results.response);
        } 
    }
]);

Upvotes: 1

Etienne Margraff
Etienne Margraff

Reputation: 711

You should not pass a parameter to the next() function but use the session.YOUVARIABLES to store data through the waterfall.

Something like :

function (session, results, next) {
    var person = builder.EntityRecognizer.findEntity(results.entities, 'Person');
    if(!person){
        builder.Prompts.text(session, prompts.meetingPersonMissing); 
    } else {
        session.person = person.entity
        next();
    }
}

Upvotes: 0

Related Questions