Ed Andersen

Software Developer and Architect in Japan

File Search in C# / .NET with Azure OpenAI Service Assistants V2 API

Ed Andersen Avatar

by

in , ,

The Azure OpenAI Service is a variant of OpenAI that runs within your Azure tenant, which makes it great for companies and use cases where data sovereignty is important. I think its great!

The most significant update is that the service is now open to everyone, and you don’t need special approval to access it. Previously, to gain access to Azure OpenAI Service, you had to fill a special form and get approval from Microsoft. This was exclusive to Microsoft’s partners. But now, anyone with an Azure subscription can access the service, which is great news.

We also finally now have access to the retrieval tool in the OpenAI Assistant API, named the “file search” tool. This tool allows the LLM to search for file information inside files, a feature that was not previously supported. Users in Azure were left with no other option but to use the slow code interpreter tool before now.

However, the file search documentation still lacks some source code examples, especially for C# and .NET. Although Python and REST calls are covered, I really wish Microsoft would include samples in C# and .NET in their docs by default.

No C# samples ๐Ÿ™

I already have a project on my GitHub where I used the old Code Interpreter tool to use the Assistant API to query for information in a file. Now that File Search is supported, it was time to take another look at it and update it!


To start, we’ll change the SDK package that is used, switching it over to version two of this top-level nuget package, Azure.AI.OpenAI, which now seems to include all of the Assistant stuff.

<ItemGroup>
  <PackageReference Include="Azure.AI.OpenAI" Version="2.0.0-beta.2" />
</ItemGroup>

Next up, load up an AzureOpenAIClient and get an AssistantClient from it. You’ll need to ignore the OPENAI001 warning at the moment.

using Azure.AI.OpenAI;
using OpenAI.Assistants;

AzureOpenAIClient azureClient = new(
            new Uri("https://your-deployment-url.openai.azure.com/"),
            new Azure.AzureKeyCredential("your azure open ai api key"));

#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

var client = azureClient.GetAssistantClient();

#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

We’ll grab the filename from the command-line arguments that we pass in.

var filename = args[0];

We’ll create an assistant that will answer questions from a user about the provided file using the file search tool. The model name here is your deployment name on Azure OpenAI service.

var assistantCreationOptions = new AssistantCreationOptions
{
    Name = "File question answerer",
    Instructions = "Answer questions from the user about the provided file.",
    Tools = { ToolDefinition.CreateFileSearch() },
};

var assistant = await client.CreateAssistantAsync("gpt4-assistant2", assistantCreationOptions);

Next, we’ll upload the file and print its name to the console.

var fileUploadResponse = await azureClient.GetFileClient().UploadFileAsync(File.Open(filename, FileMode.Open), 
System.IO.Path.GetFileName(filename), OpenAI.Files.FileUploadPurpose.Assistants);
Console.WriteLine($"Uploaded file {fileUploadResponse.Value.Filename}");

We’ll ask the user to provide a question about the file.

Console.WriteLine("Ask a question about the file (empty response to quit):");
var question = Console.ReadLine();

var thread = await client.CreateThreadAsync();

Then we’ll enter a loop in which we’ll create a message with the user’s question and an attachment to the uploaded file. We’ll start a run and print the run’s updates to the console. You’ll notice we can now using the streaming API from an Assistant context, which means we can print tokens out as they are generated, something that wasn’t previously supported.

while (!string.IsNullOrWhiteSpace(question))
{
    var messageCreationOptions = new MessageCreationOptions();
    messageCreationOptions.Attachments.Add(new MessageCreationAttachment(fileUploadResponse.Value.Id, new List<ToolDefinition>() {ToolDefinition.CreateFileSearch()}));

    await client.CreateMessageAsync(thread, new List<MessageContent>() { MessageContent.FromText(question)}, messageCreationOptions);

    await foreach (StreamingUpdate streamingUpdate
            in client.CreateRunStreamingAsync(thread, assistant, new RunCreationOptions()))
        {
            if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunCreated)
            {
                Console.WriteLine($"--- Run started! ---");
            }

            else if (streamingUpdate is MessageContentUpdate contentUpdate)
            {
                if (contentUpdate?.TextAnnotation?.InputFileId == fileUploadResponse.Value.Id)
                {
                    Console.Write(" (From: " + fileUploadResponse.Value.Filename + ")");
                } 
                else 
                {
                    Console.Write(contentUpdate?.Text);
                }
            } 
        }

    Console.WriteLine();
    Console.WriteLine("Your response: (leave empty to quit)");
    question = Console.ReadLine();

}

Finally, we’ll clean up the file and assistant before exiting the application.

Console.WriteLine("Cleaning up and exiting...");
await azureClient.GetFileClient().DeleteFileAsync(fileUploadResponse.Value.Id);
await client.DeleteThreadAsync(thread.Value.Id);
await client.DeleteAssistantAsync(assistant.Value.Id);

By running this application passing the path to a local file as the first parameter, you’ll get a nice console prompt where you can ask questions about the file.

For a video version of this post, take a look at the following:

Thanks for reading!

Ed Andersen Avatar

About me

Hi! ๐Ÿ‘‹ I’m a Software Developer, Architect and Consultant living in Japan, building web and cloud apps. Here I write about software development and other things I find interesting. Read more about my background.

Ed’s “Newsletter”

Get the latest blog posts via email โœŒ๏ธ


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *