gemini-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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +85 -0
- data/LICENSE +9 -0
- data/README.md +547 -0
- data/controllers/client.rb +84 -0
- data/gemini-ai.gemspec +37 -0
- data/ports/dsl/gemini-ai.rb +14 -0
- data/static/gem.rb +15 -0
- data/tasks/generate-readme.clj +39 -0
- data/template.md +528 -0
- metadata +114 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'event_stream_parser'
|
4
|
+
require 'faraday'
|
5
|
+
require 'json'
|
6
|
+
require 'googleauth'
|
7
|
+
|
8
|
+
module Gemini
|
9
|
+
module Controllers
|
10
|
+
class Client
|
11
|
+
def initialize(config)
|
12
|
+
@authorizer = ::Google::Auth::ServiceAccountCredentials.make_creds(
|
13
|
+
json_key_io: File.open(config[:credentials][:file_path]),
|
14
|
+
scope: 'https://www.googleapis.com/auth/cloud-platform'
|
15
|
+
)
|
16
|
+
|
17
|
+
@address = "https://#{config[:credentials][:region]}-aiplatform.googleapis.com/v1/projects/#{config[:credentials][:project_id]}/locations/#{config[:credentials][:region]}/publishers/google/models/#{config[:settings][:model]}"
|
18
|
+
|
19
|
+
@stream = config[:settings][:stream]
|
20
|
+
end
|
21
|
+
|
22
|
+
def stream_generate_content(payload, stream: nil, &callback)
|
23
|
+
request('streamGenerateContent', payload, stream:, &callback)
|
24
|
+
end
|
25
|
+
|
26
|
+
def request(path, payload, stream: nil, &callback)
|
27
|
+
stream_enabled = stream.nil? ? @stream : stream
|
28
|
+
url = "#{@address}:#{path}"
|
29
|
+
url += '?alt=sse' if stream_enabled
|
30
|
+
|
31
|
+
if !callback.nil? && !stream_enabled
|
32
|
+
raise StandardError, 'You are trying to use a block without stream enabled."'
|
33
|
+
end
|
34
|
+
|
35
|
+
results = []
|
36
|
+
|
37
|
+
response = Faraday.new.post do |request|
|
38
|
+
request.url url
|
39
|
+
request.headers['Content-Type'] = 'application/json'
|
40
|
+
request.headers['Authorization'] = "Bearer #{@authorizer.fetch_access_token!['access_token']}"
|
41
|
+
request.body = payload.to_json
|
42
|
+
|
43
|
+
if stream_enabled
|
44
|
+
parser = EventStreamParser::Parser.new
|
45
|
+
|
46
|
+
request.options.on_data = proc do |chunk, bytes, env|
|
47
|
+
if env && env.status != 200
|
48
|
+
raise_error = Faraday::Response::RaiseError.new
|
49
|
+
raise_error.on_complete(env.merge(body: chunk))
|
50
|
+
end
|
51
|
+
|
52
|
+
parser.feed(chunk) do |type, data, id, reconnection_time|
|
53
|
+
parsed_data = safe_parse_json(data)
|
54
|
+
result = {
|
55
|
+
event: safe_parse_json(data),
|
56
|
+
parsed: { type:, data:, id:, reconnection_time: },
|
57
|
+
raw: { chunk:, bytes:, env: }
|
58
|
+
}
|
59
|
+
|
60
|
+
callback.call(result[:event], result[:parsed], result[:raw]) unless callback.nil?
|
61
|
+
|
62
|
+
results << result
|
63
|
+
|
64
|
+
parsed_data['candidates'].find do |candidate|
|
65
|
+
!candidate['finishReason'].nil? && candidate['finishReason'] != ''
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
return safe_parse_json(response.body) unless stream_enabled
|
73
|
+
|
74
|
+
results.map { |result| result[:event] }
|
75
|
+
end
|
76
|
+
|
77
|
+
def safe_parse_json(raw)
|
78
|
+
raw.start_with?('{', '[') ? JSON.parse(raw) : raw
|
79
|
+
rescue JSON::ParserError
|
80
|
+
raw
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/gemini-ai.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'static/gem'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = Gemini::GEM[:name]
|
7
|
+
spec.version = Gemini::GEM[:version]
|
8
|
+
spec.authors = [Gemini::GEM[:author]]
|
9
|
+
|
10
|
+
spec.summary = Gemini::GEM[:summary]
|
11
|
+
spec.description = Gemini::GEM[:description]
|
12
|
+
|
13
|
+
spec.homepage = Gemini::GEM[:github]
|
14
|
+
|
15
|
+
spec.license = Gemini::GEM[:license]
|
16
|
+
|
17
|
+
spec.required_ruby_version = Gem::Requirement.new(">= #{Gemini::GEM[:ruby]}")
|
18
|
+
|
19
|
+
spec.metadata['allowed_push_host'] = Gemini::GEM[:gem_server]
|
20
|
+
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
spec.metadata['source_code_uri'] = Gemini::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 'event_stream_parser', '~> 1.0'
|
33
|
+
spec.add_dependency 'faraday', '~> 2.7', '>= 2.7.12'
|
34
|
+
spec.add_dependency 'googleauth', '~> 1.9', '>= 1.9.1'
|
35
|
+
|
36
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
37
|
+
end
|
data/static/gem.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gemini
|
4
|
+
GEM = {
|
5
|
+
name: 'gemini-ai',
|
6
|
+
version: '1.0.0',
|
7
|
+
author: 'gbaptista',
|
8
|
+
summary: "Interact with Google's Gemini AI.",
|
9
|
+
description: "A Ruby Gem for interacting with Gemini through Vertex AI, Google's generative AI service.",
|
10
|
+
github: 'https://github.com/gbaptista/gemini-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."))
|