ollama-ruby 0.4.0 → 0.5.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.
data/bin/ollama_cli CHANGED
@@ -16,6 +16,8 @@ def usage
16
16
  -M OPTIONS the ollama model options to use, OLLAMA_MODEL_OPTIONS
17
17
  -s SYSTEM the system prompt to use as a file, OLLAMA_SYSTEM
18
18
  -p PROMPT the user prompt to use as a file, OLLAMA_PROMPT
19
+ if it contains %{stdin} it is substituted by stdin input
20
+ -P VARIABLE sets prompt var %{foo} to "bar" if VARIABLE is foo=bar
19
21
  -H HANDLER the handler to use for the response, defaults to Print
20
22
  -S use streaming for generation
21
23
  -h this help
@@ -24,7 +26,7 @@ def usage
24
26
  exit 0
25
27
  end
26
28
 
27
- opts = go 'u:m:M:s:p:H:Sh', defaults: { ?H => 'Print', ?M => '{}' }
29
+ opts = go 'u:m:M:s:p:P:H:Sh', defaults: { ?H => 'Print', ?M => '{}' }
28
30
 
29
31
  opts[?h] and usage
30
32
 
@@ -38,14 +40,14 @@ prompt = get_file_argument(opts[?p], default: ENV['OLLAMA_PROMPT'])
38
40
 
39
41
  if prompt.nil?
40
42
  prompt = STDIN.read
41
- elsif c = prompt.scan('%s').size
42
- case c
43
- when 0
44
- when 1
45
- prompt = prompt % STDIN.read
46
- else
47
- STDERR.puts "Found more than one plaeceholder %s. => Ignoring."
48
- end
43
+ else
44
+ vars = prompt.scan(/%\{([^}]+)\}/).inject([], &:concat).uniq.map(&:to_sym)
45
+ stdin = (STDIN.read if vars.include?(:stdin)).to_s
46
+ values = opts[?P].to_a.inject({ stdin: }) { |h, pair|
47
+ n, v = pair.split(?=, 2)
48
+ h.merge(n.to_sym => v)
49
+ }
50
+ prompt = prompt % values
49
51
  end
50
52
 
51
53
  if ENV['DEBUG'].to_i == 1
@@ -2,16 +2,18 @@ require 'redis'
2
2
 
3
3
  class Ollama::Documents
4
4
  class RedisBackedMemoryCache < MemoryCache
5
- def initialize(prefix:, url: ENV['REDIS_URL'])
5
+ def initialize(prefix:, url: ENV['REDIS_URL'], object_class: nil)
6
6
  super(prefix:)
7
7
  url or raise ArgumentError, 'require redis url'
8
- @prefix, @url = prefix, url
9
- @redis_cache = Ollama::Documents::RedisCache.new(prefix:, url:)
8
+ @prefix, @url, @object_class = prefix, url, object_class
9
+ @redis_cache = Ollama::Documents::RedisCache.new(prefix:, url:, object_class:)
10
10
  @redis_cache.full_each do |key, value|
11
11
  @data[key] = value
12
12
  end
13
13
  end
14
14
 
15
+ attr_reader :object_class
16
+
15
17
  def redis
16
18
  @redis_cache.redis
17
19
  end
@@ -32,13 +34,5 @@ class Ollama::Documents
32
34
  super
33
35
  self
34
36
  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
37
  end
44
38
  end
@@ -4,11 +4,13 @@ require 'redis'
4
4
  class Ollama::Documents::RedisCache
5
5
  include Ollama::Documents::Cache::Common
6
6
 
7
- def initialize(prefix:, url: ENV['REDIS_URL'])
7
+ def initialize(prefix:, url: ENV['REDIS_URL'], object_class: nil, ex: nil)
8
8
  url or raise ArgumentError, 'require redis url'
9
- @prefix, @url = prefix, url
9
+ @prefix, @url, @object_class, @ex = prefix, url, object_class, ex
10
10
  end
11
11
 
12
+ attr_reader :object_class
13
+
12
14
  def redis
13
15
  @redis ||= Redis.new(url: @url)
14
16
  end
@@ -16,12 +18,16 @@ class Ollama::Documents::RedisCache
16
18
  def [](key)
17
19
  value = redis.get(pre(key))
18
20
  unless value.nil?
19
- JSON(value, object_class: Ollama::Documents::Record)
21
+ JSON(value, object_class:)
20
22
  end
21
23
  end
22
24
 
23
25
  def []=(key, value)
24
- redis.set(pre(key), JSON(value))
26
+ redis.set(pre(key), JSON.generate(value), ex: @ex)
27
+ end
28
+
29
+ def ttl(key)
30
+ redis.ttl(pre(key))
25
31
  end
26
32
 
27
33
  def key?(key)
@@ -50,7 +56,7 @@ class Ollama::Documents::RedisCache
50
56
  include Enumerable
51
57
 
52
58
  def full_each(&block)
53
- redis.scan_each do |key|
59
+ redis.scan_each(match: [ Ollama::Documents, ?* ] * ?-) do |key|
54
60
  value = redis.get(key) or next
55
61
  value = JSON(value, object_class: Ollama::Documents::Record)
56
62
  block.(key, value)
@@ -2,8 +2,9 @@ module Ollama::Documents::Splitters
2
2
  class Character
3
3
  DEFAULT_SEPARATOR = /(?:\r?\n){2,}/
4
4
 
5
- def initialize(separator: DEFAULT_SEPARATOR, include_separator: false, chunk_size: 4096)
6
- @separator, @include_separator, @chunk_size = separator, include_separator, chunk_size
5
+ def initialize(separator: DEFAULT_SEPARATOR, include_separator: false, combining_string: "\n\n", chunk_size: 4096)
6
+ @separator, @include_separator, @combining_string, @chunk_size =
7
+ separator, include_separator, combining_string, chunk_size
7
8
  if include_separator
8
9
  @separator = Regexp.new("(#@separator)")
9
10
  end
@@ -22,7 +23,7 @@ module Ollama::Documents::Splitters
22
23
  current_text = +''
23
24
  texts.each do |t|
24
25
  if current_text.size + t.size < @chunk_size
25
- current_text += t
26
+ current_text << t << @combining_string
26
27
  else
27
28
  current_text.empty? or result << current_text
28
29
  current_text = t
@@ -41,11 +42,11 @@ module Ollama::Documents::Splitters
41
42
  //,
42
43
  ].freeze
43
44
 
44
- def initialize(separators: DEFAULT_SEPARATORS, include_separator: false, chunk_size: 4096)
45
+ def initialize(separators: DEFAULT_SEPARATORS, include_separator: false, combining_string: "\n\n", chunk_size: 4096)
45
46
  separators.empty? and
46
47
  raise ArgumentError, "non-empty array of separators required"
47
- @separators, @include_separator, @chunk_size =
48
- separators, include_separator, chunk_size
48
+ @separators, @include_separator, @combining_string, @chunk_size =
49
+ separators, include_separator, combining_string, chunk_size
49
50
  end
50
51
 
51
52
  def split(text, separators: @separators)
@@ -55,6 +56,7 @@ module Ollama::Documents::Splitters
55
56
  texts = Character.new(
56
57
  separator:,
57
58
  include_separator: @include_separator,
59
+ combining_string: @combining_string,
58
60
  chunk_size: @chunk_size
59
61
  ).split(text)
60
62
  texts.count == 0 and return [ text ]
@@ -12,7 +12,7 @@ module Ollama::Documents::Splitters
12
12
  def split(text, batch_size: 100, breakpoint: :percentile, **opts)
13
13
  sentences = Ollama::Documents::Splitters::Character.new(
14
14
  separator: @separator,
15
- include_separator: true,
15
+ include_separator: opts.fetch(:include_separator, true),
16
16
  chunk_size: 1,
17
17
  ).split(text)
18
18
  embeddings = sentences.with_infobar(label: 'Split').each_slice(batch_size).inject([]) do |e, batch|
@@ -35,16 +35,19 @@ class Ollama::Documents
35
35
  alias inspect to_s
36
36
  end
37
37
 
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
40
- @cache, @redis_url = connect_cache(cache), redis_url
38
+ def initialize(ollama:, model:, model_options: nil, collection: nil, cache: MemoryCache, redis_url: nil)
39
+ collection ||= default_collection
40
+ @ollama, @model, @model_options, @collection =
41
+ ollama, model, model_options, collection.to_sym
42
+ @redis_url = redis_url
43
+ @cache = connect_cache(cache)
41
44
  end
42
45
 
43
46
  def default_collection
44
47
  :default
45
48
  end
46
49
 
47
- attr_reader :ollama, :model, :collection
50
+ attr_reader :ollama, :model, :collection, :cache
48
51
 
49
52
  def collection=(new_collection)
50
53
  @collection = new_collection.to_sym
@@ -161,7 +164,7 @@ class Ollama::Documents
161
164
  cache = nil
162
165
  if cache_class.instance_method(:redis)
163
166
  begin
164
- cache = cache_class.new(prefix:)
167
+ cache = cache_class.new(prefix:, url: @redis_url, object_class: Record)
165
168
  cache.size
166
169
  rescue Redis::CannotConnectError
167
170
  STDERR.puts(
@@ -7,32 +7,43 @@ require 'stringio'
7
7
  class Ollama::Utils::Fetcher
8
8
  module ContentType
9
9
  attr_accessor :content_type
10
+
11
+ def self.failed
12
+ object = StringIO.new.extend(self)
13
+ object.content_type = MIME::Types['text/plain'].first
14
+ object
15
+ end
10
16
  end
11
17
 
12
18
  class RetryWithoutStreaming < StandardError; end
13
19
 
14
- def initialize(debug: false)
15
- @debug = debug
16
- @started = false
17
- @streaming = true
20
+ def initialize(debug: false, http_options: {})
21
+ @debug = debug
22
+ @started = false
23
+ @streaming = true
24
+ @http_options = http_options
18
25
  end
19
26
 
20
27
  def self.get(url, **options, &block)
21
28
  new(**options).get(url, &block)
22
29
  end
23
30
 
31
+ def excon(url, **options)
32
+ Excon.new(url, options.merge(@http_options))
33
+ end
34
+
24
35
  def get(url, &block)
25
36
  response = nil
26
37
  Tempfile.open do |tmp|
27
38
  infobar.label = 'Getting'
28
39
  if @streaming
29
- response = Excon.get(url, headers:, response_block: callback(tmp))
40
+ response = excon(url, headers:, response_block: callback(tmp)).request(method: :get)
30
41
  response.status != 200 || !@started and raise RetryWithoutStreaming
31
42
  decorate_io(tmp, response)
32
43
  infobar.finish
33
44
  block.(tmp)
34
45
  else
35
- response = Excon.get(url, headers:, middlewares:)
46
+ response = excon(url, headers:, middlewares:).request(method: :get)
36
47
  if response.status != 200
37
48
  raise "invalid response status code"
38
49
  end
@@ -52,7 +63,7 @@ class Ollama::Utils::Fetcher
52
63
  if @debug && !e.is_a?(RuntimeError)
53
64
  STDERR.puts "#{e.backtrace * ?\n}"
54
65
  end
55
- yield StringIO.new.extend(ContentType)
66
+ yield ContentType.failed
56
67
  end
57
68
 
58
69
  def headers
@@ -104,4 +115,24 @@ class Ollama::Utils::Fetcher
104
115
  end
105
116
  end
106
117
  end
118
+
119
+ def self.execute(command, &block)
120
+ Tempfile.open do |tmp|
121
+ IO.popen(command) do |command|
122
+ until command.eof?
123
+ tmp.write command.read(4096)
124
+ end
125
+ tmp.rewind
126
+ tmp.extend(Ollama::Utils::Fetcher::ContentType)
127
+ tmp.content_type = MIME::Types['text/plain'].first
128
+ block.(tmp)
129
+ end
130
+ end
131
+ rescue => e
132
+ STDERR.puts "Cannot execute #{command.inspect} (#{e})"
133
+ if @debug && !e.is_a?(RuntimeError)
134
+ STDERR.puts "#{e.backtrace * ?\n}"
135
+ end
136
+ yield ContentType.failed
137
+ end
107
138
  end
@@ -23,12 +23,10 @@ module Ollama::Utils::FileArgument
23
23
  if path_or_content.present? && path_or_content.size < 2 ** 15 &&
24
24
  File.basename(path_or_content).size < 2 ** 8 &&
25
25
  File.exist?(path_or_content)
26
- then
26
+ then
27
27
  File.read(path_or_content)
28
- elsif path_or_content.present?
29
- path_or_content
30
28
  else
31
- default
29
+ path_or_content.full? || default
32
30
  end
33
31
  end
34
32
  end
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.4.0'
3
+ VERSION = '0.5.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
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require 'logger'
2
3
  require 'excon'
3
4
 
4
5
  module Ollama
data/ollama-ruby.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.4.0 ruby lib
2
+ # stub: ollama-ruby 0.5.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.4.0".freeze
6
+ s.version = "0.5.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-21"
11
+ s.date = "2024-09-26"
12
12
  s.description = "Library that allows interacting with the Ollama API".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["ollama_console".freeze, "ollama_chat".freeze, "ollama_update".freeze, "ollama_cli".freeze]
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.specification_version = 4
26
26
 
27
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.17.1".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.18.0".freeze])
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])
@@ -45,4 +45,6 @@ Gem::Specification.new do |s|
45
45
  s.add_runtime_dependency(%q<search_ui>.freeze, ["~> 0.0".freeze])
46
46
  s.add_runtime_dependency(%q<amatch>.freeze, ["~> 0.4.1".freeze])
47
47
  s.add_runtime_dependency(%q<pdf-reader>.freeze, ["~> 2.0".freeze])
48
+ s.add_runtime_dependency(%q<logger>.freeze, ["~> 1.0".freeze])
49
+ s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
48
50
  end
@@ -35,6 +35,17 @@ RSpec.describe Ollama::Documents::RedisBackedMemoryCache do
35
35
  expect(cache).to be_a described_class
36
36
  end
37
37
 
38
+ it 'defaults to nil object_class' do
39
+ cache = described_class.new prefix: 'test-', url: 'something'
40
+ expect(cache.object_class).to be_nil
41
+ end
42
+
43
+ it 'can be configured with object_class' do
44
+ object_class = Class.new(JSON::GenericObject)
45
+ cache = described_class.new(prefix: 'test-', url: 'something', object_class:)
46
+ expect(cache.object_class).to eq object_class
47
+ end
48
+
38
49
  it 'has Redis client' do
39
50
  expect(cache.redis).to eq redis
40
51
  end
@@ -6,6 +6,17 @@ RSpec.describe Ollama::Documents::RedisCache do
6
6
  expect(cache).to be_a described_class
7
7
  end
8
8
 
9
+ it 'defaults to nil object_class' do
10
+ cache = described_class.new prefix: 'test-', url: 'something'
11
+ expect(cache.object_class).to be_nil
12
+ end
13
+
14
+ it 'can be configured with object_class' do
15
+ object_class = Class.new(JSON::GenericObject)
16
+ cache = described_class.new(prefix: 'test-', url: 'something', object_class:)
17
+ expect(cache.object_class).to eq object_class
18
+ end
19
+
9
20
  it 'raises ArgumentError if url is missing' do
10
21
  expect {
11
22
  described_class.new prefix: 'test-', url: nil
@@ -37,8 +48,17 @@ RSpec.describe Ollama::Documents::RedisCache do
37
48
 
38
49
  it 'can set a value for a key' do
39
50
  key, value = 'foo', { test: true }
40
- expect(redis).to receive(:set).with('test-' + key, JSON(value))
51
+ expect(redis).to receive(:set).with('test-' + key, JSON(value), ex: nil)
52
+ cache[key] = value
53
+ end
54
+
55
+ it 'can set a value for a key with ttl' do
56
+ cache = described_class.new prefix: 'test-', url: 'something', ex: 3_600
57
+ key, value = 'foo', { test: true }
58
+ expect(redis).to receive(:set).with('test-' + key, JSON(value), ex: 3_600)
41
59
  cache[key] = value
60
+ allow(redis).to receive(:ttl).with('test-' + key).and_return 3_600
61
+ expect(cache.ttl(key)).to eq 3_600
42
62
  end
43
63
 
44
64
  it 'can determine if key exists' do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe Ollama::Documents::Splitters::Character do
4
4
  let :splitter do
5
- described_class.new chunk_size: 23
5
+ described_class.new chunk_size: 23, combining_string: ''
6
6
  end
7
7
 
8
8
  it 'can be instantiated' do
@@ -10,29 +10,41 @@ RSpec.describe Ollama::Documents::Splitters::Character do
10
10
  end
11
11
 
12
12
  it 'can split' do
13
- text = [ "A" * 10 ] * 10 * "\n\n"
13
+ text = [ ?A * 10 ] * 10 * "\n\n"
14
14
  result = splitter.split(text)
15
15
  expect(result.count).to eq 5
16
16
  expect(result.to_a.join('')).to eq ?A * 100
17
17
  end
18
18
 
19
+ it 'can split combining with separation' do
20
+ splitter = described_class.new chunk_size: 25, include_separator: false,
21
+ combining_string: ?X
22
+ text = [ ?A * 10 ] * 10 * "\n\n"
23
+ result = splitter.split(text)
24
+ expect(result.count).to eq 5
25
+ expect(result.to_a.join(?B)).to eq\
26
+ "AAAAAAAAAAXAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAXB"\
27
+ "AAAAAAAAAAAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAX"
28
+ end
29
+
19
30
  it 'can split including separator' do
20
- splitter = described_class.new chunk_size: 25, include_separator: true
21
- text = [ "A" * 10 ] * 10 * "\n\n"
31
+ splitter = described_class.new chunk_size: 25, include_separator: true,
32
+ combining_string: ''
33
+ text = [ ?A * 10 ] * 10 * "\n\n"
22
34
  result = splitter.split(text)
23
35
  expect(result.count).to eq 5
24
36
  expect(result.to_a.join('')).to eq text
25
37
  end
26
38
 
27
39
  it 'cannot split' do
28
- text = [ "A" * 10 ] * 10 * "\n"
40
+ text = [ ?A * 10 ] * 10 * "\n"
29
41
  result = splitter.split(text)
30
42
  expect(result.count).to eq 1
31
43
  expect(result.to_a.join('').count(?A)).to eq text.count(?A)
32
44
  end
33
45
 
34
46
  it 'cannot split2' do
35
- text = "A" * 25
47
+ text = ?A * 25
36
48
  result = splitter.split(text)
37
49
  expect(result.count).to eq 1
38
50
  expect(result.to_a.join('')).to eq ?A * 25
@@ -48,7 +60,7 @@ end
48
60
 
49
61
  RSpec.describe Ollama::Documents::Splitters::RecursiveCharacter do
50
62
  let :splitter do
51
- described_class.new chunk_size: 23
63
+ described_class.new chunk_size: 23, combining_string: ''
52
64
  end
53
65
 
54
66
  it 'can be instantiated' do
@@ -56,7 +68,7 @@ RSpec.describe Ollama::Documents::Splitters::RecursiveCharacter do
56
68
  end
57
69
 
58
70
  it 'can split' do
59
- text = [ "A" * 10 ] * 10 * "\n\n"
71
+ text = [ ?A * 10 ] * 10 * "\n\n"
60
72
  result = splitter.split(text)
61
73
  expect(result.count).to eq 5
62
74
  expect(result.to_a.join('')).to eq ?A * 100
@@ -65,30 +77,32 @@ RSpec.describe Ollama::Documents::Splitters::RecursiveCharacter do
65
77
  it 'cannot split' do
66
78
  splitter = described_class.new chunk_size: 23, include_separator: true,
67
79
  separators: described_class::DEFAULT_SEPARATORS[0..-2]
68
- text = "A" * 25
80
+ text = ?A * 25
69
81
  result = splitter.split(text)
70
82
  expect(result.count).to eq 1
71
83
  expect(result.to_a.join('')).to eq ?A * 25
72
84
  end
73
85
 
74
86
  it 'can split including separator' do
75
- splitter = described_class.new chunk_size: 25, include_separator: true
76
- text = [ "A" * 10 ] * 10 * "\n\n"
87
+ splitter = described_class.new chunk_size: 25, include_separator: true,
88
+ combining_string: ''
89
+ text = [ ?A * 10 ] * 10 * "\n\n"
77
90
  result = splitter.split(text)
78
91
  expect(result.count).to eq 5
79
92
  expect(result.to_a.join('')).to eq text
80
93
  end
81
94
 
82
95
  it 'can split single newline as well' do
83
- text = [ "A" * 10 ] * 10 * "\n"
96
+ text = [ ?A * 10 ] * 10 * "\n"
84
97
  result = splitter.split(text)
85
98
  expect(result.count).to eq 5
86
99
  expect(result.to_a.join('')).to eq ?A * 100
87
100
  end
88
101
 
89
102
  it 'can split single newline as well including separator' do
90
- splitter = described_class.new chunk_size: 25, include_separator: true
91
- text = [ "A" * 10 ] * 10 * "\n"
103
+ splitter = described_class.new chunk_size: 25, include_separator: true,
104
+ combining_string: ''
105
+ text = [ ?A * 10 ] * 10 * "\n"
92
106
  result = splitter.split(text)
93
107
  expect(result.count).to eq 5
94
108
  expect(result.to_a.join('')).to eq text
@@ -33,6 +33,28 @@ RSpec.describe Ollama::Utils::Fetcher do
33
33
  end
34
34
  end
35
35
 
36
+ it 'can #get without ssl peer verification' do
37
+ fetcher = described_class.new(
38
+ http_options: { ssl_verify_peer: false }
39
+ )
40
+ stub_request(:get, 'https://www.example.com/hello').
41
+ with(headers: fetcher.headers).
42
+ to_return(
43
+ status: 200,
44
+ body: 'world',
45
+ headers: { 'Content-Type' => 'text/plain' },
46
+ )
47
+ expect(Excon).to receive(:new).with(
48
+ 'https://www.example.com/hello',
49
+ hash_including(ssl_verify_peer: false)
50
+ ).and_call_original
51
+ fetcher.get(url) do |tmp|
52
+ expect(tmp).to be_a Tempfile
53
+ expect(tmp.read).to eq 'world'
54
+ expect(tmp.content_type).to eq 'text/plain'
55
+ end
56
+ end
57
+
36
58
  it 'can #get and fallback from streaming' do
37
59
  stub_request(:get, 'https://www.example.com/hello').
38
60
  with(headers: fetcher.headers).
@@ -58,6 +80,7 @@ RSpec.describe Ollama::Utils::Fetcher do
58
80
  fetcher.get(url) do |tmp|
59
81
  expect(tmp).to be_a StringIO
60
82
  expect(tmp.read).to eq ''
83
+ expect(tmp.content_type).to eq 'text/plain'
61
84
  end
62
85
  end
63
86
 
@@ -72,4 +95,21 @@ RSpec.describe Ollama::Utils::Fetcher do
72
95
  expect(file.content_type).to eq 'application/x-ruby'
73
96
  end
74
97
  end
98
+
99
+ it 'can .execute' do
100
+ described_class.execute('echo -n hello world') do |file|
101
+ expect(file).to be_a Tempfile
102
+ expect(file.read).to eq 'hello world'
103
+ expect(file.content_type).to eq 'text/plain'
104
+ end
105
+ end
106
+
107
+ it 'can .execute and fail' do
108
+ allow(IO).to receive(:popen).and_raise StandardError
109
+ described_class.execute('foobar') do |file|
110
+ expect(file).to be_a StringIO
111
+ expect(file.read).to be_empty
112
+ expect(file.content_type).to eq 'text/plain'
113
+ end
114
+ end
75
115
  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.4.0
4
+ version: 0.5.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-21 00:00:00.000000000 Z
11
+ date: 2024-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.17.1
19
+ version: 1.18.0
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.17.1
26
+ version: 1.18.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: all_images
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -304,6 +304,34 @@ dependencies:
304
304
  - - "~>"
305
305
  - !ruby/object:Gem::Version
306
306
  version: '2.0'
307
+ - !ruby/object:Gem::Dependency
308
+ name: logger
309
+ requirement: !ruby/object:Gem::Requirement
310
+ requirements:
311
+ - - "~>"
312
+ - !ruby/object:Gem::Version
313
+ version: '1.0'
314
+ type: :runtime
315
+ prerelease: false
316
+ version_requirements: !ruby/object:Gem::Requirement
317
+ requirements:
318
+ - - "~>"
319
+ - !ruby/object:Gem::Version
320
+ version: '1.0'
321
+ - !ruby/object:Gem::Dependency
322
+ name: json
323
+ requirement: !ruby/object:Gem::Requirement
324
+ requirements:
325
+ - - "~>"
326
+ - !ruby/object:Gem::Version
327
+ version: '2.0'
328
+ type: :runtime
329
+ prerelease: false
330
+ version_requirements: !ruby/object:Gem::Requirement
331
+ requirements:
332
+ - - "~>"
333
+ - !ruby/object:Gem::Version
334
+ version: '2.0'
307
335
  description: Library that allows interacting with the Ollama API
308
336
  email: flori@ping.de
309
337
  executables: