Skip to main content

聊天机器人项目中将状态管理数据存储到数据库中

分类:  Azure机器人 标签:  #Azure Bot Framework SDK #Azure Bot Service #机器人 发布于: 2023-08-07 23:12:13

我们之前学习过了Bot Framework SDK提供的状态管理组件,以及状态管理在Dialog中的应用,如果您想了解什么是状态管理,您可以参考文章:https://www.azuredeveloper.cn/article-how-to-manage-chat-bot-status-base-azure-bot-framework,  从文章中可以看到,SDK默认情况下仅仅提供了两种外部存储支持:

  • 存放在内存中:MemoryStorage是我们的类。
  • 存放在Azure Storage中,这又要求我们必须有Azure Storage的账户。

有没有办法将这些状态数据存储到本地的存储机制上呢?例如关系型数据库?

要解决这个问题,要么自己实现IStore要么可以使用现成的由开源社区开发的库:https://github.com/BotBuilderCommunity/botbuilder-community-dotnet/tree/develop/libraries/Bot.Builder.Community.Storage.EntityFramework, 这个库利用EF Core来将状态保存在SQL Server里,但是很不幸,这个库已经没有人维护了,已经无法在高于.Net 6的项目上使用了,为了解决这个问题,我将这个库fork了一次,并且修复了它的问题,您可以从这里找到这个库:

你可以将这个库clone到您的本地,然后在项目中引用这个project, 然后开始使用就好了。

使用方法

最重要的是先从我的forkclone代码到你本地,然后在自己的项目中添加引用。

然后启动你的数据库,使用文档:https://github.com/hylinux/botbuilder-community-dotnet/tree/develop/libraries/Bot.Builder.Community.Storage.EntityFramework 创建库和表。

之后可以根据文档:https://www.azuredeveloper.cn/article/create-full-function-chat-bot-template, 创建一个项目模板,最后打开Program.cs, 使用如下的方式引用:

var ConnectString = builder.Configuration["StoreConnectionString"];

var storage = new EntityFrameworkStorage(ConnectString);
var TranscriptStorageLogger = new EntityFrameworkTranscriptStore(ConnectString);

builder.Services.AddSingleton<IStorage>(storage);
builder.Services.AddSingleton<UserState>(new UserState(storage));
builder.Services.AddSingleton<ConversationState>(new ConversationState(storage));
builder.Services.AddSingleton<ITranscriptStore>(TranscriptStorageLogger);

变量定义:

 "StoreConnectionString": "Server=ServerName\\DBInstanceName;Database=botdb;User Id=sa;Password=password1;Trusted_Connection=True;",

如果要使用Transcript自动存储,还需要更改Adapter类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Microsoft.Bot.Builder.Adapters.WeChat
{
    public class WeChatAdapterWithErrorAndTranscriptLoggerHandler : WeChatHttpAdapter
    {
        public WeChatAdapterWithErrorAndTranscriptLoggerHandler(
            ITranscriptStore transcriptLogger,
            WeChatSettings settings,
            IStorage storage,
            IBackgroundTaskQueue taskQueue,
            ILogger<WeChatAdapterWithErrorAndTranscriptLoggerHandler> logger,
            ConversationState conversationState,
            UserState userState,
            WeChatClient chatClient)
            : base(settings, storage, taskQueue, logger, chatClient)
        {
            Use(new TranscriptLoggerMiddleware(transcriptLogger));

            OnTurnError = async (turnContext, exception) =>
            {
                // Log any leaked exception from the application.
                logger.LogError($"Exception caught : {exception.Message}");

                // Send a catch-all apology to the user.
                await turnContext.SendActivityAsync("Sorry, it looks like something went wrong.");

                if (conversationState != null)
                {
                    try
                    {
                        // Delete the conversationState for the current conversation to prevent the
                        // bot from getting stuck in a error-loop caused by being in a bad state.
                        // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
                        await conversationState.DeleteAsync(turnContext);
                    }
                    catch (Exception e)
                    {
                        logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}");
                    }
                }
            };

            Use(new AutoSaveStateMiddleware(conversationState, userState));
        }
    }
}

以上是一个Adapter类,其中最重要的是两句:

  • Use(new TranscriptLoggerMiddleware(transcriptLogger)); 使用Transcript自动保存的中间件.
  • Use(new AutoSaveStateMiddleware(conversationState, userState));, 使用自动保存状态的中间件。

到这里你就可以将状态存储到外部的各种关系型数据库了。