How to receive an image send by users?

2020-08-04 04:56发布

问题:

I am programming a chatbot and I want the user to upload an image so that the bot can receive it and save the image into the User profil data. But I am quite new in c# and I am a bit lost...

I am using the MS Bot Framework. To build the dialog, I use Waterfall Step and to catch the user reply, I use Prompt. To receive attachment I saw on MS documents that it exists an AttachmentPrompt class. But I am a bit confused on how to use it and how I can save the file in the user profil.

This is how I build the waterfall dialog :

public class MainDialog : ComponentDialog
{
    // Prompts names
    private const string PhotoPrompt = "PhotoPrompt";

    // Dialog IDs
    private const string ProfileDialog = "profileDialog";


    public MainDialog(IStatePropertyAccessor<IncidentFile> IncidentFileStateAccessor, ILoggerFactory loggerFactory)
        : base(nameof(MainDialog))
    {
        IncidentFileAccessor = IncidentFileStateAccessor ?? throw new ArgumentNullException(nameof(IncidentFileStateAccessor));

        // Add control flow dialogs
        var waterfallSteps = new WaterfallStep[]
        {
                InitializeStateStepAsync,
                PromptForPhotoStepAsync,
                DisplayGreetingStateStepAsync,
        };
        AddDialog(new WaterfallDialog(ProfileDialog, waterfallSteps));
        AddDialog(new AttachmentPrompt(PhotoPrompt));

    }

Then, here is the function that catch the Prompt:

private async Task<DialogTurnResult> PromptForPhotoStepAsync(WaterfallStepContext stepContext,CancellationToken cancellationToken)
    {
        var IncidentState = await IncidentFileAccessor.GetAsync(stepContext.Context);
        if (string.IsNullOrWhiteSpace(IncidentState.Photo))
        {
            // prompt for Photo, if missing in User profil
            var opts = new PromptOptions
            {
                Prompt = new Activity
                {
                    Type = ActivityTypes.Message,
                    Text = "Can you send me a photo please?",
                },
            };
            return await stepContext.PromptAsync(PhotoPrompt, opts);
        }
        else
        {
            return await stepContext.NextAsync();
        }

    }

And this is how I save the user data :

public class IncidentFile
{
    public string Name { get; set; }
    public string Photo { get; set; }

}

I don't know if I use correctly the AttachmentPrompt class. I also don't know how the Attachment prompt is sending the image to the bot, so in the IncidentFile, I put "public string" for the Photo, but I don't know if it should be a byte array, or the path of the image location or else. But anyway, after I test it and i upload a photo, the bot reply that something went wrong...

Thank you for your time!

回答1:

You're so close! Once the user uploads the photo, you can access it in the next Waterfall step with stepContext.Result:

As you can see, the type is Microsoft.Bot.Schema.Attachment, so change your IncidentFile to:

using Microsoft.Bot.Schema;

namespace <your-namespace>
{
    public class IncidentFile
    {
        public string Name { get; set; }
        public Attachment Photo { get; set; }
    }
}

You save that information in the step following the upload step with something like:

// Load the IncidentFile
var incidentFile = await IncidentFileAccessor.GetAsync(stepContext.Context);
// Save the photo
incidentFile.Photo = ((List<Attachment>)stepContext.Result)[0];
await IncidentFileAccessor.SetAsync(stepContext.Context, incidentFile);

Result:

References

  • C# Samples. I'd link to specific ones, but we're about to delete some and reorganize this repo. However, look at:
    • Basic Bot (soon to be Core Bot) - Good for figuring out how to use user profiles
    • Handling Attachments - General Attachment handling
  • Attachment Class
  • AttachmentPrompt Class