ollama-ruby 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0b3ea2bd67e3f4fa2ca4da88a25cb869fc81e35578f1e7fd97ba43e84fc2278
4
- data.tar.gz: 626c534bd2fd0580ab0520e8b70587489edbc963e179be0f800ee63235690b33
3
+ metadata.gz: d2a82c4fc1db4e92e628d0e3a84525273f2ee3bd994f34185c742f0dab1d9b78
4
+ data.tar.gz: b77caa026511e2bc49bdf3d2e3782cc6a1edd1f60161f1301efbc927dc2d3cba
5
5
  SHA512:
6
- metadata.gz: 149986d8144b1bc2c20771e245ead20f6e6bc07b46dbe26f8f355e0bc61eca146cc085a920dcbe3e3e08de65632693a35b6995c9dffef288aa929dd6b034de16
7
- data.tar.gz: 4214aa2911db561635011b8ea200074d15c74b93bf7abb3c8e77af9c40ac5d8994e908e2ade8e5f288c2919678e03ea5d84d07684a63ba1f8039de52b6091a86
6
+ metadata.gz: 6ea50f6c8fd275365b52b4c7047abc627079804dd7db61120dbbcf2c6b3f3fddf1946a46508fbb0bc26d0d7284d3b23f4f934b7c418bc91799417a5c2b72332c
7
+ data.tar.gz: cef39db9d4eb0ee160c53c4e522a158942c3532203f46d50ee88af2c1f3f36aac0030087e71864045c4979018be4891329155ad0e8863c4e8c52080ba3e28f3f
data/CHANGES.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changes
2
2
 
3
+ ## 2024-10-20 v0.9.2
4
+
5
+ * Added SourceParsing module and update parse_source method to use it:
6
+ + Added `SourceParsing` module with `parse_source` method that handles
7
+ different file types (e.g. HTML, XML, CSV, RSS)
8
+ + Added `parse_csv` method to `SourceParsing` module
9
+ + Updated `parse_source` method in main file to include new functionality
10
+ * Add colorize texts spec for Ollama::Utils::ColorizeTexts to test its
11
+ functionality.
12
+ * Added test for expected output of `documents.tags`
13
+ * Add test for empty Ollama options:
14
+ + Added test case for `Ollama::Options` being empty
15
+ * Display (embedding) model options in info output
16
+ * Only show `collection_stats` if embedding is performed
17
+ * Add empty? method to DTO class:
18
+ + Added `empty?` method to `Ollama::DTO` class using `to_hash.empty?`
19
+ + Method is used to check if the object's hash representation is empty.
20
+
21
+ ## 2024-10-19 v0.9.1
22
+
23
+ * Fixing string interpolation in `import_source` method:
24
+ + Changed result to use `#{}` instead of `%{}` for string interpolation
25
+ * Move `pull_model_unless_present` method:
26
+ + Moved the method before other methods
27
+ * Moved Switch classes and `setup_switches` method into Switches module:
28
+ + Moved the classes and method into a new module
29
+ * Utils::Fetcher: Normalize URL in fetcher utility:
30
+ + Added `normalize_url` method to class Ollama::Utils::Fetcher
31
+ + Normalizes URL by decoding URI components, removing anchors, and escaping special characters
32
+ + `excon` method now calls `normalize_url` on the provided URL
33
+ + Added specs for `normalize_url` in `fetcher_spec.rb`
34
+ * Remove Ollama top level Namespace b/c we include it from `ollama_chat`:
35
+ + Removed the top-level namespace
36
+
3
37
  ## 2024-10-18 v0.9.0
4
38
 
5
39
  * Add document policy chooser and modify embedding/importing/summarizing
data/bin/ollama_chat CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'ollama'
4
4
  include Ollama
5
+ include Tins::GO
5
6
  require 'term/ansicolor'
6
7
  include Term::ANSIColor
7
- include Tins::GO
8
8
  require 'reline'
9
9
  require 'reverse_markdown'
10
10
  require 'complex_config'
@@ -108,7 +108,7 @@ class OllamaChatConfig
108
108
  end
109
109
 
110
110
  class FollowChat
111
- include Ollama::Handlers::Concern
111
+ include Handlers::Concern
112
112
  include Term::ANSIColor
113
113
 
114
114
  def initialize(messages:, markdown: false, voice: nil, output: $stdout)
@@ -164,114 +164,142 @@ class FollowChat
164
164
  end
165
165
  end
166
166
 
167
- module CheckSwitch
168
- extend Tins::Concern
167
+ module Switches
168
+ module CheckSwitch
169
+ extend Tins::Concern
169
170
 
170
- included do
171
- alias_method :on?, :value
172
- end
171
+ included do
172
+ alias_method :on?, :value
173
+ end
173
174
 
174
- def off?
175
- !on?
176
- end
175
+ def off?
176
+ !on?
177
+ end
177
178
 
178
- def show
179
- puts @msg[value]
179
+ def show
180
+ puts @msg[value]
181
+ end
180
182
  end
181
- end
182
183
 
183
- class Switch
184
- def initialize(name, msg:, config: $config)
185
- @value = [ false, true ].include?(config) ? config : !!config.send("#{name}?")
186
- @msg = msg
187
- end
184
+ class Switch
185
+ def initialize(name, msg:, config: $config)
186
+ @value = [ false, true ].include?(config) ? config : !!config.send("#{name}?")
187
+ @msg = msg
188
+ end
188
189
 
189
- attr_reader :value
190
+ attr_reader :value
190
191
 
191
- def set(value, show: false)
192
- @value = !!value
193
- show && self.show
194
- end
192
+ def set(value, show: false)
193
+ @value = !!value
194
+ show && self.show
195
+ end
196
+
197
+ def toggle(show: true)
198
+ @value = !@value
199
+ show && self.show
200
+ end
195
201
 
196
- def toggle(show: true)
197
- @value = !@value
198
- show && self.show
202
+ include CheckSwitch
199
203
  end
200
204
 
201
- include CheckSwitch
202
- end
205
+ class CombinedSwitch
206
+ def initialize(value:, msg:)
207
+ @value = value
208
+ @msg = msg
209
+ end
203
210
 
204
- class CombinedSwitch
205
- def initialize(value:, msg:)
206
- @value = value
207
- @msg = msg
208
- end
211
+ def value
212
+ @value.()
213
+ end
209
214
 
210
- def value
211
- @value.()
215
+ include CheckSwitch
212
216
  end
213
217
 
214
- include CheckSwitch
215
- end
218
+ def setup_switches
219
+ $markdown = Switch.new(
220
+ :markdown,
221
+ msg: {
222
+ true => "Using #{italic{'ANSI'}} markdown to output content.",
223
+ false => "Using plaintext for outputting content.",
224
+ }
225
+ )
216
226
 
217
- def setup_switches
218
- $markdown = Switch.new(
219
- :markdown,
220
- msg: {
221
- true => "Using #{italic{'ANSI'}} markdown to output content.",
222
- false => "Using plaintext for outputting content.",
223
- }
224
- )
227
+ $stream = Switch.new(
228
+ :stream,
229
+ msg: {
230
+ true => "Streaming enabled.",
231
+ false => "Streaming disabled.",
232
+ }
233
+ )
225
234
 
226
- $stream = Switch.new(
227
- :stream,
228
- msg: {
229
- true => "Streaming enabled.",
230
- false => "Streaming disabled.",
231
- }
232
- )
235
+ $voice = Switch.new(
236
+ :stream,
237
+ msg: {
238
+ true => "Voice output enabled.",
239
+ false => "Voice output disabled.",
240
+ },
241
+ config: $config.voice
242
+ )
233
243
 
234
- $voice = Switch.new(
235
- :stream,
236
- msg: {
237
- true => "Voice output enabled.",
238
- false => "Voice output disabled.",
239
- },
240
- config: $config.voice
241
- )
244
+ $embedding_enabled = Switch.new(
245
+ :embedding_enabled,
246
+ msg: {
247
+ true => "Embedding enabled.",
248
+ false => "Embedding disabled.",
249
+ }
250
+ )
242
251
 
243
- $embedding_enabled = Switch.new(
244
- :embedding_enabled,
245
- msg: {
246
- true => "Embedding enabled.",
247
- false => "Embedding disabled.",
248
- }
249
- )
252
+ $embedding_paused = Switch.new(
253
+ :embedding_paused,
254
+ msg: {
255
+ true => "Embedding paused.",
256
+ false => "Embedding resumed.",
257
+ }
258
+ )
250
259
 
251
- $embedding_paused = Switch.new(
252
- :embedding_paused,
253
- msg: {
254
- true => "Embedding paused.",
255
- false => "Embedding resumed.",
256
- }
257
- )
260
+ $embedding = CombinedSwitch.new(
261
+ value: -> { $embedding_enabled.on? && $embedding_paused.off? },
262
+ msg: {
263
+ true => "Embedding is currently performed.",
264
+ false => "Embedding is currently not performed.",
265
+ }
266
+ )
258
267
 
259
- $embedding = CombinedSwitch.new(
260
- value: -> { $embedding_enabled.on? && $embedding_paused.off? },
261
- msg: {
262
- true => "Embedding is currently performed.",
263
- false => "Embedding is currently not performed.",
264
- }
265
- )
268
+ $location = Switch.new(
269
+ :location,
270
+ msg: {
271
+ true => "Location and localtime enabled.",
272
+ false => "Location and localtime disabled.",
273
+ },
274
+ config: $config.location.enabled
275
+ )
276
+ end
277
+ end
278
+ include Switches
266
279
 
267
- $location = Switch.new(
268
- :location,
269
- msg: {
270
- true => "Location and localtime enabled.",
271
- false => "Location and localtime disabled.",
272
- },
273
- config: $config.location.enabled
274
- )
280
+ def pull_model_unless_present(model, options, retried = false)
281
+ ollama.show(name: model) { |response|
282
+ puts "Model #{bold{model}} with architecture "\
283
+ "#{response.model_info['general.architecture']} found."
284
+ if system = response.system
285
+ puts "Configured model system prompt is:\n#{italic { system }}"
286
+ return system
287
+ else
288
+ return
289
+ end
290
+ }
291
+ rescue Errors::NotFoundError
292
+ puts "Model #{bold{model}} not found locally, attempting to pull it from remote now…"
293
+ ollama.pull(name: model)
294
+ if retried
295
+ exit 1
296
+ else
297
+ retried = true
298
+ retry
299
+ end
300
+ rescue Errors::Error => e
301
+ warn "Caught #{e.class} while pulling model: #{e} => Exiting."
302
+ exit 1
275
303
  end
276
304
 
277
305
  def search_web(query, n = nil)
@@ -282,7 +310,7 @@ def search_web(query, n = nil)
282
310
  n < 1 and n = 1
283
311
  query = URI.encode_uri_component(query)
284
312
  url = "https://www.duckduckgo.com/html/?q=#{query}"
285
- Ollama::Utils::Fetcher.get(url, debug: $config.debug) do |tmp|
313
+ Utils::Fetcher.get(url, debug: $config.debug) do |tmp|
286
314
  result = []
287
315
  doc = Nokogiri::HTML(tmp)
288
316
  doc.css('.results_links').each do |link|
@@ -303,38 +331,13 @@ def search_web(query, n = nil)
303
331
  end
304
332
  end
305
333
 
306
- def pull_model_unless_present(model, options, retried = false)
307
- ollama.show(name: model) { |response|
308
- puts "Model #{bold{model}} with architecture "\
309
- "#{response.model_info['general.architecture']} found."
310
- if system = response.system
311
- puts "Configured model system prompt is:\n#{italic { system }}"
312
- return system
313
- else
314
- return
315
- end
316
- }
317
- rescue Errors::NotFoundError
318
- puts "Model #{bold{model}} not found locally, attempting to pull it from remote now…"
319
- ollama.pull(name: model)
320
- if retried
321
- exit 1
322
- else
323
- retried = true
324
- retry
325
- end
326
- rescue Errors::Error => e
327
- warn "Caught #{e.class} while pulling model: #{e} => Exiting."
328
- exit 1
329
- end
330
-
331
334
  def load_conversation(filename)
332
335
  unless File.exist?(filename)
333
336
  puts "File #{filename} doesn't exist. Choose another filename."
334
337
  return
335
338
  end
336
339
  File.open(filename, 'r') do |output|
337
- return JSON(output.read).map { Ollama::Message.from_hash(_1) }
340
+ return JSON(output.read).map { Message.from_hash(_1) }
338
341
  end
339
342
  end
340
343
 
@@ -372,113 +375,120 @@ def list_conversation(messages, last = nil)
372
375
  end
373
376
  end
374
377
 
375
- def reverse_markdown(html)
376
- ReverseMarkdown.convert(
377
- html,
378
- unknown_tags: :bypass,
379
- github_flavored: true,
380
- tag_border: ''
381
- )
382
- end
378
+ module SourceParsing
379
+ def parse_source(source_io)
380
+ case source_io&.content_type
381
+ when 'text/html'
382
+ reverse_markdown(source_io.read)
383
+ when 'text/xml'
384
+ if source_io.readline =~ %r(^\s*<rss\s)
385
+ source_io.rewind
386
+ return parse_rss(source_io)
387
+ end
388
+ source_io.rewind
389
+ source_io.read
390
+ when 'text/csv' # TODO
391
+ parse_csv(source_io)
392
+ when 'application/rss+xml'
393
+ parse_rss(source_io)
394
+ when 'application/atom+xml'
395
+ parse_atom(source_io)
396
+ when 'application/postscript'
397
+ ps_read(source_io)
398
+ when 'application/pdf'
399
+ pdf_read(source_io)
400
+ when %r(\Aapplication/(json|ld\+json|x-ruby|x-perl|x-gawk|x-python|x-javascript|x-c?sh|x-dosexec|x-shellscript|x-tex|x-latex|x-lyx|x-bibtex)), %r(\Atext/), nil
401
+ source_io.read
402
+ else
403
+ STDERR.puts "Cannot embed #{source_io&.content_type} document."
404
+ return
405
+ end
406
+ end
383
407
 
384
- def parse_rss(source_io)
385
- feed = RSS::Parser.parse(source_io, false, false)
386
- title = <<~EOT
387
- # #{feed&.channel&.title}
408
+ def parse_csv(source_io)
409
+ result = +''
410
+ CSV.table(File.new(source_io), col_sep: ?,).each do |row|
411
+ next if row.fields.select(&:present?).size == 0
412
+ result << row.map { |pair|
413
+ pair.compact.map { _1.to_s.strip } * ': ' if pair.last.present?
414
+ }.select(&:present?).map { _1.prepend(' ') } * ?\n
415
+ result << "\n\n"
416
+ end
417
+ result
418
+ end
388
419
 
389
- EOT
390
- feed.items.inject(title) do |text, item|
391
- text << <<~EOT
392
- ## [#{item&.title}](#{item&.link})
420
+ def parse_rss(source_io)
421
+ feed = RSS::Parser.parse(source_io, false, false)
422
+ title = <<~EOT
423
+ # #{feed&.channel&.title}
393
424
 
394
- updated on #{item&.pubDate}
425
+ EOT
426
+ feed.items.inject(title) do |text, item|
427
+ text << <<~EOT
428
+ ## [#{item&.title}](#{item&.link})
395
429
 
396
- #{reverse_markdown(item&.description)}
430
+ updated on #{item&.pubDate}
397
431
 
398
- EOT
432
+ #{reverse_markdown(item&.description)}
433
+
434
+ EOT
435
+ end
399
436
  end
400
- end
401
437
 
402
- def parse_atom(source_io)
403
- feed = RSS::Parser.parse(source_io, false, false)
404
- title = <<~EOT
405
- # #{feed.title.content}
438
+ def parse_atom(source_io)
439
+ feed = RSS::Parser.parse(source_io, false, false)
440
+ title = <<~EOT
441
+ # #{feed.title.content}
406
442
 
407
- EOT
408
- feed.items.inject(title) do |text, item|
409
- text << <<~EOT
410
- ## [#{item&.title&.content}](#{item&.link&.href})
443
+ EOT
444
+ feed.items.inject(title) do |text, item|
445
+ text << <<~EOT
446
+ ## [#{item&.title&.content}](#{item&.link&.href})
411
447
 
412
- updated on #{item&.updated&.content}
448
+ updated on #{item&.updated&.content}
413
449
 
414
- #{reverse_markdown(item&.content&.content)}
450
+ #{reverse_markdown(item&.content&.content)}
415
451
 
416
- EOT
452
+ EOT
453
+ end
417
454
  end
418
- end
419
455
 
420
- def pdf_read(io)
421
- reader = PDF::Reader.new(io)
422
- reader.pages.inject(+'') { |result, page| result << page.text }
423
- end
456
+ def pdf_read(io)
457
+ reader = PDF::Reader.new(io)
458
+ reader.pages.inject(+'') { |result, page| result << page.text }
459
+ end
424
460
 
425
- def ps_read(io)
426
- gs = `which gs`.chomp
427
- if gs.present?
428
- Tempfile.create do |tmp|
429
- IO.popen("#{gs} -q -sDEVICE=pdfwrite -sOutputFile=#{tmp.path} -", 'wb') do |gs_io|
430
- until io.eof?
431
- buffer = io.read(1 << 17)
432
- IO.select(nil, [ gs_io ], nil)
433
- gs_io.write buffer
434
- end
435
- gs_io.close
436
- File.open(tmp.path, 'rb') do |pdf|
437
- pdf_read(pdf)
461
+ def ps_read(io)
462
+ gs = `which gs`.chomp
463
+ if gs.present?
464
+ Tempfile.create do |tmp|
465
+ IO.popen("#{gs} -q -sDEVICE=pdfwrite -sOutputFile=#{tmp.path} -", 'wb') do |gs_io|
466
+ until io.eof?
467
+ buffer = io.read(1 << 17)
468
+ IO.select(nil, [ gs_io ], nil)
469
+ gs_io.write buffer
470
+ end
471
+ gs_io.close
472
+ File.open(tmp.path, 'rb') do |pdf|
473
+ pdf_read(pdf)
474
+ end
438
475
  end
439
476
  end
477
+ else
478
+ STDERR.puts "Cannot convert #{io&.content_type} whith ghostscript, gs not in path."
440
479
  end
441
- else
442
- STDERR.puts "Cannot convert #{io&.content_type} whith ghostscript, gs not in path."
443
480
  end
444
- end
445
481
 
446
- def parse_source(source_io)
447
- case source_io&.content_type
448
- when 'text/html'
449
- reverse_markdown(source_io.read)
450
- when 'text/xml'
451
- if source_io.readline =~ %r(^\s*<rss\s)
452
- source_io.rewind
453
- return parse_rss(source_io)
454
- end
455
- source_io.rewind
456
- source_io.read
457
- when 'text/csv'
458
- result = +''
459
- CSV.table(File.new(source_io), col_sep: ?,).each do |row|
460
- next if row.fields.select(&:present?).size == 0
461
- result << row.map { |pair|
462
- pair.compact.map { _1.to_s.strip } * ': ' if pair.last.present?
463
- }.select(&:present?).map { _1.prepend(' ') } * ?\n
464
- result << "\n\n"
465
- end
466
- result
467
- when 'application/rss+xml'
468
- parse_rss(source_io)
469
- when 'application/atom+xml'
470
- parse_atom(source_io)
471
- when 'application/postscript'
472
- ps_read(source_io)
473
- when 'application/pdf'
474
- pdf_read(source_io)
475
- when %r(\Aapplication/(json|ld\+json|x-ruby|x-perl|x-gawk|x-python|x-javascript|x-c?sh|x-dosexec|x-shellscript|x-tex|x-latex|x-lyx|x-bibtex)), %r(\Atext/), nil
476
- source_io.read
477
- else
478
- STDERR.puts "Cannot embed #{source_io&.content_type} document."
479
- return
482
+ def reverse_markdown(html)
483
+ ReverseMarkdown.convert(
484
+ html,
485
+ unknown_tags: :bypass,
486
+ github_flavored: true,
487
+ tag_border: ''
488
+ )
480
489
  end
481
490
  end
491
+ include SourceParsing
482
492
 
483
493
  def http_options(url)
484
494
  options = {}
@@ -504,7 +514,7 @@ def fetch_source(source, &block)
504
514
  source,
505
515
  cache: $cache,
506
516
  debug: $config.debug,
507
- http_options: http_options(source)
517
+ http_options: http_options(Utils::Fetcher.normalize_url(source))
508
518
  ) do |tmp|
509
519
  block.(tmp)
510
520
  end
@@ -518,7 +528,7 @@ def fetch_source(source, &block)
518
528
  raise "invalid source"
519
529
  end
520
530
  rescue => e
521
- STDERR.puts "Cannot fetch source #{source.to_s.inspect}: #{e}\n#{e.backtrace * ?\n}"
531
+ STDERR.puts "Cannot fetch source #{source.to_s.inspect}: #{e.class} #{e}\n#{e.backtrace * ?\n}"
522
532
  end
523
533
 
524
534
  def add_image(images, source_io, source)
@@ -530,7 +540,8 @@ end
530
540
  def import_source(source_io, source)
531
541
  source = source.to_s
532
542
  puts "Importing #{italic { source_io&.content_type }} document #{source.inspect} now."
533
- "Imported #{source.inspect}:\n%s\n\n" % parse_source(source_io)
543
+ source_content = parse_source(source_io)
544
+ "Imported #{source.inspect}:\n#{source_content}\n\n"
534
545
  end
535
546
 
536
547
  def import(source)
@@ -572,17 +583,17 @@ def embed_source(source_io, source, count: nil)
572
583
  inputs = nil
573
584
  case splitter_config.name
574
585
  when 'Character'
575
- splitter = Ollama::Documents::Splitters::Character.new(
586
+ splitter = Documents::Splitters::Character.new(
576
587
  chunk_size: splitter_config.chunk_size,
577
588
  )
578
589
  inputs = splitter.split(text)
579
590
  when 'RecursiveCharacter'
580
- splitter = Ollama::Documents::Splitters::RecursiveCharacter.new(
591
+ splitter = Documents::Splitters::RecursiveCharacter.new(
581
592
  chunk_size: splitter_config.chunk_size,
582
593
  )
583
594
  inputs = splitter.split(text)
584
595
  when 'Semantic'
585
- splitter = Ollama::Documents::Splitters::Semantic.new(
596
+ splitter = Documents::Splitters::Semantic.new(
586
597
  ollama:, model: $config.embedding.model.name,
587
598
  chunk_size: splitter_config.chunk_size,
588
599
  )
@@ -597,7 +608,7 @@ def embed_source(source_io, source, count: nil)
597
608
  inputs or return
598
609
  source = source.to_s
599
610
  if source.start_with?(?!)
600
- source = Ollama::Utils::Width.truncate(
611
+ source = Utils::Width.truncate(
601
612
  source[1..-1].gsub(/\W+/, ?_),
602
613
  length: 10
603
614
  )
@@ -662,7 +673,7 @@ end
662
673
  def choose_model(cli_model, current_model)
663
674
  models = ollama.tags.models.map(&:name).sort
664
675
  model = if cli_model == ''
665
- Ollama::Utils::Chooser.choose(models) || current_model
676
+ Utils::Chooser.choose(models) || current_model
666
677
  else
667
678
  cli_model || current_model
668
679
  end
@@ -679,7 +690,7 @@ def choose_collection(current_collection)
679
690
  collections = [ current_collection ] + $documents.collections
680
691
  collections = collections.compact.map(&:to_s).uniq.sort
681
692
  collections.unshift('[EXIT]').unshift('[NEW]')
682
- collection = Ollama::Utils::Chooser.choose(collections) || current_collection
693
+ collection = Utils::Chooser.choose(collections) || current_collection
683
694
  case collection
684
695
  when '[NEW]'
685
696
  $documents.collection = ask?(prompt: "Enter name of the new collection: ")
@@ -703,7 +714,7 @@ def choose_document_policy
703
714
  policies.first
704
715
  end
705
716
  policies.unshift('[EXIT]')
706
- policy = Ollama::Utils::Chooser.choose(policies)
717
+ policy = Utils::Chooser.choose(policies)
707
718
  case policy
708
719
  when nil, '[EXIT]'
709
720
  puts "Exiting chooser."
@@ -722,7 +733,6 @@ def collection_stats
722
733
  puts <<~EOT
723
734
  Current Collection
724
735
  Name: #{bold{$documents.collection}}
725
- Embedding model: #{bold{$embedding_model}}
726
736
  #Embeddings: #{$documents.size}
727
737
  #Tags: #{$documents.tags.size}
728
738
  Tags: #{$documents.tags}
@@ -733,19 +743,19 @@ end
733
743
 
734
744
  def configure_cache
735
745
  if $opts[?M]
736
- Ollama::Documents::MemoryCache
746
+ Documents::MemoryCache
737
747
  else
738
748
  Object.const_get($config.cache)
739
749
  end
740
750
  rescue => e
741
751
  STDERR.puts "Caught #{e.class}: #{e} => Falling back to MemoryCache."
742
- Ollama::Documents::MemoryCache
752
+ Documents::MemoryCache
743
753
  end
744
754
 
745
755
  def show_system_prompt
746
756
  puts <<~EOT
747
757
  Configured system prompt is:
748
- #{Ollama::Utils::ANSIMarkdown.parse($system.to_s).gsub(/\n+\z/, '').full? || 'n/a'}
758
+ #{Utils::ANSIMarkdown.parse($system.to_s).gsub(/\n+\z/, '').full? || 'n/a'}
749
759
  EOT
750
760
  end
751
761
 
@@ -769,7 +779,7 @@ end
769
779
 
770
780
  def change_system_prompt(messages, default)
771
781
  prompts = $config.system_prompts.attribute_names.compact
772
- chosen = Ollama::Utils::Chooser.choose(prompts)
782
+ chosen = Utils::Chooser.choose(prompts)
773
783
  system = if chosen
774
784
  $config.system_prompts.send(chosen)
775
785
  else
@@ -779,16 +789,23 @@ def change_system_prompt(messages, default)
779
789
  end
780
790
 
781
791
  def change_voice
782
- chosen = Ollama::Utils::Chooser.choose($config.voice.list)
792
+ chosen = Utils::Chooser.choose($config.voice.list)
783
793
  $current_voice = chosen.full? || $config.voice.default
784
794
  end
785
795
 
786
796
  def info
787
797
  puts "Current model is #{bold{$model}}."
788
- collection_stats
798
+ if $model_options.present?
799
+ puts " Options: #{JSON.pretty_generate($model_options).gsub(/(?<!\A)^/, ' ')}"
800
+ end
789
801
  $embedding.show
790
802
  if $embedding.on?
803
+ puts "Embedding model is #{bold{$embedding_model}}"
804
+ if $embedding_model_options.present?
805
+ puts " Options: #{JSON.pretty_generate($embedding_model_options).gsub(/(?<!\A)^/, ' ')}"
806
+ end
791
807
  puts "Text splitter is #{bold{$config.embedding.splitter.name}}."
808
+ collection_stats
792
809
  end
793
810
  puts "Documents database cache is #{$documents.nil? ? 'n/a' : bold{$documents.cache.class}}"
794
811
  $markdown.show
@@ -891,12 +908,12 @@ $opts[?h] and usage
891
908
  $opts[?V] and version
892
909
 
893
910
  base_url = $opts[?u] || $config.url
894
- $ollama = Client.new(base_url:, debug: $config.debug)
911
+ $ollama = Client.new(base_url:, debug: $config.debug)
895
912
 
896
913
  $document_policy = $config.document_policy
897
914
  $model = choose_model($opts[?m], $config.model.name)
898
- options = Options[$config.model.options]
899
- model_system = pull_model_unless_present($model, options)
915
+ $model_options = Options[$config.model.options]
916
+ model_system = pull_model_unless_present($model, $model_options)
900
917
  messages = []
901
918
  $embedding_enabled.set($config.embedding.enabled && !$opts[?E])
902
919
 
@@ -907,15 +924,15 @@ else
907
924
  if $opts[?s] == ??
908
925
  change_system_prompt(messages, default)
909
926
  else
910
- system = Ollama::Utils::FileArgument.get_file_argument($opts[?s], default:)
927
+ system = Utils::FileArgument.get_file_argument($opts[?s], default:)
911
928
  system.present? and set_system_prompt(messages, system)
912
929
  end
913
930
  end
914
931
 
915
932
  if $embedding.on?
916
933
  $embedding_model = $config.embedding.model.name
917
- embedding_model_options = Options[$config.embedding.model.options]
918
- pull_model_unless_present($embedding_model, embedding_model_options)
934
+ $embedding_model_options = Options[$config.embedding.model.options]
935
+ pull_model_unless_present($embedding_model, $embedding_model_options)
919
936
  collection = $opts[?C] || $config.embedding.collection
920
937
  $documents = Documents.new(
921
938
  ollama:,
@@ -957,7 +974,7 @@ else
957
974
  end
958
975
 
959
976
  if redis_expiring_url = $config.redis.expiring.url?
960
- $cache = Ollama::Documents::RedisCache.new(
977
+ $cache = Documents::RedisCache.new(
961
978
  prefix: 'Expiring-',
962
979
  url: redis_expiring_url,
963
980
  ex: $config.redis.expiring.ex,
@@ -1051,7 +1068,7 @@ loop do
1051
1068
  when 'clear'
1052
1069
  loop do
1053
1070
  tags = $documents.tags.add('[EXIT]').add('[ALL]')
1054
- tag = Ollama::Utils::Chooser.choose(tags, prompt: 'Clear? %s')
1071
+ tag = Utils::Chooser.choose(tags, prompt: 'Clear? %s')
1055
1072
  case tag
1056
1073
  when nil, '[EXIT]'
1057
1074
  puts "Exiting chooser."
@@ -1154,7 +1171,7 @@ loop do
1154
1171
  messages << Message.new(role: 'user', content:, images: images.dup)
1155
1172
  images.clear
1156
1173
  handler = FollowChat.new(messages:, markdown: $markdown.on?, voice: ($current_voice if $voice.on?))
1157
- ollama.chat(model: $model, messages:, options:, stream: $stream.on?, &handler)
1174
+ ollama.chat(model: $model, messages:, options: $model_options, stream: $stream.on?, &handler)
1158
1175
 
1159
1176
  if $embedding.on? && !records.empty?
1160
1177
  puts "", records.map { |record|
data/lib/ollama/dto.rb CHANGED
@@ -33,6 +33,10 @@ module Ollama::DTO
33
33
 
34
34
  alias to_hash as_json
35
35
 
36
+ def empty?
37
+ to_hash.empty?
38
+ end
39
+
36
40
  def to_json(*)
37
41
  as_json.to_json(*)
38
42
  end
@@ -38,6 +38,13 @@ class Ollama::Utils::Fetcher
38
38
  end
39
39
  end
40
40
 
41
+ def self.normalize_url(url)
42
+ url = url.to_s
43
+ url = URI.decode_uri_component(url)
44
+ url = url.sub(/#.*/, '')
45
+ URI::Parser.new.escape(url).to_s
46
+ end
47
+
41
48
  def self.read(filename, &block)
42
49
  if File.exist?(filename)
43
50
  File.open(filename) do |file|
@@ -80,6 +87,7 @@ class Ollama::Utils::Fetcher
80
87
  private
81
88
 
82
89
  def excon(url, **options)
90
+ url = self.class.normalize_url(url)
83
91
  Excon.new(url, options.merge(@http_options))
84
92
  end
85
93
 
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.9.0'
3
+ VERSION = '0.9.2'
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,26 +1,26 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.9.0 ruby lib
2
+ # stub: ollama-ruby 0.9.2 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.9.0".freeze
6
+ s.version = "0.9.2".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-10-18"
11
+ s.date = "2024-10-20"
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
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/ansi_markdown.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/utils/width.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/ansi_markdown.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/utils/width.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/ansi_markdown_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_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/ollama/utils/width_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".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/ansi_markdown.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/utils/width.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/ansi_markdown_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/ollama/utils/width_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.18".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/ansi_markdown_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_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/ollama/utils/width_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/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/ansi_markdown_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/ollama/utils/width_spec.rb".freeze, "spec/spec_helper.rb".freeze]
24
24
 
25
25
  s.specification_version = 4
26
26
 
@@ -60,16 +60,16 @@ RSpec.describe Ollama::Documents do
60
60
  expect(ollama).to receive(:embed).
61
61
  with(model:, input: [ 'foo' ], options: nil).
62
62
  and_return(double(embeddings: [ [ 0.1 ] ]))
63
- expect(documents.add('foo', tags: %i[ test ])).to eq documents
63
+ expect(documents.add('foo', tags: %w[ test ])).to eq documents
64
64
  expect(ollama).to receive(:embed).
65
65
  with(model:, input: 'foo', options: nil).
66
66
  and_return(double(embeddings: [ [ 0.1 ] ]))
67
- records = documents.find('foo', tags: %i[ nix ])
67
+ records = documents.find('foo', tags: %w[ nix ])
68
68
  expect(records).to eq []
69
69
  expect(ollama).to receive(:embed).
70
70
  with(model:, input: 'foo', options: nil).
71
71
  and_return(double(embeddings: [ [ 0.1 ] ]))
72
- records = documents.find('foo', tags: %i[ test ])
72
+ records = documents.find('foo', tags: %w[ test ])
73
73
  expect(records).to eq [
74
74
  Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ]
75
75
  ]
@@ -135,8 +135,9 @@ RSpec.describe Ollama::Documents do
135
135
  expect(ollama).to receive(:embed).
136
136
  with(model:, input: %w[ bar ], options: nil).
137
137
  and_return(double(embeddings: [ [ 0.1 ] ]))
138
- expect(documents.add('foo', tags: %i[ test ])).to eq documents
139
- expect(documents.add('bar', tags: %i[ test2 ])).to eq documents
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 ]
140
141
  expect {
141
142
  documents.clear tags: 'test'
142
143
  }.to change { documents.size }.from(2).to(1)
@@ -13,6 +13,10 @@ RSpec.describe Ollama::Options do
13
13
  expect(options).to be_a described_class
14
14
  end
15
15
 
16
+ it 'can be empty' do
17
+ expect(described_class.new).to be_empty
18
+ end
19
+
16
20
  it 'can be used to cast hashes' do
17
21
  expect(described_class[{
18
22
  penalize_newline: true,
@@ -0,0 +1,13 @@
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
@@ -19,7 +19,7 @@ RSpec.describe Ollama::Utils::Fetcher do
19
19
  end
20
20
 
21
21
  it 'can #get with streaming' do
22
- stub_request(:get, 'https://www.example.com/hello').
22
+ stub_request(:get, url).
23
23
  with(headers: fetcher.headers).
24
24
  to_return(
25
25
  status: 200,
@@ -37,7 +37,7 @@ RSpec.describe Ollama::Utils::Fetcher do
37
37
  fetcher = described_class.new(
38
38
  http_options: { ssl_verify_peer: false }
39
39
  ).expose
40
- stub_request(:get, 'https://www.example.com/hello').
40
+ stub_request(:get, url).
41
41
  with(headers: fetcher.headers).
42
42
  to_return(
43
43
  status: 200,
@@ -45,7 +45,7 @@ RSpec.describe Ollama::Utils::Fetcher do
45
45
  headers: { 'Content-Type' => 'text/plain' },
46
46
  )
47
47
  expect(Excon).to receive(:new).with(
48
- 'https://www.example.com/hello',
48
+ url,
49
49
  hash_including(ssl_verify_peer: false)
50
50
  ).and_call_original
51
51
  fetcher.get(url) do |tmp|
@@ -56,7 +56,7 @@ RSpec.describe Ollama::Utils::Fetcher do
56
56
  end
57
57
 
58
58
  it 'can #get and fallback from streaming' do
59
- stub_request(:get, 'https://www.example.com/hello').
59
+ stub_request(:get, url).
60
60
  with(headers: fetcher.headers).
61
61
  to_return(
62
62
  { status: 501 },
@@ -74,9 +74,10 @@ RSpec.describe Ollama::Utils::Fetcher do
74
74
  end
75
75
 
76
76
  it 'can #get and finally fail' do
77
- stub_request(:get, 'https://www.example.com/hello').
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)
80
81
  fetcher.get(url) do |tmp|
81
82
  expect(tmp).to be_a StringIO
82
83
  expect(tmp.read).to eq ''
@@ -106,10 +107,31 @@ RSpec.describe Ollama::Utils::Fetcher do
106
107
 
107
108
  it 'can .execute and fail' do
108
109
  expect(IO).to receive(:popen).and_raise StandardError
110
+ expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
109
111
  described_class.execute('foobar') do |file|
110
112
  expect(file).to be_a StringIO
111
113
  expect(file.read).to be_empty
112
114
  expect(file.content_type).to eq 'text/plain'
113
115
  end
114
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
115
137
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-18 00:00:00.000000000 Z
11
+ date: 2024-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -516,6 +516,7 @@ files:
516
516
  - spec/ollama/tool_spec.rb
517
517
  - spec/ollama/utils/ansi_markdown_spec.rb
518
518
  - spec/ollama/utils/cache_fetcher_spec.rb
519
+ - spec/ollama/utils/colorize_texts_spec.rb
519
520
  - spec/ollama/utils/fetcher_spec.rb
520
521
  - spec/ollama/utils/file_argument_spec.rb
521
522
  - spec/ollama/utils/tags_spec.rb
@@ -585,6 +586,7 @@ test_files:
585
586
  - spec/ollama/tool_spec.rb
586
587
  - spec/ollama/utils/ansi_markdown_spec.rb
587
588
  - spec/ollama/utils/cache_fetcher_spec.rb
589
+ - spec/ollama/utils/colorize_texts_spec.rb
588
590
  - spec/ollama/utils/fetcher_spec.rb
589
591
  - spec/ollama/utils/file_argument_spec.rb
590
592
  - spec/ollama/utils/tags_spec.rb