ollama-rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bc1be94d75a4db6787115a0cfbdc7b6aa149418a59612e0012f845512f361ec0
4
+ data.tar.gz: d1a565383613490c54c45a534e5fff1a9060803423b6dd9146f036eb769c15ef
5
+ SHA512:
6
+ metadata.gz: 6a09fcb88ec6f2a4e41706fad85ca3def0e75b0a7df87d60fa7c167cccb19abc24163a5dc3d9c1bee1a8a88eca06fa0dbeefa8dd9b79c9215d2db564d28ea5e8
7
+ data.tar.gz: c8ec22503cb81e3dd376b0775930047d685c0ead3c6d699249449a08544d1de2435b18fb4f2a92d2819cd7f25e320ee2a57d23e82e6386a7760bd0074137de6d
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-03-19
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 songji.zeng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # Ollama Ruby Library
2
+
3
+ The Ollama Ruby library provides the easiest way to integrate your Ruby project with [Ollama](https://github.com/jmorganca/ollama).
4
+
5
+ ## Index
6
+
7
+ - [Ollama Ruby Library](#ollama-ruby-library)
8
+ - [Installation](#installation)
9
+ - [Usage](#usage)
10
+ - [Create a Client](#create-a-client)
11
+ - [Generate a chat completion](#generate-a-chat-completion)
12
+ - [Generate a completion](#generate-a-completion)
13
+ - [Create a Model](#create-a-model)
14
+ - [List Local Models](#list-local-models)
15
+ - [Show Model Information](#show-model-information)
16
+ - [Copy a Model](#copy-a-model)
17
+ - [Delete a Model](#delete-a-model)
18
+ - [Pull a Model](#pull-a-model)
19
+ - [Push a Model](#push-a-model)
20
+ - [Generate Embeddings](#generate-embeddings)
21
+ - [Development](#development)
22
+ - [Contributing](#contributing)
23
+ - [License](#license)
24
+
25
+ ## Installation
26
+
27
+ Install the gem and add to the application's Gemfile by executing:
28
+
29
+ ```sh
30
+ bundle add ollama-rb
31
+ ```
32
+
33
+ If bundler is not being used to manage dependencies, install the gem by executing:
34
+
35
+ ```sh
36
+ gem install ollama-rb
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### Create a Client
42
+
43
+ ```ruby
44
+ require "ollama"
45
+
46
+ ollama = Ollama::Client.new
47
+
48
+ # Specify url, default to http://localhost:11434
49
+ ollama = Ollama::Client.new(base_url: "http://localhost:11434")
50
+ ```
51
+
52
+ ### Generate a chat completion
53
+
54
+ ```ruby
55
+ response = ollama.chat.create(
56
+ model: "llama2",
57
+ messages: [
58
+ { role: "user", content: "Why is the sky blue?" }
59
+ ]
60
+ )
61
+ # => #<Ollama::Response:0x000000011fa1a840...
62
+ response.ok?
63
+ # => true
64
+ response.result
65
+ # =>
66
+ # {"model"=>"llama2",
67
+ # "created_at"=>"2024-03-20T06:53:18.298807078Z",
68
+ # "message"=>
69
+ # {"role"=>"assistant",
70
+ # "content"=> ...
71
+ ```
72
+
73
+ **Streaming response**
74
+
75
+ ```ruby
76
+ response = ollama.chat.create(
77
+ model: "llama2",
78
+ messages: [
79
+ { role: "user", content: "Why is the sky blue?" }
80
+ ]
81
+ ) do |chunk|
82
+ puts chunk
83
+ end
84
+ # =>
85
+ #{"model"=>"llama2", "created_at"=>"2024-03-20T06:57:57.513159464Z", "message"=>{"role"=>"assistant", "content"=>"\n"}, "done"=>false}
86
+ #{"model"=>"llama2", "created_at"=>"2024-03-20T06:57:57.616592691Z", "message"=>{"role"=>"assistant", "content"=>"The"}, "done"=>false}
87
+ #{"model"=>"llama2", "created_at"=>"2024-03-20T06:57:57.70737176Z", "message"=>{"role"=>"assistant", "content"=>" sky"}, "done"=>false}
88
+ #{"model"=>"llama2", "created_at"=>"2024-03-20T06:57:57.796324471Z", "message"=>{"role"=>"assistant", "content"=>" appears"}, "done"=>false}
89
+ #{"model"=>"llama2", "created_at"=>"2024-03-20T06:57:57.884097322Z", "message"=>{"role"=>"assistant", "content"=>" blue"}, "done"=>false}
90
+ # ...
91
+ ```
92
+
93
+ ### Generate a completion
94
+
95
+ ```ruby
96
+ response = ollama.completion.create(model: "llama2", prompt: "hello!")
97
+
98
+ response.result
99
+ # =>
100
+ # {"model"=>"llama2",
101
+ # "created_at"=>"2024-03-20T08:03:27.910169204Z",
102
+ # "response"=>"Hello there! It's nice to meet you. Is there something I can help you with or would you like to chat?",
103
+ # "done"=>true,
104
+ # "context"=>
105
+ # [518,
106
+ # 25580,
107
+ # 29962,
108
+ # 3532,
109
+ # ...
110
+ # 13563,
111
+ # 29973],
112
+ # "total_duration"=>6212545461,
113
+ # "load_duration"=>2024921059,
114
+ # "prompt_eval_count"=>22,
115
+ # "prompt_eval_duration"=>1815255000,
116
+ # "eval_count"=>27,
117
+ # "eval_duration"=>2371725000}
118
+ ```
119
+
120
+ **Streaming response**
121
+
122
+ ```ruby
123
+ ollama.completion.create(model: "llama2", prompt: "hello!") do |chunk|
124
+ puts chunk
125
+ end
126
+ # =>
127
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.196291424Z", "response"=>"Hello", "done"=>false}
128
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.285639365Z", "response"=>"!", "done"=>false}
129
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.3753276Z", "response"=>" It", "done"=>false}
130
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.464252328Z", "response"=>"'", "done"=>false}
131
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.552918803Z", "response"=>"s", "done"=>false}
132
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.641877239Z", "response"=>" nice", "done"=>false}
133
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.730397754Z", "response"=>" to", "done"=>false}
134
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.819209813Z", "response"=>" meet", "done"=>false}
135
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.907875913Z", "response"=>" you", "done"=>false}
136
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:01.996684973Z", "response"=>".", "done"=>false}
137
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.085516116Z", "response"=>" Is", "done"=>false}
138
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.1781973Z", "response"=>" there", "done"=>false}
139
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.267609408Z", "response"=>" something", "done"=>false}
140
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.357217892Z", "response"=>" I", "done"=>false}
141
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.446981087Z", "response"=>" can", "done"=>false}
142
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.536783282Z", "response"=>" help", "done"=>false}
143
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.645166548Z", "response"=>" you", "done"=>false}
144
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.737494769Z", "response"=>" with", "done"=>false}
145
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.82763751Z", "response"=>" or", "done"=>false}
146
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:02.917220827Z", "response"=>" would", "done"=>false}
147
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.006731978Z", "response"=>" you", "done"=>false}
148
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.098463277Z", "response"=>" like", "done"=>false}
149
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.18839214Z", "response"=>" to", "done"=>false}
150
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.277780622Z", "response"=>" chat", "done"=>false}
151
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.367252189Z", "response"=>"?", "done"=>false}
152
+ # {"model"=>"llama2", "created_at"=>"2024-03-20T08:08:03.457281303Z", "response"=>"", "done"=>true, "context"=>[518, 25580, 29962, 3532, 14816, 29903, 29958, 5299, 829, 14816, 29903, 6778, 13, 13, 12199, 29991, 518, 29914, 25580, 29962, 13, 10994, 29991, 739, 29915, 29879, 7575, 304, 5870, 366, 29889, 1317, 727, 1554, 306, 508, 1371, 366, 411, 470, 723, 366, 763, 304, 13563, 29973], "total_duration"=>2432818562, "load_duration"=>1470557, "prompt_eval_duration"=>167895000, "eval_count"=>26, "eval_duration"=>2260824000}
153
+ ```
154
+
155
+ ### Create a Model
156
+
157
+ ```ruby
158
+ ollama.models.create(name: "mario", modelfile: "FROM llama2\nSYSTEM You are mario from Super Mario Bros.") do |chunk|
159
+ puts chunk
160
+ end
161
+ # =>
162
+ # {"status"=>"reading model metadata"}
163
+ # {"status"=>"creating system layer"}
164
+ # {"status"=>"using already created layer sha256:8934d96d3f08982e95922b2b7a2c626a1fe873d7c3b06e8e56d7bc0a1fef9246"}
165
+ # {"status"=>"using already created layer sha256:8c17c2ebb0ea011be9981cc3922db8ca8fa61e828c5d3f44cb6ae342bf80460b"}
166
+ # {"status"=>"using already created layer sha256:7c23fb36d80141c4ab8cdbb61ee4790102ebd2bf7aeff414453177d4f2110e5d"}
167
+ # {"status"=>"using already created layer sha256:2e0493f67d0c8c9c68a8aeacdf6a38a2151cb3c4c1d42accf296e19810527988"}
168
+ # {"status"=>"using already created layer sha256:fa304d6750612c207b8705aca35391761f29492534e90b30575e4980d6ca82f6"}
169
+ # {"status"=>"writing layer sha256:1741cf59ce26ff01ac614d31efc700e21e44dd96aed60a7c91ab3f47e440ef94"}
170
+ # {"status"=>"writing layer sha256:786d77d232711e91aafad74df1bacc01e630525d8e83d57a758693725f08d511"}
171
+ # {"status"=>"writing manifest"}
172
+ # {"status"=>"success"}
173
+ ```
174
+
175
+ ### List Local Models
176
+
177
+ ```ruby
178
+ response = ollama.models.list
179
+ response.result
180
+ # =>
181
+ # {"models"=>
182
+ # [{"name"=>"llama2:latest",
183
+ # "model"=>"llama2:latest",
184
+ # "modified_at"=>"2024-03-19T10:37:39.212281917Z",
185
+ # "size"=>3826793677,
186
+ # "digest"=>"78e26419b4469263f75331927a00a0284ef6544c1975b826b15abdaef17bb962",
187
+ # "details"=>{"parent_model"=>"", "format"=>"gguf", "family"=>"llama", "families"=>["llama"], "parameter_size"=>"7B", "quantization_level"=>"Q4_0"}},
188
+ # {"name"=>"mario:latest",
189
+ # "model"=>"mario:latest",
190
+ # "modified_at"=>"2024-03-20T08:21:20.316403821Z",
191
+ # "size"=>3826793787,
192
+ # "digest"=>"291f46d2fa687dfaff45de96a8cb6e32707bc16ec1e1dfe8d65e9634c34c660c",
193
+ # "details"=>{"parent_model"=>"", "format"=>"gguf", "family"=>"llama", "families"=>["llama"], "parameter_size"=>"7B", "quantization_level"=>"Q4_0"}}]}
194
+ ```
195
+
196
+ ### Show Model Information
197
+
198
+ ```ruby
199
+ response = ollama.models.show("mario")
200
+ response.result
201
+ =>
202
+ {"license"=>
203
+ "LLAMA 2 COMMUNITY LICENSE AGREEMENT\t\nLlama 2 Version Release Date: July 18, 2023\n\n\"Agreement\" means the terms and conditions for use, reproduction, distribution and \nmodification of the Llama Materials set forth herein.\n\n\"...",
204
+ "modelfile"=>
205
+ "# Modelfile generated by \"ollama show\"\n# To build a new Modelfile based on this one, replace the FROM line with:\n# FROM mario:latest\n\nFROM llama2:latest\nTEMPLATE \
206
+ "\"\"[INST] <<SYS>>{{ .System }}<</SYS>>\n\n{{ .Prompt }} [/INST]\n\"\"\"\nSYSTEM \"\"\"You are mario from Super Mario Bros.\"\"\"\nPARAMETER stop \"[INST]\"\nPARAMETER stop
207
+ \"[/INST]\"\nPARAMETER stop \"<<SYS>>\"\nPARAMETER stop \"<</SYS>>\"",
208
+ "parameters"=>
209
+ "stop \"[INST]\"\nstop \"[/INST]\"\nstop \"<<SYS>>\"\nstop \"<</SYS
210
+ >>\"",
211
+ "template"=>"[INST] <<SYS>>{{ .System }}<</SYS>>\n\n{{ .Prompt }} [/INST]\n",
212
+ "system"=>"You are mario from Super Mario Bros.",
213
+ "details"=>{"parent_model"=>"llama2:latest", "format"=>"gguf", "family"=>"llama", "families"=>["llama"], "parameter_size"=>"7B", "quantization_level"=>"Q4_0"}}
214
+ ```
215
+
216
+ ### Copy a Model
217
+
218
+ ```ruby
219
+ response = ollama.models.copy(source: "llama2")
220
+ # Same as
221
+ response = ollama.models.copy(source: "llama2", destination: "llama2-backup")
222
+ response.ok?
223
+ # => true
224
+
225
+ response = ollama.models.copy(source: "non-existence")
226
+ response.ok?
227
+ # => false
228
+ response.result
229
+ # => {"error"=>"model 'non-existence' not found"}
230
+ ```
231
+
232
+ ### Delete a Model
233
+
234
+ ```ruby
235
+ response = ollama.models.delete("llama2-backup")
236
+ response.ok?
237
+ # => true
238
+
239
+ response = ollama.models.delete("non-existence")
240
+ response.ok?
241
+ # => false
242
+ response.result
243
+ # => {"error"=>"model 'non-existence' not found"}
244
+ ```
245
+
246
+ ### Pull a Model
247
+
248
+ ```ruby
249
+ ollama.models.pull(name: "tinyllama") do |chunk|
250
+ puts chunk
251
+ end
252
+ # =>
253
+ # {"status"=>"pulling manifest"}
254
+ # {"status"=>"pulling 2af3b81862c6", "digest"=>"sha256:2af3b81862c6be03c769683af18efdadb2c33f60ff32ab6f83e42c043d6c7816", "total"=>637699456, "completed"=>637699456}
255
+ # {"status"=>"pulling af0ddbdaaa26", "digest"=>"sha256:af0ddbdaaa26f30d54d727f9dd944b76bdb926fdaf9a58f63f78c532f57c191f", "total"=>70, "completed"=>70}
256
+ # {"status"=>"pulling c8472cd9daed", "digest"=>"sha256:c8472cd9daed5e7c20aa53689e441e10620a002aacd58686aeac2cb188addb5c", "total"=>31, "completed"=>31}
257
+ # {"status"=>"pulling fa956ab37b8c", "digest"=>"sha256:fa956ab37b8c21152f975a7fcdd095c4fee8754674b21d9b44d710435697a00d", "total"=>98, "completed"=>98}
258
+ # {"status"=>"pulling 6331358be52a", "digest"=>"sha256:6331358be52a6ebc2fd0755a51ad1175734fd17a628ab5ea6897109396245362", "total"=>483, "completed"=>483}
259
+ # {"status"=>"verifying sha256 digest"}
260
+ # {"status"=>"writing manifest"}
261
+ # {"status"=>"removing any unused layers"}
262
+ # {"status"=>"success"}
263
+ ```
264
+
265
+ ### Push a Model
266
+
267
+ You need to create an account at https://ollama.ai and add your Public Key at https://ollama.ai/settings/keys to allow you push models to your namespace.
268
+
269
+ ```ruby
270
+ ollama.models.copy(source: "mario", destination: "your-namespace/mario")
271
+ ollama.models.push(name: "your-namespace/mario") do |chunk|
272
+ puts chunk
273
+ end
274
+ ```
275
+
276
+ ### Generate Embeddings
277
+
278
+ ```ruby
279
+ response = ollama.embeddings.create(model: "llama2", prompt: "Hello!")
280
+ response.result
281
+ # =>
282
+ {"embedding"=>
283
+ [1.3464512825012207,
284
+ -1.0983257293701172,
285
+ ...
286
+ -2.2046988010406494, 0.3163630962371826] }
287
+ ```
288
+
289
+ ## Development
290
+
291
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
292
+
293
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
294
+
295
+ ## Contributing
296
+
297
+ Bug reports and pull requests are welcome on GitHub at https://github.com/songjiz/ollama-rb.
298
+
299
+ ## License
300
+
301
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module API
5
+ class Blobs
6
+ def initialize(client:)
7
+ @client = client
8
+ end
9
+
10
+ def create(digest)
11
+ @client.post "/api/blobs/#{digest}"
12
+ end
13
+
14
+ def exists?(digest)
15
+ response = @client.head "/api/blobs/#{digest}"
16
+ response.ok?
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module API
5
+ class Chat
6
+ def initialize(client:)
7
+ @client = client
8
+ end
9
+
10
+ def create(model:, messages:, **options, &block)
11
+ json = {
12
+ model: model,
13
+ messages: messages
14
+ }.merge(options).compact.transform_keys(&:to_sym)
15
+
16
+ json[:stream] = block_given?
17
+
18
+ @client.post "/api/chat", json: json, &block
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module API
5
+ class Completion
6
+ def initialize(client:)
7
+ @client = client
8
+ end
9
+
10
+ def create(model:, prompt:, images: [], **options, &block)
11
+ json = {
12
+ model: model,
13
+ prompt: prompt,
14
+ images: images
15
+ }.merge(options).compact.transform_keys(&:to_sym)
16
+
17
+ json[:stream] = block_given?
18
+
19
+ @client.post "/api/generate", json: json, &block
20
+ end
21
+
22
+ alias generate create
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module API
5
+ class Embeddings
6
+ def initialize(client:)
7
+ @client = client
8
+ end
9
+
10
+ def create(model:, prompt:, **options)
11
+ @client.post "/api/embeddings", json: { model: model, prompt: prompt }.merge(options).compact
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module API
5
+ class Models
6
+ def initialize(client:)
7
+ @client = client
8
+ end
9
+
10
+ def list
11
+ @client.get "/api/tags"
12
+ end
13
+
14
+ def create(name:, modelfile: nil, path: nil, &block)
15
+ @client.post "/api/create", json: { name: name, modelfile: modelfile, path: path, stream: block_given? }.compact, &block
16
+ end
17
+
18
+ def show(name)
19
+ @client.post "/api/show", json: { name: name }
20
+ end
21
+
22
+ def copy(source:, destination: nil)
23
+ @client.post "/api/copy", json: { source: source, destination: destination || "#{source}-backup" }
24
+ end
25
+
26
+ def delete(name)
27
+ @client.delete "/api/delete", json: { name: name }
28
+ end
29
+
30
+ def pull(name:, insecure: nil, &block)
31
+ @client.post "/api/pull", json: { name: name, insecure: insecure, stream: block_given? }.compact, &block
32
+ end
33
+
34
+ def push(name:, insecure: nil, &block)
35
+ @client.post "/api/push", json: { name: name, insecure: insecure, stream: block_given? }.compact, &block
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require_relative "connection"
5
+ require_relative "api/blobs"
6
+ require_relative "api/chat"
7
+ require_relative "api/completion"
8
+ require_relative "api/embeddings"
9
+ require_relative "api/models"
10
+
11
+ module Ollama
12
+ class Client
13
+ extend Forwardable
14
+
15
+ def_delegators :@connection, :post, :get, :delete, :head
16
+
17
+ def initialize(base_url: "http://localhost:11434", logger: nil, **options)
18
+ @connection = Connection.new(base_url, logger: logger, **options)
19
+ end
20
+
21
+ def chat
22
+ API::Chat.new client: self
23
+ end
24
+
25
+ def completion
26
+ API::Completion.new client: self
27
+ end
28
+
29
+ def models
30
+ API::Models.new client: self
31
+ end
32
+
33
+ def blobs
34
+ API::Blobs.new client: self
35
+ end
36
+
37
+ def embeddings
38
+ API::Embeddings.new client: self
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/https"
4
+ require "json"
5
+ require "uri"
6
+ require_relative "response"
7
+
8
+ module Ollama
9
+ class Connection
10
+ def initialize(base_url, logger: nil, **options)
11
+ @base_uri = URI.parse(base_url.to_s)
12
+ @logger = logger
13
+ @options = options
14
+ end
15
+
16
+ def post(path, json: nil, headers: {}, **options)
17
+ http = new_http
18
+ request = Net::HTTP::Post.new(path)
19
+ set_request_headers request, default_headers.merge(headers)
20
+ request.body = JSON.generate(json) if json
21
+
22
+ return Response.new(http.request(request)) unless block_given?
23
+
24
+ result = []
25
+ response = http.request(request) do |http_response|
26
+ # Raises if response is not successful
27
+ # http_response.value
28
+ http_response.read_body do |chunk|
29
+ parsed = JSON.parse(chunk)
30
+ result << parsed
31
+ yield parsed
32
+ end
33
+ end
34
+
35
+ Response.new(response).tap { |resp| resp.result = result }
36
+ end
37
+
38
+ def get(path, params: {}, headers: {}, **options)
39
+ http = new_http
40
+ query = URI.encode_www_form(params)
41
+ uri = URI.parse(path).tap { |uri| uri.query = query if query.length > 0 }
42
+ request = Net::HTTP::Get.new(uri.to_s)
43
+ set_request_headers request, default_headers.merge(headers)
44
+ Response.new http.request(request)
45
+ end
46
+
47
+ def delete(path, json: nil, headers: {}, **options)
48
+ http = new_http
49
+ request = Net::HTTP::Delete.new(path)
50
+ set_request_headers request, default_headers.merge(headers)
51
+ request.body = JSON.generate(json) if json
52
+
53
+ Response.new http.request(request)
54
+ end
55
+
56
+ def head(path, headers: {}, **options)
57
+ http = new_http
58
+ request = Net::HTTP::Head.new(path)
59
+ set_request_headers request, default_headers.merge(headers)
60
+ Response.new http.request(request)
61
+ end
62
+
63
+ private
64
+ def new_http
65
+ Net::HTTP.new(@base_uri.host, @base_uri.port).tap do |http|
66
+ http.set_debug_output @logger if @logger
67
+ end
68
+ end
69
+
70
+ def default_headers
71
+ {
72
+ "User-Agent" => USER_AGENT
73
+ }
74
+ end
75
+
76
+ def set_request_headers(request, headers)
77
+ request.tap do
78
+ headers.each do |key, value|
79
+ request[key] = value
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "json"
5
+
6
+ module Ollama
7
+ class Response
8
+ extend Forwardable
9
+ def_delegators :@http_response, :code, :body
10
+
11
+ def initialize(http_response)
12
+ @http_response = http_response
13
+ end
14
+
15
+ def ok?
16
+ code == "200"
17
+ end
18
+
19
+ def error?
20
+ !ok?
21
+ end
22
+
23
+ def result=(value)
24
+ @result = value
25
+ end
26
+
27
+ def result
28
+ @result ||= JSON.parse(body) rescue {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ VERSION = "0.1.0"
5
+ end
data/lib/ollama.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ollama/version"
4
+ require_relative "ollama/client"
5
+
6
+ module Ollama
7
+ USER_AGENT = "ollama-rb/#{VERSION}"
8
+ class Error < StandardError; end
9
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ollama-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - songji.zeng
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: The Ollama Ruby library provides the easiest way to integrate your Ruby
14
+ project with Ollama.
15
+ email:
16
+ - songji.zeng@outlook.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rubocop.yml"
22
+ - CHANGELOG.md
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/ollama.rb
27
+ - lib/ollama/api/blobs.rb
28
+ - lib/ollama/api/chat.rb
29
+ - lib/ollama/api/completion.rb
30
+ - lib/ollama/api/embeddings.rb
31
+ - lib/ollama/api/models.rb
32
+ - lib/ollama/client.rb
33
+ - lib/ollama/connection.rb
34
+ - lib/ollama/response.rb
35
+ - lib/ollama/version.rb
36
+ homepage: https://github.com/songjiz/ollama-rb
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ homepage_uri: https://github.com/songjiz/ollama-rb
41
+ source_code_uri: https://github.com/songjiz/ollama-rb
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.0.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.5.6
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Ollama Ruby library
61
+ test_files: []