Skip to content

Commit a85eebb

Browse files
authored
Update to Aspire 9.5 and changed things (#14)
* Upgrade Aspire packages to version 9.5.0-preview.1.25421.6 and add NuGet.config for package source mapping * Refactor OpenAI client integration in ChatClientExtensions and update ModelExtensions for improved resource handling * Update CommunityToolkit.Aspire.OllamaSharp to version 9.7.0 and enhance connection string handling in ChatClientConnectionInfo * Update package versions to 9.5.0-pr.11227.a5d368e0 and enhance NuGet.config for additional package source mapping * Refactor ChatClientExtensions to enhance OpenTelemetry integration and improve connection handling * Update package versions to 9.5.0-preview.1.25458.3 and modify NuGet.config for improved package source mapping * Remove obsolete package source for local Aspire hive from NuGet.config * Update package versions to 9.5.0 and remove obsolete NuGet.config * Remove --prerelease flag from Aspire CLI installation in publish workflow * Add YARP support for static file serving and reverse proxy; update Docker and Docker Compose configurations
1 parent f3148db commit a85eebb

File tree

12 files changed

+86
-144
lines changed

12 files changed

+86
-144
lines changed

.github/workflows/aspire-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
dotnet-version: '9.x'
2525

2626
- name: Install Aspire CLI
27-
run: dotnet tool install --global aspire.cli --prerelease
27+
run: dotnet tool install --global aspire.cli
2828

2929
- name: Run Aspire Publish
3030
run: aspire publish -p docker-compose -o artifacts

AIChat.AppHost/AIChat.AppHost.csproj

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

3-
<Sdk Name="Aspire.AppHost.Sdk" Version="9.4.1" />
3+
<Sdk Name="Aspire.AppHost.Sdk" Version="9.5.0" />
44

55
<PropertyGroup>
66
<OutputType>Exe</OutputType>
@@ -12,11 +12,13 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.4.1" />
16-
<PackageReference Include="Aspire.Hosting.Docker" Version="9.4.1-preview.1.25408.4" />
17-
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.4.1" />
18-
<PackageReference Include="Aspire.Hosting.Redis" Version="9.4.1" />
19-
<PackageReference Include="Aspire.Hosting.NodeJs" Version="9.4.1" />
15+
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.0" />
16+
<PackageReference Include="Aspire.Hosting.Docker" Version="9.5.0-preview.1.25474.7" />
17+
<PackageReference Include="Aspire.Hosting.OpenAI" Version="9.5.0-preview.1.25474.7" />
18+
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.5.0" />
19+
<PackageReference Include="Aspire.Hosting.Redis" Version="9.5.0" />
20+
<PackageReference Include="Aspire.Hosting.NodeJs" Version="9.5.0" />
21+
<PackageReference Include="Aspire.Hosting.Yarp" Version="9.5.0-preview.1.25474.7" />
2022
<PackageReference Include="CommunityToolkit.Aspire.Hosting.NodeJS.Extensions" Version="9.4.0" />
2123
<PackageReference Include="CommunityToolkit.Aspire.Hosting.Ollama" Version="9.4.0" />
2224
</ItemGroup>

AIChat.AppHost/ModelExtensions.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,12 @@ public static IResourceBuilder<AIModel> AsOpenAI(this IResourceBuilder<AIModel>
5050
{
5151
builder.Reset();
5252

53-
var apiKey = builder.ApplicationBuilder.AddParameter($"{builder.Resource.Name}-openai-api-key", secret:true)
54-
.WithDescription("OpenAI API Key https://platform.openai.com/api-keys", enableMarkdown: true);
53+
var oai = builder.ApplicationBuilder.AddOpenAI("oai");
5554

56-
var cs = builder.ApplicationBuilder.AddConnectionString(builder.Resource.Name, csb =>
57-
{
58-
csb.Append($"AccessKey={apiKey};");
59-
csb.Append($"Model={modelName};");
60-
csb.AppendLiteral("Endpoint=https://api.openai.com/v1;");
61-
csb.AppendLiteral("Provider=OpenAI");
62-
});
63-
64-
builder.Resource.UnderlyingResource = apiKey.Resource;
65-
builder.Resource.ConnectionString = cs.Resource.ConnectionStringExpression;
55+
var model = oai.AddModel(builder.Resource.Name, modelName);
56+
57+
builder.Resource.UnderlyingResource = model.Resource;
58+
builder.Resource.ConnectionString = ReferenceExpression.Create($"{model};Provider=OpenAI");
6659

6760
return builder;
6861
}

AIChat.AppHost/Program.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,27 @@
4747
.WithReference(cache)
4848
.WaitFor(cache);
4949

50-
builder.AddNpmApp("chatui", "../chatui")
51-
.WithNpmPackageInstallation()
52-
.WithHttpEndpoint(env: "PORT")
53-
.WithReverseProxy(chatapi.GetEndpoint("http"))
50+
if (builder.ExecutionContext.IsRunMode)
51+
{
52+
builder.AddNpmApp("chatui-fe", "../chatui")
53+
.WithNpmPackageInstallation()
54+
.WithHttpEndpoint(env: "PORT")
55+
.WithEnvironment("BACKEND_URL", chatapi.GetEndpoint("http"))
56+
.WithOtlpExporter()
57+
.WithEnvironment("BROWSER", "none");
58+
}
59+
60+
// We use YARP as the static file server and reverse proxy. This is used to test
61+
// the application in a containerized environment.
62+
builder.AddYarp("chatui")
63+
.WithStaticFiles()
5464
.WithExternalHttpEndpoints()
55-
.WithOtlpExporter()
56-
.WithEnvironment("BROWSER", "none");
65+
.WithDockerfile("../chatui")
66+
.WithConfiguration(c =>
67+
{
68+
c.AddRoute("/api/{**catch-all}", chatapi.GetEndpoint("http"));
69+
})
70+
.WithExplicitStart();
5771

5872
builder.Build().Run();
5973

AIChat.AppHost/ProxyExtensions.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

AIChat.AppHost/docker-infra/docker-compose.yaml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ services:
1010
- "aspire"
1111
restart: "always"
1212
pg:
13-
image: "docker.io/library/postgres:17.5"
13+
image: "docker.io/library/postgres:17.6"
1414
environment:
1515
POSTGRES_HOST_AUTH_METHOD: "scram-sha-256"
1616
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256"
@@ -26,7 +26,7 @@ services:
2626
networks:
2727
- "aspire"
2828
cache:
29-
image: "docker.io/library/redis:7.4"
29+
image: "docker.io/library/redis:8.2"
3030
command:
3131
- "-c"
3232
- "redis-server --requirepass $$REDIS_PASSWORD"
@@ -46,7 +46,7 @@ services:
4646
OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory"
4747
ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true"
4848
HTTP_PORTS: "${CHATAPI_PORT}"
49-
ConnectionStrings__llm: "AccessKey=${LLM_OPENAI_API_KEY};Model=gpt-4.1;Endpoint=https://api.openai.com/v1;Provider=OpenAI"
49+
ConnectionStrings__llm: "Endpoint=https://api.openai.com/v1;Key=${OAI_OPENAI_APIKEY};Model=gpt-4.1;Provider=OpenAI"
5050
ConnectionStrings__conversations: "Host=pg;Port=5432;Username=postgres;Password=${PG_PASSWORD};Database=conversations"
5151
ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}"
5252
OTEL_EXPORTER_OTLP_ENDPOINT: "http://env-dashboard:18889"
@@ -63,17 +63,22 @@ services:
6363
- "aspire"
6464
chatui:
6565
image: "${CHATUI_IMAGE}"
66+
command:
67+
- "/app/yarp.dll"
68+
entrypoint:
69+
- "dotnet"
6670
environment:
67-
NODE_ENV: "production"
68-
PORT: "80"
69-
BACKEND_URL: "chatapi:${CHATAPI_PORT}"
70-
SPAN: "chatui"
71-
BROWSER: "none"
71+
ASPNETCORE_ENVIRONMENT: "Production"
72+
YARP_ENABLE_STATIC_FILES: "true"
73+
REVERSEPROXY__ROUTES__route0__MATCH__PATH: "/api/{**catch-all}"
74+
REVERSEPROXY__ROUTES__route0__CLUSTERID: "cluster_chatapi"
75+
REVERSEPROXY__CLUSTERS__cluster_chatapi__DESTINATIONS__destination1__ADDRESS: "http://_http.chatapi"
76+
services__chatapi__http__0: "http://chatapi:${CHATAPI_PORT}"
7277
OTEL_EXPORTER_OTLP_ENDPOINT: "http://env-dashboard:18889"
7378
OTEL_EXPORTER_OTLP_PROTOCOL: "grpc"
7479
OTEL_SERVICE_NAME: "chatui"
7580
ports:
76-
- "80"
81+
- "5000"
7782
networks:
7883
- "aspire"
7984
networks:

AIChat.ServiceDefaults/AIChat.ServiceDefaults.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<FrameworkReference Include="Microsoft.AspNetCore.App" />
1212

1313
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.5.0" />
14-
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.4.1" />
14+
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.5.0" />
1515
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
1616
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
1717
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />

ChatApi/ChatApi.csproj

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
44
<TargetFramework>net9.0</TargetFramework>
@@ -7,15 +7,14 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.4.1" />
11-
<PackageReference Include="CommunityToolkit.Aspire.OllamaSharp" Version="9.4.0-preview.1.250420-0640" />
12-
<PackageReference Include="Microsoft.Extensions.AI" Version="9.7.1" />
10+
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.5.0" />
11+
<PackageReference Include="CommunityToolkit.Aspire.OllamaSharp" Version="9.7.0" />
1312
</ItemGroup>
1413

1514
<ItemGroup>
1615
<ProjectReference Include="..\AIChat.ServiceDefaults\AIChat.ServiceDefaults.csproj" />
17-
<PackageReference Include="Aspire.OpenAI" Version="9.4.1-preview.1.25408.4" />
18-
<PackageReference Include="Aspire.StackExchange.Redis" Version="9.4.1" />
16+
<PackageReference Include="Aspire.OpenAI" Version="9.5.0-preview.1.25474.7" />
17+
<PackageReference Include="Aspire.StackExchange.Redis" Version="9.5.0" />
1918
</ItemGroup>
2019

2120
</Project>

ChatApi/ChatClientConnectionInfo.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public static bool TryParse(string? connectionString, [NotNullWhen(true)] out Ch
4040
{
4141
accessKey = (string)connectionBuilder["AccessKey"];
4242
}
43+
else if (connectionBuilder.ContainsKey("Key"))
44+
{
45+
accessKey = (string)connectionBuilder["Key"];
46+
}
4347

4448
var provider = ClientChatProvider.Unknown;
4549
if (connectionBuilder.ContainsKey("Provider"))

ChatApi/ChatClientExtensions.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Runtime.CompilerServices;
2+
using CommunityToolkit.Aspire.OllamaSharp;
13
using Microsoft.Extensions.AI;
24

35
public static class ChatClientExtensions
@@ -11,42 +13,42 @@ public static IHostApplicationBuilder AddChatClient(this IHostApplicationBuilder
1113
throw new InvalidOperationException($"Invalid connection string: {cs}. Expected format: 'Endpoint=endpoint;AccessKey=your_access_key;Model=model_name;Provider=ollama/openai/azureopenai;'.");
1214
}
1315

14-
var chatClientBuilder = connectionInfo.Provider switch
16+
_ = connectionInfo.Provider switch
1517
{
1618
ClientChatProvider.Ollama => builder.AddOllamaClient(connectionName, connectionInfo),
1719
ClientChatProvider.OpenAI => builder.AddOpenAIClient(connectionName, connectionInfo),
1820
_ => throw new NotSupportedException($"Unsupported provider: {connectionInfo.Provider}")
1921
};
2022

21-
// Add OpenTelemetry tracing for the ChatClient activity source
22-
chatClientBuilder.UseOpenTelemetry().UseLogging();
23-
24-
// This is the default name of the trace source and meter
25-
var telemetryName = "Experimental.Microsoft.Extensions.AI";
26-
27-
builder.Services.AddOpenTelemetry()
28-
.WithTracing(t => t.AddSource(telemetryName))
29-
.WithMetrics(m => m.AddMeter(telemetryName));
30-
3123
return builder;
3224
}
3325

3426
private static ChatClientBuilder AddOpenAIClient(this IHostApplicationBuilder builder, string connectionName, ChatClientConnectionInfo connectionInfo)
3527
{
36-
return builder.AddOpenAIClient(connectionName, settings =>
37-
{
38-
settings.Endpoint = connectionInfo.Endpoint;
39-
settings.Key = connectionInfo.AccessKey;
40-
})
41-
.AddChatClient(connectionInfo.SelectedModel);
28+
return builder.AddOpenAIClient(connectionName, settings => settings.EnableSensitiveTelemetryData = true).AddChatClient();
4229
}
4330

4431
private static ChatClientBuilder AddOllamaClient(this IHostApplicationBuilder builder, string connectionName, ChatClientConnectionInfo connectionInfo)
4532
{
46-
return builder.AddOllamaApiClient(connectionName, settings =>
33+
var ollamaBuilder = builder.AddOllamaApiClient(connectionName, settings =>
4734
{
4835
settings.SelectedModel = connectionInfo.SelectedModel;
49-
})
50-
.AddChatClient();
36+
SetDisableTracing(settings, true);
37+
});
38+
39+
// Set up OpenTelemetry for tracing and metrics. This needs to be default in the
40+
// community toolkit.
41+
var telemetryName = "Experimental.Microsoft.Extensions.AI";
42+
43+
builder.Services.AddOpenTelemetry()
44+
.WithTracing(t => t.AddSource(telemetryName))
45+
.WithMetrics(m => m.AddMeter(telemetryName));
46+
47+
return ollamaBuilder.AddChatClient()
48+
.UseOpenTelemetry(configure: options => options.EnableSensitiveData = true)
49+
.UseLogging();
5150
}
51+
52+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_DisableTracing")]
53+
public static extern void SetDisableTracing(OllamaSharpSettings settings, bool value);
5254
}

0 commit comments

Comments
 (0)