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 +4 -4
- data/CHANGES.md +19 -0
- data/Rakefile +3 -4
- data/bin/ollama_chat +8 -6
- data/lib/ollama/handlers/say.rb +42 -3
- data/lib/ollama/version.rb +1 -1
- data/ollama-ruby.gemspec +6 -7
- data/spec/ollama/handlers/say_spec.rb +73 -10
- data/spec/ollama/utils/fetcher_spec.rb +24 -24
- metadata +24 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6611c14b779a919b256552774080305825b4e81cd5e43ae0303026aaaed7c13e
|
4
|
+
data.tar.gz: a34e71ef5b07cdd8a0cdf5dce9de7f7e9c3faca1829e4837c54ea243458b8f05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
118
|
-
@say
|
119
|
-
@messages
|
120
|
-
@user
|
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
|
-
|
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)
|
data/lib/ollama/handlers/say.rb
CHANGED
@@ -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
|
-
|
6
|
+
def initialize(output: nil, voice: 'Samantha', interactive: nil)
|
7
|
+
@voice = voice
|
8
|
+
@interactive = interactive
|
8
9
|
super(output:)
|
9
|
-
|
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
|
data/lib/ollama/version.rb
CHANGED
data/ollama-ruby.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: ollama-ruby 0.
|
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.
|
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-
|
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
|
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
|
10
|
-
|
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
|
-
|
62
|
+
say = described_class.new(output:)
|
14
63
|
response = double('response', response: 'testing', done: false)
|
15
|
-
|
64
|
+
say.call(response)
|
16
65
|
response = double('response', response: nil, message: nil, done: true)
|
17
|
-
|
66
|
+
say.call(response)
|
18
67
|
end
|
19
68
|
|
20
|
-
it 'can
|
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
|
-
|
73
|
+
say = described_class.new(output:)
|
25
74
|
response = double('response', response: nil, message: double(content: 'testing'), done: false)
|
26
|
-
|
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
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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.
|
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-
|
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
|
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
|
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
|
- - "~>"
|