Skip to content

Commit

Permalink
OpenAI-DotNet 8.2.2 (#352)
Browse files Browse the repository at this point in the history
- Added generic parameters to methods that support structured output
  • Loading branch information
StephenHodgson authored Aug 19, 2024
1 parent 2cf2a22 commit d79c4d4
Show file tree
Hide file tree
Showing 20 changed files with 501 additions and 254 deletions.
3 changes: 2 additions & 1 deletion OpenAI-DotNet-Tests/TestFixture_00_01_Authentication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ public void Test_11_AzureConfigurationSettings()
var auth = new OpenAIAuthentication("testKeyAaBbCcDd");
var settings = new OpenAIClientSettings(resourceName: "test-resource", deploymentId: "deployment-id-test");
var api = new OpenAIClient(auth, settings);
Console.WriteLine(api.OpenAIClientSettings.DeploymentId);
Console.WriteLine(api.OpenAIClientSettings.BaseRequest);
Console.WriteLine(api.OpenAIClientSettings.BaseRequestUrlFormat);
Assert.AreEqual("https://test-resource.openai.azure.com/openai/{0}", api.OpenAIClientSettings.BaseRequestUrlFormat);
}

[Test]
Expand All @@ -181,6 +181,7 @@ public void Test_12_CustomDomainConfigurationSettings()
var api = new OpenAIClient(auth, settings);
Console.WriteLine(api.OpenAIClientSettings.BaseRequest);
Console.WriteLine(api.OpenAIClientSettings.BaseRequestUrlFormat);
Assert.AreEqual("https://api.your-custom-domain.com/v1/{0}", api.OpenAIClientSettings.BaseRequestUrlFormat);
}

[TearDown]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using NUnit.Framework;
using OpenAI.Images;
using OpenAI.Tests.StructuredOutput;
using OpenAI.Tests.Weather;
using System;
using System.Collections.Generic;
Expand All @@ -12,10 +13,10 @@

namespace OpenAI.Tests
{
internal class TestFixture_00_02_Tools : AbstractTestFixture
internal class TestFixture_00_02_Extensions : AbstractTestFixture
{
[Test]
public void Test_01_GetTools()
public void Test_01_01_GetTools()
{
var tools = Tool.GetAllAvailableTools(forceUpdate: true, clearCache: true).ToList();
Assert.IsNotNull(tools);
Expand All @@ -29,7 +30,7 @@ public void Test_01_GetTools()
}

[Test]
public async Task Test_02_Tool_Funcs()
public async Task Test_01_02_Tool_Funcs()
{
var tools = new List<Tool>
{
Expand Down Expand Up @@ -115,7 +116,7 @@ private string FunctionWithArrayArgs(List<int> args)
}

[Test]
public void Test_03_Tool_works_when_called_concurrently()
public void Test_01_03_Tool_works_when_called_concurrently()
{
Assert.Multiple(async () =>
{
Expand All @@ -138,5 +139,12 @@ async Task Test(int id)
Assert.AreEqual(id, result);
}
}

[Test]
public void Test_02_01_GenerateJsonSchema()
{
JsonSchema mathSchema = typeof(MathResponse);
Console.WriteLine(mathSchema.ToString());
}
}
}
95 changes: 52 additions & 43 deletions OpenAI-DotNet-Tests/TestFixture_03_Threads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.Models;
using OpenAI.Tests.StructuredOutput;
using OpenAI.Tests.Weather;
using OpenAI.Threads;
using System;
Expand Down Expand Up @@ -672,66 +673,74 @@ public async Task Test_04_04_CreateThreadAndRun_SubmitToolOutput()
public async Task Test_05_01_CreateThreadAndRun_StructuredOutputs_Streaming()
{
Assert.NotNull(OpenAIClient.ThreadsEndpoint);
var mathSchema = new JsonSchema("math_response", @"
{
""type"": ""object"",
""properties"": {
""steps"": {
""type"": ""array"",
""items"": {
""type"": ""object"",
""properties"": {
""explanation"": {
""type"": ""string""
},
""output"": {
""type"": ""string""
}
},
""required"": [
""explanation"",
""output""
],
""additionalProperties"": false
}
},
""final_answer"": {
""type"": ""string""
}
},
""required"": [
""steps"",
""final_answer""
],
""additionalProperties"": false
}");
var assistant = await OpenAIClient.AssistantsEndpoint.CreateAssistantAsync(
var assistant = await OpenAIClient.AssistantsEndpoint.CreateAssistantAsync<MathResponse>(
new CreateAssistantRequest(
name: "Math Tutor",
instructions: "You are a helpful math tutor. Guide the user through the solution step by step.",
model: "gpt-4o-2024-08-06",
jsonSchema: mathSchema));
model: "gpt-4o-2024-08-06"));
Assert.NotNull(assistant);
ThreadResponse thread = null;
// check if any exceptions thrown in stream event handler
var exceptionThrown = false;

try
{
var run = await assistant.CreateThreadAndRunAsync("how can I solve 8x + 7 = -23",
async @event =>
async Task StreamEventHandler(IServerSentEvent @event)
{
try
{
Console.WriteLine(@event.ToJsonString());
await Task.CompletedTask;
});
switch (@event)
{
case MessageResponse message:
if (message.Status != MessageStatus.Completed)
{
Console.WriteLine(@event.ToJsonString());
break;
}

var mathResponse = message.FromSchema<MathResponse>();
Assert.IsNotNull(mathResponse);
Assert.IsNotNull(mathResponse.Steps);
Assert.IsNotEmpty(mathResponse.Steps);

for (var i = 0; i < mathResponse.Steps.Count; i++)
{
var step = mathResponse.Steps[i];
Assert.IsNotNull(step.Explanation);
Console.WriteLine($"Step {i}: {step.Explanation}");
Assert.IsNotNull(step.Output);
Console.WriteLine($"Result: {step.Output}");
}

Assert.IsNotNull(mathResponse.FinalAnswer);
Console.WriteLine($"Final Answer: {mathResponse.FinalAnswer}");
break;
default:
Console.WriteLine(@event.ToJsonString());
break;
}
}
catch (Exception e)
{
Console.WriteLine(e);
exceptionThrown = true;
throw;
}

await Task.CompletedTask;
}

var run = await assistant.CreateThreadAndRunAsync("how can I solve 8x + 7 = -23", StreamEventHandler);
Assert.IsNotNull(run);
Assert.IsFalse(exceptionThrown);
thread = await run.GetThreadAsync();
run = await run.WaitForStatusChangeAsync();
Assert.IsNotNull(run);
Assert.IsTrue(run.Status == RunStatus.Completed);
Console.WriteLine($"Created thread and run: {run.ThreadId} -> {run.Id} -> {run.CreatedAt}");
Assert.NotNull(thread);
var messages = await thread.ListMessagesAsync();

foreach (var response in messages.Items)
foreach (var response in messages.Items.OrderBy(response => response.CreatedAt))
{
Console.WriteLine($"{response.Role}: {response.PrintContent()}");
}
Expand Down
126 changes: 40 additions & 86 deletions OpenAI-DotNet-Tests/TestFixture_04_Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using NUnit.Framework;
using OpenAI.Chat;
using OpenAI.Models;
using OpenAI.Tests.StructuredOutput;
using OpenAI.Tests.Weather;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -537,52 +538,27 @@ public async Task Test_06_01_GetChat_JsonSchema()
new(Role.System, "You are a helpful math tutor. Guide the user through the solution step by step."),
new(Role.User, "how can I solve 8x + 7 = -23")
};

var mathSchema = new JsonSchema("math_response", @"
{
""type"": ""object"",
""properties"": {
""steps"": {
""type"": ""array"",
""items"": {
""type"": ""object"",
""properties"": {
""explanation"": {
""type"": ""string""
},
""output"": {
""type"": ""string""
}
},
""required"": [
""explanation"",
""output""
],
""additionalProperties"": false
}
},
""final_answer"": {
""type"": ""string""
}
},
""required"": [
""steps"",
""final_answer""
],
""additionalProperties"": false
}");
var chatRequest = new ChatRequest(messages, model: new("gpt-4o-2024-08-06"), jsonSchema: mathSchema);
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Assert.IsNotEmpty(response.Choices);

foreach (var choice in response.Choices)
{
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
var chatRequest = new ChatRequest(messages, model: "gpt-4o-2024-08-06");
var (mathResponse, chatResponse) = await OpenAIClient.ChatEndpoint.GetCompletionAsync<MathResponse>(chatRequest);
Assert.IsNotNull(chatResponse);
Assert.IsNotNull(mathResponse);
Assert.IsNotEmpty(mathResponse.Steps);
Assert.IsNotNull(chatResponse.Choices);
Assert.IsNotEmpty(chatResponse.Choices);

for (var i = 0; i < mathResponse.Steps.Count; i++)
{
var step = mathResponse.Steps[i];
Assert.IsNotNull(step.Explanation);
Console.WriteLine($"Step {i}: {step.Explanation}");
Assert.IsNotNull(step.Output);
Console.WriteLine($"Result: {step.Output}");
}

response.GetUsage();
Assert.IsNotNull(mathResponse.FinalAnswer);
Console.WriteLine($"Final Answer: {mathResponse.FinalAnswer}");

chatResponse.GetUsage();
}

[Test]
Expand All @@ -595,43 +571,9 @@ public async Task Test_06_01_GetChat_JsonSchema_Streaming()
new(Role.System, "You are a helpful math tutor. Guide the user through the solution step by step."),
new(Role.User, "how can I solve 8x + 7 = -23")
};

var mathSchema = new JsonSchema("math_response", @"
{
""type"": ""object"",
""properties"": {
""steps"": {
""type"": ""array"",
""items"": {
""type"": ""object"",
""properties"": {
""explanation"": {
""type"": ""string""
},
""output"": {
""type"": ""string""
}
},
""required"": [
""explanation"",
""output""
],
""additionalProperties"": false
}
},
""final_answer"": {
""type"": ""string""
}
},
""required"": [
""steps"",
""final_answer""
],
""additionalProperties"": false
}");
var chatRequest = new ChatRequest(messages, model: "gpt-4o-2024-08-06", jsonSchema: mathSchema);
var chatRequest = new ChatRequest(messages, model: "gpt-4o-2024-08-06");
var cumulativeDelta = string.Empty;
var response = await OpenAIClient.ChatEndpoint.StreamCompletionAsync(chatRequest, partialResponse =>
var (mathResponse, chatResponse) = await OpenAIClient.ChatEndpoint.StreamCompletionAsync<MathResponse>(chatRequest, partialResponse =>
{
Assert.IsNotNull(partialResponse);
if (partialResponse.Usage != null) { return; }
Expand All @@ -643,17 +585,29 @@ public async Task Test_06_01_GetChat_JsonSchema_Streaming()
cumulativeDelta += choice.Delta.Content;
}
}, true);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
var choice = response.FirstChoice;
Assert.IsNotNull(chatResponse);
Assert.IsNotNull(mathResponse);
Assert.IsNotNull(chatResponse.Choices);
var choice = chatResponse.FirstChoice;
Assert.IsNotNull(choice);
Assert.IsNotNull(choice.Message);
Assert.IsFalse(string.IsNullOrEmpty(choice.ToString()));
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
Assert.IsTrue(choice.Message.Role == Role.Assistant);
Assert.IsTrue(choice.Message.Content!.Equals(cumulativeDelta));
Console.WriteLine(response.ToString());
response.GetUsage();

for (var i = 0; i < mathResponse.Steps.Count; i++)
{
var step = mathResponse.Steps[i];
Assert.IsNotNull(step.Explanation);
Console.WriteLine($"Step {i}: {step.Explanation}");
Assert.IsNotNull(step.Output);
Console.WriteLine($"Result: {step.Output}");
}

Assert.IsNotNull(mathResponse.FinalAnswer);
Console.WriteLine($"Final Answer: {mathResponse.FinalAnswer}");

chatResponse.GetUsage();
}
}
}
14 changes: 14 additions & 0 deletions OpenAI-DotNet-Tests/TestServices/DateTimeUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.Threading.Tasks;

namespace OpenAI.Tests.Weather
{
internal static class DateTimeUtility
{
[Function("Get the current date and time.")]
public static async Task<string> GetDateTime()
=> await Task.FromResult(DateTimeOffset.Now.ToString());
}
}
Loading

0 comments on commit d79c4d4

Please sign in to comment.