Unable to reach endpoint after QnAMaker migration - botframework

We have a bot that has been in production for several months. The bot configured with the preview service is working great.
So I followed the steps in the migration document. I created a QnA Service in Azure, then created the knowledgebase. I imported my knowledgebase, save/trained, and published.
In my web.config I replaced the following values:
<add key="QnAKnowledgeBaseId" value="foo" />
<add key="QnaSubscriptionKey" value="bar" />
<add key="QnaMakerUpdateKnowledgeBaseEndpoint" value="https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases" />
I used the values given after publishing my knowledgebase, so
POST /knowledgebases/<QnAKnowledgeBaseId>/generateAnswer
Host: <QnaMakerUpdateKnowledgeBaseEndpoint>
Authorization: EndpointKey <QnaSubscriptionKey>
After changing these three lines my bot stops retrieving answers. This leads me to suspect either 1) I have the source for these datapoints is incorrect, or 2) Larger changes are required to convert in my situation. Can anyone guide me in the right direction?
Edit: Ultimately my issue was the bot's original developer hiding the QnAMaker's endpoing somewhere. I'm still not sure where, the url isn't in the web.config or in any of the azure settings. I overwrote it and all seems fine.
The answers below were more clear to me than the official documentation, even if they just affirmed what I thought was the right answer on my initial reading. Great job people.

The new v4 uses an azure website for its generateAnswer end point with a different scheme inside the authorisation header. Log into the new v4 ui do a publish and you will see the url example has changed.
Caught me out initially too. Their are a few changes to the api too qnaquestions collection is now qnalist and also qnaid is now just id.
You will need to thoroughly compare the api, especially if you have handrolled your client.
Happy to help
Phil

After you publish your knowledge base, you will find the endpoint details that can be used in your application or bot code. As Phil mentioned, it uses an azure website for its generateAnswer end point, which is different from old version QnA services.
old version QnA services:
So if you make the following request to get answers to a question with new knowledge base, it would not work.
https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases/<QnAKnowledgeBaseId>/generateAnswer

After publishing when you get all the necessary settings info you can add then in code like this.
Use the host address which you get at the time of publishing in qnamaker.
QnADialog.cs
namespace Test.Qna
{
[Serializable]
[QnAMaker(authKey: "AuthKey", knowledgebaseId: "KnowledgebaseId", defaultMessage: "please rephrase, I could not understand.", scoreThreshold: 0.5, top: 1, endpointHostName: "https://yourAccount.azurewebsites.net/qnamaker")]
public class QnADialog : QnAMakerDialog
{}
}
For Node js you can do like this
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
var bot = new builder.UniversalBot(connector);
bot.set('storage', new builder.MemoryBotStorage());
server.post('/api/messages', connector.listen());
var recognizer = new cognitiveservices.QnAMakerRecognizer({
knowledgeBaseId: '5abcde-cbfb-4yuio-92c5-052d3a806e78',
authKey: 'eb7uy78y-8a64-4e75-98uj-7f89987b67bc',
endpointHostName: 'https://name.azurewebsites.net/qnamaker'
});
var basicQnAMakerDialog = new cognitiveservices.QnAMakerDialog({
recognizers: [recognizer],
defaultMessage: 'No match! Try changing the query terms!',
qnaThreshold: 0.3
});
bot.dialog('/', basicQnAMakerDialog);
Hope this will help.

Related

Failed to connect (500) to bot framework using Direct Line

We have a bot running in Azure (Web App Bot) that I'm trying to embed on a website. The bot is based of the Bot Builder V4 SDK Tamplate CoreBot v4.9.2. At first I used the iframe to embed the bod. This worked but didn't provide the features we need, so now im changing it to use DirectLine.
My code on the webpage looks like this:
<script crossorigin="anonymous"
src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<div id="webchat" role="main"></div>
<script>
(async function () {
const res = await fetch('https://[my bot name here].azurewebsites.net/.bot/v3/directline/tokens/generate',
{
method: 'POST',
headers: new Headers({
'Authorization': "Bearer [my token here]"
})
});
const { token } = await res.json();
window.WebChat.renderWebChat(
{
directLine: await window.WebChat.createDirectLineAppServiceExtension({
domain: 'https://[my bot name here].azurewebsites.net/.bot/v3/directline',
token
})
},
document.getElementById('webchat')
);
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
After some struggles I managed to fetch a token from https://[my bot name here].azurewebsites.net/.bot/v3/directline.
And I can see the chat window on my webpage, but is says connecting for a while then it changes to Taking longer than usual to connect, like this:
In the Chrome console there is an error saying Failed to connect Error: Connection response code 500. When I check Chrome's Network tab I can see that the token generated completed with status 200 and that the websocket connection is open, like this:
----------EDIT---------
I just noticed that when go to https://[my bot name here].azurewebsites.net/.bot using a webbrowser, the resulting json is
{"v":"1.0.0.0.55fa54091a[some key?]","k":true,"ib":false,"ob":false,"initialized":true}
ib and ob should be true but are false, maybe this is part of the problem.
----------EDIT 2---------
OK so now I'm starting to go crazy.
Ashish helped me and at some point the ib and ob were true. They were true for most of yesterday. At some point yesterday they turned false for a short while (no more than 2 hours). I checked if someone had triggered the release pipeline but no recent releases. After that ib and ob magically turned true again and connecting to the direct line worked again.
Now this morning ib and ob were false again. And again no recent releases. I don't know what is causing this.
Does anybody know what's going on here or how to fix this? How do I find what causes ib and ob to be false?
Any help is appreciated! Thanks in advance. If you need more information, just ask and I'll post it.
If the ib and ob values displayed by the *.bot endpoint are false this means the bot and the Direct Line app service extension are unable to connect to each other.
Make sure you verify below things:
Double check the code for using named pipes has been added to the
bot.
Confirm the bot is able to start up and run at all. Useful
tools are Test in WebChat, connecting an additional channel, remote
debugging, or logging.
Restart the entire Azure App Service the bot
is hosted within, to ensure a clean start up of all processes.
Please check troubleshooting guide, it seems updated today. (still old date reflected some how, not sure why)

Which event type is triggered when a slack app is installed onto a workspace for the first time?

I'm trying to build an app that does something when it is first installed onto a workspace, eg: Ping every team member.
I couldn't find an event type that gets triggered upon app install:
https://api.slack.com/events
Is there a way to make this happen?
I think there might be a misunderstanding of the events concepts here. Events are always directly linked to one specific Slack app and needs to be processed by that very app. There is no such thing as "general" events for things happening on a workplace, like a new app being installed. Ergo there is no event for app installation.
Nevertheless you can implement the functionality you mentioned with Slack, e.g. pinging all team members once an app is first installed. All you need to do is include this function in the installation process of your Slack app and e.g. start pinging after the installation process is complete and the app verified that it was the first installation to this workspace. You do not need an event for that.
This is a partial answer because I was wondering the same thing and wanted to share what I found. On this oauth tutorial, it has the following code snippet:
app.get('/auth', function(req, res){
if (!req.query.code) { // access denied
return;
}
var data = {form: {
client_id: process.env.SLACK_CLIENT_ID,
client_secret: process.env.SLACK_CLIENT_SECRET,
code: req.query.code
}};
request.post('https://slack.com/api/oauth.access', data, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Get an auth token
let oauthToken = JSON.parse(body).access_token;
// OAuth done- redirect the user to wherever
res.redirect(__dirname + "/public/success.html");
}
})
});
I believe instead of the line res.redirect(__dirname + "/public/success.html"); at that point you can make a request to ping everyone or even call a function to do so directly there, and it will trigger immediately once the app has been installed.

Error sending message to WebChat via DirectLine

I have a bot deployed in Azure. Uses the latest >net bot framework, (v3).
The front-end uses the vanilla WebChat. I am trying to send an event from the BOT TO THE CLIENT, in order to trigger a wipe of the webchat visible history.
I'm getting the more than useless 502 error when my bot tries to send the event message.
The JS to setup the web chat and directline on my front end is:
var botConnection = new BotChat.DirectLine({
secret: {secret removed..becuase secret},
//token: params['t'],
//domain: params['domain'],
webSocket: "true" // defaults to true
});
BotChat.App({
bot: bot,
botConnection: botConnection,
resize: 'detect',
user: user,
chatTitle: false,
showUploadButton: false
}, document.getElementById('bot'));
//backchannel communication setup
botConnection.activity$
.filter(function (activity) {
return activity.type === 'event' && activity.name === 'clearChatHistory';
})
.subscribe(function (activity) {
console.log('"clearChatHistory" received');
clearChatHistory();
});
function clearChatHistory() {
$(".wc-message-wrapper").remove();
}
The idea here is that my bot code will create a message of type 'activity' with the value = 'clearChatHistory'. This fire the code on my client.
The code for sending this message is:
internal static async Task SendClearChatHistoryEvent(Activity activity)
{
Trace.TraceInformation($"Utility::SendClearChatHistoryEvent");
Activity clearMessage = activity.CreateReply();
clearMessage.Type = "event";
clearMessage.Value = "clearChatHistory";
Trace.TraceInformation(JsonConvert.SerializeObject(clearMessage));
Trace.TraceInformation($"Utility::SendClearChatHistoryEvent::ServiceURL:{activity.ServiceUrl}");
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.SendToConversationAsync(clearMessage);
}
The bot fail is happening at the 'SendToConversationAsync' call
The closest thing I get to an error is on the client side
"https://directline.botframework.com/v3/directline/conversations/5OSJJILizNqGG4H7SaV6fQ/activities 502 (Bad Gateway)"
The Visual Studio output window displays
'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException'
and 'Microsoft.Bot.Connector.ErrorResponseException
exceptions
Any insights on what I might be doing wrong or whats happening otherwise here would be greatly appreciated.
You're setting the value on the event but checking the name. If you use this as the filter it should work:
.filter(activity => activity.type === 'event' && activity.value === 'clearChatHistory')
Regarding the bad gateway however, I am not sure, as I was not seeing this occur with your code on my system.
I figured out what the problem is. First, there was a bug in my code example which Mark B pointed out. However, that was not the source of the problem but it did help me to get to the real issue.
The Bad Gateway problem wasn't really a good indicator of the problem either. I had to do a lot of Trace writing and stepping through code to finally notice what was happening. I'll try to describe the problem so you all can learn from my boneheaded mistake.
The understand the problem, you need to understand what this line of code is doing
Activity clearMessage = activity.CreateReply();
CreateReply() creates a new Activiy from an existing one. When it does that, it swaps the values of From and Recipient. This is because you want to reply to the person the original message comes from. Make 100% total sense.
The problem, for me, was my original message was ALSO created by calling CreateReaply() in a previous dialog. SO, I basically created a new message to be sent to myself (or the bot in this case). I need the message to to to the chatbot user, not the bot.
When the bot framework attempted to send itself a message it excepted and failed. Why it got the bad gateway error I dont exactly know and will continue to research that.
To fix this, I changed my upstream code to use
var newMessage = context.MakeMessage()
instead of the CreateReaply(). This does not swap From and Recipient.
Everything is now flowing along very nicely. My code will now force a wipe of the visible chat history in my WebChat client.

Using MS Teams as Channel: Authentification Dialog (GetTokenDialog class from Microsoft.Bot.Builder.Dialogs) doesn't popup

How can I use the new authentification feature in Bot Builder with MS Teams?
There seems to be an issue with Teams (see Login user with MS Teams bot or https://github.com/Microsoft/BotBuilder/issues/2104), seems if this is not considered in GetTokenDialog?
Is there any chance to get around this?
Just found the reason why it won't work with Teams. In method Microsoft.Bot.Connector.Activity.CreateOAuthReplyAsync(), Parameter asSignInCard has to be set to True for MSTeams, then, the line new CardAction() { Title = buttonLabel, Value = link, Type = ActionTypes.Signin } has to be changed to new CardAction() { Title = buttonLabel, Value = link, Type = ActionTypes.OpenUrl } because MS Teams can obviously not deal with Action type Signin. Hope, the MS developers will fix that method soon.
There are a few things you need to do to get this to work. First you need to create a manifest file for your bot in teams and whitelist token.botframework.com. That is the first problem.
From teams itself in AppStudio you create a Manifest. I had to play around with this a little bit. In AppDetails... Let it generate a new ID. Just hit the button. The URLs really don't matter much for testing. The package name just needs to be unique so something like com.ilonatag.teams.test
In the bots section you plug in your MS AppId and a bot name. This is a the real MSAPPID from your bots MicrosoftAppId" value=" from web.config in your code.
Ok now in "finish->valid domains" I added token.botframework.com and also the URL for my bot just in case. so something like franktest.azurewebsites.net
This part is done but you are not quite done... in your messages controller you need to add this since Teams sends a different verification than the other clients.
if (message.Type == ActivityTypes.Invoke)
{
// Send teams Invoke along to the Dialog stack
if (message.IsTeamsVerificationInvoke())
{
await Conversation.SendAsync(message, () => new Dialogs.RootDialog());
}
}
It took me a bunch of going back and forth with Microsoft to get this sorted out.
This is a known problem using OAuthCard in MS Teams. To solve it, you can change the Button ActionType from signIn to openUrl using this solution on github

Using Parse master key from the server and not cloud code

I recently implemented the security of my Parse app thinking that I could use the master key on my server (express not cloud code) to securely bypass my security implementations for admin/server level functions.
I'm using "parse": "^1.5.0",
in my package.json.
Right now in each of my express modules I have:
var Parse = require('parse').Parse;
Parse.initialize("Application ID", "Javascript Key", "Master Key");
Everything works fine without CLPs activated but with CLPs I can't do any read/write of the data with the server. I understand that I can move this to Cloud code and get it to work however I need to use a number of libraries in my code that Parse does not support and transporting all of the code to cloud code would be very tough.
What am I doing wrong?
Here's what worked for me.
/////////////////////////////////this is the top of the JS page/module/////
'use strict';
var Parse = require('parse/node');
Parse.initialize('app-id','js-key','master-key');
exports.create = function(req, res) {
Parse.Cloud.useMasterKey();
//now when you do a parse query or action you can bypass your security settings.
};

Resources