我试图在我的机器人中创建一个表单,用户必须上传文件和其他文本输入。为此,我制作了一个ReceiveAttachmentDialog,在其中验证用户是否上传了文件,问题是我无法确定如何检测用户何时上传文件并因此在ReceiveAttachmentDialo中午餐。
forDialog是这样的:
[Serializable]
public class FraisDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
// Root dialog initiates and waits for the next message from the user.
// When a message arrives, call MessageReceivedAsync.
var replyMessage = context.MakeMessage();
replyMessage.Attachments = new List<Connector.Attachment> { CreateAdaptiveCardwithEntry() };
await context.PostAsync("Veuillez compléter le formulaire ci-dessous");
await context.PostAsync(replyMessage, CancellationToken.None);
context.Wait(this.MessageReceivedAsync);
}
public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
context.Wait(MessageReceivedAsync);
var message = await result;
if (message.Value != null)
{
// Got an Action Submit
dynamic value = message.Value;
string submitType = value.Type.ToString();
switch (submitType)
{
case "SaveFunction":
if (value.titre == "")
{
await context.PostAsync("Veuillez compléter tous les paramètres du formulaire \n");
}
else
{
await context.PostAsync($"Vous avez saisie les paramètres suivants : \n titre : {value.titre} \n date : {value.date} \n montant : {value.montant}");
context.Done<string>(null);
}
return;
}
}
}
public Connector.Attachment CreateAdaptiveCardwithEntry()
{
var submitActionData = JObject.Parse("{ \"Type\": \"SaveFunction\" }");
var card = new AdaptiveCard()
{
Body = new List<CardElement>()
{
// Hotels Search form
new TextBlock() { Text = "Titre de la note des frais" },
new TextInput()
{
Id = "titre",
Speak = "<s>Veuillez saisir le titre</s>",
Placeholder = "Veuillez saisir le titre",
Style = TextInputStyle.Text
},
new TextBlock() { Text = "Date de la note des frais" },
new DateInput()
{
Id = "date",
Placeholder ="Veuillez saisir la Date de la note des frais"
},
new TextBlock() { Text = "Montant en euros de la note de frais" },
new NumberInput()
{
Id = "montant",
Speak = "<s>Veuillez saisir le Montant en euros de la note de frais</s>",
Placeholder = "Veuillez saisir le Montant de la note de frais",
},
},
Actions = new List<ActionBase>()
{
new SubmitAction()
{
Title = "Envoyer",
Speak = "<s>Envoyer</s>",
DataJson = submitActionData.ToString()
}
}
};
Connector.Attachment attachment = new Connector.Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = card
};
return attachment;
}
}
我的问题是我如何检测用户上传文件的时间?我应该把await context.Forward(new ReceiveAttachmentDialog(), this.ResumeAfterRecieveDialog, context.Activity, CancellationToken.None);
答案 0 :(得分:3)
如果您尚未使用FormFlow,我建议您使用FormFlow,并查看位于here和ImagesForm.cs
的示例,以查看表单本身。
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using Microsoft.Bot.Builder.FormFlow.Advanced;
using Microsoft.Bot.Connector;
namespace Microsoft.Bot.Sample.FormFlowAttachmentsBot
{
[Serializable]
public class MyAwaitableImage : AwaitableAttachment
{
// Mandatory: you should have this ctor as it is used by the recognizer
public MyAwaitableImage(Attachment source) : base(source) { }
// Mandatory: you should have this serialization ctor as well & call base
protected MyAwaitableImage(SerializationInfo info, StreamingContext context) : base(info, context) { }
// Optional: here you can check for content-type for ex 'image/png' or other..
public override async Task<ValidateResult> ValidateAsync<T>(IField<T> field, T state)
{
var result = await base.ValidateAsync(field, state);
if (result.IsValid)
{
var isValidForMe = this.Attachment.ContentType.ToLowerInvariant().Contains("image/png");
if (!isValidForMe)
{
result.IsValid = false;
result.Feedback = $"Hey, dude! Provide a proper 'image/png' attachment, not any file on your computer like '{this.Attachment.Name}'!";
}
}
return result;
}
// Optional: here you can provide additional or override custom help text completely..
public override string ProvideHelp<T>(IField<T> field)
{
var help = base.ProvideHelp(field);
help += $"{Environment.NewLine}- Only 'image/png' can be attached to this field.";
return help;
}
// Optional: here you can define your custom logic to get the attachment data or add custom logic to check it, etc..
protected override async Task<Stream> ResolveFromSourceAsync(Attachment source)
{
var result = await base.ResolveFromSourceAsync(source);
// You can apply custom logic to result or avoid calling base and resolve it yourself
// For ex. if you plan to use your instance several times you can return a MemoryStream instead
return result;
}
}
[Serializable]
public class ImagesForm
{
// Attachment field has no validation - any attachment would work
public AwaitableAttachment BestImage;
// Attachment field is optional - validation is done through AttachmentContentTypeValidator usage
[Optional]
[AttachmentContentTypeValidator(ContentType = "png")]
public AwaitableAttachment SecondaryImage;
// You can use an AwaitableAttachment descendant in order to have your own custom logic
public IEnumerable<MyAwaitableImage> CustomImages;
public static IForm<ImagesForm> BuildForm()
{
OnCompletionAsyncDelegate<ImagesForm> onFormCompleted = async (context, state) =>
{
await context.PostAsync("Here is a summary of the data you submitted:");
var bestImageSize = await RetrieveAttachmentSizeAsync(state.BestImage);
await context.PostAsync($"Your best image is '{state.BestImage.Attachment.Name}' - Type: {state.BestImage.Attachment.ContentType} - Size: {bestImageSize} bytes");
if (state.SecondaryImage != null)
{
var secondaryImageSize = await RetrieveAttachmentSizeAsync(state.SecondaryImage);
await context.PostAsync($"Your secondary image is '{state.SecondaryImage.Attachment.Name}' - Type: {state.SecondaryImage.Attachment.ContentType} - Size: {secondaryImageSize} bytes");
}
else
{
await context.PostAsync($"You didn't submit a secondary image");
}
var customImagesTextInfo = string.Empty;
foreach (var image in state.CustomImages)
{
var imgSize = await RetrieveAttachmentSizeAsync(image);
customImagesTextInfo += $"{Environment.NewLine}- Name: '{image.Attachment.Name}' - Type: {image.Attachment.ContentType} - Size: {imgSize} bytes";
}
await context.PostAsync($"Here is the info of custom images you submitted: {customImagesTextInfo}");
};
// Form localization is done by setting the thread culture
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-us");
return new FormBuilder<ImagesForm>()
.Message("Welcome, please submit all required images")
.OnCompletion(onFormCompleted)
.Build();
}
private static async Task<long> RetrieveAttachmentSizeAsync(AwaitableAttachment attachment)
{
var stream = await attachment;
return stream.Length;
}
}
}
答案 1 :(得分:3)
正如@Ali Heikal所说,formflow对你来说是一个完全有效的选择。不使用表单流的另一个选项是检查从用户收到的机器人的活动是否有Attachments
。 Activity.Attachments
是IList<Attachment>
,其中包含用户上传到机器人的任何文件。因此,只需检查Activity.Attachments.Any()
就会给你一个布尔值,告诉你用户是否上传了一个文件。
以下是RootDialog.cs
内的一个简单示例:
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace Bot_Application1.Dialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
if (activity.Attachments.Any())
{
//do something with the file
//it looks like this is where you would put your
//context.Forward()
await context.Forward(new ReceiveAttachmentDialog(), this.ResumeAfterRecieveDialog, context.Activity, CancellationToken.None);
await context.PostAsync($"you sent a file");
}
else
{
await context.PostAsync($"No File received");
}
context.Wait(MessageReceivedAsync);
}
}
}