将对话历史记录从MS bot保存到cosmos db

时间:2019-03-19 12:32:44

标签: c# .net botframework azure-cosmosdb

我正在开发的漫游器替代了公司希望与之联系的潜在客户的联系表,因此用户输入必须保存在数据库中。我已成功将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"));
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我提交了几条评论,要求您对所要查找的内容进行澄清,但我想我还是可以提供一个无所不包的答案。

使用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);
        }
    }