-
-
Notifications
You must be signed in to change notification settings - Fork 535
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bf8265a
commit acc5902
Showing
4 changed files
with
184 additions
and
4 deletions.
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
OpenAI.Utilities/FunctionCalling/PropertyDefinitionGenerator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System.Reflection; | ||
using System.Text.Json.Serialization; | ||
using OpenAI.ObjectModels.SharedModels; | ||
|
||
namespace OpenAI.Utilities.FunctionCalling; | ||
|
||
public class PropertyDefinitionGenerator | ||
{ | ||
public static PropertyDefinition GenerateFromType(Type type) | ||
{ | ||
if (type == null) | ||
throw new ArgumentNullException(nameof(type)); | ||
|
||
if (type.IsPrimitive || type == typeof(string) || type == typeof(DateTime)) | ||
{ | ||
return GeneratePrimitiveDefinition(type); | ||
} | ||
else if (type.IsEnum) | ||
{ | ||
return GenerateEnumDefinition(type); | ||
} | ||
else if (type.IsArray || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))) | ||
{ | ||
return GenerateArrayDefinition(type); | ||
} | ||
else | ||
{ | ||
return GenerateObjectDefinition(type); | ||
} | ||
} | ||
|
||
private static PropertyDefinition GeneratePrimitiveDefinition(Type type) | ||
{ | ||
if (type == typeof(string)) | ||
return PropertyDefinition.DefineString(); | ||
else if (type == typeof(int) || type == typeof(long)) | ||
return PropertyDefinition.DefineInteger(); | ||
else if (type == typeof(float) || type == typeof(double) || type == typeof(decimal)) | ||
return PropertyDefinition.DefineNumber(); | ||
else if (type == typeof(bool)) | ||
return PropertyDefinition.DefineBoolean(); | ||
else if (type == typeof(DateTime)) | ||
return PropertyDefinition.DefineString("ISO 8601 date-time string"); | ||
else | ||
throw new ArgumentException($"Unsupported primitive type: {type.Name}"); | ||
} | ||
|
||
private static PropertyDefinition GenerateEnumDefinition(Type type) | ||
{ | ||
var enumValues = Enum.GetNames(type); | ||
return PropertyDefinition.DefineEnum(new List<string>(enumValues), $"Enum of type {type.Name}"); | ||
} | ||
|
||
private static PropertyDefinition GenerateArrayDefinition(Type type) | ||
{ | ||
Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; | ||
return PropertyDefinition.DefineArray(GenerateFromType(elementType)); | ||
} | ||
|
||
private static PropertyDefinition GenerateObjectDefinition(Type type) | ||
{ | ||
var properties = new Dictionary<string, PropertyDefinition>(); | ||
var required = new List<string>(); | ||
|
||
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) | ||
{ | ||
string propertyName = GetJsonPropertyName(prop); | ||
properties[propertyName] = GenerateFromType(prop.PropertyType); | ||
|
||
// You might want to customize this logic based on your needs | ||
if (!prop.PropertyType.IsValueType && Nullable.GetUnderlyingType(prop.PropertyType) == null) | ||
{ | ||
required.Add(propertyName); | ||
} | ||
} | ||
|
||
return PropertyDefinition.DefineObject( | ||
properties, | ||
required, | ||
false, // Set additionalProperties to false by default | ||
$"Object of type {type.Name}", | ||
null | ||
); | ||
} | ||
|
||
private static string GetJsonPropertyName(PropertyInfo prop) | ||
{ | ||
var jsonPropertyNameAttribute = prop.GetCustomAttribute<JsonPropertyNameAttribute>(); | ||
return jsonPropertyNameAttribute != null ? jsonPropertyNameAttribute.Name : prop.Name; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
OpenAI.UtilitiesPlayground/TestHelpers/JsonSchemaResponseTypeTestHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using OpenAI.Interfaces; | ||
using OpenAI.ObjectModels; | ||
using OpenAI.ObjectModels.RequestModels; | ||
using OpenAI.Utilities.FunctionCalling; | ||
|
||
namespace OpenAI.UtilitiesPlayground.TestHelpers; | ||
|
||
public static class JsonSchemaResponseTypeTestHelpers | ||
{ | ||
public static async Task RunChatWithJsonSchemaResponseFormat2(IOpenAIService sdk) | ||
{ | ||
Console.WriteLine("Chat Completion Testing is starting:"); | ||
try | ||
{ | ||
var completionResult = await sdk.ChatCompletion.CreateCompletion(new() | ||
{ | ||
Messages = new List<ChatMessage> | ||
{ | ||
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() | ||
{ | ||
Type = StaticValues.CompletionStatics.ResponseFormat.JsonSchema, | ||
JsonSchema = new() | ||
{ | ||
Name = "math_response", | ||
Strict = true, | ||
Schema = PropertyDefinitionGenerator.GenerateFromType(typeof(MathResponse)) | ||
} | ||
} | ||
}); | ||
|
||
if (completionResult.Successful) | ||
{ | ||
var response =JsonSerializer.Deserialize<MathResponse>(completionResult.Choices.First().Message.Content!); | ||
foreach (var responseStep in response?.Steps!) | ||
{ | ||
Console.WriteLine(responseStep.Explanation); | ||
Console.WriteLine(responseStep.Output); | ||
} | ||
|
||
Console.WriteLine("Final:" + response.FinalAnswer); | ||
|
||
} | ||
else | ||
{ | ||
if (completionResult.Error == null) | ||
{ | ||
throw new("Unknown Error"); | ||
} | ||
|
||
Console.WriteLine($"{completionResult.Error.Code}: {completionResult.Error.Message}"); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
Console.WriteLine(e); | ||
throw; | ||
} | ||
} | ||
|
||
public class MathResponse | ||
{ | ||
public MathResponse() | ||
{ | ||
Steps = new(); | ||
} | ||
|
||
[JsonPropertyName("steps")] | ||
public List<Step> Steps { get; set; } | ||
|
||
[JsonPropertyName("final_answer")] | ||
public string FinalAnswer { get; set; } | ||
} | ||
|
||
public class Step | ||
{ | ||
[JsonPropertyName("explanation")] | ||
public string Explanation { get; set; } | ||
|
||
[JsonPropertyName("output")] | ||
public string Output { get; set; } | ||
} | ||
} |