ollama-ruby 0.12.1 → 0.14.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/.yardopts +1 -0
- data/CHANGES.md +39 -0
- data/README.md +70 -144
- data/Rakefile +5 -17
- data/bin/ollama_cli +37 -6
- data/lib/ollama/client/command.rb +2 -2
- data/lib/ollama/dto.rb +4 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama.rb +0 -11
- data/ollama-ruby.gemspec +11 -22
- data/spec/ollama/message_spec.rb +9 -0
- metadata +25 -255
- data/bin/ollama_chat +0 -1248
- data/config/redis.conf +0 -5
- data/docker-compose.yml +0 -10
- data/lib/ollama/documents/cache/common.rb +0 -36
- data/lib/ollama/documents/cache/memory_cache.rb +0 -44
- data/lib/ollama/documents/cache/records.rb +0 -87
- data/lib/ollama/documents/cache/redis_backed_memory_cache.rb +0 -39
- data/lib/ollama/documents/cache/redis_cache.rb +0 -68
- data/lib/ollama/documents/cache/sqlite_cache.rb +0 -215
- data/lib/ollama/documents/splitters/character.rb +0 -72
- data/lib/ollama/documents/splitters/semantic.rb +0 -91
- data/lib/ollama/documents.rb +0 -184
- data/lib/ollama/utils/cache_fetcher.rb +0 -38
- data/lib/ollama/utils/chooser.rb +0 -52
- data/lib/ollama/utils/colorize_texts.rb +0 -65
- data/lib/ollama/utils/fetcher.rb +0 -175
- data/lib/ollama/utils/file_argument.rb +0 -34
- data/lib/ollama/utils/math.rb +0 -48
- data/lib/ollama/utils/tags.rb +0 -67
- data/spec/assets/embeddings.json +0 -1
- data/spec/assets/prompt.txt +0 -1
- data/spec/ollama/documents/cache/memory_cache_spec.rb +0 -97
- data/spec/ollama/documents/cache/redis_backed_memory_cache_spec.rb +0 -118
- data/spec/ollama/documents/cache/redis_cache_spec.rb +0 -121
- data/spec/ollama/documents/cache/sqlite_cache_spec.rb +0 -141
- data/spec/ollama/documents/splitters/character_spec.rb +0 -110
- data/spec/ollama/documents/splitters/semantic_spec.rb +0 -56
- data/spec/ollama/documents_spec.rb +0 -162
- data/spec/ollama/utils/cache_fetcher_spec.rb +0 -43
- data/spec/ollama/utils/colorize_texts_spec.rb +0 -13
- data/spec/ollama/utils/fetcher_spec.rb +0 -137
- data/spec/ollama/utils/file_argument_spec.rb +0 -17
- data/spec/ollama/utils/tags_spec.rb +0 -53
data/lib/ollama/documents.rb
DELETED
@@ -1,184 +0,0 @@
|
|
1
|
-
require 'numo/narray'
|
2
|
-
require 'digest'
|
3
|
-
require 'kramdown/ansi'
|
4
|
-
|
5
|
-
class Ollama::Documents
|
6
|
-
end
|
7
|
-
module Ollama::Documents::Cache
|
8
|
-
end
|
9
|
-
require 'ollama/documents/cache/records'
|
10
|
-
require 'ollama/documents/cache/memory_cache'
|
11
|
-
require 'ollama/documents/cache/redis_cache'
|
12
|
-
require 'ollama/documents/cache/redis_backed_memory_cache'
|
13
|
-
require 'ollama/documents/cache/sqlite_cache'
|
14
|
-
module Ollama::Documents::Splitters
|
15
|
-
end
|
16
|
-
require 'ollama/documents/splitters/character'
|
17
|
-
require 'ollama/documents/splitters/semantic'
|
18
|
-
|
19
|
-
class Ollama::Documents
|
20
|
-
include Kramdown::ANSI::Width
|
21
|
-
include Ollama::Documents::Cache
|
22
|
-
|
23
|
-
Record = Class.new Ollama::Documents::Cache::Records::Record
|
24
|
-
|
25
|
-
def initialize(ollama:, model:, model_options: nil, collection: nil, embedding_length: 1_024, cache: MemoryCache, database_filename: nil, redis_url: nil, debug: false)
|
26
|
-
collection ||= default_collection
|
27
|
-
@ollama, @model, @model_options, @collection, @debug =
|
28
|
-
ollama, model, model_options, collection.to_sym, debug
|
29
|
-
database_filename ||= ':memory:'
|
30
|
-
@cache = connect_cache(cache, redis_url, embedding_length, database_filename)
|
31
|
-
end
|
32
|
-
|
33
|
-
def default_collection
|
34
|
-
:default
|
35
|
-
end
|
36
|
-
|
37
|
-
attr_reader :ollama, :model, :collection, :cache
|
38
|
-
|
39
|
-
def collection=(new_collection)
|
40
|
-
@collection = new_collection.to_sym
|
41
|
-
@cache.prefix = prefix
|
42
|
-
end
|
43
|
-
|
44
|
-
def add(inputs, batch_size: nil, source: nil, tags: [])
|
45
|
-
inputs = Array(inputs)
|
46
|
-
batch_size ||= 10
|
47
|
-
tags = Ollama::Utils::Tags.new(tags, source:)
|
48
|
-
if source
|
49
|
-
tags.add(File.basename(source).gsub(/\?.*/, ''), source:)
|
50
|
-
end
|
51
|
-
inputs.map! { |i|
|
52
|
-
text = i.respond_to?(:read) ? i.read : i.to_s
|
53
|
-
text
|
54
|
-
}
|
55
|
-
inputs.reject! { |i| exist?(i) }
|
56
|
-
inputs.empty? and return self
|
57
|
-
if @debug
|
58
|
-
puts Ollama::Utils::ColorizeTexts.new(inputs)
|
59
|
-
end
|
60
|
-
batches = inputs.each_slice(batch_size).
|
61
|
-
with_infobar(
|
62
|
-
label: "Add #{truncate(tags.to_s(link: false), percentage: 25)}",
|
63
|
-
total: inputs.size
|
64
|
-
)
|
65
|
-
batches.each do |batch|
|
66
|
-
embeddings = fetch_embeddings(model:, options: @model_options, input: batch)
|
67
|
-
batch.zip(embeddings) do |text, embedding|
|
68
|
-
norm = @cache.norm(embedding)
|
69
|
-
self[text] = Record[text:, embedding:, norm:, source:, tags: tags.to_a]
|
70
|
-
end
|
71
|
-
infobar.progress by: batch.size
|
72
|
-
end
|
73
|
-
infobar.newline
|
74
|
-
self
|
75
|
-
end
|
76
|
-
alias << add
|
77
|
-
|
78
|
-
def [](text)
|
79
|
-
@cache[key(text)]
|
80
|
-
end
|
81
|
-
|
82
|
-
def []=(text, record)
|
83
|
-
@cache[key(text)] = record
|
84
|
-
end
|
85
|
-
|
86
|
-
def exist?(text)
|
87
|
-
@cache.key?(key(text))
|
88
|
-
end
|
89
|
-
|
90
|
-
def delete(text)
|
91
|
-
@cache.delete(key(text))
|
92
|
-
end
|
93
|
-
|
94
|
-
def size
|
95
|
-
@cache.size
|
96
|
-
end
|
97
|
-
|
98
|
-
def clear(tags: nil)
|
99
|
-
@cache.clear(tags:)
|
100
|
-
self
|
101
|
-
end
|
102
|
-
|
103
|
-
def find(string, tags: nil, prompt: nil, max_records: nil)
|
104
|
-
needle = convert_to_vector(string, prompt:)
|
105
|
-
@cache.find_records(needle, tags:, max_records: nil)
|
106
|
-
end
|
107
|
-
|
108
|
-
def find_where(string, text_size: nil, text_count: nil, **opts)
|
109
|
-
if text_count
|
110
|
-
opts[:max_records] = text_count
|
111
|
-
end
|
112
|
-
records = find(string, **opts)
|
113
|
-
size, count = 0, 0
|
114
|
-
records.take_while do |record|
|
115
|
-
if text_size and (size += record.text.size) > text_size
|
116
|
-
next false
|
117
|
-
end
|
118
|
-
if text_count and (count += 1) > text_count
|
119
|
-
next false
|
120
|
-
end
|
121
|
-
true
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def collections
|
126
|
-
([ default_collection ] + @cache.collections('%s-' % self.class)).uniq
|
127
|
-
end
|
128
|
-
|
129
|
-
def tags
|
130
|
-
@cache.tags
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
def connect_cache(cache_class, redis_url, embedding_length, database_filename)
|
136
|
-
cache = nil
|
137
|
-
if (cache_class.instance_method(:redis) rescue nil)
|
138
|
-
begin
|
139
|
-
cache = cache_class.new(prefix:, url: redis_url, object_class: Record)
|
140
|
-
cache.size
|
141
|
-
rescue Redis::CannotConnectError
|
142
|
-
STDERR.puts(
|
143
|
-
"Cannot connect to redis URL #{redis_url.inspect}, "\
|
144
|
-
"falling back to MemoryCache."
|
145
|
-
)
|
146
|
-
end
|
147
|
-
elsif cache_class == SQLiteCache
|
148
|
-
cache = cache_class.new(
|
149
|
-
prefix:,
|
150
|
-
embedding_length:,
|
151
|
-
filename: database_filename,
|
152
|
-
debug: @debug
|
153
|
-
)
|
154
|
-
end
|
155
|
-
ensure
|
156
|
-
cache ||= MemoryCache.new(prefix:,)
|
157
|
-
cache.respond_to?(:find_records) or cache.extend(Records::FindRecords)
|
158
|
-
cache.extend(Records::Tags)
|
159
|
-
if cache.respond_to?(:redis)
|
160
|
-
cache.extend(Records::RedisFullEach)
|
161
|
-
end
|
162
|
-
return cache
|
163
|
-
end
|
164
|
-
|
165
|
-
def convert_to_vector(input, prompt: nil)
|
166
|
-
if prompt
|
167
|
-
input = prompt % input
|
168
|
-
end
|
169
|
-
input.is_a?(String) and input = fetch_embeddings(model:, input:).first
|
170
|
-
@cache.convert_to_vector(input)
|
171
|
-
end
|
172
|
-
|
173
|
-
def fetch_embeddings(model:, input:, options: nil)
|
174
|
-
@ollama.embed(model:, input:, options:).embeddings
|
175
|
-
end
|
176
|
-
|
177
|
-
def prefix
|
178
|
-
'%s-%s-' % [ self.class, @collection ]
|
179
|
-
end
|
180
|
-
|
181
|
-
def key(input)
|
182
|
-
Digest::SHA256.hexdigest(input)
|
183
|
-
end
|
184
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
|
3
|
-
class Ollama::Utils::CacheFetcher
|
4
|
-
def initialize(cache)
|
5
|
-
@cache = cache
|
6
|
-
end
|
7
|
-
|
8
|
-
def get(url, &block)
|
9
|
-
block or raise ArgumentError, 'require block argument'
|
10
|
-
body = @cache[key(:body, url)]
|
11
|
-
content_type = @cache[key(:content_type, url)]
|
12
|
-
content_type = MIME::Types[content_type].first
|
13
|
-
if body && content_type
|
14
|
-
io = StringIO.new(body)
|
15
|
-
io.rewind
|
16
|
-
io.extend(Ollama::Utils::Fetcher::HeaderExtension)
|
17
|
-
io.content_type = content_type
|
18
|
-
block.(io)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def put(url, io)
|
23
|
-
io.rewind
|
24
|
-
body = io.read
|
25
|
-
body.empty? and return
|
26
|
-
content_type = io.content_type
|
27
|
-
content_type.nil? and return
|
28
|
-
@cache.set(key(:body, url), body, ex: io.ex)
|
29
|
-
@cache.set(key(:content_type, url), content_type.to_s, ex: io.ex)
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def key(type, url)
|
36
|
-
[ type, Digest::MD5.hexdigest(url) ] * ?-
|
37
|
-
end
|
38
|
-
end
|
data/lib/ollama/utils/chooser.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'amatch'
|
2
|
-
require 'search_ui'
|
3
|
-
require 'term/ansicolor'
|
4
|
-
|
5
|
-
module Ollama::Utils::Chooser
|
6
|
-
include SearchUI
|
7
|
-
include Term::ANSIColor
|
8
|
-
|
9
|
-
module_function
|
10
|
-
|
11
|
-
# The choose method presents a list of entries and prompts the user
|
12
|
-
# for input, allowing them to select one entry based on their input.
|
13
|
-
#
|
14
|
-
# @param entries [Array] the list of entries to present to the user
|
15
|
-
# @param prompt [String] the prompt message to display when asking for input (default: 'Search? %s')
|
16
|
-
# @param return_immediately [Boolean] whether to immediately return the first entry if there is only one or nil when there is none (default: false)
|
17
|
-
#
|
18
|
-
# @return [Object] the selected entry, or nil if no entry was chosen
|
19
|
-
#
|
20
|
-
# @example
|
21
|
-
# choose(['entry1', 'entry2'], prompt: 'Choose an option:')
|
22
|
-
def choose(entries, prompt: 'Search? %s', return_immediately: false)
|
23
|
-
if return_immediately && entries.size <= 1
|
24
|
-
return entries.first
|
25
|
-
end
|
26
|
-
entry = Search.new(
|
27
|
-
prompt:,
|
28
|
-
match: -> answer {
|
29
|
-
matcher = Amatch::PairDistance.new(answer.downcase)
|
30
|
-
matches = entries.map { |n| [ n, -matcher.similar(n.to_s.downcase) ] }.
|
31
|
-
select { |_, s| s < 0 }.sort_by(&:last).map(&:first)
|
32
|
-
matches.empty? and matches = entries
|
33
|
-
matches.first(Tins::Terminal.lines - 1)
|
34
|
-
},
|
35
|
-
query: -> _answer, matches, selector {
|
36
|
-
matches.each_with_index.map { |m, i|
|
37
|
-
i == selector ? "#{blue{?⮕}} #{on_blue{m}}" : " #{m.to_s}"
|
38
|
-
} * ?\n
|
39
|
-
},
|
40
|
-
found: -> _answer, matches, selector {
|
41
|
-
matches[selector]
|
42
|
-
},
|
43
|
-
output: STDOUT
|
44
|
-
).start
|
45
|
-
if entry
|
46
|
-
entry
|
47
|
-
else
|
48
|
-
print clear_screen, move_home
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'term/ansicolor'
|
2
|
-
require 'kramdown/ansi'
|
3
|
-
|
4
|
-
class Ollama::Utils::ColorizeTexts
|
5
|
-
include Math
|
6
|
-
include Term::ANSIColor
|
7
|
-
include Kramdown::ANSI::Width
|
8
|
-
|
9
|
-
# Initializes a new instance of Ollama::Utils::ColorizeTexts
|
10
|
-
#
|
11
|
-
# @param [Array<String>] texts the array of strings to be displayed with colors
|
12
|
-
#
|
13
|
-
# @return [Ollama::Utils::ColorizeTexts] an instance of Ollama::Utils::ColorizeTexts
|
14
|
-
def initialize(*texts)
|
15
|
-
texts = texts.map(&:to_a)
|
16
|
-
@texts = Array(texts.flatten)
|
17
|
-
end
|
18
|
-
|
19
|
-
# Returns a string representation of the object, including all texts content,
|
20
|
-
# colored differently and their sizes.
|
21
|
-
#
|
22
|
-
# @return [String] The formatted string.
|
23
|
-
def to_s
|
24
|
-
result = +''
|
25
|
-
@texts.each_with_index do |t, i|
|
26
|
-
color = colors[(t.hash ^ i.hash) % colors.size]
|
27
|
-
wrap(t, percentage: 90).each_line { |l|
|
28
|
-
result << on_color(color) { color(text_color(color)) { l } }
|
29
|
-
}
|
30
|
-
result << "\n##{bold{t.size.to_s}} \n\n"
|
31
|
-
end
|
32
|
-
result
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
# Returns the nearest RGB color to the given ANSI color
|
38
|
-
#
|
39
|
-
# @param [color] color The ANSI color attribute
|
40
|
-
#
|
41
|
-
# @return [Array<RGBTriple>] An array containing two RGB colors, one for black and
|
42
|
-
# one for white text, where the first is the closest match to the input color
|
43
|
-
# when printed on a black background, and the second is the closest match
|
44
|
-
# when printed on a white background.
|
45
|
-
def text_color(color)
|
46
|
-
color = Term::ANSIColor::Attribute[color]
|
47
|
-
[
|
48
|
-
Attribute.nearest_rgb_color('#000'),
|
49
|
-
Attribute.nearest_rgb_color('#fff'),
|
50
|
-
].max_by { |t| t.distance_to(color) }
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns an array of colors for each step in the gradient
|
54
|
-
#
|
55
|
-
# @return [Array<Array<Integer>>] An array of RGB color arrays
|
56
|
-
def colors
|
57
|
-
@colors ||= (0..255).map { |i|
|
58
|
-
[
|
59
|
-
128 + 128 * sin(PI * i / 32.0),
|
60
|
-
128 + 128 * sin(PI * i / 64.0),
|
61
|
-
128 + 128 * sin(PI * i / 128.0),
|
62
|
-
].map { _1.clamp(0, 255).round }
|
63
|
-
}
|
64
|
-
end
|
65
|
-
end
|
data/lib/ollama/utils/fetcher.rb
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
require 'tins/unit'
|
3
|
-
require 'infobar'
|
4
|
-
require 'mime-types'
|
5
|
-
require 'stringio'
|
6
|
-
require 'ollama/utils/cache_fetcher'
|
7
|
-
|
8
|
-
class Ollama::Utils::Fetcher
|
9
|
-
module HeaderExtension
|
10
|
-
attr_accessor :content_type
|
11
|
-
|
12
|
-
attr_accessor :ex
|
13
|
-
|
14
|
-
def self.failed
|
15
|
-
object = StringIO.new.extend(self)
|
16
|
-
object.content_type = MIME::Types['text/plain'].first
|
17
|
-
object
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class RetryWithoutStreaming < StandardError; end
|
22
|
-
|
23
|
-
def self.get(url, **options, &block)
|
24
|
-
cache = options.delete(:cache) and
|
25
|
-
cache = Ollama::Utils::CacheFetcher.new(cache)
|
26
|
-
if result = cache&.get(url, &block)
|
27
|
-
infobar.puts "Getting #{url.to_s.inspect} from cache."
|
28
|
-
return result
|
29
|
-
else
|
30
|
-
new(**options).send(:get, url) do |tmp|
|
31
|
-
result = block.(tmp)
|
32
|
-
if cache && !tmp.is_a?(StringIO)
|
33
|
-
tmp.rewind
|
34
|
-
cache.put(url, tmp)
|
35
|
-
end
|
36
|
-
result
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.normalize_url(url)
|
42
|
-
url = url.to_s
|
43
|
-
url = URI.decode_uri_component(url)
|
44
|
-
url = url.sub(/#.*/, '')
|
45
|
-
URI::Parser.new.escape(url).to_s
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.read(filename, &block)
|
49
|
-
if File.exist?(filename)
|
50
|
-
File.open(filename) do |file|
|
51
|
-
file.extend(Ollama::Utils::Fetcher::HeaderExtension)
|
52
|
-
file.content_type = MIME::Types.type_for(filename).first
|
53
|
-
block.(file)
|
54
|
-
end
|
55
|
-
else
|
56
|
-
STDERR.puts "File #{filename.to_s.inspect} doesn't exist."
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.execute(command, &block)
|
61
|
-
Tempfile.open do |tmp|
|
62
|
-
IO.popen(command) do |command|
|
63
|
-
until command.eof?
|
64
|
-
tmp.write command.read(1 << 14)
|
65
|
-
end
|
66
|
-
tmp.rewind
|
67
|
-
tmp.extend(Ollama::Utils::Fetcher::HeaderExtension)
|
68
|
-
tmp.content_type = MIME::Types['text/plain'].first
|
69
|
-
block.(tmp)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
rescue => e
|
73
|
-
STDERR.puts "Cannot execute #{command.inspect} (#{e})"
|
74
|
-
if @debug && !e.is_a?(RuntimeError)
|
75
|
-
STDERR.puts "#{e.backtrace * ?\n}"
|
76
|
-
end
|
77
|
-
yield HeaderExtension.failed
|
78
|
-
end
|
79
|
-
|
80
|
-
def initialize(debug: false, http_options: {})
|
81
|
-
@debug = debug
|
82
|
-
@started = false
|
83
|
-
@streaming = true
|
84
|
-
@http_options = http_options
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
def excon(url, **options)
|
90
|
-
url = self.class.normalize_url(url)
|
91
|
-
Excon.new(url, options.merge(@http_options))
|
92
|
-
end
|
93
|
-
|
94
|
-
def get(url, &block)
|
95
|
-
response = nil
|
96
|
-
Tempfile.open do |tmp|
|
97
|
-
infobar.label = 'Getting'
|
98
|
-
if @streaming
|
99
|
-
response = excon(url, headers:, response_block: callback(tmp)).request(method: :get)
|
100
|
-
response.status != 200 || !@started and raise RetryWithoutStreaming
|
101
|
-
decorate_io(tmp, response)
|
102
|
-
infobar.finish
|
103
|
-
block.(tmp)
|
104
|
-
else
|
105
|
-
response = excon(url, headers:, middlewares:).request(method: :get)
|
106
|
-
if response.status != 200
|
107
|
-
raise "invalid response status code"
|
108
|
-
end
|
109
|
-
body = response.body
|
110
|
-
tmp.print body
|
111
|
-
infobar.update(message: message(body.size, body.size), force: true)
|
112
|
-
decorate_io(tmp, response)
|
113
|
-
infobar.finish
|
114
|
-
block.(tmp)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
rescue RetryWithoutStreaming
|
118
|
-
@streaming = false
|
119
|
-
retry
|
120
|
-
rescue => e
|
121
|
-
STDERR.puts "Cannot get #{url.to_s.inspect} (#{e}): #{response&.status_line || 'n/a'}"
|
122
|
-
if @debug && !e.is_a?(RuntimeError)
|
123
|
-
STDERR.puts "#{e.backtrace * ?\n}"
|
124
|
-
end
|
125
|
-
yield HeaderExtension.failed
|
126
|
-
end
|
127
|
-
|
128
|
-
def headers
|
129
|
-
{
|
130
|
-
'User-Agent' => Ollama::Client.user_agent,
|
131
|
-
}
|
132
|
-
end
|
133
|
-
|
134
|
-
def middlewares
|
135
|
-
(Excon.defaults[:middlewares] + [ Excon::Middleware::RedirectFollower ]).uniq
|
136
|
-
end
|
137
|
-
|
138
|
-
private
|
139
|
-
|
140
|
-
def decorate_io(tmp, response)
|
141
|
-
tmp.rewind
|
142
|
-
tmp.extend(HeaderExtension)
|
143
|
-
if content_type = MIME::Types[response.headers['content-type']].first
|
144
|
-
tmp.content_type = content_type
|
145
|
-
end
|
146
|
-
if cache_control = response.headers['cache-control'] and
|
147
|
-
cache_control !~ /no-store|no-cache/ and
|
148
|
-
ex = cache_control[/s-maxage\s*=\s*(\d+)/, 1] || cache_control[/max-age\s*=\s*(\d+)/, 1]
|
149
|
-
then
|
150
|
-
tmp.ex = ex.to_i
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def callback(tmp)
|
155
|
-
-> chunk, remaining_bytes, total_bytes do
|
156
|
-
total = total_bytes or next
|
157
|
-
current = total_bytes - remaining_bytes
|
158
|
-
if @started
|
159
|
-
infobar.counter.progress(by: total - current)
|
160
|
-
else
|
161
|
-
@started = true
|
162
|
-
infobar.counter.reset(total:, current:)
|
163
|
-
end
|
164
|
-
infobar.update(message: message(current, total), force: true)
|
165
|
-
tmp.print(chunk)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def message(current, total)
|
170
|
-
progress = '%s/%s' % [ current, total ].map {
|
171
|
-
Tins::Unit.format(_1, format: '%.2f %U')
|
172
|
-
}
|
173
|
-
'%l ' + progress + ' in %te, ETA %e @%E'
|
174
|
-
end
|
175
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Ollama::Utils::FileArgument
|
2
|
-
module_function
|
3
|
-
|
4
|
-
# Returns the contents of a file or string, or a default value if neither is provided.
|
5
|
-
#
|
6
|
-
# @param [String] path_or_content The path to a file or a string containing
|
7
|
-
# the content.
|
8
|
-
#
|
9
|
-
# @param [String] default The default value to return if no valid input is
|
10
|
-
# given. Defaults to nil.
|
11
|
-
#
|
12
|
-
# @return [String] The contents of the file, the string, or the default value.
|
13
|
-
#
|
14
|
-
# @example Get the contents of a file
|
15
|
-
# get_file_argument('path/to/file')
|
16
|
-
#
|
17
|
-
# @example Use a string as content
|
18
|
-
# get_file_argument('string content')
|
19
|
-
#
|
20
|
-
# @example Return a default value if no valid input is given
|
21
|
-
# get_file_argument(nil, default: 'default content')
|
22
|
-
def get_file_argument(path_or_content, default: nil)
|
23
|
-
if path_or_content.present? && path_or_content.size < 2 ** 15 &&
|
24
|
-
File.basename(path_or_content).size < 2 ** 8 &&
|
25
|
-
File.exist?(path_or_content)
|
26
|
-
then
|
27
|
-
File.read(path_or_content)
|
28
|
-
elsif path_or_content.present?
|
29
|
-
path_or_content
|
30
|
-
else
|
31
|
-
default
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/ollama/utils/math.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
module Ollama::Utils::Math
|
2
|
-
# Returns the cosine similarity between two vectors +a+ and +b+, 1.0 is
|
3
|
-
# exactly the same, 0.0 means decorrelated.
|
4
|
-
#
|
5
|
-
# @param [Vector] a The first vector
|
6
|
-
# @param [Vector] b The second vector
|
7
|
-
# @option a_norm [Float] a The Euclidean norm of vector a (default: calculated from a)
|
8
|
-
# @option b_norm [Float] b The Euclidean norm of vector b (default: calculated from b)
|
9
|
-
#
|
10
|
-
# @return [Float] The cosine similarity between the two vectors
|
11
|
-
#
|
12
|
-
# @example Calculate the cosine similarity between two vectors
|
13
|
-
# cosine_similarity(a: [1, 2], b: [3, 4])
|
14
|
-
#
|
15
|
-
# @see #convert_to_vector
|
16
|
-
# @see #norm
|
17
|
-
def cosine_similarity(a:, b:, a_norm: norm(a), b_norm: norm(b))
|
18
|
-
a, b = convert_to_vector(a), convert_to_vector(b)
|
19
|
-
a.dot(b) / (a_norm * b_norm)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns the Euclidean norm (magnitude) of a vector.
|
23
|
-
#
|
24
|
-
# @param vector [Array] The input vector.
|
25
|
-
#
|
26
|
-
# @return [Float] The magnitude of the vector.
|
27
|
-
#
|
28
|
-
# @example
|
29
|
-
# norm([3, 4]) # => 5.0
|
30
|
-
def norm(vector)
|
31
|
-
s = 0.0
|
32
|
-
vector.each { s += _1.abs2 }
|
33
|
-
Math.sqrt(s)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Converts an array to a Numo NArray.
|
37
|
-
#
|
38
|
-
# @param [Array] vector The input array to be converted.
|
39
|
-
#
|
40
|
-
# @return [Numo::NArray] The converted NArray, or the original if it's already a Numo NArray.
|
41
|
-
#
|
42
|
-
# @example Convert an array to a Numo NArray
|
43
|
-
# convert_to_vector([1, 2, 3]) # => Numo::NArray[1, 2, 3]
|
44
|
-
def convert_to_vector(vector)
|
45
|
-
vector.is_a?(Numo::NArray) and return vector
|
46
|
-
Numo::NArray[*vector]
|
47
|
-
end
|
48
|
-
end
|
data/lib/ollama/utils/tags.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
class Ollama::Utils::Tags
|
2
|
-
class Tag < String
|
3
|
-
include Term::ANSIColor
|
4
|
-
|
5
|
-
def initialize(tag, source: nil)
|
6
|
-
super(tag.to_s.gsub(/\A#+/, ''))
|
7
|
-
self.source = source
|
8
|
-
end
|
9
|
-
|
10
|
-
attr_accessor :source
|
11
|
-
|
12
|
-
alias_method :internal, :to_s
|
13
|
-
|
14
|
-
def to_s(link: true)
|
15
|
-
tag_string = start_with?(?#) ? super() : ?# + super()
|
16
|
-
my_source = source
|
17
|
-
if link && my_source
|
18
|
-
unless my_source =~ %r(\A(https?|file)://)
|
19
|
-
my_source = 'file://%s' % File.expand_path(my_source)
|
20
|
-
end
|
21
|
-
hyperlink(my_source) { tag_string }
|
22
|
-
else
|
23
|
-
tag_string
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize(tags = [], source: nil)
|
29
|
-
tags = Array(tags)
|
30
|
-
@set = []
|
31
|
-
tags.each { |tag| add(tag, source:) }
|
32
|
-
end
|
33
|
-
|
34
|
-
def add(tag, source: nil)
|
35
|
-
unless tag.is_a?(Tag)
|
36
|
-
tag = Tag.new(tag, source:)
|
37
|
-
end
|
38
|
-
index = @set.bsearch_index { _1 >= tag }
|
39
|
-
if index == nil
|
40
|
-
@set.push(tag)
|
41
|
-
elsif @set.at(index) != tag
|
42
|
-
@set.insert(index, tag)
|
43
|
-
end
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
def empty?
|
48
|
-
@set.empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
def size
|
52
|
-
@set.size
|
53
|
-
end
|
54
|
-
|
55
|
-
def clear
|
56
|
-
@set.clear
|
57
|
-
end
|
58
|
-
|
59
|
-
def each(&block)
|
60
|
-
@set.each(&block)
|
61
|
-
end
|
62
|
-
include Enumerable
|
63
|
-
|
64
|
-
def to_s(link: true)
|
65
|
-
@set.map { |tag| tag.to_s(link:) } * ' '
|
66
|
-
end
|
67
|
-
end
|