howdyai / botkit

Botkit is an open source developer tool for building chat bots, apps and custom integrations for major messaging platforms.
MIT License
11.48k stars 2.28k forks source link

Facebook attachment are not present using conve.extractResponses() #885

Closed KarlisJ closed 6 years ago

KarlisJ commented 7 years ago

I have conversation in messenger bot where I ask series of question including to send an image and share your location.

bot.createConversation(message, function(err, convo){
    convo.addMessage('Series of questions', 'default');
    convo.addQuestion('Category', function(response, convo){
        convo.next();
    },{key: 'cat'}, 'default');

    convo.addQuestion('Subategory', function(response, convo){
        convo.next();
    },{key: 'subcat'}, 'default');

    convo.addQuestion('image', function(response, convo){
        console.log('lets inspect image respone: ', response);
        convo.next();
    },{key: 'image'}, 'default');

    convo.addQuestion('description', function(response, convo){
        convo.next();
    },{key: 'desc'}, 'default');

    convo.addQuestion({
        text:"Please share your location:",
        quick_replies:[{
            "content_type":"location",
        }]
    }, function(response, convo){
               console.log('lets inspect location respone: ', response);
        convo.next();
    },{key: 'location'}, 'default');

    convo.activate();

    convo.on('end', function(convo) {
        if (convo.successful()) {
            var user = convo.context.user;
            var data = convo.extractResponses();
            console.log('Lests see data: ', data);
        }
    });
});

I receive full object in callback for addQuestion() - I can access the payload and validate it. However, when I try to extractResponses()both imageand location are empty strings.

Is it supposed to be like that?

I managed little workaround for image:

convo.addQuestion('image', function(response, convo){
    response.text = response.attachments[0].payload.url;
    convo.next();
},{key: 'image'}, 'default');

but it would not work for location or if user sent more then one image.

Really dont get if this is an issue or that just how botkit does - extractResponses() return only text property. I would hate if I had to save data to database several times during single conversation.

KarlisJ commented 7 years ago

Ok, here is how I handle this:

convo.addQuestion({
    text:"Please share your location:",
    quick_replies:[{
        "content_type":"location",
    }]
}, function(response, convo){
    var obj = {
        lat: response.attachments[0].payload.coordinates.lat,
        lon: response.attachments[0].payload.coordinates.long
    }
    response.text = JSON.stringify(obj);
    convo.next();
},{key: 'location'}, 'default');

And then get those values:

convo.on('end', function(convo) {
    if (convo.successful()) {
        var data = convo.extractResponses();
        data.location = JSON.parse(data.location);
           // Save to database
        }
});

This works and I will use the same for multiple image attachments as well. My question still stands - is this expected?

jonchurch commented 7 years ago

This is a great hack! We should probably update the capture function to do as you suggest, capture more than just text. Feel free to submit a PR if you'd like!

Currently, yes, only text responses are stored. You can see it starting here in CoreBot.js.

KarlisJ commented 7 years ago

Well I am going a bit further right now. Dont know if I am overcomplicating things or its my luck of experience as developer but I found my bots structure quite complicated.

What I found usefull was to simply pass convo object to my model, automate usefull data extraction and save. The key word is "automate extraction". convo.extracResponses() returns all responses including "has_image" and so on. So it is hard to automate it.

So now I do even uglyer hack - i start my conversation withconvo.data = {}and later store any information in there like this convo.data.image = ....

What is nice in this approach is that I can use middleware to already preprocess messages with attachments as I want and then in conversation I just do something like this

If(response.type === 'image'){
   convo.data.image = response.data;
}

where response.data is preprocessed into middleware as object of my liking to save in database.

I then have single helper function in my model (outside af models api) called extractData(convo)

In this approach I dont use convo.extractResponses() but I found it good to have extractResponse('key')to know if something special needs to be done to data before interaction with db.

It is a bit ugly. Propably should make a function convo.addData() and convo.extractData(). Currently I am under presure with works but as I see botkit as must have tool for my next big idea, I will eventually work on cleaner code and share with community.

peterswimm commented 6 years ago

Not sure if this is still relevant post pipeline release, thoughts?