ollama-ruby 0.0.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 +7 -0
- data/Gemfile +5 -0
- data/LICENSE +19 -0
- data/README.md +430 -0
- data/Rakefile +35 -0
- data/bin/ollama_chat +258 -0
- data/bin/ollama_console +20 -0
- data/lib/ollama/client/command.rb +25 -0
- data/lib/ollama/client/doc.rb +26 -0
- data/lib/ollama/client.rb +137 -0
- data/lib/ollama/commands/chat.rb +21 -0
- data/lib/ollama/commands/copy.rb +19 -0
- data/lib/ollama/commands/create.rb +20 -0
- data/lib/ollama/commands/delete.rb +19 -0
- data/lib/ollama/commands/embed.rb +21 -0
- data/lib/ollama/commands/embeddings.rb +20 -0
- data/lib/ollama/commands/generate.rb +21 -0
- data/lib/ollama/commands/ps.rb +19 -0
- data/lib/ollama/commands/pull.rb +19 -0
- data/lib/ollama/commands/push.rb +19 -0
- data/lib/ollama/commands/show.rb +20 -0
- data/lib/ollama/commands/tags.rb +19 -0
- data/lib/ollama/dto.rb +42 -0
- data/lib/ollama/errors.rb +15 -0
- data/lib/ollama/handlers/collector.rb +17 -0
- data/lib/ollama/handlers/concern.rb +31 -0
- data/lib/ollama/handlers/dump_json.rb +8 -0
- data/lib/ollama/handlers/dump_yaml.rb +8 -0
- data/lib/ollama/handlers/markdown.rb +22 -0
- data/lib/ollama/handlers/nop.rb +7 -0
- data/lib/ollama/handlers/print.rb +16 -0
- data/lib/ollama/handlers/progress.rb +36 -0
- data/lib/ollama/handlers/say.rb +19 -0
- data/lib/ollama/handlers/single.rb +17 -0
- data/lib/ollama/handlers.rb +13 -0
- data/lib/ollama/image.rb +31 -0
- data/lib/ollama/message.rb +9 -0
- data/lib/ollama/options.rb +68 -0
- data/lib/ollama/response.rb +5 -0
- data/lib/ollama/tool/function/parameters/property.rb +9 -0
- data/lib/ollama/tool/function/parameters.rb +10 -0
- data/lib/ollama/tool/function.rb +11 -0
- data/lib/ollama/tool.rb +9 -0
- data/lib/ollama/utils/ansi_markdown.rb +217 -0
- data/lib/ollama/utils/width.rb +22 -0
- data/lib/ollama/version.rb +8 -0
- data/lib/ollama.rb +43 -0
- data/ollama-ruby.gemspec +36 -0
- data/spec/assets/kitten.jpg +0 -0
- data/spec/ollama/client/doc_spec.rb +11 -0
- data/spec/ollama/client_spec.rb +144 -0
- data/spec/ollama/commands/chat_spec.rb +52 -0
- data/spec/ollama/commands/copy_spec.rb +28 -0
- data/spec/ollama/commands/create_spec.rb +37 -0
- data/spec/ollama/commands/delete_spec.rb +28 -0
- data/spec/ollama/commands/embed_spec.rb +52 -0
- data/spec/ollama/commands/embeddings_spec.rb +38 -0
- data/spec/ollama/commands/generate_spec.rb +29 -0
- data/spec/ollama/commands/ps_spec.rb +25 -0
- data/spec/ollama/commands/pull_spec.rb +28 -0
- data/spec/ollama/commands/push_spec.rb +28 -0
- data/spec/ollama/commands/show_spec.rb +28 -0
- data/spec/ollama/commands/tags_spec.rb +22 -0
- data/spec/ollama/handlers/collector_spec.rb +15 -0
- data/spec/ollama/handlers/dump_json_spec.rb +16 -0
- data/spec/ollama/handlers/dump_yaml_spec.rb +18 -0
- data/spec/ollama/handlers/markdown_spec.rb +46 -0
- data/spec/ollama/handlers/nop_spec.rb +15 -0
- data/spec/ollama/handlers/print_spec.rb +30 -0
- data/spec/ollama/handlers/progress_spec.rb +22 -0
- data/spec/ollama/handlers/say_spec.rb +30 -0
- data/spec/ollama/handlers/single_spec.rb +24 -0
- data/spec/ollama/image_spec.rb +23 -0
- data/spec/ollama/message_spec.rb +37 -0
- data/spec/ollama/options_spec.rb +25 -0
- data/spec/ollama/tool_spec.rb +78 -0
- data/spec/ollama/utils/ansi_markdown_spec.rb +15 -0
- data/spec/spec_helper.rb +16 -0
- metadata +321 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
class Ollama::Commands::Show
|
2
|
+
include Ollama::DTO
|
3
|
+
|
4
|
+
def self.path
|
5
|
+
'/api/show'
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(name:, verbose: nil)
|
9
|
+
@name, @verbose = name, verbose
|
10
|
+
@stream = false
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :name, :verbose, :stream
|
14
|
+
|
15
|
+
attr_writer :client
|
16
|
+
|
17
|
+
def perform(handler)
|
18
|
+
@client.request(method: :post, path: self.class.path, body: to_json, stream:, handler:)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Ollama::Commands::Tags
|
2
|
+
def self.path
|
3
|
+
'/api/tags'
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize(**parameters)
|
7
|
+
parameters.empty? or raise ArgumentError,
|
8
|
+
"Invalid parameters: #{parameters.keys * ' '}"
|
9
|
+
@stream = false
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :stream
|
13
|
+
|
14
|
+
attr_writer :client
|
15
|
+
|
16
|
+
def perform(handler)
|
17
|
+
@client.request(method: :get, path: self.class.path, stream:, handler:)
|
18
|
+
end
|
19
|
+
end
|
data/lib/ollama/dto.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ollama::DTO
|
2
|
+
extend Tins::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
self.attributes = Set.new
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
attr_accessor :attributes
|
10
|
+
|
11
|
+
def json_create(object)
|
12
|
+
new(**object.transform_keys(&:to_sym))
|
13
|
+
end
|
14
|
+
|
15
|
+
def attr_reader(*names)
|
16
|
+
super
|
17
|
+
attributes.merge(names.map(&:to_sym))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def as_array_of_hashes(obj)
|
22
|
+
if obj.respond_to?(:to_hash)
|
23
|
+
[ obj.to_hash ]
|
24
|
+
elsif obj.respond_to?(:to_ary)
|
25
|
+
obj.to_ary.map(&:to_hash)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def as_json(*)
|
30
|
+
{
|
31
|
+
json_class: self.class.name
|
32
|
+
}.merge(
|
33
|
+
self.class.attributes.each_with_object({}) { |a, h| h[a] = send(a) }
|
34
|
+
).reject { _2.nil? || _2.ask_and_send(:size) == 0 }
|
35
|
+
end
|
36
|
+
|
37
|
+
alias to_hash as_json
|
38
|
+
|
39
|
+
def to_json(*)
|
40
|
+
as_json.to_json(*)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'tins/concern'
|
2
|
+
require 'tins/implement'
|
3
|
+
|
4
|
+
module Ollama::Handlers::Concern
|
5
|
+
extend Tins::Concern
|
6
|
+
extend Tins::Implement
|
7
|
+
|
8
|
+
def initialize(output: $stdout)
|
9
|
+
@output = output
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :output
|
13
|
+
|
14
|
+
attr_reader :result
|
15
|
+
|
16
|
+
implement :call
|
17
|
+
|
18
|
+
def to_proc
|
19
|
+
-> response { call(response) }
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def call(response)
|
24
|
+
new.call(response)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_proc
|
28
|
+
new.to_proc
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
class Ollama::Handlers::Markdown
|
4
|
+
include Ollama::Handlers::Concern
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
def initialize(output: $stdout)
|
8
|
+
super
|
9
|
+
@output.sync = true
|
10
|
+
@content = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(response)
|
14
|
+
if content = response.response || response.message&.content
|
15
|
+
@content << content
|
16
|
+
markdown_content = Ollama::Utils::ANSIMarkdown.parse(@content)
|
17
|
+
@output.print clear_screen, move_home, markdown_content
|
18
|
+
end
|
19
|
+
response.done and @output.puts
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Ollama::Handlers::Print
|
2
|
+
include Ollama::Handlers::Concern
|
3
|
+
|
4
|
+
def initialize(output: $stdout)
|
5
|
+
super
|
6
|
+
@output.sync = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(response)
|
10
|
+
if content = response.response || response.message&.content
|
11
|
+
@output.print content
|
12
|
+
end
|
13
|
+
response.done and @output.puts
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'infobar'
|
2
|
+
|
3
|
+
class Ollama::Handlers::Progress
|
4
|
+
include Ollama::Handlers::Concern
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
def initialize(output: $stdout)
|
8
|
+
super
|
9
|
+
@current = 0
|
10
|
+
@total = nil
|
11
|
+
@last_status = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(response)
|
15
|
+
infobar.display.output = @output
|
16
|
+
status = response.status
|
17
|
+
if response.total && response.completed
|
18
|
+
if !@last_status or @last_status != status
|
19
|
+
@last_status and infobar.newline
|
20
|
+
@last_status = status
|
21
|
+
@current = 0
|
22
|
+
@total = response.total
|
23
|
+
infobar.counter.reset(total: @total, current: @current)
|
24
|
+
end
|
25
|
+
infobar.counter.progress(by: response.completed - @current)
|
26
|
+
@current = response.completed
|
27
|
+
end
|
28
|
+
if status
|
29
|
+
infobar.label = status
|
30
|
+
infobar.update(message: '%l %c/%t in %te, ETA %e @%E', force: true)
|
31
|
+
elsif error = response.error
|
32
|
+
infobar.puts bold { "Error: " } + red { error }
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
class Ollama::Handlers::Say
|
4
|
+
include Ollama::Handlers::Concern
|
5
|
+
|
6
|
+
def initialize(output: nil, voice: 'Samantha')
|
7
|
+
output ||= IO.popen(Shellwords.join([ 'say', '-v', voice ]), 'w')
|
8
|
+
super(output:)
|
9
|
+
@output.sync = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(response)
|
13
|
+
if content = response.response || response.message&.content
|
14
|
+
@output.print content
|
15
|
+
end
|
16
|
+
response.done and @output.close
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Ollama::Handlers::Single
|
2
|
+
include Ollama::Handlers::Concern
|
3
|
+
|
4
|
+
def initialize(output: $stdout)
|
5
|
+
super
|
6
|
+
@array = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(response)
|
10
|
+
@array << response
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def result
|
15
|
+
@array.size <= 1 ? @array.first : @array
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Ollama::Handlers
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'ollama/handlers/concern'
|
5
|
+
require 'ollama/handlers/collector'
|
6
|
+
require 'ollama/handlers/nop'
|
7
|
+
require 'ollama/handlers/single'
|
8
|
+
require 'ollama/handlers/markdown'
|
9
|
+
require 'ollama/handlers/progress'
|
10
|
+
require 'ollama/handlers/print'
|
11
|
+
require 'ollama/handlers/dump_json'
|
12
|
+
require 'ollama/handlers/dump_yaml'
|
13
|
+
require 'ollama/handlers/say'
|
data/lib/ollama/image.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
class Ollama::Image
|
4
|
+
def initialize(data)
|
5
|
+
@data = data
|
6
|
+
end
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def for_base64(data)
|
10
|
+
new(data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def for_string(string)
|
14
|
+
for_base64(Base64.encode64(string))
|
15
|
+
end
|
16
|
+
|
17
|
+
def for_io(io)
|
18
|
+
for_string(io.read)
|
19
|
+
end
|
20
|
+
|
21
|
+
def for_filename(path)
|
22
|
+
File.open(path, 'rb') { |io| for_io(io) }
|
23
|
+
end
|
24
|
+
|
25
|
+
private :new
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@data
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Options are explained in the parameters for the modelfile:
|
2
|
+
# https://github.com/ollama/ollama/blob/main/docs/modelfile.md#parameter
|
3
|
+
class Ollama::Options
|
4
|
+
include Ollama::DTO
|
5
|
+
|
6
|
+
@@types = {
|
7
|
+
numa: [ false, true ],
|
8
|
+
num_ctx: Integer,
|
9
|
+
num_batch: Integer,
|
10
|
+
num_gpu: Integer,
|
11
|
+
main_gpu: Integer,
|
12
|
+
low_vram: [ false, true ],
|
13
|
+
f16_kv: [ false, true ],
|
14
|
+
logits_all: [ false, true ],
|
15
|
+
vocab_only: [ false, true ],
|
16
|
+
use_mmap: [ false, true ],
|
17
|
+
use_mlock: [ false, true ],
|
18
|
+
num_thread: Integer,
|
19
|
+
num_keep: Integer,
|
20
|
+
seed: Integer,
|
21
|
+
num_predict: Integer,
|
22
|
+
top_k: Integer,
|
23
|
+
top_p: Float,
|
24
|
+
min_p: Float,
|
25
|
+
tfs_z: Float,
|
26
|
+
typical_p: Float,
|
27
|
+
repeat_last_n: Integer,
|
28
|
+
temperature: Float,
|
29
|
+
repeat_penalty: Float,
|
30
|
+
presence_penalty: Float,
|
31
|
+
frequency_penalty: Float,
|
32
|
+
mirostat: Integer,
|
33
|
+
mirostat_tau: Float,
|
34
|
+
mirostat_eta: Float,
|
35
|
+
penalize_newline: [ false, true ],
|
36
|
+
stop: Array,
|
37
|
+
}
|
38
|
+
|
39
|
+
@@types.each do |name, type|
|
40
|
+
attr_reader name
|
41
|
+
|
42
|
+
define_method("#{name}=") do |value|
|
43
|
+
instance_variable_set(
|
44
|
+
"@#{name}",
|
45
|
+
if value.nil?
|
46
|
+
nil
|
47
|
+
else
|
48
|
+
case type
|
49
|
+
when Class
|
50
|
+
send(type.name, value)
|
51
|
+
when Array
|
52
|
+
if type.include?(value)
|
53
|
+
value
|
54
|
+
else
|
55
|
+
raise TypeError, "#{value} not in #{type * ?|}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class_eval %{
|
64
|
+
def initialize(#{@@types.keys.map { "#{_1}: nil" }.join(', ') + ', **'})
|
65
|
+
#{@@types.keys.map { "self.#{_1} = #{_1}" }.join(?\n)}
|
66
|
+
end
|
67
|
+
}
|
68
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Ollama::Tool::Function::Parameters
|
2
|
+
include Ollama::DTO
|
3
|
+
|
4
|
+
attr_reader :type, :properties, :required
|
5
|
+
|
6
|
+
def initialize(type:, properties:, required:)
|
7
|
+
@type, @properties, @required =
|
8
|
+
type, Hash(properties).transform_values(&:to_hash), Array(required)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Ollama::Tool::Function
|
2
|
+
include Ollama::DTO
|
3
|
+
|
4
|
+
attr_reader :name, :description, :parameters, :required
|
5
|
+
|
6
|
+
def initialize(name:, description:, parameters: nil, required: nil)
|
7
|
+
@name, @description, @parameters, @required =
|
8
|
+
name, description, (Hash(parameters) if parameters),
|
9
|
+
(Array(required) if required)
|
10
|
+
end
|
11
|
+
end
|
data/lib/ollama/tool.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
require 'kramdown-parser-gfm'
|
3
|
+
require 'terminal-table'
|
4
|
+
|
5
|
+
class Ollama::Utils::ANSIMarkdown < Kramdown::Converter::Base
|
6
|
+
include Term::ANSIColor
|
7
|
+
include Ollama::Utils::Width
|
8
|
+
|
9
|
+
class ::Kramdown::Parser::Mygfm < ::Kramdown::Parser::GFM
|
10
|
+
def initialize(source, options)
|
11
|
+
options[:gfm_quirks] << :no_auto_typographic
|
12
|
+
super
|
13
|
+
@block_parsers -= %i[
|
14
|
+
definition_list block_html block_math
|
15
|
+
footnote_definition abbrev_definition
|
16
|
+
]
|
17
|
+
@span_parsers -= %i[ footnote_marker inline_math ]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse(source)
|
22
|
+
@doc = Kramdown::Document.new(
|
23
|
+
source, input: :mygfm, auto_ids: false, entity_output: :as_char
|
24
|
+
).to_ansi
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(root, options)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def convert(el, opts = {})
|
32
|
+
send("convert_#{el.type}", el, opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def inner(el, opts, &block)
|
36
|
+
result = +''
|
37
|
+
options = opts.dup.merge(parent: el)
|
38
|
+
el.children.each_with_index do |inner_el, index|
|
39
|
+
options[:index] = index
|
40
|
+
options[:result] = result
|
41
|
+
begin
|
42
|
+
content = send("convert_#{inner_el.type}", inner_el, options)
|
43
|
+
result << (block&.(inner_el, index, content) || content)
|
44
|
+
rescue NameError => e
|
45
|
+
warning "Caught #{e.class} for #{inner_el.type}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
def convert_root(el, opts)
|
52
|
+
inner(el, opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def convert_blank(_el, opts)
|
56
|
+
opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert_text(el, _opts)
|
60
|
+
el.value
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert_header(el, opts)
|
64
|
+
newline bold { underline { inner(el, opts) } }
|
65
|
+
end
|
66
|
+
|
67
|
+
def convert_p(el, opts)
|
68
|
+
length = width(percentage: 90) - opts[:list_indent].to_i
|
69
|
+
length < 0 and return ''
|
70
|
+
newline wrap(inner(el, opts), length:)
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_strong(el, opts)
|
74
|
+
bold { inner(el, opts) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def convert_em(el, opts)
|
78
|
+
italic { inner(el, opts) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def convert_a(el, opts)
|
82
|
+
url = el.attr['href']
|
83
|
+
hyperlink(url) { inner(el, opts) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def convert_codespan(el, _opts)
|
87
|
+
blue { el.value }
|
88
|
+
end
|
89
|
+
|
90
|
+
def convert_codeblock(el, _opts)
|
91
|
+
blue { el.value }
|
92
|
+
end
|
93
|
+
|
94
|
+
def convert_blockquote(el, opts)
|
95
|
+
newline ?“ + inner(el, opts).sub(/\n+\z/, '') + ?”
|
96
|
+
end
|
97
|
+
|
98
|
+
def convert_hr(_el, _opts)
|
99
|
+
newline ?─ * width(percentage: 100)
|
100
|
+
end
|
101
|
+
|
102
|
+
def convert_img(el, _opts)
|
103
|
+
url = el.attr['src']
|
104
|
+
alt = el.attr['alt']
|
105
|
+
alt.strip.size == 0 and alt = url
|
106
|
+
alt = '🖼 ' + alt
|
107
|
+
hyperlink(url) { alt }
|
108
|
+
end
|
109
|
+
|
110
|
+
def convert_ul(el, opts)
|
111
|
+
list_indent = opts[:list_indent].to_i
|
112
|
+
inner(el, opts) { |_inner_el, index, content|
|
113
|
+
result = '· %s' % content
|
114
|
+
result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
|
115
|
+
result.gsub(/^/, ' ' * list_indent)
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def convert_ol(el, opts)
|
120
|
+
list_indent = opts[:list_indent].to_i
|
121
|
+
inner(el, opts) { |_inner_el, index, content|
|
122
|
+
result = '%u. %s' % [ index + 1, content ]
|
123
|
+
result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
|
124
|
+
result.gsub(/^/, ' ' * list_indent)
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def convert_li(el, opts)
|
129
|
+
opts = opts.dup
|
130
|
+
opts[:list_indent] = 2 + opts[:list_indent].to_i
|
131
|
+
newline inner(el, opts).sub(/\n+\Z/, '')
|
132
|
+
end
|
133
|
+
|
134
|
+
def convert_html_element(el, opts)
|
135
|
+
if el.value == 'i' || el.value == 'em'
|
136
|
+
italic { inner(el, opts) }
|
137
|
+
elsif el.value == 'b' || el.value == 'strong'
|
138
|
+
bold { inner(el, opts) }
|
139
|
+
else
|
140
|
+
''
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def convert_table(el, opts)
|
145
|
+
table = Terminal::Table.new
|
146
|
+
table.style = {
|
147
|
+
all_separators: true,
|
148
|
+
border: :unicode_round,
|
149
|
+
}
|
150
|
+
opts[:table] = table
|
151
|
+
inner(el, opts)
|
152
|
+
el.options[:alignment].each_with_index do |a, i|
|
153
|
+
a == :default and next
|
154
|
+
opts[:table].align_column(i, a)
|
155
|
+
end
|
156
|
+
newline table.to_s
|
157
|
+
end
|
158
|
+
|
159
|
+
def convert_thead(el, opts)
|
160
|
+
rows = inner(el, opts)
|
161
|
+
rows = rows.split(/\s*\|\s*/)[1..].map(&:strip)
|
162
|
+
opts[:table].headings = rows
|
163
|
+
''
|
164
|
+
end
|
165
|
+
|
166
|
+
def convert_tbody(el, opts)
|
167
|
+
res = +''
|
168
|
+
res << inner(el, opts)
|
169
|
+
end
|
170
|
+
|
171
|
+
def convert_tfoot(el, opts)
|
172
|
+
''
|
173
|
+
end
|
174
|
+
|
175
|
+
def convert_tr(el, opts)
|
176
|
+
return '' if el.children.empty?
|
177
|
+
full_width = width(percentage: 90)
|
178
|
+
cols = el.children.map { |c| convert(c, opts).strip }
|
179
|
+
row_size = cols.sum(&:size)
|
180
|
+
return '' if row_size.zero?
|
181
|
+
opts[:table] << cols.map { |c|
|
182
|
+
length = (full_width * (c.size / row_size.to_f)).floor
|
183
|
+
wrap(c, length:)
|
184
|
+
}
|
185
|
+
''
|
186
|
+
end
|
187
|
+
|
188
|
+
def convert_td(el, opts)
|
189
|
+
inner(el, opts)
|
190
|
+
end
|
191
|
+
|
192
|
+
def convert_entity(el, _opts)
|
193
|
+
el.value.char
|
194
|
+
end
|
195
|
+
|
196
|
+
def convert_xml_comment(*)
|
197
|
+
''
|
198
|
+
end
|
199
|
+
|
200
|
+
def convert_xml_pi(*)
|
201
|
+
''
|
202
|
+
end
|
203
|
+
|
204
|
+
def convert_br(_el, opts)
|
205
|
+
''
|
206
|
+
end
|
207
|
+
|
208
|
+
def convert_smart_quote(el, _opts)
|
209
|
+
el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
|
210
|
+
end
|
211
|
+
|
212
|
+
def newline(text, count: 1)
|
213
|
+
text.gsub(/\n*\z/, ?\n * count)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
Kramdown::Converter.const_set(:Ansi, Ollama::Utils::ANSIMarkdown)
|