We have created a bot using ms bot framework and wanted to pass some data to bot which user will not input. Like I was thinking if we can pass query string to below web channel.
https://webchat.botframework.com/embed/myformbot?s=XXXXXX&mycustomfield=text
And from bot api code, I can somehow read this querystring parameter...Ideally I know we don't have control over above webchat link, we are only giving access to bot api. But is this possible or any other way to pass data to bot which is not entered by user ?
We are planning to display web channel url to different sites in iframe and wanted to pass currently browsed url to identify from where user has started conversation.
Thanks
Siddharth
This is easily done using the BotFramework-WebChat library. There are just a few steps to perform to get yourself setup.
First, include a div with an id for the webchat instance of your bot to anchor to. In this example, the id is "webchat".
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Bot Chat</title>
<style>
#webchat,
#webchat>* {
border: 1px solid #333;
float: left;
min-height: 600px;
height: 600px;
position: relative;
width: 460px;
}
</style>
</head>
<body>
<div class="example">
<h2>Back Channel Bot</h2>
<div id="webchat"></div>
Next, you will want to include the following scripts in your html page. Please keep in mind that you should NOT store your secret in the browser or client app. It is included here for simplicity.
Here's what is happening. You use the Direct Line secret (from the channel settings in your Azure bot) to generate a token. The token is used to instantiate the bot webchat control. In this example, the user's location is saved in the store's payload as the activity object. This is sent to the bot on any POST_ACTIVITY event (i.e. the user interacts with the bot).
<script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>
<script src='https://cdn.botframework.com/botframework-webchat/master/webchat.js'></script>
<script src='https://unpkg.com/simple-update-in/dist/simple-update-in.production.min.js'></script>
<script>
(async function () {
// To talk to your bot, you should use the token exchanged using your Direct Line secret.
// You should never put the Direct Line secret in the browser or client app.
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + secret
},
json: true
});
const { token } = await res.json();
let location = window.location.href;
let store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/POST_ACTIVITY') {
// simple-update-in is used to update the "action"
action = window.simpleUpdateIn(action, ['payload', 'activity', 'channelData', 'location'], () => location);
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store,
styleOptions: {
botAvatarInitials: 'BF',
userAvatarInitials: 'WC'
}
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));;
</script>
</body>
</html>
On the bot side, the bot is listening for the incoming message. The activity object will contain the data you sent and will look something like this:
channelData: { clientActivityID: '15469824216440.emdrovn0f5h', location: 'http://localhost:3000/' }
Hope of help!
Related
I'm having a go with speech for a BOT. I have been running through the Microsoft Tutorial found here. I've taken the example Echo BOT example from there, found here, as a basis so I can use it as a basis going forward. This has been successfully deployed to my Azure environment. Also in the tutorial, you run your Bot through the Direct Line Speech Client v1, everything works as expected when doing this.
I have looked at the Bot Framework Web Chat speech notes to get the Bot working using this as my channel. Here is my code for this:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Web Chat: Browser-supported speech</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
html, body { height: 100% }
body { margin: 0 }
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function () {
window.WebChat.renderWebChat({
directLine: createDirectLine({
secret: '<My Direct Line secret>'
}),
language: 'en-US',
webSpeechPonyfillFactory: await createCognitiveServicesSpeechServicesPonyfillFactory({
region: '<Speech cognitive service region>',
subscriptionKey: '<Speech cognitive service key>'
})
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
</body>
</html>
I'm able to get this working and I can do speech to text and text inputs and the contents is written back, but when it tries to do text to speech back I'm getting the following errors in the browser console:
POST https://<region>.tts.speech.microsoft.com/cognitiveservices/v1 net::ERR_ABORTED 400 (Speak node can only be the root.)
webchat.js:1 Error: Failed to syntheis speech, server returned 400
at webchat.js:1
at c (webchat.js:1)
at Generator._invoke (webchat.js:1)
at Generator.e.<computed> [as next] (webchat.js:1)
at n (webchat.js:1)
at s (webchat.js:1)
I'm not quite sure if it is something in the script code or the Bot, let me know if you need any more detail. Thanks in advance!
It is weird... I hosted a echo bot on Azure and just copy and paste your html code and did some config ,I tested on edge firefox and chrome but everything works well including tts calling :
You can try it here and check the config . Hope it helps .
Google old profile API not working now.
I used this API link before,
(http://picasaweb.google.com/data/entry/api/user/sakiremail#gmail.com?alt=json)
but it's not working now. Can't get profile information. What is the new API URL?
here I have created a demo app to work with. Before test please create an auth client id. Also, add an authorized redirect URI to http://localhost if you are checking on local.
<html lang="en">
<head>
<meta name="google-signin-scope" content="profile email">
</head>
<body>
Login
<script>
/*
* Create form to request access token from Google's OAuth 2.0 server.
*/
function oauthSignIn() {
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create <form> element to submit parameters to OAuth 2.0 endpoint.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
// Parameters to pass to OAuth 2.0 endpoint.
var params = {'client_id': 'YOUR_APP_CLIENT_ID',
'redirect_uri': 'AUTHENTICATED_REDIRECT_URI',
'response_type': 'token',
'scope': 'profile',
'include_granted_scopes': 'true',
'state': 'pass-through value'};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
var hash = window.location.hash.substr(1);
var hashresult = hash.split('&').reduce(function (result, item) {
var parts = item.split('=');
result[parts[0]] = parts[1];
return result;
}, {});
if(hashresult.access_token){
console.log(hashresult.access_token);
fetch('https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token='+hashresult.access_token)
.then(function(response) {
return response.json();
})
.then(function(userdata) {
console.log(userdata);
});
}
</script>
</body>
</html>
I have created few scenarios in health bot designer. I am trying to integrate with my front end. However, I don't see any complete documentation around integrate process. I have already referred https://github.com/Microsoft/HealthBot-WebChat without any luck. How do I get directline link for healthbot. I have tried with web bot and able to generate directline but not sure how to link web bot channel to health bot scenario. Any help?
You can integrate the Healthcare bot service into a web application using WebChat. First, you need to get your WebChat Secret from the Healthcare Bot Service Manager. In the pane on the left, click on the integrations blade, select secrets in the drop down options, and copy the webchat_secret.
Once you have the secret, you can request a token from DirectLine and render a WebChat component on your web app. Take a look at the example below.
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Healthcare bot</title>
<script src="https://cdn.botframework.com/botframework-webchat/master/webchat.js"></script>
<style>
html, body { height: 100% }
body { margin: 0 }
#webchat,
#webchat > * {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function() {
// Note, for the simplicity of this example, we are fetching the DirectLine token here;
// however, it is recommended that you create a backend REST API to generate and manage
// your tokens.
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate',
{
method: 'POST',
headers: {
'Authorization': `Bearer <WEBCHAT_SECRET>`,
'Content-Type': 'application/json'
},
body: {
// The user id must start with `dl` and should be unique for each user.
User: { Id: 'dl_user_id' }
}
});
const { token } = await res.json();
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
}, document.getElementById('webchat'));
})().catch(err => console.log(err));
</script>
</body>
Note, for the simplicity of this example, we are fetching the DirectLine token here; however, it is recommended that you create a backend REST API to generate and manage your tokens.
Hope this helps!
Found a way to do it. We need to add a model and enable the trigger through Health Bot Management Portal
There is a direct way to trigger a scenario from the front end. If you want to completely rely on your own responses, then you have to turn off the built-in scenarios and call a scenario name in the event post javascript code. Look at the "trigger" element below:
botConnection
.postActivity({
type: "event",
value: {
trigger: "your_scenario_name_here", args: {}
},
from: your_user_name,
name: "BeginDebugScenario"
});
I am testing out rxjs websocket with sample code below, but when I try to publish from https://www.websocket.org/echo.html, I couldn't receive any message on the HTML, is this expected? How can I subscribe to topic from https://www.websocket.org/echo.html?
<html>
<head>
<script src="https://unpkg.com/#reactivex/rxjs#6.2.2/dist/global/rxjs.umd.js"></script>
<script>
const { WebSocketSubject } = rxjs.webSocket;
const socket$ = new WebSocketSubject('wss://echo.websocket.org');
socket$.subscribe(
(data) => console.log(data),
(err) => console.error(err),
() => console.warn('Completed!')
);
console.log('here')
</script>
</head>
<body></body>
</html>
websocket.org/echo.html does not offer broadcast thus using it for local testing will not receive any reply.
Running a local websocket server for testing is the way to go.
I'm writing a page that uses OAuth 2.0 via gapi.auth.authorize to authenticate a Google+ user and gapi.client.request to run Google Fusion Tables sqlGet queries. I find that my queries run fine before authentication, but then fail with a 403 "Insufficient Permission" error when run more than 30 seconds
after authentication.
The problem is demonstrated with this page:
https://googledrive.com/host/0B5Urq1jZb1MYSWloU3NTY2M4Qnc/test3b.htm
Please follow these steps:
Click "Query" to run a gapi.client.request Google Fusion Table SQL-get query returning a count of rows. This will run successfully until OAuth is used in steps 2 and 3.
Click "Start OAuth" to run an immediate:true authorization against Google+. If you are currently signed into Google+, your user name and ID will be displayed in the third button.
If your Google+ user name is not displayed in the third button, click the button ("Authorize") and sign into Google+.
Click the "Query" button again. The query will run without error when pressed within about 30 seconds of OAuth authorization. After that, the query fails with a 403 error. WHY?
Here is the source for the demo page:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<title>Test3b</title>
<style type="text/css">
</style>
<script src="scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
var g_domIsReady = false;
var g_gapiIsReady = false;
$(function () {
log("#$(function())");
g_domIsReady = true;
start();
});
function gapiIsReady() {
log("#gapiIsReady");
g_gapiIsReady = true;
start();
}
function start() {
// Make sure both the gapi.client and the DOM (per jquery) are ready.
if (!(g_gapiIsReady && g_domIsReady)) return;
// Define members.
log("#start - gapi and DOM are ready");
var m_apiKey = "AIzaSyAvb0NHQMwyPbMJRtz2zRL4wTiVjZDiois"; // Points to Google account (including Google Drive) at paloalto#geodesy.net.
var m_clientId = "868768273487-q295tdfr54uvo98v74891qakcr9ci0pf.apps.googleusercontent.com";
var m_scopes = "https://www.googleapis.com/auth/plus.me";
// Wire buttons.
var queryButton = document.getElementById('query-button');
queryButton.onclick = function () { runGetRequest(); return false; };
var startOAuthButton = document.getElementById('startOAuth-button');
startOAuthButton.onclick = function () { startOAuth(); return false; };
// Set-up the gapi.
gapi.client.setApiKey(m_apiKey);
//----------------------------------------------------------------------------
// gapi.client.request query functions.
//----------------------------------------------------------------------------
function runGetRequest() {
log("#runGetRequest");
var tableId = "1VZgvKyuh9uHXkQawpxg1MU8AlO8Mngl-sx7SP74"; // TR_TREE_E
var sql = "select count(GID) from " + tableId + " where GID > 50000";
var path = "/fusiontables/v1/query";
var restRequest = gapi.client.request({
path: path,
params: { 'sql': sql }
});
restRequest.execute(jsonCallback);
}
function jsonCallback(json) {
log("#jsonCallback");
var output = JSON.stringify(json);
log(output);
alert(output);
}
//----------------------------------------------------------------------------
// OAuth functions.
//----------------------------------------------------------------------------
function startOAuth() {
log("#startOAuth");
var authorizeButton = document.getElementById('authorize-button');
window.setTimeout(checkAuth, 1); // check auth in 1 ms
function checkAuth() {
log("#checkAuth");
gapi.auth.authorize({
client_id: m_clientId,
scope: m_scopes,
immediate: true
}, handleAuthResult);
}
function handleAuthResult(authResult) {
log("#handleAuthResult");
if (authResult && !authResult.error) {
log("#handleAuthResult - authResult=true");
log(authResult); // authResult is a token (with 3600 second expiration).
authorizeButton.disabled = true;
useAuthResults();
} else {
log("#handleAuthResult - authResult=false");
authorizeButton.disabled = false;
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick() {
log("#handleAuthClick");
gapi.auth.authorize({
client_id: m_clientId,
scope: m_scopes,
immediate: false
}, handleAuthResult);
return false;
}
function useAuthResults() {
log("#useAuthResults");
// Get the Google+ user's ID and name (member info).
gapi.client.load('plus', 'v1', function () {
log("#gapi.client.load callback");
var request = gapi.client.plus.people.get({ 'userId': 'me' });
request.execute(function (aInfo) {
log("#request.execute callback");
if (aInfo.code !== undefined) {
alert('Google+ API returned ' + aInfo.code + ': ' + aInfo.message);
} else {
// Here with successful sign-in. Display the user name.
log('Google+ user id, name: ' + aInfo.id + ', ' + aInfo.displayName);
authorizeButton.value = aInfo.displayName + " +" + aInfo.id;
}
});
});
}
}
}
function log(msg) {
if (console) console.log(msg);
}
</script>
<script src="https://apis.google.com/js/client.js?onload=gapiIsReady" type="text/javascript"></script>
</head>
<body>
<h1>Test3a</h1>
<p>This pages demonstrates a problem I am having using gapi.client.request with gapi.auth.</p>
<input type="button" id="query-button" value="Query"><br>
<input type="button" id="startOAuth-button" value="Start OAuth"><br>
<input type="button" id="authorize-button" value="Authorize"><br>
<p>Steps...</p>
<p>1. Click "Query" to run a gapi.client.request Google Fusion Table SQL-get query returning
a count of rows. This will run successfully until OAuth is used in steps 2 and 3.</p>
<p>2. Click "Start OAuth" to run an immediate:true authorization against Google+. If you
are currently signed into Google+, your user name will be displayed in the third button.</p>
<p>3. If your Google+ user name is not displayed in the third button, press it ("Authorize")
and sign into Google+.</p>
<p>4. Click the "Query" button again.
The query will run without error when pressed within about 30 seconds of OAuth authorization.
After that, the query fails with a 403 error. WHY?</p>
</body>
</html>
Please note that I intend to use the Google+ sign-in to track page usage specifics by user, not to enable the Fusion Tables queries.
I'm new to OAuth and gapi.client.request so this may be a simple misunderstanding on my part.
Thanks for any insights.
I don't have all the answers for you, but here I think are some that may help:
Before you have the user sign-in with G+, the gapi.client.request object is adding a "key=yourAPIKey" parameter to each request.
After you have the user sign-in with G+, the gapi.client.request object is adding a "key=yourAPIKey" parameter to each request and is sending an "Authorization: Bearer ya.xxxxxx" header with each request, representing an access token for the user that is logged in.
I think the reason you're seeing a 403 is because the access token is being sent to the server, but the token does not include a scope authorizating access to FusionTables data. When no access token is sent - this validation is not performed.
If you actually wanted to access data that the user owned, then you need to have the user consent to give your application access to their data by including an appropriate scope in your gapi.auth.authorize call (e.g. "https://www.googleapis.com/auth/fusiontables").
However since I don't think you are trying to access data on behalf of a specific user, what I think you really want to do is prevent the "Authorization" header being sent at all during your call to Fusion Table API.
I can't see an easy way to prevent the gapi.client.request library from sending that header when the user is logged in, so an alternate solution might be to instead create an HTTP object not using the gapi.client.request library (e.g. use XMLHttpRequest directly) - and manually include the "key=yourAPIKey" in each request.
(What I can't explain is why you're seeing 30 seconds of differing behavior...)