ruby_llm 0.1.0.pre42 â 0.1.0.pre44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.rspec_status +4 -4
 - data/README.md +82 -380
 - data/lib/ruby_llm/image.rb +26 -3
 - data/lib/ruby_llm/provider.rb +10 -0
 - data/lib/ruby_llm/providers/anthropic/media.rb +5 -2
 - data/lib/ruby_llm/providers/gemini/images.rb +6 -5
 - data/lib/ruby_llm/providers/openai/images.rb +1 -0
 - data/lib/ruby_llm/version.rb +1 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 519b87700f2ba3d5aeb8ea3a87d0881f4ef58f974991647b7af4c9f138cbf3d2
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 553b6441ad59fe5efe6d51374103690101c2cb8d072f91bf2a850d84b4934601
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: e52cb96479a0f4443521bf3b5b2e98c882fb1c404e3d1527c74f638137bf56c2cb9442cc6e30ef197157fbdaa7dc189b7f6331a31e6f31ddfa28a926035d6578
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b1d7948851e6c1ffa5257e214f01e6d6efaf64d32d98dcc66ec8f5d6776df232a92b3b26ff1de78889f4195ff27e41dc7375a4b2530dc1b97edc8fd57bb2c835
         
     | 
    
        data/.rspec_status
    CHANGED
    
    | 
         @@ -35,7 +35,7 @@ example_id                                         | status | run_time        | 
     | 
|
| 
       35 
35 
     | 
    
         
             
            ./spec/ruby_llm/embeddings_spec.rb[1:1:2:1]        | passed | 0.65614 seconds |
         
     | 
| 
       36 
36 
     | 
    
         
             
            ./spec/ruby_llm/embeddings_spec.rb[1:1:2:2]        | passed | 2.16 seconds    |
         
     | 
| 
       37 
37 
     | 
    
         
             
            ./spec/ruby_llm/error_handling_spec.rb[1:1]        | passed | 0.29366 seconds |
         
     | 
| 
       38 
     | 
    
         
            -
            ./spec/ruby_llm/image_generation_spec.rb[1:1:1]    | passed |  
     | 
| 
       39 
     | 
    
         
            -
            ./spec/ruby_llm/image_generation_spec.rb[1:1:2]    | passed |  
     | 
| 
       40 
     | 
    
         
            -
            ./spec/ruby_llm/image_generation_spec.rb[1:1:3]    | passed |  
     | 
| 
       41 
     | 
    
         
            -
            ./spec/ruby_llm/image_generation_spec.rb[1:1:4]    | passed | 0. 
     | 
| 
      
 38 
     | 
    
         
            +
            ./spec/ruby_llm/image_generation_spec.rb[1:1:1]    | passed | 24.16 seconds   |
         
     | 
| 
      
 39 
     | 
    
         
            +
            ./spec/ruby_llm/image_generation_spec.rb[1:1:2]    | passed | 14.81 seconds   |
         
     | 
| 
      
 40 
     | 
    
         
            +
            ./spec/ruby_llm/image_generation_spec.rb[1:1:3]    | passed | 9.17 seconds    |
         
     | 
| 
      
 41 
     | 
    
         
            +
            ./spec/ruby_llm/image_generation_spec.rb[1:1:4]    | passed | 0.00083 seconds |
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # RubyLLM
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            A delightful Ruby way to work with AI.  
     | 
| 
      
 3 
     | 
    
         
            +
            A delightful Ruby way to work with AI. No configuration madness, no complex callbacks, no handler hell â just beautiful, expressive Ruby code.
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            <p align="center">
         
     | 
| 
       6 
6 
     | 
    
         
             
              <img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/OpenAI_Logo.svg" alt="OpenAI" height="40" width="120">
         
     | 
| 
         @@ -15,462 +15,164 @@ A delightful Ruby way to work with AI. Chat in text, analyze and generate images 
     | 
|
| 
       15 
15 
     | 
    
         
             
            <p align="center">
         
     | 
| 
       16 
16 
     | 
    
         
             
              <a href="https://badge.fury.io/rb/ruby_llm"><img src="https://badge.fury.io/rb/ruby_llm.svg" alt="Gem Version" /></a>
         
     | 
| 
       17 
17 
     | 
    
         
             
              <a href="https://github.com/testdouble/standard"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Ruby Style Guide" /></a>
         
     | 
| 
       18 
     | 
    
         
            -
              <a href="https://rubygems.org/gems/ruby_llm"><img alt="Gem  
     | 
| 
      
 18 
     | 
    
         
            +
              <a href="https://rubygems.org/gems/ruby_llm"><img alt="Gem Downloads" src="https://img.shields.io/gem/dt/ruby_llm"></a>
         
     | 
| 
       19 
19 
     | 
    
         
             
              <a href="https://codecov.io/gh/crmne/ruby_llm"><img src="https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg" alt="codecov" /></a>
         
     | 
| 
       20 
20 
     | 
    
         
             
            </p>
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            ðĪš Battle tested at [ðŽ  Chat with Work](https://chatwithwork.com)
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            ##  
     | 
| 
      
 24 
     | 
    
         
            +
            ## The problem with AI libraries
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
            - ðĩ **Audio Analysis** - Get audio transcription and understanding with `chat.ask "what's said here?", with: { audio: "clip.wav" }`
         
     | 
| 
       28 
     | 
    
         
            -
            - ðïļ **Vision Understanding** - Let AIs analyze images with a simple `chat.ask "what's in this?", with: { image: "photo.jpg" }`
         
     | 
| 
       29 
     | 
    
         
            -
            - ð **Streaming** - Real-time responses with proper Ruby streaming with `chat.ask "hello" do |chunk| puts chunk.content end`
         
     | 
| 
       30 
     | 
    
         
            -
            - ð **PDF Analysis** - Analyze PDF documents directly with `chat.ask "What's in this?", with: { pdf: "document.pdf" }`
         
     | 
| 
       31 
     | 
    
         
            -
            - ð **Rails Integration** - Persist chats and messages with ActiveRecord with `acts_as_{chat|message|tool_call}`
         
     | 
| 
       32 
     | 
    
         
            -
            - ð ïļ **Tool Support** - Give AIs access to your Ruby code with `chat.with_tool(Calculator).ask "what's 2+2?"`
         
     | 
| 
       33 
     | 
    
         
            -
            - ðĻ **Paint with AI** - Create images as easily as `RubyLLM.paint "a sunset over mountains"`
         
     | 
| 
       34 
     | 
    
         
            -
            - ð **Embeddings** - Generate vector embeddings for your text with `RubyLLM.embed "hello"`
         
     | 
| 
       35 
     | 
    
         
            -
            - ð **Multi-Provider Support** - Works with OpenAI, Anthropic, Google, and DeepSeek
         
     | 
| 
       36 
     | 
    
         
            -
            - ðŊ **Token Tracking** - Automatic usage tracking across providers
         
     | 
| 
      
 26 
     | 
    
         
            +
            Every AI provider comes with its own client library, its own response format, its own conventions for streaming, and its own way of handling errors. Want to use multiple providers? Prepare to juggle incompatible APIs and bloated dependencies.
         
     | 
| 
       37 
27 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
            Add it to your Gemfile:
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       43 
     | 
    
         
            -
            gem 'ruby_llm'
         
     | 
| 
       44 
     | 
    
         
            -
            ```
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            Or install it yourself:
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
            ```bash
         
     | 
| 
       49 
     | 
    
         
            -
            gem install ruby_llm
         
     | 
| 
       50 
     | 
    
         
            -
            ```
         
     | 
| 
      
 28 
     | 
    
         
            +
            RubyLLM fixes all that. One beautiful API for everything. One consistent format. Minimal dependencies â just Faraday and Zeitwerk. Because working with AI should be a joy, not a chore.
         
     | 
| 
       51 
29 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
            ##  
     | 
| 
      
 30 
     | 
    
         
            +
            ## What makes it great
         
     | 
| 
       53 
31 
     | 
    
         | 
| 
       54 
32 
     | 
    
         
             
            ```ruby
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
            # Configure your API keys
         
     | 
| 
       58 
     | 
    
         
            -
            RubyLLM.configure do |config|
         
     | 
| 
       59 
     | 
    
         
            -
              config.openai_api_key = ENV['OPENAI_API_KEY']
         
     | 
| 
       60 
     | 
    
         
            -
              config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
         
     | 
| 
       61 
     | 
    
         
            -
              config.gemini_api_key = ENV['GEMINI_API_KEY']
         
     | 
| 
       62 
     | 
    
         
            -
              config.deepseek_api_key = ENV['DEEPSEEK_API_KEY']
         
     | 
| 
       63 
     | 
    
         
            -
            end
         
     | 
| 
       64 
     | 
    
         
            -
            ```
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
            ## Quick Start
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
            RubyLLM makes it dead simple to start chatting with AI models:
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       71 
     | 
    
         
            -
            # Start a conversation
         
     | 
| 
      
 33 
     | 
    
         
            +
            # Just ask questions
         
     | 
| 
       72 
34 
     | 
    
         
             
            chat = RubyLLM.chat
         
     | 
| 
       73 
35 
     | 
    
         
             
            chat.ask "What's the best way to learn Ruby?"
         
     | 
| 
       74 
     | 
    
         
            -
            ```
         
     | 
| 
       75 
36 
     | 
    
         | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
      
 37 
     | 
    
         
            +
            # Analyze images
         
     | 
| 
      
 38 
     | 
    
         
            +
            chat.ask "What's in this image?", with: { image: "ruby_conf.jpg" }
         
     | 
| 
       77 
39 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
      
 40 
     | 
    
         
            +
            # Analyze audio recordings
         
     | 
| 
      
 41 
     | 
    
         
            +
            chat.ask "Describe this meeting", with: { audio: "meeting.wav" }
         
     | 
| 
       79 
42 
     | 
    
         | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
            RubyLLM.models.all
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
            # Get models by type
         
     | 
| 
       85 
     | 
    
         
            -
            chat_models = RubyLLM.models.chat_models
         
     | 
| 
       86 
     | 
    
         
            -
            embedding_models = RubyLLM.models.embedding_models
         
     | 
| 
       87 
     | 
    
         
            -
            audio_models = RubyLLM.models.audio_models
         
     | 
| 
       88 
     | 
    
         
            -
            image_models = RubyLLM.models.image_models
         
     | 
| 
       89 
     | 
    
         
            -
            ```
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
            ## Having a Conversation
         
     | 
| 
      
 43 
     | 
    
         
            +
            # Analyze documents
         
     | 
| 
      
 44 
     | 
    
         
            +
            chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
         
     | 
| 
       92 
45 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       96 
     | 
    
         
            -
            chat = RubyLLM.chat model: 'gemini-2.0-flash'
         
     | 
| 
      
 46 
     | 
    
         
            +
            # Generate images
         
     | 
| 
      
 47 
     | 
    
         
            +
            RubyLLM.paint "a sunset over mountains in watercolor style"
         
     | 
| 
       97 
48 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
            #  
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
            # Create vector embeddings
         
     | 
| 
      
 50 
     | 
    
         
            +
            RubyLLM.embed "Ruby is elegant and expressive"
         
     | 
| 
       100 
51 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
            #  
     | 
| 
       102 
     | 
    
         
            -
            chat.ask "Can you elaborate on that?"
         
     | 
| 
       103 
     | 
    
         
            -
            chat.ask "How does that compare to Python?"
         
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
            # Stream responses as they come
         
     | 
| 
       106 
     | 
    
         
            -
            chat.ask "Tell me a story about a Ruby programmer" do |chunk|
         
     | 
| 
       107 
     | 
    
         
            -
              print chunk.content
         
     | 
| 
       108 
     | 
    
         
            -
            end
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
            # Ask about images
         
     | 
| 
       111 
     | 
    
         
            -
            chat.ask "What do you see in this image?", with: { image: "ruby_logo.png" }
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
            # Get analysis of audio content
         
     | 
| 
       114 
     | 
    
         
            -
            chat.ask "What's being said in this recording?", with: { audio: "meeting.wav" }
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
            # Combine multiple pieces of content
         
     | 
| 
       117 
     | 
    
         
            -
            chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
            # Ask about PDFs
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
            chat = RubyLLM.chat(model: 'claude-3-7-sonnet-20250219')
         
     | 
| 
       122 
     | 
    
         
            -
            chat.ask "Summarize this research paper", with: { pdf: "research.pdf" }
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
            # Multiple PDFs work too
         
     | 
| 
       125 
     | 
    
         
            -
            chat.ask "Compare these contracts", with: { pdf: ["contract1.pdf", "contract2.pdf"] }
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
            # Check token usage
         
     | 
| 
       128 
     | 
    
         
            -
            last_message = chat.messages.last
         
     | 
| 
       129 
     | 
    
         
            -
            puts "Conversation used #{last_message.input_tokens} input tokens and #{last_message.output_tokens} output tokens"
         
     | 
| 
       130 
     | 
    
         
            -
            ```
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
            You can provide content as local files or URLs - RubyLLM handles the rest. Vision and audio capabilities are available with compatible models. The API stays clean and consistent whether you're working with text, images, or audio.
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
            ## Image Generation
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
            Want to create AI-generated images? RubyLLM makes it super simple:
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       139 
     | 
    
         
            -
            # Paint a picture!
         
     | 
| 
       140 
     | 
    
         
            -
            image = RubyLLM.paint "a starry night over San Francisco in Van Gogh's style"
         
     | 
| 
       141 
     | 
    
         
            -
            image.url         # => "https://..."
         
     | 
| 
       142 
     | 
    
         
            -
            image.revised_prompt  # Shows how DALL-E interpreted your prompt
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
            # Choose size and model
         
     | 
| 
       145 
     | 
    
         
            -
            image = RubyLLM.paint(
         
     | 
| 
       146 
     | 
    
         
            -
              "a cyberpunk cityscape at sunset",
         
     | 
| 
       147 
     | 
    
         
            -
              model: "dall-e-3",
         
     | 
| 
       148 
     | 
    
         
            -
              size: "1792x1024"
         
     | 
| 
       149 
     | 
    
         
            -
            )
         
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
            # Set your default model
         
     | 
| 
       152 
     | 
    
         
            -
            RubyLLM.configure do |config|
         
     | 
| 
       153 
     | 
    
         
            -
              config.default_image_model = "dall-e-3"
         
     | 
| 
       154 
     | 
    
         
            -
            end
         
     | 
| 
       155 
     | 
    
         
            -
            ```
         
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
            RubyLLM automatically handles all the complexities of the DALL-E API, token/credit management, and error handling, so you can focus on being creative.
         
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
            ## Text Embeddings
         
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
            Need vector embeddings for your text? RubyLLM makes it simple:
         
     | 
| 
       162 
     | 
    
         
            -
             
     | 
| 
       163 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       164 
     | 
    
         
            -
            # Get embeddings with the default model
         
     | 
| 
       165 
     | 
    
         
            -
            RubyLLM.embed "Hello, world!"
         
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
            # Use a specific model
         
     | 
| 
       168 
     | 
    
         
            -
            RubyLLM.embed "Ruby is awesome!", model: "text-embedding-004"
         
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
            # Process multiple texts at once
         
     | 
| 
       171 
     | 
    
         
            -
            RubyLLM.embed([
         
     | 
| 
       172 
     | 
    
         
            -
              "First document",
         
     | 
| 
       173 
     | 
    
         
            -
              "Second document",
         
     | 
| 
       174 
     | 
    
         
            -
              "Third document"
         
     | 
| 
       175 
     | 
    
         
            -
            ])
         
     | 
| 
       176 
     | 
    
         
            -
             
     | 
| 
       177 
     | 
    
         
            -
            # Configure the default model
         
     | 
| 
       178 
     | 
    
         
            -
            RubyLLM.configure do |config|
         
     | 
| 
       179 
     | 
    
         
            -
              config.default_embedding_model = 'text-embedding-3-large'
         
     | 
| 
       180 
     | 
    
         
            -
            end
         
     | 
| 
       181 
     | 
    
         
            -
            ```
         
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
            ## Using Tools
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
            Give your AI assistants access to your Ruby code by creating tool classes that do one thing well:
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
            ```ruby
         
     | 
| 
      
 52 
     | 
    
         
            +
            # Let AI use your code
         
     | 
| 
       188 
53 
     | 
    
         
             
            class Calculator < RubyLLM::Tool
         
     | 
| 
       189 
     | 
    
         
            -
              description "Performs  
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
              param :expression,
         
     | 
| 
       192 
     | 
    
         
            -
                type: :string,
         
     | 
| 
       193 
     | 
    
         
            -
                desc: "A mathematical expression to evaluate (e.g. '2 + 2')"
         
     | 
| 
      
 54 
     | 
    
         
            +
              description "Performs calculations"
         
     | 
| 
      
 55 
     | 
    
         
            +
              param :expression, type: :string, desc: "Math expression to evaluate"
         
     | 
| 
       194 
56 
     | 
    
         | 
| 
       195 
57 
     | 
    
         
             
              def execute(expression:)
         
     | 
| 
       196 
58 
     | 
    
         
             
                eval(expression).to_s
         
     | 
| 
       197 
59 
     | 
    
         
             
              end
         
     | 
| 
       198 
60 
     | 
    
         
             
            end
         
     | 
| 
       199 
61 
     | 
    
         | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
              description "Searches documents by similarity"
         
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
              param :query,
         
     | 
| 
       204 
     | 
    
         
            -
                desc: "The search query"
         
     | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
              param :limit,
         
     | 
| 
       207 
     | 
    
         
            -
                type: :integer,
         
     | 
| 
       208 
     | 
    
         
            -
                desc: "Number of results to return",
         
     | 
| 
       209 
     | 
    
         
            -
                required: false
         
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
              def initialize(repo:)
         
     | 
| 
       212 
     | 
    
         
            -
                @repo = repo
         
     | 
| 
       213 
     | 
    
         
            -
              end
         
     | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
       215 
     | 
    
         
            -
              def execute(query:, limit: 5)
         
     | 
| 
       216 
     | 
    
         
            -
                @repo.similarity_search(query, limit:)
         
     | 
| 
       217 
     | 
    
         
            -
              end
         
     | 
| 
       218 
     | 
    
         
            -
            end
         
     | 
| 
      
 62 
     | 
    
         
            +
            chat.with_tool(Calculator).ask "What's 123 * 456?"
         
     | 
| 
       219 
63 
     | 
    
         
             
            ```
         
     | 
| 
       220 
64 
     | 
    
         | 
| 
       221 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
            ## Installation
         
     | 
| 
       222 
66 
     | 
    
         | 
| 
       223 
67 
     | 
    
         
             
            ```ruby
         
     | 
| 
       224 
     | 
    
         
            -
            #  
     | 
| 
       225 
     | 
    
         
            -
             
     | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
     | 
    
         
            -
            # Tools with dependencies are just regular Ruby objects
         
     | 
| 
       228 
     | 
    
         
            -
            search = Search.new repo: Document
         
     | 
| 
       229 
     | 
    
         
            -
            chat.with_tools search, Calculator
         
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
     | 
    
         
            -
            # Configure as needed
         
     | 
| 
       232 
     | 
    
         
            -
            chat.with_model('claude-3-5-sonnet-20241022')
         
     | 
| 
       233 
     | 
    
         
            -
                .with_temperature(0.9)
         
     | 
| 
      
 68 
     | 
    
         
            +
            # In your Gemfile
         
     | 
| 
      
 69 
     | 
    
         
            +
            gem 'ruby_llm'
         
     | 
| 
       234 
70 
     | 
    
         | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
            # Then run
         
     | 
| 
      
 72 
     | 
    
         
            +
            bundle install
         
     | 
| 
       237 
73 
     | 
    
         | 
| 
       238 
     | 
    
         
            -
             
     | 
| 
       239 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
            # Or install it yourself
         
     | 
| 
      
 75 
     | 
    
         
            +
            gem install ruby_llm
         
     | 
| 
       240 
76 
     | 
    
         
             
            ```
         
     | 
| 
       241 
77 
     | 
    
         | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
      
 78 
     | 
    
         
            +
            Configure with your API keys:
         
     | 
| 
       243 
79 
     | 
    
         | 
| 
       244 
80 
     | 
    
         
             
            ```ruby
         
     | 
| 
       245 
     | 
    
         
            -
             
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
       248 
     | 
    
         
            -
             
     | 
| 
       249 
     | 
    
         
            -
             
     | 
| 
      
 81 
     | 
    
         
            +
            RubyLLM.configure do |config|
         
     | 
| 
      
 82 
     | 
    
         
            +
              config.openai_api_key = ENV['OPENAI_API_KEY']
         
     | 
| 
      
 83 
     | 
    
         
            +
              config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
         
     | 
| 
      
 84 
     | 
    
         
            +
              config.gemini_api_key = ENV['GEMINI_API_KEY']
         
     | 
| 
      
 85 
     | 
    
         
            +
              config.deepseek_api_key = ENV['DEEPSEEK_API_KEY'] # Optional
         
     | 
| 
      
 86 
     | 
    
         
            +
            end
         
     | 
| 
       250 
87 
     | 
    
         
             
            ```
         
     | 
| 
       251 
88 
     | 
    
         | 
| 
       252 
     | 
    
         
            -
            ##  
     | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
       254 
     | 
    
         
            -
            RubyLLM wraps provider errors in clear Ruby exceptions:
         
     | 
| 
      
 89 
     | 
    
         
            +
            ## Have great conversations
         
     | 
| 
       255 
90 
     | 
    
         | 
| 
       256 
91 
     | 
    
         
             
            ```ruby
         
     | 
| 
       257 
     | 
    
         
            -
             
     | 
| 
       258 
     | 
    
         
            -
             
     | 
| 
       259 
     | 
    
         
            -
              chat.ask "Hello world!"
         
     | 
| 
       260 
     | 
    
         
            -
            rescue RubyLLM::UnauthorizedError
         
     | 
| 
       261 
     | 
    
         
            -
              puts "Check your API credentials"
         
     | 
| 
       262 
     | 
    
         
            -
            rescue RubyLLM::BadRequestError => e
         
     | 
| 
       263 
     | 
    
         
            -
              puts "Something went wrong: #{e.message}"
         
     | 
| 
       264 
     | 
    
         
            -
            rescue RubyLLM::PaymentRequiredError
         
     | 
| 
       265 
     | 
    
         
            -
              puts "Time to top up your API credits"
         
     | 
| 
       266 
     | 
    
         
            -
            rescue RubyLLM::ServiceUnavailableError
         
     | 
| 
       267 
     | 
    
         
            -
              puts "API service is temporarily down"
         
     | 
| 
       268 
     | 
    
         
            -
            end
         
     | 
| 
       269 
     | 
    
         
            -
            ```
         
     | 
| 
      
 92 
     | 
    
         
            +
            # Start a chat with the default model (GPT-4o-mini)
         
     | 
| 
      
 93 
     | 
    
         
            +
            chat = RubyLLM.chat
         
     | 
| 
       270 
94 
     | 
    
         | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
      
 95 
     | 
    
         
            +
            # Or specify what you want
         
     | 
| 
      
 96 
     | 
    
         
            +
            chat = RubyLLM.chat(model: 'claude-3-7-sonnet-20250219')
         
     | 
| 
       272 
97 
     | 
    
         | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
      
 98 
     | 
    
         
            +
            # Simple questions just work
         
     | 
| 
      
 99 
     | 
    
         
            +
            chat.ask "What's the difference between attr_reader and attr_accessor?"
         
     | 
| 
       274 
100 
     | 
    
         | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
            class CreateChats < ActiveRecord::Migration[8.0]
         
     | 
| 
       278 
     | 
    
         
            -
              def change
         
     | 
| 
       279 
     | 
    
         
            -
                create_table :chats do |t|
         
     | 
| 
       280 
     | 
    
         
            -
                  t.string :model_id
         
     | 
| 
       281 
     | 
    
         
            -
                  t.timestamps
         
     | 
| 
       282 
     | 
    
         
            -
                end
         
     | 
| 
       283 
     | 
    
         
            -
              end
         
     | 
| 
       284 
     | 
    
         
            -
            end
         
     | 
| 
      
 101 
     | 
    
         
            +
            # Multi-turn conversations are seamless
         
     | 
| 
      
 102 
     | 
    
         
            +
            chat.ask "Could you give me an example?"
         
     | 
| 
       285 
103 
     | 
    
         | 
| 
       286 
     | 
    
         
            -
            #  
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
               
     | 
| 
       289 
     | 
    
         
            -
                create_table :messages do |t|
         
     | 
| 
       290 
     | 
    
         
            -
                  t.references :chat, null: false
         
     | 
| 
       291 
     | 
    
         
            -
                  t.string :role
         
     | 
| 
       292 
     | 
    
         
            -
                  t.text :content
         
     | 
| 
       293 
     | 
    
         
            -
                  t.string :model_id
         
     | 
| 
       294 
     | 
    
         
            -
                  t.integer :input_tokens
         
     | 
| 
       295 
     | 
    
         
            -
                  t.integer :output_tokens
         
     | 
| 
       296 
     | 
    
         
            -
                  t.references :tool_call
         
     | 
| 
       297 
     | 
    
         
            -
                  t.timestamps
         
     | 
| 
       298 
     | 
    
         
            -
                end
         
     | 
| 
       299 
     | 
    
         
            -
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            # Stream responses in real-time
         
     | 
| 
      
 105 
     | 
    
         
            +
            chat.ask "Tell me a story about a Ruby programmer" do |chunk|
         
     | 
| 
      
 106 
     | 
    
         
            +
              print chunk.content
         
     | 
| 
       300 
107 
     | 
    
         
             
            end
         
     | 
| 
       301 
108 
     | 
    
         | 
| 
       302 
     | 
    
         
            -
            #  
     | 
| 
       303 
     | 
    
         
            -
             
     | 
| 
       304 
     | 
    
         
            -
             
     | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
       306 
     | 
    
         
            -
             
     | 
| 
       307 
     | 
    
         
            -
             
     | 
| 
       308 
     | 
    
         
            -
             
     | 
| 
       309 
     | 
    
         
            -
                  t.jsonb :arguments, default: {}
         
     | 
| 
       310 
     | 
    
         
            -
                  t.timestamps
         
     | 
| 
       311 
     | 
    
         
            -
                end
         
     | 
| 
       312 
     | 
    
         
            -
             
     | 
| 
       313 
     | 
    
         
            -
                add_index :tool_calls, :tool_call_id
         
     | 
| 
       314 
     | 
    
         
            -
              end
         
     | 
| 
       315 
     | 
    
         
            -
            end
         
     | 
| 
      
 109 
     | 
    
         
            +
            # Understand content in multiple forms
         
     | 
| 
      
 110 
     | 
    
         
            +
            chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
         
     | 
| 
      
 111 
     | 
    
         
            +
            chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
         
     | 
| 
      
 112 
     | 
    
         
            +
            chat.ask "What's being said?", with: { audio: "meeting.wav" }
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            # Need a different model mid-conversation? No problem
         
     | 
| 
      
 115 
     | 
    
         
            +
            chat.with_model('gemini-2.0-flash').ask "What's your favorite algorithm?"
         
     | 
| 
       316 
116 
     | 
    
         
             
            ```
         
     | 
| 
       317 
117 
     | 
    
         | 
| 
       318 
     | 
    
         
            -
             
     | 
| 
      
 118 
     | 
    
         
            +
            ## Rails integration that makes sense
         
     | 
| 
       319 
119 
     | 
    
         | 
| 
       320 
120 
     | 
    
         
             
            ```ruby
         
     | 
| 
      
 121 
     | 
    
         
            +
            # app/models/chat.rb
         
     | 
| 
       321 
122 
     | 
    
         
             
            class Chat < ApplicationRecord
         
     | 
| 
       322 
123 
     | 
    
         
             
              acts_as_chat
         
     | 
| 
       323 
124 
     | 
    
         | 
| 
       324 
     | 
    
         
            -
              #  
     | 
| 
      
 125 
     | 
    
         
            +
              # Works great with Turbo
         
     | 
| 
       325 
126 
     | 
    
         
             
              broadcasts_to ->(chat) { "chat_#{chat.id}" }
         
     | 
| 
       326 
127 
     | 
    
         
             
            end
         
     | 
| 
       327 
128 
     | 
    
         | 
| 
      
 129 
     | 
    
         
            +
            # app/models/message.rb
         
     | 
| 
       328 
130 
     | 
    
         
             
            class Message < ApplicationRecord
         
     | 
| 
       329 
131 
     | 
    
         
             
              acts_as_message
         
     | 
| 
       330 
132 
     | 
    
         
             
            end
         
     | 
| 
       331 
133 
     | 
    
         | 
| 
      
 134 
     | 
    
         
            +
            # app/models/tool_call.rb
         
     | 
| 
       332 
135 
     | 
    
         
             
            class ToolCall < ApplicationRecord
         
     | 
| 
       333 
136 
     | 
    
         
             
              acts_as_tool_call
         
     | 
| 
       334 
137 
     | 
    
         
             
            end
         
     | 
| 
       335 
     | 
    
         
            -
            ```
         
     | 
| 
       336 
     | 
    
         
            -
             
     | 
| 
       337 
     | 
    
         
            -
            That's it! Now you can use chats straight from your models:
         
     | 
| 
       338 
     | 
    
         
            -
             
     | 
| 
       339 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       340 
     | 
    
         
            -
            # Create a new chat
         
     | 
| 
       341 
     | 
    
         
            -
            chat = Chat.create! model_id: "gpt-4o-mini"
         
     | 
| 
       342 
     | 
    
         
            -
             
     | 
| 
       343 
     | 
    
         
            -
            # Ask questions - messages are automatically saved
         
     | 
| 
       344 
     | 
    
         
            -
            chat.ask "What's the weather in Paris?"
         
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
     | 
    
         
            -
            # Stream responses in real-time
         
     | 
| 
       347 
     | 
    
         
            -
            chat.ask "Tell me a story" do |chunk|
         
     | 
| 
       348 
     | 
    
         
            -
              broadcast_chunk chunk
         
     | 
| 
       349 
     | 
    
         
            -
            end
         
     | 
| 
       350 
138 
     | 
    
         | 
| 
       351 
     | 
    
         
            -
            #  
     | 
| 
       352 
     | 
    
         
            -
            chat. 
     | 
| 
       353 
     | 
    
         
            -
             
     | 
| 
       354 
     | 
    
         
            -
               
     | 
| 
       355 
     | 
    
         
            -
                 
     | 
| 
       356 
     | 
    
         
            -
             
     | 
| 
       357 
     | 
    
         
            -
                 
     | 
| 
       358 
     | 
    
         
            -
             
     | 
| 
      
 139 
     | 
    
         
            +
            # In your controller
         
     | 
| 
      
 140 
     | 
    
         
            +
            chat = Chat.create!(model_id: "gpt-4o-mini")
         
     | 
| 
      
 141 
     | 
    
         
            +
            chat.ask("What's your favorite Ruby gem?") do |chunk|
         
     | 
| 
      
 142 
     | 
    
         
            +
              Turbo::StreamsChannel.broadcast_append_to(
         
     | 
| 
      
 143 
     | 
    
         
            +
                chat,
         
     | 
| 
      
 144 
     | 
    
         
            +
                target: "response",
         
     | 
| 
      
 145 
     | 
    
         
            +
                partial: "messages/chunk",
         
     | 
| 
      
 146 
     | 
    
         
            +
                locals: { chunk: chunk }
         
     | 
| 
      
 147 
     | 
    
         
            +
              )
         
     | 
| 
       359 
148 
     | 
    
         
             
            end
         
     | 
| 
       360 
     | 
    
         
            -
            ```
         
     | 
| 
       361 
     | 
    
         
            -
             
     | 
| 
       362 
     | 
    
         
            -
            ### Real-time Updates with Hotwire
         
     | 
| 
       363 
     | 
    
         
            -
             
     | 
| 
       364 
     | 
    
         
            -
            The Rails integration works great with Hotwire out of the box:
         
     | 
| 
       365 
     | 
    
         
            -
             
     | 
| 
       366 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       367 
     | 
    
         
            -
            # app/controllers/chats_controller.rb
         
     | 
| 
       368 
     | 
    
         
            -
            class ChatsController < ApplicationController
         
     | 
| 
       369 
     | 
    
         
            -
              def show
         
     | 
| 
       370 
     | 
    
         
            -
                @chat = Chat.find(params[:id])
         
     | 
| 
       371 
     | 
    
         
            -
              end
         
     | 
| 
       372 
     | 
    
         
            -
             
     | 
| 
       373 
     | 
    
         
            -
              def ask
         
     | 
| 
       374 
     | 
    
         
            -
                @chat = Chat.find(params[:id])
         
     | 
| 
       375 
     | 
    
         
            -
                @chat.ask(params[:message]) do |chunk|
         
     | 
| 
       376 
     | 
    
         
            -
                  Turbo::StreamsChannel.broadcast_append_to(
         
     | 
| 
       377 
     | 
    
         
            -
                    @chat,
         
     | 
| 
       378 
     | 
    
         
            -
                    target: "messages",
         
     | 
| 
       379 
     | 
    
         
            -
                    partial: "messages/chunk",
         
     | 
| 
       380 
     | 
    
         
            -
                    locals: { chunk: chunk }
         
     | 
| 
       381 
     | 
    
         
            -
                  )
         
     | 
| 
       382 
     | 
    
         
            -
                end
         
     | 
| 
       383 
     | 
    
         
            -
              end
         
     | 
| 
       384 
     | 
    
         
            -
            end
         
     | 
| 
       385 
     | 
    
         
            -
             
     | 
| 
       386 
     | 
    
         
            -
            # app/views/chats/show.html.erb
         
     | 
| 
       387 
     | 
    
         
            -
            <%= turbo_stream_from @chat %>
         
     | 
| 
       388 
149 
     | 
    
         | 
| 
       389 
     | 
    
         
            -
             
     | 
| 
       390 
     | 
    
         
            -
              <%= render @chat.messages %>
         
     | 
| 
       391 
     | 
    
         
            -
            </div>
         
     | 
| 
       392 
     | 
    
         
            -
             
     | 
| 
       393 
     | 
    
         
            -
            <%= form_with(url: ask_chat_path(@chat), local: false) do |f| %>
         
     | 
| 
       394 
     | 
    
         
            -
              <%= f.text_area :message %>
         
     | 
| 
       395 
     | 
    
         
            -
              <%= f.submit "Send" %>
         
     | 
| 
       396 
     | 
    
         
            -
            <% end %>
         
     | 
| 
      
 150 
     | 
    
         
            +
            # That's it - chat history is automatically saved
         
     | 
| 
       397 
151 
     | 
    
         
             
            ```
         
     | 
| 
       398 
152 
     | 
    
         | 
| 
       399 
     | 
    
         
            -
             
     | 
| 
       400 
     | 
    
         
            -
             
     | 
| 
       401 
     | 
    
         
            -
            The persistence works seamlessly with background jobs:
         
     | 
| 
       402 
     | 
    
         
            -
             
     | 
| 
       403 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       404 
     | 
    
         
            -
            class ChatJob < ApplicationJob
         
     | 
| 
       405 
     | 
    
         
            -
              def perform(chat_id, message)
         
     | 
| 
       406 
     | 
    
         
            -
                chat = Chat.find chat_id
         
     | 
| 
       407 
     | 
    
         
            -
             
     | 
| 
       408 
     | 
    
         
            -
                chat.ask(message) do |chunk|
         
     | 
| 
       409 
     | 
    
         
            -
                  # Optional: Broadcast chunks for real-time updates
         
     | 
| 
       410 
     | 
    
         
            -
                  Turbo::StreamsChannel.broadcast_append_to(
         
     | 
| 
       411 
     | 
    
         
            -
                    chat,
         
     | 
| 
       412 
     | 
    
         
            -
                    target: "messages",
         
     | 
| 
       413 
     | 
    
         
            -
                    partial: "messages/chunk",
         
     | 
| 
       414 
     | 
    
         
            -
                    locals: { chunk: chunk }
         
     | 
| 
       415 
     | 
    
         
            -
                  )
         
     | 
| 
       416 
     | 
    
         
            -
                end
         
     | 
| 
       417 
     | 
    
         
            -
              end
         
     | 
| 
       418 
     | 
    
         
            -
            end
         
     | 
| 
       419 
     | 
    
         
            -
            ```
         
     | 
| 
       420 
     | 
    
         
            -
             
     | 
| 
       421 
     | 
    
         
            -
            ### Using Tools
         
     | 
| 
       422 
     | 
    
         
            -
             
     | 
| 
       423 
     | 
    
         
            -
            Tools work just like they do in regular RubyLLM chats:
         
     | 
| 
      
 153 
     | 
    
         
            +
            ## Creating tools is a breeze
         
     | 
| 
       424 
154 
     | 
    
         | 
| 
       425 
155 
     | 
    
         
             
            ```ruby
         
     | 
| 
       426 
     | 
    
         
            -
            class  
     | 
| 
       427 
     | 
    
         
            -
              description " 
     | 
| 
      
 156 
     | 
    
         
            +
            class Search < RubyLLM::Tool
         
     | 
| 
      
 157 
     | 
    
         
            +
              description "Searches a knowledge base"
         
     | 
| 
       428 
158 
     | 
    
         | 
| 
       429 
     | 
    
         
            -
              param : 
     | 
| 
       430 
     | 
    
         
            -
             
     | 
| 
       431 
     | 
    
         
            -
                desc: "City name or coordinates"
         
     | 
| 
      
 159 
     | 
    
         
            +
              param :query, desc: "The search query"
         
     | 
| 
      
 160 
     | 
    
         
            +
              param :limit, type: :integer, desc: "Max results", required: false
         
     | 
| 
       432 
161 
     | 
    
         | 
| 
       433 
     | 
    
         
            -
              def execute( 
     | 
| 
       434 
     | 
    
         
            -
                #  
     | 
| 
       435 
     | 
    
         
            -
                 
     | 
| 
      
 162 
     | 
    
         
            +
              def execute(query:, limit: 5)
         
     | 
| 
      
 163 
     | 
    
         
            +
                # Your search logic here
         
     | 
| 
      
 164 
     | 
    
         
            +
                Document.search(query).limit(limit).map(&:title)
         
     | 
| 
       436 
165 
     | 
    
         
             
              end
         
     | 
| 
       437 
166 
     | 
    
         
             
            end
         
     | 
| 
       438 
167 
     | 
    
         | 
| 
       439 
     | 
    
         
            -
            #  
     | 
| 
       440 
     | 
    
         
            -
            chat  
     | 
| 
       441 
     | 
    
         
            -
            chat.chat.with_tool WeatherTool.new
         
     | 
| 
       442 
     | 
    
         
            -
             
     | 
| 
       443 
     | 
    
         
            -
            # Ask about weather - tool usage is automatically saved
         
     | 
| 
       444 
     | 
    
         
            -
            chat.ask "What's the weather in Paris?"
         
     | 
| 
       445 
     | 
    
         
            -
             
     | 
| 
       446 
     | 
    
         
            -
            # Tool calls and results are persisted as messages
         
     | 
| 
       447 
     | 
    
         
            -
            pp chat.messages.map(&:role)
         
     | 
| 
       448 
     | 
    
         
            -
            #=> [:user, :assistant, :tool, :assistant]
         
     | 
| 
      
 168 
     | 
    
         
            +
            # Let the AI use it
         
     | 
| 
      
 169 
     | 
    
         
            +
            chat.with_tool(Search).ask "Find documents about Ruby 3.3 features"
         
     | 
| 
       449 
170 
     | 
    
         
             
            ```
         
     | 
| 
       450 
171 
     | 
    
         | 
| 
       451 
     | 
    
         
            -
            ##  
     | 
| 
       452 
     | 
    
         
            -
             
     | 
| 
       453 
     | 
    
         
            -
            | Feature | OpenAI | Anthropic | Google | DeepSeek |
         
     | 
| 
       454 
     | 
    
         
            -
            |---------|--------|-----------|--------|----------|
         
     | 
| 
       455 
     | 
    
         
            -
            | Chat | â
 GPT-4o, GPT-3.5 | â
 Claude 3.7, 3.5, 3 | â
 Gemini 2.0, 1.5 | â
 DeepSeek Chat, Reasoner |
         
     | 
| 
       456 
     | 
    
         
            -
            | Vision | â
 GPT-4o, GPT-4 | â
 All Claude 3 models | â
 Gemini 2.0, 1.5 | â |
         
     | 
| 
       457 
     | 
    
         
            -
            | Audio | â
 GPT-4o-audio, Whisper | â | â
 Gemini models | â |
         
     | 
| 
       458 
     | 
    
         
            -
            | PDF Analysis | â | â
 All Claude 3 models | â
 Gemini models | â |
         
     | 
| 
       459 
     | 
    
         
            -
            | Function Calling | â
 Most models | â
 Claude 3 models | â
 Gemini models (except Lite) | â
 |
         
     | 
| 
       460 
     | 
    
         
            -
            | JSON Mode | â
 Most recent models | â
 Claude 3 models | â
 Gemini models | â |
         
     | 
| 
       461 
     | 
    
         
            -
            | Image Generation | â
 DALL-E 3 | â | â
 Imagen | â |
         
     | 
| 
       462 
     | 
    
         
            -
            | Embeddings | â
 text-embedding-3 | â | â
 text-embedding-004 | â |
         
     | 
| 
       463 
     | 
    
         
            -
            | Context Size | â Up to 200K (o1) | â 200K tokens | â Up to 2M tokens | 64K tokens |
         
     | 
| 
       464 
     | 
    
         
            -
            | Streaming | â
 | â
 | â
 | â
 |
         
     | 
| 
       465 
     | 
    
         
            -
             
     | 
| 
       466 
     | 
    
         
            -
            ## Development
         
     | 
| 
       467 
     | 
    
         
            -
             
     | 
| 
       468 
     | 
    
         
            -
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt.
         
     | 
| 
       469 
     | 
    
         
            -
             
     | 
| 
       470 
     | 
    
         
            -
            ## Contributing
         
     | 
| 
      
 172 
     | 
    
         
            +
            ## Learn more
         
     | 
| 
       471 
173 
     | 
    
         | 
| 
       472 
     | 
    
         
            -
             
     | 
| 
      
 174 
     | 
    
         
            +
            Check out the guides at https://rubyllm.com for deeper dives into conversations with tools, streaming responses, embedding generations, and more.
         
     | 
| 
       473 
175 
     | 
    
         | 
| 
       474 
176 
     | 
    
         
             
            ## License
         
     | 
| 
       475 
177 
     | 
    
         | 
| 
       476 
     | 
    
         
            -
            Released under the MIT License. 
     | 
| 
      
 178 
     | 
    
         
            +
            Released under the MIT License.
         
     | 
    
        data/lib/ruby_llm/image.rb
    CHANGED
    
    | 
         @@ -3,16 +3,39 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module RubyLLM
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Represents a generated image from an AI model.
         
     | 
| 
       5 
5 
     | 
    
         
             
              # Provides an interface to image generation capabilities
         
     | 
| 
       6 
     | 
    
         
            -
              # from providers like DALL-E.
         
     | 
| 
      
 6 
     | 
    
         
            +
              # from providers like DALL-E and Gemini's Imagen.
         
     | 
| 
       7 
7 
     | 
    
         
             
              class Image
         
     | 
| 
       8 
     | 
    
         
            -
                attr_reader :url, :revised_prompt, :model_id
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :url, :data, :mime_type, :revised_prompt, :model_id
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                def initialize(url 
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(url: nil, data: nil, mime_type: nil, revised_prompt: nil, model_id: nil)
         
     | 
| 
       11 
11 
     | 
    
         
             
                  @url = url
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @data = data
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @mime_type = mime_type
         
     | 
| 
       12 
14 
     | 
    
         
             
                  @revised_prompt = revised_prompt
         
     | 
| 
       13 
15 
     | 
    
         
             
                  @model_id = model_id
         
     | 
| 
       14 
16 
     | 
    
         
             
                end
         
     | 
| 
       15 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
                def base64?
         
     | 
| 
      
 19 
     | 
    
         
            +
                  !@data.nil?
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                # Returns the raw binary image data regardless of source
         
     | 
| 
      
 23 
     | 
    
         
            +
                def to_blob
         
     | 
| 
      
 24 
     | 
    
         
            +
                  if base64?
         
     | 
| 
      
 25 
     | 
    
         
            +
                    Base64.decode64(@data)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  else
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # Use Faraday instead of URI.open for better security
         
     | 
| 
      
 28 
     | 
    
         
            +
                    response = Faraday.get(@url)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    response.body
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Saves the image to a file path
         
     | 
| 
      
 34 
     | 
    
         
            +
                def save(path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  File.binwrite(File.expand_path(path), to_blob)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  path
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       16 
39 
     | 
    
         
             
                def self.paint(prompt, model: nil, size: '1024x1024')
         
     | 
| 
       17 
40 
     | 
    
         
             
                  model_id = model || RubyLLM.config.default_image_model
         
     | 
| 
       18 
41 
     | 
    
         
             
                  Models.find(model_id) # Validate model exists
         
     | 
    
        data/lib/ruby_llm/provider.rb
    CHANGED
    
    | 
         @@ -158,6 +158,16 @@ module RubyLLM 
     | 
|
| 
       158 
158 
     | 
    
         
             
                  end
         
     | 
| 
       159 
159 
     | 
    
         
             
                end
         
     | 
| 
       160 
160 
     | 
    
         | 
| 
      
 161 
     | 
    
         
            +
                def parse_data_uri(uri)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  if uri&.start_with?('data:')
         
     | 
| 
      
 163 
     | 
    
         
            +
                    match = uri.match(/\Adata:([^;]+);base64,(.+)\z/)
         
     | 
| 
      
 164 
     | 
    
         
            +
                    return { mime_type: match[1], data: match[2] } if match
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                  # If it's not a data URI, return nil
         
     | 
| 
      
 168 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 169 
     | 
    
         
            +
                end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
       161 
171 
     | 
    
         
             
                class << self
         
     | 
| 
       162 
172 
     | 
    
         
             
                  def extended(base)
         
     | 
| 
       163 
173 
     | 
    
         
             
                    base.extend(Methods)
         
     | 
| 
         @@ -34,10 +34,13 @@ module RubyLLM 
     | 
|
| 
       34 
34 
     | 
    
         
             
                      source = part[:source]
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
                      if source.start_with?('http')
         
     | 
| 
       37 
     | 
    
         
            -
                        # For URLs
         
     | 
| 
      
 37 
     | 
    
         
            +
                        # For URLs - add "type": "url" here
         
     | 
| 
       38 
38 
     | 
    
         
             
                        {
         
     | 
| 
       39 
39 
     | 
    
         
             
                          type: 'document',
         
     | 
| 
       40 
     | 
    
         
            -
                          source: { 
     | 
| 
      
 40 
     | 
    
         
            +
                          source: {
         
     | 
| 
      
 41 
     | 
    
         
            +
                            type: 'url', # This line is missing in the current implementation
         
     | 
| 
      
 42 
     | 
    
         
            +
                            url: source
         
     | 
| 
      
 43 
     | 
    
         
            +
                          }
         
     | 
| 
       41 
44 
     | 
    
         
             
                        }
         
     | 
| 
       42 
45 
     | 
    
         
             
                      else
         
     | 
| 
       43 
46 
     | 
    
         
             
                        # For local files
         
     | 
| 
         @@ -37,12 +37,13 @@ module RubyLLM 
     | 
|
| 
       37 
37 
     | 
    
         
             
                        raise Error, 'Unexpected response format from Gemini image generation API'
         
     | 
| 
       38 
38 
     | 
    
         
             
                      end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                      #  
     | 
| 
       41 
     | 
    
         
            -
                       
     | 
| 
      
 40 
     | 
    
         
            +
                      # Extract mime type and base64 data
         
     | 
| 
      
 41 
     | 
    
         
            +
                      mime_type = image_data['mimeType'] || 'image/png'
         
     | 
| 
      
 42 
     | 
    
         
            +
                      base64_data = image_data['bytesBase64Encoded']
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
       42 
44 
     | 
    
         
             
                      Image.new(
         
     | 
| 
       43 
     | 
    
         
            -
                         
     | 
| 
       44 
     | 
    
         
            -
                         
     | 
| 
       45 
     | 
    
         
            -
                        model_id: ''
         
     | 
| 
      
 45 
     | 
    
         
            +
                        data: base64_data,
         
     | 
| 
      
 46 
     | 
    
         
            +
                        mime_type: mime_type
         
     | 
| 
       46 
47 
     | 
    
         
             
                      )
         
     | 
| 
       47 
48 
     | 
    
         
             
                    end
         
     | 
| 
       48 
49 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/ruby_llm/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: ruby_llm
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.1.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0.pre44
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Carmine Paolino
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2025-02- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2025-02-28 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: event_stream_parser
         
     |