Blazor Server upload image and pass file stream into Azure Form Recognizer/Cognitive Services API issue

Viewed 275

Edit: Minimum reproduceable code found at the bottom of this post.

Using Blazor Server, I'm having difficulty allowing a user to upload an image (the image being a receipt/invoice) then using Azure Form Recognizer to analyse the image by passing in a FileStream.

My Code

I'll show my code here, describe the problem, then explain what I've tried. The following UploadFile code has been taken from Microsoft Docs ASP.NET Core Blazor file uploads. The code can be found above the "Upload files to a server" article section.

As well as Microsoft Docs analyze forms with an invoice model. and GitHub Azure Samples - Use a prebuilt model to analyze a document from a file stream. NOTE: I am using Azure.AI.FormRecognizer version 3.1.1..

On Index.razor:

@page "/"

@using Azure.AI.FormRecognizer
@using Azure.AI.FormRecognizer.Models
@using Azure

@inject IWebHostEnvironment _env

<InputFile OnChange="@UploadFile" type="file" />

@code {
    private static string apiKey = "APIKEY_HERE"; // form recognizer api key
    private static string endpoint = "ENDPOINT_HERE"; // form recognizer endpoint

    private static FormRecognizerClient client = new FormRecognizerClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

    private async Task UploadFile(InputFileChangeEventArgs e)
    {
        try
        {        
            var path = Path.Combine(_env.ContentRootPath, e.File.Name);

            await using FileStream fs = new(path, FileMode.Create);

            // 4_000_000 = 4MB max file size
            await e.File.OpenReadStream(4_000_000).CopyToAsync(fs);

            RecognizedFormCollection invoices = await client.StartRecognizeInvoices(fs)
                .WaitForCompletionAsync();

            RecognizedForm invoice = invoices.Single();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

Upon running and uploading an invoice, it **crashes inside After the API has been called, with an error message:

'Content type of the stream could not be detected. It can be manually set in the options parameter of the start operation method. (Parameter 'form')'

Following this, I created RecognizeInvoicesOptions options and set the ContentType to FormContentType.Png and passed the options in as parameter to the operation. This resulted in the application crashing at the same location:

Analyze request is either invalid or missing required parameters. Refer to the API reference and retry your request. Status: 400 (Bad Request) ErrorCode: 1002

After opening the copied image when the application crashes, it contains nothing.

Assuming that this is the issue

After narrowing this down further, the CopyToAsync(fs) method within Index.razor runs asynchronously, so by the time the API requires the stream, the uploaded image has not been 100% copied. on top of this, I cannot find a way for CopyToAsync(fs) to run synchronously without throwing an exception.

Final remarks

All the documentation for Form Recognizer on Microsoft Docs & GitHub only demonstrates how to analyse documents with a hard-coded imageUrl or imagePath. This is easy to get working as expected, however, allowing the user to upload an image is more difficult.

Thanks for reading. Please let me know where I'm going wrong and if there is an alternative approach. :)

Minimum Reproduceable Code

@page "/"

@using Azure.AI.FormRecognizer
@using Azure.AI.FormRecognizer.Models
@using Azure

@inject IWebHostEnvironment _env

<InputFile OnChange="@UploadFile" type="file" />

@code {
    private static string apiKey = "APIKEY_HERE"; // form recognizer api key
    private static string endpoint = "ENDPOINT_HERE"; // form recognizer endpoint

    private static FormRecognizerClient client = new FormRecognizerClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

    private async Task UploadFile(InputFileChangeEventArgs e)
    {
        try
        {        
            var path = Path.Combine(_env.ContentRootPath, e.File.Name);

            await using FileStream fs = new(path, FileMode.Create);

            // 4_000_000 = 4MB max file size
            await e.File.OpenReadStream(4_000_000).CopyToAsync(fs);

            RecognizedFormCollection invoices = await client.StartRecognizeInvoices(fs)
                .WaitForCompletionAsync();

            RecognizedForm invoice = invoices.Single();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
0 Answers
Related