ollama-ruby 0.11.0 → 0.12.1

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.
@@ -0,0 +1,215 @@
1
+ require 'ollama/documents/cache/common'
2
+ require 'sqlite3'
3
+ require 'sqlite_vec'
4
+ require 'digest/md5'
5
+
6
+ class Ollama::Documents::Cache::SQLiteCache
7
+ include Ollama::Documents::Cache::Common
8
+
9
+ def initialize(prefix:, embedding_length: 1_024, filename: ':memory:', debug: false)
10
+ super(prefix:)
11
+ @embedding_length = embedding_length
12
+ @filename = filename
13
+ @debug = debug
14
+ setup_database(filename)
15
+ end
16
+
17
+ attr_reader :filename # filename for the database, `:memory:` is in memory
18
+
19
+ attr_reader :embedding_length # length of the embeddings vector
20
+
21
+ def [](key)
22
+ result = execute(
23
+ %{
24
+ SELECT records.key, records.text, records.norm, records.source,
25
+ records.tags, embeddings.embedding
26
+ FROM records
27
+ INNER JOIN embeddings ON records.embedding_id = embeddings.rowid
28
+ WHERE records.key = ?
29
+ },
30
+ pre(key)
31
+ )&.first or return
32
+ key, text, norm, source, tags, embedding = *result
33
+ embedding = embedding.unpack("f*")
34
+ tags = Ollama::Utils::Tags.new(JSON(tags.to_s).to_a, source:)
35
+ convert_value_to_record(key:, text:, norm:, source:, tags:, embedding:)
36
+ end
37
+
38
+ def []=(key, value)
39
+ value = convert_value_to_record(value)
40
+ embedding = value.embedding.pack("f*")
41
+ execute(%{BEGIN})
42
+ execute(%{INSERT INTO embeddings(embedding) VALUES(?)}, [ embedding ])
43
+ embedding_id, = execute(%{ SELECT last_insert_rowid() }).flatten
44
+ execute(%{
45
+ INSERT INTO records(key,text,embedding_id,norm,source,tags)
46
+ VALUES(?,?,?,?,?,?)
47
+ }, [ pre(key), value.text, embedding_id, value.norm, value.source, JSON(value.tags) ])
48
+ execute(%{COMMIT})
49
+ end
50
+
51
+ def key?(key)
52
+ execute(
53
+ %{ SELECT count(records.key) FROM records WHERE records.key = ? },
54
+ pre(key)
55
+ ).flatten.first == 1
56
+ end
57
+
58
+ def delete(key)
59
+ result = key?(key) ? pre(key) : nil
60
+ execute(
61
+ %{ DELETE FROM records WHERE records.key = ? },
62
+ pre(key)
63
+ )
64
+ result
65
+ end
66
+
67
+ def tags
68
+ result = Ollama::Utils::Tags.new
69
+ execute(%{
70
+ SELECT DISTINCT(tags) FROM records WHERE key LIKE ?
71
+ }, [ "#@prefix%" ]
72
+ ).flatten.each do
73
+ JSON(_1).each { |t| result.add(t) }
74
+ end
75
+ result
76
+ end
77
+
78
+ def size
79
+ execute(%{SELECT COUNT(*) FROM records WHERE key LIKE ?}, [ "#@prefix%" ]).flatten.first
80
+ end
81
+
82
+ def clear_for_tags(tags = nil)
83
+ tags = Ollama::Utils::Tags.new(tags).to_a
84
+ if tags.present?
85
+ records = find_records_for_tags(tags)
86
+ keys = '(%s)' % records.transpose.first.map { "'%s'" % quote(_1) }.join(?,)
87
+ execute(%{DELETE FROM records WHERE key IN #{keys}})
88
+ else
89
+ clear
90
+ end
91
+ self
92
+ end
93
+
94
+ def clear
95
+ execute(%{DELETE FROM records WHERE key LIKE ?}, [ "#@prefix%" ])
96
+ self
97
+ end
98
+
99
+ def each(prefix: "#@prefix%", &block)
100
+ execute(%{
101
+ SELECT records.key, records.text, records.norm, records.source,
102
+ records.tags, embeddings.embedding
103
+ FROM records
104
+ INNER JOIN embeddings ON records.embedding_id = embeddings.rowid
105
+ WHERE records.key LIKE ?
106
+ }, [ prefix ]).each do |key, text, norm, source, tags, embedding|
107
+ embedding = embedding.unpack("f*")
108
+ tags = Ollama::Utils::Tags.new(JSON(tags.to_s).to_a, source:)
109
+ value = convert_value_to_record(key:, text:, norm:, source:, tags:, embedding:)
110
+ block.(key, value)
111
+ end
112
+ end
113
+ include Enumerable
114
+
115
+ def full_each(&block)
116
+ each(prefix: ?%, &block)
117
+ end
118
+
119
+ def convert_to_vector(vector)
120
+ vector
121
+ end
122
+
123
+ def find_records_for_tags(tags)
124
+ if tags.present?
125
+ tags_filter = Ollama::Utils::Tags.new(tags).to_a
126
+ unless tags_filter.empty?
127
+ tags_where = ' AND (%s)' % tags_filter.map {
128
+ 'tags LIKE "%%%s%%"' % quote(_1)
129
+ }.join(' OR ')
130
+ end
131
+ end
132
+ records = execute(%{
133
+ SELECT key, tags, embedding_id
134
+ FROM records
135
+ WHERE key LIKE ?#{tags_where}
136
+ }, [ "#@prefix%" ])
137
+ if tags_filter
138
+ records = records.select { |key, tags, embedding_id|
139
+ (tags_filter & JSON(tags.to_s).to_a).size >= 1
140
+ }
141
+ end
142
+ records
143
+ end
144
+
145
+ def find_records(needle, tags: nil, max_records: nil)
146
+ needle.size != @embedding_length and
147
+ raise ArgumentError, "needle embedding length != %s" % @embedding_length
148
+ needle_binary = needle.pack("f*")
149
+ max_records = [ max_records, size, 4_096 ].compact.min
150
+ records = find_records_for_tags(tags)
151
+ rowids_where = '(%s)' % records.transpose.last&.join(?,)
152
+ execute(%{
153
+ SELECT records.key, records.text, records.norm, records.source,
154
+ records.tags, embeddings.embedding
155
+ FROM records
156
+ INNER JOIN embeddings ON records.embedding_id = embeddings.rowid
157
+ WHERE embeddings.rowid IN #{rowids_where}
158
+ AND embeddings.embedding MATCH ? AND embeddings.k = ?
159
+ }, [ needle_binary, max_records ]).map do |key, text, norm, source, tags, embedding|
160
+ key = unpre(key)
161
+ embedding = embedding.unpack("f*")
162
+ tags = Ollama::Utils::Tags.new(JSON(tags.to_s).to_a, source:)
163
+ convert_value_to_record(key:, text:, norm:, source:, tags:, embedding:)
164
+ end
165
+ end
166
+
167
+ private
168
+
169
+ def execute(*a)
170
+ if @debug
171
+ e = a[0].gsub(/^\s*\n/, '')
172
+ e = e.gsub(/\A\s+/, '')
173
+ n = $&.to_s.size
174
+ e = e.gsub(/^\s{0,#{n}}/, '')
175
+ e = e.chomp
176
+ STDERR.puts("EXPLANATION:\n%s\n%s" % [
177
+ e,
178
+ @database.execute("EXPLAIN #{e}", *a[1..-1]).pretty_inspect
179
+ ])
180
+ end
181
+ @database.execute(*a)
182
+ end
183
+
184
+ def quote(string)
185
+ SQLite3::Database.quote(string)
186
+ end
187
+
188
+ def setup_database(filename)
189
+ @database = SQLite3::Database.new(filename)
190
+ @database.enable_load_extension(true)
191
+ SqliteVec.load(@database)
192
+ @database.enable_load_extension(false)
193
+ execute %{
194
+ CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
195
+ embedding float[#@embedding_length]
196
+ )
197
+ }
198
+ execute %{
199
+ CREATE TABLE IF NOT EXISTS records (
200
+ key text NOT NULL PRIMARY KEY ON CONFLICT REPLACE,
201
+ text text NOT NULL DEFAULT '',
202
+ embedding_id integer,
203
+ norm float NOT NULL DEFAULT 0.0,
204
+ source text,
205
+ tags json NOT NULL DEFAULT [],
206
+ FOREIGN KEY(embedding_id) REFERENCES embeddings(id) ON DELETE CASCADE
207
+ )
208
+ }
209
+ end
210
+
211
+ def convert_value_to_record(value)
212
+ value.is_a?(Ollama::Documents::Record) and return value
213
+ Ollama::Documents::Record[value.to_hash]
214
+ end
215
+ end
@@ -21,6 +21,7 @@ module Ollama::Documents::Splitters
21
21
  e
22
22
  end
23
23
  infobar.newline
24
+ embeddings.size < 2 and return sentences
24
25
  distances = embeddings.each_cons(2).map do |a, b|
25
26
  1.0 - cosine_similarity(a:, b:)
26
27
  end
@@ -4,11 +4,13 @@ require 'kramdown/ansi'
4
4
 
5
5
  class Ollama::Documents
6
6
  end
7
- class Ollama::Documents::Cache
7
+ module Ollama::Documents::Cache
8
8
  end
9
+ require 'ollama/documents/cache/records'
9
10
  require 'ollama/documents/cache/memory_cache'
10
11
  require 'ollama/documents/cache/redis_cache'
11
12
  require 'ollama/documents/cache/redis_backed_memory_cache'
13
+ require 'ollama/documents/cache/sqlite_cache'
12
14
  module Ollama::Documents::Splitters
13
15
  end
14
16
  require 'ollama/documents/splitters/character'
@@ -16,32 +18,16 @@ require 'ollama/documents/splitters/semantic'
16
18
 
17
19
  class Ollama::Documents
18
20
  include Kramdown::ANSI::Width
21
+ include Ollama::Documents::Cache
19
22
 
20
- class Record < JSON::GenericObject
21
- def to_s
22
- my_tags = tags_set
23
- my_tags.empty? or my_tags = " #{my_tags}"
24
- "#<#{self.class} #{text.inspect}#{my_tags} #{similarity || 'n/a'}>"
25
- end
26
-
27
- def tags_set
28
- Ollama::Utils::Tags.new(tags, source:)
29
- end
30
-
31
- def ==(other)
32
- text == other.text
33
- end
23
+ Record = Class.new Ollama::Documents::Cache::Records::Record
34
24
 
35
- alias inspect to_s
36
- end
37
-
38
- def initialize(ollama:, model:, model_options: nil, collection: nil, cache: MemoryCache, redis_url: nil, debug: false)
25
+ def initialize(ollama:, model:, model_options: nil, collection: nil, embedding_length: 1_024, cache: MemoryCache, database_filename: nil, redis_url: nil, debug: false)
39
26
  collection ||= default_collection
40
- @ollama, @model, @model_options, @collection =
41
- ollama, model, model_options, collection.to_sym
42
- @redis_url = redis_url
43
- @cache = connect_cache(cache)
44
- @debug = debug
27
+ @ollama, @model, @model_options, @collection, @debug =
28
+ ollama, model, model_options, collection.to_sym, debug
29
+ database_filename ||= ':memory:'
30
+ @cache = connect_cache(cache, redis_url, embedding_length, database_filename)
45
31
  end
46
32
 
47
33
  def default_collection
@@ -110,40 +96,19 @@ class Ollama::Documents
110
96
  end
111
97
 
112
98
  def clear(tags: nil)
113
- if tags
114
- tags = Ollama::Utils::Tags.new(Array(tags)).to_a
115
- @cache.each do |key, record|
116
- if (tags & record.tags).size >= 1
117
- @cache.delete(@cache.unpre(key))
118
- end
119
- end
120
- else
121
- @cache.clear
122
- end
99
+ @cache.clear(tags:)
123
100
  self
124
101
  end
125
102
 
126
- def find(string, tags: nil, prompt: nil)
127
- needle = convert_to_vector(string, prompt:)
128
- needle_norm = @cache.norm(needle)
129
- records = @cache
130
- if tags
131
- tags = Ollama::Utils::Tags.new(tags).to_a
132
- records = records.select { |_key, record| (tags & record.tags).size >= 1 }
133
- end
134
- records = records.sort_by { |key, record|
135
- record.key = key
136
- record.similarity = @cache.cosine_similarity(
137
- a: needle,
138
- b: record.embedding,
139
- a_norm: needle_norm,
140
- b_norm: record.norm,
141
- )
142
- }
143
- records.transpose.last&.reverse.to_a
103
+ def find(string, tags: nil, prompt: nil, max_records: nil)
104
+ needle = convert_to_vector(string, prompt:)
105
+ @cache.find_records(needle, tags:, max_records: nil)
144
106
  end
145
107
 
146
108
  def find_where(string, text_size: nil, text_count: nil, **opts)
109
+ if text_count
110
+ opts[:max_records] = text_count
111
+ end
147
112
  records = find(string, **opts)
148
113
  size, count = 0, 0
149
114
  records.take_while do |record|
@@ -162,30 +127,38 @@ class Ollama::Documents
162
127
  end
163
128
 
164
129
  def tags
165
- @cache.each_with_object(Ollama::Utils::Tags.new) do |(_, record), t|
166
- record.tags.each do |tag|
167
- t.add(tag, source: record.source)
168
- end
169
- end
130
+ @cache.tags
170
131
  end
171
132
 
172
133
  private
173
134
 
174
- def connect_cache(cache_class)
135
+ def connect_cache(cache_class, redis_url, embedding_length, database_filename)
175
136
  cache = nil
176
- if cache_class.instance_method(:redis)
137
+ if (cache_class.instance_method(:redis) rescue nil)
177
138
  begin
178
- cache = cache_class.new(prefix:, url: @redis_url, object_class: Record)
139
+ cache = cache_class.new(prefix:, url: redis_url, object_class: Record)
179
140
  cache.size
180
141
  rescue Redis::CannotConnectError
181
142
  STDERR.puts(
182
- "Cannot connect to redis URL #{@redis_url.inspect}, "\
143
+ "Cannot connect to redis URL #{redis_url.inspect}, "\
183
144
  "falling back to MemoryCache."
184
145
  )
185
146
  end
147
+ elsif cache_class == SQLiteCache
148
+ cache = cache_class.new(
149
+ prefix:,
150
+ embedding_length:,
151
+ filename: database_filename,
152
+ debug: @debug
153
+ )
186
154
  end
187
155
  ensure
188
- cache ||= MemoryCache.new(prefix:)
156
+ cache ||= MemoryCache.new(prefix:,)
157
+ cache.respond_to?(:find_records) or cache.extend(Records::FindRecords)
158
+ cache.extend(Records::Tags)
159
+ if cache.respond_to?(:redis)
160
+ cache.extend(Records::RedisFullEach)
161
+ end
189
162
  return cache
190
163
  end
191
164
 
@@ -8,7 +8,21 @@ module Ollama::Utils::Chooser
8
8
 
9
9
  module_function
10
10
 
11
- def choose(entries, prompt: 'Search? %s')
11
+ # The choose method presents a list of entries and prompts the user
12
+ # for input, allowing them to select one entry based on their input.
13
+ #
14
+ # @param entries [Array] the list of entries to present to the user
15
+ # @param prompt [String] the prompt message to display when asking for input (default: 'Search? %s')
16
+ # @param return_immediately [Boolean] whether to immediately return the first entry if there is only one or nil when there is none (default: false)
17
+ #
18
+ # @return [Object] the selected entry, or nil if no entry was chosen
19
+ #
20
+ # @example
21
+ # choose(['entry1', 'entry2'], prompt: 'Choose an option:')
22
+ def choose(entries, prompt: 'Search? %s', return_immediately: false)
23
+ if return_immediately && entries.size <= 1
24
+ return entries.first
25
+ end
12
26
  entry = Search.new(
13
27
  prompt:,
14
28
  match: -> answer {
@@ -3,7 +3,7 @@ class Ollama::Utils::Tags
3
3
  include Term::ANSIColor
4
4
 
5
5
  def initialize(tag, source: nil)
6
- super(tag.to_s)
6
+ super(tag.to_s.gsub(/\A#+/, ''))
7
7
  self.source = source
8
8
  end
9
9
 
@@ -26,6 +26,7 @@ class Ollama::Utils::Tags
26
26
  end
27
27
 
28
28
  def initialize(tags = [], source: nil)
29
+ tags = Array(tags)
29
30
  @set = []
30
31
  tags.each { |tag| add(tag, source:) }
31
32
  end
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.11.0'
3
+ VERSION = '0.12.1'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/ollama-ruby.gemspec CHANGED
@@ -1,31 +1,31 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.11.0 ruby lib
2
+ # stub: ollama-ruby 0.12.1 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.11.0".freeze
6
+ s.version = "0.12.1".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Florian Frank".freeze]
11
- s.date = "2024-11-20"
11
+ s.date = "2024-11-27"
12
12
  s.description = "Library that allows interacting with the Ollama API".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["ollama_console".freeze, "ollama_chat".freeze, "ollama_update".freeze, "ollama_cli".freeze]
15
- s.extra_rdoc_files = ["README.md".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze]
16
- s.files = [".envrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_cli".freeze, "bin/ollama_console".freeze, "bin/ollama_update".freeze, "config/redis.conf".freeze, "docker-compose.yml".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze, "ollama-ruby.gemspec".freeze, "spec/assets/embeddings.json".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
15
+ s.extra_rdoc_files = ["README.md".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/records.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/cache/sqlite_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze]
16
+ s.files = [".envrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_cli".freeze, "bin/ollama_console".freeze, "bin/ollama_update".freeze, "config/redis.conf".freeze, "docker-compose.yml".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/records.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/cache/sqlite_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze, "ollama-ruby.gemspec".freeze, "spec/assets/embeddings.json".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/cache/memory_cache_spec.rb".freeze, "spec/ollama/documents/cache/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/cache/redis_cache_spec.rb".freeze, "spec/ollama/documents/cache/sqlite_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
17
17
  s.homepage = "https://github.com/flori/ollama-ruby".freeze
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "Ollama-ruby - Interacting with the Ollama API".freeze, "--main".freeze, "README.md".freeze]
20
20
  s.required_ruby_version = Gem::Requirement.new("~> 3.1".freeze)
21
21
  s.rubygems_version = "3.5.22".freeze
22
22
  s.summary = "Interacting with the Ollama API".freeze
23
- s.test_files = ["spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze]
23
+ s.test_files = ["spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/cache/memory_cache_spec.rb".freeze, "spec/ollama/documents/cache/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/cache/redis_cache_spec.rb".freeze, "spec/ollama/documents/cache/sqlite_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze]
24
24
 
25
25
  s.specification_version = 4
26
26
 
27
27
  s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.19".freeze])
28
- s.add_development_dependency(%q<all_images>.freeze, ["~> 0.4".freeze])
28
+ s.add_development_dependency(%q<all_images>.freeze, ["~> 0.6".freeze])
29
29
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
30
30
  s.add_development_dependency(%q<webmock>.freeze, [">= 0".freeze])
31
31
  s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
@@ -48,4 +48,6 @@ Gem::Specification.new do |s|
48
48
  s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.34".freeze])
49
49
  s.add_runtime_dependency(%q<kramdown-ansi>.freeze, ["~> 0.0".freeze, ">= 0.0.1".freeze])
50
50
  s.add_runtime_dependency(%q<ostruct>.freeze, ["~> 0.0".freeze])
51
+ s.add_runtime_dependency(%q<sqlite-vec>.freeze, ["~> 0.0".freeze])
52
+ s.add_runtime_dependency(%q<sqlite3>.freeze, ["~> 2.0".freeze, ">= 2.0.1".freeze])
51
53
  end
@@ -1,8 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::MemoryCache do
4
+ let :prefix do
5
+ 'test-'
6
+ end
7
+
4
8
  let :cache do
5
- described_class.new prefix: 'test-'
9
+ described_class.new prefix:
6
10
  end
7
11
 
8
12
  it 'can be instantiated' do
@@ -27,16 +31,46 @@ RSpec.describe Ollama::Documents::MemoryCache do
27
31
  }.from(false).to(true)
28
32
  end
29
33
 
34
+ it 'can set key with different prefixes' do
35
+ key, value = 'foo', { test: true }
36
+ expect {
37
+ cache[key] = value
38
+ }.to change {
39
+ cache.size
40
+ }.from(0).to(1)
41
+ cache2 = cache.dup
42
+ cache2.prefix = 'test2-'
43
+ expect {
44
+ cache2[key] = value
45
+ }.to change {
46
+ cache2.size
47
+ }.from(0).to(1)
48
+ expect(cache.size).to eq 1
49
+ s = 0
50
+ cache.full_each { s += 1 }
51
+ expect(s).to eq 2
52
+ end
53
+
30
54
  it 'can delete' do
31
55
  key, value = 'foo', { test: true }
56
+ expect(cache.delete(key)).to be_falsy
32
57
  cache[key] = value
33
58
  expect {
34
- cache.delete(key)
59
+ expect(cache.delete(key)).to be_truthy
35
60
  }.to change {
36
61
  cache.key?(key)
37
62
  }.from(true).to(false)
38
63
  end
39
64
 
65
+ it 'can iterate over keys, values' do
66
+ key, value = 'foo', { test: true }
67
+ cache[key] = value
68
+ cache.each do |k, v|
69
+ expect(k).to eq prefix + key
70
+ expect(v).to eq value
71
+ end
72
+ end
73
+
40
74
  it 'returns size' do
41
75
  key, value = 'foo', { test: true }
42
76
  expect {
@@ -58,6 +92,6 @@ RSpec.describe Ollama::Documents::MemoryCache do
58
92
 
59
93
  it 'can iterate over keys under a prefix' do
60
94
  cache['foo'] = 'bar'
61
- expect(cache.to_a).to eq [ %w[ test-foo bar ] ]
95
+ expect(cache.to_a).to eq [ %W[ #{prefix}foo bar ] ]
62
96
  end
63
97
  end
@@ -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