Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utilities update 8.1.0 #621

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions OpenAI.Utilities/FunctionCalling/PropertyDefinitionGenerator.cs
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;
}
}
6 changes: 3 additions & 3 deletions OpenAI.Utilities/OpenAI.Utilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageProjectUrl>https://openai.com/</PackageProjectUrl>
<PackageIcon>OpenAI-Betalgo.png</PackageIcon>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>8.0.1</Version>
<Version>8.1.0</Version>
<Authors>Tolga Kayhan, Betalgo</Authors>
<Company>Betalgo Up Ltd.</Company>
<Product>Utility tools for Betalgo.OpenAI</Product>
Expand Down Expand Up @@ -40,8 +40,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Betalgo.OpenAI" Version="*"/>
<PackageReference Include="CsvHelper" Version="31.0.3" />
<PackageReference Include="Betalgo.OpenAI" Version="8.6.2" />
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Microsoft.Data.Analysis" Version="0.21.1" />
</ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion OpenAI.UtilitiesPlayground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@


//await EmbeddingTestHelpers.ExerciseEmbeddingTools(sdk);
await FunctionCallingTestHelpers.ExerciseFunctionCalling(sdk);
//await FunctionCallingTestHelpers.ExerciseFunctionCalling(sdk);
await JsonSchemaResponseTypeTestHelpers.RunChatWithJsonSchemaResponseFormat2(sdk);

Console.WriteLine("Press any key to exit...");
Console.ReadKey();
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; }
}
}
Loading