Skip to content

Commit 0380813

Browse files
committed
Update to net9.0, new AI packages, and endpoint changes
Updated target framework to net9.0 for multiple projects. Added new package references: CommunityToolkit.Aspire.OllamaSharp, Azure.AI.OpenAI, Azure.Identity, and Microsoft.Extensions.AI. Removed older packages like Microsoft.AspNetCore.OpenApi and Swashbuckle.AspNetCore, replacing them with newer versions. Enhanced Program.cs to support different AI types (ollama, azureopenai) based on configuration settings. Modified weatherforecast endpoint to use IChatClient and return an asynchronous stream of weather forecasts. Updated GetWeatherSummary method to use IChatClient interface. Refactored ChatService.cs to use IChatClient in ProcessMessage method. Updated project files to include new package references and target net9.0. Updated appsettings.json with useLocalAI and chatDeploymentName settings. Enhanced ChatApiClient and WeatherApiClient to adjust endpoint URLs and handle responses more robustly. Updated Chat.razor to use ChatRole from Microsoft.Extensions.AI and properly format messages. Updated base addresses for HTTP clients in Program.cs to include specific paths for weatherforecast and chat.
1 parent 8f8218b commit 0380813

File tree

12 files changed

+107
-62
lines changed

12 files changed

+107
-62
lines changed

src/BuildWithAspire.ApiService/BuildWithAspire.ApiService.csproj

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88

99
<ItemGroup>
1010
<PackageReference Include="Aspire.Azure.AI.OpenAI" Version="9.0.0-preview.5.24551.3" />
11-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
12-
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
11+
<PackageReference Include="CommunityToolkit.Aspire.OllamaSharp" Version="9.1.0" />
12+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
13+
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
14+
<PackageReference Include="Azure.Identity" Version="1.13.1" />
15+
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.0.1-preview.1.24570.5" />
16+
<PackageReference Include="Microsoft.Extensions.AI.Ollama" Version="9.0.1-preview.1.24570.5" />
17+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
18+
<PackageReference Include="Microsoft.Extensions.AI" Version="9.0.1-preview.1.24570.5" />
19+
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.0.1-preview.1.24570.5" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
1320
<PackageReference Include="System.Text.Json" Version="9.0.0" />
1421
<PackageReference Include="Microsoft.SemanticKernel" Version="1.32.0" />
1522
</ItemGroup>

src/BuildWithAspire.ApiService/Program.cs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1-
using OpenAI.Chat;
2-
using OpenAI;
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.Extensions.AI;
33
using Microsoft.SemanticKernel;
4-
using Microsoft.SemanticKernel.ChatCompletion;
4+
using OpenAI;
55

66
var builder = WebApplication.CreateBuilder(args);
77

88
builder.AddServiceDefaults();
99

10-
builder.AddAzureOpenAIClient("openai");
10+
var aiType = builder.Configuration["AI:Type"] ?? "ollama";
11+
var chatDeploymentName = builder.Configuration["AI:ChatDeploymentName"] ?? "chat";
12+
13+
switch (aiType.ToLower())
14+
{
15+
case "ollama":
16+
builder.AddOllamaSharpChatClient(chatDeploymentName);
17+
break;
18+
case "azureopenai":
19+
builder.AddAzureOpenAIClient(chatDeploymentName);
20+
builder.Services.AddChatClient(services => services.GetRequiredService<OpenAIClient>()
21+
.AsChatClient(chatDeploymentName));
22+
break;
23+
default:
24+
throw new InvalidOperationException($"Unsupported AI type: {aiType}");
25+
}
1126

12-
var chatDeploymentName = builder.Configuration["AI_ChatDeploymentName"] ?? "chat";
13-
builder.Services.AddKernel()
14-
.AddAzureOpenAIChatCompletion(chatDeploymentName);
27+
builder.Services.AddKernel();
1528

16-
// Add services to the container.
1729
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
1830
builder.Services.AddEndpointsApiExplorer();
1931
builder.Services.AddSwaggerGen();
@@ -33,36 +45,37 @@
3345

3446
app.UseHttpsRedirection();
3547

36-
app.MapGet("/weatherforecast", (OpenAIClient client) =>
48+
app.MapGet("/weatherforecast", async (IChatClient client) =>
3749
{
38-
var forecast = Enumerable.Range(1, 5).Select(index =>
50+
async IAsyncEnumerable<WeatherForecast> GetForecasts()
3951
{
40-
var temperature = Random.Shared.Next(-20, 55);
41-
var summary = GetWeatherSummary(client, temperature);
42-
return new WeatherForecast
43-
(
44-
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
45-
temperature,
46-
summary
47-
);
48-
})
49-
.ToArray();
50-
return forecast;
51-
52-
static string GetWeatherSummary(OpenAIClient client, int temp)
52+
for (int index = 1; index <= 5; index++)
53+
{
54+
var temperature = Random.Shared.Next(-20, 55);
55+
var summary = await GetWeatherSummary(client, temperature);
56+
yield return new WeatherForecast
57+
(
58+
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
59+
temperature,
60+
summary
61+
);
62+
}
63+
}
64+
65+
return GetForecasts();
66+
67+
static async Task<string> GetWeatherSummary(IChatClient client, int temp)
5368
{
54-
var chatClient = client.GetChatClient("chat");
55-
ChatCompletion completion = chatClient.CompleteChat(
56-
[
57-
// System messages represent instructions or other guidance about how the assistant should behave
58-
new SystemChatMessage("You are a helpful assistant that provides a description of the weather in one word based on the temperature."),
59-
// User messages represent user input, whether historical or the most recen tinput
60-
new UserChatMessage($"How would you describe the weather at temp {temp} in celcius? Provide the response in 1 word with no punctuation."),
61-
// Assistant messages in a request represent conversation history for responses
62-
]
63-
);
64-
65-
return $"{completion.Content[0].Text}";
69+
List<ChatMessage> conversation = new()
70+
{
71+
// System messages represent instructions or other guidance about how the assistant should behave
72+
new(ChatRole.System, "You are a helpful assistant that provides a description of the weather in one word based on the temperature."),
73+
// User messages represent user input, whether historical or the most recent input
74+
new(ChatRole.User, $"How would you describe the weather at temp {temp} in celcius? Provide the response in 1 word with no punctuation.")
75+
};
76+
var completion = await client.CompleteAsync(conversation);
77+
78+
return $"{completion.Message.Text}";
6679
}
6780
})
6881
.WithName("GetWeatherForecast")

src/BuildWithAspire.ApiService/Services/ChatService.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.SemanticKernel.ChatCompletion;
22
using Microsoft.SemanticKernel;
3+
using Microsoft.Extensions.AI;
34

45
public class ChatService
56
{
@@ -12,7 +13,10 @@ public ChatService(Kernel kernel)
1213

1314
public async Task<string> ProcessMessage(string message)
1415
{
15-
var chatCompletionService = _kernel.GetRequiredService<IChatCompletionService>();
16+
#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
17+
var chatCompletionService = _kernel.GetRequiredService<IChatClient>()
18+
.AsChatCompletionService();
19+
#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
1620

1721
ChatHistory history = [];
1822
history.AddSystemMessage(@"You are an AI demonstration application.

src/BuildWithAspire.AppHost/BuildWithAspire.AppHost.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net9.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
<IsAspireHost>true</IsAspireHost>
@@ -12,6 +12,7 @@
1212
<ItemGroup>
1313
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
1414
<PackageReference Include="Aspire.Hosting.Azure.CognitiveServices" Version="9.0.0" />
15+
<PackageReference Include="CommunityToolkit.Aspire.Hosting.Ollama" Version="9.1.0" />
1516
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
1617
<PackageReference Include="System.Text.Json" Version="9.0.0" />
1718
</ItemGroup>
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1+
using Microsoft.Extensions.Configuration;
2+
13
var builder = DistributedApplication.CreateBuilder(args);
24

3-
var chatDeploymentName = "chat";
5+
var useLocalAI = builder.Configuration.GetValue<bool>("UseLocalAI");
6+
var chatDeploymentName = builder.Configuration["chatDeploymentName"] ?? "chat";
7+
48
var openai = builder.AddAzureOpenAI("openai")
5-
.AddDeployment(new AzureOpenAIDeployment(chatDeploymentName, "gpt-4o", "2024-05-13", "GlobalStandard", 10));
9+
.AddDeployment(new AzureOpenAIDeployment(chatDeploymentName, "gpt-4o", "2024-11-20", "GlobalStandard", 10));
10+
11+
var ollama = builder.AddOllama("ollama")
12+
.WithDataVolume()
13+
.WithOpenWebUI()
14+
.WithContainerRuntimeArgs("--gpus=all")
15+
.AddModel("chat", "llama3.2");
16+
17+
IResourceBuilder<IResourceWithConnectionString> chat = useLocalAI ? ollama : openai;
618

719
var apiService = builder.AddProject<Projects.BuildWithAspire_ApiService>("apiservice")
8-
.WithReference(openai)
9-
.WithEnvironment("AI_ChatDeploymentName", chatDeploymentName);
20+
.WithEnvironment("AI:ChatDeploymentName", chatDeploymentName)
21+
.WithEnvironment("AI:Type", useLocalAI ? "ollama" : "azureOpenAi")
22+
.WithReference(chat, chatDeploymentName)
23+
.WaitFor(chat);
1024

1125
builder.AddProject<Projects.BuildWithAspire_Web>("webfrontend")
1226
.WithExternalHttpEndpoints()
13-
.WithReference(apiService);
27+
.WithReference(apiService)
28+
.WaitFor(apiService);
1429

1530
builder.Build().Run();

src/BuildWithAspire.AppHost/appsettings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
"Microsoft.AspNetCore": "Warning",
66
"Aspire.Hosting.Dcp": "Warning"
77
}
8-
}
8+
},
9+
"useLocalAI": true,
10+
"chatDeploymentName": "chat"
911
}

src/BuildWithAspire.ServiceDefaults/BuildWithAspire.ServiceDefaults.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<IsAspireSharedProject>true</IsAspireSharedProject>

src/BuildWithAspire.Web/BuildWithAspire.Web.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88

99
<ItemGroup>
1010
<PackageReference Include="Aspire.Azure.AI.OpenAI" Version="9.0.0-preview.5.24551.3" />
1111
<PackageReference Include="Markdig" Version="0.39.1" />
12+
<PackageReference Include="Microsoft.Extensions.AI.Ollama" Version="9.0.1-preview.1.24570.5" />
1213
<PackageReference Include="System.Text.Json" Version="9.0.0" />
1314
</ItemGroup>
1415

src/BuildWithAspire.Web/Clients/ChatApiClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
using Microsoft.Extensions.AI;
12
namespace BuildWithAspire.Web.Clients;
23

34
public class ChatApiClient(HttpClient httpClient)
45
{
56
public async Task<string> GetChatAsync(string message, CancellationToken cancellationToken = default)
67
{
7-
var response = await httpClient.GetAsync($"/chat?message={message}", cancellationToken);
8+
var response = await httpClient.GetAsync($"?message={message}", cancellationToken);
89
var chatResponse = response.IsSuccessStatusCode
910
? await response.Content.ReadAsStringAsync(cancellationToken)
1011
: throw new Exception(response.ReasonPhrase);

src/BuildWithAspire.Web/Clients/WeatherApiClient.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@ public class WeatherApiClient(HttpClient httpClient)
44
{
55
public async Task<WeatherForecast[]> GetWeatherAsync(int maxItems = 10, CancellationToken cancellationToken = default)
66
{
7-
List<WeatherForecast>? forecasts = null;
7+
var forecasts = new List<WeatherForecast>();
88

9-
await foreach (var forecast in httpClient.GetFromJsonAsAsyncEnumerable<WeatherForecast>("/weatherforecast", cancellationToken))
9+
await foreach (var forecast in httpClient.GetFromJsonAsAsyncEnumerable<WeatherForecast>("", cancellationToken))
1010
{
11-
if (forecasts?.Count >= maxItems)
11+
if (forecasts.Count >= maxItems)
1212
{
1313
break;
1414
}
1515
if (forecast is not null)
1616
{
17-
forecasts ??= [];
1817
forecasts.Add(forecast);
1918
}
2019
}
2120

22-
return forecasts?.ToArray() ?? [];
21+
return forecasts.ToArray();
2322
}
2423
}
2524

0 commit comments

Comments
 (0)