is there a possibility to preserve a session with Actions on Google?
I would like that users can leave the the current session, do something in between for a some minutes / an hour and then start with the next invocation exactly where they have been before. Is that possible?
It isn't impossible, but you would have to save the state yourself (ie - there is nothing that Actions provides that would do this for you automatically).
If you're using API.AI, for example, you could save all of the current contexts in your database. When the user returned, you could see if you have saved contexts and, if so, return them in the response as current contexts (along with any voice message saying you've done so).
As far as API.AI is concerned at that point - you're at the same place you were before.
Related
I am making a bot on Dialogflow with a Fulfillment. Considering the given strict 5-second window in DialogFlow, I am getting [empty response] as a response.
I want to overcome this issue, but my web service requires more than 9 seconds for the execution.
I am considering to redesigning the conversation flow in such a way that we will start streaming audio till the Response is processed.
Example:
User Question: xx xxx xxx xxxx xxxxx?
Response: a). We'll play fixed audio to keep the user engaged for few seconds till it finds a response text in the back end; b).
Receive answers from the web service and save them in the session to
display further.
How can I achieve this and how can I handle the Timeout issue?
You're on the right track, but there are a number of other things to consider.
First, however, keep in mind that anything that is trying to "avoid" the 5 second timeout already indicates some issues with the design. Waiting 10 seconds for a reply is a pretty long time with something as interactive as voice! Even 5 seconds, which is the timeout, is a long time. (And there is no way to change this timeout.)
So the first thing you may want to do is consider if there is a better/faster way to do what you want.
If not, the rough approach would be something like this:
Get the request from the user.
Track a unique identifier, either tied to the user or tied to the session. You'll be using this as a key into some kind of database or data store.
Start the API call as part of an asynchronous request or in another thread.
Reply immediately that you're working on it in a way that the user will send another request. (See below for this issue.) You'll want to make sure that the ID is maintained as part of this session - so you'll need to save it as part of the Session data.
At this point - you're basically doing two things in parallel.
When the API call completes, it needs to save the result in the datastore against the identifier. (It can't save it in the session itself - that response was already sent back to the Assistant.)
You're also waiting for a reply from the user. When it comes in:
Check to see if you have a response saved for this session yet.
If not, then go back to step 4. (You may want to track how many times you get here and give up at some point.)
If you do have the result, reply to the user with the information.
There is an issue with how you reply in step 4, since you want to do something that will guarantee you another request from the person expecting an answer. There are a few possible approaches:
The most straightforward way would be to send back a Media response to play a few seconds of "hold music". This has the advantage that, when the music stops, it will send an event to Dialogflow which you can capture as an Intent and then continue with step 5.
But there are some problems:
Not all versions of the Assistant support the Media response. You will need to check to confirm the feature is supported before you use it and, if not, use another approach (see below).
The media player that is presented on some Assistants allow the user to stop playback, or will not correctly send an event when the audio stops in some situations. So you may never get another request in this session.
Another approach involves some more advanced conversation design tricks, so may not always be suitable for your conversation. Your response can say that you're looking up the results but then ask the user a question - possibly one that is related to other information that you will need. With their reply, you can collect this information (if you need it) and then see if you have a result yet.
In some conversations - this works really well. For example, if you're looking up flights to somewhere, while you're looking that up you might ask them if they will need a hotel or rental car, which you might ask about anyway.
Other conversations, however, don't easily have such questions. In these cases, you may need to ask something that isn't relevant while you stall for time.
we have detect_intent function in Dialogflow python client to detect the intent of a particular text wherein we need to pass session which is created using session_id. I use a function to generate a hashed session_id for a particular end-user. Can I pass the same session_id every time I call detect_intent? In docs, they say the session is valid for 20 mins, so if I use the same session_id, will it be a new session?
Please see this excellent answer on Dialogflow Session length. Short answer - there's nothing to stop you re-opening the session after 20 minutes by using the same session ID, but all the contexts (which are the only thing that really matter as far as sessions are concerned) will have dropped off. You must also save the contexts to your database to re-initialise Dialogflow to pick up where you left off.
It's worth noting however that you probably don't need to (and shouldn't) do this for almost all use-cases.
I am creating a chatbot which have an intent with a payment link. So on trigger of this intent, I made call from webhook fulfillment to third party api which takes approx 20secs to respond. But in this period of time my response is timed out as it is limited to 5 sec from google.
Can you please suggest what approach should I follow. I just want to wait for approx 20 sec to respond.
Thanks.
one option is to keep the conversation alive using events (generated by the webhook) which trigger dedicated intents.
When a payment must be performed the webhook starts a background process to deal with the 3rd party payment API, and sleep for 4-5 sec, after that generates an event (setFollowupEvent PAYMENT_IN_PROGRESS). This event is associated to a DialogFlow Intent which fires as soon as the event is sent back to the platform.
At this point you have another incoming webhook call: check status of the payment, if it is still in progress (likely after 5 sec) then sleep 4-5 sec and send another event (setFollowupEvent PAYMENT_IN_PROGRESS_2) which produces the same workflow.
There are so many times you can do this (I think a max of 3), so you need to cater for the fact that the payment does not terminate in time (fallback scenario).
A smart option could be to keep engaging the user with the conversation, not always easy, depending on what your chatbot is about.
Hope it helps.
The short answer is that you can't.
The longer answer is that you need to think about this as a conversation. If you asked someone a question, and didn't get any response from them for 20 seconds - that would be pretty uncomfortable, wouldn't it?
Instead, we have come up with ways to compensate for that silence. In a physical conversation, people may engage with you and ask you questions to fill the time. If you're on the phone, they may play hold music. Or we may end the conversation for now and tell them later when there is a result.
When building an Action, we have similar parallels that may work better or worse based on our exact needs.
Engaging in conversation
One approach is that when we get the request from the user, we do two things:
Start a task that will execute the query and save the results in a separate "answer database", indexed against the user, a session ID, or some other temporary id we can generate and use later.
While the query is running, we reply to the user saying we're working on it, and asking them another question.
Then, when they reply with their answer to this other question, we can check if we have an answer for them in the database. If we do, we'll reply with it. If not, we'll repeat step 2 until we do.
This approach works well if we either have other questions to ask, or if we're in a good place to "make small talk". Picture booking an airline reservation - while we look up flights, we may want to ask if they prefer window or aisle seats (Which we'd need to ask later) or make small talk by asking if they're traveling for business or leisure.
Using "hold music"
A variant of this allows us to play some hold music while we're processing the answer.
Instead of asking a question in step 2 above, we reply with a Media Response that plays 20 seconds or so of music. When the music completes, our fulfillment webhook will be sent a MEDIA_STATUS event and we can either return the information from the answer database, or say we're still working on it and play more music.
This is less conversational, but may work better if we don't actually have anything to say in the meantime.
Sending a notification
If the response may take a very long time, then it may just be best to let them do other things and to send a notification or a text or email when you have a result. These cases, however, require the user to have registered with you in some way and are probably more appropriate if you have a long-standing relationship with the user.
Summary
You should be returning results as quickly as you can to keep it feeling like a conversation. When you can't, consider other means, just like how we would consider what it would be like if we were talking to another person.
We have an event sourced system using GetEventStore where the command-side and denormalisers are running in two separate processes.
I have an event handler which sends emails as the result of a user saving an application (an ApplicationSaved event), and I need to change this so that the email is sent only once for a given application.
I can see a few ways of doing this but I'm not really sure which is the right way to proceed.
1) I could look in the read store to see if theres a matching application however there's no guarantee that the data will be there when my email handler is processing the event.
2) I could attach something to my ApplicationSaved event, maybe Revision which gets incremented on each subsequent save. I then only send the email if Revision is 1.
3) In my event handler I could load in the events from my event store for the matching customer using a repository, and kind of build up an aggregate separate from the one in my domain. It could contain a list of applications with which I can use to make my decision.
My thoughts:
1) This seems a no-go as the data may or may not be in the read store
2) If the data can be derived from a stream of events then it doesn't need to be on the event itself.
3) I'm leaning towards this, but there's meant to be a clear separation between read and write sides which this feels like it violates. Is this permitted?
I can see a few ways of doing this but I'm not really sure which is the right way to proceed.
There's no perfect answer - in most cases, externally observable side effects are independent of your book of record; you're always likely to have some failure mode where an email is sent but the system doesn't know, or where the system records that an email was sent but there was actually a failure.
For a pretty good answer: you're normally going to start with a facility that sends and email and reports as an event that the email was sent successfully, or not. That's fundamentally an event stream - your model doesn't get to veto whether or not the email was sent.
With that piece in place, you effectively have a query to run, which asks "what emails do I need to send now?" You fold the ApplicationSaved events with the EmailSent events, compute from that what new work needs to be done.
Rinat Abdullin, writing Evolving Business Processes a la Lokad, suggested using a human operator to drive the process. Imagine building a screen, that shows what emails need to be sent, and then having buttons where the human says to actually do "it", and the work of sending an email happens when the human clicks the button.
What the human is looking at is a view, or projection, which is to say a read model of the state of the system computed from the recorded events. The button click sends a message to the "write model" (the button clicked event tells the system to try to send the email and write down the outcome).
When all of the information you need to act is included in the representation of the event you are reacting to, it is normal to think in terms of "pushing" data to the subscribers. But when the subscriber needs information about prior state, a "pull" based approach is often easier to reason about. The delivered event signals the project to wake up (reducing latency).
Greg Young covers push vs pull in some detail in his Polyglot Data talk.
https: xyz dot com/authenticate/cc.php
This is the page 3 of my registration....where my members enter their credit card. This is tied into my authorize.net account.
One thing i noticed recently is this page can be accessed on its own just by typing in the URL.. there is no required pre-url that leads up to it. This seems unsafe, but regardless if someone wanted to abuse it they could just go through the registration process and keep submitting incorrect CC numbers.. costing me money right?
I dont remember if we put an IP limit on it, or again if that is even 100% safeguard.
I am pretty sure we did something where if they enter mastercard with their number(temporarily stored) and it gets sent back as invalid it will match that and not allow them to keep entering the wrong 16 digit number.
Should i just leave the page accessible without specific pages allowing access and worrying about IP limits instead? Couldn't someone just keep switching their ip and submitting this page with incorrect CC's or fake ones at that?
What is the proper way to secure this page considering i/losing my merchant account could be the one at risk?
Thank you in advance
It is strange that you would allow direct acces to the 3rd step of the process, where is all the other data like the user name, addres, ...?
This are some ideas of what I would do, a completely secure system (which might not exists) would be much more complex than my simple steps.
note that you probably would like to first allow the users to register with some information where you can know who they are (verified email, verified phone number, etc) then and only then, you do the credit card thing, and if they continuosly input wrong or invalid numbers, you can do something else, like black-listing them, call them, insult them, etc..
note 2 I spent long time writting this, the more I read it and think about it, the worse it seems to be, but as it is already written I'll post it anyway.
Some notes before begin:
There is only one address, for example /authenticate/auth.php
The process has a "state" and depending on this, it will show/do different things.
For different states has other extra files which are included depending on the state.
After the process starts, a session is created and linked with the user IP, the process state and any other identifiable information about the user, for example 'User-Agent', this data is saved in the server.
Seems you would like to show a different state using different pages, so it will be like that. But actually I would do in a single page using ajax calls.
There is NO black-listing of suspicious IP addresses(too many normal or buggy or completely wrong requests), it could be added if desired, but the complexity increases. You might or might not want to do this, maybe a capcha would be enough, but..
There is NO capcha which might help in some cases, but the session handling I describe here might need to change.
There is NO email verification which you probably want to do.
Let's say that the process states are ask_name, ask_address, ask_cc, etc...
So, when there is any request to the auth page (/authenticate/auth.php), this is what we could do:
1 If 'Referer' doesn't come from one of the possible process starters (main page, etc,) or this page (/authenticate/auth.php), we redirect to the main page. end.
This first step avoids people writting the address directly or coming from untrusted pages.
2 If there is no session information for this request:
2.1 If there is a 'user_name' parameter AND 'Referer' is this page (/authenticate/auth.php)
2.1.1 If that user name is already registered, show(include, not redirect) 'ask_name.php' with the extra notice "User already registered". end.
2.1.2 Create a session for this user, link it with it's IP, User Agent, etc, other data.
2.1.3 Set the state to ask_address (the second) and show 'ask_address.php'. end.
2.2 Else (no parameter or 'Referer' was wrong)
2.2.1 Show 'ask_name.php'. end.
This second step either shows the first screen (ask_user) or the second (ask_name), it delays the creation of the session until we are sure the user wants to do something real.
It has a couple of problems:
Some user (or program) continuosly sends requests without session but with 'user_name', so forcing you to always check if the user is valid or not, and may slow things down. This could be avoided using several different techniquest, for example using a capcha or by black listing some IPs for some time.
It could be possible that one user start the process with a 'user_name' which doesn't exists, but he is slow and takes some time to finish the process, while this is happening, a second user begins and finish the process with the same 'user_name', so when the first user is going to finish, it will fail at the last step. This could be avoided with several different techniques which are left as an exercice.
3 If there is session information for this requests (this is the else to the previous step)
3.1 If referer is not this page OR the IP stored in the server is not the same as the current request OR some other data like User Agent is different OR the state is invalid (not in the list of states), remove the session id from the request (so the browser deletes it) and show 'ask_name.php' with the extra notice "Looks like your device changed!!!". end.
3.2 'include' the page for the state:
3.2.1 If the parameters are passed and are correct, set the state to the-next-state and show the page for it. If is the last state do something appropiate for the last state. end.
3.2.2 Show the same page for this state with an error message for the user to retry. end.
This last step tries to ensure that the request is not coming from a different computer and/or with stolen session keys.