Skip to content

Commit

Permalink
fix load issue. response format wip
Browse files Browse the repository at this point in the history
  • Loading branch information
obie committed Oct 22, 2024
1 parent 8809ccb commit a6ce43e
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/raix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "raix/chat_completion"
require_relative "raix/function_dispatch"
require_relative "raix/prompt_declarations"
require_relative "raix/response_format"

# The Raix module provides configuration options for the Raix gem.
module Raix
Expand Down
3 changes: 2 additions & 1 deletion lib/raix/chat_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

require "active_support/concern"
require "active_support/core_ext/object/blank"
require "raix/message_adapters/base"
require "open_router"
require "openai"

require_relative "message_adapters/base"

module Raix
# The `ChatCompletion`` module is a Rails concern that provides a way to interact
# with the OpenRouter Chat Completion API via its client. The module includes a few
Expand Down
76 changes: 76 additions & 0 deletions lib/raix/response_format.rb
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
2 changes: 1 addition & 1 deletion lib/raix/version.rb
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
7 changes: 0 additions & 7 deletions spec/raix/rails_spec.rb

This file was deleted.

70 changes: 70 additions & 0 deletions spec/raix/response_format_spec.rb
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

0 comments on commit a6ce43e

Please sign in to comment.