I am using the following sample / article to Manage a Long-running operation in MS Teams Bot.
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-long-operations-guidance?view=azure-bot-service-4.0
In step 5, a DirectLineClient is being created and an Event Activity is sent to Bot using PostActivityAsync.
var responseActivity = new Activity("event");
responseActivity.Value = originalActivity;
responseActivity.Name = "LongOperationResponse";
responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
using(DirectLineClient client = new DirectLineClient(directLineSecret))
{
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
}
However, I need the above sample to work for MS Teams Bot and not the DirectLineClient.
I used Microsoft.Bot.Connector.ConnectorClient but StartconversationAsync and PostActivityAsync methods are not available.
I tried the methods available in Microsoft.Bot.Connector.ConnectorClient
connectorClient.Conversations.CreateConversationAsync(conversationparameters)
connectorClient.ConversationsCreateDirectConversationAsync(botAccount, userAccount, (Activity)newActivity);
connectorClient.Conversations.SendToConversationAsync(conversationid, (Activity)newActivity);
But all the methods failed with Bad Requestwith the error as seen in the Response:
{"error":{"code":"BadArgument","message":"Unknown activity type"}}
The newActivity is created as below:
var messagnewActivity = new Activity("event");
newActivity.Value = originalActivity;
newActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
newActivity.Type = "event";
newActivity.Conversation = new ConversationAccount { Id = originalActivity.Conversation.Id };
newActivity.ChannelId = originalActivity.ChannelId;
Can someone please suggest how do I pass the Activity (Event Activity type) to MS Teams Bot.
Thanks
Gagan
I'm not really familiar with Direct Line, but I think it's effectively an -alternative- type of bot to Teams, so if you're trying to do this inside Teams, it explains the issue. In principle, the basic idea is quite simple though:
you store state somehow (e.g. in memory or in a database) to indicate that the long running operation is in progress for the user
when the long-running process is complete, your code (which could live OUTSIDE your bot, e.g. in an Azure Function) can send the user a message AS IF IT WAS the bot - this is called Pro-Active Messaging and you can read more about it at https://learn.microsoft.com/en-us/graph/teams-proactive-messaging.
This is to inform you that I was facing the same issue sometime before then I found a tweak in the code while debugging. when it calls twice recursively then the Activity Id is the same as the previous one. you can check if the activity id is the same then return the request else go with it.
Related
My question is a copy of this question
However, I don't understand how to use the answer given there
The library I am using already implements what the answer says
TelegramClient.cs
var config = new TLRequestGetConfig();
var request = new TLRequestInitConnection()
{
ApiId = apiId,
AppVersion = "1.0.0",
DeviceModel = "PC",
LangCode = "en",
Query = config,
SystemVersion = "Win 10.0",
SystemLangCode = "en",
LangPack = ""
};
var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 108, Query = request };
await sender.Send(invokewithLayer, token).ConfigureAwait(false);
await sender.Receive(invokewithLayer, token).ConfigureAwait(false);
dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList();
Where does Telegram send updates?
I thought the updates could be read in the TcpClient that the TelegramClient has, but no, it doesn't receive updates
The documentation says:
Update events are sent to an authorized user into the last active
connection (except for connections needed for downloading / uploading
files).
So to start receiving updates the client needs to init
connection and call API method, e.g. to fetch current state.
But where does it send updates? How do I subscribe to them / how do I read them?
P.S. updates.getDifference is not what i'm looking for
UPD
I've already looked at all the source code, but the most I found is processMessage in MtProtoSender, but it only handles manually sent requests
Another library based on TDLib handles incoming updates. Trying to understand how it does it, I got to this point. What is going on here and how can I do the same in TLSharp I do not understand
Same problem in another library which was solved but doesn't work for me
I've raised a bug item against the C# Bot Builder project on GitHub but to be honest I can't really get to the bottom of whether this is a bug with the framework or a sporadic problem originating on the Facebook side.
We have been building the bot for a couple of months and have been using in development and staging exvironments extensively and have not seen this issue once.
So we go live with our first customer and boom. This issue starts occuring.
Value cannot be null. Parameter name: invalid activity-missing From.Id
And also:
Value cannot be null. Parameter name: invalid activity-missing
Conversation.Id
The chats that produced this issue were started by users coming to the bot via the messenger web page and the Web Chat Plugin.
The users in both instances had used the "Get Started" button thus opting in to the chat. This opting in provides the bot with access to the users basic profile information.
Understandably this is pretty odd and I have been entirely unable to reproduce this issue in any testing in any of our environments (we have Dev, Staging and Live).
Has anyone else seen a similar issue?
What did you do to work around it?
At the moment since I cannot reproduce it anywhere I can't really close the bug or even have a vague level of confidence in it not happening again.
If your bot is designed with the Activity Handler, as demonstrated in the Samples-work-in-progress branch, you can add some code to the controller to log the entire Request.Body:
[Route("api/messages")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter Adapter;
private readonly IBot Bot;
public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
{
Adapter = adapter;
Bot = bot;
}
[HttpPost]
public async Task PostAsync()
{
Request.EnableBuffering();
using (var buffer = new MemoryStream())
{
await Request.Body.CopyToAsync(buffer);
buffer.Position = 0L;
using (var bodyReader = new JsonTextReader(new StreamReader(buffer, Encoding.UTF8)))
{
Debug.Print(BotMessageSerializer.Deserialize(bodyReader).ToString());
buffer.Position = 0L;
}
}
Request.Body.Position = 0;
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
This should provide more information on what type of message is being sent to the bot. My guess is that it has something to do with a Facebook Messenger specific web hook you have subscribed to. For instance, I don't think 'message_echoes' are currently sent to the bot with a .From or conversation.Id. However, we have recently modified our Connector Service to include these: the release should be within the next few weeks.
So i created a bot in azure and downloaded it. The free 1000 calls from LUIS reached its limit. I created a subscription in azure portal (I did do the docker container something). Followed this guide until step 6. When i click the endpoint url and query directly in the browser it is working fine.
I added it to the bot via Bot Emulator by clicking + sign in services and adding the bot model there. But when i run bot i get the title error. I noticed in the .bot file the authoring key and subscription key added by the bot emulator is the same.
So i changed the subscription key to the one of the keys generated by azure and still the same error. I have tried reseting the authoring key still same and deleting my luis.ai account and created a new one. (still same email because that is the one logged in azure portal.) and still the same.
Here are some pictures for reference and the error.
I also tried testing it in luis.ai and got this result.
but when i check it is set to the new resource.
Here is a pic of the bot file after adding luis via Bot emulator. It has same authoring key and subscription key (still forbidden)
so i changed it now with subscription key (still forbidden).
Here it is working properly when tested directly in the URL.
For reference:
azure portal
luis.ai
and the error
How i add luis in the bot.
Here is the code for the bot service.
using System;
using System.Collections.Generic;
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Configuration;
namespace Microsoft.BotBuilderSamples
{
public class BotServices
{
public BotServices(BotConfiguration botConfiguration)
{
foreach (var service in botConfiguration.Services)
{
switch (service.Type)
{
case ServiceTypes.Luis:
{
var luis = (LuisService)service;
if (luis == null)
{
throw new InvalidOperationException("The LUIS service is not configured correctly in your '.bot' file.");
}
var endpoint = (luis.Region?.StartsWith("https://") ?? false) ? luis.Region : luis.GetEndpoint();
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
var recognizer = new LuisRecognizer(app);
this.LuisServices.Add(luis.Name, recognizer);
break;
}
}
}
}
public Dictionary<string, LuisRecognizer> LuisServices { get; } = new Dictionary<string, LuisRecognizer>();
}
}
I am trying to solve this for 4 days already. Thanks!
Thank you for all of the images. That is a HUGE help! Here's the problem:
By default, your code looks for the AuthoringKey in this section (second line):
var endpoint = (luis.Region?.StartsWith("https://") ?? false) ? luis.Region : luis.GetEndpoint();
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
var recognizer = new LuisRecognizer(app);
this.LuisServices.Add(luis.Name, recognizer);
Since your .bot file still has the authoringKey set to the one that starts with ad9c..., which has hit its limit, your bot keeps running into the 403 error.
So, in your .bot file, replace that authoringKey with one of your endpointKeys (they start with 12ccc... or b575...).
I understand your confusion with this, especially since this requires you putting an endpointKey in your authoringKey property. I know there's some changes on the horizon to how LUIS bots will use keys, but those are probably a month or more out.
Alternatively, you can change:
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
to:
var app = new LuisApplication(luis.AppId, luis.SubscriptionKey, endpoint);
Note: If you make either of these changes, LUIS can only query (which is usually fine), since Authoring Keys do everything else (see reference, below)
References
These are not so much for you as much as others that might come across this.
Authoring vs. Endpoint Keys
Key Limits
Troubleshooting LUIS 403 Errors
I am trying to use the Microsoft Bot Framework DirectLine API to read and add messages to existing conversations between other users and my bot. From what I've read I believe this should be possible when using the master-secret but it's just not working for me. I'm using a WebAPI to try and access two of my existing conversations (on Facebook & Skype) as follows:
[HttpPost]
[Route("remind")]
public string Remind()
{
var secret = System.Configuration.ConfigurationManager.AppSettings["secret"];
var uri = new Uri("https://directline.botframework.com/");
var creds = new DirectLineClientCredentials(secret);
DirectLineClient client = new DirectLineClient(uri, creds);
Conversations convs = new Conversations(client);
var conversationIDs = new string[] { "0000000000000000-0000000000000000", "00:0123456789abcdefghijklmnopqrstuvwxyz0123456789-A-_0123456798ABCDEF" }; // Existing Facebook & Skype conversations
// Send a message to each conversation:
foreach (var conversationID in conversationIDs)
{
Message message = new Message(conversationId: conversationID, fromProperty: "My Bot", text: "Hey dude, remember that thing!");
Console.WriteLine(message.Text);
convs.PostMessage(conversationID, message); // FAILS - This executes but doesn't do anything.
}
// Try reading the messages from a conversation (just to test if it's working):
string waterMark = null;
var set = convs.GetMessages(conversationIDs[0], waterMark); // FAILS - This fails with a 404 not found.
waterMark = set.Watermark;
return "Done :-)";
}
It fails silently calling PostMessage() and fails with a 404 for the GetMessages(). I seem to be doing the right thing, the bot is live etc and works very well in Facebook & Skype separately from the DirectLine API. It only works if I create a new conversation using the DirectLine API, I can then access its messages and post new messages to it.
This question sort of helps but doesn't quite tell me what to do to fix it:
Difficulty accessing messages in an existing conversation in Microsoft Bot Framework
Any help would be much appreciated.
Thanks
For security reasons, you can't use DirectLine to spy on messages from another conversation. For the scenario you describe (escalating to a human) there a number of different ways to approach this. One is to have your bot broker conversations between the accounts (i.e. Facebook End User <-> Your Bot <-> Facebook Support Person). Each is talking to the bot, and the bot passes the message through to the other user. (Could also be Facebook User <-> Your Bot <-> Skype User) Your bot would have to store last n messages to provide context. Alternatively, I've seen folks build their own customer support chat interface using direct line that sits on the far side. Hope this helps
Right now I have an app that allows a user to schedule/post a Facebook post and then monitor the likes/comments. One of the problems I foresee is that currently I am pulling every single comment/like whether it's been processed or not. What I would like to do instead is be able to say 'Give me all the NEW comments since XYZdate/XYZcomment.' Is this currently possible?
var accessToken = existingUserNode.Attributes["accessToken"].Value;
var facebookAPIMgr = new FacebookWrapper.FacebookAPIManager();
var msg = new FacebookWrapper.FacebookMessage()
{
AccessToken = accessToken,
FacebookMessageId = facebookPost.FacebookMessageId
};
//Get Facebook Message Comments
// Need to find a way to limit this to only new comments/likes
var comments = facebookAPIMgr.RetrieveComments(msg);
You can do time-based pagination as part of your graph API query. If you keep a unix timestamp of when you polled things last, you can simply do https://graph.facebook.com/{whatever}?since={last run}.
This worked when I was working heavily with the Graph API earlier this year, and is still around on the documentation, but considering how much Facebook loves to change stuff without telling anyone you may still encounter problems. So just a warning, YMMV.