ollama-ruby 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9304634c783477787792071f039d6941222bcca0577cd59cdbc5103f820ea299
4
- data.tar.gz: 9edc7eaf98c0601e08bb5cde23fc2d46b745982172caea349982d8867790166a
3
+ metadata.gz: 29863f68627a05541de5eab810850b0509db94c1d91b2e9a5a9be9bd387e8aea
4
+ data.tar.gz: 07f3558153a0a724c08e27a86482e0951070348bf25641d2a9feed113e3e7046
5
5
  SHA512:
6
- metadata.gz: 0bda727610f0793d6c360a63c76b2c42e032109f34011ed7cbd54df5663102c3738498be836adcb00645e4ce407cab1f422737970b83a3fa757ea0b4d90d8453
7
- data.tar.gz: b9df134561b2a44accfdc1ec6da68eb0b3b9b5ce64c2d64c744834a0b74cbfde8018e270977440224d0433c681e7a203d272453e391b85a3d32f34e3b0c790ca
6
+ metadata.gz: 11c405277b59c6acc75c24220942dd883bb7aec99d97d19bc9baf8d61aa4e5dc59af905631dc37641b91babdd9e5ab7305720a8720451db7b4bb6ca067833913
7
+ data.tar.gz: 129f49e2d4b5cb65b7999f666f33798511b8a34b1be84bbc7bd4433872cd7c323812cd4dd3e8d2ae325cb013cfb6403db8181c8cbe641139469e5ea9821cc71d
data/CHANGES.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changes
2
2
 
3
+ ## 2024-09-21 v0.4.0
4
+
5
+ ### Change Log for **1.2.3**
6
+
7
+ #### New Features
8
+
9
+ * Added `-E` option to disable embeddings for this chat session.
10
+ * Added `-M` option to load document embeddings into (empty) MemoryCache for this chat session.
11
+ * Added CSV parsing support to `ollama_chat`.
12
+ * Improved error handling in `Ollama::Utils::Fetcher` methods.
13
+
14
+ #### Bug Fixes
15
+
16
+ * Handle case in `ollama_chat` where responses don't provide counts, display 0
17
+ rates instead.
18
+
19
+ #### Refactoring and Improvements
20
+
21
+ * Updated eval count and rate display in FollowChat class.
22
+ * Refactor system prompt display and chunk listing in chat output.
23
+ * Refactor cache implementation to use Ollama::Documents::Cache::Common module.
24
+ * Improved system prompt formatting in `ollama_chat` script.
25
+ * Renamed `tags` method to `tags_set` in `Ollama::Documents::Record` class.
26
+
27
+ #### Documentation
28
+
29
+ * Added comments to ColorizeTexts utility class.
30
+
3
31
  ## 2024-09-15 v0.3.2
4
32
 
5
33
  * Add color support to chooser module:
data/README.md CHANGED
@@ -43,6 +43,8 @@ ollama_chat [OPTIONS]
43
43
  -c CHAT a saved chat conversation to load
44
44
  -C COLLECTION name of the collection used in this conversation
45
45
  -D DOCUMENT load document and add to collection (multiple)
46
+ -M use (empty) MemoryCache for this chat session
47
+ -E disable embeddings for this chat session
46
48
  -v use voice output
47
49
  -h this help
48
50
  ```
data/Rakefile CHANGED
@@ -13,7 +13,8 @@ GemHadar do
13
13
  description 'Library that allows interacting with the Ollama API'
14
14
  test_dir 'spec'
15
15
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
16
- '.yardoc', 'tags', 'errors.lst', 'cscope.out', 'coverage', 'tmp', 'corpus'
16
+ '.yardoc', 'doc', 'tags', 'errors.lst', 'cscope.out', 'coverage', 'tmp',
17
+ 'corpus'
17
18
  package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
18
19
  '.rspec', *Dir.glob('.github/**/*', File::FNM_DOTMATCH)
19
20
  readme 'README.md'
@@ -41,6 +42,8 @@ GemHadar do
41
42
  development_dependency 'all_images', '~> 0.4'
42
43
  development_dependency 'rspec', '~> 3.2'
43
44
  development_dependency 'webmock'
45
+ development_dependency 'debug'
46
+ development_dependency 'simplecov'
44
47
 
45
48
  licenses << 'MIT'
46
49
 
data/bin/ollama_chat CHANGED
@@ -14,6 +14,7 @@ require 'uri'
14
14
  require 'nokogiri'
15
15
  require 'rss'
16
16
  require 'pdf/reader'
17
+ require 'csv'
17
18
 
18
19
  class OllamaChatConfig
19
20
  include ComplexConfig
@@ -47,7 +48,7 @@ class OllamaChatConfig
47
48
  splitter:
48
49
  name: RecursiveCharacter
49
50
  chunk_size: 1024
50
- cache: Ollama::Documents::RedisCache
51
+ cache: Ollama::Documents::Cache::RedisBackedMemoryCache
51
52
  redis:
52
53
  url: <%= ENV.fetch('REDIS_URL', 'null') %>
53
54
  debug: <%= ENV['OLLAMA_CHAT_DEBUG'].to_i == 1 ? true : false %>
@@ -130,11 +131,11 @@ class FollowChat
130
131
  prompt_eval_duration = response.prompt_eval_duration / 1e9
131
132
  stats_text = {
132
133
  eval_duration: Tins::Duration.new(eval_duration),
133
- eval_count: response.eval_count,
134
- eval_rate: bold { "%.2f c/s" % (response.eval_count / eval_duration) } + color(111),
134
+ eval_count: response.eval_count.to_i,
135
+ eval_rate: bold { "%.2f c/s" % (response.eval_count.to_i / eval_duration) } + color(111),
135
136
  prompt_eval_duration: Tins::Duration.new(prompt_eval_duration),
136
- prompt_eval_count: response.prompt_eval_count,
137
- prompt_eval_rate: bold { "%.2f c/s" % (response.prompt_eval_count / prompt_eval_duration) } + color(111),
137
+ prompt_eval_count: response.prompt_eval_count.to_i,
138
+ prompt_eval_rate: bold { "%.2f c/s" % (response.prompt_eval_count.to_i / prompt_eval_duration) } + color(111),
138
139
  total_duration: Tins::Duration.new(response.total_duration / 1e9),
139
140
  load_duration: Tins::Duration.new(response.load_duration / 1e9),
140
141
  }.map { _1 * '=' } * ' '
@@ -149,7 +150,7 @@ def search_web(query, n = nil)
149
150
  n < 1 and n = 1
150
151
  query = URI.encode_uri_component(query)
151
152
  url = "https://www.duckduckgo.com/html/?q=#{query}"
152
- Ollama::Utils::Fetcher.new.get(url) do |tmp|
153
+ Ollama::Utils::Fetcher.new(debug: $config.debug).get(url) do |tmp|
153
154
  result = []
154
155
  doc = Nokogiri::HTML(tmp)
155
156
  doc.css('.results_links').each do |link|
@@ -302,6 +303,16 @@ def parse_source(source_io)
302
303
  end
303
304
  source_io.rewind
304
305
  source_io.read
306
+ when 'text/csv'
307
+ result = +''
308
+ CSV.table(File.new(source_io), col_sep: ?,).each do |row|
309
+ next if row.fields.select(&:present?).size == 0
310
+ result << row.map { |pair|
311
+ pair.compact.map { _1.to_s.strip } * ': ' if pair.last.present?
312
+ }.select(&:present?).map { _1.prepend(' ') } * ?\n
313
+ result << "\n\n"
314
+ end
315
+ result
305
316
  when %r(\Atext/)
306
317
  source_io.read
307
318
  when 'application/rss+xml'
@@ -312,11 +323,7 @@ def parse_source(source_io)
312
323
  source_io.read
313
324
  when 'application/pdf'
314
325
  reader = PDF::Reader.new(source_io)
315
- result = +''
316
- reader.pages.each do |page|
317
- result << page.text
318
- end
319
- result
326
+ reader.pages.inject(+'') { |result, page| result << page.text }
320
327
  else
321
328
  STDERR.puts "Cannot import #{source_io&.content_type} document."
322
329
  return
@@ -324,10 +331,7 @@ def parse_source(source_io)
324
331
  end
325
332
 
326
333
  def import_document(source_io, source)
327
- unless $config.embedding.enabled
328
- STDOUT.puts "Embedding disabled, I won't import any documents, try: /summarize"
329
- return
330
- end
334
+ embedding_enabled? or return parse_source(source_io)
331
335
  puts "Importing #{italic { source_io&.content_type }} document #{source.to_s.inspect}."
332
336
  text = parse_source(source_io) or return
333
337
  text.downcase!
@@ -364,7 +368,7 @@ end
364
368
  def fetch_source(source, &block)
365
369
  case source
366
370
  when %r(\Ahttps?://\S+)
367
- Utils::Fetcher.get(source) do |tmp|
371
+ Utils::Fetcher.get(source, debug: $config.debug) do |tmp|
368
372
  block.(tmp)
369
373
  end
370
374
  when %r(\Afile://(?:(?:[.-]|[[:alnum:]])*)(/\S*)|([~.]?/\S*))
@@ -384,7 +388,8 @@ def summarize(source)
384
388
  puts "Now summarizing #{source.to_s.inspect}."
385
389
  source_content =
386
390
  fetch_source(source) do |source_io|
387
- content = parse_source(source_io) or return
391
+ content = parse_source(source_io)
392
+ content.present? or return
388
393
  source_io.rewind
389
394
  import_document(source_io, source)
390
395
  content
@@ -433,7 +438,7 @@ ensure
433
438
  end
434
439
 
435
440
  def choose_collection(default_collection)
436
- collections = [ default_collection ] + $documents.collections
441
+ collections = [ default_collection ] + $documents.collections.map(&:to_s)
437
442
  collections = collections.uniq.sort
438
443
  $documents.collection = collection =
439
444
  Ollama::Utils::Chooser.choose(collections) || default_collection
@@ -452,7 +457,11 @@ def collection_stats
452
457
  end
453
458
 
454
459
  def configure_cache
455
- Object.const_get($config.cache)
460
+ if $opts[?M]
461
+ Ollama::Documents::MemoryCache
462
+ else
463
+ Object.const_get($config.cache)
464
+ end
456
465
  rescue => e
457
466
  STDERR.puts "Caught #{e.class}: #{e} => Falling back to MemoryCache."
458
467
  Ollama::Documents::MemoryCache
@@ -468,6 +477,14 @@ def set_markdown(value)
468
477
  end
469
478
  end
470
479
 
480
+ def clear_messages(messages)
481
+ messages.delete_if { _1.role != 'system' }
482
+ end
483
+
484
+ def embedding_enabled?
485
+ $config.embedding.enabled && !$opts[?E]
486
+ end
487
+
471
488
  def display_chat_help
472
489
  puts <<~end
473
490
  /paste to paste content
@@ -498,7 +515,9 @@ def usage
498
515
  -s SYSTEM the system prompt to use as a file, OLLAMA_CHAT_SYSTEM
499
516
  -c CHAT a saved chat conversation to load
500
517
  -C COLLECTION name of the collection used in this conversation
501
- -D DOCUMENT load document and add to collection (multiple)
518
+ -D DOCUMENT load document and add to embeddings collection (multiple)
519
+ -M use (empty) MemoryCache for this chat session
520
+ -E disable embeddings for this chat session
502
521
  -v use voice output
503
522
  -h this help
504
523
 
@@ -510,28 +529,28 @@ def ollama
510
529
  $ollama
511
530
  end
512
531
 
513
- opts = go 'f:u:m:s:c:C:D:vh'
532
+ $opts = go 'f:u:m:s:c:C:D:MEvh'
514
533
 
515
- config = OllamaChatConfig.new(opts[?f])
534
+ config = OllamaChatConfig.new($opts[?f])
516
535
  $config = config.config
517
536
 
518
- opts[?h] and usage
537
+ $opts[?h] and usage
519
538
 
520
539
  puts "Configuration read from #{config.filename.inspect} is:", $config
521
540
 
522
- base_url = opts[?u] || $config.url
541
+ base_url = $opts[?u] || $config.url
523
542
  $ollama = Client.new(base_url:, debug: $config.debug)
524
543
 
525
- model = choose_model(opts[?m], $config.model.name)
544
+ model = choose_model($opts[?m], $config.model.name)
526
545
  options = Options[$config.model.options]
527
546
  model_system = pull_model_unless_present(model, options)
528
547
  messages = []
529
548
 
530
- if $config.embedding.enabled
549
+ if embedding_enabled?
531
550
  embedding_model = $config.embedding.model.name
532
551
  embedding_model_options = Options[$config.embedding.model.options]
533
552
  pull_model_unless_present(embedding_model, embedding_model_options)
534
- collection = opts[?C] || $config.embedding.collection
553
+ collection = $opts[?C] || $config.embedding.collection
535
554
  $documents = Documents.new(
536
555
  ollama:,
537
556
  model: $config.embedding.model.name,
@@ -541,7 +560,7 @@ if $config.embedding.enabled
541
560
  redis_url: $config.redis.url?,
542
561
  )
543
562
 
544
- document_list = opts[?D].to_a
563
+ document_list = $opts[?D].to_a
545
564
  if document_list.any?(&:empty?)
546
565
  puts "Clearing collection #{bold{collection}}."
547
566
  $documents.clear
@@ -569,18 +588,21 @@ else
569
588
  $documents = Documents.new(ollama:, model:)
570
589
  end
571
590
 
572
- if voice = ($config.voice if opts[?v])
591
+ if voice = ($config.voice if $opts[?v])
573
592
  puts "Using voice #{bold{voice}} to speak."
574
593
  end
575
594
  markdown = set_markdown($config.markdown)
576
595
 
577
- if opts[?c]
578
- messages.concat load_conversation(opts[?c])
596
+ if $opts[?c]
597
+ messages.concat load_conversation($opts[?c])
579
598
  else
580
599
  if system = Ollama::Utils::FileArgument.
581
- get_file_argument(opts[?s], default: $config.prompts.system? || model_system)
600
+ get_file_argument($opts[?s], default: $config.prompts.system? || model_system)
582
601
  messages << Message.new(role: 'system', content: system)
583
- puts "Configured system prompt is:\n#{italic { system }}"
602
+ puts <<~end
603
+ Configured system prompt is:
604
+ #{italic{Ollama::Utils::Width.wrap(system, percentage: 90)}}
605
+ end
584
606
  end
585
607
  end
586
608
 
@@ -606,11 +628,11 @@ loop do
606
628
  list_conversation(messages, markdown)
607
629
  next
608
630
  when %r(^/clear$)
609
- messages.clear
631
+ clear_messages(messages)
610
632
  puts "Cleared messages."
611
633
  next
612
634
  when %r(^/clobber$)
613
- messages.clear
635
+ clear_messages(messages)
614
636
  $documents.clear
615
637
  puts "Cleared messages and collection."
616
638
  next
@@ -697,7 +719,7 @@ loop do
697
719
  [ content, Utils::Tags.new ]
698
720
  end
699
721
 
700
- if $config.embedding.enabled && content
722
+ if embedding_enabled? && content
701
723
  records = $documents.find_where(
702
724
  content.downcase,
703
725
  tags:,
@@ -705,10 +727,9 @@ loop do
705
727
  text_size: $config.embedding.found_texts_size?,
706
728
  text_count: $config.embedding.found_texts_count?,
707
729
  )
708
- found_texts = records.map(&:text)
709
- unless found_texts.empty?
710
- content += "\nConsider these chunks for your answer:\n"\
711
- "#{found_texts.join("\n\n---\n\n")}"
730
+ unless records.empty?
731
+ content += "\nConsider these chunks for your answer:\n\n"\
732
+ "#{records.map { [ _1.text, _1.tags_set ] * ?\n }.join("\n\n---\n\n")}"
712
733
  end
713
734
  end
714
735
 
@@ -716,8 +737,8 @@ loop do
716
737
  handler = FollowChat.new(messages:, markdown:, voice:)
717
738
  ollama.chat(model:, messages:, options:, stream: true, &handler)
718
739
 
719
- if records
720
- puts records.map { |record|
740
+ if embedding_enabled? && !records.empty?
741
+ puts "", records.map { |record|
721
742
  link = if record.source =~ %r(\Ahttps?://)
722
743
  record.source
723
744
  else
@@ -0,0 +1,17 @@
1
+ module Ollama::Documents::Cache::Common
2
+ attr_writer :prefix
3
+
4
+ def collections(prefix)
5
+ unique = Set.new
6
+ full_each { |key, _| unique << key[/\A#{prefix}(.*)-/, 1] }
7
+ unique.map(&:to_sym)
8
+ end
9
+
10
+ def pre(key)
11
+ [ @prefix, key ].join
12
+ end
13
+
14
+ def unpre(key)
15
+ key.sub(/\A#@prefix/, '')
16
+ end
17
+ end
@@ -1,11 +1,13 @@
1
+ require 'ollama/documents/cache/common'
2
+
1
3
  class Ollama::Documents::MemoryCache
4
+ include Ollama::Documents::Cache::Common
5
+
2
6
  def initialize(prefix:)
3
7
  @prefix = prefix
4
8
  @data = {}
5
9
  end
6
10
 
7
- attr_writer :prefix
8
-
9
11
  def [](key)
10
12
  @data[pre(key)]
11
13
  end
@@ -23,11 +25,11 @@ class Ollama::Documents::MemoryCache
23
25
  end
24
26
 
25
27
  def size
26
- @data.size
28
+ count
27
29
  end
28
30
 
29
31
  def clear
30
- @data.clear
32
+ @data.delete_if { |key, _| key.start_with?(@prefix) }
31
33
  self
32
34
  end
33
35
 
@@ -36,11 +38,7 @@ class Ollama::Documents::MemoryCache
36
38
  end
37
39
  include Enumerable
38
40
 
39
- def pre(key)
40
- [ @prefix, key ].join
41
- end
42
-
43
- def unpre(key)
44
- key.sub(/\A#@prefix/, '')
41
+ def full_each(&block)
42
+ @data.each(&block)
45
43
  end
46
44
  end
@@ -0,0 +1,44 @@
1
+ require 'redis'
2
+
3
+ class Ollama::Documents
4
+ class RedisBackedMemoryCache < MemoryCache
5
+ def initialize(prefix:, url: ENV['REDIS_URL'])
6
+ super(prefix:)
7
+ url or raise ArgumentError, 'require redis url'
8
+ @prefix, @url = prefix, url
9
+ @redis_cache = Ollama::Documents::RedisCache.new(prefix:, url:)
10
+ @redis_cache.full_each do |key, value|
11
+ @data[key] = value
12
+ end
13
+ end
14
+
15
+ def redis
16
+ @redis_cache.redis
17
+ end
18
+
19
+ def []=(key, value)
20
+ super
21
+ redis.set(pre(key), JSON(value))
22
+ end
23
+
24
+ def delete(key)
25
+ result = redis.del(pre(key))
26
+ super
27
+ result
28
+ end
29
+
30
+ def clear
31
+ redis.scan_each(match: "#@prefix*") { |key| redis.del(key) }
32
+ super
33
+ self
34
+ end
35
+
36
+ def pre(key)
37
+ [ @prefix, key ].join
38
+ end
39
+
40
+ def unpre(key)
41
+ key.sub(/\A#@prefix/, '')
42
+ end
43
+ end
44
+ end
@@ -1,13 +1,14 @@
1
+ require 'ollama/documents/cache/common'
1
2
  require 'redis'
2
3
 
3
4
  class Ollama::Documents::RedisCache
5
+ include Ollama::Documents::Cache::Common
6
+
4
7
  def initialize(prefix:, url: ENV['REDIS_URL'])
5
8
  url or raise ArgumentError, 'require redis url'
6
9
  @prefix, @url = prefix, url
7
10
  end
8
11
 
9
- attr_writer :prefix
10
-
11
12
  def redis
12
13
  @redis ||= Redis.new(url: @url)
13
14
  end
@@ -48,11 +49,11 @@ class Ollama::Documents::RedisCache
48
49
  end
49
50
  include Enumerable
50
51
 
51
- def pre(key)
52
- [ @prefix, key ].join
53
- end
54
-
55
- def unpre(key)
56
- key.sub(/\A#@prefix/, '')
52
+ def full_each(&block)
53
+ redis.scan_each do |key|
54
+ value = redis.get(key) or next
55
+ value = JSON(value, object_class: Ollama::Documents::Record)
56
+ block.(key, value)
57
+ end
57
58
  end
58
59
  end
@@ -3,8 +3,11 @@ require 'digest'
3
3
 
4
4
  class Ollama::Documents
5
5
  end
6
- require 'ollama/documents/memory_cache'
7
- require 'ollama/documents/redis_cache'
6
+ class Ollama::Documents::Cache
7
+ end
8
+ require 'ollama/documents/cache/memory_cache'
9
+ require 'ollama/documents/cache/redis_cache'
10
+ require 'ollama/documents/cache/redis_backed_memory_cache'
8
11
  module Ollama::Documents::Splitters
9
12
  end
10
13
  require 'ollama/documents/splitters/character'
@@ -16,11 +19,15 @@ class Ollama::Documents
16
19
 
17
20
  class Record < JSON::GenericObject
18
21
  def to_s
19
- my_tags = Ollama::Utils::Tags.new(tags)
22
+ my_tags = tags_set
20
23
  my_tags.empty? or my_tags = " #{my_tags}"
21
24
  "#<#{self.class} #{text.inspect}#{my_tags} #{similarity || 'n/a'}>"
22
25
  end
23
26
 
27
+ def tags_set
28
+ Ollama::Utils::Tags.new(tags)
29
+ end
30
+
24
31
  def ==(other)
25
32
  text == other.text
26
33
  end
@@ -28,15 +35,19 @@ class Ollama::Documents
28
35
  alias inspect to_s
29
36
  end
30
37
 
31
- def initialize(ollama:, model:, model_options: nil, collection: :default, cache: MemoryCache, redis_url: nil)
32
- @ollama, @model, @model_options, @collection = ollama, model, model_options, collection
38
+ def initialize(ollama:, model:, model_options: nil, collection: default_collection, cache: MemoryCache, redis_url: nil)
39
+ @ollama, @model, @model_options, @collection = ollama, model, model_options, collection.to_sym
33
40
  @cache, @redis_url = connect_cache(cache), redis_url
34
41
  end
35
42
 
43
+ def default_collection
44
+ :default
45
+ end
46
+
36
47
  attr_reader :ollama, :model, :collection
37
48
 
38
49
  def collection=(new_collection)
39
- @collection = new_collection
50
+ @collection = new_collection.to_sym
40
51
  @cache.prefix = prefix
41
52
  end
42
53
 
@@ -137,15 +148,7 @@ class Ollama::Documents
137
148
  end
138
149
 
139
150
  def collections
140
- case @cache
141
- when MemoryCache
142
- [ @collection ]
143
- when RedisCache
144
- prefix = '%s-' % self.class
145
- Documents::RedisCache.new(prefix:, url: @redis_url).map { _1[/#{prefix}(.*)-/, 1] }.uniq
146
- else
147
- []
148
- end
151
+ ([ default_collection ] + @cache.collections('%s-' % self.class)).uniq
149
152
  end
150
153
 
151
154
  def tags
@@ -156,7 +159,7 @@ class Ollama::Documents
156
159
 
157
160
  def connect_cache(cache_class)
158
161
  cache = nil
159
- if cache_class == RedisCache
162
+ if cache_class.instance_method(:redis)
160
163
  begin
161
164
  cache = cache_class.new(prefix:)
162
165
  cache.size
@@ -3,11 +3,20 @@ class Ollama::Utils::ColorizeTexts
3
3
  include Term::ANSIColor
4
4
  include Ollama::Utils::Width
5
5
 
6
+ # Initializes a new instance of Ollama::Utils::ColorizeTexts
7
+ #
8
+ # @param [Array<String>] texts the array of strings to be displayed with colors
9
+ #
10
+ # @return [Ollama::Utils::ColorizeTexts] an instance of Ollama::Utils::ColorizeTexts
6
11
  def initialize(*texts)
7
- texts = texts.map(&:to_a)
12
+ texts = texts.map(&:to_a)
8
13
  @texts = Array(texts.flatten)
9
14
  end
10
15
 
16
+ # Returns a string representation of the object, including all texts content,
17
+ # colored differently and their sizes.
18
+ #
19
+ # @return [String] The formatted string.
11
20
  def to_s
12
21
  result = +''
13
22
  @texts.each_with_index do |t, i|
@@ -22,6 +31,14 @@ class Ollama::Utils::ColorizeTexts
22
31
 
23
32
  private
24
33
 
34
+ # Returns the nearest RGB color to the given ANSI color
35
+ #
36
+ # @param [color] color The ANSI color attribute
37
+ #
38
+ # @return [Array<RGBTriple>] An array containing two RGB colors, one for black and
39
+ # one for white text, where the first is the closest match to the input color
40
+ # when printed on a black background, and the second is the closest match
41
+ # when printed on a white background.
25
42
  def text_color(color)
26
43
  color = Term::ANSIColor::Attribute[color]
27
44
  [
@@ -30,6 +47,9 @@ class Ollama::Utils::ColorizeTexts
30
47
  ].max_by { |t| t.distance_to(color) }
31
48
  end
32
49
 
50
+ # Returns an array of colors for each step in the gradient
51
+ #
52
+ # @return [Array<Array<Integer>>] An array of RGB color arrays
33
53
  def colors
34
54
  @colors ||= (0..255).map { |i|
35
55
  [
@@ -2,6 +2,7 @@ require 'tempfile'
2
2
  require 'tins/unit'
3
3
  require 'infobar'
4
4
  require 'mime-types'
5
+ require 'stringio'
5
6
 
6
7
  class Ollama::Utils::Fetcher
7
8
  module ContentType
@@ -10,13 +11,14 @@ class Ollama::Utils::Fetcher
10
11
 
11
12
  class RetryWithoutStreaming < StandardError; end
12
13
 
13
- def initialize
14
+ def initialize(debug: false)
15
+ @debug = debug
14
16
  @started = false
15
17
  @streaming = true
16
18
  end
17
19
 
18
- def self.get(url, &block)
19
- new.get(url, &block)
20
+ def self.get(url, **options, &block)
21
+ new(**options).get(url, &block)
20
22
  end
21
23
 
22
24
  def get(url, &block)
@@ -46,11 +48,11 @@ class Ollama::Utils::Fetcher
46
48
  @streaming = false
47
49
  retry
48
50
  rescue => e
49
- STDERR.puts "Cannot get #{url.to_s.inspect} (#{e}): #{response&.status_line}"
50
- unless e.is_a?(RuntimeError)
51
+ STDERR.puts "Cannot get #{url.to_s.inspect} (#{e}): #{response&.status_line || 'n/a'}"
52
+ if @debug && !e.is_a?(RuntimeError)
51
53
  STDERR.puts "#{e.backtrace * ?\n}"
52
54
  end
53
- yield nil
55
+ yield StringIO.new.extend(ContentType)
54
56
  end
55
57
 
56
58
  def headers
@@ -1,6 +1,24 @@
1
1
  module Ollama::Utils::FileArgument
2
2
  module_function
3
3
 
4
+ # Returns the contents of a file or string, or a default value if neither is provided.
5
+ #
6
+ # @param [String] path_or_content The path to a file or a string containing
7
+ # the content.
8
+ #
9
+ # @param [String] default The default value to return if no valid input is
10
+ # given. Defaults to nil.
11
+ #
12
+ # @return [String] The contents of the file, the string, or the default value.
13
+ #
14
+ # @example Get the contents of a file
15
+ # get_file_argument('path/to/file')
16
+ #
17
+ # @example Use a string as content
18
+ # get_file_argument('string content')
19
+ #
20
+ # @example Return a default value if no valid input is given
21
+ # get_file_argument(nil, default: 'default content')
4
22
  def get_file_argument(path_or_content, default: nil)
5
23
  if path_or_content.present? && path_or_content.size < 2 ** 15 &&
6
24
  File.basename(path_or_content).size < 2 ** 8 &&
@@ -1,5 +1,6 @@
1
1
  require 'sorted_set'
2
2
 
3
+
3
4
  class Ollama::Utils::Tags < SortedSet
4
5
  def to_a
5
6
  super.map(&:to_s)
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.3.2'
3
+ VERSION = '0.4.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,26 +1,26 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.3.2 ruby lib
2
+ # stub: ollama-ruby 0.4.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.3.2".freeze
6
+ s.version = "0.4.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-09-15"
11
+ s.date = "2024-09-21"
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/memory_cache.rb".freeze, "lib/ollama/documents/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/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/memory_cache.rb".freeze, "lib/ollama/documents/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/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_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/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/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/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/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/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.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_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/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/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/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
 
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
28
28
  s.add_development_dependency(%q<all_images>.freeze, ["~> 0.4".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
+ s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
32
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
31
33
  s.add_runtime_dependency(%q<excon>.freeze, ["~> 0.111".freeze])
32
34
  s.add_runtime_dependency(%q<infobar>.freeze, ["~> 0.8".freeze])
33
35
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
@@ -1,63 +1,63 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::MemoryCache do
4
- let :memory_cache do
4
+ let :cache do
5
5
  described_class.new prefix: 'test-'
6
6
  end
7
7
 
8
8
  it 'can be instantiated' do
9
- expect(memory_cache).to be_a described_class
9
+ expect(cache).to be_a described_class
10
10
  end
11
11
 
12
12
  it 'can get/set a key' do
13
13
  key, value = 'foo', { test: true }
14
14
  expect {
15
- memory_cache[key] = value
15
+ cache[key] = value
16
16
  }.to change {
17
- memory_cache[key]
17
+ cache[key]
18
18
  }.from(nil).to(value)
19
19
  end
20
20
 
21
21
  it 'can determine if key exists' do
22
22
  key, value = 'foo', { test: true }
23
23
  expect {
24
- memory_cache[key] = value
24
+ cache[key] = value
25
25
  }.to change {
26
- memory_cache.key?(key)
26
+ cache.key?(key)
27
27
  }.from(false).to(true)
28
28
  end
29
29
 
30
30
  it 'can delete' do
31
31
  key, value = 'foo', { test: true }
32
- memory_cache[key] = value
32
+ cache[key] = value
33
33
  expect {
34
- memory_cache.delete(key)
34
+ cache.delete(key)
35
35
  }.to change {
36
- memory_cache.key?(key)
36
+ cache.key?(key)
37
37
  }.from(true).to(false)
38
38
  end
39
39
 
40
40
  it 'returns size' do
41
41
  key, value = 'foo', { test: true }
42
42
  expect {
43
- memory_cache[key] = value
43
+ cache[key] = value
44
44
  }.to change {
45
- memory_cache.size
45
+ cache.size
46
46
  }.from(0).to(1)
47
47
  end
48
48
 
49
49
  it 'can clear' do
50
50
  key, value = 'foo', { test: true }
51
- memory_cache[key] = value
51
+ cache[key] = value
52
52
  expect {
53
- expect(memory_cache.clear).to eq memory_cache
53
+ expect(cache.clear).to eq cache
54
54
  }.to change {
55
- memory_cache.size
55
+ cache.size
56
56
  }.from(1).to(0)
57
57
  end
58
58
 
59
59
  it 'can iterate over keys under a prefix' do
60
- memory_cache['foo'] = 'bar'
61
- expect(memory_cache.to_a).to eq [ %w[ test-foo bar ] ]
60
+ cache['foo'] = 'bar'
61
+ expect(cache.to_a).to eq [ %w[ test-foo bar ] ]
62
62
  end
63
63
  end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Ollama::Documents::RedisBackedMemoryCache do
4
+ it 'raises ArgumentError if url is missing' do
5
+ expect {
6
+ described_class.new prefix: 'test-', url: nil
7
+ }.to raise_error ArgumentError
8
+ end
9
+
10
+ context 'test redis interactions' do
11
+ let :cache do
12
+ described_class.new prefix: 'test-', url: 'something'
13
+ end
14
+
15
+ let :data do
16
+ cache.instance_eval { @data }
17
+ end
18
+
19
+ let :redis_cache do
20
+ cache.instance_eval { @redis_cache }
21
+ end
22
+
23
+ let :redis do
24
+ double('Redis')
25
+ end
26
+
27
+ before do
28
+ allow_any_instance_of(Ollama::Documents::RedisCache).to\
29
+ receive(:redis).and_return(redis)
30
+ allow(redis).to receive(:scan_each)
31
+ end
32
+
33
+ it 'can be instantiated and initialized' do
34
+ cache = described_class.new prefix: 'test-', url: 'something'
35
+ expect(cache).to be_a described_class
36
+ end
37
+
38
+ it 'has Redis client' do
39
+ expect(cache.redis).to eq redis
40
+ end
41
+
42
+ it 'can get a key' do
43
+ key = 'foo'
44
+ expect(data).to receive(:[]).with('test-' + key).and_return 666
45
+ expect(cache[key]).to eq 666
46
+ end
47
+
48
+ it 'can set a value for a key' do
49
+ key, value = 'foo', { test: true }
50
+ expect(data).to receive(:[]=).with('test-' + key, { test: true }).and_call_original
51
+ expect(redis).to receive(:set).with('test-' + key, JSON(value))
52
+ cache[key] = value
53
+ end
54
+
55
+ it 'can determine if key exists' do
56
+ key = 'foo'
57
+ expect(data).to receive(:key?).with('test-' + key).and_return(false, true)
58
+ expect(cache.key?('foo')).to eq false
59
+ expect(cache.key?('foo')).to eq true
60
+ end
61
+
62
+ it 'can delete' do
63
+ key = 'foo'
64
+ expect(data).to receive(:delete).with('test-' + key)
65
+ expect(redis).to receive(:del).with('test-' + key)
66
+ cache.delete(key)
67
+ end
68
+
69
+ it 'returns size' do
70
+ allow(cache).to receive(:count).and_return 3
71
+ expect(cache.size).to eq 3
72
+ end
73
+
74
+ it 'can clear' do
75
+ expect(redis).to receive(:scan_each).with(match: 'test-*').and_yield(
76
+ 'test-foo'
77
+ )
78
+ expect(redis).to receive(:del).with('test-foo')
79
+ expect(cache.clear).to eq cache
80
+ end
81
+
82
+ it 'can iterate over keys under a prefix' do
83
+ data['test-foo'] = 'bar'
84
+ expect(cache.to_a).to eq [ %w[ test-foo bar ] ]
85
+ end
86
+
87
+ it 'can compute prefix with pre' do
88
+ expect(cache.pre('foo')).to eq 'test-foo'
89
+ end
90
+
91
+ it 'can remove prefix with unpre' do
92
+ expect(cache.unpre('test-foo')).to eq 'foo'
93
+ end
94
+ end
95
+ end
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::RedisCache do
4
4
  it 'can be instantiated' do
5
- redis_cache = described_class.new prefix: 'test-', url: 'something'
6
- expect(redis_cache).to be_a described_class
5
+ cache = described_class.new prefix: 'test-', url: 'something'
6
+ expect(cache).to be_a described_class
7
7
  end
8
8
 
9
9
  it 'raises ArgumentError if url is missing' do
@@ -13,7 +13,7 @@ RSpec.describe Ollama::Documents::RedisCache do
13
13
  end
14
14
 
15
15
  context 'test redis interactions' do
16
- let :redis_cache do
16
+ let :cache do
17
17
  described_class.new prefix: 'test-', url: 'something'
18
18
  end
19
19
 
@@ -26,32 +26,32 @@ RSpec.describe Ollama::Documents::RedisCache do
26
26
  end
27
27
 
28
28
  it 'has Redis client' do
29
- expect(redis_cache.redis).to eq redis
29
+ expect(cache.redis).to eq redis
30
30
  end
31
31
 
32
32
  it 'can get a key' do
33
33
  key = 'foo'
34
- expect(redis).to receive(:get).with('test-' + key).and_return 666
35
- redis_cache[key]
34
+ expect(redis).to receive(:get).with('test-' + key).and_return '"some_json"'
35
+ expect(cache[key]).to eq 'some_json'
36
36
  end
37
37
 
38
38
  it 'can set a value for a key' do
39
39
  key, value = 'foo', { test: true }
40
40
  expect(redis).to receive(:set).with('test-' + key, JSON(value))
41
- redis_cache[key] = value
41
+ cache[key] = value
42
42
  end
43
43
 
44
44
  it 'can determine if key exists' do
45
45
  key = 'foo'
46
46
  expect(redis).to receive(:exists?).with('test-' + key).and_return(false, true)
47
- expect(redis_cache.key?('foo')).to eq false
48
- expect(redis_cache.key?('foo')).to eq true
47
+ expect(cache.key?('foo')).to eq false
48
+ expect(cache.key?('foo')).to eq true
49
49
  end
50
50
 
51
51
  it 'can delete' do
52
52
  key = 'foo'
53
53
  expect(redis).to receive(:del).with('test-' + key)
54
- redis_cache.delete(key)
54
+ cache.delete(key)
55
55
  end
56
56
 
57
57
  it 'returns size' do
@@ -59,7 +59,7 @@ RSpec.describe Ollama::Documents::RedisCache do
59
59
  and_yield('test-foo').
60
60
  and_yield('test-bar').
61
61
  and_yield('test-baz')
62
- expect(redis_cache.size).to eq 3
62
+ expect(cache.size).to eq 3
63
63
  end
64
64
 
65
65
  it 'can clear' do
@@ -67,20 +67,20 @@ RSpec.describe Ollama::Documents::RedisCache do
67
67
  'test-foo'
68
68
  )
69
69
  expect(redis).to receive(:del).with('test-foo')
70
- expect(redis_cache.clear).to eq redis_cache
70
+ expect(cache.clear).to eq cache
71
71
  end
72
72
 
73
73
  it 'can iterate over keys under a prefix' do
74
74
  expect(redis).to receive(:scan_each).with(match: 'test-*')
75
- redis_cache.to_a
75
+ cache.to_a
76
76
  end
77
77
 
78
78
  it 'can compute prefix with pre' do
79
- expect(redis_cache.pre('foo')).to eq 'test-foo'
79
+ expect(cache.pre('foo')).to eq 'test-foo'
80
80
  end
81
81
 
82
82
  it 'can remove prefix with unpre' do
83
- expect(redis_cache.unpre('test-foo')).to eq 'foo'
83
+ expect(cache.unpre('test-foo')).to eq 'foo'
84
84
  end
85
85
  end
86
86
  end
@@ -56,7 +56,8 @@ RSpec.describe Ollama::Utils::Fetcher do
56
56
  with(headers: fetcher.headers).
57
57
  to_return(status: 500)
58
58
  fetcher.get(url) do |tmp|
59
- expect(tmp).to be_nil
59
+ expect(tmp).to be_a StringIO
60
+ expect(tmp.read).to eq ''
60
61
  end
61
62
  end
62
63
 
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.3.2
4
+ version: 0.4.0
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-09-15 00:00:00.000000000 Z
11
+ date: 2024-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: debug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: excon
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -303,8 +331,10 @@ extra_rdoc_files:
303
331
  - lib/ollama/commands/show.rb
304
332
  - lib/ollama/commands/tags.rb
305
333
  - lib/ollama/documents.rb
306
- - lib/ollama/documents/memory_cache.rb
307
- - lib/ollama/documents/redis_cache.rb
334
+ - lib/ollama/documents/cache/common.rb
335
+ - lib/ollama/documents/cache/memory_cache.rb
336
+ - lib/ollama/documents/cache/redis_backed_memory_cache.rb
337
+ - lib/ollama/documents/cache/redis_cache.rb
308
338
  - lib/ollama/documents/splitters/character.rb
309
339
  - lib/ollama/documents/splitters/semantic.rb
310
340
  - lib/ollama/dto.rb
@@ -367,8 +397,10 @@ files:
367
397
  - lib/ollama/commands/show.rb
368
398
  - lib/ollama/commands/tags.rb
369
399
  - lib/ollama/documents.rb
370
- - lib/ollama/documents/memory_cache.rb
371
- - lib/ollama/documents/redis_cache.rb
400
+ - lib/ollama/documents/cache/common.rb
401
+ - lib/ollama/documents/cache/memory_cache.rb
402
+ - lib/ollama/documents/cache/redis_backed_memory_cache.rb
403
+ - lib/ollama/documents/cache/redis_cache.rb
372
404
  - lib/ollama/documents/splitters/character.rb
373
405
  - lib/ollama/documents/splitters/semantic.rb
374
406
  - lib/ollama/dto.rb
@@ -420,6 +452,7 @@ files:
420
452
  - spec/ollama/commands/show_spec.rb
421
453
  - spec/ollama/commands/tags_spec.rb
422
454
  - spec/ollama/documents/memory_cache_spec.rb
455
+ - spec/ollama/documents/redis_backed_memory_cache_spec.rb
423
456
  - spec/ollama/documents/redis_cache_spec.rb
424
457
  - spec/ollama/documents/splitters/character_spec.rb
425
458
  - spec/ollama/documents/splitters/semantic_spec.rb
@@ -486,6 +519,7 @@ test_files:
486
519
  - spec/ollama/commands/show_spec.rb
487
520
  - spec/ollama/commands/tags_spec.rb
488
521
  - spec/ollama/documents/memory_cache_spec.rb
522
+ - spec/ollama/documents/redis_backed_memory_cache_spec.rb
489
523
  - spec/ollama/documents/redis_cache_spec.rb
490
524
  - spec/ollama/documents/splitters/character_spec.rb
491
525
  - spec/ollama/documents/splitters/semantic_spec.rb