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 +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
|
- - "~>"
|