ollama_chat 0.0.20 → 0.0.21
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/VERSION +1 -1
- data/lib/ollama_chat/chat.rb +172 -5
- data/lib/ollama_chat/dialog.rb +8 -5
- data/lib/ollama_chat/follow_chat.rb +36 -0
- data/lib/ollama_chat/information.rb +1 -0
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +1 -0
- data/lib/ollama_chat/source_fetching.rb +91 -1
- data/lib/ollama_chat/switches.rb +79 -16
- data/lib/ollama_chat/utils/cache_fetcher.rb +30 -0
- data/lib/ollama_chat/utils/fetcher.rb +117 -0
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat/vim.rb +53 -0
- data/lib/ollama_chat/web_searching.rb +35 -1
- data/lib/ollama_chat.rb +1 -0
- data/ollama_chat.gemspec +4 -4
- data/spec/assets/api_tags.json +17 -0
- data/spec/ollama_chat/switches_spec.rb +9 -14
- metadata +3 -1
data/lib/ollama_chat/switches.rb
CHANGED
@@ -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
|
-
|
20
|
-
|
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
|
-
:
|
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
|
-
:
|
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
|
-
:
|
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')
|
data/lib/ollama_chat/version.rb
CHANGED
@@ -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
|
@@ -1,4 +1,16 @@
|
|
1
1
|
module OllamaChat::WebSearching
|
2
|
+
# The search_web method performs a web search using the configured search
|
3
|
+
# engine.
|
4
|
+
# It appends location information to the query if available and limits the
|
5
|
+
# number of results.
|
6
|
+
# The method delegates to engine-specific search methods based on the
|
7
|
+
# configured search engine.
|
8
|
+
#
|
9
|
+
# @param query [ String ] the search query string
|
10
|
+
# @param n [ Integer ] the maximum number of results to return
|
11
|
+
#
|
12
|
+
# @return [ Array<String>, nil ] an array of URLs from the search results or
|
13
|
+
# nil if the search engine is not implemented
|
2
14
|
def search_web(query, n = nil)
|
3
15
|
l = @messages.at_location.full? and query += " #{l}"
|
4
16
|
n = n.to_i.clamp(1..)
|
@@ -14,10 +26,22 @@ module OllamaChat::WebSearching
|
|
14
26
|
|
15
27
|
private
|
16
28
|
|
29
|
+
# The search_engine method returns the currently configured web search engine
|
30
|
+
# to be used for online searches.
|
31
|
+
#
|
32
|
+
# @return [ String ] the name of the web search engine
|
33
|
+
# @see OllamaChat::Config::WebSearch#use
|
17
34
|
def search_engine
|
18
35
|
config.web_search.use
|
19
36
|
end
|
20
37
|
|
38
|
+
# The search_web_with_searxng method performs a web search using the SearxNG
|
39
|
+
# engine and returns the URLs of the first n search results.
|
40
|
+
#
|
41
|
+
# @param query [ String ] the search query string
|
42
|
+
# @param n [ Integer ] the number of search results to return
|
43
|
+
#
|
44
|
+
# @return [ Array<String> ] an array of URLs from the search results
|
21
45
|
def search_web_with_searxng(query, n)
|
22
46
|
url = config.web_search.engines.searxng.url % { query: }
|
23
47
|
OllamaChat::Utils::Fetcher.get(
|
@@ -30,6 +54,15 @@ module OllamaChat::WebSearching
|
|
30
54
|
end
|
31
55
|
end
|
32
56
|
|
57
|
+
# The search_web_with_duckduckgo method performs a web search using the
|
58
|
+
# DuckDuckGo search engine and extracts URLs from the search results.
|
59
|
+
#
|
60
|
+
# @param query [ String ] the search query string to be used
|
61
|
+
# @param n [ Integer ] the maximum number of URLs to extract from the search
|
62
|
+
# results
|
63
|
+
#
|
64
|
+
# @return [ Array<String> ] an array of URL strings extracted from the search
|
65
|
+
# results
|
33
66
|
def search_web_with_duckduckgo(query, n)
|
34
67
|
url = config.web_search.engines.duckduckgo.url % { query: }
|
35
68
|
OllamaChat::Utils::Fetcher.get(
|
@@ -47,7 +80,8 @@ module OllamaChat::WebSearching
|
|
47
80
|
url = URI.decode_uri_component(url)
|
48
81
|
url = URI.parse(url)
|
49
82
|
url.host =~ /duckduckgo\.com/ and next
|
50
|
-
|
83
|
+
url = url.to_s
|
84
|
+
links.add(url)
|
51
85
|
result << url
|
52
86
|
n -= 1
|
53
87
|
else
|
data/lib/ollama_chat.rb
CHANGED
@@ -19,6 +19,7 @@ require 'ollama_chat/dialog'
|
|
19
19
|
require 'ollama_chat/information'
|
20
20
|
require 'ollama_chat/message_output'
|
21
21
|
require 'ollama_chat/clipboard'
|
22
|
+
require 'ollama_chat/vim'
|
22
23
|
require 'ollama_chat/document_cache'
|
23
24
|
require 'ollama_chat/history'
|
24
25
|
require 'ollama_chat/server_socket'
|
data/ollama_chat.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: ollama_chat 0.0.
|
2
|
+
# stub: ollama_chat 0.0.21 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "ollama_chat".freeze
|
6
|
-
s.version = "0.0.
|
6
|
+
s.version = "0.0.21".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]
|
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = "The app provides a command-line interface (CLI) to an Ollama AI model,\nallowing users to engage in text-based conversations and generate\nhuman-like responses. Users can import data from local files or web pages,\nwhich are then processed through three different modes: fully importing the\ncontent into the conversation context, summarizing the information for\nconcise reference, or storing it in an embedding vector database for later\nretrieval based on the conversation.\n".freeze
|
13
13
|
s.email = "flori@ping.de".freeze
|
14
14
|
s.executables = ["ollama_chat".freeze, "ollama_chat_send".freeze]
|
15
|
-
s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/file_argument.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
|
16
|
-
s.files = [".all_images.yml".freeze, ".envrc".freeze, ".gitignore".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/file_argument.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/file_argument_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/file_argument.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
|
16
|
+
s.files = [".all_images.yml".freeze, ".envrc".freeze, ".gitignore".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/file_argument.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/file_argument_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
|
17
17
|
s.homepage = "https://github.com/flori/ollama_chat".freeze
|
18
18
|
s.licenses = ["MIT".freeze]
|
19
19
|
s.rdoc_options = ["--title".freeze, "OllamaChat - A command-line interface (CLI) for interacting with an Ollama AI model.".freeze, "--main".freeze, "README.md".freeze]
|
data/spec/assets/api_tags.json
CHANGED
@@ -16,6 +16,23 @@
|
|
16
16
|
"parameter_size": "8.0B",
|
17
17
|
"quantization_level": "Q4_K_M"
|
18
18
|
}
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"name": "qwen3-coder:latest",
|
22
|
+
"model": "qwen3-coder:latest",
|
23
|
+
"modified_at": "2025-08-08T00:10:43.7235626Z",
|
24
|
+
"size": 18556701140,
|
25
|
+
"digest": "ad67f85ca2502e92936ef793bf29a312e1912ecd1e2c09c9c2963adf1debde78",
|
26
|
+
"details": {
|
27
|
+
"parent_model": "",
|
28
|
+
"format": "gguf",
|
29
|
+
"family": "qwen3moe",
|
30
|
+
"families": [
|
31
|
+
"qwen3moe"
|
32
|
+
],
|
33
|
+
"parameter_size": "30.5B",
|
34
|
+
"quantization_level": "Q4_K_M"
|
35
|
+
}
|
19
36
|
}
|
20
37
|
]
|
21
38
|
}
|