ollama-ruby 0.12.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGES.md +39 -0
  4. data/README.md +70 -144
  5. data/Rakefile +5 -17
  6. data/bin/ollama_cli +37 -6
  7. data/lib/ollama/client/command.rb +2 -2
  8. data/lib/ollama/dto.rb +4 -0
  9. data/lib/ollama/version.rb +1 -1
  10. data/lib/ollama.rb +0 -11
  11. data/ollama-ruby.gemspec +11 -22
  12. data/spec/ollama/message_spec.rb +9 -0
  13. metadata +25 -255
  14. data/bin/ollama_chat +0 -1248
  15. data/config/redis.conf +0 -5
  16. data/docker-compose.yml +0 -10
  17. data/lib/ollama/documents/cache/common.rb +0 -36
  18. data/lib/ollama/documents/cache/memory_cache.rb +0 -44
  19. data/lib/ollama/documents/cache/records.rb +0 -87
  20. data/lib/ollama/documents/cache/redis_backed_memory_cache.rb +0 -39
  21. data/lib/ollama/documents/cache/redis_cache.rb +0 -68
  22. data/lib/ollama/documents/cache/sqlite_cache.rb +0 -215
  23. data/lib/ollama/documents/splitters/character.rb +0 -72
  24. data/lib/ollama/documents/splitters/semantic.rb +0 -91
  25. data/lib/ollama/documents.rb +0 -184
  26. data/lib/ollama/utils/cache_fetcher.rb +0 -38
  27. data/lib/ollama/utils/chooser.rb +0 -52
  28. data/lib/ollama/utils/colorize_texts.rb +0 -65
  29. data/lib/ollama/utils/fetcher.rb +0 -175
  30. data/lib/ollama/utils/file_argument.rb +0 -34
  31. data/lib/ollama/utils/math.rb +0 -48
  32. data/lib/ollama/utils/tags.rb +0 -67
  33. data/spec/assets/embeddings.json +0 -1
  34. data/spec/assets/prompt.txt +0 -1
  35. data/spec/ollama/documents/cache/memory_cache_spec.rb +0 -97
  36. data/spec/ollama/documents/cache/redis_backed_memory_cache_spec.rb +0 -118
  37. data/spec/ollama/documents/cache/redis_cache_spec.rb +0 -121
  38. data/spec/ollama/documents/cache/sqlite_cache_spec.rb +0 -141
  39. data/spec/ollama/documents/splitters/character_spec.rb +0 -110
  40. data/spec/ollama/documents/splitters/semantic_spec.rb +0 -56
  41. data/spec/ollama/documents_spec.rb +0 -162
  42. data/spec/ollama/utils/cache_fetcher_spec.rb +0 -43
  43. data/spec/ollama/utils/colorize_texts_spec.rb +0 -13
  44. data/spec/ollama/utils/fetcher_spec.rb +0 -137
  45. data/spec/ollama/utils/file_argument_spec.rb +0 -17
  46. data/spec/ollama/utils/tags_spec.rb +0 -53
@@ -1,162 +0,0 @@
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
- expect(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
- expect(ollama).to receive(:embed).
61
- with(model:, input: [ 'foo' ], options: nil).
62
- and_return(double(embeddings: [ [ 0.1 ] ]))
63
- expect(documents.add('foo', tags: %w[ 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: %w[ 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: %w[ 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
- it 'can find strings conditionally' do
80
- expect(ollama).to receive(:embed).
81
- with(model:, input: [ 'foobar' ], options: nil).
82
- and_return(double(embeddings: [ [ 0.01 ] ]))
83
- expect(ollama).to receive(:embed).
84
- with(model:, input: [ 'foo' ], options: nil).
85
- and_return(double(embeddings: [ [ 0.1 ] ]))
86
- expect(documents << 'foobar').to eq documents
87
- expect(documents << 'foo').to eq documents
88
- expect(ollama).to receive(:embed).at_least(:once).
89
- with(model:, input: 'foo', options: nil).
90
- and_return(double(embeddings: [ [ 0.1 ] ]))
91
- records = documents.find_where('foo', text_count: 1)
92
- expect(records).to eq [
93
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
94
- ]
95
- records = documents.find_where('foo', text_size: 3)
96
- expect(records).to eq [
97
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
98
- ]
99
- records = documents.find_where('foo')
100
- expect(records).to eq [
101
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
102
- Ollama::Documents::Record[text: 'foobar', embedding: [ 0.1 ], similarity: 1.0 ],
103
- ]
104
- end
105
-
106
-
107
- context 'it uses cache' do
108
- before do
109
- allow(ollama).to receive(:embed).
110
- with(model:, input: %w[ foo ], options: nil).
111
- and_return(double(embeddings: [ [ 0.1 ] ]))
112
- end
113
-
114
- it 'can delete texts' do
115
- expect(documents << 'foo').to eq documents
116
- expect {
117
- documents.delete('foo')
118
- }.to change { documents.exist?('foo') }.from(true).to(false)
119
- end
120
-
121
- it 'tracks size' do
122
- expect {
123
- expect(documents << 'foo').to eq documents
124
- }.to change { documents.size }.from(0).to(1)
125
- end
126
-
127
- it 'can clear texts' do
128
- expect(documents << 'foo').to eq documents
129
- expect {
130
- documents.clear
131
- }.to change { documents.size }.from(1).to(0)
132
- end
133
-
134
- it 'can clear texts with tags' do
135
- expect(ollama).to receive(:embed).
136
- with(model:, input: %w[ bar ], options: nil).
137
- and_return(double(embeddings: [ [ 0.1 ] ]))
138
- expect(documents.add('foo', tags: %w[ test ])).to eq documents
139
- expect(documents.add('bar', tags: %w[ test2 ])).to eq documents
140
- expect(documents.tags.to_a).to eq %w[ test test2 ]
141
- expect {
142
- documents.clear tags: 'test'
143
- }.to change { documents.size }.from(2).to(1)
144
- expect {
145
- documents.clear tags: :test2
146
- }.to change { documents.size }.from(1).to(0)
147
- end
148
-
149
- it 'returns collections' do
150
- expect(documents.collections).to eq [ :default ]
151
- end
152
-
153
- it 'can change collection' do
154
- expect(documents.instance_eval { @cache }).to receive(:prefix=).
155
- with(/#@collection/).and_call_original
156
- expect { documents.collection = :new_collection }.
157
- to change { documents.collection }.
158
- from(:default).
159
- to(:new_collection)
160
- end
161
- end
162
- end
@@ -1,43 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::CacheFetcher do
4
- let :url do
5
- 'https://www.example.com/hello'
6
- end
7
-
8
- let :cache do
9
- double('RedisCache')
10
- end
11
-
12
- let :fetcher do
13
- described_class.new(cache).expose
14
- end
15
-
16
- it 'can be instantiated' do
17
- expect(fetcher).to be_a described_class
18
- end
19
-
20
- it 'has #get' do
21
- expect(cache).to receive(:[]).with('body-69ce405ab83f42dffa9fd22bbd47783f').and_return 'world'
22
- expect(cache).to receive(:[]).with('content_type-69ce405ab83f42dffa9fd22bbd47783f').and_return 'text/plain'
23
- yielded_io = nil
24
- block = -> io { yielded_io = io }
25
- fetcher.get(url, &block)
26
- expect(yielded_io).to be_a StringIO
27
- expect(yielded_io.read).to eq 'world'
28
- end
29
-
30
- it '#get needs block' do
31
- expect { fetcher.get(url) }.to raise_error(ArgumentError)
32
- end
33
-
34
- it 'has #put' do
35
- io = StringIO.new('world')
36
- io.extend(Ollama::Utils::Fetcher::HeaderExtension)
37
- io.content_type = MIME::Types['text/plain'].first
38
- io.ex = 666
39
- expect(cache).to receive(:set).with('body-69ce405ab83f42dffa9fd22bbd47783f', 'world', ex: 666)
40
- expect(cache).to receive(:set).with('content_type-69ce405ab83f42dffa9fd22bbd47783f', 'text/plain', ex: 666)
41
- fetcher.put(url, io)
42
- end
43
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::ColorizeTexts do
4
- it 'colorizes texts' do
5
- ct = described_class.new(%w[ foo bar ])
6
- colored = ct.to_s
7
- uncolored = Term::ANSIColor.uncolor(ct.to_s)
8
- expect(colored.size).to be > uncolored.size
9
- expect(uncolored).to eq(
10
- "foo\n#3 \n\nbar\n#3 \n\n"
11
- )
12
- end
13
- end
@@ -1,137 +0,0 @@
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.expose
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, url).
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 without ssl peer verification' do
37
- fetcher = described_class.new(
38
- http_options: { ssl_verify_peer: false }
39
- ).expose
40
- stub_request(:get, url).
41
- with(headers: fetcher.headers).
42
- to_return(
43
- status: 200,
44
- body: 'world',
45
- headers: { 'Content-Type' => 'text/plain' },
46
- )
47
- expect(Excon).to receive(:new).with(
48
- url,
49
- hash_including(ssl_verify_peer: false)
50
- ).and_call_original
51
- fetcher.get(url) do |tmp|
52
- expect(tmp).to be_a Tempfile
53
- expect(tmp.read).to eq 'world'
54
- expect(tmp.content_type).to eq 'text/plain'
55
- end
56
- end
57
-
58
- it 'can #get and fallback from streaming' do
59
- stub_request(:get, url).
60
- with(headers: fetcher.headers).
61
- to_return(
62
- { status: 501 },
63
- {
64
- status: 200,
65
- body: 'world',
66
- headers: { 'Content-Type' => 'text/plain' },
67
- }
68
- )
69
- fetcher.get(url) do |tmp|
70
- expect(tmp).to be_a Tempfile
71
- expect(tmp.read).to eq 'world'
72
- expect(tmp.content_type).to eq 'text/plain'
73
- end
74
- end
75
-
76
- it 'can #get and finally fail' do
77
- stub_request(:get, url).
78
- with(headers: fetcher.headers).
79
- to_return(status: 500)
80
- expect(STDERR).to receive(:puts).with(/cannot.*get.*#{url}/i)
81
- fetcher.get(url) do |tmp|
82
- expect(tmp).to be_a StringIO
83
- expect(tmp.read).to eq ''
84
- expect(tmp.content_type).to eq 'text/plain'
85
- end
86
- end
87
-
88
- it 'can redirect' do
89
- expect(fetcher.middlewares).to include Excon::Middleware::RedirectFollower
90
- end
91
-
92
- it 'can .read' do
93
- described_class.read(__FILE__) do |file|
94
- expect(file).to be_a File
95
- expect(file.read).to include 'can .read'
96
- expect(file.content_type).to eq 'application/x-ruby'
97
- end
98
- end
99
-
100
- it 'can .execute' do
101
- described_class.execute('echo -n hello world') do |file|
102
- expect(file).to be_a Tempfile
103
- expect(file.read).to eq 'hello world'
104
- expect(file.content_type).to eq 'text/plain'
105
- end
106
- end
107
-
108
- it 'can .execute and fail' do
109
- expect(IO).to receive(:popen).and_raise StandardError
110
- expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
111
- described_class.execute('foobar') do |file|
112
- expect(file).to be_a StringIO
113
- expect(file.read).to be_empty
114
- expect(file.content_type).to eq 'text/plain'
115
- end
116
- end
117
-
118
- describe '.normalize_url' do
119
- it 'can handle umlauts' do
120
- expect(described_class.normalize_url('https://foo.de/bär')).to eq(
121
- 'https://foo.de/b%C3%A4r'
122
- )
123
- end
124
-
125
- it 'can handle escaped umlauts' do
126
- expect(described_class.normalize_url('https://foo.de/b%C3%A4r')).to eq(
127
- 'https://foo.de/b%C3%A4r'
128
- )
129
- end
130
-
131
- it 'can remove #anchors' do
132
- expect(described_class.normalize_url('https://foo.de#bar')).to eq(
133
- 'https://foo.de'
134
- )
135
- end
136
- end
137
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::FileArgument do
4
- it 'it can return content' do
5
- expect(described_class.get_file_argument('foo')).to eq 'foo'
6
- end
7
-
8
- it 'it can return content at path' do
9
- expect(described_class.get_file_argument(asset('prompt.txt'))).to include\
10
- 'test prompt'
11
- end
12
-
13
- it 'it can return default content' do
14
- expect(described_class.get_file_argument('', default: 'foo')).to eq 'foo'
15
- expect(described_class.get_file_argument(nil, default: 'foo')).to eq 'foo'
16
- end
17
- end
@@ -1,53 +0,0 @@
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(%w[ bar foo ])
10
- expect(tags.to_a).to eq %w[ bar foo ]
11
- end
12
-
13
- it 'can contain unique tags with leading # characters and is sorted' do
14
- tags = described_class.new(%w[ #bar ##foo ])
15
- expect(tags.to_a).to eq %w[ bar foo ]
16
- end
17
-
18
- it 'tags can be added to it' do
19
- tags = described_class.new([ 'foo' ])
20
- tags.add 'bar'
21
- expect(tags.to_a).to eq %w[ bar foo ]
22
- end
23
-
24
- it 'can increase in size' do
25
- tags = described_class.new
26
- expect { tags.add 'foo' }.to change { tags.size }.from(0).to(1)
27
- expect { tags.add 'bar' }.to change { tags.size }.from(1).to(2)
28
- end
29
-
30
- it 'can be cleared' do
31
- tags = described_class.new([ 'foo', 'bar' ])
32
- expect { tags.clear }.to change { tags.size }.from(2).to(0)
33
- end
34
-
35
- it 'tags can be empty' do
36
- tags = described_class.new([ 'foo' ])
37
- expect { tags.clear }.to change { tags.empty? }.from(false).to(true)
38
- end
39
-
40
- it 'can be output nicely' do
41
- expect(described_class.new(%w[ #foo bar ]).to_s).to eq '#bar #foo'
42
- end
43
-
44
- it 'can be output nicely with links to source' do
45
- tags = described_class.new([ 'foo' ], source: 'https://foo.example.com')
46
- tags.add 'bar', source: '/path/to/bar.html'
47
- expect(tags.to_a).to eq %w[ bar foo ]
48
- tags.all? { expect(_1).to be_a(Ollama::Utils::Tags::Tag) }
49
- expect(tags.to_s).to eq(
50
- "\e]8;;file:///path/to/bar.html\e\\#bar\e]8;;\e\\ \e]8;;https://foo.example.com\e\\#foo\e]8;;\e\\"
51
- )
52
- end
53
- end