ollama-ruby 0.3.2 → 0.4.0

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