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 ");
});
Related
I have created a Echo Bot in c# using QnA maker which is working absolutely fine now I wanted to achieve a scenario where if user ask any question and bot unable to find related answer than this question must be sent on Microsoft Teams channel where except will reply to the same and that message will sent to the user.
So, Is there any way to send message user message to Microsoft Teams for expert reply. If you have any sample code for the scenario please feel free to mention.
As per your current requirement this is kind of handoff or human live agent connect.
The following way you can achieve posting a message in ms team ( Go through this article Send proactive messages to Teams channels and users ).
Send proactive messages to Teams channels and users ( Microsoft Bot Framework v4 )
The user should be part of ms teams ( Azure AD valid users ).
Suggestions : If you are using domain bot then human live agent or handoff concept is the best approach otherwise you can integrate bin search api or any other third party api for unanswered question.
As per your requirement you can use Graph API to send message to channel using below code
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var chatMessage = new ChatMessage
{
Body = new ItemBody
{
Content = "Hello World"
}
};
await graphClient.Teams["{team-id}"].Channels["{channel-id}"].Messages
.Request()
.AddAsync(chatMessage);
Please go through this documentation for more info.
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.
I am attempting to send a message to a Teams Channel from within a proactive 3rd party WebHook callback that resides in my Teams Bot which is triggered externally some time after my bot conversation has ended.
My config.ServiceURL is 'https://smba.trafficmanager.net/amer/' which I got from my bot while conversing in a session.
My config.MicrosoftAppId value is the ApplicationID assigned to my bot App registration in Azure.
My config.MicrosoftAppPassword is a Client secret I created for the registered bot App.
My ChannelInfo value is the value I discovered by enumerating all the target team's channels in another application. I replaced the actual values with 'f's.
In Azure I added the following permission to my registered App: Delegate - Group.ReadWrite.All
When I attempt to create the conversation I get a Forbidden response. If I change my ChannelInfo below to a bogus value I receive a Not Found response as expected so at least the ChannelInfo appears to be a valid value.
Is there another permission I need to add? Have I missed step? Is there something I did wrong?
Here is the code:
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
var credentials = new MicrosoftAppCredentials(config.MicrosoftAppId, config.MicrosoftAppPassword);
if (!MicrosoftAppCredentials.IsTrustedServiceUrl(config.ServiceURL))
{
MicrosoftAppCredentials.TrustServiceUrl(config.ServiceURL);
}
var serviceUri = new Uri(config.ServiceURL);
var botConnector = new ConnectorClient(serviceUri, credentials);
Activity message = (Activity)Activity.CreateMessageActivity();
message.Text = "Hello World";
var conversationParameters = new ConversationParameters
{
Bot = message.From,
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo("19:ffffffffffffffffffffffffffffffff#thread.skype")
},
Activity = (Activity)message
};
var conversationResponse = await botConnector.Conversations.CreateConversationAsync(conversationParameters);
await botConnector
.Conversations
.SendToConversationAsync(message);
Your code worked fine for me. Here's a few things you can try:
Ensure you sideloaded your bot into Teams via App Studio or manifest upload and that you're not just talking with the bot by appId
Ensure your bot is installed to the Team you want it to message
Add the domain your bot is hosted on to the Valid Domains section of the bot manifest
Esure you're sending the message to the correct conversation by changing .SendToConversationAsync(message); to .SendToConversationAsync(conversationResponse.Id, message);
Also note that the Microsoft.Bot.Builder.Teams package has been deprecated now that Bot<->Teams functionality has been rolled directly into the Bot Framework SDK. I highly recommend migrating away from it.
You may want to send proactive messages as shown in this sample. The other Teams Samples are numbers 50-60.
Let me know if you want to stick with that package and I can continue trying to provide support.
I am developing a bot for Microsoft Teams using the Bot Framework SDK v4 for NodeJS. Is there a way that the bot can automatically initiate a conversation in a channel, rather than user initiating the conversation? My bot works fine when the user initiates the conversation. Any suggestions on how I can proceed with this?
MS Teams calls that a "Proactive Message" (note: Bot Framework generally defines a "proactive message" as sending a user a message not related to current conversation, that you have a reference for. Teams lumps a few things into this category). You can read more about how to use proactive messaging from the official Teams docs. Or, more specifically, creating a channel conversation.
The gist of it is that you need to capture a conversationUpdate and check for a new member added to the conversation or fetch the team roster, then you send the proactive message.
Note: For MS Teams, the user or team will have to add the bot first:
Bots can create new conversations with an individual Microsoft Teams user as long as your bot has user information obtained through previous addition in a personal or team scope. This information enables your bot to proactively notify them. For instance, if your bot was added to a team, it could query the team roster and send users individual messages in personal chats, or a user could #mention another user to trigger the bot to send that user a direct message.
Some developers come across 401: Unauthorized errors when using proactive messaging, especially if the bot was restarted for some reason and the bot is attempting to re-initiate a proactive message. You can read more about preventing that by using trustServiceUrl from this Sample (this is my branch, which is being used to submit a Pull Request to update the Proactive Sample with trustServiceUrl info).
You can initiate a brand new conversation using the connector Client in the Botframework V4 and the Teams Extensions V4. In nodejs, you will find a solution in one of the comments for this Github Issue. For anyone looking for a solution in C#, here is a detailed blog post about accomplishing this in C# version of the botframework.
in nodejs :
var conversationReference = TurnContext.getConversationReference(context.activity)
connectorClient = await createConnectorClient(context)
var conversationParameters = {
isGroup: true,
bot: conversationReference.bot,
channelData: (await teamsCtx.getTeamsChannelData()),
tenantId: teamsCtx.tenant.id,
activity: MessageFactory.text("Queue Summary Placeholder") as Activity
} as ConversationParameters
await connectorClient.conversations.createConversation(conversationParameters)
In C#
ConnectorClient _client = new ConnectorClient(new Uri(turnContext.Activity.ServiceUrl), await GetMicrosoftAppCredentialsAsync(turnContext), new HttpClient());
var channelData = turnContext.Activity.GetChannelData<TeamsChannelData>();
var conversationParameter = new ConversationParameters
{
Bot = turnContext.Activity.Recipient,
IsGroup = true,
ChannelData = channelData,
TenantId = channelData.Tenant.Id,
Activity = MessageFactory.Text(message)
};
var response = await _client.Conversations.CreateConversationAsync(conversationParameter);
Really we need to know when you want the bot to send the message, the bot framework TeamsActivityHandler class provides multiple methods that you can utilise for example:
onMembersAdded(BotHandler): Registers an activity event handler for the members added event, emitted for any incoming conversation update activity that includes members added to the conversation.
Learn more about the events / methods you can utilise here.
I ended up figuring it out and i wrote a bot controller that i can invoke on demand with the following code.
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
// this needs to come from the teams context.
Channel = new ChannelInfo(channelId),
},
Activity = (Activity)MessageFactory.Attachment(attachment)
};
// your service url may differ.
MicrosoftAppCredentials.TrustServiceUrl(String.IsNullOrEmpty(serviceUrl) ? constantServiceUrl : serviceUrl, DateTime.MaxValue);
var response = connectorClient.Conversations.CreateConversationAsync(conversationParameters).GetAwaiter().GetResult();
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.