Last active
November 4, 2023 21:07
-
-
Save nathanborror/c500c4e27a564b638206553d510c509f to your computer and use it in GitHub Desktop.
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
// NEW WAY | |
// Annotate fields directly on the expected response and use an | |
// encoder to convert to a JSONSchema object. | |
public struct MoonPhaseParameters: Codable { | |
@Schema(description: "The location latitude") | |
public var latitude: Double = 0.0 | |
@Schema(description: "The location longitude") | |
public var longitude: Double = 0.0 | |
} | |
ChatFunctionDeclaration( | |
name: "get_moon_phase", | |
description: "Returns the current moon phase for a location given the location's latitude and longitude.", | |
parameters: JSONSchemaEncoder(MoonPhaseParameters()) | |
) |
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
// OLD WAY | |
// Expected response is disconnected from the function declaration. | |
// Forces you to make updates in two locations and keep both in sync. | |
struct MoonPhaseParameters: Codable { | |
public let latitude: Double | |
public let longitude: Double | |
} | |
ChatFunctionDeclaration( | |
name: "get_moon_phase", | |
description: "Returns the current moon phase for a location given the location's latitude and longitude.", | |
parameters: JSONSchema( | |
type: .object, | |
properties: [ | |
"latitude": .init(type: .number, description: "The location latitude"), | |
"longitude": .init(type: .number, description: "The location longitude"), | |
], | |
required: ["latitude", "longitude"] | |
) | |
) |
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
import Foundation | |
import OpenAI | |
func JSONSchemaEncoder<T>(_ instance: T) -> JSONSchema { | |
var properties = [String: JSONSchema.Property]() | |
var required = [String]() | |
let mirror = Mirror(reflecting: instance) | |
for child in mirror.children { | |
if let label = child.label, let schemaInfo = child.value as? any SchemaProtocol { | |
let name = String(label.trimmingPrefix("_")) | |
let type = newJSONSchemaType(schemaInfo.type) | |
let childMirror = Mirror(reflecting: child.value) | |
if childMirror.displayStyle != .optional { | |
required.append(name) | |
} | |
let prop = JSONSchema.Property( | |
type: type, | |
description: schemaInfo.description, | |
format: schemaInfo.format, | |
items: schemaInfo.items, | |
enumValues: schemaInfo.enumValues | |
) | |
properties[name] = prop | |
} | |
} | |
return JSONSchema(type: .object, properties: properties, required: required) | |
} | |
func newJSONSchemaType(_ type: String) -> JSONSchema.JSONType { | |
if type.hasPrefix("Array") { | |
return .array | |
} | |
return .init(rawValue: type.lowercased()) ?? .null | |
} | |
protocol SchemaProtocol { | |
var description: String { get } | |
var format: String? { get } | |
var items: JSONSchema.Items? { get } | |
var required: [String]? { get } | |
var pattern: String? { get } | |
var const: String? { get } | |
var enumValues: [String]? { get } | |
var multipleOf: Int? { get } | |
var minimum: Double? { get } | |
var maximum: Double? { get } | |
var minItems: Int? { get } | |
var maxItems: Int? { get } | |
var uniqueItems: Bool? { get } | |
var type: String { get } | |
} | |
extension Schema: SchemaProtocol { | |
var type: String { | |
String(describing: Value.self) | |
} | |
} | |
@propertyWrapper | |
public struct Schema<Value: Codable>: Codable { | |
public var wrappedValue: Value | |
let description: String | |
let format: String? | |
let items: JSONSchema.Items? | |
let required: [String]? | |
let pattern: String? | |
let const: String? | |
let enumValues: [String]? | |
let multipleOf: Int? | |
let minimum: Double? | |
let maximum: Double? | |
let minItems: Int? | |
let maxItems: Int? | |
let uniqueItems: Bool? | |
init(wrappedValue: Value, description: String, format: String? = nil, items: JSONSchema.Items? = nil, required: [String]? = nil, | |
pattern: String? = nil, const: String? = nil, enumValues: [String]? = nil, multipleOf: Int? = nil, | |
minimum: Double? = nil, maximum: Double? = nil, minItems: Int? = nil, maxItems: Int? = nil, uniqueItems: Bool? = nil) { | |
self.wrappedValue = wrappedValue | |
self.description = description | |
self.format = format | |
self.items = items | |
self.required = required | |
self.pattern = pattern | |
self.const = const | |
self.enumValues = enumValues | |
self.multipleOf = multipleOf | |
self.minimum = minimum | |
self.maximum = maximum | |
self.minItems = minItems | |
self.maxItems = maxItems | |
self.uniqueItems = uniqueItems | |
} | |
public init(from decoder: Decoder) throws { | |
let container = try decoder.singleValueContainer() | |
wrappedValue = try container.decode(Value.self) | |
description = "" | |
format = nil | |
items = nil | |
required = nil | |
pattern = nil | |
const = nil | |
enumValues = nil | |
multipleOf = nil | |
minimum = nil | |
maximum = nil | |
minItems = nil | |
maxItems = nil | |
uniqueItems = nil | |
} | |
public func encode(to encoder: Encoder) throws { | |
var container = encoder.singleValueContainer() | |
try container.encode(wrappedValue) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment