ollama_chat 0.0.20 → 0.0.22

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.
@@ -1,4 +1,13 @@
1
1
  module OllamaChat::SourceFetching
2
+ # The http_options method prepares HTTP options for requests based on
3
+ # configuration settings.
4
+ # It determines whether SSL peer verification should be disabled for a given
5
+ # URL and whether a proxy should be used, then returns a hash of options.
6
+ #
7
+ # @param url [ String ] the URL for which HTTP options are being prepared
8
+ #
9
+ # @return [ Hash ] a hash containing HTTP options such as ssl_verify_peer and
10
+ # proxy settings
2
11
  def http_options(url)
3
12
  options = {}
4
13
  if ssl_no_verify = config.ssl_no_verify?
@@ -11,6 +20,13 @@ module OllamaChat::SourceFetching
11
20
  options
12
21
  end
13
22
 
23
+ # The fetch_source method retrieves content from various source types
24
+ # including commands, URLs, and file paths. It processes the source based on
25
+ # its type and yields a temporary file handle for further processing.
26
+ #
27
+ # @param source [ String ] the source identifier which can be a command, URL, or file path
28
+ #
29
+ # @yield [ tmp ]
14
30
  def fetch_source(source, &block)
15
31
  case source
16
32
  when %r(\A!(.*))
@@ -36,18 +52,38 @@ module OllamaChat::SourceFetching
36
52
  block.(tmp)
37
53
  end
38
54
  else
39
- raise "invalid source"
55
+ raise "invalid source #{source.inspect}"
40
56
  end
41
57
  rescue => e
42
58
  STDERR.puts "Cannot fetch source #{source.to_s.inspect}: #{e.class} #{e}\n#{e.backtrace * ?\n}"
43
59
  end
44
60
 
61
+
62
+ # Adds an image to the images collection from the given source IO and source
63
+ # identifier.
64
+ #
65
+ # This method takes an IO object containing image data and associates it with
66
+ # a source, creating an Ollama::Image instance and adding it to the images
67
+ # array.
68
+ #
69
+ # @param images [Array] The collection of images to which the new image will be added
70
+ # @param source_io [IO] The input stream containing the image data
71
+ # @param source [String, #to_s] The identifier or path for the source of the image
45
72
  def add_image(images, source_io, source)
46
73
  STDERR.puts "Adding #{source_io&.content_type} image #{source.to_s.inspect}."
47
74
  image = Ollama::Image.for_io(source_io, path: source.to_s)
48
75
  (images << image).uniq!
49
76
  end
50
77
 
78
+ # The import_source method processes and imports content from a given source,
79
+ # displaying information about the document type and returning a formatted
80
+ # string that indicates the import result along with the parsed content.
81
+ #
82
+ # @param source_io [ IO ] the input stream containing the document content
83
+ # @param source [ String ] the source identifier or path
84
+ #
85
+ # @return [ String ] a formatted message indicating the import result and the
86
+ # parsed content
51
87
  def import_source(source_io, source)
52
88
  source = source.to_s
53
89
  document_type = source_io&.content_type.full? { |ct| italic { ct } + ' ' }
@@ -56,6 +92,16 @@ module OllamaChat::SourceFetching
56
92
  "Imported #{source.inspect}:\n\n#{source_content}\n\n"
57
93
  end
58
94
 
95
+ # Imports content from the specified source and processes it.
96
+ #
97
+ # This method fetches content from a given source (command, URL, or file) and
98
+ # passes the resulting IO object to the import_source method for processing.
99
+ #
100
+ # @param source [String] The source identifier which can be a command, URL,
101
+ # or file path
102
+ #
103
+ # @return [String, nil] A formatted message indicating the import result and
104
+ # parsed content, # or nil if the operation fails
59
105
  def import(source)
60
106
  fetch_source(source) do |source_io|
61
107
  content = import_source(source_io, source) or return
@@ -64,6 +110,16 @@ module OllamaChat::SourceFetching
64
110
  end
65
111
  end
66
112
 
113
+
114
+ # Summarizes content from the given source IO and source identifier.
115
+ #
116
+ # This method takes an IO object containing document content and generates a
117
+ # summary based on the configured prompt template and word count.
118
+ #
119
+ # @param source_io [IO] The input stream containing the document content to summarize
120
+ # @param source [String, #to_s] The identifier or path for the source of the content
121
+ # @param words [Integer, nil] The target number of words for the summary (defaults to 100)
122
+ # @return [String, nil] The formatted summary message or nil if content is empty or cannot be processed
67
123
  def summarize_source(source_io, source, words: nil)
68
124
  STDOUT.puts "Summarizing #{italic { source_io&.content_type }} document #{source.to_s.inspect} now."
69
125
  words = words.to_i
@@ -73,6 +129,15 @@ module OllamaChat::SourceFetching
73
129
  config.prompts.summarize % { source_content:, words: }
74
130
  end
75
131
 
132
+
133
+ # Summarizes content from the specified source.
134
+ #
135
+ # This method fetches content from a given source (command, URL, or file) and
136
+ # generates a summary using the summarize_source method.
137
+ #
138
+ # @param source [String] The source identifier which can be a command, URL, or file path
139
+ # @param words [Integer, nil] The target number of words for the summary (defaults to 100)
140
+ # @return [String, nil] The formatted summary message or nil if the operation fails
76
141
  def summarize(source, words: nil)
77
142
  fetch_source(source) do |source_io|
78
143
  content = summarize_source(source_io, source, words:) or return
@@ -81,6 +146,19 @@ module OllamaChat::SourceFetching
81
146
  end
82
147
  end
83
148
 
149
+
150
+ # Embeds content from the given source IO and source identifier.
151
+ #
152
+ # This method processes document content by splitting it into chunks using
153
+ # various splitting strategies (Character, RecursiveCharacter, Semantic) and
154
+ # adds the chunks to a document store for embedding.
155
+ #
156
+ # @param source_io [IO] The input stream containing the document content to embed
157
+ # @param source [String, #to_s] The identifier or path for the source of the content
158
+ # @param count [Integer, nil] An optional counter for tracking processing order
159
+ #
160
+ # @return [Array, String, nil] The embedded chunks or processed content, or
161
+ # nil if embedding is disabled or fails
84
162
  def embed_source(source_io, source, count: nil)
85
163
  @embedding.on? or return parse_source(source_io)
86
164
  m = "Embedding #{italic { source_io&.content_type }} document #{source.to_s.inspect}."
@@ -127,6 +205,18 @@ module OllamaChat::SourceFetching
127
205
  @documents.add(inputs, source:, batch_size: config.embedding.batch_size?)
128
206
  end
129
207
 
208
+
209
+ # Embeds content from the specified source.
210
+ #
211
+ # This method fetches content from a given source (command, URL, or file) and
212
+ # processes it for embedding using the embed_source method. If embedding is
213
+ # disabled, it falls back to generating a summary instead.
214
+ #
215
+ # @param source [String] The source identifier which can be a command, URL,
216
+ # or file path
217
+ #
218
+ # @return [String, nil] The formatted embedding result or summary message, or
219
+ # nil if the operation fails
130
220
  def embed(source)
131
221
  if @embedding.on?
132
222
  STDOUT.puts "Now embedding #{source.to_s.inspect}."
@@ -6,28 +6,56 @@ module OllamaChat::Switches
6
6
  alias_method :on?, :value
7
7
  end
8
8
 
9
+ # The off? method returns true if the switch is in the off state, false
10
+ # otherwise.
11
+ #
12
+ # @return [ TrueClass, FalseClass ] indicating whether the switch is off
9
13
  def off?
10
14
  !on?
11
15
  end
12
16
 
17
+ # The show method outputs the current value of the message to standard
18
+ # output.
19
+ #
20
+ # @return [ void ]
13
21
  def show
14
22
  STDOUT.puts @msg[value]
15
23
  end
16
24
  end
17
25
 
18
26
  class Switch
19
- def initialize(name, msg:, config:)
20
- @value = [ false, true ].include?(config) ? config : !!config.send("#{name}?")
27
+ # The initialize method sets up the switch with a default value and
28
+ # message.
29
+ #
30
+ # @param msg [ Hash ] a hash containing true and false messages
31
+ # @param value [ Object ] the default state of the switch
32
+ #
33
+ # @return [ void ]
34
+ def initialize(msg:, value:)
35
+ @value = !!value
21
36
  @msg = msg
22
37
  end
23
38
 
39
+ # The value reader returns the current value of the attribute.
24
40
  attr_reader :value
25
41
 
42
+ # The set method assigns a boolean value to the instance variable @value
43
+ # and optionally displays it.
44
+ #
45
+ # @param value [ Object ] the value to be converted to a boolean and
46
+ # assigned
47
+ # @param show [ TrueClass, FalseClass ] determines whether to display the
48
+ # value after setting
26
49
  def set(value, show: false)
27
50
  @value = !!value
28
51
  show && self.show
29
52
  end
30
53
 
54
+ # The toggle method switches the current value of the instance variable and
55
+ # optionally displays it.
56
+ #
57
+ # @param show [ TrueClass, FalseClass ] determines whether to show the
58
+ # value after toggling
31
59
  def toggle(show: true)
32
60
  @value = !@value
33
61
  show && self.show
@@ -37,11 +65,17 @@ module OllamaChat::Switches
37
65
  end
38
66
 
39
67
  class CombinedSwitch
68
+ # The initialize method sets up the switch with a value and message.
69
+ #
70
+ # @param value [ Object ] the value to be stored
71
+ # @param msg [ Hash ] the message hash containing true and false keys
40
72
  def initialize(value:, msg:)
41
73
  @value = value
42
74
  @msg = msg
43
75
  end
44
76
 
77
+ # The value method returns the result of calling the stored proc with no
78
+ # arguments.
45
79
  def value
46
80
  @value.()
47
81
  end
@@ -49,26 +83,61 @@ module OllamaChat::Switches
49
83
  include CheckSwitch
50
84
  end
51
85
 
86
+ # The think method returns the current state of the stream switch.
87
+ #
88
+ # @return [ OllamaChat::Switches::Switch ] the stream switch instance
52
89
  attr_reader :stream
53
90
 
91
+ # The think method returns the current state of the thinking switch.
92
+ #
93
+ # @return [ OllamaChat::Switches::Switch ] the thinking switch instance
54
94
  attr_reader :think
55
95
 
96
+ # The markdown attribute reader returns the markdown switch object.
97
+ # The voice reader returns the voice switch instance.
98
+ #
99
+ # @return [ OllamaChat::Switches::Switch ] the markdown switch instance
56
100
  attr_reader :markdown
57
101
 
102
+ # The voice reader returns the voice switch instance.
103
+ #
104
+ # @return [ OllamaChat::Switches::Switch ] the voice switch instance
58
105
  attr_reader :voice
59
106
 
107
+ # The embedding attribute reader returns the embedding switch object.
108
+ #
109
+ # @return [ OllamaChat::Switches::CombinedSwitch ] the embedding switch
110
+ # instance
60
111
  attr_reader :embedding
61
112
 
113
+ # The embedding_enabled reader returns the embedding enabled switch instance.
114
+ #
115
+ # @return [ OllamaChat::Switches::Switch ] the embedding enabled switch
116
+ # instance
62
117
  attr_reader :embedding_enabled
63
118
 
119
+ # The embedding_paused method returns the current state of the embedding pause flag.
120
+ #
121
+ # @return [ OllamaChat::Switches::Switch ] the embedding pause flag switch instance
64
122
  attr_reader :embedding_paused
65
123
 
124
+ # The location method returns the current location setting.
125
+ #
126
+ # @return [ OllamaChat::Switches::Switch ] the location setting object
66
127
  attr_reader :location
67
128
 
129
+ # The setup_switches method initializes various switches for configuring the
130
+ # application's behavior.
131
+ #
132
+ # This method creates and configures multiple switch objects that control
133
+ # different aspects of the application, such as streaming, thinking, markdown
134
+ # output, voice output, embedding, and location settings.
135
+ #
136
+ # @param config [ ComplexConfig::Settings ] the configuration object
137
+ # containing settings for the switches
68
138
  def setup_switches(config)
69
139
  @stream = Switch.new(
70
- :stream,
71
- config:,
140
+ value: config.stream,
72
141
  msg: {
73
142
  true => "Streaming enabled.",
74
143
  false => "Streaming disabled.",
@@ -76,8 +145,7 @@ module OllamaChat::Switches
76
145
  )
77
146
 
78
147
  @think = Switch.new(
79
- :think,
80
- config:,
148
+ value: config.think,
81
149
  msg: {
82
150
  true => "Thinking enabled.",
83
151
  false => "Thinking disabled.",
@@ -85,8 +153,7 @@ module OllamaChat::Switches
85
153
  )
86
154
 
87
155
  @markdown = Switch.new(
88
- :markdown,
89
- config:,
156
+ value: config.markdown,
90
157
  msg: {
91
158
  true => "Using #{italic{'ANSI'}} markdown to output content.",
92
159
  false => "Using plaintext for outputting content.",
@@ -94,8 +161,7 @@ module OllamaChat::Switches
94
161
  )
95
162
 
96
163
  @voice = Switch.new(
97
- :stream,
98
- config: config.voice,
164
+ value: config.voice.enabled,
99
165
  msg: {
100
166
  true => "Voice output enabled.",
101
167
  false => "Voice output disabled.",
@@ -103,8 +169,7 @@ module OllamaChat::Switches
103
169
  )
104
170
 
105
171
  @embedding_enabled = Switch.new(
106
- :embedding_enabled,
107
- config:,
172
+ value: config.embedding.enabled,
108
173
  msg: {
109
174
  true => "Embedding enabled.",
110
175
  false => "Embedding disabled.",
@@ -112,8 +177,7 @@ module OllamaChat::Switches
112
177
  )
113
178
 
114
179
  @embedding_paused = Switch.new(
115
- :embedding_paused,
116
- config:,
180
+ value: config.embedding.paused,
117
181
  msg: {
118
182
  true => "Embedding paused.",
119
183
  false => "Embedding resumed.",
@@ -129,8 +193,7 @@ module OllamaChat::Switches
129
193
  )
130
194
 
131
195
  @location = Switch.new(
132
- :location,
133
- config: config.location.enabled,
196
+ value: config.location.enabled,
134
197
  msg: {
135
198
  true => "Location and localtime enabled.",
136
199
  false => "Location and localtime disabled.",
@@ -1,10 +1,24 @@
1
1
  require 'digest/md5'
2
2
 
3
3
  class OllamaChat::Utils::CacheFetcher
4
+ # The initialize method sets up the cache instance variable for the object.
5
+ #
6
+ # @param cache [ Object ] the cache object to be stored
7
+ #
8
+ # @return [ void ]
4
9
  def initialize(cache)
5
10
  @cache = cache
6
11
  end
7
12
 
13
+ # The get method retrieves cached content by key and yields it as an IO object.
14
+ # It first checks if the body and content type are present in the cache.
15
+ # If both are found, it creates a StringIO object from the body,
16
+ # extends it with HeaderExtension, sets the content type,
17
+ # and then yields the IO object to the provided block.
18
+ #
19
+ # @param url [ String ] the URL used as a key for caching
20
+ #
21
+ # @yield [ io ] yields the cached IO object if found
8
22
  def get(url, &block)
9
23
  block or raise ArgumentError, 'require block argument'
10
24
  body = @cache[key(:body, url)]
@@ -19,6 +33,13 @@ class OllamaChat::Utils::CacheFetcher
19
33
  end
20
34
  end
21
35
 
36
+ # The put method stores the body and content type of an IO object in the
37
+ # cache using a URL-based key.
38
+ #
39
+ # @param url [ String ] the URL used to generate the cache key
40
+ # @param io [ StringIO, Tempfile ] the IO object containing the body and content type
41
+ #
42
+ # @return [ CacheFetcher ] returns itself to allow for method chaining
22
43
  def put(url, io)
23
44
  io.rewind
24
45
  body = io.read
@@ -32,6 +53,15 @@ class OllamaChat::Utils::CacheFetcher
32
53
 
33
54
  private
34
55
 
56
+ # The key method generates a unique identifier by combining a type prefix
57
+ # with a URL digest.
58
+ # It returns a string that consists of the type, a hyphen, and the MD5 hash
59
+ # of the URL.
60
+ #
61
+ # @param type [ String ] the type prefix for categorizing the key
62
+ # @param url [ String ] the URL to be hashed
63
+ #
64
+ # @return [ String ] a hyphen-separated string of the type and URL's MD5 digest
35
65
  def key(type, url)
36
66
  [ type, Digest::MD5.hexdigest(url) ] * ?-
37
67
  end
@@ -7,10 +7,22 @@ require 'ollama_chat/utils/cache_fetcher'
7
7
 
8
8
  class OllamaChat::Utils::Fetcher
9
9
  module HeaderExtension
10
+ # The content_type method accesses the content type attribute of the object.
11
+ #
12
+ # @return [ String ] the content type of the object.
10
13
  attr_accessor :content_type
11
14
 
15
+ # The ex accessor is used to get or set the expiry value in seconds.
12
16
  attr_accessor :ex
13
17
 
18
+ # The failed method creates a StringIO object with a text/plain content type.
19
+ #
20
+ # This method is used to generate a failed response object that can be used
21
+ # when an operation does not succeed. It initializes a new StringIO object
22
+ # and extends it with the current class, setting its content type to
23
+ # text/plain.
24
+ #
25
+ # @return [ StringIO ] a StringIO object with text/plain content type
14
26
  def self.failed
15
27
  object = StringIO.new.extend(self)
16
28
  object.content_type = MIME::Types['text/plain'].first
@@ -20,6 +32,22 @@ class OllamaChat::Utils::Fetcher
20
32
 
21
33
  class RetryWithoutStreaming < StandardError; end
22
34
 
35
+ # The get method retrieves content from a URL, using caching when available.
36
+ # It processes the URL with optional headers and additional options,
37
+ # then yields a temporary file containing the retrieved content.
38
+ # If caching is enabled and content is found in the cache,
39
+ # it returns the cached result instead of fetching again.
40
+ # The method handles both cached and fresh fetches,
41
+ # ensuring that cache is updated when new content is retrieved.
42
+ #
43
+ # @param url [ String ] the URL to fetch content from
44
+ # @param headers [ Hash ] optional headers to include in the request
45
+ # @param options [ Hash ] additional options for the fetch operation
46
+ #
47
+ # @yield [ tmp ]
48
+ #
49
+ # @return [ Object ] the result of the block execution
50
+ # @return [ nil ] if no block is given or if the fetch fails
23
51
  def self.get(url, headers: {}, **options, &block)
24
52
  cache = options.delete(:cache) and
25
53
  cache = OllamaChat::Utils::CacheFetcher.new(cache)
@@ -38,6 +66,9 @@ class OllamaChat::Utils::Fetcher
38
66
  end
39
67
  end
40
68
 
69
+ # The normalize_url method processes a URL by converting it to a string,
70
+ # decoding any URI components, removing anchors, and then escaping the URL to
71
+ # ensure it is properly formatted.
41
72
  def self.normalize_url(url)
42
73
  url = url.to_s
43
74
  url = URI.decode_uri_component(url)
@@ -45,6 +76,17 @@ class OllamaChat::Utils::Fetcher
45
76
  URI::Parser.new.escape(url).to_s
46
77
  end
47
78
 
79
+ # The read method opens a file and extends it with header extension metadata.
80
+ # It then yields the file to the provided block for processing.
81
+ # If the file does not exist, it outputs an error message to standard error.
82
+ #
83
+ # @param filename [ String ] the path to the file to be read
84
+ #
85
+ # @yield [ file ] yields the opened file with header extension
86
+ #
87
+ # @return [ nil ] returns nil if the file does not exist
88
+ # @return [ Object ] returns the result of the block execution if the file
89
+ # exists
48
90
  def self.read(filename, &block)
49
91
  if File.exist?(filename)
50
92
  File.open(filename) do |file|
@@ -57,6 +99,16 @@ class OllamaChat::Utils::Fetcher
57
99
  end
58
100
  end
59
101
 
102
+ # The execute method runs a shell command and processes its output.
103
+ #
104
+ # It captures the command's standard output and error streams,
105
+ # writes them to a temporary file, and yields the file to the caller.
106
+ # If an exception occurs during execution, it reports the error
107
+ # and yields a failed temporary file instead.
108
+ #
109
+ # @param command [ String ] the shell command to execute
110
+ #
111
+ # @yield [ tmpfile ]
60
112
  def self.execute(command, &block)
61
113
  Tempfile.open do |tmp|
62
114
  unless command =~ /2>&1/
@@ -80,6 +132,11 @@ class OllamaChat::Utils::Fetcher
80
132
  yield HeaderExtension.failed
81
133
  end
82
134
 
135
+ # The initialize method sets up the fetcher instance with debugging and HTTP
136
+ # configuration options.
137
+ #
138
+ # @param debug [ TrueClass, FalseClass ] enables or disables debug output
139
+ # @param http_options [ Hash ] additional options to pass to the HTTP client
83
140
  def initialize(debug: false, http_options: {})
84
141
  @debug = debug
85
142
  @started = false
@@ -89,11 +146,34 @@ class OllamaChat::Utils::Fetcher
89
146
 
90
147
  private
91
148
 
149
+ # The excon method creates a new Excon client instance configured with the
150
+ # specified URL and options.
151
+ #
152
+ # @param url [ String ] the URL to be used for the Excon client
153
+ # @param options [ Hash ] additional options to be merged with http_options
154
+ #
155
+ # @return [ Excon ] a new Excon client instance
156
+ #
157
+ # @see #normalize_url
158
+ # @see #http_options
92
159
  def excon(url, **options)
93
160
  url = self.class.normalize_url(url)
94
161
  Excon.new(url, options.merge(@http_options))
95
162
  end
96
163
 
164
+ # Makes an HTTP GET request to the specified URL with optional headers and
165
+ # processing block.
166
+ #
167
+ # This method handles both streaming and non-streaming HTTP requests, using
168
+ # Excon for the actual HTTP communication. The response body is written to a
169
+ # temporary file which is then decorated with additional behavior before
170
+ # being passed to the provided block.
171
+ #
172
+ # @param url [String] The URL to make the GET request to
173
+ # @param headers [Hash] Optional headers to include in the request (keys will
174
+ # be converted to strings)
175
+ # @yield [Tempfile] The temporary file containing the response body, after
176
+ # decoration
97
177
  def get(url, headers: {}, &block)
98
178
  headers |= self.headers
99
179
  headers = headers.transform_keys(&:to_s)
@@ -130,18 +210,41 @@ class OllamaChat::Utils::Fetcher
130
210
  yield HeaderExtension.failed
131
211
  end
132
212
 
213
+ # The headers method returns a hash containing the default HTTP headers
214
+ # that should be used for requests, including a User-Agent header
215
+ # configured with the application's user agent string.
216
+ #
217
+ # @return [ Hash ] a hash mapping header names to their values
218
+ # @note The returned hash includes the 'User-Agent' header
219
+ # set to OllamaChat::Chat.user_agent.
133
220
  def headers
134
221
  {
135
222
  'User-Agent' => OllamaChat::Chat.user_agent,
136
223
  }
137
224
  end
138
225
 
226
+ # The middlewares method returns the combined array of default Excon
227
+ # middlewares and the RedirectFollower middleware, ensuring there are no
228
+ # duplicates.
229
+ #
230
+ # @return [ Array ] an array of middleware classes including RedirectFollower
231
+ # deduplicated from the default Excon middlewares.
139
232
  def middlewares
140
233
  (Excon.defaults[:middlewares] + [ Excon::Middleware::RedirectFollower ]).uniq
141
234
  end
142
235
 
143
236
  private
144
237
 
238
+ # Decorates a temporary IO object with header information from an HTTP
239
+ # response.
240
+ #
241
+ # This method extends the given temporary IO object with HeaderExtension
242
+ # module and populates it with content type and cache expiration information
243
+ # extracted from the provided response headers.
244
+ #
245
+ # @param tmp [IO] The temporary IO object to decorate (typically a file handle)
246
+ # @param response [Object] HTTP response object containing headers
247
+ # @option response [Hash] :headers HTTP headers hash
145
248
  def decorate_io(tmp, response)
146
249
  tmp.rewind
147
250
  tmp.extend(HeaderExtension)
@@ -156,6 +259,13 @@ class OllamaChat::Utils::Fetcher
156
259
  end
157
260
  end
158
261
 
262
+ # The callback method creates a proc that handles chunked data processing by
263
+ # updating progress information and writing chunks to a temporary file.
264
+ #
265
+ # @param tmp [ Tempfile ] the temporary file to which data chunks are written
266
+ #
267
+ # @return [ Proc ] a proc that accepts chunk, remaining_bytes, and total_bytes
268
+ # parameters for processing streamed data
159
269
  def callback(tmp)
160
270
  -> chunk, remaining_bytes, total_bytes do
161
271
  total = total_bytes or next
@@ -171,6 +281,13 @@ class OllamaChat::Utils::Fetcher
171
281
  end
172
282
  end
173
283
 
284
+ # The message method formats progress information by combining current and
285
+ # total values with unit formatting, along with timing details.
286
+ #
287
+ # @param current [ Integer ] the current progress value
288
+ # @param total [ Integer ] the total progress value
289
+ #
290
+ # @return [ String ] a formatted progress string including units and timing information
174
291
  def message(current, total)
175
292
  progress = '%s/%s' % [ current, total ].map {
176
293
  Tins::Unit.format(_1, format: '%.2f %U')
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.20'
3
+ VERSION = '0.0.22'
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:
@@ -0,0 +1,53 @@
1
+ require 'tempfile'
2
+ require 'pathname'
3
+
4
+ class OllamaChat::Vim
5
+ # Initializes a new Vim server connection
6
+ #
7
+ # Creates a new OllamaChat::Vim instance for interacting with a specific Vim
8
+ # server. If no server name is provided, it defaults to using the current
9
+ # working directory as the server identifier.
10
+ #
11
+ # @param server_name [String, nil] The name of the Vim server to connect to.
12
+ # If nil or empty, defaults to the current working directory path in
13
+ # uppercase
14
+ def initialize(server_name)
15
+ server_name.full? or server_name = default_server_name
16
+ @server_name = server_name
17
+ end
18
+
19
+ # The default server name is derived from the current working directory It
20
+ # converts the absolute path to uppercase for consistent identification This
21
+ # approach ensures each working directory gets a unique server identifier The
22
+ # server name format makes it easy to distinguish different Vim sessions
23
+ def default_server_name
24
+ Pathname.pwd.to_s.upcase
25
+ end
26
+
27
+ # Inserts text at the current cursor position in Vim
28
+ #
29
+ # This method writes the provided text to a temporary file and uses Vim's
30
+ # remote-send functionality to insert it at the current cursor position.
31
+ # The text is automatically indented to match the current column position.
32
+ #
33
+ # @param text [String] The text to be inserted into the Vim buffer
34
+ def insert(text)
35
+ spaces = (col - 1).clamp(0..)
36
+ text = text.gsub(/^/, ' ' * spaces)
37
+ Tempfile.open do |tmp|
38
+ tmp.write(text)
39
+ tmp.flush
40
+ system %{vim --servername "#@server_name" --remote-send "<ESC>:r #{tmp.path}<CR>"}
41
+ end
42
+ end
43
+
44
+ # Returns the current column position of the cursor in the Vim server
45
+ #
46
+ # This method queries the specified Vim server for the current cursor position
47
+ # using Vim's remote expression feature. It executes a Vim command that returns
48
+ # the result of `col('.')`, which represents the current column number (1-indexed)
49
+ # of the cursor position.
50
+ def col
51
+ `vim --servername "#@server_name" --remote-expr "col('.')"`.chomp.to_i
52
+ end
53
+ end