如何在嵌套对话框中处理状态并配置cosmos db存储? (bot framewrok v4) [英] How to handle state and configure cosmos db storage in a nested dialog? (bot framewrok v4)
问题描述
我正在尝试使用嵌套对话框构建聊天机器人,该对话框应该从用户那里收集信息并将其存储在Azure CosmosDB中.在我实现Cosmos DB存储之前,该对话框运行良好.现在,使用CosmosDB存储,对话框将在第一个对话框中的第一个任务上循环,而不是继续.我该如何解决这个问题?
I am trying to build a chatbot with nested dialogs which is supposed to gather information from the user and store it in Azure CosmosDB. The dialog worked fine until I implemented the Cosmos DB storage. Now, with the CosmosDB storage the dialog loops on the first task in the first dialog, instead of continuing. How can I solve this problem?
从对话框开始,以及在实现CosmosDB存储之前的状态.我基本上遵循此样本 43中的代码.复杂对话框.
Beginning with the dialogs, and how it was before implementing CosmosDB storage. I basically followed the code in this sample 43.complex-dialog.
然后,实现我使用的存储此答案作为指导.我在Startup.cs中设置了cosmosDB存储,如下所示:
Then, implementing the storage I used this answer as a guide. I set up the cosmosDB storage in Startup.cs like this:
public class Startup
{
private const string CosmosServiceEndpoint = "MyCosmosServiceEndpoint";
private const string CosmosDBKey = "MyCosmosDBKey";
private const string CosmosDBDatabaseName = "MyCosmosDBDatabaseName";
private const string CosmosDBCollectionName = "MyCosmosDBCollectionName";
private const string CosmosDBPartitionKey = "MyCosmosDBPartitionKey";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var storage = new CosmosDbStorage(new CosmosDbStorageOptions
{
AuthKey = CosmosDBKey,
CollectionId = CosmosDBCollectionName,
CosmosDBEndpoint = new Uri(CosmosServiceEndpoint),
DatabaseId = CosmosDBDatabaseName,
PartitionKey = CosmosDBPartitionKey
});
var conversationState = new ConversationState(storage);
var userState = new UserState(storage);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddSingleton<MainDialog>();
services.AddTransient<IBot, WelcomeBot<MainDialog>>();
services.AddSingleton<IStorage, MemoryStorage>();
services.AddSingleton(userState);
services.AddSingleton(conversationState);
services.AddSingleton(userState.CreateProperty<UserProfile>("MyUserState"));
services.AddSingleton(conversationState.CreateProperty<DialogState>("MyBotDialogState"));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
}
}
}
我的主要bot看起来像这样(不要在意"Echobot"的名字):
My main bot looks like this (don't mind the name "Echobot"):
public class EchoBot<T> : ActivityHandler where T : Dialog
{
private readonly BotState _userState;
private readonly BotState _conversationState;
private readonly Dialog _dialog;
private readonly ILogger _logger;
private readonly IStatePropertyAccessor<UserProfile> _userStateAccessor;
private readonly IStatePropertyAccessor<DialogState> _conversationDialogStateAccessor;
// Create cancellation token (used by Async Write operation).
public CancellationToken CancellationToken { get; private set; }
public EchoBot(ConversationState conversationState, UserState userState, T dialog, ILogger<EchoBot<T>> logger, IStatePropertyAccessor<UserProfile> userStatePropertyAccessor, IStatePropertyAccessor<DialogState> dialogStatePropertyAccessor)
{
_conversationState = conversationState;
_userState = userState;
_dialog = dialog;
_logger = logger;
_userStateAccessor = userStatePropertyAccessor;
_conversationDialogStateAccessor = dialogStatePropertyAccessor;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
await base.OnTurnAsync(turnContext, cancellationToken);
var currentUserState = await _userStateAccessor.GetAsync(turnContext, () => new UserProfile(), cancellationToken);
var currentConversationDialogState = await _conversationDialogStateAccessor.GetAsync(turnContext, () => new DialogState(), cancellationToken);
await _userStateAccessor.SetAsync(turnContext, currentUserState, cancellationToken);
await _conversationDialogStateAccessor.SetAsync(turnContext, currentConversationDialogState, cancellationToken);
// Save any state changes that might have occured during the turn.
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken=default)
{
_logger.LogInformation("Running dialog with Message Activity.");
//See DialogExtension.cs in the sample "complex-dialog" to see the Run method.
await _dialog.Run(turnContext, _conversationDialogStateAccessor, cancellationToken);
}
}
}
推荐答案
现在,如果您从CosmosDbStorageOptions
中删除PartitionKey
参数,它应该可以工作.由于您的容器当前已分区,因此您可能需要删除您的容器或使用其他名称.最简单的方法就是删除您的容器,然后让机器人为您创建一个容器.
For now, it should work if you remove the PartitionKey
parameter from CosmosDbStorageOptions
. You will likely need to delete your Container or use a different name, since yours is currently partitioned. Easiest to just delete your Container and let the bot make one for you.
提供了partitionKey时,所有Bot Builder SDK当前都存在一个读取分区数据库中的错误. 在此处跟踪问题
There's currently a bug in all the Bot Builder SDKs around reading from partitioned databases when the partitionKey is supplied. Tracking the issue here
这篇关于如何在嵌套对话框中处理状态并配置cosmos db存储? (bot framewrok v4)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!