ollama-ruby 0.10.0 → 0.12.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.
@@ -1,17 +1,21 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::RedisBackedMemoryCache do
4
+ let :prefix do
5
+ 'test-'
6
+ end
7
+
8
+ let :cache do
9
+ described_class.new prefix: 'test-', url: 'something'
10
+ end
11
+
4
12
  it 'raises ArgumentError if url is missing' do
5
13
  expect {
6
- described_class.new prefix: 'test-', url: nil
14
+ described_class.new prefix:, url: nil
7
15
  }.to raise_error ArgumentError
8
16
  end
9
17
 
10
18
  context 'test redis interactions' do
11
- let :cache do
12
- described_class.new prefix: 'test-', url: 'something'
13
- end
14
-
15
19
  let :data do
16
20
  cache.instance_eval { @data }
17
21
  end
@@ -31,12 +35,10 @@ RSpec.describe Ollama::Documents::RedisBackedMemoryCache do
31
35
  end
32
36
 
33
37
  it 'can be instantiated and initialized' do
34
- cache = described_class.new prefix: 'test-', url: 'something'
35
38
  expect(cache).to be_a described_class
36
39
  end
37
40
 
38
41
  it 'defaults to nil object_class' do
39
- cache = described_class.new prefix: 'test-', url: 'something'
40
42
  expect(cache.object_class).to be_nil
41
43
  end
42
44
 
@@ -77,6 +79,16 @@ RSpec.describe Ollama::Documents::RedisBackedMemoryCache do
77
79
  cache.delete(key)
78
80
  end
79
81
 
82
+ it 'can iterate over keys, values' do
83
+ key, value = 'foo', { 'test' => true }
84
+ expect(redis).to receive(:set).with('test-' + key, JSON(value))
85
+ cache[key] = value
86
+ cache.each do |k, v|
87
+ expect(k).to eq prefix + key
88
+ expect(v).to eq value
89
+ end
90
+ end
91
+
80
92
  it 'returns size' do
81
93
  expect(cache).to receive(:count).and_return 3
82
94
  expect(cache.size).to eq 3
@@ -1,33 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::RedisCache do
4
+ let :prefix do
5
+ 'test-'
6
+ end
7
+
8
+ let :cache do
9
+ described_class.new prefix:, url: 'something'
10
+ end
11
+
4
12
  it 'can be instantiated' do
5
- cache = described_class.new prefix: 'test-', url: 'something'
6
13
  expect(cache).to be_a described_class
7
14
  end
8
15
 
9
16
  it 'defaults to nil object_class' do
10
- cache = described_class.new prefix: 'test-', url: 'something'
11
17
  expect(cache.object_class).to be_nil
12
18
  end
13
19
 
14
20
  it 'can be configured with object_class' do
15
21
  object_class = Class.new(JSON::GenericObject)
16
- cache = described_class.new(prefix: 'test-', url: 'something', object_class:)
22
+ cache = described_class.new(prefix:, url: 'something', object_class:)
17
23
  expect(cache.object_class).to eq object_class
18
24
  end
19
25
 
20
26
  it 'raises ArgumentError if url is missing' do
21
27
  expect {
22
- described_class.new prefix: 'test-', url: nil
28
+ described_class.new prefix:, url: nil
23
29
  }.to raise_error ArgumentError
24
30
  end
25
31
 
26
32
  context 'test redis interactions' do
27
- let :cache do
28
- described_class.new prefix: 'test-', url: 'something'
29
- end
30
-
31
33
  let :redis do
32
34
  double('Redis')
33
35
  end
@@ -42,43 +44,56 @@ RSpec.describe Ollama::Documents::RedisCache do
42
44
 
43
45
  it 'can get a key' do
44
46
  key = 'foo'
45
- expect(redis).to receive(:get).with('test-' + key).and_return '"some_json"'
47
+ expect(redis).to receive(:get).with(prefix + key).and_return '"some_json"'
46
48
  expect(cache[key]).to eq 'some_json'
47
49
  end
48
50
 
49
51
  it 'can set a value for a key' do
50
52
  key, value = 'foo', { test: true }
51
- expect(redis).to receive(:set).with('test-' + key, JSON(value), ex: nil)
53
+ expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: nil)
52
54
  cache[key] = value
53
55
  end
54
56
 
55
57
  it 'can set a value for a key with ttl' do
56
- cache = described_class.new prefix: 'test-', url: 'something', ex: 3_600
58
+ cache = described_class.new prefix:, url: 'something', ex: 3_600
57
59
  key, value = 'foo', { test: true }
58
- expect(redis).to receive(:set).with('test-' + key, JSON(value), ex: 3_600)
60
+ expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: 3_600)
59
61
  cache[key] = value
60
- expect(redis).to receive(:ttl).with('test-' + key).and_return 3_600
62
+ expect(redis).to receive(:ttl).with(prefix + key).and_return 3_600
61
63
  expect(cache.ttl(key)).to eq 3_600
62
64
  end
63
65
 
64
66
  it 'can determine if key exists' do
65
67
  key = 'foo'
66
- expect(redis).to receive(:exists?).with('test-' + key).and_return(false, true)
68
+ expect(redis).to receive(:exists?).with(prefix + key).and_return(false, true)
67
69
  expect(cache.key?('foo')).to eq false
68
70
  expect(cache.key?('foo')).to eq true
69
71
  end
70
72
 
71
73
  it 'can delete' do
72
74
  key = 'foo'
73
- expect(redis).to receive(:del).with('test-' + key)
75
+ expect(redis).to receive(:del).with(prefix + key)
74
76
  cache.delete(key)
75
77
  end
76
78
 
79
+ it 'can iterate over keys, values' do
80
+ key, value = 'foo', { 'test' => true }
81
+ expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: nil)
82
+ cache[key] = value
83
+ expect(redis).to receive(:scan_each).with(match: "#{prefix}*").
84
+ and_yield("#{prefix}foo")
85
+ expect(redis).to receive(:get).with(prefix + key).and_return(JSON(test: true))
86
+ cache.each do |k, v|
87
+ expect(k).to eq prefix + key
88
+ expect(v).to eq value
89
+ end
90
+ end
91
+
77
92
  it 'returns size' do
78
- allow(redis).to receive(:scan_each).with(match: 'test-*').
79
- and_yield('test-foo').
80
- and_yield('test-bar').
81
- and_yield('test-baz')
93
+ expect(redis).to receive(:scan_each).with(match: "#{prefix}*").
94
+ and_yield("#{prefix}foo").
95
+ and_yield("#{prefix}bar").
96
+ and_yield("#{prefix}baz")
82
97
  expect(cache.size).to eq 3
83
98
  end
84
99
 
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Ollama::Documents::SQLiteCache do
4
+ let :prefix do
5
+ 'test-'
6
+ end
7
+
8
+ let :test_value do
9
+ {
10
+ key: 'test',
11
+ text: 'test text',
12
+ norm: 0.5,
13
+ source: 'for-test.txt',
14
+ tags: %w[ test ],
15
+ embedding: [ 0.5 ] * 1_024,
16
+ }
17
+ end
18
+
19
+ let :cache do
20
+ described_class.new prefix:
21
+ end
22
+
23
+ it 'can be instantiated' do
24
+ expect(cache).to be_a described_class
25
+ end
26
+
27
+ it 'defaults to :memory: mode' do
28
+ expect(cache.filename).to eq ':memory:'
29
+ end
30
+
31
+ it 'can be switchted to file mode' do
32
+ expect(SQLite3::Database).to receive(:new).with('foo.sqlite').
33
+ and_return(double.as_null_object)
34
+ cache = described_class.new prefix:, filename: 'foo.sqlite'
35
+ expect(cache.filename).to eq 'foo.sqlite'
36
+ end
37
+
38
+ it 'can get/set a key' do
39
+ key, value = 'foo', test_value
40
+ queried_value = nil
41
+ expect {
42
+ cache[key] = value
43
+ }.to change {
44
+ queried_value = cache[key]
45
+ }.from(nil).to(Ollama::Documents::Record[value])
46
+ expect(queried_value.embedding).to eq [ 0.5 ] * 1_024
47
+ end
48
+
49
+ it 'can determine if key exists' do
50
+ key, value = 'foo', test_value
51
+ expect {
52
+ cache[key] = value
53
+ }.to change {
54
+ cache.key?(key)
55
+ }.from(false).to(true)
56
+ end
57
+
58
+ it 'can set key with different prefixes' do
59
+ key, value = 'foo', test_value
60
+ expect {
61
+ cache[key] = value
62
+ }.to change {
63
+ cache.size
64
+ }.from(0).to(1)
65
+ cache2 = cache.dup
66
+ cache2.prefix = 'test2-'
67
+ expect {
68
+ cache2[key] = value
69
+ }.to change {
70
+ cache2.size
71
+ }.from(0).to(1)
72
+ expect(cache.size).to eq 1
73
+ s = 0
74
+ cache.full_each { s += 1 }
75
+ expect(s).to eq 2
76
+ end
77
+
78
+ it 'can delete' do
79
+ key, value = 'foo', test_value
80
+ expect(cache.delete(key)).to be_falsy
81
+ cache[key] = value
82
+ expect {
83
+ expect(cache.delete(key)).to be_truthy
84
+ }.to change {
85
+ cache.key?(key)
86
+ }.from(true).to(false)
87
+ end
88
+
89
+ it 'returns size' do
90
+ key, value = 'foo', test_value
91
+ expect {
92
+ cache[key] = value
93
+ }.to change {
94
+ cache.size
95
+ }.from(0).to(1)
96
+ end
97
+
98
+ it 'can convert_to_vector' do
99
+ vector = [ 23.0, 666.0 ]
100
+ expect(cache.convert_to_vector(vector)).to eq vector
101
+ end
102
+
103
+ it 'can clear' do
104
+ key, value = 'foo', { embedding: [ 0.5 ] * 1_024 }
105
+ cache[key] = value
106
+ expect {
107
+ expect(cache.clear).to eq cache
108
+ }.to change {
109
+ cache.size
110
+ }.from(1).to(0)
111
+ end
112
+
113
+ it 'can clear for tags' do
114
+ key, value = 'foo', { tags: %w[ foo ], embedding: [ 0.5 ] * 1_024 }
115
+ cache[key] = value
116
+ key, value = 'bar', { embedding: [ 0.5 ] * 1_024 }
117
+ cache[key] = value
118
+ expect {
119
+ expect(cache.clear_for_tags(%w[ #foo ])).to eq cache
120
+ }.to change {
121
+ cache.size
122
+ }.from(2).to(1)
123
+ expect(cache).not_to be_key 'foo'
124
+ expect(cache).to be_key 'bar'
125
+ end
126
+
127
+ it 'can return tags' do
128
+ key, value = 'foo', { tags: %w[ foo ], embedding: [ 0.5 ] * 1_024 }
129
+ cache[key] = value
130
+ key, value = 'bar', { tags: %w[ bar baz ], embedding: [ 0.5 ] * 1_024 }
131
+ cache[key] = value
132
+ tags = cache.tags
133
+ expect(tags).to be_a Ollama::Utils::Tags
134
+ expect(tags.to_a).to eq %w[ bar baz foo ]
135
+ end
136
+
137
+ it 'can iterate over keys under a prefix' do
138
+ cache['foo'] = test_value
139
+ expect(cache.to_a).to eq [ [ 'test-foo', Ollama::Documents::Record[test_value] ] ]
140
+ end
141
+ end
@@ -1,30 +1,93 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Handlers::Say do
4
+ let :say do
5
+ described_class.new
6
+ end
7
+
4
8
  it 'has .to_proc' do
5
9
  expect_any_instance_of(described_class).to receive(:call).with(:foo)
6
10
  described_class.call(:foo)
7
11
  end
8
12
 
9
- it 'can print response' do
10
- output = double('output', :sync= => true)
13
+ it 'can be instantiated' do
14
+ expect(say).to be_a described_class
15
+ end
16
+
17
+ it 'can be instantiated with a given voice' do
18
+ expect_any_instance_of(described_class).to receive(:command).
19
+ with(hash_including(voice: 'TheVoice')).and_return %w[ true ]
20
+ say = described_class.new(voice: 'TheVoice')
21
+ expect(say).to be_a described_class
22
+ end
23
+
24
+ describe 'command' do
25
+ it 'can be instantiated interactively' do
26
+ expect_any_instance_of(described_class).to receive(:command).
27
+ with(hash_including(interactive: true)).and_return %w[ true ]
28
+ say = described_class.new(interactive: true)
29
+ expect(say).to be_a described_class
30
+ end
31
+
32
+ it 'can set the voice' do
33
+ expect(say.send(:command, voice: 'TheVoice', interactive: nil)).to eq(
34
+ %w[ say -v TheVoice ]
35
+ )
36
+ end
37
+
38
+ it 'can be instantiated interactively with green' do
39
+ expect_any_instance_of(described_class).to receive(:command).
40
+ with(hash_including(interactive: 'green')).and_return %w[ true ]
41
+ say = described_class.new(interactive: 'green')
42
+ expect(say).to be_a described_class
43
+ end
44
+
45
+ it 'can set interactive mode' do
46
+ expect(say.send(:command, voice: nil, interactive: true)).to eq(
47
+ %w[ say -i ]
48
+ )
49
+ end
50
+
51
+ it 'can set interactive mode to green' do
52
+ expect(say.send(:command, voice: nil, interactive: 'green')).to eq(
53
+ %w[ say --interactive=green ]
54
+ )
55
+ end
56
+ end
57
+
58
+ it 'can say response' do
59
+ output = double('output', :sync= => true, closed?: false)
11
60
  expect(output).to receive(:print).with('testing')
12
61
  expect(output).to receive(:close)
13
- print = described_class.new(output:)
62
+ say = described_class.new(output:)
14
63
  response = double('response', response: 'testing', done: false)
15
- print.call(response)
64
+ say.call(response)
16
65
  response = double('response', response: nil, message: nil, done: true)
17
- print.call(response)
66
+ say.call(response)
18
67
  end
19
68
 
20
- it 'can print message content' do
21
- output = double('output', :sync= => true)
69
+ it 'can say message content' do
70
+ output = double('output', :sync= => true, closed?: false)
22
71
  expect(output).to receive(:print).with('testing')
23
72
  expect(output).to receive(:close)
24
- print = described_class.new(output:)
73
+ say = described_class.new(output:)
25
74
  response = double('response', response: nil, message: double(content: 'testing'), done: false)
26
- print.call(response)
75
+ say.call(response)
76
+ response = double('response', response: nil, message: nil, done: true)
77
+ say.call(response)
78
+ end
79
+
80
+ it 'can reopen output if closed' do
81
+ output = double('output', :sync= => true, closed?: true)
82
+ reopened_output = double('output', :sync= => true, closed?: false, pid: 666)
83
+ expect(reopened_output).to receive(:print).with('testing')
84
+ expect(reopened_output).to receive(:close)
85
+ say = described_class.new(output:)
86
+ expect(say).to receive(:open_output).and_return(reopened_output)
87
+ response = double('response', response: 'testing', done: false)
88
+ say.call(response)
27
89
  response = double('response', response: nil, message: nil, done: true)
28
- print.call(response)
90
+ say.call(response)
29
91
  end
92
+
30
93
  end
@@ -77,12 +77,12 @@ RSpec.describe Ollama::Utils::Fetcher do
77
77
  stub_request(:get, url).
78
78
  with(headers: fetcher.headers).
79
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
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
86
  end
87
87
 
88
88
  it 'can redirect' do
@@ -107,7 +107,7 @@ RSpec.describe Ollama::Utils::Fetcher do
107
107
 
108
108
  it 'can .execute and fail' do
109
109
  expect(IO).to receive(:popen).and_raise StandardError
110
- expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
110
+ expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
111
111
  described_class.execute('foobar') do |file|
112
112
  expect(file).to be_a StringIO
113
113
  expect(file.read).to be_empty
@@ -115,23 +115,23 @@ RSpec.describe Ollama::Utils::Fetcher do
115
115
  end
116
116
  end
117
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
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
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
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
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
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
137
  end
@@ -10,6 +10,11 @@ RSpec.describe Ollama::Utils::Tags do
10
10
  expect(tags.to_a).to eq %w[ bar foo ]
11
11
  end
12
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
+
13
18
  it 'tags can be added to it' do
14
19
  tags = described_class.new([ 'foo' ])
15
20
  tags.add 'bar'
@@ -27,13 +32,13 @@ RSpec.describe Ollama::Utils::Tags do
27
32
  expect { tags.clear }.to change { tags.size }.from(2).to(0)
28
33
  end
29
34
 
30
- it 'tags can be empt' do
35
+ it 'tags can be empty' do
31
36
  tags = described_class.new([ 'foo' ])
32
37
  expect { tags.clear }.to change { tags.empty? }.from(false).to(true)
33
38
  end
34
39
 
35
40
  it 'can be output nicely' do
36
- expect(described_class.new(%w[ foo bar ]).to_s).to eq '#bar #foo'
41
+ expect(described_class.new(%w[ #foo bar ]).to_s).to eq '#bar #foo'
37
42
  end
38
43
 
39
44
  it 'can be output nicely with links to source' do