Using Text Translator to make a Multilingual QnA Bot - azure-bot-service

I have a QnA bot that I am trying to add bilingual support for. My goal is to use Text translator cognitive service in Azure to identify the user's language based on their initial contact, translate that to english to search the QnA knowledge base and then translate the answer back to the user's language.
The QnA bot is hosted on Azure as a Web Service. I have a beginner level knowledge in programming, and some of the support I have found on the web goes way over my head.
What is the best way to integrate the text translator with the QnA bot?

Your QnA bot is simply a bot which is interacting with QnA Maker API.
So in your case, the easier way of processing is to translate the received message just before querying QnA Maker, then doing the reverse translate on its replies once you got it.
If you have a look to the Bot Builder samples for QnA Maker here, you can see the query, which is using Microsoft.Bot.Builder.AI.QnA:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var httpClient = _httpClientFactory.CreateClient();
var qnaMaker = new QnAMaker(new QnAMakerEndpoint
{
KnowledgeBaseId = _configuration["QnAKnowledgebaseId"],
EndpointKey = _configuration["QnAEndpointKey"],
Host = _configuration["QnAEndpointHostName"]
},
null,
httpClient);
_logger.LogInformation("Calling QnA Maker");
// The actual call to the QnA Maker service.
var response = await qnaMaker.GetAnswersAsync(turnContext);
if (response != null && response.Length > 0)
{
await turnContext.SendActivityAsync(MessageFactory.Text(response[0].Answer), cancellationToken);
}
else
{
await turnContext.SendActivityAsync(MessageFactory.Text("No QnA Maker answers were found."), cancellationToken);
}
}
As you can see, the call await qnaMaker.GetAnswersAsync(turnContext) is using turnContext directly, not the text itself.
You must modify the Activity text before making this call. Here you can use Translator Text API from Microsoft to do the translation. It can automatically detect input language (but if you already know it, it's better to provide the value).
Then, you have to translate response[0].Answer in the reply.
The reference of Translator API is here: https://learn.microsoft.com/en-us/azure/cognitive-services/translator/reference/v3-0-translate
Note: there is a library which is currently experimental in Bot Builder samples regarding translation: https://github.com/microsoft/BotBuilder-Samples/tree/master/experimental/multilingual-luis/csharp_dotnetcore/Libraries/Microsoft.Bot.Builder.AI.Translation
I did not mentioned it in my reply as I did not had time to check and due to its experimental status.

Related

QnA Maker Bot working in Teams private chats, but no answers when mentioned in team

I configured a knowledge base at qnamaker.ai, published it, and created a bot using Azure Bot Service.
In Teams, I created a new bot app and associated it with the deployed bot. The bot is allowed for private chats, group chats, and teams.
If I'm in a private chat and "ask" it "deploy cosmosdb", it comes back with the correct answer.
If I'm using the bot in a team, by mentioning it "#CS Bot deploy cosmosdb", it doesn't know the anwer.
If I mention the bot in the private chat, I see the same behaviour: no answer.
But to talk to the bot it MUST be mentioned, so where's the problem here?
UPDATE:
Thanks to Hilton's answer below, I noticed that when you download the bot source code (in my case, it's a dotnet core project), the README.MD file states this issue and how to fix it:
Microsoft Teams channel group chat fix
Goto Bot/QnABot.cs
Add References
using Microsoft.Bot.Connector;
using System.Text.RegularExpressions;
Modify OnTurnAsync function as:
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
// Teams group chat
if (turnContext.Activity.ChannelId.Equals(Channels.Msteams))
{
turnContext.Activity.Text = turnContext.Activity.RemoveRecipientMention();
}
await base.OnTurnAsync(turnContext, cancellationToken);
// Save any state changes that might have occurred during the turn.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
If you inspect the text that comes back in the 1st message, it will be "deploy cosmosdb". In the 2nd message though, it will be "CS Bot deploy cosmosdb" which the QnAMaker is struggling to parse. What you want to do, before passing the query text to QnAMaker, is to remove the "#" mention entirely from the text.
This is a common issue, so the Bot Framework already has a method to deal with this. You haven't mentioned what platform you're developing on, but here is a link for dotnet to the RemoveRecipientMention method. I'm pretty sure there's an equivalent on Node, etc.
The final effect would be to convert your Activity's Text to be the same in both cases, which would result in the same response from QnAMaker.

How to pass the password activity form bot to the front end in microsoft bot framework

I am trying to implement the functionality of the password as shown in this link.
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/05.custom-components/f.password-input
but how to pass the password activity form the bot to the front end. I am using the c# template for the developing the bot.
As per my understanding, we need to pass a password activity from the bot to the front-end for the execution of the password things as mentioned in the link.
An example would be help-full in knowing how to pass this type of customer activity forms the bot.
Thanks,
I used this sample myself for one of my bots. The bot logic is built in node but I guess it shouldn't be hard to translate to c#
const askPwd =
{
name: 'passwordInput',
type: 'event'
};
await stepContext.context.sendActivity(askPwd);
return await stepContext.prompt(PASSWORD_PROMPT, '');
In c# this will probabaly translate into something like this (I don't know c#):
Activity activity = new Activity
{
Type = ActivityTypes.Event,
Name = "passwordInput"
};
await stepContext.Context.SendActivityAsync(activity, cancellationToken);});

Microsoft Bot Framework - Handoff to an agent

I am working on creating a chat bot using microsoft bot framework. Have a requirement to add an agent into the conversation if the bot is not able to identify customer's intent.
All the examples that I found are for botbuilder:3.7.0 but we are using botbuilder:4.1.5 .
Found a method in BotFrameworkAdapter, which would help us do this but it is not working.
reference = TurnContext.getConversationReference(context.activity);
await adapter.createConversation(reference, async (ctx) => {
console.log(ctx);
await ctx.sendActivity("Hi (in private) -- Successful ");
});

Botbuilder SDK v4 creating 1:1 conversation from group

I'm attempting to send a 1:1 / private message to a specific user who tagged the bot in channel in Microsoft Teams. Because there isn't a botbuilder-teams that is compatible with botbuilder v4, I figured I'd have to implement this functionality myself. I know with proactive messages, you can use adapter.continueConversation which works correctly, but adapter.createConversation does not. Here is the relevant piece of code within one of my dialogs:
let reference = TurnContext.getConversationReference(cx.activity);
await adapter.createConversation(reference, async (context) => {
await context.sendActivity("Hello World!");
});
The first parameter for CreateConversation Method should be the channel ID, which is in your case "teams". You don't have to supply the existing conversation reference as you are creating a new one.

Securing traffic from Microsoft Teams to a bot?

How to secure the traffic from Microsoft Teams to a bot, so that bot could be answering on company specific questions / discussions and would not need to be exposed as anonymous WebAPI?
Bot integration to Teams UIs is easy from bot framework side, but right now there's no documentation for how to isolate bot only for specific enterprise.
Business case - We want to build enterprise specific bot, which could answer questions only specific to that particular enterprise where the questions are coming from. Technically this could be done with app-only access to SharePoint or Microsoft Graph, but we cannot expose this kind of WebAPI anonymously for Internet.
Any design patterns for this?
This is now possible, and I've actually even implemented it for Hubot in CoffeeScript and Node.JS. What I've described below is what it would look like in JavaScript/Node.JS.
Define an environment variable that, when set, filters for a particular tenant ID, OFFICE_365_TENANT_FILTER. (Doing it this way is a handy way of turning this feature on in production but not necessarily during development.)
For Microsoft Teams, the Office 365 tenant ID can be found here: session.message.sourceEvent.tenant.id.
The most elegant way to do it is to check for the tenant ID as middleware, and just drop further processing of the message if the filter is set and it doesn't match:
// [...]
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
var bot = new builder.UniversalBot(connector);
// Middleware to check for OFFICE_365_TENANT_FILTER and only continue processing if it matches.
// If OFFICE_365_TENANT_FILTER is not specified, do nothing.
bot.use({
botbuilder: function(session, next) {
var targetTenant = typeof(process.env.OFFICE_365_TENANT_FILTER) !== "undefined" ? process.env.OFFICE_365_TENANT_FILTER : null;
var currentMsgTenant = typeof(session.message.sourceEvent.tenant) !== "undefined" ? session.message.sourceEvent.tenant.id : null;
if (targetTenant !== null) {
if (targetTenant == currentMsgTenant) {
next();
}
else {
console.log("MS Teams: Attempted access from a different Office 365 tenant (" + currentMsgTenant + "): message rejected");
}
}
else {
next();
}
}
});
// [...]
Here's how to do this in C#, the SDK exposes the TenantFilter that allows you to add this action filter to the controller class as shown below.
using Microsoft.Bot.Connector.Teams;
namespace Microsoft.Teams.Samples.HelloWorld.Web.Controllers
{
[BotAuthentication, TenantFilter]
public class MessagesController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody] Activity activity)
The tenant filter will take a comma separated list of tenantIds that will need to be placed in the web.config
<configuration>
<appSettings>
<!--other settings-->
<add key="AllowedTenants" value="*TenantId1,TenantId2,...*"/>
Find your Office 365 tenant ID shows how you can do it through PowerShell.
It is not currently possible to know the tenant-id of the user chatting with the bot right away, unless the bot authenticates the user first. Please take a look at AuthBot. It illustrates how to send a sign-in link to a user and authenticate the user against AAD.
Although not exactly what you are looking for, you can create custom bots which will be scoped to individual Teams.
The security key/HMAC auth will prevent others from accessing the API. With the drawback that you will have to configure the bot with a separate security token for every Team where you want to use it.

Resources