diff --git a/dotnet/samples/06.assistants.a.mathBot/Program.cs b/dotnet/samples/06.assistants.a.mathBot/Program.cs index 069dfaca6..ac03e8c87 100644 --- a/dotnet/samples/06.assistants.a.mathBot/Program.cs +++ b/dotnet/samples/06.assistants.a.mathBot/Program.cs @@ -35,7 +35,7 @@ if (config.Azure!.OpenAIApiKey != string.Empty) { - apiKey = config.Azure!.OpenAIApiKey!; + apiKey = config.Azure!.OpenAIApiKey!; } else { @@ -76,7 +76,6 @@ newAssistantId = AssistantsPlanner.CreateAssistantAsync(tokenCredential!, assistantCreationOptions, "gpt-4o-mini", endpoint!).Result.Id; } - string newAssistantId = AssistantsPlanner.CreateAssistantAsync(apiKey, assistantCreateParams, "gpt-4", endpoint).Result.Id; Console.WriteLine($"Created a new assistant with an ID of: {newAssistantId}"); Console.WriteLine("Copy and save above ID, and set `OpenAI:AssistantId` in appsettings.Development.json."); Console.WriteLine("Press any key to exit."); diff --git a/dotnet/samples/06.assistants.b.orderBot/ActionHandlers.cs b/dotnet/samples/06.assistants.b.orderBot/ActionHandlers.cs index 1ae85d1ae..37c61f029 100644 --- a/dotnet/samples/06.assistants.b.orderBot/ActionHandlers.cs +++ b/dotnet/samples/06.assistants.b.orderBot/ActionHandlers.cs @@ -31,5 +31,14 @@ public async Task OnPlaceOrder([ActionTurnContext] ITurnContext turnCont return "order placed"; } + + [Action(AIConstants.UnknownActionName, false)] + public string UnknownAction([ActionTurnContext] ITurnContext turnContext) + { + ArgumentNullException.ThrowIfNull(turnContext); + + // Continues execution of next command in the plan. + return "The predicted function tool call doesn't exist. Please try again."; + } } } diff --git a/dotnet/samples/06.assistants.b.orderBot/Models/OrderParameters.cs b/dotnet/samples/06.assistants.b.orderBot/Models/OrderParameters.cs index 87e3bf6b4..4715d3a0b 100644 --- a/dotnet/samples/06.assistants.b.orderBot/Models/OrderParameters.cs +++ b/dotnet/samples/06.assistants.b.orderBot/Models/OrderParameters.cs @@ -57,7 +57,7 @@ public static Dictionary GetSchema() }, ""kind"": { ""type"": ""string"", - ""description"": ""examples: Mack and Jacks, Sierra Nevada Pale Ale, Miller Lite"" + ""description"": ""Mack and Jacks, Sierra Nevada Pale Ale, Miller Lite"" }, ""quantity"": { ""type"": ""number"", diff --git a/dotnet/samples/06.assistants.b.orderBot/Program.cs b/dotnet/samples/06.assistants.b.orderBot/Program.cs index 6cc07d97b..a9321e05d 100644 --- a/dotnet/samples/06.assistants.b.orderBot/Program.cs +++ b/dotnet/samples/06.assistants.b.orderBot/Program.cs @@ -11,7 +11,14 @@ using Azure.Core; using Azure.Identity; using System.Runtime.CompilerServices; - +using Microsoft.Teams.AI.Application; +using OpenAI.Files; +using OpenAI.VectorStores; +using OpenAI; +using Azure.AI.OpenAI; +using System.ClientModel; + +#pragma warning disable OPENAI001 var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); @@ -57,6 +64,59 @@ // Missing Assistant ID, create new Assistant if (string.IsNullOrEmpty(assistantId)) { + VectorStore store = null!; + try + { + OpenAIClient client; + if (endpoint != null) + { + if (apiKey != null) + { + client = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey)); + } + else + { + client = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential()); + } + } + else + { + client = new OpenAIClient(apiKey!); + } + + // Create Vector Store + var storeClient = client.GetVectorStoreClient(); + store = storeClient.CreateVectorStore(new VectorStoreCreationOptions()); + + // Upload file. + var fileClient = client.GetFileClient(); + var uploadedFile = fileClient.UploadFile("./assets/menu.pdf", FileUploadPurpose.Assistants); + + // Attach file to vector store + var fileAssociation = storeClient.AddFileToVectorStore(store, uploadedFile); + + // Poll vector store until file is uploaded + var maxPollCount = 5; + var pollCount = 1; + while (store.FileCounts.Completed == 0 && pollCount <= maxPollCount) + { + // Wait a second + await Task.Delay(1000); + store = storeClient.GetVectorStore(store.Id); + pollCount += 1; + } + + if (store.FileCounts.Completed == 0) + { + throw new Exception("Unable to attach file to vector store. Timed out"); + } + } + catch (Exception e) + { + throw new Exception("Failed to upload file to vector store.", e.InnerException); + } + + AssistantCreationOptions assistantCreationOptions = new() { Name = "Order Bot", @@ -67,9 +127,14 @@ "If the customer doesn't specify the type of pizza, beer, or salad they want ask them.", "Verify the order is complete and accurate before placing it with the place_order function." }), + ToolResources = new ToolResources() + { + FileSearch = new FileSearchToolResources() { VectorStoreIds = new List() { store.Id } } + } }; assistantCreationOptions.Tools.Add(new FunctionToolDefinition("place_order", "Creates or updates a food order.", new BinaryData(OrderParameters.GetSchema()))); + assistantCreationOptions.Tools.Add(new FileSearchToolDefinition()); string newAssistantId = ""; if (apiKey != null) @@ -91,8 +156,8 @@ // Prepare Configuration for ConfigurationBotFrameworkAuthentication builder.Configuration["MicrosoftAppType"] = "MultiTenant"; -builder.Configuration["MicrosoftAppId"] = ""; // config.BOT_ID; -builder.Configuration["MicrosoftAppPassword"] = ""; // config.BOT_PASSWORD; +builder.Configuration["MicrosoftAppId"] = config.BOT_ID; +builder.Configuration["MicrosoftAppPassword"] = config.BOT_PASSWORD; // Create the Bot Framework Authentication to be used with the Bot Adapter. builder.Services.AddSingleton(); @@ -123,11 +188,21 @@ { ILoggerFactory loggerFactory = sp.GetService()!; IPlanner planner = new AssistantsPlanner(sp.GetService()!, loggerFactory); + + TeamsAdapter adapter = sp.GetService()!; + TeamsAttachmentDownloaderOptions fileDownloaderOptions = new(config.BOT_ID!, adapter); + + IInputFileDownloader teamsAttachmentDownloader = new TeamsAttachmentDownloader(fileDownloaderOptions); + ApplicationOptions applicationOptions = new() { - AI = new AIOptions(planner), + AI = new AIOptions(planner) { AllowLooping = true }, Storage = sp.GetService(), - LoggerFactory = loggerFactory + LoggerFactory = loggerFactory, + FileDownloaders = new List>() { teamsAttachmentDownloader }, + LongRunningMessages = true, + Adapter = sp.GetService(), + BotAppId = config.BOT_ID }; Application app = new(applicationOptions); @@ -153,3 +228,4 @@ app.MapControllers(); app.Run(); +#pragma warning restore OPENAI001 diff --git a/dotnet/samples/06.assistants.b.orderBot/appPackage/manifest.json b/dotnet/samples/06.assistants.b.orderBot/appPackage/manifest.json index 8b7fee405..799393151 100644 --- a/dotnet/samples/06.assistants.b.orderBot/appPackage/manifest.json +++ b/dotnet/samples/06.assistants.b.orderBot/appPackage/manifest.json @@ -41,7 +41,7 @@ "isNotificationOnly": false, "supportsCalling": false, "supportsVideo": false, - "supportsFiles": false + "supportsFiles": true } ], "validDomains": [ diff --git a/dotnet/samples/06.assistants.b.orderBot/assets/menu.pdf b/dotnet/samples/06.assistants.b.orderBot/assets/menu.pdf new file mode 100644 index 000000000..80078ca5f Binary files /dev/null and b/dotnet/samples/06.assistants.b.orderBot/assets/menu.pdf differ diff --git a/dotnet/samples/06.assistants.b.orderBot/env/.env.local b/dotnet/samples/06.assistants.b.orderBot/env/.env.local index 48434a361..b64fba40a 100644 --- a/dotnet/samples/06.assistants.b.orderBot/env/.env.local +++ b/dotnet/samples/06.assistants.b.orderBot/env/.env.local @@ -1,12 +1,9 @@ -# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. - -# Built-in environment variables +APP_NAME_SUFFIX=local +TEAMS_APP_ID=ed8ff81d-89ec-4860-9afc-176c268c8434 +TEAMS_APP_TENANT_ID=e474fd88-c1e2-4a74-bf7f-ffc1cc00a46c +BOT_ID=43a3a1b5-68a6-4c63-86c7-7ed0e2edeed4 TEAMSFX_ENV=local +TEAMSFX_M365_USER_NAME=kavin@solangealTestTenant.onmicrosoft.com -# Generated during provision, you can also add your own variables. -BOT_ID= -TEAMS_APP_ID= -BOT_DOMAIN= - - -APP_NAME_SUFFIX=local +BOT_ENDPOINT=https://9v2ggs46-5130.use.devtunnels.ms +BOT_DOMAIN=9v2ggs46-5130.use.devtunnels.ms \ No newline at end of file