Actions SDK conv.hasScreen not working as expected - dialogflow-es

I am building an action using DialogFlow and Firebase cloud functions. I have a simple check to either ask a question or close the conversation depending on user's device type.
if (conv.hasScreen) {
response += `Do you want to see a picture?`;
conv.ask(response);
return;
}
else{
conv.close(response);
return;
}
I tested using Google Home mini, as expected, the conversation gracefully closed. But when I tested on a phone, the if check failed and the conversation was closed again. I was expecting the contestation to continue and assistant would ask me to show a picture but it did not happen. What am I doing wrong?

It looks like the syntax is simply conv.screen. As the property hasScreen does not exist, the conditional always returns undefined, which is a falsey value.

Take a look at the following to understand Surface Capabilities.
Are you using the following statement or not?
const hasScreen =
conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT');

Related

Alexa lamda get underlying resolved slot value in Node.JS

I have an intent called "Get Status" this has a SHOULDCHANGESTATUS slot which is of type YES_NO
I have the following logic in my Lambda which worked fine using the text Test facility in the Alexa Dev tools.
let changeStatusSlot = handlerInput.requestEnvelope.request.intent.slots.SHOULDCHANGESTATUS.value;
if(changeStatusSlot === 'no'){
return statusFunctions.closureMessage(handlerInput);
}
When I'm testing this using the actual device the word "No" is coming through as "Naw".
The Yes_No slot has "naw" as an acceptable type for "No", so I should be able to handle this.
I need to change the selector on the SHOULDCHANGESTATUS slot to get me the underlying value for this slot, which should be NO but I cant get it to work.
I have tried:
handlerInput.requestEnvelope.request.intent.slots.SHOULDCHANGESTATUS.Resolution.Authorities[0].Values[0].Value.Name
but I get an undefined error.
I was close, the solution was:
handlerInput.requestEnvelope.request.intent.slots['SHOULDCHANGESTATUS'].resolutions.resolutionsPerAuthority[0].values[0].value.name;
This object structure helped me find what i needed:

DialogFlow follow up triggers empty response

I have a DialogFlow intent follow up that I'm having a hard time with. It's the only follow up to my main intent, and the issue I'm having is that when
the incidents.data array is empty it doesn't trigger the conv.ask statement in the else case and causes DialogFlow to throw an empty speech response error. The code looks something like this:
app.intent('metro_timetable - yes', async (conv: any) => {
const incidents = await serviceIncidents.getIncidents();
if (incidents.data.length > 0) {
conv.ask('I have incidents')
} else {
conv.ask(
`I wasn't able to understand your request, could you please say that again?`
);
}
});
incidents.data gets stored in the global scope, and is set deep within
the metro_timetable intent. It stores an incident for the follow up. Because all yes responses trigger the follow up I setup an else case so it catches it if someone says yes when metro_timetable doesn't understand their original request and asks them to repeat it. If incidents.data actually has information to share the dialog triggers correctly and I have incidents is correctly read to the user.
In DialogFlow it looks something like this. Where am I going wrong here?
Your description is a little convoluted how incidents.data actually gets set, but it sounds possible that instead of it being set to an empty array, it isn't set at all. In this case, I suspect that the following happened:
incidents.data would be undefined
Trying to evaluate incidents.data.length would cause an error
Since the program crashes, your webhook doesn't return a result. Since you probably didn't set a result in the UI for the intent, an empty result was returned.
You can probably solve this by doing a test such as (for example)
incidents && incidents.data && incidents.data.length > 0
Your other issue, however, seems to be that you have a Followup Intent set for a scenario where you don't actually want that as the followup. This is one of the reasons you probably shouldn't use Followup Intents but, instead, only set a context when you send a response where that context would make sense, and look for the "Yes" response in the context you define. Then, when metro_timetable doesn't understand the request, you don't set the context and you give an error.
To do this, you would remove the automatically generated metro_timetable-followup context from the two Intents. You'll create your own context, which I'll name timetable for purposes of this example.
In the fulfillment for the metro_timetable Intent, if you respond with something that needs confirmation (ie - when "yes" will be something the user says), you would set the timetable context with something like
conv.contexts.set('timetable',2);
conv.ask('Are you sure?');
You can then create an Intent that checks for timetable as the Incoming Context and has training phrases that are equivalent to "yes". In that Intent, you'd do what you need to and respond.

How do I add button in NetSuite client script and use it as trigger for script function?

I'm trying to add a button to the current record with the Client Script button definition on a script record, but for some reason it's not finding my function. I'm returning my function tryThisand there is a button on the page which I created on the script record with the function tryThis defined in the appropriate field, but the code doesn't run. Here's my script:
define (['N/currentRecord','N/search','N/record'] ,
function(currentRecord,search,record) {
function tryThis(context){
log.debug({
title: 'try this',
details: 'try this'
});
}
function pageInit(context) {
}
return {
pageInit: pageInit,
tryThis: tryThis
};
});
Nothing happens :(
Yes, the script is deployed.
How can I use this button on a client script??
This doesn't exactly answer your question directly, but I hope it may help. I tested this, and there appears to be nothing wrong with the way you've set it up - the only thing that seems to be not working is the log module, which I've come across before in client scripts.
Try running your function using a console.log() or alert() instead (both work for me).
Hopefully someone with more detailed knowledge of the N/log module's design and behavior will chip in, as the documentation seems to indicate that this should work.
At the bottom of your Client Script record in Edit mode you will find where you can easily set the button and function to call.

Chrome screen sharing get monitor info

I implemented chrome extension which using chrome.desktopCapture.chooseDesktopMedia to retrieve screen id.
This is my background script:
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(messageHandler);
// listen to "content-script.js"
function messageHandler(message) {
if(message == 'get-screen-id') {
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], port.sender.tab, onUserAction);
}
}
function onUserAction(sourceId) {
//Access denied
if(!sourceId || !sourceId.length) {
return port.postMessage('permission-denie');
}
port.postMessage({
sourceId: sourceId
});
}
});
I need to get shared monitor info(resolution, landscape or portrait).
My question is: If customer using more than one monitor, how can i determine which monitor he picked?
Can i add for example "system.display" permissions to my extension and get picked monitor info from "chrome.system.display.getInfo"?
You are right. You could add system.display permission and call chrome.system.display.getDisplayLayout(callbackFuncion(DisplayLayout)) and handle the DisplayLayout.position in the callback to get the layout and the chrome.system.display.getInfo to handle the array of displayInfo in the callback. You should look for 'isPrimary' value
This is a year old question, but I came across it since I was after the same information and I finally managed to figure how you can identify which monitor the user selected for screen-sharing in Chrome.
First of all: this information will not come from the extension that you probably built for screen-sharing in Chrome, because:
The chrome.desktopCapture.chooseDesktopMedia API callback only returns a sourceId, which is a string that represents a stream id, that you can then use to call the getMediaSource API to build the media stream.
The chrome.system.display.getInfo will give you a list of the displays, yes, but from that info you can't tell which one is being shared, and there is no way to match the sourceId with any of the fields returned for each display.
So... the solution I've found comes from the MediaStream object itself. Once you have the stream, after calling getMediaSource, you need to get the video track, and in there you will find a property called "label". This label gives you an idea of which screen the user picked.
You can get the video track with something like:
const videoTrack = mediaStream.getVideoTracks()[0];
(Check the getVideoTracks API here: https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks).
If you print that object, you will see the "label" field. In Chrome screen 1 shows as "0:0", whereas screen 2 shows as "1:0", and I assume screen i would be "i-1:0" (I've only tested with 2 screens).
Here is a capture of that object printed in the console:
And not only works for Chrome, but for other browsers that implement it! In Firefox they show up as "Screen i":
Also, if you check Chrome chrome://webrtc-internals you'll see this is what they show in the addStream event:
And that's it! It's not ideal, since this is a label, more than a real screen identifier, but well, it's something to work with. Once you have the screen identified, in Chrome you can work with the chrome.system.display.getInfo to get information for that display.

"immediate_failed" - Could not automatially log in the user

I have a problem when I developed my website with Google+ sign-in:
I did step by step that the doc told me but I always failed at step4:
https://developers.google.com/+/web/signin/
the result was always ""immediate_failed" - Could not automatially log in the user", I just don't kown why, can anyone help me, thanks very much! :-(
Note that in the sample code you pointed to, the "immediate_failed" check is commented out. This is intentional, since the first time a user encounters the Sign-in button on the page, it will fail.
The reason it fails is that when the page first loads, before the user even presses the button, a request is sent to Google to determine if the user has already logged in (via Google or another site, for example). If they are - there is no need for them to log in again, so the button never needs to be shown. But if they have not been logged in already, you will get the "immediate_failed" response, and will need to either show (or not clear) the button.
tl;dr - Don't worry aout getting immediate_failed when the page first loads. This is normal.
As a workaround I use gapi.auth.authorize method in the gapi.auth.signIn callback. Here is my code:
gapi.auth.signIn({
'callback': gPlusLoginCallback
});
function gPlusLoginCallback(authResult) {
if (authResult['status']['signed_in']) {
doSmth(authRes['access_token']);
} else if (authResult['error'] == "immediate_failed") {
gapi.auth.authorize({
client_id: gplusClientId,
scope: 'https://www.googleapis.com/auth/plus.login email',
immediate: true
}, function (authRes) {
if (authRes['status']['signed_in']) {
doSmth(authRes['access_token']);
}
});
}
}
function doSmth(accessToken){
//Do smth
}
Change this setting "immediate: true", to be false " immediate: false".
But if you like to make more complex implementation look at the first sample here https://developers.google.com/api-client-library/javascript/start/start-js. You have to calls to Google's "gapi.auth.authorize({...", the first one with "immediate: true", and the second one with "immediate: false".
The question is old but I faced this issue recently.
In my case, it was because I specified the URI parameter prompt to none. I guess Google doesn't like that if the user has never been logged to your platform before.
Whenever I changed that to consent or totally removed it, it worked great.
In my case, the error was because of explicitly specifying the authorization parameter prompt to 'none',similar to a previous answer.
It worked for me by specifying prompt=None or as per the official docs,you may skip this parameter.

Resources