Skip to content

Commit 45ed289

Browse files
committed
Upgrade to .NET 9.0 and refactor chat management
Updated target framework to .NET 9.0 across multiple projects. Updated various package references for compatibility and new features. Replaced `ChatGptNet` with `Azure.AI.OpenAI` in `Program.cs`, enhancing chat client management. Modified `ConfigureServices` to include `HybridCache` and improve service setup. Refactored `DatabaseGptClient` to manage chat history and cache more effectively. Added `MessageLimit` property to `DatabaseGptSettings` for better message control. Streamlined `AddDatabaseGpt` extension methods for improved clarity and dependency injection.
1 parent 1dc39b1 commit 45ed289

File tree

11 files changed

+95
-87
lines changed

11 files changed

+95
-87
lines changed

samples/DatabaseGpt.Web/DatabaseGpt.Web.csproj

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

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<SourceRevisionId>build$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss"))</SourceRevisionId>
77
<Company>Marco Minerva</Company>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="LigerShark.WebOptimizer.Core" Version="3.0.426" />
12-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
13-
<PackageReference Include="MinimalHelpers.OpenApi" Version="2.0.16" />
14-
<PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.0.13" />
15-
<PackageReference Include="OperationResultTools.AspNetCore.Http" Version="1.0.25" />
16-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
17-
<PackageReference Include="TinyHelpers" Version="3.1.18" />
18-
<PackageReference Include="TinyHelpers.AspNetCore" Version="3.1.19" />
11+
<PackageReference Include="LigerShark.WebOptimizer.Core" Version="3.0.436" />
12+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
13+
<PackageReference Include="MinimalHelpers.OpenApi" Version="2.1.7" />
14+
<PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.1.3" />
15+
<PackageReference Include="OperationResultTools.AspNetCore.Http" Version="1.0.28" />
16+
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
17+
<PackageReference Include="TinyHelpers" Version="3.2.25" />
18+
<PackageReference Include="TinyHelpers.AspNetCore" Version="4.0.26" />
1919
</ItemGroup>
2020

2121
<ItemGroup>

samples/DatabaseGptConsole/DatabaseGptConsole.csproj

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

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
<FileVersion>1.4</FileVersion>
99
<AssemblyVersion>1.4</AssemblyVersion>
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Spectre.Console" Version="0.49.1" />
14-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
13+
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
14+
<PackageReference Include="Microsoft.Extensions.AI" Version="9.5.0" />
15+
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.5.0-preview.1.25265.7" />
16+
<PackageReference Include="Spectre.Console" Version="0.50.0" />
17+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
1518
</ItemGroup>
1619

1720
<ItemGroup>

samples/DatabaseGptConsole/Program.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using ChatGptNet;
1+
using Azure;
2+
using Azure.AI.OpenAI;
23
using DatabaseGpt;
34
using DatabaseGptConsole;
5+
using Microsoft.Extensions.AI;
46
using Microsoft.Extensions.Configuration;
57
using Microsoft.Extensions.DependencyInjection;
68
using Microsoft.Extensions.Hosting;
@@ -29,6 +31,17 @@ static void ConfigureServices(HostBuilderContext context, IServiceCollection ser
2931
{
3032
services.AddSingleton<Application>();
3133

34+
services.AddHybridCache();
35+
36+
var apiKey = context.Configuration.GetValue<string>("ChatGPT:ApiKey")!;
37+
var deploymentName = context.Configuration.GetValue<string>("ChatGPT:DeploymentName")!;
38+
var endpoint = context.Configuration.GetValue<string>("ChatGpt:Endpoint")!;
39+
40+
var azureOpenAIClient = new AzureOpenAIClient(new(endpoint), new AzureKeyCredential(apiKey));
41+
var chatClient = azureOpenAIClient.GetChatClient(deploymentName).AsIChatClient();
42+
43+
services.AddChatClient(chatClient);
44+
3245
services.AddDatabaseGpt(database =>
3346
{
3447
// For SQL Server.
@@ -42,9 +55,5 @@ static void ConfigureServices(HostBuilderContext context, IServiceCollection ser
4255
// For SQLite.
4356
//database.UseConfiguration(context.Configuration)
4457
// .UseSqlite(context.Configuration.GetConnectionString("SqliteConnection"));
45-
},
46-
chatGpt =>
47-
{
48-
chatGpt.UseConfiguration(context.Configuration);
4958
});
5059
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
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
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
10+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
1111
</ItemGroup>
1212

1313
</Project>

src/DatabaseGpt.Npgsql/DatabaseGpt.Npgsql.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
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
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Dapper" Version="2.1.35" />
11-
<PackageReference Include="Npgsql" Version="8.0.5" />
10+
<PackageReference Include="Dapper" Version="2.1.66" />
11+
<PackageReference Include="Npgsql" Version="9.0.3" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

src/DatabaseGpt.SqlServer/DatabaseGpt.SqlServer.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
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
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
11-
<PackageReference Include="Dapper" Version="2.1.35" />
10+
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
11+
<PackageReference Include="Dapper" Version="2.1.66" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

src/DatabaseGpt.Sqlite/DatabaseGpt.Sqlite.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
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
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Dapper" Version="2.1.35" />
11-
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.10" />
10+
<PackageReference Include="Dapper" Version="2.1.66" />
11+
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.5" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

src/DatabaseGpt/DatabaseGpt.csproj

Lines changed: 4 additions & 3 deletions
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
</PropertyGroup>
@@ -11,8 +11,9 @@
1111
</ItemGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="ChatGptNet" Version="3.3.5" />
15-
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.10.0" />
14+
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.5.0" />
15+
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.5.0" />
16+
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.5.0" />
1617
</ItemGroup>
1718

1819
<ItemGroup>

src/DatabaseGpt/DatabaseGptClient.cs

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
using ChatGptNet;
2-
using ChatGptNet.Extensions;
3-
using DatabaseGpt.Abstractions;
1+
using DatabaseGpt.Abstractions;
42
using DatabaseGpt.Exceptions;
53
using DatabaseGpt.Models;
64
using DatabaseGpt.Settings;
5+
using Microsoft.Extensions.AI;
6+
using Microsoft.Extensions.Caching.Hybrid;
77
using Polly;
88
using Polly.Registry;
9+
using ChatHistory = System.Collections.Generic.List<Microsoft.Extensions.AI.ChatMessage>;
910

1011
namespace DatabaseGpt;
1112

12-
internal class DatabaseGptClient(IChatGptClient chatGptClient, ResiliencePipelineProvider<string> pipelineProvider, IServiceProvider serviceProvider, DatabaseGptSettings databaseGptSettings) : IDatabaseGptClient
13+
internal class DatabaseGptClient(IChatClient chatGptClient, HybridCache cache, ResiliencePipelineProvider<string> pipelineProvider, IServiceProvider serviceProvider, DatabaseGptSettings databaseGptSettings) : IDatabaseGptClient
1314
{
1415
private readonly IDatabaseGptProvider provider = databaseGptSettings.CreateProvider();
1516
private readonly ResiliencePipeline pipeline = pipelineProvider.GetPipeline(nameof(DatabaseGptClient));
@@ -48,8 +49,8 @@ private async Task<DatabaseGptQueryResult> ExecuteNaturalLanguageQueryInternalAs
4849

4950
private async Task<Guid> CreateSessionAsync(Guid sessionId, CancellationToken cancellationToken)
5051
{
51-
var conversationExists = await chatGptClient.ConversationExistsAsync(sessionId, cancellationToken);
52-
if (!conversationExists)
52+
var history = await GetChatHistoryAsync(sessionId, cancellationToken);
53+
if (history.Count == 0)
5354
{
5455
var tables = await provider.GetTablesAsync(databaseGptSettings.IncludedTables, databaseGptSettings.ExcludedTables, cancellationToken);
5556

@@ -67,7 +68,8 @@ private async Task<Guid> CreateSessionAsync(Guid sessionId, CancellationToken ca
6768
""";
6869
}
6970

70-
sessionId = await chatGptClient.SetupAsync(sessionId, systemMessage, cancellationToken);
71+
history.Add(new(ChatRole.System, systemMessage));
72+
await UpdateCacheAsync(sessionId, history, cancellationToken);
7173
}
7274

7375
return sessionId;
@@ -90,9 +92,15 @@ The selected tables should be returned in a comma separated list. Your response
9092
await options.OnStarting.Invoke(serviceProvider);
9193
}
9294

93-
var response = await chatGptClient.AskAsync(sessionId, request, cancellationToken: cancellationToken);
95+
var chat = await GetChatHistoryAsync(sessionId, cancellationToken);
96+
chat.Add(new(ChatRole.User, question));
9497

95-
var candidateTables = response.GetContent()!.Trim('\'');
98+
var response = await chatGptClient.GetResponseAsync(chat, cancellationToken: cancellationToken);
99+
100+
chat.Add(new(ChatRole.Assistant, response.Text));
101+
await UpdateCacheAsync(sessionId, chat, cancellationToken);
102+
103+
var candidateTables = response.Text.Trim('\'');
96104
if (candidateTables == "NONE")
97105
{
98106
throw new NoTableFoundException($"No available information in the provided tables can be useful for the question '{question}'.");
@@ -134,9 +142,15 @@ CREATE TABLE Table2 (Column3 VARCHAR(255), Column4 VARCHAR(255))
134142
request += $"{Environment.NewLine}{queryHints}";
135143
}
136144

137-
var response = await chatGptClient.AskAsync(sessionId, request, cancellationToken: cancellationToken);
145+
var chat = await GetChatHistoryAsync(sessionId, cancellationToken);
146+
chat.Add(new(ChatRole.User, question));
147+
148+
var response = await chatGptClient.GetResponseAsync(chat, cancellationToken: cancellationToken);
149+
150+
chat.Add(new(ChatRole.Assistant, response.Text));
151+
await UpdateCacheAsync(sessionId, chat, cancellationToken);
138152

139-
var query = response.GetContent()!;
153+
var query = response.Text;
140154
if (query == "NONE")
141155
{
142156
throw new InvalidSqlException($"The question '{question}' requires an INSERT, UPDATE or DELETE command, that isn't supported.");
@@ -155,6 +169,27 @@ CREATE TABLE Table2 (Column3 VARCHAR(255), Column4 VARCHAR(255))
155169
return query;
156170
}
157171

172+
private async Task UpdateCacheAsync(Guid conversationId, ChatHistory chat, CancellationToken cancellationToken)
173+
{
174+
if (chat.Count > databaseGptSettings.MessageLimit)
175+
{
176+
chat.RemoveRange(0, chat.Count - databaseGptSettings.MessageLimit);
177+
}
178+
179+
await cache.SetAsync(conversationId.ToString(), chat, cancellationToken: cancellationToken);
180+
}
181+
182+
private async Task<ChatHistory> GetChatHistoryAsync(Guid conversationId, CancellationToken cancellationToken)
183+
{
184+
var historyCache = await cache.GetOrCreateAsync(conversationId.ToString(), (cancellationToken) =>
185+
{
186+
return ValueTask.FromResult<ChatHistory>([]);
187+
}, cancellationToken: cancellationToken);
188+
189+
var chat = new ChatHistory(historyCache);
190+
return chat;
191+
}
192+
158193
protected virtual void Dispose(bool disposing)
159194
{
160195
if (!disposedValue)

src/DatabaseGpt/DatabaseGptServiceCollectionExtensions.cs

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using ChatGptNet;
2-
using DatabaseGpt.Abstractions.Exceptions;
1+
using DatabaseGpt.Abstractions.Exceptions;
32
using DatabaseGpt.Settings;
43
using Microsoft.Extensions.Configuration;
54
using Microsoft.Extensions.DependencyInjection;
@@ -11,28 +10,10 @@ namespace DatabaseGpt;
1110

1211
public static class DatabaseGptServiceCollectionExtensions
1312
{
14-
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<DatabaseGptSettings> configureDatabaseGpt, Action<ChatGptOptionsBuilder> configureChatGpt, ServiceLifetime lifetime = ServiceLifetime.Scoped)
13+
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<IServiceProvider, DatabaseGptSettings> configureDatabaseGpt, int maxQueryGenerationRetries = 3)
1514
{
1615
ArgumentNullException.ThrowIfNull(services);
1716
ArgumentNullException.ThrowIfNull(configureDatabaseGpt);
18-
ArgumentNullException.ThrowIfNull(configureChatGpt);
19-
20-
var settings = new DatabaseGptSettings();
21-
configureDatabaseGpt(settings);
22-
services.AddSingleton(settings);
23-
24-
services.Add(new ServiceDescriptor(typeof(IDatabaseGptClient), typeof(DatabaseGptClient), lifetime));
25-
services.AddChatGpt(configureChatGpt, httpClient => ConfigureHttpClientResiliency(httpClient));
26-
services.AddResiliencePipeline(settings.MaxRetries);
27-
28-
return services;
29-
}
30-
31-
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<IServiceProvider, DatabaseGptSettings> configureDatabaseGpt, Action<ChatGptOptionsBuilder> configureChatGpt, int maxQueryGenerationRetries = 3)
32-
{
33-
ArgumentNullException.ThrowIfNull(services);
34-
ArgumentNullException.ThrowIfNull(configureDatabaseGpt);
35-
ArgumentNullException.ThrowIfNull(configureChatGpt);
3617

3718
services.AddScoped(provider =>
3819
{
@@ -42,49 +23,26 @@ public static IServiceCollection AddDatabaseGpt(this IServiceCollection services
4223
});
4324

4425
services.AddScoped<IDatabaseGptClient, DatabaseGptClient>();
45-
services.AddChatGpt(configureChatGpt, httpClient => ConfigureHttpClientResiliency(httpClient));
4626
services.AddResiliencePipeline(maxQueryGenerationRetries);
4727

4828
return services;
4929
}
5030

51-
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<DatabaseGptSettings> configureDatabaseGpt, Action<IServiceProvider, ChatGptOptionsBuilder> configureChatGpt, ServiceLifetime lifetime = ServiceLifetime.Scoped)
31+
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<DatabaseGptSettings> configureDatabaseGpt, ServiceLifetime lifetime = ServiceLifetime.Scoped)
5232
{
5333
ArgumentNullException.ThrowIfNull(services);
5434
ArgumentNullException.ThrowIfNull(configureDatabaseGpt);
55-
ArgumentNullException.ThrowIfNull(configureChatGpt);
5635

5736
var settings = new DatabaseGptSettings();
5837
configureDatabaseGpt(settings);
5938
services.AddSingleton(settings);
6039

6140
services.Add(new ServiceDescriptor(typeof(IDatabaseGptClient), typeof(DatabaseGptClient), lifetime));
62-
services.AddChatGpt(configureChatGpt, httpClient => ConfigureHttpClientResiliency(httpClient));
6341
services.AddResiliencePipeline(settings.MaxRetries);
6442

6543
return services;
6644
}
6745

68-
public static IServiceCollection AddDatabaseGpt(this IServiceCollection services, Action<IServiceProvider, DatabaseGptSettings> configureDatabaseGpt, Action<IServiceProvider, ChatGptOptionsBuilder> configureChatGpt, int maxQueryGenerationRetries = 3)
69-
{
70-
ArgumentNullException.ThrowIfNull(services);
71-
ArgumentNullException.ThrowIfNull(configureDatabaseGpt);
72-
ArgumentNullException.ThrowIfNull(configureChatGpt);
73-
74-
services.AddScoped(provider =>
75-
{
76-
var settings = new DatabaseGptSettings();
77-
configureDatabaseGpt(provider, settings);
78-
return settings;
79-
});
80-
81-
services.AddScoped<IDatabaseGptClient, DatabaseGptClient>();
82-
services.AddChatGpt(configureChatGpt, httpClient => ConfigureHttpClientResiliency(httpClient));
83-
services.AddResiliencePipeline(maxQueryGenerationRetries);
84-
85-
return services;
86-
}
87-
8846
public static DatabaseGptSettings UseConfiguration(this DatabaseGptSettings settings, IConfiguration configuration, string databaseGptSettingsSectionName = "DatabaseGptSettings")
8947
{
9048
ArgumentNullException.ThrowIfNull(settings);

0 commit comments

Comments
 (0)