Samit Shirsat
Samit Shirsat

Reputation: 83

Accepting attachments on a waterfall dialog and storing them locally in bot framework v4

I was trying to add a functionality to take input-attachments from the user, basically trying to merge the handling-attachments bot sample from bot framework and my custom waterfall dialog .

But how do you access iturncontext functions in the waterfall dialog? . Below is a explanation of my code.

One of my waterfall step :

private async Task<DialogTurnResult> DescStepAsync2(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{


    stepContext.Values["Title"] = (string)stepContext.Result;
    await stepContext.Context.SendActivityAsync(MessageFactory.Text("upload a image"), cancellationToken);

    var activity = stepContext.Context.Activity;
    if (activity.Attachments != null && activity.Attachments.Any())
    {

        Activity reply = (Activity)HandleIncomingAttachment(stepContext.Context.Activity);
        return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = reply }, cancellationToken);
    }
    else
    {
        var reply = MessageFactory.Text("else image condition thrown");
        //  reply.Attachments.Add(Cards.GetHeroCard().ToAttachment());
        return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = reply }, cancellationToken);
    }
}

Here is the HandleIncomingAttachment function which i borrowed from bot builder samples linked above .

private static IMessageActivity HandleIncomingAttachment(IMessageActivity activity)
{
    string replyText = string.Empty;
    foreach (var file in activity.Attachments)
    {
        // Determine where the file is hosted.
        var remoteFileUrl = file.ContentUrl;

        // Save the attachment to the system temp directory.
        var localFileName = Path.Combine(Path.GetTempPath(), file.Name);

        // Download the actual attachment
        using (var webClient = new WebClient())
        {
            webClient.DownloadFile(remoteFileUrl, localFileName);
        }

        replyText += $"Attachment \"{file.Name}\"" +
                     $" has been received and saved to \"{localFileName}\"\r\n";
    }

    return MessageFactory.Text(replyText);
}

Here is the transcript of the conversation: Transcript bot framework

EDIT: i have edited my code to this , it still doesnt wait for me to upload a attachment .just finishes the step .

private async Task<DialogTurnResult> DescStepAsync2(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    stepContext.Values["Desc"] = (string)stepContext.Result;
    var reply = (Activity)ProcessInput(stepContext.Context);
    return await stepContext.PromptAsync(nameof(AttachmentPrompt), new PromptOptions { Prompt = reply }, cancellationToken);
}

process input function :

private static IMessageActivity ProcessInput(ITurnContext turnContext)
{
    var activity = turnContext.Activity;
    IMessageActivity reply = null;

    if (activity.Attachments != null && activity.Attachments.Any())
    {
        // We know the user is sending an attachment as there is at least one item .
        // in the Attachments list.
        reply = HandleIncomingAttachment(activity);
    }
    else
    {
        reply = MessageFactory.Text("No attachement detected ");
        // Send at attachment to the user.              
    }
    return reply;
}

Upvotes: 2

Views: 2195

Answers (2)

Samit Shirsat
Samit Shirsat

Reputation: 83

so i figured this out , thanks to this post: github.com/microsoft/botframework-sdk/issues/5312

how my code looks now :

declaring a attachment prompt:

 public class CancelDialog : ComponentDialog
{

    private static string attachmentPromptId = $"{nameof(CancelDialog)}_attachmentPrompt";
    public CancelDialog()
        : base(nameof(CancelDialog))
    {

        // This array defines how the Waterfall will execute.
        var waterfallSteps = new WaterfallStep[]
        {
            TitleStepAsync,
            DescStepAsync,
          //  AskForAttachmentStepAsync,
            UploadAttachmentAsync,
            UploadCodeAsync,
            SummaryStepAsync,

        };

        // Add named dialogs to the DialogSet. These names are saved in the dialog state.
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
        AddDialog(new TextPrompt(nameof(TextPrompt)));
        AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
        AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
        AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
        AddDialog(new AttachmentPrompt(attachmentPromptId));

ask for attachment prompt in the waterfall :

private async Task<DialogTurnResult> UploadAttachmentAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {

        stepContext.Values["desc"] = (string)stepContext.Result;
     //   if ((bool)stepContext.Result)
        {
            return await stepContext.PromptAsync(
        attachmentPromptId,
        new PromptOptions
        {
            Prompt = MessageFactory.Text($"Can you upload a file?"),
        });
        }
        //else
        //{
        //    return await stepContext.NextAsync(-1, cancellationToken);
        //}

    }

processing the file and storing it :

private async Task<DialogTurnResult> UploadCodeAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        List<Attachment> attachments = (List<Attachment>)stepContext.Result;
        string replyText = string.Empty;
        foreach (var file in attachments)
        {
            // Determine where the file is hosted.
            var remoteFileUrl = file.ContentUrl;

            // Save the attachment to the system temp directory.
            var localFileName = Path.Combine(Path.GetTempPath(), file.Name);

            // Download the actual attachment
            using (var webClient = new WebClient())
            {
                webClient.DownloadFile(remoteFileUrl, localFileName);
            }

            replyText += $"Attachment \"{file.Name}\"" +
                         $" has been received and saved to \"{localFileName}\"\r\n";
        }}

hope you get a idea . thank you @Kyle and @Michael

Upvotes: 2

Kyle Delaney
Kyle Delaney

Reputation: 12264

A WaterfallStepContext inherits from DialogContext and therefore the ITurnContext can be accessed through its Context property. The waterfall step code you posted already does this when it uses stepContext.Context.SendActivityAsync or stepContext.Context.Activity.

Upvotes: 1

Related Questions