How to access Bot Skills via API? - botframework

Does Microsoft publish Bot Skills as a API for consumption. I have a need to invoke botskills command programmatically in order to publish it to my VA. How can i do this?

botskills is a Command Line Tool, so no, there's no direct API for it.
That being said, most programming languages allow you to execute shell commands. Based on your post history, it looks like you're using Node. So, you can do something like this:
const { exec } = require("child_process");
exec("botskills connect --localManifest "./skills/customSkill/customSkillManifest.json" --skillsFile "./skills.json" --cs --verbose", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
If botskills is hosted somewhere and you need to use it like an API, you can always add an endpoint to your bot:
server.post('/api/botskills', (req, res) => {
// 1. Do some kind of conditional check on the request to make sure it is allowed to do this
// 2. Execute the command in the previous code block
// 3. Return a response
}
If your questions is not about the botskills package/CLI and is actually about "Bot Skills", you interact with a skill just like a bot. They're basically the same thing and you'd use the same REST API.

Related

Teams bot, transfer a call to another application / voicemail

In our Teams calling bot, we would like to transfer certain calls to specific Teams users, PSTN, but also to an other Teams calling bot and/or voicemail.
For specific Teams users and PSTN we got it working. If we want to transfer a call to another application, we can do so by using its pstn number. But ideally we would also like to transfer using its objectId.
I tried using a transferrequest like this:
var requestBody = new CallTransferRequestBody()
{
TransferTarget = new InvitationParticipantInfo()
{
Identity = new IdentitySet()
{
AdditionalData = new Dictionary<string, object>()
}
}
};
requestBody.TransferTarget.Identity.Application = new Identity { Id = transferTargetId };
//this line does not make any difference
requestBody.TransferTarget.Identity.Application.SetTenantId(tenantId);
But this results in a "Request authorization tenant mismatch." error. Is it possible to directly transfer to another application?
I haven't tried voicemail boxes yet, but if any info on how to transfer to those, is appreciated.
Basically we can transfer an active peer-to-peer call. This is only supported if both the transferee and transfer target are Microsoft Teams users that belong to the same tenant.
However for redirecting call to call queue or auto attendants, you can use the "applicationInstance" identity. The bot is expected to redirect the call before the call times out. The current timeout value is 15 seconds.
const requestBody = {
"targets": [{
"#odata.type": "#microsoft.graph.invitationParticipantInfo",
"identity": {
"#odata.type": "#microsoft.graph.identitySet",
"applicationInstance": {
"#odata.type": "#microsoft.graph.identity",
"displayName": "Call Queue",
"id": queueId
}
}
}],}
Please refer to the documentation here: https://learn.microsoft.com/en-us/graph/api/call-redirect?view=graph-rest-beta&tabs=csharp#request
The redirect API is still having that limitation from my understanding.
But that should work with the new Transfer API:
https://learn.microsoft.com/en-us/graph/api/call-transfer?view=graph-rest-beta&tabs=http

connect ETIMEDOUT 137.116.128.188:443 for bot FRAMEWORK, can be extended

So I have a request that is expected to run for at least 1 min. before it will give a response
To help aid user on not doing anything while my request is still running, I set some sendTyping activities:
For censoring production codes work sensitive information
, this is generally how my code looks like:
var queryDone = "No";
var xmlData = '';
let soappy = soapQuery("123", "456", "789","getInfo");
soappy.then(function (res) {
queryDone = 'Yes';
xmlData = res;
console.log(xmlData);
}, function (err) {
queryDone = 'Timeout';
})
while (queryDone == 'No') {
await step.context.sendActivity({ type: 'typing' });
}
where soapQuery() is a function that sends and returns the POST request which looks like this:
return new Promise(function (resolve, reject) {
request.post(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
reject(error);
}
})
})
Problem comes because of this 1 minute response, (it's not really negotiable as the server requires at least 1 min to process it, due to large number of data and validation of my request).
Though after 1 minute, the console does print the response, sadly even before this, the bot already time out.
Any suggestion how to fix this, or extend time out of the bot?
I need the sendtyping activity so that user understands that the request is not yet done. And again, it really takes 1 minute before my request responds.
Thank you!
So, the reason that this happens is that HTTP requests work a little bit differently in the Bot Framework than you might expect. Here's how it works:
So basically, what's happening in your scenario is:
User sends HTTP POST
Bot calls your soapQuery
Bot starts sending Typing Indicators
soapQuery completes
Bot finally sends an HTTP Response to the HTTP POST from step #1, after the request has already timed out, which happens after 15 seconds
To fix this, I would:
Use showTypingMiddleware to send the typing indicator continuously and automatically until the bot sends another message (this gets rid of your blocking while loop)
Once soapQuery finishes, the bot will have lost context for the conversation, so your soappy.then() function will need to send a proactive message. To do so, you'll need to save a reference to the conversation prior to calling soappy(), and then within the then() function, you'll need to use that conversationReference to send the proactive message to the user.
Note, however, that the bot in the sample I linked above calls the proactive message after receiving a request on the api/notify endpoint. Yours doesn't need to do that. It just needs to send the proactive message using similar code. Here's some more documentation on Proactive Messages

Get all the conversations of a user

(New to Microsoft Bot Framework) Is there a way in which I can find all the existing conversations of a user? I am using the Microsoft Bot Framework (SDK4) to make a chat bot.
Requirement: I want to list all the conversations a user has had till now.
Bot Framework, at this time, doesn't have a way of ingesting all past conversations from a transcript or store.
However, there are a couple options for how you can capture user conversations so you don't have to rely on a complete transcript of a conversation.
The first option is to implement middleware that logs the activity or elements of the activity you want. What you choose to capture and what you choose to do with it is up to you. In the following code, I am logging in the console all user responses and all bot activity that isn't a typing event or an endOfConversation event. You would replace the console.log() calls with your custom code that would store the data. Just keep in mind, that whatever call you make here would happen on every user / bot activity. If you're looking to make API calls, consider storing the data in an object and saving it when the 'endOfConversation' is returned (or something similar).
adapter.use(async (turnContext, next) => {
// turnContext.(async (ctx, activities, next) => {
// activities.filter(a => a.type === 'message').forEach(a => console.log('From user: ', a));
// });
const userActivity = turnContext.activity;
if (userActivity.from.role === 'user' && turnContext.activity.text.length > 0) {
console.log('From user: ', userActivity);
}
turnContext.onSendActivities(async (sendContext, activities, nextSend) => {
await nextSend();
activities.filter(a => a.type !== 'typing' && a.type !== 'endOfConversation').forEach(a => console.log('From bot: ', a));
});
await next();
});
The second option is to model your bot after the logger / transcript-logger samples from the Botbuilder-Samples repo. You can modify the customLogger.js file to match your needs and output to a store.
Hope of help!

Using MS BotFramework NodeJS sdk WITHOUT LUIS

I am currently working on a project where visitors are normally using both English and Chinese to talk to each other.
Since LUIS did not support multi-language very well (Yes I know it can support in certain ways but I want a better service), I would like to build my own Neural Network as a REST API so that, when someone submits their text, we can simply predict the "Intent", while we are still using MS BotFramework (NodeJS).
By doing this we can bypass MS LUIS and using our own Language understanding service.
Here are my two questions:
Has anyone done that before? Any GitHub link I can reference to?
If I did that, what is the BotFramework API I should use? There is a recognizer called "Custom Recognizer" and I wonder if it really works.
Thank you very much in advance for all your help.
Another option apart from Alexandru's suggestions is to add a middleware which will call the NLP service of your choosing everytime the bot receive a chat/request.
Botbuilder allows middleware functions to be applied before handling any dialogs, I created a sample code for a better understanding below.
const bot = new builder.UniversalBot(connector, function(session) {
//pass to root
session.replaceDialog('root_dialog');
})
//custom middleware
bot.use({
botbuilder: specialCommandHandler
});
//dummy call NLP service
let callNLP = (text) => {
return new Promise((resolve, reject) => {
// do your NLP service API call here and resolve the result
resolve({});
});
}
let specialCommandHandler = (session, next) => {
//user message here
let userMessage = session.message.text;
callNLP.then(NLPresult => {
// you can save your NLP result to a session
session.conversationData.nlpResult = NLPResult;
// this will continue to the bot dialog, in this case it will continue to root
// dialog
next();
}).catch(err => {
//handle errors
})
}
//root dialog
bot.dialog('root_dialog', [(session, args, next) => {
// your NLP call result
let nlpResult = session.conversationData.nlpResult;
// do any operations with the result here, either redirecting to a new dialog
// for specific intent/entity, etc.
}]);
For Nodejs botframework implementation you have at least two ways:
With LuisRecognizer as a starting point to create your own Recognizer. This approach works with single intent NLU's and entities arrays (just like LUIS);
Create a SimpleDialog with a single handler function that calls the desired NLU API;

how to use 'actions-on-google' libray in aws lambda

In actions-on-google , both the request and response object need to provide as input to this library. but in lambda function, only the request object exists.
So how can i override it ?
in aws lambda the format is
exports.handler = function (event, context, callback) { // event is the request object , the response is provided using the callback() functon
}
the actions-on-google object is created as :
const DialogflowApp = require('actions-on-google').DialogflowApp;
const app = new DialogflowApp({ request: request, response: response });
To get a Google Action to work on AWS Lambda, you need to do 2 things:
Code your app in a way that it's executable on Lambda
Create an API Gateway to your Lambda Function which you can then use for Dialogflow Fulfillment
I believe the first setp can't be done off-the-shelf with the Actions SDK. If you're using a framework like Jovo, you can create code that works for both Amazon Alexa and Google Assistant, and host it on AWS Lambda.
You can find a step by step tutorial about setting up a "Hello World" Google Action, host it on Lambda, and create an API Gateway here: https://www.jovo.tech/blog/google-action-tutorial-nodejs/
Disclaimer: I'm one of the founders of Jovo. Happy to answer any further questions.
This is only a half answer:
Ok, so I dont think I can tell you how to make the action on google sdk correct working on AWS Lambda.
Maybe its easy, I just dont know and need to read everything to know it.
My, "easy to go", but at the end you will maybe have more work solution, would be just interprete the request jsons by yourself and responde with a message as shown below
This here would be a extrem trivial javascript function to create a extrem trivial JSON response.
Parameters:
Message is the string you would like to add as answer.
Slots should be an array that can be used to bias the speech recognition.
(you can just give an empty array to this function if you dont want to bias the speech).
And State is any kind of serilizable javascript object this is for your self to maintain states or something else It will be transfered between all the intents.
This is an standard response on an speech request.
You can add other plattforms than speech for this, by adding different initial prompts please see the JSON tabs from the documentation:
https://developers.google.com/actions/assistant/responses#json
function answerWithMessage(message,slots,state){
let newmessage = message.toLowerCase();
let jsonResponse = {
conversationToken: JSON.stringify(state),
expectUserResponse: true,
expectedInputs: [
{
inputPrompt: {
initialPrompts: [
{
textToSpeech: newmessage
}
],
noInputPrompts: []
},
possibleIntents: [
{
intent: "actions.intent.TEXT"
}
],
speechBiasingHints: slots
}
]
};
return JSON.stringify(jsonResponse,null, 4);
}

Resources