I created a chatbot which Cortana is using as a skill, it works great, however, I'm currently reading some parameters from a blob storage file and I'd like to make it more dynamic; is there a way to send parameters upon initialization of the skill coming from Cortana? I read here:
Get the user's profile and contextual information
That Cortana can read the UserInfo such as name, email, localization, etc, but I haven't seen any way to enter custom values that I can read once the message is received on init.
I would appreciate your help, thanks!
Don't forget that Cortana is conversational (RESTful, and for the most part stateless). Ask yourself what configuration is part of the dialog, versus what is part of service. If there is configuration that is sent from the user, then it makes sense to store it on the session using one of the three contexts described: user data, conversation data, or private conversation data. This is all botframework: manage state data.
There are a couple ways you can discern if Cortana is configured or not. If you have not stored the properties on userData, assume you are not configured and change your dialog flow. If you want to check at the time you are invoked, you can always do something like this if( session.message.entities[0].name === 'Microsoft.Launch' ) { ... }
In one of my skills, I just do this... if(! session.userData.bookName ) { session.beginDialog('openBook'); return; } where openBook sets the name.
If this is service related, then you can move your configuration where you like. Keeping it in Azure storage may still require a service restart to use changes (unless you continuously poll.) Conversely, you can put the configuration data in system properties (environment variables), either in your web.config or on the container. For example,
<configuration>
<appSettings>
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
<add key="BotId" value="YourBotId" />
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" /> ...
You can set IIS to watch for changed in the config file to auto-restart.
Hope this helps.
Related
I am trying to load interstitial advertisements for my app. Whenever I try to load these ads I get a Error saying "No Ads Config" from Domain "com.google.android.gms.ads".
Here is the code:
My AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ayush.torch">
<application
android:allowBackup="true"
android:icon="#drawable/ic_ico"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="i_have_put_my_app_id_here"/>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
</manifest>
onCreate() in main.java
// Creating the InterstitialAd and setting the adUnitId.
interstitialAd = new InterstitialAd(this);
interstitialAd.setAdUnitId("i have also put my interstitial ad id here");
interstitialAd.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
Toast.makeText(main.this, "Ad Loaded", Toast.LENGTH_SHORT).show();
}
#Override
public void onAdFailedToLoad(LoadAdError loadAdError) {
String error = String.format("domain: %s, code: %d, message: %s", loadAdError.getDomain(), loadAdError.getCode(), loadAdError.getMessage());
Toast.makeText(main.this, "onAdFailedToLoad() with error: " + error, Toast.LENGTH_SHORT).show();
}
});
When I load my ad in a on function it gives me error "No Ad Config."
Log.d("[Ads]","Ad Load State For on(): " + interstitialAd.isLoaded());
if (interstitialAd.isLoaded())
{
interstitialAd.show();
}
Fixed It and it works.
Found a resource from google. And It cleared all my doubts. For Test Ad Resource Click Me
The Advertisement works in two ways.
While The App Is In Development.
While The App Is In Production.
Scenario 1: While the App Is In Devlopment
For this case, we need to use Test Advertisements. Admob and "com.google.android.gms.ads" doesnt allow user to use Advertisements in Development Phase due to false impressions.
To enable Test Advertisement. There are two ways:
You can either use google ad unit id's which are available on the link adove.
Or
You can use your own ad unit id, but you will be needing to register your device as a test device and use your own request configuration.
Here is a simple Example:
Search for your "Device Id" In "Logcat"
It will look something like
I/ADS: Use Requested Configuration......Arrays.asList("Your device Id will be here");
Then Just Copy Paste This(i can read your mind..)
// Change your Id
RequestConfiguration configuration = new RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("your device id should go here")).build();
MobileAds.setRequestConfiguration(configuration);
Now just load the ad and it will pop up. Congratz. :)
Scenario 2: While the App Is In Production
This is pretty simple part...
Just remove the .setTestDeviceIds(Arrays.asList("your device id should go here")) part from the code...
Link your AdMob App to PlayStore. [Is your app published? Yes...yes...and on...]
Just opt for ad.
And check if Ads are enabled in your app settings on play console.
It should work now. Congratz.
My mistake: Setting test devices and loading test ads at the same time
Solution: Use one only. By using the test devices with production ad unit id's the error disappeared. Ads are loading again and they are test ads even if you specify the production ad unit id
This is another method which doesnt require programming.
Go to Admob dashboard > Settings > Test device > Add test device
To find this go to your device settings > Google > Ads > in that you can find your advertising id!
This also could happen if your app is uploaded to some store and you didn't set your app-ads.txt correctly.
You should bear in mind that if you are using AdMob test ads, you should add this entry into your app-ads.txt too:
google.com, pub-3940256099942544, DIRECT, f08c47fec0942fa0
Soure: https://developers.google.com/admob/android/test-ads
For FLUTTER apps, using google_mobile_ads there is a slight difference in setting test device. According to documentation you have to updateRequestConfiguration. Sample code below:
MobileAds.instance.updateRequestConfiguration(RequestConfiguration(testDeviceIds: ["yourdeviceId"]));
You can get the test device by searching for RequestConfiguration in the run output logs.
For me, This happens in a development phase, I am using .aab not .apk which Google will re-sign it using their Keystore, hence using my own Keystore will return "Error Code 3, No Ads Config".
For Live PlayStore App
Check if Ads are enabled in your app settings on the play console.
I am using flutter.
I just added my device in Admob test devices and it worked.
In production I will only remove the test device.
Let me know if I am wrong.
In my case I forgot to change the app ID for ironsource after I switched from iOS to Android so it kept calling the iOS version of ironsource which was configured to call the wrong Admob ad unit IDs. After fixing the ironsource ID, the correct Admob unit IDs were called and the error was fixed.
My app was already in production and I wanted to add ads in a new update and I faced the same problem. The solution if anyone is having the same issue is to load a test ad unit id instead of your production ad unit id. Once the app is ready and tested, simply replace the test ad unit id with your production one before publishing the app bundle to Google Play console.
Recently , i face same issue, resolved this problem.
Step1 - Please check your test ads running.
Step2 - Signin your app with your .jks file(which is previously used in old version of your app).
Thanks
This warning is nothing more than a sign that your AdMob Account has not yet received a bank confirmation or bank account addition confirmation.
I have an twilio autopilot similar to appointment schedule sample in twilio, I want it to have a memory before its even initiated, I have a B2C service, where I provide the platform to connect with their customers. Now each business offers different service so I want to be able to identify whose call my bot is attending and respond to the person based on that information.
Right now I have hardcoded business ID, but I want businesses to be able to handover to the bot with their business ID, I have read the documentation but it doesn't say how to handle call redirect as my Bot would be handling calls only.
Twilio developer evangelist here.
You can do this with Twilio Studio!
"Inbound Context lets you add data to the Autopilot Memory before starting a dialogue with the bot. In a Studio flow, it allows you to pass Flow variables created by other widgets in your flow seamlessly into Autopilot to be used in bot conversations. You can then parse these variables directly from the Memory JSON included in Autopilot's request to your application" (more info here):
-Memory.CarMake
-Memory.CarModel
You could alternatively use a URL like this one to pass Inbound Context with Memory where any message sent to a bot with this URL will insert CarModel, CarMake, and CarYear into the Autopilot Memory.
https://channels.autopilot.twilio.com/v1/<ACCOUNT_SID>/<ASSISTANT_SID>/twilio-messaging?Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}
That URL would go for a SMS bot and go in where you place the webhook URL for your Twilio phone number, but you could similarly modify it for WhatsApp (https://channels.autopilot.twilio.com/v1///twilio-messaging/whatsapp?Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}), Voice, Custom Channels (https://channels.autopilot.twilio.com/v1///custom/{YourCustomChannelName}?Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}) etc.
TwiML for voice would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect action="https://www.example.com/autopilot">
<Autopilot Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}>UAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Autopilot>
</Connect>
</Response>
Let me know if this helps at all!:D
You can utilize Inbound Context, as detailed below.
Inbound Context
https://www.twilio.com/changelog/inbound-context
Inbound Context lets you add data to the Autopilot Memory before
starting a dialogue with the bot. It can help you make the bot
experience more personalized and contextual by making information like
names, purchase histories, account numbers etc. stored in third-party
systems available directly in the bot conversation.
I found a way to handle it, and it may not be the best way, but its really helpful for me.
So what I have done is I created an API that responds back with Twml
Similar to this
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect action="https://www.example.com/autopilot">
<Autopilot Memory={"CarModel":"Diablo","CarMake":"Lamborghini","CarYear":"2019"}>UAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</Autopilot>
</Connect>
</Response>
Now I purchased number and set its webhook URL to the API I created, within that API, I can pass parameter and then create memory with those params
Here is my API handler in Nodejs:
const VoiceResponse = require('twilio').twiml.VoiceResponse
const voice = (req, res, next) => {
const response = new VoiceResponse()
const connect = response.connect()
connect.autopilot({
TargetTask: 'greeting',
Memory: `{"companyId": "${req.params.id}"}`
},
process.env.AUTOPILOT_SID)
res.type('text/xml')
res.send(response.toString())
}
I hope this helps somebody who is looking to create dynamic memory based on different numbers, or to create a bot that works for multi-tenant platform
I am trying to develop an add-in for Excel with the goal that it will create calendar events based on data inside a spreadsheet.
I can do almost everything that I want except use the REST API to build the events in the calendar and I can't exactly figure out where I went wrong.
I have followed the documentation suggested by #MarcLaFleur.
I can build and run the application no problem, but when I click on the 'Get my files from OneDrive' button, I get the following:
Code: 5001
Message: An internal error has occurred.
name: Internal Error
This is coming from the program.js file in the public directory somewhere in the else clause of this function.
function getDataWithoutAuthChallenge() {
Office.context.auth.getAccessTokenAsync({ forceConsent: false },
function (result) {
if (result.status === "succeeded") {
// TODO1: Use the access token to get Microsoft Graph data.
accessToken = result.value;
getData("/api/onedriveitems", accessToken);
}
else {
console.log("Code: " + result.error.code);
console.log("Message: " + result.error.message);
console.log("name: " + result.error.name);
document.getElementById("getGraphAccessTokenButton").disabled = true;
}
});
}
Here are the scopes in my manifest.xml
...
<WebApplicationInfo>
<Id>c931b396-7 ... </Id>
<Resource>api://localhost:3000/c931b396-7 ... </Resource>
<Scopes>
<Scope>files.read.all</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
</VersionOverrides>
And here are the scopes on apps.dev.microsoft.com:
If you can shed any light for me, it would really help me out.
5001 can be caused by not requesting profile scope. You need to request the profile scope in addition to Calendar.ReadWrite. You do this when you register the app, as well as in the manifest. For more information, see the articles that Marc LaFleur linked to.
The 5001 error often suggests something fundamentally wrong with the add-in API in Office. For example, your Office app doesn't support the API, the manifest is incorrect, or the version of office.js doesn't work with it. Since you're using the sample, two things come to mind:
You aren't running the latest Insiders
build
The wrong manifest is getting loaded (this sometimes happens if you're
on Windows and using a version of Visual Studio 2017 that has old
schema files, so you have to do a post-build clean up of the debug
Manifest XML)
Your manifest and Azure registration look mostly good, though Rick's comment about Scopes is relevant. profile must work with openid as a pair (profile alone won't work; openid alone won't work), and as discussed you need this consented. As the developer, you can try consenting for yourself at the protocol level. You’ll want to update the client_id, redirect_uri, and scope query parameters as appropriate, and add &prompt=consent.
To answer a later question, Excel and Mail add-ins are different, and my answer only applies to Excel. For Outlook there's a different sample.
The documentation can be found at Enable single sign-on for Office Add-ins. There is also walk though for both ASP.NET and Node.js as well documentation on Troubleshooting.
There are a number of things that could be going wrong here but without knowing more about your registration it is difficult to determine. That said, here are a couple of common mistakes:
You'll need to make sure you receive Admin Consent for the tenant you're developing against. This is only a dev requirement and won't be required once your publish to the Store.
Make sure you've pre-authorized the correct applications. You'll need pre-authorizations for:
d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)
57fb890c-0dab-4253-a5e0-7188c88b2bb4 (Office Online)
bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Office Online)
Make sure the scopes you're defining in your manifest.xml are reflected in the app registration at apps.dev.microsoft.com.
If you make changes to your permission scopes, you need to make sure you repeat the Admin Consent process. When you receive consent, they are consenting to the scopes that were registered at the time of consent rather than the App ID itself.
How I can send a notification for everyone that has installed my extension?
I'm using new Notification(...) but the notification is just sending for me.
Thank you for all
You will want to use the new gcm service for Push Notifications via Google Cloud Messaging Service.
Here is a tutorial on Google's Chrome Developer page.
Well, this requires a lot of work already done in the extension to be able to do that without updating the extension.
For instance, your extension can periodically look for new notices on your website.
If you need more urgency, you either need to keep WebSocket connections to your server or use some manner of push services, like gcm API that Max Worg just mentioned.
That said, to use all this you need to have the support already in place in your extension.
Okay, but suppose you don't have that support, or don't need it that often.
The usual way to do it is with an extension update, where you add a message for the users and increment a variable with the "release notes" version, so that it will only be shown once. A good idea is to use chrome.storage.sync for this, so that the user won't be annoyed multiple times.
var message = "Sup user, check this out!";
var message_version = 4; // Update this when you want to show a new one
chrome.storage.sync.get(
{message_version: 0}, // Provide default
function(data) {
if(data.message_version < message_version) {
notify(message); // TODO: implement notify()
// Alternatively, open a page with the notice with chrome.tabs.create()
chrome.storage.sync.set({message_version: message_version});
}
}
);
You can see a real-life example here (using a hybrid of localStorage and chrome.storage).
This has really been bugging me for some time so any help to confirm or affirm this is much appreciated! This is also the first time I actually post a question despite being developing for a long time :)
So I have a nodejs app integrating with the Google Drive API and I want users to authorize multiple Google Drive accounts and be able to view and open (and in general just interact with) all files from the accounts that they add.
I authorize my app using the highest available scope: https://www.googleapis.com/auth/drive and because I don't want users to have to sign-in again when the access_token runs out so I also include the approval_prompt: "force" and ``access_type: "offline"` when I request my access tokens.
Everything is fine - I authorize nicely, I can delete files, I can open them, I can share them, I can download them. Except for one thing:
If I e.g. authorize horse#gmail.com and then beaver#gmail.com. Then I can still delete, share, download and preview files from both accounts. But I simply cannot open documents from horse#gmail.com in google docs for editing (because beaver#gmail.com is signed in on my local machine). The best I can do is getting to a point where it shows me the document, with the right account logged in in the top right corner of the screen, but asks me to sign-in with a button. When I click the button it just refreshes and give me the same message and the same screen.
What I've tried is:
Simply redirecting the user to the file resources alternateLink from the API
Taking the alternateLink and appending my access_token to it and then redirect the user to it.
(and a ton of other random things I found various places that didn't work).
In both cases I have also tried signing out from all google accounts.
Now I checked a couple of webservices like Jollicloud and Odrive that tries something similar. However, both of them appear to force the user to login to google to access a file.
Is it really true that you can do all kinds of crazy things with the users files like deleting and downloading, but you can't open them in Google Docs own apps?
Not completely sure what kind of code I should add to show you what I've got. But here's some. This is my open action (what happens when the user clicks on a file and wants to open the file in the Google Docs/Sheet/etc.) (the orientdb stuff is because we're using the OrientDB graph database - it just fetches an account where we store the tokens). The link is the link property of the file (see below):
open: function(req,res,next){
var link = req.param("link");
var uid = req.param("uid");
orientdb.select().from('Account').where({uid: uid}).one()
.then(function(account){
var URL = link + "&access_token=" + account.tokens.access_token;
res.redirect(URL);
});
}
Here's an example file document from our database (I've replaced all compromising data with a descriptive
ODocument - Class: File id: #13:20499 v.6
name : Hummer2
service : Gdrive
kind : Google Doc
created : Nov 17, 2014
changed : Nov 17, 2014
users : [MB]
uid : mrb#flowtale.com
childID : <FILE.ID>
exportLinks : {DOCX=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=docx, Open Office doc=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=odt, Rich text=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=rtf, HTML=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=html, Plain text=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=txt, PDF=https://docs.google.com/feeds/download/documents/export/Export?id=<FILE.ID>&exportFormat=pdf}
usernames : [<ARRAY OF USERNAMES ASSOCIATED WITH THIS FILE>]
in_hasFile : User#11:0{out_hasFile:[size=2237],out_hasAccount:[size=4],username:null,email:h#h.com,password:<SOME ENCRYPTED PASSWORD>} v2244
out_belongsTo : Account#12:3{in_belongsTo:[size=6],type:Gdrive,uid:<SOME UID>,tokens:{access_token=<OUR ACCOUNT ACCESS TOKEN>, token_type=Bearer, refresh_token=<OUR ACCOUNT REFRESH TOKEN>, expiry_date=1416258913290},rootFolderID:<ROOT FOLDER ID>,email:<THE ACCOUNT EMAIL>,filesCached:2,usersCached:2,job:4,in_hasAccount:#11:0} v15
in_folderContains : File#13:20495{out_folderContains:[size=2],name:Testhest,service:Gdrive,kind:folder,created:Oct 12, 2014,changed:Oct 12, 2014,users:[1],link:https://docs.google.com/a/flowtale.com/folderview?id=<FOLDER.ID>&usp=drivesdk,uid:mrb#flowtale.com,childID:<FOLDER.ID>,exportLinks:{},usernames:[1],parents:[1],in_hasFile:#11:0,out_belongsTo:#12:3,in_folderContains:#13:13891} v36
link : https://docs.google.com/a/flowtale.com/document/d/<FILE.ID>/edit?usp=drivesdk
Looking forward to hear if anybody can help me or have experienced this before.
Thanks!
The API will allow you to do several actions in your drive account. I haven't been able to reproduce the behavior you mention with files that I haven't granted permissions to another account.
When you authenticate through the OAuth process, you will grant access to your account only to the application which created the OAuth request. You can not edit the content of a file without manually opening it through GDocs. Therefore, when the browser opens the AlternateUrl, it will require you to login to the account, in order to access the file.