ollama-ruby 0.0.0 → 0.1.0
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/.envrc +1 -0
 - data/README.md +67 -27
 - data/Rakefile +16 -4
 - data/bin/ollama_chat +422 -89
 - data/bin/ollama_console +3 -3
 - data/bin/ollama_update +17 -0
 - data/config/redis.conf +5 -0
 - data/docker-compose.yml +11 -0
 - data/lib/ollama/client/doc.rb +2 -1
 - data/lib/ollama/client.rb +7 -2
 - data/lib/ollama/commands/embed.rb +4 -4
 - data/lib/ollama/documents/memory_cache.rb +44 -0
 - data/lib/ollama/documents/redis_cache.rb +57 -0
 - data/lib/ollama/documents/splitters/character.rb +70 -0
 - data/lib/ollama/documents/splitters/semantic.rb +90 -0
 - data/lib/ollama/documents.rb +172 -0
 - data/lib/ollama/handlers/progress.rb +18 -5
 - data/lib/ollama/image.rb +16 -7
 - data/lib/ollama/utils/chooser.rb +30 -0
 - data/lib/ollama/utils/colorize_texts.rb +42 -0
 - data/lib/ollama/utils/fetcher.rb +105 -0
 - data/lib/ollama/utils/math.rb +48 -0
 - data/lib/ollama/utils/tags.rb +7 -0
 - data/lib/ollama/version.rb +1 -1
 - data/lib/ollama.rb +12 -5
 - data/ollama-ruby.gemspec +18 -8
 - data/spec/assets/embeddings.json +1 -0
 - data/spec/ollama/client_spec.rb +15 -15
 - data/spec/ollama/commands/chat_spec.rb +2 -2
 - data/spec/ollama/commands/copy_spec.rb +2 -2
 - data/spec/ollama/commands/create_spec.rb +2 -2
 - data/spec/ollama/commands/delete_spec.rb +2 -2
 - data/spec/ollama/commands/embed_spec.rb +4 -3
 - data/spec/ollama/commands/embeddings_spec.rb +2 -2
 - data/spec/ollama/commands/generate_spec.rb +2 -2
 - data/spec/ollama/commands/ps_spec.rb +2 -2
 - data/spec/ollama/commands/pull_spec.rb +2 -2
 - data/spec/ollama/commands/push_spec.rb +2 -2
 - data/spec/ollama/commands/show_spec.rb +2 -2
 - data/spec/ollama/commands/tags_spec.rb +2 -2
 - data/spec/ollama/documents/memory_cache_spec.rb +63 -0
 - data/spec/ollama/documents/redis_cache_spec.rb +78 -0
 - data/spec/ollama/documents/splitters/character_spec.rb +96 -0
 - data/spec/ollama/documents/splitters/semantic_spec.rb +56 -0
 - data/spec/ollama/documents_spec.rb +119 -0
 - data/spec/ollama/handlers/progress_spec.rb +2 -2
 - data/spec/ollama/image_spec.rb +4 -0
 - data/spec/ollama/utils/fetcher_spec.rb +74 -0
 - data/spec/ollama/utils/tags_spec.rb +24 -0
 - data/spec/spec_helper.rb +8 -0
 - metadata +184 -4
 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Documents::MemoryCache do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let :memory_cache do
         
     | 
| 
      
 5 
     | 
    
         
            +
                described_class.new prefix: 'test-'
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                expect(memory_cache).to be_a described_class
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it 'can get/set a key' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                key, value = 'foo', { test: true }
         
     | 
| 
      
 14 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 15 
     | 
    
         
            +
                  memory_cache[key] = value
         
     | 
| 
      
 16 
     | 
    
         
            +
                }.to change {
         
     | 
| 
      
 17 
     | 
    
         
            +
                  memory_cache[key]
         
     | 
| 
      
 18 
     | 
    
         
            +
                }.from(nil).to(value)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              it 'can determine if key exists' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                key, value = 'foo', { test: true }
         
     | 
| 
      
 23 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 24 
     | 
    
         
            +
                  memory_cache[key] = value
         
     | 
| 
      
 25 
     | 
    
         
            +
                }.to change {
         
     | 
| 
      
 26 
     | 
    
         
            +
                  memory_cache.key?(key)
         
     | 
| 
      
 27 
     | 
    
         
            +
                }.from(false).to(true)
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              it 'can delete' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                key, value = 'foo', { test: true }
         
     | 
| 
      
 32 
     | 
    
         
            +
                memory_cache[key] = value
         
     | 
| 
      
 33 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 34 
     | 
    
         
            +
                  memory_cache.delete(key)
         
     | 
| 
      
 35 
     | 
    
         
            +
                }.to change {
         
     | 
| 
      
 36 
     | 
    
         
            +
                  memory_cache.key?(key)
         
     | 
| 
      
 37 
     | 
    
         
            +
                }.from(true).to(false)
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              it 'returns size' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                key, value = 'foo', { test: true }
         
     | 
| 
      
 42 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 43 
     | 
    
         
            +
                  memory_cache[key] = value
         
     | 
| 
      
 44 
     | 
    
         
            +
                }.to change {
         
     | 
| 
      
 45 
     | 
    
         
            +
                  memory_cache.size
         
     | 
| 
      
 46 
     | 
    
         
            +
                }.from(0).to(1)
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              it 'can clear' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                key, value = 'foo', { test: true }
         
     | 
| 
      
 51 
     | 
    
         
            +
                memory_cache[key] = value
         
     | 
| 
      
 52 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 53 
     | 
    
         
            +
                  expect(memory_cache.clear).to eq memory_cache
         
     | 
| 
      
 54 
     | 
    
         
            +
                }.to change {
         
     | 
| 
      
 55 
     | 
    
         
            +
                  memory_cache.size
         
     | 
| 
      
 56 
     | 
    
         
            +
                }.from(1).to(0)
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              it 'can iterate over keys under a prefix' do
         
     | 
| 
      
 60 
     | 
    
         
            +
                memory_cache['foo'] = 'bar'
         
     | 
| 
      
 61 
     | 
    
         
            +
                expect(memory_cache.to_a).to eq [ %w[ test-foo bar ] ]
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Documents::RedisCache do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                redis_cache = described_class.new prefix: 'test-', url: 'something'
         
     | 
| 
      
 6 
     | 
    
         
            +
                expect(redis_cache).to be_a described_class
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              it 'raises ArgumentError if url is missing' do
         
     | 
| 
      
 10 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 11 
     | 
    
         
            +
                  described_class.new prefix: 'test-', url: nil
         
     | 
| 
      
 12 
     | 
    
         
            +
                }.to raise_error ArgumentError
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              context 'test redis interactions' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                let :redis_cache do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  described_class.new prefix: 'test-', url: 'something'
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                let :redis do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  double('Redis')
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                before do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  allow_any_instance_of(described_class).to receive(:redis).and_return(redis)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                it 'has Redis client' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  expect(redis_cache.redis).to eq redis
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                it 'can get a key' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                  key = 'foo'
         
     | 
| 
      
 34 
     | 
    
         
            +
                  expect(redis).to receive(:get).with('test-' + key).and_return 666
         
     | 
| 
      
 35 
     | 
    
         
            +
                  redis_cache[key]
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                it 'can set a value for a key' do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  key, value = 'foo', { test: true }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  expect(redis).to receive(:set).with('test-' + key, JSON(value))
         
     | 
| 
      
 41 
     | 
    
         
            +
                  redis_cache[key] = value
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                it 'can determine if key exists' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  key = 'foo'
         
     | 
| 
      
 46 
     | 
    
         
            +
                  expect(redis).to receive(:exists?).with('test-' + key).and_return(false, true)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  expect(redis_cache.key?('foo')).to eq false
         
     | 
| 
      
 48 
     | 
    
         
            +
                  expect(redis_cache.key?('foo')).to eq true
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                it 'can delete' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  key = 'foo'
         
     | 
| 
      
 53 
     | 
    
         
            +
                  expect(redis).to receive(:del).with('test-' + key)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  redis_cache.delete(key)
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                it 'returns size' do
         
     | 
| 
      
 58 
     | 
    
         
            +
                  allow(redis).to receive(:scan_each).with(match: 'test-*').
         
     | 
| 
      
 59 
     | 
    
         
            +
                    and_yield('test-foo').
         
     | 
| 
      
 60 
     | 
    
         
            +
                    and_yield('test-bar').
         
     | 
| 
      
 61 
     | 
    
         
            +
                    and_yield('test-baz')
         
     | 
| 
      
 62 
     | 
    
         
            +
                  expect(redis_cache.size).to eq 3
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                it 'can clear' do
         
     | 
| 
      
 66 
     | 
    
         
            +
                  expect(redis).to receive(:scan_each).with(match: 'test-*').and_yield(
         
     | 
| 
      
 67 
     | 
    
         
            +
                    'test-foo'
         
     | 
| 
      
 68 
     | 
    
         
            +
                  )
         
     | 
| 
      
 69 
     | 
    
         
            +
                  expect(redis).to receive(:del).with('test-foo')
         
     | 
| 
      
 70 
     | 
    
         
            +
                  expect(redis_cache.clear).to eq redis_cache
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                it 'can iterate over keys under a prefix' do
         
     | 
| 
      
 74 
     | 
    
         
            +
                  expect(redis).to receive(:scan_each).with(match: 'test-*')
         
     | 
| 
      
 75 
     | 
    
         
            +
                  redis_cache.to_a
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,96 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Documents::Splitters::Character do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let :splitter do
         
     | 
| 
      
 5 
     | 
    
         
            +
                described_class.new chunk_size: 23
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                expect(splitter).to be_a described_class
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it 'can split' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n\n"
         
     | 
| 
      
 14 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 15 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 16 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq ?A * 100
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              it 'can split including separator' do
         
     | 
| 
      
 20 
     | 
    
         
            +
                splitter = described_class.new chunk_size: 25, include_separator: true
         
     | 
| 
      
 21 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n\n"
         
     | 
| 
      
 22 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 23 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 24 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq text
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              it 'cannot split' do
         
     | 
| 
      
 28 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n"
         
     | 
| 
      
 29 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 30 
     | 
    
         
            +
                expect(result.count).to eq 1
         
     | 
| 
      
 31 
     | 
    
         
            +
                expect(result.to_a.join('').count(?A)).to eq text.count(?A)
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              it 'cannot split2' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                text = "A" * 25
         
     | 
| 
      
 36 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 37 
     | 
    
         
            +
                expect(result.count).to eq 1
         
     | 
| 
      
 38 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq ?A * 25
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              it 'can split sentences' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                text     = "foo.foo. bar!bar! baz?baz? quux.\nquux."
         
     | 
| 
      
 43 
     | 
    
         
            +
                splitter = described_class.new(separator: /[.!?]\s*(?:\b|\z)/, chunk_size: 2)
         
     | 
| 
      
 44 
     | 
    
         
            +
                result   = splitter.split(text)
         
     | 
| 
      
 45 
     | 
    
         
            +
                expect(result.to_a).to eq %w[ foo foo bar bar baz baz quux quux ]
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            RSpec.describe Ollama::Documents::Splitters::RecursiveCharacter do
         
     | 
| 
      
 50 
     | 
    
         
            +
              let :splitter do
         
     | 
| 
      
 51 
     | 
    
         
            +
                described_class.new chunk_size: 23
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                expect(splitter).to be_a described_class
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              it 'can split' do
         
     | 
| 
      
 59 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n\n"
         
     | 
| 
      
 60 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 61 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 62 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq ?A * 100
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              it 'cannot split' do
         
     | 
| 
      
 66 
     | 
    
         
            +
                splitter = described_class.new chunk_size: 23, include_separator: true,
         
     | 
| 
      
 67 
     | 
    
         
            +
                  separators: described_class::DEFAULT_SEPARATORS[0..-2]
         
     | 
| 
      
 68 
     | 
    
         
            +
                text = "A" * 25
         
     | 
| 
      
 69 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 70 
     | 
    
         
            +
                expect(result.count).to eq 1
         
     | 
| 
      
 71 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq ?A * 25
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              it 'can split including separator' do
         
     | 
| 
      
 75 
     | 
    
         
            +
                splitter = described_class.new chunk_size: 25, include_separator: true
         
     | 
| 
      
 76 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n\n"
         
     | 
| 
      
 77 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 78 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 79 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq text
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              it 'can split single newline as well' do
         
     | 
| 
      
 83 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n"
         
     | 
| 
      
 84 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 85 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 86 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq ?A * 100
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              it 'can split single newline as well including separator' do
         
     | 
| 
      
 90 
     | 
    
         
            +
                splitter = described_class.new chunk_size: 25, include_separator: true
         
     | 
| 
      
 91 
     | 
    
         
            +
                text = [ "A" * 10 ] * 10 * "\n"
         
     | 
| 
      
 92 
     | 
    
         
            +
                result = splitter.split(text)
         
     | 
| 
      
 93 
     | 
    
         
            +
                expect(result.count).to eq 5
         
     | 
| 
      
 94 
     | 
    
         
            +
                expect(result.to_a.join('')).to eq text
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Documents::Splitters::Semantic do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let :ollama do
         
     | 
| 
      
 5 
     | 
    
         
            +
                double('Ollama::Client')
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              let :splitter do
         
     | 
| 
      
 9 
     | 
    
         
            +
                described_class.new ollama:, model: 'mxbai-embed-large'
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              let :embeddings do
         
     | 
| 
      
 13 
     | 
    
         
            +
                JSON(File.read(asset('embeddings.json')))
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                expect(splitter).to be_a described_class
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              before do
         
     | 
| 
      
 21 
     | 
    
         
            +
                allow(ollama).to receive(:embed).and_return(double(embeddings:))
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              it 'can split with breakpoint :percentile' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
         
     | 
| 
      
 26 
     | 
    
         
            +
                result = splitter.split(text, breakpoint: :percentile, percentile: 75)
         
     | 
| 
      
 27 
     | 
    
         
            +
                expect(result.count).to eq 3
         
     | 
| 
      
 28 
     | 
    
         
            +
                expect(result.to_a.join('').count(?A)).to eq text.count(?A)
         
     | 
| 
      
 29 
     | 
    
         
            +
                expect(result.to_a.join('').count(?B)).to eq text.count(?B)
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              it 'can split with breakpoint :percentile' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                described_class.new ollama:, model: 'mxbai-embed-large', chunk_size: 50
         
     | 
| 
      
 34 
     | 
    
         
            +
                text = ([ "A" * 10 ] * 6 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
         
     | 
| 
      
 35 
     | 
    
         
            +
                result = splitter.split(text, breakpoint: :percentile, percentile: 75)
         
     | 
| 
      
 36 
     | 
    
         
            +
                expect(result.count).to eq 4
         
     | 
| 
      
 37 
     | 
    
         
            +
                expect(result.to_a.join('').count(?A)).to eq text.count(?A)
         
     | 
| 
      
 38 
     | 
    
         
            +
                expect(result.to_a.join('').count(?B)).to eq text.count(?B)
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              it 'can split with breakpoint :standard_deviation' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
         
     | 
| 
      
 43 
     | 
    
         
            +
                result = splitter.split(text, breakpoint: :standard_deviation, percentage: 100)
         
     | 
| 
      
 44 
     | 
    
         
            +
                expect(result.count).to eq 3
         
     | 
| 
      
 45 
     | 
    
         
            +
                expect(result.to_a.join('').count(?A)).to eq text.count(?A)
         
     | 
| 
      
 46 
     | 
    
         
            +
                expect(result.to_a.join('').count(?B)).to eq text.count(?B)
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              it 'can split with breakpoint :interquartile' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
         
     | 
| 
      
 51 
     | 
    
         
            +
                result = splitter.split(text, breakpoint: :interquartile, percentage: 75)
         
     | 
| 
      
 52 
     | 
    
         
            +
                expect(result.count).to eq 3
         
     | 
| 
      
 53 
     | 
    
         
            +
                expect(result.to_a.join('').count(?A)).to eq text.count(?A)
         
     | 
| 
      
 54 
     | 
    
         
            +
                expect(result.to_a.join('').count(?B)).to eq text.count(?B)
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,119 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Documents do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let :ollama do
         
     | 
| 
      
 5 
     | 
    
         
            +
                double('Ollama::Client')
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              let :model do
         
     | 
| 
      
 9 
     | 
    
         
            +
                'mxbai-embed-large'
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              let :documents do
         
     | 
| 
      
 13 
     | 
    
         
            +
                described_class.new ollama:, model:
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                expect(documents).to be_a described_class
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              it 'no texts can be added to it' do
         
     | 
| 
      
 21 
     | 
    
         
            +
                expect(documents.add([])).to eq documents
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              it 'texts can be added to it' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                expect(ollama).to receive(:embed).
         
     | 
| 
      
 26 
     | 
    
         
            +
                  with(model:, input: %w[ foo bar ], options: nil).
         
     | 
| 
      
 27 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ], [ 0.2 ] ]))
         
     | 
| 
      
 28 
     | 
    
         
            +
                expect(documents.add(%w[ foo bar ])).to eq documents
         
     | 
| 
      
 29 
     | 
    
         
            +
                expect(documents.exist?('foo')).to eq true
         
     | 
| 
      
 30 
     | 
    
         
            +
                expect(documents.exist?('bar')).to eq true
         
     | 
| 
      
 31 
     | 
    
         
            +
                expect(documents['foo']).to be_a Ollama::Documents::Record
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              it 'a text can be added to it' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                expect(ollama).to receive(:embed).
         
     | 
| 
      
 36 
     | 
    
         
            +
                  with(model:, input: %w[ foo ], options: nil).
         
     | 
| 
      
 37 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 38 
     | 
    
         
            +
                expect(documents << 'foo').to eq documents
         
     | 
| 
      
 39 
     | 
    
         
            +
                expect(documents.exist?('foo')).to eq true
         
     | 
| 
      
 40 
     | 
    
         
            +
                expect(documents.exist?('bar')).to eq false
         
     | 
| 
      
 41 
     | 
    
         
            +
                expect(documents['foo']).to be_a Ollama::Documents::Record
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              it 'can find strings' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                allow(ollama).to receive(:embed).
         
     | 
| 
      
 46 
     | 
    
         
            +
                  with(model:, input: [ 'foo' ], options: nil).
         
     | 
| 
      
 47 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 48 
     | 
    
         
            +
                expect(documents << 'foo').to eq documents
         
     | 
| 
      
 49 
     | 
    
         
            +
                expect(ollama).to receive(:embed).
         
     | 
| 
      
 50 
     | 
    
         
            +
                  with(model:, input: 'foo', options: nil).
         
     | 
| 
      
 51 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 52 
     | 
    
         
            +
                records = documents.find('foo')
         
     | 
| 
      
 53 
     | 
    
         
            +
                expect(records).to eq [
         
     | 
| 
      
 54 
     | 
    
         
            +
                  Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ]
         
     | 
| 
      
 55 
     | 
    
         
            +
                ]
         
     | 
| 
      
 56 
     | 
    
         
            +
                expect(records[0].to_s).to eq '#<Ollama::Documents::Record "foo" 1.0>'
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              it 'can find only tagged strings' do
         
     | 
| 
      
 60 
     | 
    
         
            +
                allow(ollama).to receive(:embed).
         
     | 
| 
      
 61 
     | 
    
         
            +
                  with(model:, input: [ 'foo' ], options: nil).
         
     | 
| 
      
 62 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 63 
     | 
    
         
            +
                expect(documents.add('foo', tags: %i[ test ])).to eq documents
         
     | 
| 
      
 64 
     | 
    
         
            +
                expect(ollama).to receive(:embed).
         
     | 
| 
      
 65 
     | 
    
         
            +
                  with(model:, input: 'foo', options: nil).
         
     | 
| 
      
 66 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 67 
     | 
    
         
            +
                records = documents.find('foo', tags: %i[ nix ])
         
     | 
| 
      
 68 
     | 
    
         
            +
                expect(records).to eq []
         
     | 
| 
      
 69 
     | 
    
         
            +
                expect(ollama).to receive(:embed).
         
     | 
| 
      
 70 
     | 
    
         
            +
                  with(model:, input: 'foo', options: nil).
         
     | 
| 
      
 71 
     | 
    
         
            +
                  and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 72 
     | 
    
         
            +
                records = documents.find('foo', tags: %i[ test ])
         
     | 
| 
      
 73 
     | 
    
         
            +
                expect(records).to eq [
         
     | 
| 
      
 74 
     | 
    
         
            +
                  Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ]
         
     | 
| 
      
 75 
     | 
    
         
            +
                ]
         
     | 
| 
      
 76 
     | 
    
         
            +
                expect(records[0].to_s).to eq '#<Ollama::Documents::Record "foo" #test 1.0>'
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              context 'it uses cache' do
         
     | 
| 
      
 80 
     | 
    
         
            +
                before do
         
     | 
| 
      
 81 
     | 
    
         
            +
                  allow(ollama).to receive(:embed).
         
     | 
| 
      
 82 
     | 
    
         
            +
                    with(model:, input: %w[ foo ], options: nil).
         
     | 
| 
      
 83 
     | 
    
         
            +
                    and_return(double(embeddings: [ [ 0.1 ] ]))
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                it 'can delete texts' do
         
     | 
| 
      
 87 
     | 
    
         
            +
                  expect(documents << 'foo').to eq documents
         
     | 
| 
      
 88 
     | 
    
         
            +
                  expect {
         
     | 
| 
      
 89 
     | 
    
         
            +
                    documents.delete('foo')
         
     | 
| 
      
 90 
     | 
    
         
            +
                  }.to change { documents.exist?('foo') }.from(true).to(false)
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                it 'tracks size' do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  expect {
         
     | 
| 
      
 95 
     | 
    
         
            +
                    expect(documents << 'foo').to eq documents
         
     | 
| 
      
 96 
     | 
    
         
            +
                  }.to change { documents.size }.from(0).to(1)
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                it 'can clear texts' do
         
     | 
| 
      
 100 
     | 
    
         
            +
                  expect(documents << 'foo').to eq documents
         
     | 
| 
      
 101 
     | 
    
         
            +
                  expect {
         
     | 
| 
      
 102 
     | 
    
         
            +
                    documents.clear
         
     | 
| 
      
 103 
     | 
    
         
            +
                  }.to change { documents.size }.from(1).to(0)
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                it 'returns collections' do
         
     | 
| 
      
 107 
     | 
    
         
            +
                  expect(documents.collections).to eq [ :default ]
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                it 'can change collection' do
         
     | 
| 
      
 111 
     | 
    
         
            +
                  expect(documents.instance_eval { @cache }).to receive(:prefix=).
         
     | 
| 
      
 112 
     | 
    
         
            +
                    with(/#@collection/).and_call_original
         
     | 
| 
      
 113 
     | 
    
         
            +
                  expect { documents.collection = :new_collection }.
         
     | 
| 
      
 114 
     | 
    
         
            +
                    to change { documents.collection }.
         
     | 
| 
      
 115 
     | 
    
         
            +
                    from(:default).
         
     | 
| 
      
 116 
     | 
    
         
            +
                    to(:new_collection)
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,7 +7,7 @@ RSpec.describe Ollama::Handlers::Progress do 
     | 
|
| 
       7 
7 
     | 
    
         
             
              end
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
              it 'can display progress' do
         
     | 
| 
       10 
     | 
    
         
            -
                response = double('response', status: 'testing', completed: 23, total: 666)
         
     | 
| 
      
 10 
     | 
    
         
            +
                response = double('response', status: 'testing', completed: 23, total: 666, error: nil)
         
     | 
| 
       11 
11 
     | 
    
         
             
                expect(infobar.counter).to receive(:progress).with(by: 23).and_call_original
         
     | 
| 
       12 
12 
     | 
    
         
             
                expect(infobar.display).to receive(:update).and_call_original
         
     | 
| 
       13 
13 
     | 
    
         
             
                described_class.new.call(response)
         
     | 
| 
         @@ -16,7 +16,7 @@ RSpec.describe Ollama::Handlers::Progress do 
     | 
|
| 
       16 
16 
     | 
    
         
             
              it 'can display errors in progress' do
         
     | 
| 
       17 
17 
     | 
    
         
             
                response = double('response', error: 'foo', status: nil, completed: nil, total: nil)
         
     | 
| 
       18 
18 
     | 
    
         
             
                progress = described_class.new
         
     | 
| 
       19 
     | 
    
         
            -
                expect( 
     | 
| 
      
 19 
     | 
    
         
            +
                expect(infobar).to receive(:puts).with(/Error: .*foo/)
         
     | 
| 
       20 
20 
     | 
    
         
             
                progress.call(response)
         
     | 
| 
       21 
21 
     | 
    
         
             
              end
         
     | 
| 
       22 
22 
     | 
    
         
             
            end
         
     | 
    
        data/spec/ollama/image_spec.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Utils::Fetcher do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let :url do
         
     | 
| 
      
 5 
     | 
    
         
            +
                'https://www.example.com/hello'
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              let :fetcher do
         
     | 
| 
      
 9 
     | 
    
         
            +
                described_class.new
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                expect(fetcher).to be_a described_class
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it 'has .get' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                expect(described_class).to receive(:new).and_return double(get: true)
         
     | 
| 
      
 18 
     | 
    
         
            +
                described_class.get(url)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              it 'can #get with streaming' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                stub_request(:get, 'https://www.example.com/hello').
         
     | 
| 
      
 23 
     | 
    
         
            +
                  with(headers: fetcher.headers).
         
     | 
| 
      
 24 
     | 
    
         
            +
                  to_return(
         
     | 
| 
      
 25 
     | 
    
         
            +
                    status: 200,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    body: 'world',
         
     | 
| 
      
 27 
     | 
    
         
            +
                    headers: { 'Content-Type' => 'text/plain' },
         
     | 
| 
      
 28 
     | 
    
         
            +
                  )
         
     | 
| 
      
 29 
     | 
    
         
            +
                fetcher.get(url) do |tmp|
         
     | 
| 
      
 30 
     | 
    
         
            +
                  expect(tmp).to be_a Tempfile
         
     | 
| 
      
 31 
     | 
    
         
            +
                  expect(tmp.read).to eq 'world'
         
     | 
| 
      
 32 
     | 
    
         
            +
                  expect(tmp.content_type).to eq 'text/plain'
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              it 'can #get and fallback from streaming' do
         
     | 
| 
      
 37 
     | 
    
         
            +
                stub_request(:get, 'https://www.example.com/hello').
         
     | 
| 
      
 38 
     | 
    
         
            +
                  with(headers: fetcher.headers).
         
     | 
| 
      
 39 
     | 
    
         
            +
                  to_return(
         
     | 
| 
      
 40 
     | 
    
         
            +
                    { status: 501 },
         
     | 
| 
      
 41 
     | 
    
         
            +
                    {
         
     | 
| 
      
 42 
     | 
    
         
            +
                      status: 200,
         
     | 
| 
      
 43 
     | 
    
         
            +
                      body: 'world',
         
     | 
| 
      
 44 
     | 
    
         
            +
                      headers: { 'Content-Type' => 'text/plain' },
         
     | 
| 
      
 45 
     | 
    
         
            +
                    }
         
     | 
| 
      
 46 
     | 
    
         
            +
                  )
         
     | 
| 
      
 47 
     | 
    
         
            +
                fetcher.get(url) do |tmp|
         
     | 
| 
      
 48 
     | 
    
         
            +
                  expect(tmp).to be_a Tempfile
         
     | 
| 
      
 49 
     | 
    
         
            +
                  expect(tmp.read).to eq 'world'
         
     | 
| 
      
 50 
     | 
    
         
            +
                  expect(tmp.content_type).to eq 'text/plain'
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              it 'can #get and finally fail' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                stub_request(:get, 'https://www.example.com/hello').
         
     | 
| 
      
 56 
     | 
    
         
            +
                  with(headers: fetcher.headers).
         
     | 
| 
      
 57 
     | 
    
         
            +
                  to_return(status: 500)
         
     | 
| 
      
 58 
     | 
    
         
            +
                fetcher.get(url) do |tmp|
         
     | 
| 
      
 59 
     | 
    
         
            +
                  expect(tmp).to be_nil
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
              it 'can redirect' do
         
     | 
| 
      
 64 
     | 
    
         
            +
                expect(fetcher.middlewares).to include Excon::Middleware::RedirectFollower
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              it 'can .read' do
         
     | 
| 
      
 68 
     | 
    
         
            +
                described_class.read(__FILE__) do |file|
         
     | 
| 
      
 69 
     | 
    
         
            +
                  expect(file).to be_a File
         
     | 
| 
      
 70 
     | 
    
         
            +
                  expect(file.read).to include 'can .read'
         
     | 
| 
      
 71 
     | 
    
         
            +
                  expect(file.content_type).to eq 'application/x-ruby'
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Ollama::Utils::Tags do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it 'can be instantiated' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                expect(described_class.new).to be_a described_class
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it 'can contain unique tags and is sorted' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                tags = described_class.new([ 'bar', 'foo'])
         
     | 
| 
      
 10 
     | 
    
         
            +
                expect(tags.to_a).to eq %w[ bar foo ]
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              it 'tags can be added to it' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                tags = described_class.new([ 'foo' ])
         
     | 
| 
      
 15 
     | 
    
         
            +
                tags.add 'bar'
         
     | 
| 
      
 16 
     | 
    
         
            +
                expect(tags.to_a).to eq %w[ bar foo ]
         
     | 
| 
      
 17 
     | 
    
         
            +
                tags.merge [ 'baz', 'baz2' ]
         
     | 
| 
      
 18 
     | 
    
         
            +
                expect(tags.to_a).to eq %w[ bar baz baz2 foo ]
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              it 'can be output nicely' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                expect(described_class.new(%w[foo bar]).to_s).to eq '#bar #foo'
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | 
         @@ -9,8 +9,16 @@ begin 
     | 
|
| 
       9 
9 
     | 
    
         
             
              require 'debug'
         
     | 
| 
       10 
10 
     | 
    
         
             
            rescue LoadError
         
     | 
| 
       11 
11 
     | 
    
         
             
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'webmock/rspec'
         
     | 
| 
      
 13 
     | 
    
         
            +
            WebMock.disable_net_connect!
         
     | 
| 
       12 
14 
     | 
    
         
             
            require 'ollama'
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
16 
     | 
    
         
             
            def asset(name)
         
     | 
| 
       15 
17 
     | 
    
         
             
              File.join(__dir__, 'assets', name)
         
     | 
| 
       16 
18 
     | 
    
         
             
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 21 
     | 
    
         
            +
              config.before(:suite) do
         
     | 
| 
      
 22 
     | 
    
         
            +
                infobar.show = nil
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     |