【问题标题】:Save conversation history from MS bot to cosmos db将对话历史从 MS bot 保存到 cosmos db
【发布时间】:2019-12-31 02:24:31
【问题描述】:

我正在开发的机器人替代了希望与公司联系的潜在客户的联系表格,因此必须将用户输入保存在数据库中。我已成功将 Cosmos DB 连接到我的机器人,该机器人在使用机器人时收集状态数据。我有一个对话框堆栈,每个用户输入一个对话框(姓名、电子邮件和用户想要留下的消息)。

我找不到任何有关如何保存用 C# 编写的机器人的对话历史记录的有用文档。谁能帮我吗?我还是 Bot Framework 和 C# 的初学者。

这是我的 global.asax 文件:

 public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
        var key = ConfigurationManager.AppSettings["DocumentDbKey"];
        var store = new DocumentDbBotDataStore(uri, key);

        Conversation.UpdateContainer(
                    builder =>
                    {
                        builder.Register(c => store)
                            .Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
                            .AsSelf()
                            .SingleInstance();

                        builder.Register(c => new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency))
                            .As<IBotDataStore<BotData>>()
                            .AsSelf()
                            .InstancePerLifetimeScope();

                    });

    }
}

这是我用来收集用户名的NameDialog:(其他对话框几乎与此相同)

[Serializable]
public class NameDialog : IDialog<string>
{
    private int attempts = 3;

    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("What's your name?");

        context.Wait(this.MessageReceivedAsync);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var message = await result;


        if ((message.Text != null) && (message.Text.Trim().Length > 0))
        {

            context.Done(message.Text);
        }

        else
        {
            --attempts;
            if (attempts > 0)
            {
                await context.PostAsync("I couldn't understand, can you try again?");

                context.Wait(this.MessageReceivedAsync);
            }
            else
            {

                context.Fail(new TooManyAttemptsException("This is not a valid input"));
            }
        }
    }
}

【问题讨论】:

  • 为了澄清,您是要保存整个对话历史记录,还是只保存用户数据(姓名、电子邮件、消息)?
  • 另外,您在 SDK 的 V3 而非 V4 中构建机器人是否有原因?

标签: c# .net botframework azure-cosmosdb


【解决方案1】:

我提交了几个 cmets 要求澄清您在寻找什么,但我想我不妨提供一个包罗万象的答案。

使用 V4

如果您的机器人是新的,只需使用 BotBuilder/BotFramework 的 V4。它更容易,功能更多,支持更好。无论如何,我会为两者提供答案。

在 V4 中保存自定义数据

参考资料:

对于您指定用户 ID 的自定义存储:

// Create Cosmos Storage
private static readonly CosmosDbStorage _myStorage = new CosmosDbStorage(new CosmosDbStorageOptions
{
   AuthKey = CosmosDBKey,
   CollectionId = CosmosDBCollectionName,
   CosmosDBEndpoint = new Uri(CosmosServiceEndpoint),
   DatabaseId = CosmosDBDatabaseName,
});

// Write
var userData = new { Name = "xyz", Email = "xyz@email.com", Message = "my message" };
var changes = Dictionary<string, object>();
{
    changes.Add("UserId", userData);
};
await _myStorage.WriteAsync(changes, cancellationToken);

// Read
var userDataFromStorage = await _myStorage.read(["UserId"]);

对于机器人处理 Id 的用户数据:

See Basic Bot Sample

关键部分:

Define the Greeting State

public class GreetingState
{
    public string Name { get; set; }

    public string City { get; set; }
}

Instantiate a State Accessor

private readonly IStatePropertyAccessor<GreetingState> _greetingStateAccessor;
[...]
_greetingStateAccessor = _userState.CreateProperty<GreetingState>(nameof(GreetingState));
[...]
Dialogs.Add(new GreetingDialog(_greetingStateAccessor));

Save UserState at the end of OnTurnAsync:

await _userState.SaveChangesAsync(turnContext);

Greeting Dialog to Get and Set User Data

var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);
[...]
greetingState.Name = char.ToUpper(lowerCaseName[0]) + lowerCaseName.Substring(1);
await UserProfileAccessor.SetAsync(stepContext.Context, greetingState);

在 V4 中保存完整的对话历史

参考资料:

只需阅读文档并查看此文档的示例。复制/粘贴的代码太多。

在 V3 中保存自定义数据

参考资料:

我将从this good answer to a similar question on StackOverflow复制/粘贴代码,以供后代使用:

public class WebChatController : Controller
{
    public ActionResult Index()
    {
        var connectionString = ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString;
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

        CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

        CloudTable table = tableClient.GetTableReference("BotStore");
        string userId = Guid.NewGuid().ToString();
        TableQuery<BotDataRow> query = new TableQuery<BotDataRow>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, userId));

        var dataRow = table.ExecuteQuery(query).FirstOrDefault();
        if(dataRow != null)
        {
            dataRow.Data = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                UserName = "This user's name",
                Email = "whatever@email.com",
                GraphAccessToken = "token",
                TokenExpiryTime = DateTime.Now.AddHours(1)
            });
            dataRow.Timestamp = DateTimeOffset.UtcNow;
            table.Execute(TableOperation.Replace(dataRow));
        }
        else
        {
            var row = new BotDataRow(userId, "userData");
            row.Data = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                UserName = "This user's name",
                Email = "whatever@email.com",
                GraphAccessToken = "token",
                TokenExpiryTime = DateTime.Now.AddHours(1)
            });
            row.Timestamp = DateTimeOffset.UtcNow;
            table.Execute(TableOperation.Insert(row));
        }

        var vm = new WebChatModel();
        vm.UserId = userId;
        return View(vm);
    }

    public class BotDataRow : TableEntity
    {
        public BotDataRow(string partitionKey, string rowKey)
        {
            this.PartitionKey = partitionKey;
            this.RowKey = rowKey;
        }

        public BotDataRow() { }

        public bool IsCompressed { get; set; }
        public string Data { get; set; }
    }
}

保存用户数据:

See State API Bot Sample

在 V3 中保存完整的对话历史记录

参考资料:

基本上,您希望首先使用IActivityLogger 捕获所有活动,就像上面的示例一样:

创建DebugActivityLogger

public class DebugActivityLogger : IActivityLogger
{
    public async Task LogAsync(IActivity activity)
    {
        Debug.WriteLine($"From:{activity.From.Id} - To:{activity.Recipient.Id} - Message:{activity.AsMessageActivity()?.Text}");
        // Add code to save in whatever format you'd like using "Saving Custom Data in V3" section
    }
}

将以下内容添加到Global.asax.cs

public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<DebugActivityLogger>().AsImplementedInterfaces().InstancePerDependency();
            builder.Update(Conversation.Container);

            GlobalConfiguration.Configure(WebApiConfig.Register);
        }
    }

【讨论】:

  • 您用于存储完整对话的“对话历史示例”链接不起作用。能否请您发布更新的链接?
  • @RohanRao 我们不再为此提供更新的示例,但here's the old one
猜你喜欢
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-20
  • 2017-08-27
  • 1970-01-01
  • 2015-07-26
相关资源
最近更新 更多