Just a quick tip, if there is a nicer way then please comment 🙂
activity.Attachments?. Where(a => a.ContentType == "application/vnd.microsoft.card.hero"). Select(c => JsonConvert.DeserializeObject(c.Content.ToString())). ToList()
Just a quick tip, if there is a nicer way then please comment 🙂
activity.Attachments?. Where(a => a.ContentType == "application/vnd.microsoft.card.hero"). Select(c => JsonConvert.DeserializeObject(c.Content.ToString())). ToList()
V4.3 comes with some nice additional support that I was eager to use. However, there is a problem. v4.3 (Microsoft.Bot.Builder.Azure) uses the latest variant of the Azure Storage library whereas Microsoft.AspNetCore.All, via Microsoft.AspNetCore.DataProtection.AzureStorage (2.2.0), uses the older variant. This can cause problems if your own code wishes to use one of the clashing types. E.g. if you add
CloudStorageAccount blah = new CloudStorageAccount(null, false);
Then you’ll get an error like The type X exists in both Y and Z, e.g.
error CS0433: The type 'CloudStorageAccount' exists in both 'Microsoft.Azure.Storage.Common, Version=9.4.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' and 'Microsoft.WindowsAzure.Storage, Version=9.3.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
The only solution I’ve found is to utilize the obscure extern and some trickery I grabbed from SO – using extern alias.
Step 1 – Create (or ensure there is) an xml file in the root of your project called Directory.Build.targets (don’t put .xml as the extension)
Step 2 – populate with;
<Project> <Target Name="AddPackageAliases" BeforeTargets="ResolveReferences" Outputs="%(PackageReference.Identity)"> <PropertyGroup> <AliasPackageReference>@(PackageReference->'%(Identity)')</AliasPackageReference> <AliasName>@(PackageReference->'%(Alias)')</AliasName> </PropertyGroup> <ItemGroup> <ReferencePath Condition="'%(FileName)'=='$(AliasPackageReference)'"> <Aliases>$(AliasName)</Aliases> </ReferencePath> </ItemGroup> </Target> </Project>
Step 3 – edit the project. Unload your bot project, edit it and find the reference you wish to alias. Add Alias= E.g. to add the alias AzureCommon
<ItemGroup> <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.9.1" /> <PackageReference Include="Microsoft.ApplicationInsights.TraceListener" Version="2.9.1" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.All" /> <PackageReference Include="Microsoft.Azure.KeyVault.Core" Version="3.0.3" /> <PackageReference Include="Microsoft.Azure.Storage.Common" Version="9.4.2" Alias="AzureCommon"/>
Save and reload the project
Step 4 (optional) -That should be enough to provide the separation for the compiler. But if you want to use the aliased version then add the extern to where you wish to use the clashing type, e.g.;
extern alias AzureCommon; using AzureStore = AzureCommon; ... AzureCommon.Microsoft.WindowsAzure.Storage.CloudStorageAccount blah = new AzureCommon.Microsoft.WindowsAzure.Storage.CloudStorageAccount(null, false);
Step 5 – celebrate you’ve avoided this hiccup 🙂
Bot Framework v4.3 has introduced a series of ‘On’ activity handlers to make you code more modular and easier to understand. Once you updated your project reference to use 4.3 you need to change you main bot to use the new activity handler class;
public class MayBotBot : IBot To public class MayBotBot : ActivityHandler
You’ll then be able to use override to discover the options, e.g.
protected virtual Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { return Task.CompletedTask; }
The other nice new feature that might slide under the radar is when the framework looks for a dialog Id it will now search up the stack to look for one. I.e. you could, if you wanted to, AddDialog all your possible dialogs in the root dialog and remove all AddDialog from everywhere else. Don’t do that, but in theory you could. The advantage here is that you can declare your common dialogs once and not have to keep adding them everywhere else.
Enjoy the chocolatey goodness of 4.3.
When you upgrade your bot from .net core 2.0/2.1 to 2.2 you may see an warning that states; ‘A PackageReference to ‘Microsoft.AspNetCore.All’ specified a Version of 2.2.1
. Specifying the version of this package is not recommended’.
To avoid this warning;
LUIS Containers is a really interesting (preview) feature. One of the issues with LUIS, and machine learning in general, is that each endpoint learns differently. E.g. if you create two LUIS endpoints, JANET and JOHN, and import the exact same JSON model then Janet and John will likely give you different scores for exactly the same utterance. Whilst that is just something you need to appreciate it, it does make a lot of workflow scenarios very difficult, E.g. testing. One potential solution to this is to export the LUIS model as a Container. In my initial tests this seems to clone the server, i.e. you get JANET2 rather than daughter of JANET – you get the same scores for the same utterance. Here is my add-on help to the documentation.
The main documentation is currently located at Install and run LUIS docker containers. If you don’t want to follow my guide then my advice is to read that but before you do anything read the next document along as that has a better explanation of the settings Configure Language Understanding Docker containers
I’m assuming you’ll be using the Command prompt and not a Bash terminal (as used in the official guide).
docker pull mcr.microsoft.com/azure-cognitive-services/luis:latest
docker run --rm -it -p 5000:5000 --memory 4g --cpus 2 --mount type=bind,src=c:\luis\input,target=/input --mount type=bind,src=c:\luis\output,target=/output mcr.microsoft.com/azure-cognitive-services/luis Eula=Accept Billing=https://YOUR_REGION.api.cognitive.microsoft.com/luis/v2.0 ApiKey=YOUR_API_KEY
Where the Billing endpoint can be take from the first part of the Endpoint address in LUIS ‘Keys and Endpoint settings’ and the ApiKey is only the set of digits from the key of the same page. E.g. 3q919c439w2445f217b3w262622331c1
NB, when you finish with this and try it again at a later date you may get errors when restarting your container, step (6). It may say something like, Error starting userland proxy. This appears to be a problem with Docker on Windows 10. You need to reopen the Docker desktop from the Taskbar and select Restart. This can take a little time but keep hovering over the icon and it will show you when it’s running again. Then you can re-issue step (6) and everything should be fine again.
One last note is that you need to stay online when using the Container. You can temporarily go offline but any prolonged absence and the LUIS Container will take itself offline with failed to reach metering endpoint, resource temporarily unavailable. Shame, that scuppers offline use. Oh well, can’t have everything you want 🙂
I decided that today was the day that I could no longer write a useful LUIS + Bot by only consuming the top scoring intent. So I checked the little Include all predicted intent scores switch in LUIS and ensured the ‘REST-API’ results had returned all the predictions. Yay. Changed my code to consume them to discover I was still only getting the top intent. Turns out you to do a little more work with the Bot SDKs to see the other intents;
In your code that implements the LUISDialog base class;
protected override LuisRequest ModifyLuisRequest(LuisRequest request) { request.Verbose = true; return base.ModifyLuisRequest(request); }
In the code where you create your LUIS Application and Recognizer, add the IncludeAllIntents options;
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, luis.GetEndpoint()); var recognizer = new LuisRecognizer( app, new LuisPredictionOptions { IncludeAllIntents = true });
An recent update to the Bot Framework means that you may see some obsolete messages when trying to add conversation/user state, etc. to the options object in the setup. Don’t worry, it’s easy enough to alter.
... // Create and add conversation state. var conversationState = new ConversationState(dataStore); // REMOVE THIS -> options.State.Add(conversationState); services.AddSingleton(conversationState); ...
Make sure your Waterfall Dialog is the FIRST dialog you add. I.e. the Bot Framework invokes the first dialog in the dialog set it DOES NOT favour the first Waterfall Dialog.
Introduction to the tutorial series is about writing bot applications using the Microsoft Bot Framework v4. The goal of this tutorial is to help someone who is interested in writing a Bot application that may not have much experience in software development. It will be a, “warts and all” journey to show how I would develop a bot. So I will be making mistakes and showing you how I go about resolving them. It will get you to a point where you can write your own conversational bot and provide you with some of the additional tools to help you resolve issues that you may find.
Another quick extension method to help with getting a sentiment score from a RecognizerResult;
public static double? GetSentimentScore(this RecognizerResult luisResult) { double? result = null; if (luisResult != null) { var data = luisResult.Properties["sentiment"]; var sentimentValues = data as IDictionary; var score = sentimentValues["score"] as JValue; result = (double)score.Value; } return result; }