![](/img/trans.png)
[英]Using a trigger word to store conversation data permanently in a Azure chat bot
[英]Retrieving Chat Bot conversation data in Azure
首先简要介绍一下背景:Bot 框架将对话数据存储在 Azure 表/Cosmos DB(在我的案例中为 Azure 表)的存储中。 对于每个对话,在 Azure 表中都有一个条目,其中包含时间戳、用户 ID、对话消息和其他详细信息。
我正在尝试使用 C# 中的自定义代码从 Azure 表存储中检索对话详细信息,如下所示。
Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(connectionString);
Microsoft.WindowsAzure.Storage.Table.CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("botdata");
TableQuery<DynamicTableEntity> projectionQuery = new TableQuery<DynamicTableEntity>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "directline:user"));
var dataRow = table.ExecuteQuery(projectionQuery).Where(q => q.RowKey == "souvik").FirstOrDefault();
var conversation = Encoding.UTF8.GetString(dataRow.Properties["Data"].BinaryValue);
Console.WriteLine(conversation);
当我检索时,我收到了一些乱码,类似于这样的 - \ \\b\\0\\0\\0\\0\\0\\\0 \\\0C \\\0\\0\\0
以二进制格式存储在 Azure 表存储中的数据。 数据在 Azure 存储资源管理器中如下所示 -
我对每个对话都进行了尝试和测试,我发现每次我键入并向机器人发送数据并获得响应时,都会将新记录添加到 Azure 表中,并带有正确的时间戳。 这是检索数据的正确方法还是我做错了什么? 如果我可以添加更多详细信息,请告诉我。
更新 1:
我已经提到了这个 - 如何在 Azure (Tablelogger) 中检索保存的对话数据,但对我的问题没有太大帮助。
更新 2
基于 Fei 在下面的回答,我刚刚注意到当我使用PartitionKey
作为directline:user
或directline:conversation
我得到反序列化的值作为{}
但如果我使用directline:private
我得到这样的东西 -
{"ResumptionContext":{"locale":"en-US","isTrustedServiceUrl":true}, "DialogState":"H4sIAAAAAAAEAO1a328iVRRmYGYKbTfbdZtNzLq7GM26DWS2FGi7MVUptUrcVi1VYxrSvcCFjh1mmrl3quyjb74YEx+N/hW+uzFxE/8KX9fsH6HnzAxQ7A8GhHpZoemBDs O953znO+d+99KQFAqF/oIHPuNjNgzm8y29YlvMqnFt3YJfRzeq1E7GP6U20y1zLa2llrQlLZOM5x2DOzZdM6nDbWIk4x85ZUOvfECbu9YhhTtT5Vp6NbtMqunlDE1nFZznF+nM8bWCyaltEoNpm 3oZpvKeHqX29s6+f0MnhlVnJz7nXdkl7DAZH1kMpVIEglAYJ5VDtWaTBmXKl0TnLCLLT8LFJuO0oeUtw6AVDjMx7T1qUluvaA91xs+P5lT0hU0cW8DwRzo4CYhOESAlhv6YIMaJIrdsWjAhJ2aF rjd3m0e06Ni2VSecJj4sfwGp2KE1alN4Gxl+ObPgbwzJEpPRKGBk/HPCkmFUoLqvA4ZM2Wf6YxrdP/aGBaR/DdpfhMVur4TUiUZjqs8i5I8iXwpxsUPLeEfkjs/ST0ydN7sGfN/CWV16T4GRFN /FWBTMFDodkvxL8pOxz4YbZwzNNJgrYRlj7gUOMlTeIJzE3DsQ0NkcY7RRNprbEKcUkqLqDNz0NPBqiPBskgrksikgSphsdXak6kFy6YXzXAHzW1DgPoPFWWzcYoibEutLGwlcLHKD2Icyai JZvpyV9odwH1x4tCQaask9v5t4oSXjDVaxbEMvd0bPaIv403vw8soKyVayy6kH6QxdXH3gpcTtYVfRzGFzxkbmdrRraF7CS1dbPfw6cnFuAmpvUGWbMi6blFZlOTBYO/CZ/yNYiYD4bAOcbcb OIxefw/60n0+j9Jg6JoZD9/dD0bAvRhSk+tNxp3T32HnLNCkubFphizJG6jQHu4lj0Bv/9KJ95xC7/An2B8ZVVPYLhOtAhXIDWf4nFMpz/zBHwqZ+rf3Ws5NvXW/JqJdDfeyWth3DcMtCPNHR 0VDz/axbopJxlK3Y3Zdw0FMqJ3adcrVB+YFVjcg9t3s/nUOUi3BK7B445iHg7HhiddSLzH1/AhCH/sGKtgVbLmoXzJp13hb2JppX0NxCCt3oZ50QlUKC9LPB2fb7ENgmCAgDE/M2mjto4ti2b 7ba9quTJndxK+isB1jWojcuXJNV251K/qaHr55HuRr3vhi5lG3ja1jEtwYgMZJVxsOurpOvWN4gjLmvinrdJOjWdPvV0rQ3JG755/wz8Zxdh6BNziR8hCLRK74jeNNeSX0d50GeuzlX745BztU 3wMmvI604DmxKqrpZ19AP5lrwIOjBqa/K+o+4VIojbPcCn9D6X8gNMNM5zWSQBnSGYwVAEfzqyhhMeQrePJ4nGYbLUTc1C+o9SMQz5eJE9JsJwZrtaL+LGYxCYwLRcPk50pYSiO54gj4t3W4piY WJ1h2azOuIDpRsL5B+PalPfu5PnwgSQVvKJFBHo5hGOaMmu3WD9mKlTb0P8fw4kRjDbeFBkxtQfSxCjr5XJ+pjoj4uQX0I0piCCxUFt54CbYkHP876tkcQ+QOim4mHlnXkXRH2sDSFZglNGsxsBs zax2YOYur4lQrql+kYhoJr8njKisHpcLfbryJpHBlU83DUdiyLe4FnBs1SFs0ymhVUPKmW3l8Vq546khkZJVqNoO6dzkE3rdAqNbncR9LCLfyldEtsvglmxseWNc2KpznXBIxbfQuc+k66QJTET8 RxztrbXrm8F1B5nH7Fe65zOfyvIVI26KnTnAX1bXDrj//erZFi72/Qs62CfWdsm2OntrEOAtYO3BnC+pFWWmWzDmbe93wHKlE/plU3wWr+Xy896kZwz9R33UxcxL6zvBwdDQNvRBbUTdxkhMVxXRSKesU28zeNVmRMBTMAAA=="}
感觉上面JSON中的DialogState
数据需要解密?
对于我输入的每条消息和收到的响应,Azure 表中插入了三条记录,每条记录都有不同的PartitionKey
,分别是 - directline:private
、 directline:user
和directline:conversation
。
Azure Table Storage
二进制数据存储为Base64 encoded string
。 您需要做的是先将此字符串转换为字节,然后从这些字节中获取字符串。
类似的东西:
var conversation = Encoding.UTF8.GetString(Convert.FromBase64String(dataRow.Properties["Data"].BinaryValue));
如果您想使用WindowsAzure.Storage 客户端库从表存储中检索实体并从Data
属性中提取数据,您可以参考以下代码。
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName={your_account_name};AccountKey={your_account_key};EndpointSuffix=core.windows.net");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("botdata");
TableQuery<MessageEntity> query = new TableQuery<MessageEntity>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "emulator:user"));
foreach (MessageEntity entity in table.ExecuteQuery(query))
{
string mydata = "";
using (var msi = new MemoryStream(entity.Data))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
gs.CopyTo(mso);
}
mydata = Encoding.UTF8.GetString(mso.ToArray());
}
object data = JsonConvert.DeserializeObject(mydata);
//.....
}
MessageEntity
:
public class MessageEntity : TableEntity
{
public MessageEntity(string pk, string rk)
{
this.PartitionKey = pk;
this.RowKey = rk;
}
public MessageEntity() { }
public string BotId { get; set; }
public string ChannelId { get; set; }
public string ConversationId { get; set; }
public byte[] Data { get; set; }
public string UserId { get; set; }
}
测试结果:
注意:
BotDataEntity
类中找到定义为byte[]
的Data
属性。Data
属性的序列化和反序列化的信息。我假设您正在使用 botbuilder-azure 包
不要在对话框中执行此操作,因为您只能访问context
对象中的相同数据。 它恰好是我写代码的地方
其实就这么简单:
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
IBotDataStore<BotData> table = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
//use the type of state data you need
var userData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotUserData, CancellationToken.None );
var privateConvoData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotPrivateConversationData, CancellationToken.None );
var convoData = await table.LoadAsync(Address.FromActivity(activity), BotStoreType.BotConversationData, CancellationToken.None);
//in this case I am just replying with the data, but do what you need with it here
var reply = activity.CreateReply(userData.Data.ToString());
var reply2 = activity.CreateReply(privateConvoData.Data.ToString());
var reply3 = activity.CreateReply(convoData.Data.ToString());
await context.PostAsync(reply);
await context.PostAsync(reply2);
await context.PostAsync(reply3);
context.Wait(MessageReceivedAsync);
}
如果您在botbuilder-azure的源代码中注意到有一个序列化和反序列化方法。 发生这种情况的地方:
private byte[] Serialize(object data)
{
using (var cmpStream = new MemoryStream())
using (var stream = new GZipStream(cmpStream, CompressionMode.Compress))
using (var streamWriter = new StreamWriter(stream))
{
var serializedJSon = JsonConvert.SerializeObject(data, serializationSettings);
streamWriter.Write(serializedJSon);
streamWriter.Close();
stream.Close();
return cmpStream.ToArray();
}
}
所以你需要的数据被压缩成你看到的“乱码”。 当通过LoadAsync
方法访问数据时,它也被解压缩,如下所示:
private object Deserialize(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var gz = new GZipStream(stream, CompressionMode.Decompress))
using (var streamReader = new StreamReader(gz))
{
return JsonConvert.DeserializeObject(streamReader.ReadToEnd());
}
}
在返回语句中的LoadAsync
方法内部调用反序列化return new BotData(entity.ETag, entity.GetData());
它的GetData()
方法如下所示:
internal ObjectT GetData<ObjectT>()
{
return ((JObject)Deserialize(this.Data)).ToObject<ObjectT>();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.