Rach
A lightweight Ruby framework for OpenAI interactions, focusing on simplicity and clean design.
Installation
Add this line to your application's Gemfile:
gem 'rach'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install rach
Usage
Basic Chat
require 'rach'
client = Rach::Client.new(access_token: YOUR_OPENAI_API_KEY, model: "gpt-4o")
response = client.chat("Hello, how are you?")
puts response.content
# => "Hello! I'm just a computer program, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?"
Conversations
Rach supports stateful conversations with memory:
require 'rach'
client = Rach::Client.new(access_token: YOUR_OPENAI_API_KEY, model: "gpt-4o")
convo = Rach::Conversation.new
convo.system "You teach the German language."
convo.user "Translate: There are two birds singing outside my window."
response = client.chat(convo)
response.content
# => "Es gibt zwei Vögel, die draußen vor meinem Fenster singen."
# Continue the conversation...
convo.add_response(response)
convo.user "What are the verbs in your translation?"
response = client.chat(convo)
response.content
# => "The verbs in the translation \"Es gibt zwei Vögel, die vor meinem Fenster singen\" are \"gibt\" and \"singen.\""
# Remove the last message from the conversation history and continue
convo.pop
convo.user "Explain the structure of your translation."
response = client.chat(convo)
response.content
# => "Your last message to me was: \"Translate: There are two birds singing outside my window.\""
Response Formatting
Define structured response schemas for type-safe AI responses:
class GermanTranslatorSchema
include Rach::ResponseFormat
def explain_structure
object do
array :structure_explanation do
items type: :string
description "A step by step explanation of the structure of the translation."
end
string :final_translation
end
end
end
response = client.chat(convo, response_format: GermanTranslatorSchema.render(:explain_structure))
JSON.load(response.content)
# => {"structure_explanation"=> ["The phrase starts with 'Es gibt' which translates to 'There are'. 'Es' is a pronoun that means 'it', and 'gibt' is the third person singular form of the verb 'geben' (to give), meaning 'there are' in this context.", "'zwei Vögel' means 'two birds'. 'zwei' is the number 'two' and 'Vögel' is the plural form of 'Vogel' (bird).", "The relative clause 'die draußen vor meinem Fenster singen' describes the birds. 'die' is a relative pronoun meaning 'that' or 'which',' 'draußen' means 'outside', and 'vor meinem Fenster' means 'in front of my window'.", "'singen' is the infinitive form of the verb 'sing' (to sing). It tells us what the birds are doing."], "final_translation"=>"Es gibt zwei Vögel, die draußen vor meinem Fenster singen."}
Function Calling / Tools
Rach supports OpenAI's function calling feature:
class GetWeather
include Rach::Function
def function_name
"get_current_weather"
end
def function_description
"Get the current weather in a given location"
end
def schema
object do
string :location, description: "The city and state, e.g. San Francisco, CA"
string :unit, enum: %w[celsius fahrenheit]
end
end
def execute(location:, unit: "fahrenheit")
# Implementation of weather fetching logic
"The weather in #{location} is nice 🌞 #{unit}"
end
end
response = client.chat("What is the weather in San Francisco?", tools: [GetWeather.function_schema])
response.tool_calls
# => [{"id"=>"call_8v3MuUICwn0AjPRy1wZMCXtf",
# "type"=>"function",
# "function"=>{"name"=>"get_current_weather", "arguments"=>"{\"location\":\"San Francisco, CA\",\"unit\":\"celsius\"}"}}]
Multiple Providers
Rach supports using multiple providers in your application. You can configure different providers and their parameters when creating a client:
client = Rach::Client.new(
providers: {
openai: {
access_token: YOUR_OPENAI_API_KEY
},
anthropic: {
access_token: YOUR_ANTHROPIC_API_KEY
}
}
)
# Use specific provider
response = client.chat("Hello!", model: "gpt-4o")
puts response.content
# Switch to another provider
response = client.chat("Hi there!", model: "claude-3-5-sonnet-20241022")
puts response.content
Logging
Rach supports logging of API calls and their parameters. You can provide any logger that responds to the info
method:
require 'logger'
# Create a logger that writes to STDOUT
logger = Logger.new(STDOUT)
# Pass the logger when creating the client
client = Rach::Client.new(
access_token: YOUR_OPENAI_API_KEY,
model: "gpt-4",
logger: logger
)
# Now when you make API calls, parameters will be logged
client.chat("Hello!")
# [2024-01-20T10:30:00.000Z] INFO: Making API call to openai
# [2024-01-20T10:30:00.000Z] INFO: Request parameters: {:model=>"gpt-4", :messages=>[{:role=>"user", :content=>"Hello!"}], :temperature=>1.0}
You can also use your own custom logger as long as it responds to the info
method:
class CustomLogger
def info()
puts "[RACH] #{}"
end
end
client = Rach::Client.new(
access_token: YOUR_OPENAI_API_KEY,
model: "gpt-4",
logger: CustomLogger.new
)
License
Rach is available as open source under the terms of the MIT License.