Skip to content

Commit 834a791

Browse files
committed
Update to 2.7.0
1 parent c546c07 commit 834a791

File tree

11 files changed

+74
-104
lines changed

11 files changed

+74
-104
lines changed

OpenAI.ChatGpt.AspNetCore/OpenAI.ChatGpt.AspNetCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<PackageId>OpenAI.ChatGPT.AspNetCore</PackageId>
99
<PackageProjectUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</PackageProjectUrl>
1010
<Product>OpenAI ChatGPT integration for .NET with DI</Product>
11-
<Version>2.6.0</Version>
11+
<Version>2.7.0</Version>
1212
<Description>OpenAI Chat Completions API (ChatGPT) integration with easy DI supporting (Microsoft.Extensions.DependencyInjection). It allows you to use the API in your .NET applications. Also, the client supports streaming responses (like ChatGPT) via async streams.</Description>
1313
<RepositoryUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</RepositoryUrl>
1414
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>

OpenAI.ChatGpt.EntityFrameworkCore/OpenAI.ChatGpt.EntityFrameworkCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageId>OpenAI.ChatGPT.EntityFrameworkCore</PackageId>
1010
<PackageProjectUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</PackageProjectUrl>
1111
<Product>OpenAI ChatGPT integration for .NET with EF Core storage</Product>
12-
<Version>2.6.0</Version>
12+
<Version>2.7.0</Version>
1313
<Description>OpenAI Chat Completions API (ChatGPT) integration with DI and EF Core supporting. It allows you to use the API in your .NET applications. Also, the client supports streaming responses (like ChatGPT) via async streams.</Description>
1414
<RepositoryUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</RepositoryUrl>
1515
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<ImplicitUsings>enable</ImplicitUsings>
4+
<Nullable>enable</Nullable>
5+
<LangVersion>11</LangVersion>
6+
<Authors>Rodion Mostovoi</Authors>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<PackageId>OpenAI.ChatGPT.Modules.StructuredResponse</PackageId>
9+
<PackageProjectUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</PackageProjectUrl>
10+
<Product>OpenAI ChatGPT structured response module</Product>
11+
<Version>2.7.0</Version>
12+
<Description>The module for OpenAI ChatGPT that allows to retrive a structured response from ChatGPT.</Description>
13+
<RepositoryUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</RepositoryUrl>
14+
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
15+
<PackageTags>chatgpt, openai, sdk, api, chatcompletions, gpt3, gpt4, json, structured</PackageTags>
16+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
17+
<Title>OpenAI ChatGPT structured response</Title>
18+
<Copyright>Rodion Mostovoi</Copyright>
19+
</PropertyGroup>
20+
21+
<PropertyGroup>
22+
<ImplicitUsings>enable</ImplicitUsings>
23+
<Nullable>enable</Nullable>
24+
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
25+
</PropertyGroup>
26+
27+
<ItemGroup>
28+
<PackageReference Include="JsonSchema.Net.Generation" Version="3.3.0" />
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<ProjectReference Include="..\OpenAI.ChatGpt\OpenAI.ChatGpt.csproj" />
33+
</ItemGroup>
34+
35+
</Project>

OpenAI.ChatGpt/OpenAiClientExtensions.GetAsObjectAsync.cs renamed to OpenAI.ChatGpt.Modules.StructuredResponse/OpenAiClientExtensions.GetAsObjectAsync.cs

Lines changed: 17 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System.Text.Json;
2-
using System.Text.Json.Serialization;
2+
using Json.Schema;
3+
using Json.Schema.Generation;
34
using OpenAI.ChatGpt.Models.ChatCompletion;
45
using OpenAI.ChatGpt.Models.ChatCompletion.Messaging;
56

6-
namespace OpenAI.ChatGpt;
7+
namespace OpenAI.ChatGpt.Modules.StructuredResponse;
78

89
public static class OpenAiClientExtensions
910
{
@@ -40,69 +41,13 @@ public static Task<TObject> GetStructuredResponse<TObject>(
4041
string? user = null,
4142
Action<ChatCompletionRequest>? requestModifier = null,
4243
Action<ChatCompletionResponse>? rawResponseGetter = null,
43-
JsonSerializerOptions? jsonSerializerOptions = null,
44-
JsonSerializerOptions? jsonDeserializerOptions = null,
45-
CancellationToken cancellationToken = default) where TObject: new()
46-
{
47-
ArgumentNullException.ThrowIfNull(client);
48-
ArgumentNullException.ThrowIfNull(dialog);
49-
var responseFormat = CreateResponseFormatJson<TObject>(new TObject(), jsonSerializerOptions);
50-
51-
return client.GetStructuredResponse<TObject>(
52-
dialog: dialog,
53-
responseFormat: responseFormat,
54-
maxTokens: maxTokens,
55-
model: model,
56-
temperature: temperature,
57-
user: user,
58-
requestModifier: requestModifier,
59-
rawResponseGetter: rawResponseGetter,
60-
jsonDeserializerOptions: jsonDeserializerOptions,
61-
cancellationToken: cancellationToken);
62-
}
63-
64-
/// <summary>
65-
/// Asynchronously gets a response from the OpenAI API, and attempts to deserialize it into an instance of the specified type.
66-
/// </summary>
67-
/// <typeparam name="TObject">The type into which to deserialize the response.</typeparam>
68-
/// <param name="client">The OpenAI client.</param>
69-
/// <param name="dialog">The dialog to send to the OpenAI API.</param>
70-
/// <param name="responseExample">Is used to infer the expected structure of the response if no response format is explicitly specified.</param>
71-
/// <param name="maxTokens">(Optional) The maximum number of tokens for the model to generate. If null, the default is calculated.</param>
72-
/// <param name="model">(Optional) The model to use. If null, the default model is used.</param>
73-
/// <param name="temperature">(Optional) Controls randomness in the AI's output. Default is defined by ChatCompletionTemperatures.Default.</param>
74-
/// <param name="user">(Optional) User identifier. If null, the default user is used.</param>
75-
/// <param name="requestModifier">(Optional) Delegate for modifying the request.</param>
76-
/// <param name="rawResponseGetter">(Optional) Delegate for processing the raw response.</param>
77-
/// <param name="jsonSerializerOptions">(Optional) Options for the JSON serializer. If null, the default options are used.</param>
78-
/// <param name="jsonDeserializerOptions">(Optional) Options for the JSON deserializer. If null, case-insensitive property name matching is used.</param>
79-
/// <param name="cancellationToken">(Optional) A token that can be used to cancel the operation.</param>
80-
/// <returns>The task object representing the asynchronous operation, containing the deserialized response,
81-
/// or the default response if deserialization fails.</returns>
82-
/// <exception cref="ArgumentNullException">Thrown if <paramref name="client"/> or <paramref name="dialog"/> or <paramref name="responseExample"/> is null.</exception>
83-
/// <remarks>
84-
/// This method modifies the content of the dialog to include a message instructing the AI to respond in a certain format.
85-
/// After the call to the API, the original content of the dialog is restored.
86-
/// </remarks>
87-
public static Task<TObject> GetStructuredResponse<TObject>(
88-
this IOpenAiClient client,
89-
UserOrSystemMessage dialog,
90-
TObject responseExample,
91-
int? maxTokens = null,
92-
string? model = null,
93-
float temperature = ChatCompletionTemperatures.Default,
94-
string? user = null,
95-
Action<ChatCompletionRequest>? requestModifier = null,
96-
Action<ChatCompletionResponse>? rawResponseGetter = null,
97-
JsonSerializerOptions? jsonSerializerOptions = null,
9844
JsonSerializerOptions? jsonDeserializerOptions = null,
9945
CancellationToken cancellationToken = default)
10046
{
10147
ArgumentNullException.ThrowIfNull(client);
10248
ArgumentNullException.ThrowIfNull(dialog);
103-
ArgumentNullException.ThrowIfNull(responseExample);
49+
var responseFormat = CreateResponseFormatJson<TObject>();
10450

105-
var responseFormat = CreateResponseFormatJson(responseExample, jsonSerializerOptions);
10651
return client.GetStructuredResponse<TObject>(
10752
dialog: dialog,
10853
responseFormat: responseFormat,
@@ -139,7 +84,8 @@ internal static async Task<TObject> GetStructuredResponse<TObject>(
13984
{
14085
editMsg.Content += GetAdditionalJsonResponsePrompt(responseFormat);
14186

142-
(model, maxTokens) = ChatCompletionMessage.FindOptimalModelAndMaxToken(dialog.GetMessages(), model, maxTokens);
87+
(model, maxTokens) =
88+
ChatCompletionMessage.FindOptimalModelAndMaxToken(dialog.GetMessages(), model, maxTokens);
14389

14490
var response = await client.GetChatCompletions(
14591
dialog,
@@ -169,30 +115,20 @@ internal static async Task<TObject> GetStructuredResponse<TObject>(
169115

170116
private static string GetAdditionalJsonResponsePrompt(string responseFormat)
171117
{
172-
return $"\n\nWrite your response in JSON format, which structure is enclosed within double backticks ``{responseFormat}``";
118+
return$"\n\nWrite your response in JSON format. The response structure is enclosed within double backticks (JSON Schema) ``{responseFormat}``";
173119
}
174120

175-
internal static string CreateResponseFormatJson<TObject>(
176-
TObject objectToDeserialize,
177-
JsonSerializerOptions? jsonSerializerOptions)
121+
internal static string CreateResponseFormatJson<TObject>()
178122
{
179-
ArgumentNullException.ThrowIfNull(objectToDeserialize);
180-
if (jsonSerializerOptions is null)
181-
{
182-
jsonSerializerOptions = new JsonSerializerOptions()
123+
var schemaBuilder = new JsonSchemaBuilder();
124+
JsonSchema schema = schemaBuilder.FromType<TObject>(new SchemaGeneratorConfiguration()
183125
{
184-
WriteIndented = false,
185-
DefaultIgnoreCondition = JsonIgnoreCondition.Never
186-
};
187-
}
188-
else
189-
{
190-
jsonSerializerOptions = new JsonSerializerOptions(jsonSerializerOptions)
191-
{
192-
WriteIndented = false,
193-
DefaultIgnoreCondition = JsonIgnoreCondition.Never
194-
};
195-
}
196-
return JsonSerializer.Serialize(objectToDeserialize, jsonSerializerOptions);
126+
Nullability = Nullability.Disabled,
127+
PropertyOrder = PropertyOrder.AsDeclared,
128+
PropertyNamingMethod = PropertyNamingMethods.AsDeclared
129+
}
130+
).Build();
131+
string schemaString = JsonSerializer.Serialize(schema, new JsonSerializerOptions() {WriteIndented = false});
132+
return schemaString;
197133
}
198134
}

OpenAI.ChatGpt.Modules.Translator/OpenAI.ChatGpt.Modules.Translator.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageId>OpenAI.ChatGPT.Modules.Translator</PackageId>
1010
<PackageProjectUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</PackageProjectUrl>
1111
<Product>OpenAI ChatGPT based language translator</Product>
12-
<Version>2.6.0</Version>
12+
<Version>2.7.0</Version>
1313
<Description>OpenAI ChatGPT based language translator.</Description>
1414
<RepositoryUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</RepositoryUrl>
1515
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>

OpenAI.ChatGpt/OpenAI.ChatGpt.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<PackageId>OpenAI.ChatGPT</PackageId>
1111
<PackageProjectUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</PackageProjectUrl>
1212
<Product>OpenAI ChatGPT integration for .NET</Product>
13-
<Version>2.6.0</Version>
13+
<Version>2.7.0</Version>
1414
<Description>.NET integration for ChatGPT with streaming responses supporting (like ChatGPT) via async streams.</Description>
1515
<RepositoryUrl>https://github.com/rodion-m/ChatGPT_API_dotnet</RepositoryUrl>
1616
<PackageLicenseExpression>MIT</PackageLicenseExpression>

OpenAI_DotNet.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.ChatGpt.Modules.Tran
3333
EndProject
3434
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.Tests.Shared", "tests\OpenAI.Tests.Shared\OpenAI.Tests.Shared.csproj", "{E303F270-6091-47DE-9260-DAD6122005A7}"
3535
EndProject
36+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.ChatGpt.Modules.StructuredResponse", "OpenAI.ChatGpt.Modules.StructuredResponse\OpenAI.ChatGpt.Modules.StructuredResponse.csproj", "{F2968A66-5672-439E-823E-D35100CA067D}"
37+
EndProject
3638
Global
3739
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3840
Debug|Any CPU = Debug|Any CPU
@@ -91,6 +93,10 @@ Global
9193
{E303F270-6091-47DE-9260-DAD6122005A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
9294
{E303F270-6091-47DE-9260-DAD6122005A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
9395
{E303F270-6091-47DE-9260-DAD6122005A7}.Release|Any CPU.Build.0 = Release|Any CPU
96+
{F2968A66-5672-439E-823E-D35100CA067D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
97+
{F2968A66-5672-439E-823E-D35100CA067D}.Debug|Any CPU.Build.0 = Debug|Any CPU
98+
{F2968A66-5672-439E-823E-D35100CA067D}.Release|Any CPU.ActiveCfg = Release|Any CPU
99+
{F2968A66-5672-439E-823E-D35100CA067D}.Release|Any CPU.Build.0 = Release|Any CPU
94100
EndGlobalSection
95101
GlobalSection(SolutionProperties) = preSolution
96102
HideSolutionNode = FALSE

tests/OpenAI.ChatGpt.IntegrationTests/OpenAI.ChatGpt.IntegrationTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<ItemGroup>
3131
<ProjectReference Include="..\..\OpenAI.ChatGpt.EntityFrameworkCore\OpenAI.ChatGpt.EntityFrameworkCore.csproj" />
3232
<ProjectReference Include="..\..\OpenAI.ChatGpt.AspNetCore\OpenAI.ChatGpt.AspNetCore.csproj" />
33+
<ProjectReference Include="..\..\OpenAI.ChatGpt.Modules.StructuredResponse\OpenAI.ChatGpt.Modules.StructuredResponse.csproj" />
3334
<ProjectReference Include="..\OpenAI.Tests.Shared\OpenAI.Tests.Shared.csproj" />
3435
</ItemGroup>
3536

tests/OpenAI.ChatGpt.IntegrationTests/OpenAiClientTests/OpenAiClient_GetAsObjectTests.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace OpenAI.ChatGpt.IntegrationTests.OpenAiClientTests;
1+
using OpenAI.ChatGpt.Modules.StructuredResponse;
2+
3+
namespace OpenAI.ChatGpt.IntegrationTests.OpenAiClientTests;
24

35
public class OpenAiClientGetAsObjectTests
46
{
@@ -27,7 +29,7 @@ public async void Get_structured_response_with_array_from_ChatGPT()
2729
{
2830
var message =
2931
Dialog.StartAsSystem("What did user input?")
30-
.ThenUser("My name is John, my age is 30, my email is john@gmail.com. I want to buy 2 apples and 3 oranges.");
32+
.ThenUser("My name is John, my age is 30, my email is john@gmail.com. I want to buy 2 apple and 3 orange.");
3133
var response = await _client.GetStructuredResponse<Order>(message);
3234
response.Should().NotBeNull();
3335
response.UserInfo.Name.Should().Be("John");
@@ -43,8 +45,8 @@ public async void Get_structured_response_with_array_from_ChatGPT()
4345

4446
private class Order
4547
{
46-
public UserInfo UserInfo { get; set; } = new();
47-
public List<Item> Items { get; set; } = new() {new Item()};
48+
public UserInfo UserInfo { get; set; }
49+
public List<Item> Items { get; set; }
4850

4951
public class Item
5052
{

tests/OpenAI.ChatGpt.Modules.Translator.UnitTests/ChatGptTranslatorServiceTests.cs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,6 @@ public void Initialization_with_null_client_should_throw_exception()
2929
act.Should().Throw<ArgumentNullException>();
3030
}
3131

32-
[Fact]
33-
public void Dispose_with_injected_client_should_not_dispose_client()
34-
{
35-
// Arrange
36-
var clientMock = new Mock<OpenAiClient>();
37-
clientMock.Setup(client => client.Dispose()).Verifiable();
38-
var translatorService = new ChatGPTTranslatorService(clientMock.Object);
39-
40-
// Act
41-
translatorService.Dispose();
42-
43-
// Assert
44-
clientMock.Verify(client => client.Dispose(), Times.Never);
45-
}
46-
4732
[Fact]
4833
public async Task Translate_without_source_and_target_languages_uses_default_languages()
4934
{

0 commit comments

Comments
 (0)