How to construct a QnA Maker Instance Class in C# - CoreBot?

断了今生、忘了曾经 提交于 2020-06-27 16:19:36

问题


I got a System.AggregateException after running my Core Bot C# sample.

In the Startup.cs I added the class as followes:

     services.AddSingleton<ChitChatRecognizer>();

The Recognizer Class looks like:

    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Bot.Builder;
    using Microsoft.Bot.Builder.AI.QnA;
    using Microsoft.Bot.Schema;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Logging;

    namespace CoreBot
    {
        public class ChitChatRecognizer : ActivityHandler
        {

            private readonly IConfiguration _configuration;
            private readonly ILogger<ChitChatRecognizer> _logger;
            private readonly IHttpClientFactory _httpClientFactory;

            public ChitChatRecognizer(IConfiguration configuration, ILogger<ChitChatRecognizer> logger, IHttpClientFactory httpClientFactory)
            {
                _configuration = configuration;
                _logger = logger;
                _httpClientFactory = httpClientFactory;
            }

            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");

                var options = new QnAMakerOptions { Top = 1 };

                // The actual call to the QnA Maker service.
                var response = await qnaMaker.GetAnswersAsync(turnContext, options);
                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);
                }
            }
        }
    }

I'm not even using the Class yet but can't even start my program without the error. What should I do?

ErrorCode:

"Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CoreBot.ChitChatRecognizer Lifetime: Singleton ImplementationType: CoreBot.ChitChatRecognizer': Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate 'CoreBot.ChitChatRecognizer'.) (Error while validating the service descriptor 'ServiceType: Microsoft.BotBuilderSamples.Dialogs.MainDialog Lifetime: Singleton ImplementationType: Microsoft.BotBuilderSamples.Dialogs.MainDialog': Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate 'CoreBot.ChitChatRecognizer'.) (Error while validating the service descriptor 'ServiceType: Microsoft.Bot.Builder.IBot Lifetime: Transient ImplementationType: Microsoft.BotBuilderSamples.Bots.DialogAndWelcomeBot`1[Microsoft.BotBuilderSamples.Dialogs.MainDialog]': Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate 'CoreBot.ChitChatRecognizer'.)"


回答1:


Your setup is odd...you're making your ChitChatRecognizer, which is a bot (it derives from ActivityHandler), and then later DI into either a dialog or another bot, I imagine? Also it seems you want to treat QnAMaker (the recognizer for QnA) as a singleton, but you initialize it in OnMessageActivityAsync--meaning it won't initialize unless your bot receives a message activity, so if you're trying to initialize something else the requires a QnAMaker, it won't exist on startup.


Anyways, to answer the question of how do you insert QnAMakerinto corebot, if you wanted to add QnAMaker as a singleton, you can add it as singleton in startup, then call it from your bot code when you need to make a call to QnAMaker.

Add QnAMaker to Corebot Sample

In Startup.ConfigureServices:

// Register QnAMaker recognizer
services.AddSingleton<MyQnaMaker>();

MyQnAMaker.cs

namespace Microsoft.BotBuilderSamples
{
    public class MyQnaMaker
    {
        public MyQnaMaker(IConfiguration configuration)
        {
            ChitChatRecognizer = new QnAMaker(new QnAMakerEndpoint
            {
                KnowledgeBaseId = configuration["QnAKnowledgebaseId"],
                EndpointKey = configuration["QnAEndpointKey"],
                Host = configuration["QnAEndpointHostName"]
            });
        }

        public QnAMaker ChitChatRecognizer { get; set; }
    }
}

DialogAndWelcomeBot.cs constructor

DI QnAMaker into the Bot

        public DialogAndWelcomeBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger, MyQnaMaker myQnAMaker)
            : base(conversationState, userState, dialog, logger, myQnAMaker)

DialogBot.cs

        public DialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger, MyQnaMaker qnaMaker)
        {
            ConversationState = conversationState;
            UserState = userState;
            Dialog = dialog;
            Logger = logger;
            MyQnaMaker = qnaMaker;
        }

...

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            Logger.LogInformation("Running dialog with Message Activity.");

            if (turnContext.Activity.Text == "yo")
            {
                await CallQnAMaker(turnContext, cancellationToken);
            } else {
                // Run the Dialog with the new message Activity.
                await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
            }

        }

        private async Task CallQnAMaker(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var options = new QnAMakerOptions { Top = 1 };

            // The actual call to the QnA Maker service.
            var response = await MyQnaMaker.ChitChatRecognizer.GetAnswersAsync(turnContext, options);
            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);
            }
        }

Add more to your classes as needed, this is just the bare minimum. Above in DialogBot.cs, you can see that I have the trigger to call QnAMaker be if the user types in "yo" as a message, for testing purposes.


Running Corebot


Alternatives

Alternatively you could just new up a new QnAMaker within the bot's message handler (like DialogBot.OnMessageActivityAsync()), similar to how is done in sample 11.qnamaker, and do away with the singleton.



来源:https://stackoverflow.com/questions/61343711/how-to-construct-a-qna-maker-instance-class-in-c-sharp-corebot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!