ollama-ruby 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0'
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.0 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.0".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-26"
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