watson-developer-cloud / botkit-middleware

A middleware to connect Watson Conversation Service to different chat channels using Botkit
https://www.npmjs.com/package/botkit-middleware-watson
Apache License 2.0
207 stars 255 forks source link

Never Restart conversation? #107

Closed huesoamz closed 6 years ago

huesoamz commented 6 years ago

Hi, I have a bot on this fanpage:

https://www.facebook.com/Conversationwatsonw3-2-1340872815982568 (its spanish bot about apply for differents jobs)

The problem its the following: 2 days ago I started a conversation, and I leave that in the middle of XXX Dialog...Today I speak again with the bot and the conversation its "STILL ALIVE" he dont restart the conversation id, Watson follow in the same STEP that I left 2 days ago...

That is a normal behaviour?, its configurable to refresh the conversation after no hear from the same user for XXX TIME?

Thanks in advance,

Regards.-

Naktibalda commented 6 years ago

There is no builtin storage cleanup functionality in the watson middleware. Implementation is likely to depend on the storage module that you use.

huesoamz commented 6 years ago

I use the default:

var controller = Botkit.facebookbot({ debug: true, access_token: process.env.FB_ACCESS_TOKEN, verify_token: process.env.FB_VERIFY_TOKEN, receive_via_postback: true, require_delivery: true }); var bot = controller.spawn(); controller.hears('(.*)', 'message_received', function(bot, message) { ...

So, its a normal behaviour?, the conversation keeps the last Dialog Node forever?

Naktibalda commented 6 years ago

There is no storage option and no json_file_store, so you are actually using in-memory store, aren't you? Do you see this message in the output ** No persistent storage method specified! Data may be lost when process shuts down.?

If that's the case, then you should start using a more persistent kind of storage. The simplest option is to store data in files by adding json_file_store option.

Then you could use some kind of scheduled job which would delete files not updated for X hours.

huesoamz commented 6 years ago

image I dont idea about that option, there exist a guide how to storage watson conversations? a example? I dont find anything in this repository =/ I'm using 1.3.0 version of this middleware, at this momento I can't upgrade to the last 1.6.0 should be a lots of new changes and we have the bot on production enviroment, 1.3.0 its capable to storage too true?

pgoldweic commented 6 years ago

Note that the file-storage option that @Naktibalda mentions is not going to give you a way to control the start/end of conversations (you'll see exactly the same behavior that you're currently seeing). I was going through this myself last month until I realized that I had to code that functionality myself if I wanted to use file storage and have conversations start/end. Or perhaps there is something already coded for this in other storage providers, as @Naktibalda mentions (I haven't checked myself, but it would be good to know what you are able to find, so please update this issue in that case). Also note that the file-storage option is default as long as you specify it when creating your controller, but not otherwise. For example, here's my controller definition:

 var jsonFile = __dirname + '/../.data/test-db';

// Create the Botkit controller, which controls all instances of the bot.
var controller = Botkit.sparkbot({
    public_address: process.env.public_address,
    ciscospark_access_token: process.env.access_token,
    studio_token: process.env.studio_token, 
    secret: process.env.secret, 
    studio_command_uri: process.env.studio_command_uri,
   ,json_file_store: jsonFile 
});
huesoamz commented 6 years ago

@pgoldweic thanks I use that config now, but didnt work as I expected: https://jsonblob.com/294404b9-aeb0-11e7-9b68-2dcda6beeed7 (that its a example that a json that its store)

1) First at all, save data "rare" 2) I erase the json, and chat again..and the bot persist en same STEP that I leave before :S...so what its the solution for refreshing the conversation whitout RESTART the NodeJS? (deleting the files doenst work)

Thanks!

pgoldweic commented 6 years ago

Sorry, I don't have time to read your code. However, I think you missed an important part of my reply above. I said "I was going through this myself last month until I realized that I had to code that functionality myself if I wanted to use file storage and have conversations start/end.". The pieces of logic that I ended up coding were as follows:

Note that this was just my way around this problem; there could be better ways (also, I am currently just using one-to-one conversations). Also, as I mentioned earlier, you might want to do a little research on different storage providers for botkit -instead of using the built-in file storage-, since they might incorporate this concept (of the conversation start/end) already in them with no need for extra coding.

huesoamz commented 6 years ago

Thanks for your explanation but I dont understand...I save the conversation in users "folder" (not me..its automatic)....so regarding you and @Naktibalda sayed if we ERASE the all json in the folder the conversation will be restart...and that it's not true...the conversation DONT restart, so...I dont wanna restart my nodeJS for clear all of my conversations...what exactly I need to do? because the adding this: json_file_store: __dirname + '/data/db/', in bot-facebook.js + delete ALL json in that folder...doenst work

pgoldweic commented 6 years ago

I know @Naktibalda suggesting deleting the json directly, but I did not suggest that. Instead, I gave you a list of 4 steps above that I needed to code into my bot in order to have conversations start and end (and you'd need to do the same). In order to implement this, you will need to familiarize yourself with the botkit storage documentation (https://github.com/howdyai/botkit/blob/master/docs/storage.md ). I cannot share the totality of my code, but here is a little piece (more specifically, step 2 in my list above) to give you an idea:

(BTW, I am using watson-middleware, so you don't want to take this as is; you'll need to modify it to fit your case:)

  controller.hears(['.*'], ['direct_message','direct_mention'], function(bot, message) {
    console.log("Just heard the following message: " + JSON.stringify(message));
    // retrieve conversation history to see if bot should ask about possible resumption
    controller.storage.channels.get(message.channel, function(err, data) {
        if (err ) {
            console.log("Warning: error retrieving channel: " + channelId + " is: " + JSON.stringify(err));
        } else {
            if (!data || data === null) {
                data = {id: message.channelId};
            }
            console.log("Successfully retrieved conversation history..." );
            if (data && data.lastActivityTime) {
                const lastActivityDate = new Date(data.lastActivityTime)
                const now = new Date()
                const millisecondsElapsed = now.getTime() - lastActivityDate.getTime()
                if (millisecondsElapsed > maxElapsedUnits) {//should ask for resumption
                    console.log("Should be asking for resumption...")
                    askForResumption(bot, message, watsonInterpret )
                } else {// no need to ask for resumption
                    console.log("No need for bot to ask for resumption...")
                    watsonInterpret(false, bot, message);
                }
            } else {
                console.log("No need for bot to ask for resumption...")
                watsonInterpret(false, bot, message);
            }
        }
    });
});

Some notes: the 'askForResumption' function asks the user whether they want to start or resume the conversation -I coded it myself-, and the 'watsonInterpret' function passes on to watson the user's utterance after possibly calling a 'resetBotkitContext' function depending on the value of the first parameter (again, I coded all of these functions myself). You may not want the complication of the 'askForResumption'; this is all up to you. Hope this helps.

huesoamz commented 6 years ago

Thanks for share your piece of code, and thanks for share the documentation of botkit. I use bokit middleware too, its a pity that we have to do a lot of work for erase the conversations, but I appreciate to much your help!

@Naktibalda According to you, your solution would be delete the json but that doenst work, so..its a issue of this middleware? its possible to fix please? I need a fast/easy solution, not a complex solution.

I really appreciate the help of @pgoldweic but its not possible at this moment make a new logic trying to erase conversations with a custom workflow, as she indicates, first at all because i dont have channels, i only see jsons on "users" folder.

Thanks!

Naktibalda commented 6 years ago

@pgoldweic has more experience with this subject than I do, because I hadn't had to implement anything like this yet.

Watson middleware has no persistence of its own, it uses botkit's storage, so it can't be an issue of the middleware.

Replace channels in that code with users to make it check user storage.

huesoamz commented 6 years ago

@Naktibalda oks, maybe we have lack of documentation here, I try to summarize:

1) By default the conversations between Watson and Facebook never refreshing, until your NodeApp is restarted. 2) Using this:

var controller = Botkit.facebookbot({ json_file_store: __dirname + '/data/db/', .... You can restart the conversations if you use this line: var userId =message.user; controller.storage.users.delete(userId, function(err) { });
By default the storage use users folder, not channel.

Thanks both for the help me, I hope this would be usefull for others.

germanattanasio commented 6 years ago

closing this due to inactivity

AutomataVM commented 4 years ago

How should I do this while using websockets? Each time the conversation restarts, whenever I send a message watson asks the question where it left off, rather than starting again. I am not using any method to store the questions or anything like that.

Naktibalda commented 4 years ago

@juanpablo64 you can handle it the function which handles hello event:

controller.on('hello', handleHelloEvent);

If you want to restart conversation, you have to delete conversation state from storage (key = 'user.' + message.user).

pgoldweic commented 4 years ago

I’d like to point out that even though the suggestion is a good idea, this may do only part of the job, as many conversations may start with an intent different than ‘hello’ (in other words, depending on your bot, users may first talk to it without saying hello, but directly asking a question). My own solution to this was to:

1- Keep at least a record of when each message (or at least the last message) was sent, with regards to a particular user (that is, messages from and to the user). Note: you could keep this even if you don’t keep the conversation content.

2- Once a message is received (any such message, and not just hello), check (using your particular algorithm*) to see whether a new conversation should be started or not, taking as one input the values saved in #1. At that point, if the decision is to restart, then you do this in some way by clearing the conversation state (the suggestion in the previous email could do it). -Patricia

*this could involve asking the user for confirmation, simply deciding that after x minutes of inactivity you consider a conversation done, etc.

From: Gintautas Miselis notifications@github.com Sent: Monday, December 9, 2019 9:50 AM To: watson-developer-cloud/botkit-middleware botkit-middleware@noreply.github.com Cc: Patricia N Goldweic pgoldweic@northwestern.edu; Mention mention@noreply.github.com Subject: Re: [watson-developer-cloud/botkit-middleware] Never Restart conversation? (#107)

@juanpablo64https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_juanpablo64&d=DwMCaQ&c=yHlS04HhBraes5BQ9ueu5zKhE7rtNXt_d012z2PA6ws&r=wKI-i4jfOP2_IX0VXdng78rOaKode2RXLGgvtbrQuLI&m=3k6OwiWV1qtChZPHBa2MNgm0zF--Zq4Qvd_mbCPMI_8&s=8od1ac3-FTx9zXOgfj6Tukj-E5dgRMUMY_xjpeEJ8JQ&e= you can handle it the function which handles hello event:

controller.on('hello', handleHelloEvent);

If you want to restart conversation, you have to delete conversation state from storage (key = 'user.' + message.user).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_watson-2Ddeveloper-2Dcloud_botkit-2Dmiddleware_issues_107-3Femail-5Fsource-3Dnotifications-26email-5Ftoken-3DAABF66Y7BL477EV3UG7V5TLQXZSMHA5CNFSM4D6PZNJ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEGJUZ7Y-23issuecomment-2D563301631&d=DwMCaQ&c=yHlS04HhBraes5BQ9ueu5zKhE7rtNXt_d012z2PA6ws&r=wKI-i4jfOP2_IX0VXdng78rOaKode2RXLGgvtbrQuLI&m=3k6OwiWV1qtChZPHBa2MNgm0zF--Zq4Qvd_mbCPMI_8&s=wM47bZtBrewPO8wugzj9W_-hLmUMmiLNIGoTtxSJqj0&e=, or unsubscribehttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_notifications_unsubscribe-2Dauth_AABF667FT456V5L3TALGMU3QXZSMHANCNFSM4D6PZNJQ&d=DwMCaQ&c=yHlS04HhBraes5BQ9ueu5zKhE7rtNXt_d012z2PA6ws&r=wKI-i4jfOP2_IX0VXdng78rOaKode2RXLGgvtbrQuLI&m=3k6OwiWV1qtChZPHBa2MNgm0zF--Zq4Qvd_mbCPMI_8&s=J53AKCGNhfbYn5HTNj3Cn9uNOk9nKg__306Ovo9odVs&e=.

AutomataVM commented 4 years ago

@juanpablo64 you can handle it the function which handles hello event:

controller.on('hello', handleHelloEvent);

If you want to restart conversation, you have to delete conversation state from storage (key = 'user.' + message.user).

the problem is that I don't store the conversation in any way, nor mongo nor json file. It just sorts of do automatically, unless I stop the process and restart again. It's weird

Naktibalda commented 4 years ago

Yes, Botkit stores conversation state in memory by default. You should see a warning message about that when the chatbot is started.

AutomataVM commented 4 years ago

yeah, you are right, so calling this function: await storage.delete(); with the user + the message should do it, right?

Naktibalda commented 4 years ago

it depends on a version of botkit you use.

AutomataVM commented 4 years ago

I actually didn't find any on the documentation. I am using V4 on nodejs

Naktibalda commented 4 years ago
bot.controller.storage.delete(['user.' + message.user]);

Botbuilder storage modules used in v4 can read, write and delete multiple items in one call, which is completely useless from Watson middleware point of view and makes code uglier, especially write.