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)
Related
I am having a weird problem with google gapi auth. For some reason, the value for gapi.auth2.getAuthInstance().isSignedIn().get() is always returning false. This is my setup:
gapi.load("auth2", initAuth2);
initAuth2(){
gapi.auth2.init({
client_id: "xxxxx-yyyyy.apps.googleusercontent.com",
hosted_domain: "domain.com",
redirect_uri: "http://localhost:4200",
ux_mode: "redirect",
}).then(performAuth, error=>{
console.error(`Error initiating gapi auth2: ${error.details}`);
});
}
performAuth(googleAuth){
const isSignedIn = googleAuth.isSignedIn.get();
if(!isSignedIn){
googleAuth.signIn();
return;
}
const user = googleAuth.currentUser.get();
console.log(user);
}
I have two google workspace accounts sign in the same chrome profile. When I run this script, I get the prompt to select an account. No matter which one I choose, the flow just keeps looping. The reason for that is that the line const isSignedIn = googleAuth.isSignedIn.get(); is always returning false.
Things I've tried so far:
I thought that maybe the client_id was corrupted so I generated a new one. Same behaviour.
I though the GCP project was corrupted, so I created a new project with new credentials. Same behaviour.
Thought there was an issue with cookies, so I deleted and clear cookies and history. Same behaviour.
Thought is was related only to localhost so I deployed to the web. Same behaviour.
If I change the init options from ux_mode: "redirect" to ux_mode: "prompt". It works. However, that is not the desired experience. Also, if I only have one google workspace in the chrome profile, it works. Even more interesting... if I use a client id from an older project... it works! The problem is that the consent screen shows the wrong app name.
I know this question is similar to this one, however I feel it's different because none of the above troubleshooting works. Any insights?
There is a case for the exact same problem here, it is most likely a bug in the api set
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.
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.
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.
I'm an iOS developer who recently started using Socket.IO. During the life cycle of my iOS application, my server will be receiving messages from my app as the client, but for one particular case, the server will also need to receive a message from a web browser as the client. I'm testing a very basic browser UI, which includes a text field and a button and on the tap of that button, a numeric code (which was entered in the text field) needs to be sent to the server. This is what that looks like:
<form>
Code:<br>
<input type="text" id="code" name="code"><br>
<input type="submit" id="validatebutton" value="Validate">
<script src="/socket.io-client/dist/socket.io.js"></script>
<script>
document.getElementById("validatebutton").onclick = function() {
var socket = io('http://localhost:3000');
socket.on('connect', function(clientSocket) {
clientSocket.emit('validateCode', document.getElementById("code"));
});
};
</script>
</form>
The connection works fine. When I run this code, the client successfully connects to the listening socket server. The only problem is that the event handler is not executed. I may be very off here, but what I went for is a client event handler, which is included in the Swift SDK:
self.socket.on(clientEvent: .connect, callback: { (data:[Any], ack:SocketAckEmitter) in
// Do something here
})
self.socket.connect()
I'm just assuming that the Javascript client has a client event handler (named 'connect') as well, which is received by the client at the moment of connecting to a server. Like I said, I may be way off here. I'm just following the Socket.IO documentation posted on their website, which tells me to do it this way. If someone can tell me what I'm missing, or what I'm doing wrong, it would be much appreciated. Sorry for all the noobishness, but I really don't know where else to turn, since the official documentation is very vague and the other question on Stack are a little too advanced for me.
I wouldn't put the emit function inside the connect. Try emitting like below in your client
<script>
var socket = io('http://localhost:3000');
document.getElementById("validatebutton").onclick = function() {
socket.emit('validateCode', document.getElementById("code"));
};
</script>
Your click event was probably getting executed, but the emit was not due to it being wrapped in the connect function (which only gets executed when the socket connects to the server)
Also I would put the JavaScript in its own file, but for now, at least after the form (not inside it) will work.