Dialogflow account linking - google home - dialogflow-es

I'm having slight issues using dialogflow and the SignIn helper with google home, in the simulator it works all fine with account linking including the google home simulator, but when I reset and attempt to link it again with my physical google home that I have, it's saying the following phrase everytime I hit the sign in intent:
"Alright, no problem. Just so you know, that means you won't be able to use your account with x. If you change your mind, you can always come back and sign in then. Sorry, can you say that again?"
This phrase seems to come from when you decline to sign in.
Does anyone have any idea how to fix this? It should actually refer me to my application, on the Google Home simulator is directs me to something like this which is correct:
"To get your account details, you'll need an account with x. To get you signed in, I'll just need some info. If you want more details, say "Tell me more. " So, can I ask Google for your name, email address, and profile picture?"
Heres my intent code:
import { dialogflow, SignIn} from 'actions-on-google';
import '#babel/polyfill';
const app = dialogflow({
debug: true,
clientId: process.env.client_id,
});
app.intent('StartSignIn', conv => {
conv.ask(new SignIn('Sign in'))
});
exports.main = app
P.S does anyone know how to get the sign in status, I can't seem to get it via (conv, params, signin) handler of the intent.
Many thanks!

I replicated your scenario and found a similar issue. Google Assistant went unresponsive after initiating the sign-in intent from my phone. The simulator worked fine for phone and speaker devices. I think it might not be available yet. You can give it a try with a deployed version.
Regarding the (conv, params, signin), be sure to add the actions_intent_SIGN_IN to the intent you want to be detected when the sign-in flow finishes.
After that, you can access the status, like this:
app.intent('signInConfirm', (conv, params, signin) => {
conv.close(`Sign in status: ${signin.status}`);
});

Related

Bixby Capsule asks for login indefinitely

I am working on enabling Bixby Oauth2 Authorization on some actions.
I have configured the authorization.bxb as follows:
authorization {
user {
oauth2-authorization-code (PROVIDER) {
authorize-endpoint (https://X.com/authorize)
client-id (userId)
client-secret-key (password)
login-button-label(LOGIN)
token-endpoint (https://X.com/token)
}
}
}
I have declared my endpoint like:
action-endpoint (MyAuthenticatedAction) {
accepted-inputs ($vivContext)
local-endpoint (myAuthenticatedAction.js)
authorization {
user
}
}
Bixby successfully shows up popup to login and opens up X.com for authorization. After authorization a callback is done to Bixby with code and state parameters.
Bixby now sends the code received from the callback to token-endpoint. But even after getting a success response from the route (as per server logs), Bixby again shows the login popup.
The response of token-endpoint is:
{
"access_token":"XXXXXXXXXXXXXXXXXXX",
"expires_in": 3600,
"refresh_token": "XXXXXXXXXXXXXXXXXX"
}
Bixby continues to show the Login popup yet after receiving the response. Bixby debugger does not help as well.
Answering this question might require some more information about your capsule.
I'd recommend experiencing the behavior again and reaching out to the support team via the "Contact Support" option in Bixby Studio's Help dropdown menu.
This will give the Support team additional diagnostics to investigate further.

Wrong recipient error while using SignIn after switching Dialogflow agents

I made a new Dialogflow agent and transferred my code, which was working on the previous agent, to the new one. One of the main things my agent does is account linking using the SignIn helper. I also got a new clientID in my Google Assistant console and pasted it in my code.
Now however I get this error in my NGROK: {"error":"Wrong recipient, payload audience != requiredAudience"}
I assume the problem is related to Dialogflow's clientID, which I replaced in my code after transferring to a new agent. The problem? I have no idea what the error means and the internet isn't helping me understand it too much, since I'm not advanced at this yet.
This is how I link my clientID as described here: https://developers.google.com/assistant/identity/google-sign-in
const app = dialogflow({
clientId: 'xxxxxxxxxxxxxx.apps.googleusercontent.com',
debug: false,
});
Does anyone know what the problem might be/have experience with this error? I know it isn't in my code, since it worked before.

How to pass to an intent if Permission request is denied

I have an Action that integrates with Dialogflow which as part of the conversation requests access to the user's location.
This is fulfilled via a webhook:
app.intent('actions_intent_PERMISSION', async (conv, params, permissionGranted) => {
if (!permissionGranted) {
app.intent('actions_intent_PERMISSION - no', (conv, params) => {
conv.ask('sad face, you said no to my permission request!');
});
// conv.ask(`Ok, no worries. I'll have to figure out how to get your postcode. follow-up intent I suppose`);
} else {
conv.data.postcode = conv.device.location.zipCode;
conv.ask(`Ok great - please give me a minute, I have to get data from a few different places.`);
//use postcode to make some other API calls
}
});
Everything is fine when the user gives permission but when they don't give permission I would like to pass off to an intent that asks for their location manually ('what is your postcode/zipcode?').
As per the screenshot I tried creating a followup intent to actions_intent_PERMISSION called actions_intent_PERMISSION - no but this causes the app to crash.
What is the best way to pass the conversation to another intent is the value of permissionGranted is false?
Your question doesn't quite make sense the way you've asked it. Intents represent what the user has said and not what you do with it - that is what your webhook does in an Intent Handler. There is nothing (technically) stopping you from replying to the user asking for their zip code by just replying differently.
If you want users to be able to trigger some Intents if they have given permissions, and other Intents if they have not, you can set a different Context for each. Then you would set some Intents to only be triggered if the "permitted" context was set, and others only if the "notpermitted" context was set.
However, you have a non-technical problem to consider. If they aren't giving you permission to get their location, why would they tell you their location? It also is likely that the reviewers would reject it, saying that you should be getting location information through the provided API.

How to replace default response in account linking on Google Assistant

As part of an action configured for account linking with the following topology:
Actions-on-Google->Dialogflow->Webhook,
I'm seeing Google Assistant injecting its own message prior to going through the account linking flow, as follows:
"I need to link your <action-name> to Google. Is that ok?"
The linking flow is triggered by the following in the webhook:
public ActionResponse launchRequestHandler(ActionRequest request) throws Exception {
ResponseBuilder responseBuilder = getResponseBuilder(request);
responseBuilder.add(new SignIn());
}
I'd like to be able to replace the above stock message with a custom one, however when attaching a context to a sign in card with our own message, like so:
String speech = "Hi, I see that your account isn't connected. "
+ "I've sent a link to your Google Assistant app that will get you started and set up in just several simple steps. "
+ "Don't worry, I'll be here waiting, just call me when you're ready.";
responseBuilder.add(
new SignIn()
.setContext(speech));
I'm still seeing the default message tacked at the end:
"Hi, I see that your account isn't connected.
I've sent a link to your Google Assistant app that will get you started and set up in just several simple steps.
Don't worry, I'll be here waiting, just call me when you're ready.,
I need to link your <action-name> to Google. Is that ok? "
How can I replace the Google default message with my own?
To ensure a consistent experience for users, you cannot replace the default message. You can only set the context, which lets you provide your custom information for the user ahead of the generic question.
The context is an additional piece of information which may be more relevant to your Action. Let's say it's connecting to your example.com account. You would add the context as a string:
app.intent('Login', conv => {
conv.ask(new SignIn('To provide you with personalized info from example.com'))
})
The user would hear this message, with the generic prompt appended:
To provide you with personalized info from example.com, I need to link your Example Action to Google. Is that ok?
Then you can say yes or no, and go through the OAuth flow / Google Sign-In flow.

Is it possible to lookup a database in a Dialogflow intent?

I'm trying to make an app using DialogFlow which finds a specific object in a specific place.
This is a generic example.
The user would say something like "Where to I find Dog in Europe" and the app would reply with "Dog can be found in Europe via: breeding, finding it out in the wild or by buying it"
considering Dog as input1 and europe as input2
Ideally the app should be able to cross reference input1 and input2 to find the correct response. Can I implement a database like structure and do this?
You can't access a database from Dialogflow directly, but you can build your own fulfillment backend that can do anything you want. It communicates with Dialogflow via HTTP requests/responses in the Dialogflow Webhook format.
Here is an example fulfillment that reads data from Firebase database - https://github.com/actions-on-google/dialogflow-updates-nodejs
You can't access a database directly in Dialog flow, but you can build your own fulfillment back end. I have been using Airtable as a database and Integromat and Webhooks to query the database and parse the results back to Dialogflow. As a novice coder I found this to be the simnplest way.
KaySubb is right, you can make a fulfillment that reads data from a firebase database(or firestore).
You can do this turning on fulfillment at the bottom page of the intent page.
First go to https://console.firebase.google.com/ (login with google account) and you should be able to see your google cloud platform project.
To use firebase, you need to first install it. Get node.js as you need npm first. I'm not sure what OS you're on but go into command line or terminal and type.
npm install firebase --save
then type:
firebase login
this will authenticate your login and connect your project when you deploy.
Then use go to the directory you want to create your project in:
firebase init functions
Select your project and select javascript, install all dependencies
Now go to functions and open the index.js file. Here you can change you write code needed in js.
Write your functions and type:
firebase deploy
in the command line open in the file directory. When it completes, it will
give you a link. This as the webhook URL in dialogflow (it should start with
https://us-central). If you see only 1 link which says
console.firebase.google.com....... then open that link on a browser, click on
"functions" on the left side of the screen and get the link from there.
This should get you started with firebase, now you can link your project to firebase fulfillment. There is great firestore explanation here
https://www.youtube.com/watch?v=kdk6MhhI8oc
But I'll give you a brief explanation:
On the top of your index.js file you will need:
const functions = require('firebase-functions');
var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var firestore = admin.firestore();
The basic code is here:
exports.webhook = functions.https.onRequest((request, response) => {
switch(request.body.result.action){
case 'saveData':
let params = request.body.result.parameters
firestore.collection('colName').doc('docName').add({
name:params.name
age:params.age
}).then(() => {
response.send({
speech:
`this is a response for "${params.name}".`
});
})
.catch((e => {
console.log('Error getting documents', e);
response.send({
speech:
`Sorry, something has gone wrong. Try again and if the problem persists, please report it.`
});
}))
break;
default:
}
})
I'll explain what it does:
You need the switch to decide which intent to do. request.body.result.action returns the action name (write this in dialogflow just above the parameters).
Once that is decided request.body.result.parameters give you the parameters from the intent. params.______ gives you the parameter.
I would definitely recommend reading the official documentation:
https://firebase.google.com/docs/firestore/quickstart
to help understand the data structure to help create the ideal database for you. Essentially a collection is a list and within that a doc is one entry. You can name them yourself of using the entries from param.
respond.send is what the bot will reply to the user, I've also shown how to use the parameters in the response.
.catch will just store any errors in the log, you can read the log in console.firebase.google.com.... open your project and click on function. There will be a place to read logs there. You can check any errors encountered over there.
default: will output whatever default response you wrote on dialogflow at the bottom of the intent.
Hope this helps,comment any questions. I have gone through a huge amount as concisely as I could. This will take some time to get used to and become good at, follow the docs and the youtube videos if you have a lot of trouble!
If you're having even more trouble, there is a slack that helps people that I can direct you to.

Resources