A powerful Ruby gem for generating content using Google's Gemini AI with advanced features like streaming, function calling, intelligent caching, and Rails integration.
- π€ Simple Content Generation - Easy-to-use interface for Gemini AI
- π Streaming Support - Real-time content generation for better UX
- π§ Function Calling - Enable AI to call your Ruby functions/APIs
- π Enhanced Caching - Intelligent caching with automatic cleanup
- π Comprehensive Error Handling - Specific error types for better debugging
- π Rails Integration - Built-in Rails logger support
- β‘ Connection Pooling - Optimized for high-throughput applications
- π Automatic Retries - Smart retry logic for failed requests
- π‘οΈ Thread Safe - Safe for concurrent usage
Add this line to your application's Gemfile:
gem 'gemini_craft'And then execute:
$ bundle installOr install it yourself as:
$ gem install gemini_craftGet your Gemini API key from Google AI Studio.
require 'gemini_craft'
GeminiCraft.configure do |config|
config.api_key = 'your-gemini-api-key'
# Or set the GEMINI_API_KEY environment variable
endresponse = GeminiCraft.generate_content("Write a haiku about Ruby programming")
puts responseGeminiCraft.configure do |config|
config.api_key = 'your-gemini-api-key'
config.model = 'gemini-2.0-flash' # Default model
config.timeout = 30 # Request timeout in seconds
config.max_retries = 3 # Number of retry attempts
endGeminiCraft.configure do |config|
# Authentication
config.api_key = 'your-gemini-api-key'
# Model Configuration
config.model = 'gemini-2.0-flash'
config.api_base_url = 'https://generativelanguage.googleapis.com/v1beta'
# Performance & Reliability
config.timeout = 45
config.max_retries = 5
config.connection_pool_size = 10
config.keep_alive_timeout = 60
# Caching
config.cache_enabled = true
config.cache_ttl = 3600 # 1 hour
# Logging (Rails integration)
config.logger = Rails.logger
config.log_level = :info
# Features
config.streaming_enabled = true
end# Set your API key
export GEMINI_API_KEY="your-api-key-here"# Simple text generation
response = GeminiCraft.generate_content("Explain quantum computing in simple terms")
puts response
# With system instruction
system_instruction = "You are a helpful coding assistant. Be concise and practical."
response = GeminiCraft.generate_content(
"How do I sort an array in Ruby?",
system_instruction
)
puts response
# With custom options
options = {
temperature: 0.7, # Creativity level (0.0 - 1.0)
topK: 40, # Consider top K tokens
topP: 0.95, # Nucleus sampling
maxOutputTokens: 1024 # Maximum response length
}
response = GeminiCraft.generate_content(
"Write a creative story about AI",
"You are a creative writer",
options
)
puts responsePerfect for real-time applications like chatbots or live content generation:
# Method 1: Using stream_content
puts "Generating story (streaming):"
stream = GeminiCraft.stream_content("Tell me an adventure story")
stream.each do |chunk|
print chunk
$stdout.flush
sleep(0.02) # Optional: Add slight delay for visual effect
end
puts "\n"
# Method 2: Using generate_content with stream option
GeminiCraft.generate_content(
"Explain machine learning",
stream: true
).each do |chunk|
print chunk
$stdout.flush
end
# Method 3: Collect all chunks
chunks = []
GeminiCraft.stream_content("Write a poem").each { |chunk| chunks << chunk }
full_response = chunks.join
puts full_responseEnable AI to call your Ruby functions/APIs:
# Define available functions
functions = [
{
name: "get_current_weather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "Temperature unit"
}
},
required: ["location"]
}
},
{
name: "calculate_tip",
description: "Calculate tip amount for a bill",
parameters: {
type: "object",
properties: {
bill_amount: {
type: "number",
description: "The total bill amount"
},
tip_percentage: {
type: "number",
description: "Tip percentage (default: 18)"
}
},
required: ["bill_amount"]
}
}
]
# Generate content with function calling
result = GeminiCraft.generate_with_functions(
"What's the weather like in Tokyo? Also calculate 18% tip for a $50 bill.",
functions,
"You are a helpful assistant that can check weather and calculate tips."
)
puts "AI Response: #{result[:content]}"
# Handle function calls
result[:function_calls].each do |call|
case call[:name]
when "get_current_weather"
location = call[:args]["location"]
unit = call[:args]["unit"] || "celsius"
# Call your weather API here
puts "π€οΈ Would call weather API for #{location} in #{unit}"
when "calculate_tip"
bill = call[:args]["bill_amount"]
tip_pct = call[:args]["tip_percentage"] || 18
tip = (bill * tip_pct / 100).round(2)
puts "π° Tip calculation: $#{bill} * #{tip_pct}% = $#{tip}"
end
endFor more control over the client instance:
client = GeminiCraft.client
# Standard generation
response = client.generate_content("Hello, how are you?")
puts response
# With system instruction and options
response = client.generate_content(
"Explain Ruby blocks",
"You are a Ruby expert who teaches with examples",
{ temperature: 0.3, maxOutputTokens: 500 }
)
puts response
# Function calling with client
result = client.generate_with_functions(
"What's 15% tip on $80?",
[tip_function],
"You are a helpful calculator"
)Intelligent caching for improved performance:
# Enable caching in configuration
GeminiCraft.configure do |config|
config.cache_enabled = true
config.cache_ttl = 1800 # 30 minutes
end
# Same requests will be cached
response1 = GeminiCraft.generate_content("What is Ruby?")
response2 = GeminiCraft.generate_content("What is Ruby?") # Served from cache
# Check cache statistics
stats = GeminiCraft.cache_stats
puts "Cache entries: #{stats[:size]}"
puts "Oldest entry: #{Time.at(stats[:oldest_entry]) if stats[:oldest_entry]}"
puts "Newest entry: #{Time.at(stats[:newest_entry]) if stats[:newest_entry]}"
# Clear cache manually
GeminiCraft.clear_cache
puts "Cache cleared!"Comprehensive error handling with specific error types:
begin
response = GeminiCraft.generate_content("Hello there!")
puts response
rescue GeminiCraft::AuthenticationError => e
puts "β Authentication failed: #{e.message}"
puts "Please check your API key"
rescue GeminiCraft::RateLimitError => e
puts "β° Rate limit exceeded: #{e.message}"
puts "Please wait before making more requests"
rescue GeminiCraft::TimeoutError => e
puts "β±οΈ Request timed out: #{e.message}"
puts "Try increasing the timeout or check your connection"
rescue GeminiCraft::ConnectionError => e
puts "π Connection failed: #{e.message}"
puts "Please check your internet connection"
rescue GeminiCraft::ServerError => e
puts "π§ Server error: #{e.message}"
puts "The API service may be temporarily unavailable"
rescue GeminiCraft::APIError => e
puts "π¨ API error: #{e.message}"
rescue StandardError => e
puts "π₯ Unexpected error: #{e.message}"
endPerfect integration with Ruby on Rails applications:
# config/initializers/gemini_craft.rb
GeminiCraft.configure do |config|
config.api_key = Rails.application.credentials.gemini_api_key
config.logger = Rails.logger
config.log_level = Rails.env.production? ? :warn : :info
config.cache_enabled = Rails.env.production?
config.cache_ttl = 30.minutes
config.timeout = 45
config.max_retries = 5
end
# In your controllers
class ContentController < ApplicationController
def generate
begin
@content = GeminiCraft.generate_content(
params[:prompt],
"You are a helpful assistant for #{current_user.name}",
{ temperature: 0.7 }
)
render json: { content: @content }
rescue GeminiCraft::RateLimitError
render json: { error: "Rate limit exceeded" }, status: 429
rescue GeminiCraft::APIError => e
Rails.logger.error "Gemini API error: #{e.message}"
render json: { error: "Content generation failed" }, status: 500
end
end
def stream_generate
response.headers['Content-Type'] = 'text/event-stream'
response.headers['Cache-Control'] = 'no-cache'
begin
GeminiCraft.stream_content(params[:prompt]).each do |chunk|
response.stream.write("data: #{chunk}\n\n")
end
ensure
response.stream.close
end
end
end
# In your models
class Article < ApplicationRecord
def generate_summary
return if content.blank?
self.summary = GeminiCraft.generate_content(
"Summarize this article in 2-3 sentences: #{content}",
"You are a professional editor creating concise summaries"
)
end
end
# Background jobs
class ContentGenerationJob < ApplicationJob
def perform(user_id, prompt)
user = User.find(user_id)
content = GeminiCraft.generate_content(
prompt,
"Generate content for #{user.name}",
{ temperature: 0.8, maxOutputTokens: 2000 }
)
user.generated_contents.create!(prompt: prompt, content: content)
rescue GeminiCraft::APIError => e
Rails.logger.error "Content generation failed for user #{user_id}: #{e.message}"
# Handle error (retry, notify user, etc.)
end
end| Option | Default | Description |
|---|---|---|
api_key |
ENV['GEMINI_API_KEY'] |
Your Gemini API key |
model |
'gemini-2.0-flash' |
The Gemini model to use |
api_base_url |
'https://generativelanguage.googleapis.com/v1beta' |
Base URL for the API |
timeout |
30 |
Request timeout in seconds |
cache_enabled |
false |
Enable response caching |
cache_ttl |
3600 |
Cache time-to-live in seconds |
max_retries |
3 |
Number of retry attempts |
logger |
nil |
Logger instance for debugging |
log_level |
:info |
Logging level (:debug, :info, :warn, :error, :fatal) |
streaming_enabled |
false |
Enable streaming support |
connection_pool_size |
5 |
HTTP connection pool size |
keep_alive_timeout |
30 |
Keep-alive timeout for connections |
| Model | Description | Best For |
|---|---|---|
gemini-2.0-flash |
Fast, efficient model | General content generation, chatbots |
gemini-1.5-pro |
Most capable model | Complex reasoning, analysis |
gemini-1.5-flash |
Balanced speed and capability | Most applications |
The gem provides specific error types for better error handling:
GeminiCraft::Error- Base error classGeminiCraft::APIError- General API errorsGeminiCraft::AuthenticationError- Invalid API key or authentication failuresGeminiCraft::AuthorizationError- Access forbidden or permission issuesGeminiCraft::NotFoundError- Model or endpoint not foundGeminiCraft::RateLimitError- Rate limit exceededGeminiCraft::ClientError- Client-side errors (4xx)GeminiCraft::ServerError- Server-side errors (5xx)GeminiCraft::TimeoutError- Request timeoutsGeminiCraft::ConnectionError- Connection failuresGeminiCraft::StreamingError- Streaming-specific errorsGeminiCraft::ResponseError- Response parsing errorsGeminiCraft::ConfigurationError- Configuration errors
# β
Good: Use environment variables
config.api_key = ENV['GEMINI_API_KEY']
# β
Good: Use Rails credentials
config.api_key = Rails.application.credentials.gemini_api_key
# β Bad: Hard-code in source
config.api_key = "your-actual-api-key"# β
Good: Specific error handling
rescue GeminiCraft::RateLimitError
# Implement backoff strategy
rescue GeminiCraft::AuthenticationError
# Log and alert about API key issues
# β Bad: Generic error handling
rescue StandardError
# Too broad, might hide important errors# β
Good: Enable caching for production
GeminiCraft.configure do |config|
config.cache_enabled = Rails.env.production?
config.cache_ttl = 1.hour
end
# β
Good: Cache expensive operations
def generate_analysis(data)
cache_key = "analysis_#{Digest::SHA256.hexdigest(data)}"
Rails.cache.fetch(cache_key, expires_in: 30.minutes) do
GeminiCraft.generate_content("Analyze: #{data}")
end
end# β
Good: Use streaming for long content
def stream_story
GeminiCraft.stream_content("Write a long story").each do |chunk|
ActionCable.server.broadcast("story_channel", { chunk: chunk })
end
end# β
Good: Validate function parameters
def execute_function_call(call)
case call[:name]
when "get_weather"
location = call[:args]["location"]
return "Location required" if location.blank?
WeatherService.new.get_weather(location)
end
end# spec/support/gemini_craft.rb
RSpec.configure do |config|
config.before(:suite) do
GeminiCraft.configure do |config|
config.api_key = "test-api-key"
config.cache_enabled = false
config.logger = Logger.new(IO::NULL)
end
end
end
# In your specs
RSpec.describe ContentGenerator do
before do
allow(GeminiCraft).to receive(:generate_content)
.and_return("Generated content")
end
it "generates content" do
result = subject.generate_summary("test input")
expect(result).to eq("Generated content")
end
end# Gemfile (test group)
gem 'webmock'
# In your test
require 'webmock/rspec'
RSpec.describe "Gemini integration" do
before do
stub_request(:post, /generativelanguage\.googleapis\.com/)
.to_return(
status: 200,
body: {
candidates: [{
content: {
parts: [{ text: "Test response" }]
}
}]
}.to_json
)
end
it "generates content" do
result = GeminiCraft.generate_content("test")
expect(result).to eq("Test response")
end
endThe v0.2.0 release maintains backward compatibility. However, to use new features:
# Old way (still works)
response = GeminiCraft.generate_content("Hello")
# New way with streaming
stream = GeminiCraft.stream_content("Hello")
# New way with function calling
result = GeminiCraft.generate_with_functions("Hello", functions)
# Enhanced error handling
rescue GeminiCraft::RateLimitError # New specific error type- Enable Caching: For production applications to reduce API calls
- Use Streaming: For better user experience with long responses
- Implement Proper Retry Logic: Handle transient failures gracefully
- Monitor Rate Limits: Implement backoff strategies for sustained usage
- Optimize Prompts: Shorter, clearer prompts often work better
- Batch Operations: Group related requests when possible
Authentication Error
# Check your API key
puts ENV['GEMINI_API_KEY'] # Should not be nilRate Limiting
# Implement exponential backoff
rescue GeminiCraft::RateLimitError
sleep(2 ** retry_count)
retry if (retry_count += 1) < 3Timeout Issues
# Increase timeout for complex requests
GeminiCraft.configure { |c| c.timeout = 120 }Caching Problems
# Clear cache if responses seem stale
GeminiCraft.clear_cacheWe welcome contributions! Here's how to get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for your changes
- Ensure all tests pass (
bundle exec rake spec) - Ensure code style is correct (
bundle exec rake rubocop) - Commit your changes (
git commit -am 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Create a Pull Request
git clone https://github.com/shobhits7/gemini_craft.git
cd gemini_craft
bin/setup
bundle exec rake spec# Run all tests
bundle exec rake spec
# Run specific test file
bundle exec rspec spec/gemini_craft/client_spec.rb
# Run with coverage
COVERAGE=true bundle exec rake spec# Check code style
bundle exec rake rubocop
# Auto-fix issues
bundle exec rubocop -aThe gem is available as open source under the terms of the MIT License.
Everyone interacting in the GeminiCraft project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
- GitHub Repository
- RubyGems Page
- Documentation
- Issues & Bug Reports
- Google AI Studio (Get API Key)
- Gemini API Documentation
See CHANGELOG.md for a detailed history of changes.
If you find this gem helpful, please:
- β Star the repository
- π Report bugs
- π‘ Suggest new features
- π Contribute to documentation
- π’ Share with others
Made with β€οΈ by Shobhit Jain and contributors