Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions eng/packages/General.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageVersion Include="Azure.Core" Version="1.45.0" />
<PackageVersion Include="Azure.Identity" Version="1.13.2" />
<PackageVersion Include="Azure.Core" Version="1.49.0" />
<PackageVersion Include="Azure.Identity" Version="1.16.0" />
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.21.0" />
<PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.5" />
<PackageVersion Include="DnsClient" Version="1.8.0" />
Expand Down
1 change: 0 additions & 1 deletion eng/packages/TestOnly.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageVersion Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.3.0-beta.2" />
<PackageVersion Include="autofixture" Version="4.17.0" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.5" />
<PackageVersion Include="AwesomeAssertions" Version="8.0.2" />
Expand Down
2 changes: 0 additions & 2 deletions src/ProjectTemplates/GeneratedContent.targets
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
<PropertyGroup>
<TemplatePackageVersion_Aspire>9.5.0</TemplatePackageVersion_Aspire>
<TemplatePackageVersion_Aspire_Preview>9.5.0-preview.1.25474.7</TemplatePackageVersion_Aspire_Preview>
<TemplatePackageVersion_AzureAIOpenAI>2.3.0-beta.2</TemplatePackageVersion_AzureAIOpenAI>
<TemplatePackageVersion_AzureAIProjects>1.0.0-beta.9</TemplatePackageVersion_AzureAIProjects>
<TemplatePackageVersion_AzureIdentity>1.14.0</TemplatePackageVersion_AzureIdentity>
<TemplatePackageVersion_AzureSearchDocuments>11.6.1</TemplatePackageVersion_AzureSearchDocuments>
Expand All @@ -62,7 +61,6 @@
<!-- Package version properties -->
TemplatePackageVersion_Aspire=$(TemplatePackageVersion_Aspire);
TemplatePackageVersion_Aspire_Preview=$(TemplatePackageVersion_Aspire_Preview);
TemplatePackageVersion_AzureAIOpenAI=$(TemplatePackageVersion_AzureAIOpenAI);
TemplatePackageVersion_AzureAIProjects=$(TemplatePackageVersion_AzureAIProjects);
TemplatePackageVersion_AzureIdentity=$(TemplatePackageVersion_AzureIdentity);
TemplatePackageVersion_AzureSearchDocuments=$(TemplatePackageVersion_AzureSearchDocuments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
]
},
{
"condition": "(!UseLocalVectorStore)",
"condition": "(!IsLocalVectorStore)",
"exclude": [
"ChatWithCustomData-CSharp.Web/Services/JsonVectorStore.cs"
]
Expand Down Expand Up @@ -185,6 +185,10 @@
"defaultValue": "false",
"description": "Create the project as a distributed application using Aspire."
},
"IsManagedIdentity": {
"type": "computed",
"value": "(UseManagedIdentity)"
},
"IsAspire": {
"type": "computed",
"value": "(UseAspire || VectorStore == \"qdrant\")"
Expand All @@ -209,21 +213,21 @@
"type": "computed",
"value": "(AiServiceProvider == \"azureaifoundry\")"
},
"UseAzureAISearch": {
"IsAzureAISearch": {
"type": "computed",
"value": "(VectorStore == \"azureaisearch\")"
},
"UseLocalVectorStore": {
"IsLocalVectorStore": {
"type": "computed",
"value": "(VectorStore == \"local\")"
},
"UseQdrant": {
"IsQdrant": {
"type": "computed",
"value": "(VectorStore == \"qdrant\")"
},
"UseAzure": {
"IsAzure": {
"type": "computed",
"value": "(IsAzureOpenAI || IsAzureAiFoundry || UseAzureAISearch)"
"value": "(IsAzureOpenAI || IsAzureAIFoundry || IsAzureAISearch)"
},
"ChatModel": {
"type": "parameter",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
modelName: "text-embedding-3-small",
modelVersion: "1");
#endif
#if (UseAzureAISearch)
#if (IsAzureAISearch)

// See https://learn.microsoft.com/dotnet/aspire/azure/local-provisioning#configuration
// for instructions providing configuration values
Expand All @@ -42,13 +42,13 @@
var chat = ollama.AddModel("chat", "llama3.2");
var embeddings = ollama.AddModel("embeddings", "all-minilm");
#endif
#if (UseAzureAISearch) // VECTOR DATABASE CONFIGURATION
#elif (UseQdrant)
#if (IsAzureAISearch) // VECTOR DATABASE CONFIGURATION
#elif (IsQdrant)

var vectorDB = builder.AddQdrant("vectordb")
.WithDataVolume()
.WithLifetime(ContainerLifetime.Persistent);
#else // UseLocalVectorStore
#else // IsLocalVectorStore
#endif

var webApp = builder.AddProject<Projects.ChatWithCustomData_CSharp_Web_AspireClassName_Web>("aichatweb-app");
Expand All @@ -65,15 +65,15 @@
.WithReference(openai)
.WaitFor(openai);
#endif
#if (UseAzureAISearch) // VECTOR DATABASE REFERENCES
#if (IsAzureAISearch) // VECTOR DATABASE REFERENCES
webApp
.WithReference(search)
.WaitFor(search);
#elif (UseQdrant)
#elif (IsQdrant)
webApp
.WithReference(vectorDB)
.WaitFor(vectorDB);
#else // UseLocalVectorStore
#else // IsLocalVectorStore
#endif

builder.Build().Run();
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="${TemplatePackageVersion_Aspire}" />
<!--#if (UseQdrant)
<!--#if (IsQdrant)
<PackageReference Include="Aspire.Hosting.Qdrant" Version="${TemplatePackageVersion_Aspire}" />
#elif (UseAzureAISearch)
#elif (IsAzureAISearch)
<PackageReference Include="Aspire.Hosting.Azure.Search" Version="${TemplatePackageVersion_Aspire}" />
#endif -->
<!--#if (IsAzureOpenAI) -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,35 @@
<PackageReference Include="OllamaSharp" Version="${TemplatePackageVersion_OllamaSharp}" />
#elif ((IsGHModels || IsOpenAI) && !IsAspire)
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="${TemplatePackageVersion_MicrosoftExtensionsAIOpenAI}" />
#elif (IsAzureAiFoundry)
<PackageReference Include="Azure.AI.OpenAI" Version="${TemplatePackageVersion_AzureAIOpenAI}" />
#elif (IsAzureAIFoundry)
<PackageReference Include="Azure.AI.Projects" Version="${TemplatePackageVersion_AzureAIProjects}" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="${TemplatePackageVersion_MicrosoftExtensionsAIOpenAI}" />
#endif -->
<!--#if ((IsAzureOpenAI || IsOpenAI || IsGHModels) && IsAspire) -->
<PackageReference Include="Azure.AI.OpenAI" Version="${TemplatePackageVersion_AzureAIOpenAI}" />
<PackageReference Include="Aspire.Azure.AI.OpenAI" Version="${TemplatePackageVersion_Aspire_Preview}" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="${TemplatePackageVersion_MicrosoftExtensionsAIOpenAI}" />
<!--#endif -->
<!--#if (IsAzureOpenAI && !IsAspire) -->
<PackageReference Include="Azure.AI.OpenAI" Version="${TemplatePackageVersion_AzureAIOpenAI}" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="${TemplatePackageVersion_MicrosoftExtensionsAIOpenAI}" />
<!--#endif -->
<!--#if (UseManagedIdentity) -->
<!--#if (IsManagedIdentity) -->
<PackageReference Include="Azure.Identity" Version="${TemplatePackageVersion_AzureIdentity}" />
<!--#endif -->
<PackageReference Include="Microsoft.Extensions.AI" Version="${TemplatePackageVersion_MicrosoftExtensionsAI}" />
<PackageReference Include="Microsoft.SemanticKernel.Core" Version="${TemplatePackageVersion_MicrosoftSemanticKernel}" />
<PackageReference Include="PdfPig" Version="${TemplatePackageVersion_PdfPig}" />
<PackageReference Include="System.Linq.Async" Version="${TemplatePackageVersion_SystemLinqAsync}" />
<!--#if (UseAzureAISearch && IsAspire)
<!--#if (IsAzureAISearch && IsAspire)
<PackageReference Include="Aspire.Azure.Search.Documents" Version="${TemplatePackageVersion_Aspire}" />
#elif (UseAzureAISearch && !IsAspire)
#elif (IsAzureAISearch && !IsAspire)
<PackageReference Include="Azure.Search.Documents" Version="${TemplatePackageVersion_AzureSearchDocuments}" />
#endif -->
<!--#if (UseAzureAISearch)
<!--#if (IsAzureAISearch)
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAISearch" Version="${TemplatePackageVersion_MicrosoftSemanticKernel_Preview}" />
#elif (UseQdrant)-->
#elif (IsQdrant)-->
<PackageReference Include="Aspire.Qdrant.Client" Version="${TemplatePackageVersion_Aspire}" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="${TemplatePackageVersion_MicrosoftSemanticKernel_Preview}" />
<!--#elif (UseLocalVectorStore)-->
<!--#elif (IsLocalVectorStore)-->
<PackageReference Include="Microsoft.SemanticKernel.Connectors.SqliteVec" Version="${TemplatePackageVersion_MicrosoftSemanticKernel_Preview}" />
<!--#endif -->
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using Microsoft.Extensions.AI;
#if (IsOpenAI || IsGHModels)
using OpenAI;
#endif
using ChatWithCustomData_CSharp.Web.Components;
using ChatWithCustomData_CSharp.Web.Services;
using ChatWithCustomData_CSharp.Web.Services.Ingestion;
#if (IsOllama)
#elif (IsOpenAI || IsGHModels)
using OpenAI;
#else // IsAzureOpenAI
#endif

var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
Expand All @@ -20,7 +18,7 @@
c.EnableSensitiveData = builder.Environment.IsDevelopment());
builder.AddOllamaApiClient("embeddings")
.AddEmbeddingGenerator();
#elif (IsAzureAiFoundry)
#elif (IsAzureAIFoundry)
#else // (IsOpenAI || IsAzureOpenAI || IsGHModels)
#if (IsOpenAI)
var openai = builder.AddOpenAIClient("openai");
Expand All @@ -34,15 +32,15 @@
openai.AddEmbeddingGenerator("text-embedding-3-small");
#endif

#if (UseAzureAISearch)
#if (IsAzureAISearch)
builder.AddAzureSearchClient("search");
builder.Services.AddAzureAISearchCollection<IngestedChunk>("data-ChatWithCustomData-CSharp.Web-chunks");
builder.Services.AddAzureAISearchCollection<IngestedDocument>("data-ChatWithCustomData-CSharp.Web-documents");
#elif (UseQdrant)
#elif (IsQdrant)
builder.AddQdrantClient("vectordb");
builder.Services.AddQdrantCollection<Guid, IngestedChunk>("data-ChatWithCustomData-CSharp.Web-chunks");
builder.Services.AddQdrantCollection<Guid, IngestedDocument>("data-ChatWithCustomData-CSharp.Web-documents");
#else // UseLocalVectorStore
#else // IsLocalVectorStore
var vectorStorePath = Path.Combine(AppContext.BaseDirectory, "vector-store.db");
var vectorStoreConnectionString = $"Data Source={vectorStorePath}";
builder.Services.AddSqliteCollection<string, IngestedChunk>("data-ChatWithCustomData-CSharp.Web-chunks", vectorStoreConnectionString);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using Microsoft.Extensions.AI;
using ChatWithCustomData_CSharp.Web.Components;
using ChatWithCustomData_CSharp.Web.Services;
using ChatWithCustomData_CSharp.Web.Services.Ingestion;
#if(IsAzureOpenAI || UseAzureAISearch)
#if (!IsOllama)
using System.ClientModel;
#endif
#if (IsAzureAISearch && !IsManagedIdentity)
using Azure;
#if (UseManagedIdentity)
#elif (IsManagedIdentity)
using Azure.Core;
using Azure.Identity;
#endif
#endif
using Microsoft.Extensions.AI;
#if (IsOllama)
using OllamaSharp;
#elif (IsOpenAI || IsGHModels)
using OpenAI;
using System.ClientModel;
#else
using Azure.AI.OpenAI;
using System.ClientModel;
using OpenAI;
#endif
using ChatWithCustomData_CSharp.Web.Components;
using ChatWithCustomData_CSharp.Web.Services;
using ChatWithCustomData_CSharp.Web.Services.Ingestion;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
Expand Down Expand Up @@ -51,48 +50,50 @@
var chatClient = openAIClient.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
#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.
var embeddingGenerator = openAIClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
#elif (IsAzureAiFoundry)
#elif (IsAzureAIFoundry)

#else // IsAzureOpenAI
// You will need to set the endpoint and key to your own values
// You can do this using Visual Studio's "Manage User Secrets" UI, or on the command line:
// cd this-project-directory
// dotnet user-secrets set AzureOpenAI:Endpoint https://YOUR-DEPLOYMENT-NAME.openai.azure.com
#if (!UseManagedIdentity)
#if (!IsManagedIdentity)
// dotnet user-secrets set AzureOpenAI:Key YOUR-API-KEY
#endif
var azureOpenAi = new AzureOpenAIClient(
new Uri(builder.Configuration["AzureOpenAI:Endpoint"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Endpoint. See the README for details.")),
#if (UseManagedIdentity)
new DefaultAzureCredential());
var azureOpenAIEndpoint = new Uri(new Uri(builder.Configuration["AzureOpenAI:Endpoint"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Endpoint. See the README for details.")), "/openai/v1");
#if (IsManagedIdentity)
var azureOpenAi = new OpenAIClient(
new BearerTokenPolicy(new DefaultAzureCredential(), "https://ai.azure.com/.default"),
new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint });
#else
new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Key. See the README for details.")));
var openAIOptions = new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint };
var azureOpenAi = new OpenAIClient(new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Key. See the README for details.")), openAIOptions);
#endif
#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 chatClient = azureOpenAi.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
#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.
var embeddingGenerator = azureOpenAi.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
#endif

#if (UseAzureAISearch)
#if (IsAzureAISearch)
// You will need to set the endpoint and key to your own values
// You can do this using Visual Studio's "Manage User Secrets" UI, or on the command line:
// cd this-project-directory
// dotnet user-secrets set AzureAISearch:Endpoint https://YOUR-DEPLOYMENT-NAME.search.windows.net
#if (!UseManagedIdentity)
#if (!IsManagedIdentity)
// dotnet user-secrets set AzureAISearch:Key YOUR-API-KEY
#endif
var azureAISearchEndpoint = new Uri(builder.Configuration["AzureAISearch:Endpoint"]
?? throw new InvalidOperationException("Missing configuration: AzureAISearch:Endpoint. See the README for details."));
#if (UseManagedIdentity)
#if (IsManagedIdentity)
var azureAISearchCredential = new DefaultAzureCredential();
#else
var azureAISearchCredential = new AzureKeyCredential(builder.Configuration["AzureAISearch:Key"]
?? throw new InvalidOperationException("Missing configuration: AzureAISearch:Key. See the README for details."));
#endif
builder.Services.AddAzureAISearchCollection<IngestedChunk>("data-ChatWithCustomData-CSharp.Web-chunks", azureAISearchEndpoint, azureAISearchCredential);
builder.Services.AddAzureAISearchCollection<IngestedDocument>("data-ChatWithCustomData-CSharp.Web-documents", azureAISearchEndpoint, azureAISearchCredential);
#else // UseLocalVectorStore
#else // IsLocalVectorStore
var vectorStorePath = Path.Combine(AppContext.BaseDirectory, "vector-store.db");
var vectorStoreConnectionString = $"Data Source={vectorStorePath}";
builder.Services.AddSqliteCollection<string, IngestedChunk>("data-ChatWithCustomData-CSharp.Web-chunks", vectorStoreConnectionString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This project is an AI chat application that demonstrates how to chat with custom
>[!NOTE]
> Before running this project you need to configure the API keys or endpoints for the providers you have chosen. See below for details specific to your choices.

#### ---#if (UseAzure)
#### ---#if (IsAzure)
### Prerequisites
To use Azure OpenAI or Azure AI Search, you need an Azure account. If you don't already have one, [create an Azure account](https://azure.microsoft.com/free/).

Expand Down Expand Up @@ -104,7 +104,7 @@ To use Azure OpenAI, you will need an Azure account and an Azure OpenAI Service
### 2. Deploy the Models
Deploy the `gpt-4o-mini` and `text-embedding-3-small` models to your Azure OpenAI Service resource. When creating those deployments, give them the same names as the models (`gpt-4o-mini` and `text-embedding-3-small`). See the Azure OpenAI documentation to learn how to [Deploy a model](https://learn.microsoft.com/azure/ai-services/openai/how-to/create-resource?pivots=web-portal#deploy-a-model).

#### ---#if (UseManagedIdentity)
#### ---#if (IsManagedIdentity)
### 3. Configure Azure OpenAI for Keyless Authentication
This template is configured to use keyless authentication (also known as Managed Identity, with Entra ID). In the Azure Portal, when viewing the Azure OpenAI resource you just created, view access control settings and assign yourself the `Azure AI Developer` role. [Learn more about configuring authentication for local development](https://learn.microsoft.com/azure/developer/ai/keyless-connections?tabs=csharp%2Cazure-cli#authenticate-for-local-development).

Expand Down Expand Up @@ -160,7 +160,7 @@ Make sure to replace `YOUR-AZURE-OPENAI-KEY` and `YOUR-AZURE-OPENAI-ENDPOINT` wi

#### ---#endif
#### ---#endif
#### ---#if (UseAzureAISearch)
#### ---#if (IsAzureAISearch)
## Configure Azure AI Search

To use Azure AI Search, you will need an Azure account and an Azure AI Search resource. For detailed instructions, see the [Azure AI Search documentation](https://learn.microsoft.com/azure/search/search-create-service-portal).
Expand All @@ -170,7 +170,7 @@ Follow the instructions in the [Azure portal](https://portal.azure.com/) to crea

Note that if you previously used the same Azure AI Search resource with different model using this project name, you may need to delete your `data-ChatWithCustomData-CSharp.Web-chunks` and `data-ChatWithCustomData-CSharp.Web-documents` indexes using the [Azure portal](https://portal.azure.com/) first before continuing; otherwise, data ingestion may fail due to a vector dimension mismatch.

#### ---#if (UseManagedIdentity)
#### ---#if (IsManagedIdentity)
### 2. Configure Azure AI Search for Keyless Authentication
This template is configured to use keyless authentication (also known as Managed Identity, with Entra ID). Before continuing, you'll need to configure your Azure AI Search resource to support this. [Learn more](https://learn.microsoft.com/azure/search/keyless-connections). After creation, ensure that you have selected Role-Based Access Control (RBAC) under Settings > Keys, as this is not the default. Assign yourself the roles called out for local development. [Learn more](https://learn.microsoft.com/azure/search/keyless-connections#roles-for-local-development).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ public class IngestedChunk
#else
private const int VectorDimensions = 1536; // 1536 is the default vector size for the OpenAI text-embedding-3-small model
#endif
#if (UseAzureAISearch || UseQdrant)
#if (IsAzureAISearch || IsQdrant)
private const string VectorDistanceFunction = DistanceFunction.CosineSimilarity;
#else
private const string VectorDistanceFunction = DistanceFunction.CosineDistance;
#endif

[VectorStoreKey]
#if (UseQdrant)
#if (IsQdrant)
public required Guid Key { get; set; }
#else
public required string Key { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ namespace ChatWithCustomData_CSharp.Web.Services;
public class IngestedDocument
{
private const int VectorDimensions = 2;
#if (UseAzureAISearch || UseQdrant)
#if (IsAzureAISearch || IsQdrant)
private const string VectorDistanceFunction = DistanceFunction.CosineSimilarity;
#else
private const string VectorDistanceFunction = DistanceFunction.CosineDistance;
#endif

[VectorStoreKey]
#if (UseQdrant)
#if (IsQdrant)
public required Guid Key { get; set; }
#else
public required string Key { get; set; }
Expand Down
Loading
Loading