ollama-ruby 0.10.0 → 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: 17d71b1a18444b7e2d80e3e0da1e56c38140eaa47ac671aef4968f3cc2cb8c56
4
- data.tar.gz: f395c4750e3a440739423906fb722ae2f7c1feedd31f417f4dc1e6677a5d86ba
3
+ metadata.gz: 6611c14b779a919b256552774080305825b4e81cd5e43ae0303026aaaed7c13e
4
+ data.tar.gz: a34e71ef5b07cdd8a0cdf5dce9de7f7e9c3faca1829e4837c54ea243458b8f05
5
5
  SHA512:
6
- metadata.gz: ff1b123a36389fcc17dcaf45e8fc655fad7a8d143825621645606178346d09becba16ba5586031bf983d5c951cebbdb03a0720a41c2d3211fe47d4d9c8b244c2
7
- data.tar.gz: 33700ca555ce9328d753544ba964a6482416bf62bac22fb358a2eb1cb214a7c85d6df9fa9b54b2e22cc673f45da8df03821f2c41b2d8361e4313626197c3fea5
6
+ metadata.gz: aa38db4bdd42ebffe2ef9b5abf7f644e38821acc4fb9650b7e8646a9fab3350640224c4ba59e13d7f182becd2a84ac881fd0c5d136ca88782e1a7febec31c2fe
7
+ data.tar.gz: b14f2626d9f2c8e6e8bc6c3b3d8947d78b4400cf0dd8888cf9f818261ba3605fc9971c2c9015f976ec48f2004cb4b0ff5d922e2efe001b5b443f03728f14ce51
data/CHANGES.md CHANGED
@@ -1,5 +1,24 @@
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
+
3
22
  ## 2024-10-31 v0.10.0
4
23
 
5
24
  * Improved URL and tag parsing in `parse_content`:
data/Rakefile CHANGED
@@ -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,7 +40,8 @@ GemHadar do
42
40
  dependency 'json', '~> 2.0'
43
41
  dependency 'xdg', '~> 7.0'
44
42
  dependency 'tins', '~> 1.34'
45
- dependency 'kramdown-ansi', '~> 0.0'
43
+ dependency 'kramdown-ansi', '~> 0.0', '>= 0.0.1'
44
+ dependency 'ostruct', '~> 0.0'
46
45
  development_dependency 'all_images', '~> 0.4'
47
46
  development_dependency 'rspec', '~> 3.2'
48
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)
@@ -540,7 +540,7 @@ end
540
540
  def import_source(source_io, source)
541
541
  source = source.to_s
542
542
  puts "Importing #{italic { source_io&.content_type }} document #{source.to_s.inspect} now."
543
- source_content = parse_source(source_io)
543
+ source_content = parse_source(source_io)
544
544
  "Imported #{source.inspect}:\n#{source_content}\n\n"
545
545
  end
546
546
 
@@ -657,6 +657,8 @@ def parse_content(content, images)
657
657
  add_image(images, source_io, source)
658
658
  when 'text', 'application', nil
659
659
  case $document_policy
660
+ when 'ignoring'
661
+ nil
660
662
  when 'importing'
661
663
  contents << import_source(source_io, source)
662
664
  when 'embedding'
@@ -711,7 +713,7 @@ ensure
711
713
  end
712
714
 
713
715
  def choose_document_policy
714
- policies = %w[ importing embedding summarizing ].sort
716
+ policies = %w[ importing embedding summarizing ignoring ].sort
715
717
  current = if policies.index($document_policy)
716
718
  $document_policy
717
719
  elsif policies.index($config.document_policy)
@@ -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,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.10.0'
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/ollama-ruby.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 0.10.0 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.10.0".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-31"
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]
@@ -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,5 +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])
51
- s.add_runtime_dependency(%q<kramdown-ansi>.freeze, ["~> 0.0".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])
52
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.10.0
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-31 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
@@ -354,6 +326,26 @@ dependencies:
354
326
  version: '1.34'
355
327
  - !ruby/object:Gem::Dependency
356
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
357
349
  requirement: !ruby/object:Gem::Requirement
358
350
  requirements:
359
351
  - - "~>"