ollama-ruby 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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
  - - "~>"