-
Notifications
You must be signed in to change notification settings - Fork 7
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
Showing
6 changed files
with
150 additions
and
9 deletions.
There are no files selected for viewing
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
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,76 @@ | ||
# frozen_string_literal: true | ||
|
||
require "active_support/core_ext/object/deep_dup" | ||
|
||
module Raix | ||
# Handles the formatting of responses for AI interactions. | ||
# | ||
# This class is responsible for converting input data into a JSON schema | ||
# that can be used to structure and validate AI responses. It supports | ||
# nested structures and arrays, ensuring that the output conforms to | ||
# the expected format for AI model interactions. | ||
# | ||
# @example | ||
# input = { name: { type: "string" }, age: { type: "integer" } } | ||
# format = ResponseFormat.new("PersonInfo", input) | ||
# schema = format.to_schema | ||
# | ||
# @attr_reader [String] name The name of the response format | ||
# @attr_reader [Hash] input The input data to be formatted | ||
class ResponseFormat | ||
def initialize(name, input) | ||
@name = name | ||
@input = input | ||
end | ||
|
||
def to_json(*) | ||
JSON.pretty_generate(to_schema) | ||
end | ||
|
||
def to_schema | ||
{ | ||
type: "json_schema", | ||
json_schema: { | ||
name: @name, | ||
schema: { | ||
type: "object", | ||
properties: decode(@input.deep_dup), | ||
required: @input.keys, | ||
additionalProperties: false | ||
}, | ||
strict: true | ||
} | ||
} | ||
end | ||
|
||
private | ||
|
||
def decode(input) | ||
{}.tap do |response| | ||
case input | ||
when Array | ||
properties = {} | ||
input.each { |item| properties.merge!(decode(item)) } | ||
|
||
response[:type] = "array" | ||
response[:items] = { | ||
type: "object", | ||
properties:, | ||
required: properties.keys.select { |key| properties[key].delete(:required) }, | ||
additionalProperties: false | ||
} | ||
when Hash | ||
input.each do |key, value| | ||
response[key] = if value.is_a?(Hash) && value.key?(:type) | ||
value | ||
else | ||
decode(value) | ||
end | ||
end | ||
else | ||
raise "Invalid input" | ||
end | ||
end | ||
end | ||
end | ||
end |
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
module Raix | ||
VERSION = "0.4.0" | ||
VERSION = "0.4.1" | ||
end |
This file was deleted.
Oops, something went wrong.
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,70 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe Raix::ResponseFormat do | ||
let(:input) do | ||
{ | ||
observations: [ | ||
{ | ||
brief: { | ||
type: "string", | ||
description: "brief description of the observation", | ||
required: true | ||
}, | ||
content: { | ||
type: "string", | ||
description: "content of the observation", | ||
required: true | ||
}, | ||
importance: { | ||
type: "integer", | ||
description: "importance of the observation", | ||
required: true | ||
} | ||
} | ||
] | ||
} | ||
end | ||
|
||
let(:rf) { described_class.new("observations", input) } | ||
|
||
xit "matches the expected schema" do | ||
json = JSON.pretty_generate({ | ||
"type": "json_schema", | ||
"json_schema": { | ||
"name": "observations", | ||
"schema": { | ||
"type": "object", | ||
"properties": { | ||
"observations": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"brief": { | ||
"type": "string", | ||
"description": "brief description of the observation" | ||
}, | ||
"content": { | ||
"type": "string", | ||
"description": "content of the observation" | ||
}, | ||
"importance": { | ||
"type": "integer", | ||
"description": "importance of the observation" | ||
} | ||
}, | ||
"required": %w[brief content importance], | ||
"additionalProperties": false | ||
} | ||
} | ||
}, | ||
"required": ["observations"], | ||
"additionalProperties": false | ||
}, | ||
"strict": true | ||
} | ||
}) | ||
|
||
expect(rf.to_json.squish).to eq(json.squish) | ||
end | ||
end |