How to change default answer when QnAmaker does not have any response to display a prompt dialog.
For example:
User1: Hello
Bot : Hello there !!
User1: Do you sell cars?
Bot : No good match found !
Instead of No good match found, the bot should propose a list of services available.
Also, anytime a match is not found, the bot should again propose a list of services available.
How can this be achieve?
QnAMakerAttribute has a defaultMessage parameter allowing you to customize the 'no match' response text: https://github.com/Microsoft/BotBuilder-CognitiveServices/blob/7866f5a1bc970bdd0be341b9ba24c74067edf57c/CSharp/Library/QnAMaker/QnAMaker/QnAMakerService/QnAMakerAttribute.cs
public class BasicQnAMakerDialog : QnAMakerDialog
{
public BasicQnAMakerDialog() : base(
new QnAMakerService(
new QnAMakerAttribute(
Utils.GetAppSetting("QnASubscriptionKey"),
Utils.GetAppSetting("QnAKnowledgebaseId"),
"**List of services: one, two three**",
0.30,
8))) {}
}
There is also a pull request waiting to be merged that will allow overriding sending the default message: https://github.com/Microsoft/BotBuilder-CognitiveServices/pull/87 Until then, it seems your only option is to duplicate the QnAMakerDialog in your own code base: QnAMakerDialog source
Because there's a few different ways to use the QnA maker alongside the botframework there's quite a few differing suggestions for the issue you have at the moment but not as many proper guidelines from Microsoft around it at this time. (At least not that I've found)
I came across this issue listed against the QnA makers git repository: found here. There are a few different suggestions, so I'll list them below from least to most effort.
Option 1: [Assumes you're creating a base dialog class that connects to the QnA maker]
public BasicQnAMakerDialog() : base(new QnAMakerService(new QnAMakerAttribute(ConfigurationManager.AppSettings["QnASubscriptionKey"], ConfigurationManager.AppSettings["QnAKnowledgebaseId"], "No good match in FAQ")))
Option 2: [Simply look out for the specific string that's returned by default and 'override' it]
protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result)
{
var answer = result.Answers.First().Answer;
Activity reply = ((Activity)context.Activity).CreateReply();
if (reply.Text.equals("Not Match Found!))
reply.Text = "No good match in FAQ";
await context.PostAsync(reply);
}
There were instances back when QnAMaker was still in it's preview that option 1 wouldn't work as expected. Option 2 is not as neat in my opinion but it's a decent work around.
As Eric has said in his answer, there is an active pull request awaiting a merge against this issue in their git repo. So eventually this will be an easier thing to deal with. Until then hopefully the above two options will help.
Related
I've searched everywhere and nowhere does it mention where this key is defined, or similar ones such as HTTP_X_FORWARDED_FOR, REMOTE_ADDR etc.
MSDN documentation doesn't mention anything useful. The only thing close to useful I came about was some stackoverflow questions (this and this), along with this short blog post.
None of these sadly address my current question - from where does all these dictionary keys come from? Where is their specification, so that one knows they exist and learn to utilize them, by seeing the contents they hold?
EDIT: I'm using .NET Framework 4.6.0, where System.Net.Http's version is 4.0.0.0.
To get the client IP, I'm doing the following:
public string GetSomeIp(HttpRequestMessage request)
{
HttpContextWrapper context =
request.Properties["MS_HttpContext"] as HttpContextWrapper;
return (context == null) ?
string.Empty : (context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
?? context.Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim();
}
I'd like to find the documentation, which explains what MS_HttpContext does/holds in detail, as well as REMOTE_ADDR, HTTP_X_FORWADED_FOR, and where they are defined, so I can see all the other keys and more in detail of their implementation/proper usage.
I'm aware of the following server variables, but the keys used here are not mentioned there. (except REMOTE_ADDR)
I'd like to find the documentation, which explains what MS_HttpContext does/holds in detail
The System.Web.Http.* assemblies seem not described on the https://referencesource.microsoft.com/.
However, all these projects are now hosted on the GitHub as Open? Source https://github.com/aspnet/AspNetWebStack.
So far, I assume that this constant/key is used within a routine that assigns the System.Web -> HttpContext to System.Web.Http -> Request.
https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Http.WebHost/HttpRequestMessageExtensions.cs#L11-L44
Another occurrences are related to CORS and Tests. You can clone this repo and search for the "MS_HttpContext" occurrences in depth in you are looking for details. However, I am not sure about its documentation.
where this key is defined, or similar ones such as HTTP_X_FORWARDED_FOR, REMOTE_ADDR etc.
from where does all these dictionary keys come from?
These request's properties (aka Server Variables) are created (almost duplicated) from the corresponding headers sent by a client here (applicable for HttpContext - ASP.NET WebForms/MVC):
https://referencesource.microsoft.com/#System.Web/HttpRequest.cs,dc76880a3cfd0009
https://referencesource.microsoft.com/#System.Web/HttpRequest.cs,639
By the way, there are no more such properties in the HttpRequest for ASP.NET Core (headers only).
If you need to grab the client IP information, use any approach from the aforementioned (yours or suggested) links.
If you need to retrieve the familiar HttpContext instance (for example, outside the ApiController, for example, DelegatingHandler/aka middleware), use any of the approaches illustrated in this (already mentioned as well).
If you need to retrieve it inside the ApiController, it may be even easier (don't forget about required null ref checks and self-hosted WebAPI solutions):
public class YourApiController : ApiController {
public HttpResponseMessage YourActionName() {
var request = new HttpContextWrapper(CurrentContext).Request;
...
}
}
public class YourAuditHandler : DelegatingHandler {
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
string ipAddress = HttpContext.Current != null ? HttpContext.Current.Request.UserHostAddress : "0.0.0.0";
...
}
}
I'm testing and training a new QnA bot for my web application and I want to print out the right answer format when it encounters escape sequences. How can I implement such approach in order to have the bot recognize the escape sequences that I have added? The bot emulator adds an extra '\' at the beginning of '\n\n'
I am using Bot Framework emulator for sdvk 3 and QnA Maker website
My answer is as follows:
\n\n 1. Visit the heroes Portal website.\n\n 2. Select the create button.\n\n 3. Click “choose class” under the classes \n your heroes section.\n\n 4. Follow the instructions provided.\n If you require further assistance, please email us \n at ####$$$.com\n
using Microsoft.Bot.Builder.CognitiveServices.QnAMaker;
using System;
namespace heroes.ChatBot.Dialogs.QnA
{
[Serializable]
[QnAMaker("####", "###",
"Sorry I could not find an answer to your question", 0.5, 1, "website" )]
public class QnAHeroesDialog : QnAMakerDialog
{
}
}
1.Visit the heroes Portal website.
2.Select the create button.
3.Click “choose class” under the classes \n your heroes section.
4.Follow the instructions provided.\n
If you require further assistance,\n
please follow instruction.
What you are looking for is an override of the response provided by QnAMaker. There are some samples available in the official Github repo: https://github.com/Microsoft/BotBuilder-CognitiveServices/blob/master/CSharp/Samples/QnAMaker/QnABotWithOverrides/Dialogs/QnADialogWithOverrides.cs
In a few words, override RespondFromQnAMakerResultAsync to handle this "double \n" problem
It will look like the following:
[Serializable]
[QnAMaker("####", "###",
"Sorry I could not find an answer to your question", 0.5, 1, "website" )]
public class QnAHeroesDialog : QnAMakerDialog
{
protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults results)
{
if (results.Answers.Count > 0)
{
var foundReply = results.Answers.First().Answer;
var response = $"{foundReply.Replace("\n\n", "\n")}";
await context.PostAsync(response);
}
}
}
My code may need a quick tuning for the Replace as I don't have the exact format of your response value
I am creating a Discord bot using the Discord.NET API. I have been implementing commands and modules to my bot for a while now, and I am attempting to add a ban command to my bot. I made the command so you have to have a role named "Bot Admin". Here is the code that I am using that seems to be causing the problem:
public class Ban : ModuleBase<SocketCommandContext>
{
[Command("ban")]
[RequireBotPermission(GuildPermission.BanMembers)]
public async Task banUser([Remainder]SocketGuildUser usertobehammered, string banre)
{
var rUser = Context.User as SocketGuildUser;
var role = Context.Guild.Roles.FirstOrDefault(x => x.Name == "Bot Admin");
if (rUser.Roles.Contains(role))
{
await ReplyAsync($"User {usertobehammered.Mention} has been banned.");
await Context.Guild.AddBanAsync(usertobehammered, 0, banre);
}
else
{
await ReplyAsync(":no_entry_sign: You need the Bot Admin role to do that!");
}
}
}
I don't know why, but with this here my bot will come online when I run it like normal, but attempting to run any commands will do nothing. Deleting the class allows users to use commands again.
Anybody know what the problem is here?
EDIT: Still don't know the cause of this, but I do have another command that uses the variables "rUser" and "role" which are also used here, but I don't believe that is the problem.
Figured it out myself, it was actually really simple. I just had to swap the SocketGuildUser and the string around so it would look like this:
[Command("ban")]
[RequireBotPermission(GuildPermission.BanMembers)]
public async Task banUser(string banre, [Remainder]SocketGuildUser usertobehammered)
Rather than the original which looks like this:
[Command("ban")]
[RequireBotPermission(GuildPermission.BanMembers)]
public async Task banUser([Remainder]SocketGuildUser usertobehammered, string banre)
I think the problem was that I believe Remainder puts anything after the first word into the next argument, which would make it so a SocketGuildUser is being put into a string, which without using something like "SocketGuildUser.mention" apparently makes the bot not respond to commands. People, please don't make this silly mistake I made. :$
I'm building a bot using Microsoft Bot Framework using C#. I'm controlling my flow using Dialogs, and using quick replies as buttons, they dissapear when a new message is sent.
I also created a global command to help the user. When the user types "help" the bot will give some information about what it can do.
The problem is that if the user asks for help the quick replies will dissapear and the user might not know how to continue the dialog. I was wondering if there is any way to repeat the last sent message after the help is sent (the help is not a Dialog, the Scorable sends the message).
Thanks
Nothing stops you from keeping a record of the messages the user has sent. If you build your own UI you could do it in a common way, so pressing the up arrow for example could cycle the user through their commands.
activity.Text has the text command, just add that to a list of your own, use the bot state or whatever mechanism you want for that as you will need a storage mechanism.
There are other ways as well, don't forget that the state of each dialog is maintained so once you invoke it again it will continue from where it left off.
I ended following #Andrei Dragotoniu idea, but I'd like to provide some implementation details.
Short story
Save the last (or more if you want) sent message in some storage (you can use the conversation id to identify it). Resend it when needed.
Long story
To save the last message the simplest way I found was to create a IBotToUser implementation and add it to the IBotToUser chain.
public class StoreLastActivity : IBotToUser
{
private readonly IBotToUser inner;
public StoreLastActivity(IBotToUser inner)
{
SetField.NotNull(out this.inner, nameof(inner), inner);
}
public IMessageActivity MakeMessage()
{
return this.inner.MakeMessage();
}
public async Task PostAsync(IMessageActivity message, CancellationToken cancellationToken = default(CancellationToken))
{
// Save the message here!!!
await this.inner.PostAsync(message, cancellationToken);
}
}
In Global.asax.cs or in some Module class register the class and the new chain. Update the Conversation container.
Conversation.UpdateContainer(builder =>
{
// Registers the class the saves the last send message for each conversation.
builder
.RegisterKeyedType<StoreLastActivity, IBotToUser>()
.InstancePerLifetimeScope();
// Adds the class on the IBotToUser chain.
builder
.RegisterAdapterChain<IBotToUser>
(
typeof(AlwaysSendDirect_BotToUser),
typeof(AutoInputHint_BotToUser),
typeof(MapToChannelData_BotToUser),
typeof(StoreLastActivity),
typeof(LogBotToUser)
)
.InstancePerLifetimeScope();
}
This means that every message sent to the user will pass by StoreLastActivity.PostAsync, so you can save it anywhere and use message.Conversation.Id as an id. I saved the entire IMessageActivity as it not always just text, it may contains cards, buttons etc...
Now just retrieve the IMessageActivity and send it whenever you need.
If anyone got a simpler solution I'd like to hear it.
Thank you.
I've been given 6 bits of information to access some data from a website:
Website Json Url (eg: http://somesite.com/items/list.json)
OAuth Authorization Url (eg: http://somesite.com/oauth/authorization)
OAuth Request Url (eg: http://somesite.com/oauth/request)
OAuth Access Url (eg: http://somesite.com/oauth/access)
Client Key (eg: 12345678)
Client Secret (eg: abcdefghijklmnop)
Now, I've looked at DotNetOpenAuth and OAuth.NET libraries, and while I'm sure they are very capable of doing what I need, I just can't figure out how to use either in this way.
Could someone post some sample code of how to consume the Url (Point 1.) in either library (or any other way that may work just as well)?
Thanks!
I also just started working with OAuth a month ago and was also confused by all these libraries. One thing I realized about these libraries is that they're quite complicated (as you have found out). Another thing that makes it hard is that there wasn't a lot of example (it was worse in my case because I was trying to implement a Provider and not a Client).
Originally, I wanted to use the latest OAuth 2.0 but the only .NET library out there that implements it is DotNetOpenAuth. It's probably one of the most complete .NET OAuth library out there but it'll take too long for me to understand (due to not knowing WCF, MVC, etc). I have since downgraded to OAuth 1.0a because I found these examples for DevDefined OAuth. I don't know about you but I found it easier to learn from examples.
It looks like you only want to implement a Client so make sure to look at the Consumer examples. Try to compile the examples and ignore the Provider examples because you don't need them and it'll make you more confused. Be patient. If you're still confused, it might be a good idea to look at some of the libraries made for other languages as they might have easier to understand documentations.
OK, I know your last post was months ago, but in case you were still working on this (or for people like me who would have loved to see an answer to this question), here's some information regarding the NullReferenceException you encountered creating the OAuth request:
The null reference comes from the IServiceLocator that is used to resolve dependencies. If you don't explicitly pass one into the constructor, it uses the static property ServiceLocator.Current in the Microsoft.Practices.ServiceLocation namespace.
This is one of the many pitfalls of using static methods and global state, is you hide issues like this from the consumer of your API. So if you haven't specified a default service locator, then null is returned, resulting in the NullReferenceException.
So to fix this issue, I wired up an implementation of IServiceLocator that uses StructureMap (one of the many IoC containers available) as the container. Lastly, you will need to register instances for two interfaces: ISigningProvider and INonceProvider. Luckily, several standard implementations exist in the OAuth.Net.Components assembly, such as GuidNonceProvider and HmacSha1SigningProvider.
The resulting code looks like something like this:
var container = new Container();
container.Configure(a => a.For<INonceProvider>().Use<GuidNonceProvider>());
container.Configure(a => a.For<ISigningProvider>()
.Use<HmacSha1SigningProvider>()
.Named("signing.provider:HMAC-SHA1"));
var locator = new StructureMapAdapter(container);
ServiceLocator.SetLocatorProvider(delegate { return locator; });
I realize this isn't the final solution to your original question (I'm still working on getting it working myself), but I hope it gets you a few steps further. And if you've long abandoned this implementation altogether... well, happy coding anyway!
For OAuth 2.0:
I learned that it's easiest to just put up the authentication page in an HTML window then trap the returned access_token. You can then do that using in client-side web browser.
For example, in MonoTouch it would be:
//
// Present the authentication page to the user
//
var authUrl = "http://www.example.com/authenticate";
_borwser.LoadRequest (new NSUrlRequest (new NSUrl (authUrl)));
//
// The user logged in an we have gotten an access_token
//
void Success(string access_token) {
_web.RemoveFromSuperview();
var url = "http://www.example.com/data?access_token=" + access_token;
// FETCH the URL as needed
}
//
// Watch for the login
//
class Del : UIWebViewDelegate
{
public override void LoadingFinished (UIWebView webView)
{
try {
var url = webView.Request.Url.AbsoluteString;
var ci = url.LastIndexOf ("access_token=");
if (ci > 0) {
var code = url.Substring (ci + "access_token=".Length);
_ui.Success (code);
}
} catch (Exception error) {
Log.Error (error);
}
}
}