ollama-ruby 0.3.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 510c31683b2251118a7c3b469620400016b29fd1ea6f17cc86e4f99f62ecea2f
4
- data.tar.gz: a00c4275e42002a01a99f874a855386c83e502551360c1f4146eee0b74f2fd08
3
+ metadata.gz: c0e3428486bf4d60d1e4a64574a9c04bb41da5a5fe76b5f4bc37c5f089221cf3
4
+ data.tar.gz: 0a2f6f5269c97b22493400448204116aebef642273c024aee474a38741dfdce5
5
5
  SHA512:
6
- metadata.gz: 17e50d40e4c24b56b5c2923f0b73f3e4294587b61a302fbaf4cd8f891e879eb435541e1f7e195a4f88352fd99aa80ff44c8577b8c195d7ef31af1c33229018b7
7
- data.tar.gz: a18bcef82e9481b75fee4a4c88598a7a374c48f841e9870b39174c0d1f5f235f1173bdbff939182481d431e4e9c8c85501be4f5ef917ca02865692cfc39fde5a
6
+ metadata.gz: 3fd8db76a1cad30ba41af287e1abb77a102913f09f1648c9fbaf89f5e3bf4f3dace4a39cc6b72da456b633eb42d331b356134aecc196b112c7f94215177b4023
7
+ data.tar.gz: 4541a1e93c2714b786cb21b5e401ffc48a08e05c39bfac860e8cdd275a447bbc7db0b6cf80fee5f459f86734320a90362418a50f4174d53ece4e1a9d2f1dc647
data/CHANGES.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # Changes
2
2
 
3
+ ## 2024-09-12 v0.3.1
4
+
5
+ * Update dependencies and date in gemspec files:
6
+ - Updated `complex_config` dependency to '~> 0.22'
7
+ * Refactor FollowChat#eval_stats to add bold eval rates
8
+ * Improve formatting in eval_stats using bold and color for better
9
+ readability.
10
+ * Update import_document and add_image methods to handle nil values
11
+ correctly.
12
+ * Update width method in utils/width.rb to use uncolor when checking line
13
+ length.
14
+ * Refactor eval stats output in FollowChat class
15
+ - Add indentation to eval stats output for better readability
16
+ * FollowChat evaluation stats refactored
17
+ - Removed hardcoded eval_stats hash and replaced with method call
18
+ `eval_stats(response)`
19
+ - Added new method `eval_stats(response)` to calculate evaluation statistics
20
+ - Calculates eval duration, prompt eval duration, total duration, and load
21
+ duration
22
+ - Adds eval count, prompt eval count, eval rate, and prompt eval rate
23
+ * Use default to_s tree representation of config.
24
+ * Update complex_config dependency to ~> 0.21, >= 0.21.1 in Rakefile
25
+ * Update complex_config dependency to ~> 0.21, >= 0.21.1 in
26
+ ollama-ruby.gemspec
27
+ * Update dependencies and configuration display
28
+ * Update 'complex_config' dependency to '~> 0.21'
29
+ * Change OllamaChatConfig to display configuration as a tree instead of yaml
30
+ * Improve /web search command
31
+ * Update infobar dependency to ~> 0.8
32
+ * Update /web command to summarize web sources as well as importing them
33
+ directly
34
+ * Add /clobber command to clear conversation messages and collection
35
+ * Refactor Ollama chat configuration and summary generation.
36
+ * Update `OllamaChatConfig` to use `prompts.system` instead of `system`.
37
+ * Introduce `prompts.summarize` config as template for generating abstract
38
+ summaries.
39
+ * Replace hardcoded summary generation with call to `prompts.summarize`.
40
+ * Display /help for all unknown chat commands starting wit `/`
41
+
3
42
  ## 2024-09-05 v0.3.0
4
43
 
5
44
  * **New Features**
data/README.md CHANGED
@@ -156,6 +156,7 @@ The following commands can be given inside the chat, if prefixed by a `/`:
156
156
  /markdown toggle markdown output
157
157
  /list list the messages of the conversation
158
158
  /clear clear the conversation messages
159
+ /clobber clear conversation messages and collection
159
160
  /pop [n] pop the last n exchanges, defaults to 1
160
161
  /model change the model
161
162
  /regenerate the last answer message
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ GemHadar do
24
24
  required_ruby_version '~> 3.1'
25
25
 
26
26
  dependency 'excon', '~> 0.111'
27
- dependency 'infobar', '~> 0.7'
27
+ dependency 'infobar', '~> 0.8'
28
28
  dependency 'term-ansicolor', '~> 1.11'
29
29
  dependency 'kramdown-parser-gfm', '~> 1.1'
30
30
  dependency 'terminal-table', '~> 3.0'
@@ -34,7 +34,7 @@ GemHadar do
34
34
  dependency 'sorted_set', '~> 1.0'
35
35
  dependency 'mime-types', '~> 3.0'
36
36
  dependency 'reverse_markdown', '~> 2.0'
37
- dependency 'complex_config', '~> 0.20'
37
+ dependency 'complex_config', '~> 0.22'
38
38
  dependency 'search_ui', '~> 0.0'
39
39
  dependency 'amatch', '~> 0.4.1'
40
40
  dependency 'pdf-reader', '~> 2.0'
data/bin/ollama_chat CHANGED
@@ -26,7 +26,12 @@ class OllamaChatConfig
26
26
  name: <%= ENV.fetch('OLLAMA_CHAT_MODEL', 'llama3.1') %>
27
27
  options:
28
28
  num_ctx: 8192
29
- system: <%= ENV.fetch('OLLAMA_CHAT_SYSTEM', 'null') %>
29
+ prompts:
30
+ system: <%= ENV.fetch('OLLAMA_CHAT_SYSTEM', 'null') %>
31
+ summarize: |
32
+ Generate an abstract summary of the content in this document:
33
+
34
+ %s
30
35
  voice: Samantha
31
36
  markdown: true
32
37
  embedding:
@@ -50,7 +55,7 @@ class OllamaChatConfig
50
55
 
51
56
  def initialize(filename = nil)
52
57
  @filename = filename || default_path
53
- @config = Provider.config(@filename)
58
+ @config = Provider.config(@filename, '⚙️')
54
59
  retried = false
55
60
  rescue ConfigurationFileMissing
56
61
  if @filename == default_path && !retried
@@ -115,19 +120,28 @@ class FollowChat
115
120
  @say.call(response)
116
121
  end
117
122
  if response.done
118
- @output.puts
119
- eval_stats = {
120
- eval_duration: Tins::Duration.new(response.eval_duration / 1e9),
121
- eval_count: response.eval_count,
122
- prompt_eval_duration: Tins::Duration.new(response.prompt_eval_duration / 1e9),
123
- prompt_eval_count: response.prompt_eval_count,
124
- total_duration: Tins::Duration.new(response.total_duration / 1e9),
125
- load_duration: Tins::Duration.new(response.load_duration / 1e9),
126
- }.map { _1 * '=' } * ' '
127
- @output.puts '📊 ' + color(111) { Utils::Width.wrap(eval_stats, percentage: 90) }
123
+ @output.puts "", eval_stats(response)
128
124
  end
129
125
  self
130
126
  end
127
+
128
+ def eval_stats(response)
129
+ eval_duration = response.eval_duration / 1e9
130
+ prompt_eval_duration = response.prompt_eval_duration / 1e9
131
+ stats_text = {
132
+ eval_duration: Tins::Duration.new(eval_duration),
133
+ eval_count: response.eval_count,
134
+ eval_rate: bold { "%.2f c/s" % (response.eval_count / eval_duration) } + color(111),
135
+ prompt_eval_duration: Tins::Duration.new(prompt_eval_duration),
136
+ prompt_eval_count: response.prompt_eval_count,
137
+ prompt_eval_rate: bold { "%.2f c/s" % (response.prompt_eval_count / prompt_eval_duration) } + color(111),
138
+ total_duration: Tins::Duration.new(response.total_duration / 1e9),
139
+ load_duration: Tins::Duration.new(response.load_duration / 1e9),
140
+ }.map { _1 * '=' } * ' '
141
+ '📊 ' + color(111) {
142
+ Utils::Width.wrap(stats_text, percentage: 90).gsub(/(?<!\A)^/, ' ')
143
+ }
144
+ end
131
145
  end
132
146
 
133
147
  def search_web(query, n = 5)
@@ -312,7 +326,7 @@ def import_document(source_io, source)
312
326
  STDOUT.puts "Embedding disabled, I won't import any documents, try: /summarize"
313
327
  return
314
328
  end
315
- infobar.puts "Importing #{italic { source_io.content_type }} document #{source.to_s.inspect}."
329
+ puts "Importing #{italic { source_io&.content_type }} document #{source.to_s.inspect}."
316
330
  text = parse_source(source_io) or return
317
331
  text.downcase!
318
332
  splitter_config = $config.embedding.splitter
@@ -340,7 +354,7 @@ def import_document(source_io, source)
340
354
  end
341
355
 
342
356
  def add_image(images, source_io, source)
343
- STDERR.puts "Adding #{source_io.content_type} image #{source.to_s.inspect}."
357
+ STDERR.puts "Adding #{source_io&.content_type} image #{source.to_s.inspect}."
344
358
  image = Image.for_io(source_io, path: source.to_s)
345
359
  (images << image).uniq!
346
360
  end
@@ -365,16 +379,12 @@ rescue => e
365
379
  end
366
380
 
367
381
  def summarize(source)
368
- puts "Now summarizing #{source.inspect}."
382
+ puts "Now summarizing #{source.to_s.inspect}."
369
383
  source_content =
370
384
  fetch_source(source) do |source_io|
371
385
  parse_source(source_io) or return
372
386
  end
373
- <<~end
374
- # Generate an abstract summary of the content in this document:
375
-
376
- #{source_content}
377
- end
387
+ $config.prompts.summarize % source_content
378
388
  end
379
389
 
380
390
  def parse_content(content, images)
@@ -459,6 +469,7 @@ def display_chat_help
459
469
  /markdown toggle markdown output
460
470
  /list list the messages of the conversation
461
471
  /clear clear the conversation messages
472
+ /clobber clear conversation messages and collection
462
473
  /pop [n] pop the last n exchanges, defaults to 1
463
474
  /model change the model
464
475
  /regenerate the last answer message
@@ -501,8 +512,7 @@ $config = config.config
501
512
 
502
513
  opts[?h] and usage
503
514
 
504
- puts "Configuration read from #{config.filename.inspect} is:"
505
- y $config.to_h
515
+ puts "Configuration read from #{config.filename.inspect} is:", $config
506
516
 
507
517
  base_url = opts[?u] || $config.url
508
518
  $ollama = Client.new(base_url:, debug: $config.debug)
@@ -540,7 +550,7 @@ if $config.embedding.enabled
540
550
  File.expand_path(doc)
541
551
  end
542
552
  end
543
- infobar.puts "Collection #{bold{collection}}: Adding #{document_list.size} documents…"
553
+ puts "Collection #{bold{collection}}: Adding #{document_list.size} documents…"
544
554
  document_list.each_slice(25) do |docs|
545
555
  docs.each do |doc|
546
556
  fetch_source(doc) do |doc_io|
@@ -563,7 +573,7 @@ if opts[?c]
563
573
  messages.concat load_conversation(opts[?c])
564
574
  else
565
575
  if system = Ollama::Utils::FileArgument.
566
- get_file_argument(opts[?s], default: $config.system? || model_system)
576
+ get_file_argument(opts[?s], default: $config.prompts.system? || model_system)
567
577
  messages << Message.new(role: 'system', content: system)
568
578
  puts "Configured system prompt is:\n#{italic { system }}"
569
579
  end
@@ -584,7 +594,7 @@ loop do
584
594
  when %r(^/quit$)
585
595
  puts "Goodbye."
586
596
  exit 0
587
- when %r(^/markdown)
597
+ when %r(^/markdown$)
588
598
  markdown = set_markdown(!markdown)
589
599
  next
590
600
  when %r(^/list$)
@@ -594,6 +604,11 @@ loop do
594
604
  messages.clear
595
605
  puts "Cleared messages."
596
606
  next
607
+ when %r(^/clobber$)
608
+ messages.clear
609
+ $documents.clear
610
+ puts "Cleared messages and collection."
611
+ next
597
612
  when %r(^/collection\s+(clear|stats|change|new)(?:\s+(.+))?$)
598
613
  command, arg = $1, $2
599
614
  case command
@@ -636,13 +651,19 @@ loop do
636
651
  when %r(^/summarize\s+(.+))
637
652
  parse_content = false
638
653
  content = summarize($1) or next
639
- when %r(^/web\s+(?:(\d+)\s+)?(.+)$)
640
- parse_content = true
641
- urls = search_web($2, $1.to_i)
654
+ when %r(^/web\s+(?:(\d+)\s+)?(.+))
655
+ parse_content = false
656
+ urls = search_web($2, $1.to_i)
657
+ urls.each do |url|
658
+ fetch_source(url) do |url_io|
659
+ import_document(url_io, url)
660
+ end
661
+ end
662
+ urls_summarized = urls.map { summarize(_1) }
642
663
  content = <<~end
643
- Answer the the query #{$2.inspect} using these sources:
664
+ Answer the the query #{$2.inspect} using these sources and summaries:
644
665
 
645
- #{urls * ?\n}
666
+ #{urls.zip(urls_summarized).map { |u, s| "%s as \n:%s" % [ u, s ] } * "\n\n"}
646
667
  end
647
668
  when %r(^/save\s+(.+)$)
648
669
  save_conversation($1, messages)
@@ -652,7 +673,7 @@ loop do
652
673
  messages = load_conversation($1)
653
674
  puts "Loaded conversation from #$1."
654
675
  next
655
- when %r(^/help$)
676
+ when %r(^/)
656
677
  display_chat_help
657
678
  next
658
679
  when nil, ''
@@ -1,6 +1,8 @@
1
1
  require 'tins/terminal'
2
2
 
3
3
  module Ollama::Utils::Width
4
+ include Term::ANSIColor
5
+
4
6
  module_function
5
7
 
6
8
  def width(percentage: 100.0)
@@ -12,7 +14,7 @@ module Ollama::Utils::Width
12
14
  raise ArgumentError, "either pass percentage or length argument"
13
15
  percentage and length ||= width(percentage:)
14
16
  text.gsub(/(?<!\n)\n(?!\n)/, ' ').lines.map do |line|
15
- if length >= 1 && line.length > length
17
+ if length >= 1 && uncolor { line }.length > length
16
18
  line.gsub(/(.{1,#{length}})(\s+|$)/, "\\1\n").strip
17
19
  else
18
20
  line.strip
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '0.3.0'
3
+ VERSION = '0.3.1'
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.3.0 ruby lib
2
+ # stub: ollama-ruby 0.3.1 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "0.3.0".freeze
6
+ s.version = "0.3.1".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-09-06"
11
+ s.date = "2024-09-12"
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]
@@ -24,13 +24,13 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.specification_version = 4
26
26
 
27
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.17.0".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.17.1".freeze])
28
28
  s.add_development_dependency(%q<all_images>.freeze, ["~> 0.4".freeze])
29
29
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
30
30
  s.add_development_dependency(%q<utils>.freeze, [">= 0".freeze])
31
31
  s.add_development_dependency(%q<webmock>.freeze, [">= 0".freeze])
32
32
  s.add_runtime_dependency(%q<excon>.freeze, ["~> 0.111".freeze])
33
- s.add_runtime_dependency(%q<infobar>.freeze, ["~> 0.7".freeze])
33
+ s.add_runtime_dependency(%q<infobar>.freeze, ["~> 0.8".freeze])
34
34
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
35
35
  s.add_runtime_dependency(%q<kramdown-parser-gfm>.freeze, ["~> 1.1".freeze])
36
36
  s.add_runtime_dependency(%q<terminal-table>.freeze, ["~> 3.0".freeze])
@@ -40,7 +40,7 @@ Gem::Specification.new do |s|
40
40
  s.add_runtime_dependency(%q<sorted_set>.freeze, ["~> 1.0".freeze])
41
41
  s.add_runtime_dependency(%q<mime-types>.freeze, ["~> 3.0".freeze])
42
42
  s.add_runtime_dependency(%q<reverse_markdown>.freeze, ["~> 2.0".freeze])
43
- s.add_runtime_dependency(%q<complex_config>.freeze, ["~> 0.20".freeze])
43
+ s.add_runtime_dependency(%q<complex_config>.freeze, ["~> 0.22".freeze])
44
44
  s.add_runtime_dependency(%q<search_ui>.freeze, ["~> 0.0".freeze])
45
45
  s.add_runtime_dependency(%q<amatch>.freeze, ["~> 0.4.1".freeze])
46
46
  s.add_runtime_dependency(%q<pdf-reader>.freeze, ["~> 2.0".freeze])
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.3.0
4
+ version: 0.3.1
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-09-06 00:00:00.000000000 Z
11
+ date: 2024-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.17.0
19
+ version: 1.17.1
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.17.0
26
+ version: 1.17.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: all_images
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.7'
103
+ version: '0.8'
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.7'
110
+ version: '0.8'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: term-ansicolor
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -240,14 +240,14 @@ dependencies:
240
240
  requirements:
241
241
  - - "~>"
242
242
  - !ruby/object:Gem::Version
243
- version: '0.20'
243
+ version: '0.22'
244
244
  type: :runtime
245
245
  prerelease: false
246
246
  version_requirements: !ruby/object:Gem::Requirement
247
247
  requirements:
248
248
  - - "~>"
249
249
  - !ruby/object:Gem::Version
250
- version: '0.20'
250
+ version: '0.22'
251
251
  - !ruby/object:Gem::Dependency
252
252
  name: search_ui
253
253
  requirement: !ruby/object:Gem::Requirement