ollama-ai 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module Errors
5
+ class OllamaError < StandardError
6
+ def initialize(message = nil)
7
+ super(message)
8
+ end
9
+ end
10
+
11
+ class BlockWithoutServerSentEventsError < OllamaError; end
12
+
13
+ class RequestError < OllamaError
14
+ attr_reader :request, :payload
15
+
16
+ def initialize(message = nil, request: nil, payload: nil)
17
+ @request = request
18
+ @payload = payload
19
+
20
+ super(message)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ require_relative '../ports/dsl/ollama-ai/errors'
7
+
8
+ module Ollama
9
+ module Controllers
10
+ class Client
11
+ DEFAULT_ADDRESS = 'http://localhost:11434'
12
+
13
+ ALLOWED_REQUEST_OPTIONS = %i[timeout open_timeout read_timeout write_timeout].freeze
14
+
15
+ def initialize(config)
16
+ @server_sent_events = config.dig(:options, :server_sent_events)
17
+
18
+ @address = if config[:credentials][:address].nil? || config[:credentials][:address].to_s.strip.empty?
19
+ "#{DEFAULT_ADDRESS}/"
20
+ else
21
+ "#{config[:credentials][:address].to_s.sub(%r{/$}, '')}/"
22
+ end
23
+
24
+ @request_options = config.dig(:options, :connection, :request)
25
+
26
+ @request_options = if @request_options.is_a?(Hash)
27
+ @request_options.select do |key, _|
28
+ ALLOWED_REQUEST_OPTIONS.include?(key)
29
+ end
30
+ else
31
+ {}
32
+ end
33
+ end
34
+
35
+ def generate(payload, server_sent_events: nil, &callback)
36
+ request('api/generate', payload, server_sent_events:, &callback)
37
+ end
38
+
39
+ def chat(payload, server_sent_events: nil, &callback)
40
+ request('api/chat', payload, server_sent_events:, &callback)
41
+ end
42
+
43
+ def create(payload, server_sent_events: nil, &callback)
44
+ request('api/create', payload, server_sent_events:, &callback)
45
+ end
46
+
47
+ def tags(server_sent_events: nil, &callback)
48
+ request('api/tags', nil, server_sent_events:, request_method: 'GET', &callback)
49
+ end
50
+
51
+ def show(payload, server_sent_events: nil, &callback)
52
+ request('api/show', payload, server_sent_events:, &callback)
53
+ end
54
+
55
+ def copy(payload, server_sent_events: nil, &callback)
56
+ request('api/copy', payload, server_sent_events:, &callback)
57
+ true
58
+ end
59
+
60
+ def delete(payload, server_sent_events: nil, &callback)
61
+ request('api/delete', payload, server_sent_events:, request_method: 'DELETE', &callback)
62
+ true
63
+ end
64
+
65
+ def pull(payload, server_sent_events: nil, &callback)
66
+ request('api/pull', payload, server_sent_events:, &callback)
67
+ end
68
+
69
+ def push(payload, server_sent_events: nil, &callback)
70
+ request('api/push', payload, server_sent_events:, &callback)
71
+ end
72
+
73
+ def embeddings(payload, server_sent_events: nil, &callback)
74
+ request('api/embeddings', payload, server_sent_events:, &callback)
75
+ end
76
+
77
+ def request(path, payload = nil, server_sent_events: nil, request_method: 'POST', &callback)
78
+ server_sent_events_enabled = server_sent_events.nil? ? @server_sent_events : server_sent_events
79
+ url = "#{@address}#{path}"
80
+
81
+ if !callback.nil? && !server_sent_events_enabled
82
+ raise BlockWithoutServerSentEventsError,
83
+ 'You are trying to use a block without Server Sent Events (SSE) enabled.'
84
+ end
85
+
86
+ results = []
87
+
88
+ method_to_call = request_method.to_s.strip.downcase.to_sym
89
+
90
+ partial_json = ''
91
+
92
+ response = Faraday.new(request: @request_options) do |faraday|
93
+ faraday.response :raise_error
94
+ end.send(method_to_call) do |request|
95
+ request.url url
96
+ request.headers['Content-Type'] = 'application/json'
97
+
98
+ request.body = payload.to_json unless payload.nil?
99
+
100
+ if server_sent_events_enabled
101
+ request.options.on_data = proc do |chunk, bytes, env|
102
+ if env && env.status != 200
103
+ raise_error = Faraday::Response::RaiseError.new
104
+ raise_error.on_complete(env.merge(body: chunk))
105
+ end
106
+
107
+ partial_json += chunk
108
+
109
+ parsed_json = safe_parse_json(partial_json)
110
+
111
+ if parsed_json
112
+ result = { event: parsed_json, raw: { chunk:, bytes:, env: } }
113
+
114
+ callback.call(result[:event], result[:raw]) unless callback.nil?
115
+
116
+ results << result
117
+
118
+ partial_json = ''
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ return safe_parse_jsonl(response.body) unless server_sent_events_enabled
125
+
126
+ results.map { |result| result[:event] }
127
+ rescue Faraday::Error => e
128
+ raise RequestError.new(e.message, request: e, payload:)
129
+ end
130
+
131
+ def safe_parse_json(raw)
132
+ raw.to_s.lstrip.start_with?('{', '[') ? JSON.parse(raw) : nil
133
+ rescue JSON::ParserError
134
+ nil
135
+ end
136
+
137
+ def safe_parse_jsonl(raw)
138
+ raw.to_s.lstrip.start_with?('{', '[') ? raw.split("\n").map { |line| JSON.parse(line) } : raw
139
+ rescue JSON::ParserError
140
+ raw
141
+ end
142
+ end
143
+ end
144
+ end
data/ollama-ai.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'static/gem'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = Ollama::GEM[:name]
7
+ spec.version = Ollama::GEM[:version]
8
+ spec.authors = [Ollama::GEM[:author]]
9
+
10
+ spec.summary = Ollama::GEM[:summary]
11
+ spec.description = Ollama::GEM[:description]
12
+
13
+ spec.homepage = Ollama::GEM[:github]
14
+
15
+ spec.license = Ollama::GEM[:license]
16
+
17
+ spec.required_ruby_version = Gem::Requirement.new(">= #{Ollama::GEM[:ruby]}")
18
+
19
+ spec.metadata['allowed_push_host'] = Ollama::GEM[:gem_server]
20
+
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] = Ollama::GEM[:github]
23
+
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ f.match(%r{\A(?:test|spec|features)/})
27
+ end
28
+ end
29
+
30
+ spec.require_paths = ['ports/dsl']
31
+
32
+ spec.add_dependency 'faraday', '~> 2.8'
33
+
34
+ spec.metadata['rubygems_mfa_required'] = 'true'
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../components/errors'
4
+
5
+ include Ollama::Errors
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../static/gem'
4
+ require_relative '../../controllers/client'
5
+
6
+ module Ollama
7
+ def self.new(...)
8
+ Controllers::Client.new(...)
9
+ end
10
+
11
+ def self.version
12
+ Ollama::GEM[:version]
13
+ end
14
+ end
data/static/gem.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ GEM = {
5
+ name: 'ollama-ai',
6
+ version: '1.0.0',
7
+ author: 'gbaptista',
8
+ summary: 'Interact with Ollama API to run open source AI models locally.',
9
+ description: "A Ruby gem for interacting with Ollama's API that allows you to run open source AI LLMs (Large Language Models) locally.",
10
+ github: 'https://github.com/gbaptista/ollama-ai',
11
+ gem_server: 'https://rubygems.org',
12
+ license: 'MIT',
13
+ ruby: '3.1.0'
14
+ }.freeze
15
+ end
@@ -0,0 +1,39 @@
1
+ (require '[clojure.string :as str])
2
+
3
+ (defn slugify [text]
4
+ (-> text
5
+ (clojure.string/lower-case)
6
+ (clojure.string/replace " " "-")
7
+ (clojure.string/replace #"[^a-z0-9\-_]" "")))
8
+
9
+ (defn remove-code-blocks [content]
10
+ (let [code-block-regex #"(?s)```.*?```"]
11
+ (clojure.string/replace content code-block-regex "")))
12
+
13
+ (defn process-line [line]
14
+ (when-let [[_ hashes title] (re-find #"^(\#{2,}) (.+)" line)]
15
+ (let [link (slugify title)]
16
+ {:level (count hashes) :title title :link link})))
17
+
18
+ (defn create-index [content]
19
+ (let [processed-content (remove-code-blocks content)
20
+ processed-lines (->> processed-content
21
+ clojure.string/split-lines
22
+ (map process-line)
23
+ (remove nil?))]
24
+ (->> processed-lines
25
+ (map (fn [{:keys [level title link]}]
26
+ (str (apply str (repeat (* 4 (- level 2)) " "))
27
+ "- ["
28
+ title
29
+ "](#"
30
+ link
31
+ ")")))
32
+ (clojure.string/join "\n"))))
33
+
34
+
35
+ (let [content (slurp "template.md")
36
+ index (create-index content)
37
+ updated-content (clojure.string/replace content "{index}" index)]
38
+ (spit "README.md" updated-content)
39
+ (println "README.md successfully generated."))