Skip to content

Commit

Permalink
Merge pull request #150 from milbk/main
Browse files Browse the repository at this point in the history
Add JsonSchema
  • Loading branch information
awaescher authored Dec 9, 2024
2 parents 699615b + 62aa629 commit 23f0d32
Show file tree
Hide file tree
Showing 4 changed files with 600 additions and 454 deletions.
4 changes: 2 additions & 2 deletions src/Models/Chat/ChatRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public class ChatRequest : OllamaRequest
public string? KeepAlive { get; set; }

/// <summary>
/// Gets or sets the format to return a response in. Currently only accepts "json" or null.
/// Gets or sets the format to return a response in. Currently accepts "json" and JsonSchema or null.
/// </summary>
[JsonPropertyName("format")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Format { get; set; }
public object? Format { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the response will be returned as a single response object rather than a stream of objects.
Expand Down
4 changes: 2 additions & 2 deletions src/Models/Generate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ public class GenerateRequest : OllamaRequest
public string? KeepAlive { get; set; }

/// <summary>
/// The format to return a response in. Currently only accepts "json" or null.
/// Gets or sets the format to return a response in. Currently accepts "json" and JsonSchema or null.
/// </summary>
[JsonPropertyName("format")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Format { get; set; }
public object? Format { get; set; }

/// <summary>
/// If false the response will be returned as a single response object,
Expand Down
146 changes: 146 additions & 0 deletions src/Models/JsonSchema.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.Json.Serialization;

namespace OllamaSharp.Models;

public class JsonSchema
{
/// <summary>
/// Gets or sets the type of the schema, default is "object".
/// </summary>
[JsonPropertyName("type")]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public string? Type { get; set; } = "object";

/// <summary>
/// Gets or sets the properties of the schema.
/// </summary>
[JsonPropertyName("properties")]
public Dictionary<string, Property>? Properties { get; set; }

/// <summary>
/// Gets or sets a list of required fields within the schema.
/// </summary>
[JsonPropertyName("required")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IEnumerable<string>? Required { get; set; }

/// <summary>
/// Get the JsonSchema from Type, use typeof(Class) to get the Type of Class.
/// </summary>

public static JsonSchema ToJsonSchema(Type type)
{
var required = new List<string>();
var properties = new Dictionary<string, Property>();
foreach (var property in type.GetProperties())
{
var propertyName = property.Name;
var propertyType = property.PropertyType;

var isEnumerable = type.IsArray || (typeof(IEnumerable).IsAssignableFrom(propertyType) && propertyType != typeof(string));
var isNullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);

properties.Add(propertyName,
new Property
{
Type = GetTypeName(propertyType),
Items = isEnumerable
? new Item
{
Type = GetTypeName(propertyType.IsArray
? propertyType.GetElementType()
: propertyType.GetGenericArguments().First())
}
: null
});

if (!isNullable)
required.Add(propertyName);
}

return new JsonSchema { Properties = properties, Required = required };
}

private static string GetTypeName(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var underlyingType = type.GetGenericArguments().First();
return GetTypeName(underlyingType);
}

var typeCode = System.Type.GetTypeCode(type);

switch (typeCode)
{
case TypeCode.Int32:
case TypeCode.Int16:
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return "integer";
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return "number";
case TypeCode.Boolean:
return "boolean";
case TypeCode.String:
return "string";
case TypeCode.Object:
if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type))
return "array";
return "object";
default:
return "object";
}
}
}

public class Property
{
/// <summary>
/// Gets or sets the type of the property.
/// </summary>
[JsonPropertyName("type")]
public string? Type { get; set; }

/// <summary>
/// Gets or sets the items of the property.
/// </summary>
[JsonPropertyName("items")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Item? Items { get; set; }

/// <summary>
/// Gets or sets the description of the property.
/// </summary>
[JsonPropertyName("description")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Description { get; set; }

/// <summary>
/// Gets or sets the Enum of the property.
/// </summary>
[JsonPropertyName("enum")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<string>? Enum { get; set; }
}

public class Item
{
/// <summary>
/// Gets or sets the type of the item.
/// </summary>
[JsonPropertyName("type")]
public string? Type { get; set; }
}
Loading

0 comments on commit 23f0d32

Please sign in to comment.