Сохранить историю разговоров из MS Bot в космос db - PullRequest
0 голосов
/ 19 марта 2019

Бот, который я разрабатываю, заменяет контактную форму для потенциальных клиентов, с которыми компания хочет связаться, поэтому пользовательские данные должны быть сохранены в базе данных. Я успешно подключил базу данных Cosmos к своему боту, который собирает данные о состоянии при использовании бота. У меня есть стек диалогов с одним диалогом для каждого пользовательского ввода (имя, адрес электронной почты и сообщение, которое пользователь хочет оставить).

Я не могу найти никакой полезной документации о том, как сохранить историю разговоров для ботов, написанных на 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 Ответ

1 голос
/ 19 марта 2019

Я отправил пару комментариев с просьбой дать разъяснения по поводу того, что вы ищете, но подумал, что я мог бы просто дать всеобъемлющий ответ.

Используйте V4

Если вашбот новый, просто используйте V4 BotBuilder / BotFramework.Это проще, больше возможностей и лучшая поддержка.В любом случае, я предоставлю ответы на оба вопроса.

Сохранение пользовательских данных в V4

Ссылки:

Для пользовательского хранилища, где вы указываете идентификатор пользователя:

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

Для пользовательских данных, где обрабатывает ботИдентификатор:

См. Базовый образец бота .

Ключевые части:

Определение состояния приветствия

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

    public string City { get; set; }
}

Создание экземпляра состояния доступа

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

Сохранить UserState в конце OnTurnAsync :

await _userState.SaveChangesAsync(turnContext);

Диалог приветствия для получения и установки пользовательских данных

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

Ссылки:

Я скопирую / вставлю код из это хорошоответ на аналогичный вопрос по 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; }
    }
}

Сохранение пользовательских данных:

См. Пример API-интерфейса State Bot

Сохранение полной истории разговоров в 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);
        }
    }
...