diff --git a/OpenAI.Playground/Program.cs b/OpenAI.Playground/Program.cs index 2a9d0448..94b5584e 100644 --- a/OpenAI.Playground/Program.cs +++ b/OpenAI.Playground/Program.cs @@ -60,6 +60,7 @@ //await ChatCompletionTestHelper.RunChatFunctionCallTestAsStream(sdk); //await ChatCompletionTestHelper.RunSimpleCompletionStreamWithUsageTest(sdk); //await BatchTestHelper.RunBatchOperationsTest(sdk); +//await ChatCompletionTestHelper.RunChatWithJsonSchemaResponseFormat(sdk); // Whisper //await AudioTestHelper.RunSimpleAudioCreateTranscriptionTest(sdk); diff --git a/OpenAI.Playground/TestHelpers/ChatCompletionTestHelper.cs b/OpenAI.Playground/TestHelpers/ChatCompletionTestHelper.cs index 74d8a18a..fe1a08e3 100644 --- a/OpenAI.Playground/TestHelpers/ChatCompletionTestHelper.cs +++ b/OpenAI.Playground/TestHelpers/ChatCompletionTestHelper.cs @@ -445,4 +445,77 @@ public static async Task RunChatFunctionCallTestAsStream(IOpenAIService sdk) throw; } } + + //https://platform.openai.com/docs/guides/structured-outputs/how-to-use + public static async Task RunChatWithJsonSchemaResponseFormat(IOpenAIService sdk) + { + ConsoleExtensions.WriteLine("Chat Completion Testing is starting:", ConsoleColor.Cyan); + try + { + var completionResult = await sdk.ChatCompletion.CreateCompletion(new() + { + Messages = new List + { + ChatMessage.FromSystem("You are a helpful math tutor. Guide the user through the solution step by step."), + ChatMessage.FromUser("how can I solve 8x + 7 = -23"), + }, + Model = "gpt-4o-2024-08-06", + ResponseFormat = new ResponseFormat() + { + Type = StaticValues.CompletionStatics.ResponseFormat.JsonSchema, + JsonSchema = new() + { + Name = "math_response", + Strict = true, + Schema = PropertyDefinition.DefineObject( + new Dictionary + { + { + "steps", PropertyDefinition.DefineArray( + PropertyDefinition.DefineObject( + new Dictionary + { + { "explanation", PropertyDefinition.DefineString("The explanation of the step") }, + { "output", PropertyDefinition.DefineString("The output of the step") } + }, + new List { "explanation", "output" }, + false, + "A step in the mathematical process", + null + ) + ) + }, + { + "final_answer", PropertyDefinition.DefineString("The final answer of the mathematical process") + } + }, + new List { "steps", "final_answer" }, + false, + "Response containing steps and final answer of a mathematical process", + null + ) + } + } + }); + + if (completionResult.Successful) + { + Console.WriteLine(completionResult.Choices.First().Message.Content); + } + else + { + if (completionResult.Error == null) + { + throw new("Unknown Error"); + } + + Console.WriteLine($"{completionResult.Error.Code}: {completionResult.Error.Message}"); + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } } \ No newline at end of file diff --git a/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs b/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs index 6a797985..17aa564f 100644 --- a/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs +++ b/OpenAI.SDK/ObjectModels/RequestModels/ChatCompletionCreateRequest.cs @@ -10,7 +10,8 @@ public class ChatCompletionCreateRequest : IModelValidate, IOpenAiModels.ITemper public enum ResponseFormats { Text, - Json + Json, + JsonSchema } /// @@ -227,6 +228,7 @@ public ResponseFormats? ChatResponseFormat { ResponseFormats.Json => StaticValues.CompletionStatics.ResponseFormat.Json, ResponseFormats.Text => StaticValues.CompletionStatics.ResponseFormat.Text, + ResponseFormats.JsonSchema => StaticValues.CompletionStatics.ResponseFormat.JsonSchema, _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) } }; diff --git a/OpenAI.SDK/ObjectModels/RequestModels/ResponseFormat.cs b/OpenAI.SDK/ObjectModels/RequestModels/ResponseFormat.cs index 0a171510..75b9cfa0 100644 --- a/OpenAI.SDK/ObjectModels/RequestModels/ResponseFormat.cs +++ b/OpenAI.SDK/ObjectModels/RequestModels/ResponseFormat.cs @@ -1,4 +1,6 @@ +using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; +using OpenAI.ObjectModels.SharedModels; namespace OpenAI.ObjectModels.RequestModels; @@ -17,6 +19,24 @@ public class ResponseFormat [JsonPropertyName("type")] public string? Type { get; set; } + + [JsonPropertyName("json_schema")] + public JsonSchema JsonSchema { get; set; } +} + +public class JsonSchema +{ + [JsonPropertyName("description")] + public string? Description { get; set; } + + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("strict")] + public bool? Strict { get; set; } + + [JsonPropertyName("schema")] + public PropertyDefinition? Schema { get; set; } } [JsonConverter(typeof(ResponseFormatOptionConverter))] diff --git a/OpenAI.SDK/ObjectModels/StaticValueHelper.cs b/OpenAI.SDK/ObjectModels/StaticValueHelper.cs index 234d8544..8ff1d15b 100644 --- a/OpenAI.SDK/ObjectModels/StaticValueHelper.cs +++ b/OpenAI.SDK/ObjectModels/StaticValueHelper.cs @@ -6,6 +6,7 @@ public static class CompletionStatics { public static class ResponseFormat { + public static string JsonSchema => "json_schema"; public static string Json => "json_object"; public static string Text => "text"; } diff --git a/Readme.md b/Readme.md index 5d12f65a..dcb0f15c 100644 --- a/Readme.md +++ b/Readme.md @@ -115,7 +115,8 @@ Due to time constraints, not all methods have been thoroughly tested or fully do Needless to say, I cannot accept responsibility for any damage caused by using the library. ## Changelog - +### 8.6.2 +- Added support for Structured Outputs, here is the link for samples: [Wiki, Structured Outputs ](https://github.com/betalgo/openai/wiki/Structured-Outputs) ### 8.6.1 - Updated Models with new GPT-4o mini model. ### 8.6.0