Monday, 14 October 2024

Working with OpenAI Assistants: Using file search

This is the second post in the series where we explore the OpenAI Assistants API. In this post, we will be looking at the file search capabilities which allows us to upload files to the Assistants API and chat with them. See the following posts for the entire series:

Working with OpenAI Assistants: Create a simple assistant

Working with OpenAI Assistants: Using file search (this post)

Working with OpenAI Assistants: Chat with Excel files using code interpreter

Working with OpenAI Assistants: Using code interpreter to generate charts

The file search API uses the Retrieval Augmented Generation (RAG) pattern which has been made popular recently. The added advantage of using the Assistants API for this is that the API manages document chunking, vectorizing and indexing for us. Whereas without the Assistants API we would have to use a separate service like Azure AI Search and manage the document indexing ourselves. 

To upload and chat with documents using the Assistants API, we have to use the following moving pieces: 

  • First, we need to create a Vector Store in the Assistants API.
  • Then, we need to upload files using the Open AI File client and add them to the vector store.
  • Finally, we need to connect the vector store to either an assistant or a thread which would enable to assistant to answer questions based on the document.

For the demo code, we will be using the Azure OpenAI service for working with the OpenAI gpt-4o model and since we will be using .NET code, we will need the Azure OpenAI .NET SDK as well as Azure.AI.OpenAI.Assistants nuget packages.

string endpoint = "https://<myopenaiservice>.openai.azure.com/";
string key = "<my-open-ai-service-key>";
string deploymentName = "gpt-4o";
var azureClient = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(key));
OpenAIFileClient fileClient = azureClient.GetOpenAIFileClient();
AssistantClient assistantClient = azureClient.GetAssistantClient();
VectorStoreClient vectorClient = azureClient.GetVectorStoreClient();
var vectorStore = vectorClient.CreateVectorStore(true, new VectorStoreCreationOptions()
{
Name = "focusworks_ai_vector_store",
//Make the documents expire after 3 days of inactivity.
ExpirationPolicy = new VectorStoreExpirationPolicy() {
Anchor = VectorStoreExpirationAnchor.LastActiveAt,
Days = 3
}
});
//Create and upload sample document
using Stream document = BinaryData.FromBytes(@"Focusworks AI is a versatile productivity tool designed to streamline your workflow and enhance collaboration within Microsoft Teams. With its internet-connected ChatGPT bot, you can engage in insightful conversations on any topic, leveraging a rich knowledge base to gain valuable insights. It also empowers you to create stunning AI-powered images effortlessly, simply by describing what you envision in your own words.
One of the standout features of Focusworks AI is its ability to interact with your data. You can upload documents, ask questions, and have a dynamic conversation with your information, uncovering details and insights you might have missed. The AI is also tailored to help you craft more effective Teams messages, improving communication quality and ensuring your ideas are clearly conveyed. Additionally, it can summarize both your personal and group chats, making it easy to extract key points and stay updated.
Sharing your generated content and insights with colleagues is made seamless through Focusworks AI. You can post directly to Teams channels and group chats, ensuring everyone stays informed. The intuitive dashboard allows you to view all your recently created content and quickly access the relevant chats or channels, keeping your workflow organized and efficient. With Focusworks AI, you can eliminate information overload and enjoy a more productive work environment. Try the app for free and conveniently upgrade to a subscription if it elevates your workflow!"u8.ToArray()).ToStream();
OpenAIFile infoFile = await fileClient.UploadFileAsync(document, "focusworks_ai.txt", FileUploadPurpose.Assistants);
await vectorClient.AddFileToVectorStoreAsync(vectorStore.VectorStoreId, infoFile.Id, true);
AssistantCreationOptions assistantOptions = new()
{
Name = "FileSearchPro",
Instructions =
@"You are FileSearchPro, an intelligent assistant designed to help users locate information within their uploaded files. Your primary function is to search through these documents and provide accurate, concise answers to users' questions. You understand various file types and can extract relevant data, ensuring users get the information they need quickly and efficiently.
Key Features:
Efficiently search all uploaded documents to extract precise information.
Provide clear, straightforward answers directly from the file contents.
Maintain confidentiality and security of all user data.
Offer guidance on effective search queries if needed.
Always strive to deliver accurate and helpful information, enhancing users' ability to access and utilize their stored documents effectively.",
Tools =
{
new FileSearchToolDefinition(),
},
ToolResources = new() //Files can be specified at the assistant level.
{
FileSearch = new()
{
VectorStoreIds = { vectorStore.VectorStoreId },
}
}
};
Assistant assistant = assistantClient.CreateAssistant(deploymentName, assistantOptions);
ThreadCreationOptions threadOptions = new()
{
InitialMessages = { "What is Focusworks AI?" },
//Files can also be specified at the thread level.
//ToolResources = new()
//{
// FileSearch = new()
// {
// VectorStoreIds = { vectorStore.VectorStoreId },
// }
//}
};
ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Id, threadOptions);
do
{
Thread.Sleep(TimeSpan.FromSeconds(1));
threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);
CollectionResult<ThreadMessage> messages = assistantClient.GetMessages(threadRun.ThreadId, new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });
foreach (ThreadMessage message in messages)
{
Console.Write($"[{message.Role.ToString().ToUpper()}]: ");
foreach (MessageContent contentItem in message.Content)
{
if (!string.IsNullOrEmpty(contentItem.Text))
{
Console.WriteLine($"{contentItem.Text}");
if (contentItem.TextAnnotations.Count > 0)
{
Console.WriteLine();
}
// Include annotations, if any.
foreach (TextAnnotation annotation in contentItem.TextAnnotations)
{
if (!string.IsNullOrEmpty(annotation.InputFileId))
{
Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}");
}
if (!string.IsNullOrEmpty(annotation.OutputFileId))
{
Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}");
}
}
}
}
}

[USER]: What is Focusworks AI?

[ASSISTANT]: Focusworks AI is a productivity tool designed to enhance collaboration and streamline workflows within Microsoft Teams. It features an internet-connected ChatGPT bot that allows users to engage in insightful conversations and gain valuable insights from a rich knowledge base. The tool can create AI-powered images by simply describing users' visions. A key feature of Focusworks AI is its ability to interact with users' data, enabling document uploads and dynamic conversations to uncover insights. It also improves communication by helping craft more effective Teams messages and by summarizing both personal and group chats.

  • File citation, file ID: assistant-VVwKBdUixwPyk6RuOEnJpixh
view raw output.md hosted with ❤ by GitHub

Limitations


As per OpenAI docs, there are some limitations for the file search tool:

  • Each vector store can hold up to 10,000 files.
  • The maximum file size of a file which can be uploaded is 512 MB. Each file should contain no more than 5,000,000 tokens per file (computed automatically when you attach a file).

When querying for the documents in the vector store, we have to be aware of the following things which are not possible right now. However, the OpenAI team are working on this and some of these features will be available soon:

  • Support for deterministic pre-search filtering using custom metadata.
  • Support for parsing images within documents (including images of charts, graphs, tables etc.)
  • Support for retrievals over structured file formats (like csv or jsonl).
  • Better support for summarization — the tool today is optimized for search queries.

Current supported files types can be found in the OpenAI docs

Hope this helps!

Monday, 7 October 2024

Working with OpenAI Assistants: Create a simple assistant

With OpenAI's recently released Assistants API, building AI bots becomes a lot easier. Using the API, an assistant can leverage custom instructions, files and tools (previously called functions) and answer user questions based on them.

Before the Assistants API, building such assistants was possible but for a lot of things, we had to use our own services e.g. vector storage for file search, database for maintaining chat history etc.

The Assistants API gives us a handy wrapper on top of all these disparate services and a single endpoint to work with. So in this series of posts, let's have a look at what the Assistants API can do.

Working with OpenAI Assistants: Create a simple assistant (this post)

Working with OpenAI Assistants: Using file search

Working with OpenAI Assistants: Chat with Excel files using code interpreter

Working with OpenAI Assistants: Using code interpreter to generate charts

The first thing we are going to do is build a simple assistant which has a "SharePoint Tutor" personality. It will be used to answer questions for users who are learning to use SharePoint. Before deep diving into the code, lets understand the different moving pieces of the Assistants API: 

An assistant is a container in which all operations between the AI and the user are managed.

A thread is a list of messages which were exchanged between the user and AI. The thread is also responsible for maintaining the conversation history.

A run is a single invocation of an assistant based on the history in the thread as well as the tools available to the assistant. After a run is executed, new messages are generated and added to the thread.

For the demo code, we will be using the Azure OpenAI service for working with the OpenAI gpt-4o model and since we will be using .NET code, we will need the Azure OpenAI .NET SDK as well as Azure.AI.OpenAI.Assistants nuget packages.

string endpoint = "https://<myopenaiservice>.openai.azure.com/";
string key = "<my-open-ai-service-key>";
string deploymentName = "gpt-4o";
//We are using the Azure OpenAI Service so create an Azure OpenAI client
var azureClient = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(key));
AssistantClient assistantClient = azureClient.GetAssistantClient();
//Create assistant
AssistantCreationOptions assistantOptions = new()
{
Name = "SharePoint Tutor",
Instructions =
"You are SharePoint Tutor, an expert assistant in guiding users through SharePoint. " +
"Your role is to provide clear, step-by-step instructions, troubleshooting tips, and best practices for managing and navigating SharePoint. " +
"Always respond in a friendly, approachable tone, and aim to make even complex tasks easy to understand. " +
"When users ask for help with specific tasks, provide detailed instructions. If they encounter issues, offer practical solutions and guidance. " +
"Ensure your responses are concise yet informative, and be ready to suggest tips that improve the user's overall SharePoint experience."
};
Assistant assistant = assistantClient.CreateAssistant(deploymentName, assistantOptions);
//Create thread
ThreadCreationOptions threadOptions = new()
{
InitialMessages = { "What is a webpart?" }
};
//Create a run
ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Id, threadOptions, new RunCreationOptions() { });
do
{
Thread.Sleep(TimeSpan.FromSeconds(1));
threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);
//Get messages from a thread. This includes the most recent created message as well.
CollectionResult<ThreadMessage> messages = assistantClient.GetMessages(threadRun.ThreadId, new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });
foreach (ThreadMessage message in messages)
{
Console.Write($"[{message.Role.ToString().ToUpper()}]: ");
foreach (MessageContent contentItem in message.Content)
{
if (!string.IsNullOrEmpty(contentItem.Text))
{
Console.WriteLine($"{contentItem.Text}");
if (contentItem.TextAnnotations.Count > 0)
{
Console.WriteLine();
}
}
}
Console.WriteLine();
}

[USER]: What is a webpart?

[ASSISTANT]: A web part is a versatile and reusable building block in SharePoint that allows you to add dynamic content and functionality to your SharePoint pages. You can think of a web part as a widget that you can place on a page to display information or provide certain functionality, such as showing a calendar, a list of documents, news headlines, or even embedding video content.

view raw output.md hosted with ❤ by GitHub
This was a simple assistant creation just to get us familiar with the Assitants API. In the next posts, we will dive deeper into the API and explore the more advanced concepts. Stay tuned!