Actions on Google (Handle fallback) - actions-on-google

I have a query on a Google home (Dialogflow).
In a specific, after I execute fallback intent three times it exits with a statement
Sorry I can't help
But it should prompt
I am ending this session see you again later.
Here is code of fallback intent
app.intent('Default Fallback Intent', (conv) =>
{
const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT'));
if (repromptCount === 0) { conv.ask(`Hey are you listening?`); }
else if (repromptCount === 1) { conv.ask(`Are you still around?`); }
else if (conv.arguments.get('IS_FINAL_REPROMPT')) { conv.close(`I am ending this session see you again later.`); }
});

I am assuming you're trying to follow the directions in the documentation about dynamic reprompts for "no-input" type responses.
The problem appears to be that you're trying to use this for the Fallback Intent, which is not specifically triggered on a NO_INPUT event. So it is doing the test, and neither the REPROMPT_COUNT nor IS_FINAL_REPROMPT arguments are set.
If you're using the multivocal library, it will keep counters of all the Intents and Actions that are called (both for the session and sequentially) and has some macros that assist in your responses.
If you want to use the existing library, you'll need to keep track of this yourself and either store this in a Context or store it in the session data object.
If you intended to use this as part of a "no-input" response, you need to make sure you're using this with an Intent that has the actions_intent_NO_INPUT event set.

Related

How to do actions when MongoDB Realm Web SDK change stream closes or times out?

I want to delete all of a user's inserts in a collection when they stop watching a change stream from a React client. I'm using the Realm Web SDK for this.
Here's a summary of my code with what I want to do at the end of it:
import * as Realm from "realm-web";
const realmApp: Realm.App = new Realm.App({ id: realmAppId });
const credentials = Realm.Credentials.anonymous();
const user: Realm.User = await realmApp.logIn(credentials);
const mongodb = realmApp?.currentUser?.mongoClient("mongodb-atlas");
const users = mongodb?.db("users").collection("users");
const changeStream = users.watch();
for await (const change of changeStream) {
switch (change.operationType) {
case "insert": {
...
break;
}
case ...
}
}
// This pseudo-code shows what I want to do
changeStream.on("close", () => // delete all user's inserts)
changeStream.on("timeout", () => // delete all user's inserts)
changeStream.on("user closes app thus also closing stream", () => ... )
Realm Web SDK patterns seem rather different from the NodeJS ones and do not seem to include a method for closing a stream or for running a callback when it closes. In any case, they don't fit my use case.
These MongoDB Realm Web docs lead to more docs about Realm. Unless I'm missing it, both sets don't talk about how to monitor for closing and timing out of a change stream watcher instantiated from the Realm Web SDK, and how to do something when it happens.
I thought another way to do this would be in Realm's Triggers. But it doesn't seem likely from their docs.
Can this even be done from a front end client? Is there a way to do this on MongoDB itself in a "serverless" way?
If you want to delete the inserts specifically when a (client-)listener of a change-stream stops listening you have to implement some logic on client side. There is currently no way to get notified of such even within Mongodb Realm.
Sice a watcher could be closed because the app / browser is closed I would recommend against running the deletion logic on your client. Instead notify a server (or call a Mongodb Realm function / http endpoint) to make the deletions.
You can use the Beacon API to reliably send a request to trigger the delete, even when the window unloads.
Client side
const inserts = [];
for await (const change of changeStream) {
switch (change.operationType) {
case 'insert': inserts.push(change);
}
}
// This point is only reached if the generator returns / stream closes
navigator.sendBeacon('url/to/endpoint', JSON.stringify(inserts));
// Might also add a handler to catch users closing the app.
window.addEventListener('unload', sendBeacon);
Note that the unload event is not reliable MDN. But there are some alternatives which maybe be good enough for your use case.
Inside a realm function you could delete the documents.
That being said, maybe there is a better way to do what you want to achieve. Is it really the timeout of the change stream listener that has to trigger the delete or some other userevent?

Getting Text Input in Google Actions(recent version)

How to get user input from actions SDK(recent version).
In the previous version, we just use text intent like the example
app.intent('actions.intent.TEXT', async (conv, input) => {
console.log('input', input)
})
I want to get user input as we do get in the previous version but the previous version is deprecating.
How to get user input from the action builder?
In recent version they are providing intents, scenes, types etcc...
The custom NLU sample provides an example of sending the user's full text to your webhook to process.
It is accomplished through a simple user_utterance intent that accepts freeText and then calls a webhook.
Then your webhook can handle the intent's parameter:
app.handle('doAny', (conv) => {
const any = conv.intent.params.any.original;
conv.add(`You said ${any}.`);
});

Is it possible to use one intent to detect all user input to be use to query data from Firestore?

I am trying to connect my chat bot created using Dialogflow to the Google Cloud Firestore. I was thinking if I have to map the intent in the fulfillment one by one that'd be a huge amount of work.
Is it possible to write a fulfillment to detect the user input and maps to the intent then go on to query data from the Firestore?
For example, I would like the agent below to map the user input to the intent I already created then query
function intentHandler(agent) {
const userInput = request.body.queryResult.parameters['Entity_detected'];
}
Dialogflow provides default intent called Fallback Intent. It will be called when there is no matching intent found.
You can take advantage of this and call webhooks on this intent.
Checkout official document
You can indeed map to a different intent using the user input. For this you can use context to map to a different intent after sending a response. I've never tried it with entities, but I imagine it would be implemented something like this.
const userInput = request.body.queryResult.parameters['Your Entity'];
switch (typeof(userInput)) {
case SelectQueryEntity:
// perform select query
conv.ask("I've performed a select query");
conv.context.set("SelectQueryIntent", 1);
break;
case UpdateQueryEntity:
// perform update query
conv.ask("I've performed a update query");
conv.context.set("UpdateQueryIntent", 1);
break;
etc..
};
The context will allow you to navigate the conversation into your desired direction. So if the user inputs anything that matches a SelectQueryEntity, the context will be set to SelectQueryIntent. Any intent which has SelectQueryIntent as an input context will then be allowed to follow up the users next input. Using an intent lifespan of 1 makes this navigation easier to work with.

Are in-dialog intents supported in the ActionsSdkApp

Are in-dialog intents supported? I tried something that I thought might work. It didn't. I'm wondering if I need to look harder for a bug on my part or if I can't get there from here. I looked at the ask() method:
ask (inputPrompt, dialogState) {
debug('ask: inputPrompt=%s, dialogState=%s',
JSON.stringify(inputPrompt), JSON.stringify(dialogState));
const expectedIntent = this.buildExpectedIntent_(this.StandardIntents.TEXT, []);
if (!expectedIntent) {
error('Error in building expected intent');
return null;
}
return this.buildAskHelper_(inputPrompt, [expectedIntent], dialogState);
}
It is specifying the name of the intent where the user's response will end up. The comments above the buildExpectedIntent_() method have this quip
intent Developer specified in-dialog intent inside the Action
* Package or an App built-in intent like
* 'assistant.intent.action.TEXT'.
So I thought I might be able to create a new method by starting with the ask method and adding a parameter to take the name of an in-dialog intent and then defining the intent in my action package. I don't see an obvious error when I do that but my text intent is the one that gets the text spoken by the user, not the in-dialog intent.
Should this work - that is should I keep looking for where I went wrong?
While I'm at it, there is also this
* Refer to {#link ActionsSdkApp#newRuntimeEntity} to create
* the list of runtime entities required by this method.
* Runtime entities need to be defined in the Action Package.
just above the description of the intent. What are runtime entities in this context?
It is not possible to match any user defined intent using the Actions SDK integration after the MAIN intent as all the next intents will match the TEXT intent unless it's a built-in intent (system intent). You can find more info on ExpectedIntent in this page.
User defined intents are only accessible through deep-linking. More info here.

ASP.NET MVC2 AsyncController: Does performing multiple async operations in series cause a possible race condition?

The preamble
We're implementing a MVC2 site that needs to consume an external API via https (We cannot use WCF or even old-style SOAP WebServices, I'm afraid). We're using AsyncController wherever we need to communicate with the API, and everything is running fine so far.
Some scenarios have come up where we need to make multiple API calls in series, using results from one step to perform the next.
The general pattern (simplified for demonstration purposes) so far is as follows:
public class WhateverController : AsyncController
{
public void DoStuffAsync(DoStuffModel data)
{
AsyncManager.OutstandingOperations.Increment();
var apiUri = API.getCorrectServiceUri();
var req = new WebClient();
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["result"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
req.DownloadStringAsync(apiUri);
}
public ActionResult DoStuffCompleted(string result)
{
return View(result);
}
}
We have several Actions that need to perform API calls in parallel working just fine already; we just perform multiple requests, and ensure that we increment AsyncManager.OutstandingOperations correctly.
The scenario
To perform multiple API service requests in series, we presently are calling the next step within the event handler for the first request's DownloadStringCompleted. eg,
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["step1"] = e.Result;
OtherActionAsync(e.Result);
AsyncManager.OutstandingOperations.Decrement();
}
where OtherActionAsync is another action defined in this same controller following the same pattern as defined above.
The question
Can calling other async actions from within the event handler cause a possible race when accessing values within AsyncManager?
I tried looking around MSDN but all of the commentary about AsyncManager.Sync() was regarding the BeginMethod/EndMethod pattern with IAsyncCallback. In that scenario, the documentation warns about potential race conditions.
We don't need to actually call another action within the controller, if that is off-putting to you. The code to build another WebClient and call .DownloadStringAsync() on that could just as easily be placed within the event handler of the first request. I have just shown it like that here to make it slightly easier to read.
Hopefully that makes sense! If not, please leave a comment and I'll attempt to clarify anything you like.
Thanks!
It turns out the answer is "No".
(for future reference incase anyone comes across this question via a search)