0.0
The project is in a healthy, maintained state
GeminiCraft provides a simple and robust interface to generate content using Google's Gemini AI models with support for streaming, function calling, and advanced caching
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 2.8
~> 3.12
~> 1.50
~> 0.22
~> 3.18
~> 0.9

Runtime

 Project Readme

GeminiCraft ๐Ÿš€

Gem Version Ruby License: MIT

A powerful Ruby gem for generating content using Google's Gemini AI with advanced features like streaming, function calling, intelligent caching, and Rails integration.

โœจ Features

  • ๐Ÿค– 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

๐Ÿ“ฆ Installation

Add this line to your application's Gemfile:

gem 'gemini_craft'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install gemini_craft

๐Ÿ”‘ Getting Started

1. Get Your API Key

Get your Gemini API key from Google AI Studio.

2. Basic Configuration

require 'gemini_craft'

GeminiCraft.configure do |config|
  config.api_key = 'your-gemini-api-key'
  # Or set the GEMINI_API_KEY environment variable
end

3. Generate Your First Content

response = GeminiCraft.generate_content("Write a haiku about Ruby programming")
puts response

๐Ÿ”ง Configuration

Basic Configuration

GeminiCraft.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
end

Advanced Configuration

GeminiCraft.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

Environment Variables

# Set your API key
export GEMINI_API_KEY="your-api-key-here"

๐Ÿš€ Usage Examples

Basic Content Generation

# 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 response

๐ŸŒŠ Streaming Content

Perfect 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_response

๐Ÿ”ง Function Calling

Enable 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
end

๐Ÿ”„ Using the Client Directly

For 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"
)

๐Ÿ“Š Cache Management

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!"

๐Ÿ›ก๏ธ Error Handling

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}"
end

๐Ÿ”ง Rails Integration

Perfect 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

โš™๏ธ Configuration Options

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

๐Ÿ—๏ธ Available Models

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

๐Ÿšจ Error Types

The gem provides specific error types for better error handling:

  • GeminiCraft::Error - Base error class
  • GeminiCraft::APIError - General API errors
  • GeminiCraft::AuthenticationError - Invalid API key or authentication failures
  • GeminiCraft::AuthorizationError - Access forbidden or permission issues
  • GeminiCraft::NotFoundError - Model or endpoint not found
  • GeminiCraft::RateLimitError - Rate limit exceeded
  • GeminiCraft::ClientError - Client-side errors (4xx)
  • GeminiCraft::ServerError - Server-side errors (5xx)
  • GeminiCraft::TimeoutError - Request timeouts
  • GeminiCraft::ConnectionError - Connection failures
  • GeminiCraft::StreamingError - Streaming-specific errors
  • GeminiCraft::ResponseError - Response parsing errors
  • GeminiCraft::ConfigurationError - Configuration errors

๐ŸŽฏ Best Practices

1. API Key Security

# โœ… 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"

2. Error Handling

# โœ… 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

3. Caching Strategy

# โœ… 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

4. Streaming for Better UX

# โœ… 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

5. Function Calling

# โœ… 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

๐Ÿงช Testing

RSpec Integration

# 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

WebMock for Testing

# 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
end

๐Ÿ”„ Migration from v0.1.x

The 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

๐Ÿš€ Performance Tips

  1. Enable Caching: For production applications to reduce API calls
  2. Use Streaming: For better user experience with long responses
  3. Implement Proper Retry Logic: Handle transient failures gracefully
  4. Monitor Rate Limits: Implement backoff strategies for sustained usage
  5. Optimize Prompts: Shorter, clearer prompts often work better
  6. Batch Operations: Group related requests when possible

๐Ÿ“‹ Troubleshooting

Common Issues

Authentication Error

# Check your API key
puts ENV['GEMINI_API_KEY'] # Should not be nil

Rate Limiting

# Implement exponential backoff
rescue GeminiCraft::RateLimitError
  sleep(2 ** retry_count)
  retry if (retry_count += 1) < 3

Timeout Issues

# Increase timeout for complex requests
GeminiCraft.configure { |c| c.timeout = 120 }

Caching Problems

# Clear cache if responses seem stale
GeminiCraft.clear_cache

๐Ÿค Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for your changes
  5. Ensure all tests pass (bundle exec rake spec)
  6. Ensure code style is correct (bundle exec rake rubocop)
  7. Commit your changes (git commit -am 'Add amazing feature')
  8. Push to the branch (git push origin feature/amazing-feature)
  9. Create a Pull Request

Development Setup

git clone https://github.com/shobhits7/gemini_craft.git
cd gemini_craft
bin/setup
bundle exec rake spec

Running Tests

# 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

Code Style

# Check code style
bundle exec rake rubocop

# Auto-fix issues
bundle exec rubocop -a

๐Ÿ“„ License

The gem is available as open source under the terms of the MIT License.

๐Ÿ† Code of Conduct

Everyone interacting in the GeminiCraft project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

๐Ÿ”— Links

๐Ÿ“ˆ Changelog

See CHANGELOG.md for a detailed history of changes.

โค๏ธ Support

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