ollama-ruby 0.9.3 → 0.11.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: fda5b55631024d2e7367400032462d87244daaa44dac2835aae7f7dad3f3f885
4
- data.tar.gz: b085138d8de3daa61cc5f7f2cdfc17ff14c7a17737675452ce8e9ea5be002113
3
+ metadata.gz: 6611c14b779a919b256552774080305825b4e81cd5e43ae0303026aaaed7c13e
4
+ data.tar.gz: a34e71ef5b07cdd8a0cdf5dce9de7f7e9c3faca1829e4837c54ea243458b8f05
5
5
  SHA512:
6
- metadata.gz: dc3c61c2f9484d5d2a5e8b5fc97c357139d8326700ea83e6b61984c7b58d62fe2377a5c288a65a6aad7c98dcf4b3bb341772f0ff4fd9bf3b3bf9b23061040eb1
7
- data.tar.gz: 4c14196cea496a866f50bd1e414620bc7441a1923a729cffe52a42ef8cc77b16982b4be2bc644b09601900d5b403b117dd3dfe462dd5d4c6e1f324699d7396d8
6
+ metadata.gz: aa38db4bdd42ebffe2ef9b5abf7f644e38821acc4fb9650b7e8646a9fab3350640224c4ba59e13d7f182becd2a84ac881fd0c5d136ca88782e1a7febec31c2fe
7
+ data.tar.gz: b14f2626d9f2c8e6e8bc6c3b3d8947d78b4400cf0dd8888cf9f818261ba3605fc9971c2c9015f976ec48f2004cb4b0ff5d922e2efe001b5b443f03728f14ce51
data/CHANGES.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changes
2
2
 
3
+ ## 2024-11-20 v0.11.0
4
+
5
+ * Added `voice` and `interactive` reader attributes to the Say handler class.
6
+ * Refactored the `call` method in the Say handler to reopen the output stream
7
+ if it has been closed.
8
+ * Added the `open_output` method to open a new IO stream with synchronization
9
+ enabled.
10
+ * Added a test for the reopened output stream in the Say spec.
11
+ * Updated `initialize` method in `lib/ollama/handlers/say.rb` to add
12
+ `interactive` option and call new `command` method.
13
+ * Add private `command` method in lib/ollama/handlers/say.rb to generate
14
+ command for say utility based on voice and interactive options.
15
+ * Update specs in `spec/ollama/handlers/say_spec.rb` to test new behavior.
16
+ * Updated `FollowChat` class to correctly initialize markdown and voice
17
+ attributes
18
+ * Update `choose_document_policy` policy list in chat script to include
19
+ 'ignoring'
20
+ * Updated `parse_content` method to handle 'ignoring' document policy.
21
+
22
+ ## 2024-10-31 v0.10.0
23
+
24
+ * Improved URL and tag parsing in `parse_content`:
25
+ + Added support for `file://` protocol to content scans.
26
+ + Updated regex pattern to match local files starting with `~`, `.`, or `/`.
27
+ + Remove # anchors for file URLs (and files)
28
+ * Improved parsing of content in ollama_chat:
29
+ + Use `content.scan(%r((https?://\S+)|(#\S+)|(\S+\/\S+)))` to match URLs, tags and files.
30
+ + For foo/bar file pathes prepend `./`foo/bar, for foo you have to enter ./foo still.
31
+ + Added a check for file existence before fetching its content
32
+ * Move vector methods into cache implementations:
33
+ + Update `documents.rb` to use `@cache.norm` and `@cache.cosine_similarity`
34
+ + Remove unused code in `documents.rb` (including `Ollama::Utils::Math`)
35
+ + Add `include Ollama::Utils::Math` in `cache/common.rb`
36
+ * Document existing collections, pre, and unpre methods:
37
+ + Update module Ollama::Documents::Cache::Common to include documentation for existing methods
38
+ * Use kramdown-ansi gem for Markdown output in terminal:
39
+ + Update `kramdown-ansi` to **0.0** in Gemfile and Rakefile
40
+ + Remove `ollama/utils/width.rb` as it's no longer needed
41
+ + Remove `spec/ollama/utils/width_spec.rb` and `spec/ollama/utils/ansi_markdown_spec.rb` as they're not used anymore
42
+ + Update `ollama-ruby.gemspec` to reflect the new dependencies and remove unused files
43
+ * Updated print messages to include `.to_s.inspect` for accurate inspection of
44
+ source content in `ollama_chat`.
45
+
3
46
  ## 2024-10-21 v0.9.3
4
47
 
5
48
  * Update dependencies and date:
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ GemHadar do
14
14
  test_dir 'spec'
15
15
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
16
16
  '.yardoc', 'doc', 'tags', 'errors.lst', 'cscope.out', 'coverage', 'tmp',
17
- 'corpus'
17
+ 'corpus', 'yard'
18
18
  package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
19
19
  '.rspec', *Dir.glob('.github/**/*', File::FNM_DOTMATCH)
20
20
  readme 'README.md'
@@ -24,11 +24,9 @@ GemHadar do
24
24
 
25
25
  required_ruby_version '~> 3.1'
26
26
 
27
- dependency 'excon', '~> 0.111'
27
+ dependency 'excon', '~> 1.0'
28
28
  dependency 'infobar', '~> 0.8'
29
29
  dependency 'term-ansicolor', '~> 1.11'
30
- dependency 'kramdown-parser-gfm', '~> 1.1'
31
- dependency 'terminal-table', '~> 3.0'
32
30
  dependency 'redis', '~> 5.0'
33
31
  dependency 'numo-narray', '~> 0.9'
34
32
  dependency 'more_math', '~> 1.1'
@@ -42,6 +40,8 @@ GemHadar do
42
40
  dependency 'json', '~> 2.0'
43
41
  dependency 'xdg', '~> 7.0'
44
42
  dependency 'tins', '~> 1.34'
43
+ dependency 'kramdown-ansi', '~> 0.0', '>= 0.0.1'
44
+ dependency 'ostruct', '~> 0.0'
45
45
  development_dependency 'all_images', '~> 0.4'
46
46
  development_dependency 'rspec', '~> 3.2'
47
47
  development_dependency 'webmock'
data/bin/ollama_chat CHANGED
@@ -114,10 +114,10 @@ class FollowChat
114
114
  def initialize(messages:, markdown: false, voice: nil, output: $stdout)
115
115
  super(output:)
116
116
  @output.sync = true
117
- @markdown = markdown
118
- @say = voice ? Handlers::Say.new(voice:) : NOP
119
- @messages = messages
120
- @user = nil
117
+ @markdown = markdown
118
+ @say = voice ? Handlers::Say.new(voice:) : NOP
119
+ @messages = messages
120
+ @user = nil
121
121
  end
122
122
 
123
123
  def call(response)
@@ -132,7 +132,7 @@ class FollowChat
132
132
  content = response.message&.content
133
133
  @messages.last.content << content
134
134
  if @markdown and content = @messages.last.content.full?
135
- markdown_content = Utils::ANSIMarkdown.parse(content)
135
+ markdown_content = Kramdown::ANSI.parse(content)
136
136
  @output.print clear_screen, move_home, @user, ?\n, markdown_content
137
137
  else
138
138
  @output.print content
@@ -159,7 +159,7 @@ class FollowChat
159
159
  load_duration: Tins::Duration.new(response.load_duration / 1e9),
160
160
  }.map { _1 * '=' } * ' '
161
161
  '📊 ' + color(111) {
162
- Utils::Width.wrap(stats_text, percentage: 90).gsub(/(?<!\A)^/, ' ')
162
+ Kramdown::ANSI::Width.wrap(stats_text, percentage: 90).gsub(/(?<!\A)^/, ' ')
163
163
  }
164
164
  end
165
165
  end
@@ -364,7 +364,7 @@ def list_conversation(messages, last = nil)
364
364
  when 'system' then 213
365
365
  else 210
366
366
  end
367
- content = m.content.full? { $markdown.on? ? Utils::ANSIMarkdown.parse(_1) : _1 }
367
+ content = m.content.full? { $markdown.on? ? Kramdown::ANSI.parse(_1) : _1 }
368
368
  message_text = message_type(m.images) + " "
369
369
  message_text += bold { color(role_color) { m.role } }
370
370
  message_text += ":\n#{content}"
@@ -539,8 +539,8 @@ end
539
539
 
540
540
  def import_source(source_io, source)
541
541
  source = source.to_s
542
- puts "Importing #{italic { source_io&.content_type }} document #{source.inspect} now."
543
- source_content = parse_source(source_io)
542
+ puts "Importing #{italic { source_io&.content_type }} document #{source.to_s.inspect} now."
543
+ source_content = parse_source(source_io)
544
544
  "Imported #{source.inspect}:\n#{source_content}\n\n"
545
545
  end
546
546
 
@@ -553,7 +553,7 @@ def import(source)
553
553
  end
554
554
 
555
555
  def summarize_source(source_io, source, words: nil)
556
- puts "Summarizing #{italic { source_io&.content_type }} document #{source.inspect} now."
556
+ puts "Summarizing #{italic { source_io&.content_type }} document #{source.to_s.inspect} now."
557
557
  words = words.to_i
558
558
  words < 1 and words = 100
559
559
  source_content = parse_source(source_io)
@@ -608,7 +608,7 @@ def embed_source(source_io, source, count: nil)
608
608
  inputs or return
609
609
  source = source.to_s
610
610
  if source.start_with?(?!)
611
- source = Utils::Width.truncate(
611
+ source = Kramdown::ANSI::Width.truncate(
612
612
  source[1..-1].gsub(/\W+/, ?_),
613
613
  length: 10
614
614
  )
@@ -638,31 +638,39 @@ def parse_content(content, images)
638
638
  tags = Utils::Tags.new
639
639
 
640
640
  contents = [ content ]
641
- content.scan(%r((?:\.\.|[.~])?/\S+|https?://\S+|#\S+)).each do |source|
642
- case source
643
- when /\A#(\S+)/
644
- tags.add($1, source:)
645
- else
646
- source = source.sub(/(["')]|\*+)\z/, '')
647
- fetch_source(source) do |source_io|
648
- case source_io&.content_type&.media_type
649
- when 'image'
650
- add_image(images, source_io, source)
651
- when 'text', 'application', nil
652
- case $document_policy
653
- when 'importing'
654
- contents << import_source(source_io, source)
655
- when 'embedding'
656
- embed_source(source_io, source)
657
- when 'summarizing'
658
- contents << summarize_source(source_io, source)
659
- end
660
- else
661
- STDERR.puts(
662
- "Cannot fetch #{source.to_s.inspect} with content type "\
663
- "#{source_io&.content_type.inspect}"
664
- )
641
+ content.scan(%r((https?://\S+)|(#\S+)|(?:file://)?(\S*\/\S+))).each do |url, tag, file|
642
+ case
643
+ when tag
644
+ tags.add(tag)
645
+ next
646
+ when file
647
+ file = file.sub(/#.*/, '')
648
+ file =~ %r(\A[~./]) or file.prepend('./')
649
+ File.exist?(file) or next
650
+ source = file
651
+ when url
652
+ source = url
653
+ end
654
+ fetch_source(source) do |source_io|
655
+ case source_io&.content_type&.media_type
656
+ when 'image'
657
+ add_image(images, source_io, source)
658
+ when 'text', 'application', nil
659
+ case $document_policy
660
+ when 'ignoring'
661
+ nil
662
+ when 'importing'
663
+ contents << import_source(source_io, source)
664
+ when 'embedding'
665
+ embed_source(source_io, source)
666
+ when 'summarizing'
667
+ contents << summarize_source(source_io, source)
665
668
  end
669
+ else
670
+ STDERR.puts(
671
+ "Cannot fetch #{source.to_s.inspect} with content type "\
672
+ "#{source_io&.content_type.inspect}"
673
+ )
666
674
  end
667
675
  end
668
676
  end
@@ -705,7 +713,7 @@ ensure
705
713
  end
706
714
 
707
715
  def choose_document_policy
708
- policies = %w[ importing embedding summarizing ].sort
716
+ policies = %w[ importing embedding summarizing ignoring ].sort
709
717
  current = if policies.index($document_policy)
710
718
  $document_policy
711
719
  elsif policies.index($config.document_policy)
@@ -755,7 +763,7 @@ end
755
763
  def show_system_prompt
756
764
  puts <<~EOT
757
765
  Configured system prompt is:
758
- #{Utils::ANSIMarkdown.parse($system.to_s).gsub(/\n+\z/, '').full? || 'n/a'}
766
+ #{Kramdown::ANSI.parse($system.to_s).gsub(/\n+\z/, '').full? || 'n/a'}
759
767
  EOT
760
768
  end
761
769
 
@@ -1165,7 +1173,8 @@ loop do
1165
1173
  end
1166
1174
 
1167
1175
  if location = at_location.full?
1168
- content += " [#{location} – do not comment on this information, just consider it for eventual queries]"
1176
+ content += " [#{location} – do not comment on this the time and location, "\
1177
+ "just consider it for eventual queries]"
1169
1178
  end
1170
1179
 
1171
1180
  messages << Message.new(role: 'user', content:, images: images.dup)
@@ -1,16 +1,31 @@
1
1
  module Ollama::Documents::Cache::Common
2
- attr_writer :prefix
2
+ include Ollama::Utils::Math
3
3
 
4
+ attr_writer :prefix # current prefix defined for the cache
5
+
6
+ # Returns an array of collection names that match the given prefix.
7
+ #
8
+ # @param prefix [String] a string to search for in collection names
9
+ # @return [Array<Symbol>] an array of matching collection names
4
10
  def collections(prefix)
5
11
  unique = Set.new
6
12
  full_each { |key, _| unique << key[/\A#{prefix}(.*)-/, 1] }
7
13
  unique.map(&:to_sym)
8
14
  end
9
15
 
16
+ # Returns a string representing the given `key` prefixed with the defined
17
+ # prefix.
18
+ #
19
+ # @param key [String] the key to join with the prefix
20
+ # @return [String] the joined string of prefix and key
10
21
  def pre(key)
11
22
  [ @prefix, key ].join
12
23
  end
13
24
 
25
+ # Returns a string with the prefix removed from the given `key`.
26
+ #
27
+ # @param key [String] the input string containing the prefix.
28
+ # @return [String] the input string without the prefix.
14
29
  def unpre(key)
15
30
  key.sub(/\A#@prefix/, '')
16
31
  end
@@ -1,5 +1,6 @@
1
1
  require 'numo/narray'
2
2
  require 'digest'
3
+ require 'kramdown/ansi'
3
4
 
4
5
  class Ollama::Documents
5
6
  end
@@ -14,8 +15,7 @@ require 'ollama/documents/splitters/character'
14
15
  require 'ollama/documents/splitters/semantic'
15
16
 
16
17
  class Ollama::Documents
17
- include Ollama::Utils::Math
18
- include Ollama::Utils::Width
18
+ include Kramdown::ANSI::Width
19
19
 
20
20
  class Record < JSON::GenericObject
21
21
  def to_s
@@ -79,7 +79,7 @@ class Ollama::Documents
79
79
  batches.each do |batch|
80
80
  embeddings = fetch_embeddings(model:, options: @model_options, input: batch)
81
81
  batch.zip(embeddings) do |text, embedding|
82
- norm = norm(embedding)
82
+ norm = @cache.norm(embedding)
83
83
  self[text] = Record[text:, embedding:, norm:, source:, tags: tags.to_a]
84
84
  end
85
85
  infobar.progress by: batch.size
@@ -125,7 +125,7 @@ class Ollama::Documents
125
125
 
126
126
  def find(string, tags: nil, prompt: nil)
127
127
  needle = convert_to_vector(string, prompt:)
128
- needle_norm = norm(needle)
128
+ needle_norm = @cache.norm(needle)
129
129
  records = @cache
130
130
  if tags
131
131
  tags = Ollama::Utils::Tags.new(tags).to_a
@@ -133,7 +133,7 @@ class Ollama::Documents
133
133
  end
134
134
  records = records.sort_by { |key, record|
135
135
  record.key = key
136
- record.similarity = cosine_similarity(
136
+ record.similarity = @cache.cosine_similarity(
137
137
  a: needle,
138
138
  b: record.embedding,
139
139
  a_norm: needle_norm,
@@ -193,11 +193,8 @@ class Ollama::Documents
193
193
  if prompt
194
194
  input = prompt % input
195
195
  end
196
- if input.is_a?(String)
197
- Numo::NArray[*fetch_embeddings(model:, input:).first]
198
- else
199
- super(input)
200
- end
196
+ input.is_a?(String) and input = fetch_embeddings(model:, input:).first
197
+ @cache.convert_to_vector(input)
201
198
  end
202
199
 
203
200
  def fetch_embeddings(model:, input:, options: nil)
@@ -1,4 +1,5 @@
1
1
  require 'term/ansicolor'
2
+ require 'kramdown/ansi'
2
3
 
3
4
  class Ollama::Handlers::Markdown
4
5
  include Ollama::Handlers::Concern
@@ -13,7 +14,7 @@ class Ollama::Handlers::Markdown
13
14
  def call(response)
14
15
  if content = response.response || response.message&.content
15
16
  @content << content
16
- markdown_content = Ollama::Utils::ANSIMarkdown.parse(@content)
17
+ markdown_content = Kramdown::ANSI.parse(@content)
17
18
  @output.print clear_screen, move_home, markdown_content
18
19
  end
19
20
  self
@@ -3,17 +3,56 @@ require 'shellwords'
3
3
  class Ollama::Handlers::Say
4
4
  include Ollama::Handlers::Concern
5
5
 
6
- def initialize(output: nil, voice: 'Samantha')
7
- output ||= IO.popen(Shellwords.join([ 'say', '-v', voice ]), 'w')
6
+ def initialize(output: nil, voice: 'Samantha', interactive: nil)
7
+ @voice = voice
8
+ @interactive = interactive
8
9
  super(output:)
9
- @output.sync = true
10
+ unless output
11
+ @output = open_output
12
+ @output_pid = @output.pid
13
+ end
10
14
  end
11
15
 
16
+ attr_reader :voice
17
+
18
+ attr_reader :interactive
19
+
12
20
  def call(response)
21
+ if @output.closed?
22
+ wait_output_pid
23
+ @output = open_output
24
+ @output_pid = @output.pid
25
+ end
13
26
  if content = response.response || response.message&.content
14
27
  @output.print content
15
28
  end
16
29
  response.done and @output.close
17
30
  self
18
31
  end
32
+
33
+ private
34
+
35
+ def open_output
36
+ io = IO.popen(Shellwords.join(command(voice:, interactive:)), 'w')
37
+ io.sync = true
38
+ io
39
+ end
40
+
41
+ def wait_output_pid
42
+ @output_pid or return
43
+ Process.wait(@output_pid, Process::WNOHANG | Process::WUNTRACED)
44
+ rescue Errno::ECHILD
45
+ end
46
+
47
+ def command(voice:, interactive:)
48
+ command = [ 'say' ]
49
+ voice and command.concat([ '-v', voice ])
50
+ case interactive
51
+ when true
52
+ command << '-i'
53
+ when String
54
+ command << '--interactive=%s' % interactive
55
+ end
56
+ command
57
+ end
19
58
  end
@@ -1,7 +1,10 @@
1
+ require 'term/ansicolor'
2
+ require 'kramdown/ansi'
3
+
1
4
  class Ollama::Utils::ColorizeTexts
2
5
  include Math
3
6
  include Term::ANSIColor
4
- include Ollama::Utils::Width
7
+ include Kramdown::ANSI::Width
5
8
 
6
9
  # Initializes a new instance of Ollama::Utils::ColorizeTexts
7
10
  #
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.9.3'
3
+ VERSION = '0.11.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/lib/ollama.rb CHANGED
@@ -16,8 +16,6 @@ end
16
16
 
17
17
  module Ollama::Utils
18
18
  end
19
- require 'ollama/utils/width'
20
- require 'ollama/utils/ansi_markdown'
21
19
  require 'ollama/utils/tags'
22
20
  require 'ollama/utils/math'
23
21
  require 'ollama/utils/colorize_texts'
data/ollama-ruby.gemspec CHANGED
@@ -1,26 +1,26 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.9.3 ruby lib
2
+ # stub: ollama-ruby 0.11.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.9.3".freeze
6
+ s.version = "0.11.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-10-21"
11
+ s.date = "2024-11-20"
12
12
  s.description = "Library that allows interacting with the Ollama API".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["ollama_console".freeze, "ollama_chat".freeze, "ollama_update".freeze, "ollama_cli".freeze]
15
- s.extra_rdoc_files = ["README.md".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/ansi_markdown.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/utils/width.rb".freeze, "lib/ollama/version.rb".freeze]
16
- s.files = [".envrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_cli".freeze, "bin/ollama_console".freeze, "bin/ollama_update".freeze, "config/redis.conf".freeze, "docker-compose.yml".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/ansi_markdown.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/utils/width.rb".freeze, "lib/ollama/version.rb".freeze, "ollama-ruby.gemspec".freeze, "spec/assets/embeddings.json".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/ansi_markdown_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/ollama/utils/width_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
15
+ s.extra_rdoc_files = ["README.md".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze]
16
+ s.files = [".envrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_cli".freeze, "bin/ollama_console".freeze, "bin/ollama_update".freeze, "config/redis.conf".freeze, "docker-compose.yml".freeze, "lib/ollama.rb".freeze, "lib/ollama/client.rb".freeze, "lib/ollama/client/command.rb".freeze, "lib/ollama/client/doc.rb".freeze, "lib/ollama/commands/chat.rb".freeze, "lib/ollama/commands/copy.rb".freeze, "lib/ollama/commands/create.rb".freeze, "lib/ollama/commands/delete.rb".freeze, "lib/ollama/commands/embed.rb".freeze, "lib/ollama/commands/embeddings.rb".freeze, "lib/ollama/commands/generate.rb".freeze, "lib/ollama/commands/ps.rb".freeze, "lib/ollama/commands/pull.rb".freeze, "lib/ollama/commands/push.rb".freeze, "lib/ollama/commands/show.rb".freeze, "lib/ollama/commands/tags.rb".freeze, "lib/ollama/documents.rb".freeze, "lib/ollama/documents/cache/common.rb".freeze, "lib/ollama/documents/cache/memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_backed_memory_cache.rb".freeze, "lib/ollama/documents/cache/redis_cache.rb".freeze, "lib/ollama/documents/splitters/character.rb".freeze, "lib/ollama/documents/splitters/semantic.rb".freeze, "lib/ollama/dto.rb".freeze, "lib/ollama/errors.rb".freeze, "lib/ollama/handlers.rb".freeze, "lib/ollama/handlers/collector.rb".freeze, "lib/ollama/handlers/concern.rb".freeze, "lib/ollama/handlers/dump_json.rb".freeze, "lib/ollama/handlers/dump_yaml.rb".freeze, "lib/ollama/handlers/markdown.rb".freeze, "lib/ollama/handlers/nop.rb".freeze, "lib/ollama/handlers/print.rb".freeze, "lib/ollama/handlers/progress.rb".freeze, "lib/ollama/handlers/say.rb".freeze, "lib/ollama/handlers/single.rb".freeze, "lib/ollama/image.rb".freeze, "lib/ollama/message.rb".freeze, "lib/ollama/options.rb".freeze, "lib/ollama/response.rb".freeze, "lib/ollama/tool.rb".freeze, "lib/ollama/tool/function.rb".freeze, "lib/ollama/tool/function/parameters.rb".freeze, "lib/ollama/tool/function/parameters/property.rb".freeze, "lib/ollama/utils/cache_fetcher.rb".freeze, "lib/ollama/utils/chooser.rb".freeze, "lib/ollama/utils/colorize_texts.rb".freeze, "lib/ollama/utils/fetcher.rb".freeze, "lib/ollama/utils/file_argument.rb".freeze, "lib/ollama/utils/math.rb".freeze, "lib/ollama/utils/tags.rb".freeze, "lib/ollama/version.rb".freeze, "ollama-ruby.gemspec".freeze, "spec/assets/embeddings.json".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
17
17
  s.homepage = "https://github.com/flori/ollama-ruby".freeze
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "Ollama-ruby - Interacting with the Ollama API".freeze, "--main".freeze, "README.md".freeze]
20
20
  s.required_ruby_version = Gem::Requirement.new("~> 3.1".freeze)
21
21
  s.rubygems_version = "3.5.22".freeze
22
22
  s.summary = "Interacting with the Ollama API".freeze
23
- s.test_files = ["spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/ansi_markdown_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/ollama/utils/width_spec.rb".freeze, "spec/spec_helper.rb".freeze]
23
+ s.test_files = ["spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/documents/memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_backed_memory_cache_spec.rb".freeze, "spec/ollama/documents/redis_cache_spec.rb".freeze, "spec/ollama/documents/splitters/character_spec.rb".freeze, "spec/ollama/documents/splitters/semantic_spec.rb".freeze, "spec/ollama/documents_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/ollama/utils/cache_fetcher_spec.rb".freeze, "spec/ollama/utils/colorize_texts_spec.rb".freeze, "spec/ollama/utils/fetcher_spec.rb".freeze, "spec/ollama/utils/file_argument_spec.rb".freeze, "spec/ollama/utils/tags_spec.rb".freeze, "spec/spec_helper.rb".freeze]
24
24
 
25
25
  s.specification_version = 4
26
26
 
@@ -30,11 +30,9 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency(%q<webmock>.freeze, [">= 0".freeze])
31
31
  s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
32
32
  s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
33
- s.add_runtime_dependency(%q<excon>.freeze, ["~> 0.111".freeze])
33
+ s.add_runtime_dependency(%q<excon>.freeze, ["~> 1.0".freeze])
34
34
  s.add_runtime_dependency(%q<infobar>.freeze, ["~> 0.8".freeze])
35
35
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
36
- s.add_runtime_dependency(%q<kramdown-parser-gfm>.freeze, ["~> 1.1".freeze])
37
- s.add_runtime_dependency(%q<terminal-table>.freeze, ["~> 3.0".freeze])
38
36
  s.add_runtime_dependency(%q<redis>.freeze, ["~> 5.0".freeze])
39
37
  s.add_runtime_dependency(%q<numo-narray>.freeze, ["~> 0.9".freeze])
40
38
  s.add_runtime_dependency(%q<more_math>.freeze, ["~> 1.1".freeze])
@@ -48,4 +46,6 @@ Gem::Specification.new do |s|
48
46
  s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
49
47
  s.add_runtime_dependency(%q<xdg>.freeze, ["~> 7.0".freeze])
50
48
  s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.34".freeze])
49
+ s.add_runtime_dependency(%q<kramdown-ansi>.freeze, ["~> 0.0".freeze, ">= 0.0.1".freeze])
50
+ s.add_runtime_dependency(%q<ostruct>.freeze, ["~> 0.0".freeze])
51
51
  end
@@ -1,30 +1,93 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Handlers::Say do
4
+ let :say do
5
+ described_class.new
6
+ end
7
+
4
8
  it 'has .to_proc' do
5
9
  expect_any_instance_of(described_class).to receive(:call).with(:foo)
6
10
  described_class.call(:foo)
7
11
  end
8
12
 
9
- it 'can print response' do
10
- output = double('output', :sync= => true)
13
+ it 'can be instantiated' do
14
+ expect(say).to be_a described_class
15
+ end
16
+
17
+ it 'can be instantiated with a given voice' do
18
+ expect_any_instance_of(described_class).to receive(:command).
19
+ with(hash_including(voice: 'TheVoice')).and_return %w[ true ]
20
+ say = described_class.new(voice: 'TheVoice')
21
+ expect(say).to be_a described_class
22
+ end
23
+
24
+ describe 'command' do
25
+ it 'can be instantiated interactively' do
26
+ expect_any_instance_of(described_class).to receive(:command).
27
+ with(hash_including(interactive: true)).and_return %w[ true ]
28
+ say = described_class.new(interactive: true)
29
+ expect(say).to be_a described_class
30
+ end
31
+
32
+ it 'can set the voice' do
33
+ expect(say.send(:command, voice: 'TheVoice', interactive: nil)).to eq(
34
+ %w[ say -v TheVoice ]
35
+ )
36
+ end
37
+
38
+ it 'can be instantiated interactively with green' do
39
+ expect_any_instance_of(described_class).to receive(:command).
40
+ with(hash_including(interactive: 'green')).and_return %w[ true ]
41
+ say = described_class.new(interactive: 'green')
42
+ expect(say).to be_a described_class
43
+ end
44
+
45
+ it 'can set interactive mode' do
46
+ expect(say.send(:command, voice: nil, interactive: true)).to eq(
47
+ %w[ say -i ]
48
+ )
49
+ end
50
+
51
+ it 'can set interactive mode to green' do
52
+ expect(say.send(:command, voice: nil, interactive: 'green')).to eq(
53
+ %w[ say --interactive=green ]
54
+ )
55
+ end
56
+ end
57
+
58
+ it 'can say response' do
59
+ output = double('output', :sync= => true, closed?: false)
11
60
  expect(output).to receive(:print).with('testing')
12
61
  expect(output).to receive(:close)
13
- print = described_class.new(output:)
62
+ say = described_class.new(output:)
14
63
  response = double('response', response: 'testing', done: false)
15
- print.call(response)
64
+ say.call(response)
16
65
  response = double('response', response: nil, message: nil, done: true)
17
- print.call(response)
66
+ say.call(response)
18
67
  end
19
68
 
20
- it 'can print message content' do
21
- output = double('output', :sync= => true)
69
+ it 'can say message content' do
70
+ output = double('output', :sync= => true, closed?: false)
22
71
  expect(output).to receive(:print).with('testing')
23
72
  expect(output).to receive(:close)
24
- print = described_class.new(output:)
73
+ say = described_class.new(output:)
25
74
  response = double('response', response: nil, message: double(content: 'testing'), done: false)
26
- print.call(response)
75
+ say.call(response)
76
+ response = double('response', response: nil, message: nil, done: true)
77
+ say.call(response)
78
+ end
79
+
80
+ it 'can reopen output if closed' do
81
+ output = double('output', :sync= => true, closed?: true)
82
+ reopened_output = double('output', :sync= => true, closed?: false, pid: 666)
83
+ expect(reopened_output).to receive(:print).with('testing')
84
+ expect(reopened_output).to receive(:close)
85
+ say = described_class.new(output:)
86
+ expect(say).to receive(:open_output).and_return(reopened_output)
87
+ response = double('response', response: 'testing', done: false)
88
+ say.call(response)
27
89
  response = double('response', response: nil, message: nil, done: true)
28
- print.call(response)
90
+ say.call(response)
29
91
  end
92
+
30
93
  end
@@ -77,12 +77,12 @@ RSpec.describe Ollama::Utils::Fetcher do
77
77
  stub_request(:get, url).
78
78
  with(headers: fetcher.headers).
79
79
  to_return(status: 500)
80
- expect(STDERR).to receive(:puts).with(/cannot.*get.*#{url}/i)
81
- fetcher.get(url) do |tmp|
82
- expect(tmp).to be_a StringIO
83
- expect(tmp.read).to eq ''
84
- expect(tmp.content_type).to eq 'text/plain'
85
- end
80
+ expect(STDERR).to receive(:puts).with(/cannot.*get.*#{url}/i)
81
+ fetcher.get(url) do |tmp|
82
+ expect(tmp).to be_a StringIO
83
+ expect(tmp.read).to eq ''
84
+ expect(tmp.content_type).to eq 'text/plain'
85
+ end
86
86
  end
87
87
 
88
88
  it 'can redirect' do
@@ -107,7 +107,7 @@ RSpec.describe Ollama::Utils::Fetcher do
107
107
 
108
108
  it 'can .execute and fail' do
109
109
  expect(IO).to receive(:popen).and_raise StandardError
110
- expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
110
+ expect(STDERR).to receive(:puts).with(/cannot.*execute.*foobar/i)
111
111
  described_class.execute('foobar') do |file|
112
112
  expect(file).to be_a StringIO
113
113
  expect(file.read).to be_empty
@@ -115,23 +115,23 @@ RSpec.describe Ollama::Utils::Fetcher do
115
115
  end
116
116
  end
117
117
 
118
- describe '.normalize_url' do
119
- it 'can handle umlauts' do
120
- expect(described_class.normalize_url('https://foo.de/bär')).to eq(
121
- 'https://foo.de/b%C3%A4r'
122
- )
123
- end
118
+ describe '.normalize_url' do
119
+ it 'can handle umlauts' do
120
+ expect(described_class.normalize_url('https://foo.de/bär')).to eq(
121
+ 'https://foo.de/b%C3%A4r'
122
+ )
123
+ end
124
124
 
125
- it 'can handle escaped umlauts' do
126
- expect(described_class.normalize_url('https://foo.de/b%C3%A4r')).to eq(
127
- 'https://foo.de/b%C3%A4r'
128
- )
129
- end
125
+ it 'can handle escaped umlauts' do
126
+ expect(described_class.normalize_url('https://foo.de/b%C3%A4r')).to eq(
127
+ 'https://foo.de/b%C3%A4r'
128
+ )
129
+ end
130
130
 
131
- it 'can remove #anchors' do
132
- expect(described_class.normalize_url('https://foo.de#bar')).to eq(
133
- 'https://foo.de'
134
- )
135
- end
136
- end
131
+ it 'can remove #anchors' do
132
+ expect(described_class.normalize_url('https://foo.de#bar')).to eq(
133
+ 'https://foo.de'
134
+ )
135
+ end
136
+ end
137
137
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.11.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-10-21 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.111'
103
+ version: '1.0'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.111'
110
+ version: '1.0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: infobar
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -136,34 +136,6 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.11'
139
- - !ruby/object:Gem::Dependency
140
- name: kramdown-parser-gfm
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.1'
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '1.1'
153
- - !ruby/object:Gem::Dependency
154
- name: terminal-table
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '3.0'
160
- type: :runtime
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '3.0'
167
139
  - !ruby/object:Gem::Dependency
168
140
  name: redis
169
141
  requirement: !ruby/object:Gem::Requirement
@@ -352,6 +324,40 @@ dependencies:
352
324
  - - "~>"
353
325
  - !ruby/object:Gem::Version
354
326
  version: '1.34'
327
+ - !ruby/object:Gem::Dependency
328
+ name: kramdown-ansi
329
+ requirement: !ruby/object:Gem::Requirement
330
+ requirements:
331
+ - - "~>"
332
+ - !ruby/object:Gem::Version
333
+ version: '0.0'
334
+ - - ">="
335
+ - !ruby/object:Gem::Version
336
+ version: 0.0.1
337
+ type: :runtime
338
+ prerelease: false
339
+ version_requirements: !ruby/object:Gem::Requirement
340
+ requirements:
341
+ - - "~>"
342
+ - !ruby/object:Gem::Version
343
+ version: '0.0'
344
+ - - ">="
345
+ - !ruby/object:Gem::Version
346
+ version: 0.0.1
347
+ - !ruby/object:Gem::Dependency
348
+ name: ostruct
349
+ requirement: !ruby/object:Gem::Requirement
350
+ requirements:
351
+ - - "~>"
352
+ - !ruby/object:Gem::Version
353
+ version: '0.0'
354
+ type: :runtime
355
+ prerelease: false
356
+ version_requirements: !ruby/object:Gem::Requirement
357
+ requirements:
358
+ - - "~>"
359
+ - !ruby/object:Gem::Version
360
+ version: '0.0'
355
361
  description: Library that allows interacting with the Ollama API
356
362
  email: flori@ping.de
357
363
  executables:
@@ -406,7 +412,6 @@ extra_rdoc_files:
406
412
  - lib/ollama/tool/function.rb
407
413
  - lib/ollama/tool/function/parameters.rb
408
414
  - lib/ollama/tool/function/parameters/property.rb
409
- - lib/ollama/utils/ansi_markdown.rb
410
415
  - lib/ollama/utils/cache_fetcher.rb
411
416
  - lib/ollama/utils/chooser.rb
412
417
  - lib/ollama/utils/colorize_texts.rb
@@ -414,7 +419,6 @@ extra_rdoc_files:
414
419
  - lib/ollama/utils/file_argument.rb
415
420
  - lib/ollama/utils/math.rb
416
421
  - lib/ollama/utils/tags.rb
417
- - lib/ollama/utils/width.rb
418
422
  - lib/ollama/version.rb
419
423
  files:
420
424
  - ".envrc"
@@ -473,7 +477,6 @@ files:
473
477
  - lib/ollama/tool/function.rb
474
478
  - lib/ollama/tool/function/parameters.rb
475
479
  - lib/ollama/tool/function/parameters/property.rb
476
- - lib/ollama/utils/ansi_markdown.rb
477
480
  - lib/ollama/utils/cache_fetcher.rb
478
481
  - lib/ollama/utils/chooser.rb
479
482
  - lib/ollama/utils/colorize_texts.rb
@@ -481,7 +484,6 @@ files:
481
484
  - lib/ollama/utils/file_argument.rb
482
485
  - lib/ollama/utils/math.rb
483
486
  - lib/ollama/utils/tags.rb
484
- - lib/ollama/utils/width.rb
485
487
  - lib/ollama/version.rb
486
488
  - ollama-ruby.gemspec
487
489
  - spec/assets/embeddings.json
@@ -520,13 +522,11 @@ files:
520
522
  - spec/ollama/message_spec.rb
521
523
  - spec/ollama/options_spec.rb
522
524
  - spec/ollama/tool_spec.rb
523
- - spec/ollama/utils/ansi_markdown_spec.rb
524
525
  - spec/ollama/utils/cache_fetcher_spec.rb
525
526
  - spec/ollama/utils/colorize_texts_spec.rb
526
527
  - spec/ollama/utils/fetcher_spec.rb
527
528
  - spec/ollama/utils/file_argument_spec.rb
528
529
  - spec/ollama/utils/tags_spec.rb
529
- - spec/ollama/utils/width_spec.rb
530
530
  - spec/spec_helper.rb
531
531
  - tmp/.keep
532
532
  homepage: https://github.com/flori/ollama-ruby
@@ -590,11 +590,9 @@ test_files:
590
590
  - spec/ollama/message_spec.rb
591
591
  - spec/ollama/options_spec.rb
592
592
  - spec/ollama/tool_spec.rb
593
- - spec/ollama/utils/ansi_markdown_spec.rb
594
593
  - spec/ollama/utils/cache_fetcher_spec.rb
595
594
  - spec/ollama/utils/colorize_texts_spec.rb
596
595
  - spec/ollama/utils/fetcher_spec.rb
597
596
  - spec/ollama/utils/file_argument_spec.rb
598
597
  - spec/ollama/utils/tags_spec.rb
599
- - spec/ollama/utils/width_spec.rb
600
598
  - spec/spec_helper.rb
@@ -1,217 +0,0 @@
1
- require 'kramdown'
2
- require 'kramdown-parser-gfm'
3
- require 'terminal-table'
4
-
5
- class Ollama::Utils::ANSIMarkdown < Kramdown::Converter::Base
6
- include Term::ANSIColor
7
- include Ollama::Utils::Width
8
-
9
- class ::Kramdown::Parser::Mygfm < ::Kramdown::Parser::GFM
10
- def initialize(source, options)
11
- options[:gfm_quirks] << :no_auto_typographic
12
- super
13
- @block_parsers -= %i[
14
- definition_list block_html block_math
15
- footnote_definition abbrev_definition
16
- ]
17
- @span_parsers -= %i[ footnote_marker inline_math ]
18
- end
19
- end
20
-
21
- def self.parse(source)
22
- @doc = Kramdown::Document.new(
23
- source, input: :mygfm, auto_ids: false, entity_output: :as_char
24
- ).to_ansi
25
- end
26
-
27
- def initialize(root, options)
28
- super
29
- end
30
-
31
- def convert(el, opts = {})
32
- send("convert_#{el.type}", el, opts)
33
- end
34
-
35
- def inner(el, opts, &block)
36
- result = +''
37
- options = opts.dup.merge(parent: el)
38
- el.children.each_with_index do |inner_el, index|
39
- options[:index] = index
40
- options[:result] = result
41
- begin
42
- content = send("convert_#{inner_el.type}", inner_el, options)
43
- result << (block&.(inner_el, index, content) || content)
44
- rescue NameError => e
45
- warning "Caught #{e.class} for #{inner_el.type}"
46
- end
47
- end
48
- result
49
- end
50
-
51
- def convert_root(el, opts)
52
- inner(el, opts)
53
- end
54
-
55
- def convert_blank(_el, opts)
56
- opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
57
- end
58
-
59
- def convert_text(el, _opts)
60
- el.value
61
- end
62
-
63
- def convert_header(el, opts)
64
- newline bold { underline { inner(el, opts) } }
65
- end
66
-
67
- def convert_p(el, opts)
68
- length = width(percentage: 90) - opts[:list_indent].to_i
69
- length < 0 and return ''
70
- newline wrap(inner(el, opts), length:)
71
- end
72
-
73
- def convert_strong(el, opts)
74
- bold { inner(el, opts) }
75
- end
76
-
77
- def convert_em(el, opts)
78
- italic { inner(el, opts) }
79
- end
80
-
81
- def convert_a(el, opts)
82
- url = el.attr['href']
83
- hyperlink(url) { inner(el, opts) }
84
- end
85
-
86
- def convert_codespan(el, _opts)
87
- blue { el.value }
88
- end
89
-
90
- def convert_codeblock(el, _opts)
91
- blue { el.value }
92
- end
93
-
94
- def convert_blockquote(el, opts)
95
- newline ?“ + inner(el, opts).sub(/\n+\z/, '') + ?”
96
- end
97
-
98
- def convert_hr(_el, _opts)
99
- newline ?─ * width(percentage: 100)
100
- end
101
-
102
- def convert_img(el, _opts)
103
- url = el.attr['src']
104
- alt = el.attr['alt']
105
- alt.strip.size == 0 and alt = url
106
- alt = '🖼 ' + alt
107
- hyperlink(url) { alt }
108
- end
109
-
110
- def convert_ul(el, opts)
111
- list_indent = opts[:list_indent].to_i
112
- inner(el, opts) { |_inner_el, index, content|
113
- result = '· %s' % content
114
- result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
115
- result.gsub(/^/, ' ' * list_indent)
116
- }
117
- end
118
-
119
- def convert_ol(el, opts)
120
- list_indent = opts[:list_indent].to_i
121
- inner(el, opts) { |_inner_el, index, content|
122
- result = '%u. %s' % [ index + 1, content ]
123
- result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
124
- result.gsub(/^/, ' ' * list_indent)
125
- }
126
- end
127
-
128
- def convert_li(el, opts)
129
- opts = opts.dup
130
- opts[:list_indent] = 2 + opts[:list_indent].to_i
131
- newline inner(el, opts).sub(/\n+\Z/, '')
132
- end
133
-
134
- def convert_html_element(el, opts)
135
- if el.value == 'i' || el.value == 'em'
136
- italic { inner(el, opts) }
137
- elsif el.value == 'b' || el.value == 'strong'
138
- bold { inner(el, opts) }
139
- else
140
- ''
141
- end
142
- end
143
-
144
- def convert_table(el, opts)
145
- table = Terminal::Table.new
146
- table.style = {
147
- all_separators: true,
148
- border: :unicode_round,
149
- }
150
- opts[:table] = table
151
- inner(el, opts)
152
- el.options[:alignment].each_with_index do |a, i|
153
- a == :default and next
154
- opts[:table].align_column(i, a)
155
- end
156
- newline table.to_s
157
- end
158
-
159
- def convert_thead(el, opts)
160
- rows = inner(el, opts)
161
- rows = rows.split(/\s*\|\s*/)[1..].map(&:strip)
162
- opts[:table].headings = rows
163
- ''
164
- end
165
-
166
- def convert_tbody(el, opts)
167
- res = +''
168
- res << inner(el, opts)
169
- end
170
-
171
- def convert_tfoot(el, opts)
172
- ''
173
- end
174
-
175
- def convert_tr(el, opts)
176
- return '' if el.children.empty?
177
- full_width = width(percentage: 90)
178
- cols = el.children.map { |c| convert(c, opts).strip }
179
- row_size = cols.sum(&:size)
180
- return '' if row_size.zero?
181
- opts[:table] << cols.map { |c|
182
- length = (full_width * (c.size / row_size.to_f)).floor
183
- wrap(c, length:)
184
- }
185
- ''
186
- end
187
-
188
- def convert_td(el, opts)
189
- inner(el, opts)
190
- end
191
-
192
- def convert_entity(el, _opts)
193
- el.value.char
194
- end
195
-
196
- def convert_xml_comment(*)
197
- ''
198
- end
199
-
200
- def convert_xml_pi(*)
201
- ''
202
- end
203
-
204
- def convert_br(_el, opts)
205
- ''
206
- end
207
-
208
- def convert_smart_quote(el, _opts)
209
- el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
210
- end
211
-
212
- def newline(text, count: 1)
213
- text.gsub(/\n*\z/, ?\n * count)
214
- end
215
- end
216
-
217
- Kramdown::Converter.const_set(:Ansi, Ollama::Utils::ANSIMarkdown)
@@ -1,39 +0,0 @@
1
- require 'tins/terminal'
2
-
3
- module Ollama::Utils::Width
4
- include Term::ANSIColor
5
- extend Term::ANSIColor
6
-
7
- module_function
8
-
9
- def width(percentage: 100.0)
10
- ((Float(percentage) * Tins::Terminal.columns) / 100).floor
11
- end
12
-
13
- def wrap(text, percentage: nil, length: nil)
14
- percentage.nil? ^ length.nil? or
15
- raise ArgumentError, "either pass percentage or length argument"
16
- percentage and length ||= width(percentage:)
17
- text.gsub(/(?<!\n)\n(?!\n)/, ' ').lines.map do |line|
18
- if length >= 1 && uncolor { line }.length > length
19
- line.gsub(/(.{1,#{length}})(\s+|$)/, "\\1\n").strip
20
- else
21
- line.strip
22
- end
23
- end * ?\n
24
- end
25
-
26
- def truncate(text, percentage: nil, length: nil, ellipsis: ?…)
27
- percentage.nil? ^ length.nil? or
28
- raise ArgumentError, "either pass percentage or length argument"
29
- percentage and length ||= width(percentage:)
30
- ellipsis_length = ellipsis.size
31
- if length < ellipsis_length
32
- +''
33
- elsif text.size >= length + ellipsis_length
34
- text[0, length - ellipsis_length] + ellipsis
35
- else
36
- text
37
- end
38
- end
39
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::ANSIMarkdown do
4
- let :source do
5
- File.read(Pathname.new(__dir__) + '..' + '..' + '..' + 'README.md')
6
- end
7
-
8
- it 'can parse' do
9
- File.open('tmp/README.ansi', ?w) do |output|
10
- ansi = described_class.parse(source)
11
- expect(ansi).to match("This is the end.")
12
- output.puts ansi
13
- end
14
- end
15
- end
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::Width do
4
- before do
5
- allow(Tins::Terminal).to receive(:columns).and_return 80
6
- end
7
-
8
- describe '.width' do
9
- it 'defaults to 100%' do
10
- expect(described_class.width).to eq 80
11
- end
12
-
13
- it 'can be to 80%' do
14
- expect(described_class.width(percentage: 80)).to eq 64
15
- end
16
- end
17
-
18
- describe '.wrap' do
19
- it 'can wrap with percentage' do
20
- wrapped = described_class.wrap([ ?A * 10 ] * 10 * ' ', percentage: 80)
21
- expect(wrapped).to eq(
22
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA\n"\
23
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA"
24
- )
25
- expect(wrapped.size).to eq 109
26
- end
27
-
28
- it 'can wrap with length' do
29
- wrapped = described_class.wrap([ ?A * 10 ] * 10 * ' ', length: 64)
30
- expect(wrapped).to eq(
31
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA\n"\
32
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA"
33
- )
34
- expect(wrapped.size).to eq 109
35
- end
36
-
37
- it "doesn't wrap with length 0" do
38
- wrapped = described_class.wrap([ ?A * 10 ] * 10 * ' ', length: 0)
39
- expect(wrapped).to eq(
40
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA "\
41
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA"
42
- )
43
- end
44
- end
45
-
46
- describe '.truncate' do
47
- it 'can truncate with percentage' do
48
- truncated = described_class.truncate([ ?A * 10 ] * 10 * ' ', percentage: 80)
49
- expect(truncated).to eq(
50
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAA…"
51
- )
52
- expect(truncated.size).to eq 64
53
- end
54
-
55
- it 'can truncate with length' do
56
- truncated = described_class.truncate([ ?A * 10 ] * 10 * ' ', length: 64)
57
- expect(truncated).to eq(
58
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAA…"
59
- )
60
- expect(truncated.size).to eq 64
61
- end
62
-
63
- it 'cannot truncate if not necessary' do
64
- text = [ ?A * 10 ] * 5 * ' '
65
- truncated = described_class.truncate(text, length: 54)
66
- expect(truncated).to eq text
67
- end
68
-
69
- it 'can truncate with length 0' do
70
- truncated = described_class.truncate([ ?A * 10 ] * 10 * ' ', length: 0)
71
- expect(truncated).to be_empty
72
- end
73
-
74
- it 'can truncate with ...' do
75
- truncated = described_class.truncate([ ?A * 10 ] * 10 * ' ', length: 64, ellipsis: '...')
76
- expect(truncated).to eq(
77
- "AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAA..."
78
- )
79
- expect(truncated.size).to eq 64
80
- end
81
- end
82
- end