gemini-ai 3.2.0 → 4.1.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 +4 -4
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +47 -25
- data/README.md +430 -46
- data/components/errors.rb +2 -1
- data/controllers/client.rb +85 -16
- data/gemini-ai.gemspec +5 -1
- data/static/gem.rb +1 -1
- data/tasks/generate-readme.clj +1 -1
- data/template.md +387 -13
- metadata +9 -2
data/controllers/client.rb
CHANGED
@@ -21,16 +21,24 @@ module Gemini
|
|
21
21
|
@service = config[:credentials][:service]
|
22
22
|
|
23
23
|
unless %w[vertex-ai-api generative-language-api].include?(@service)
|
24
|
-
raise Errors::UnsupportedServiceError, "Unsupported service: #{@service}"
|
24
|
+
raise Errors::UnsupportedServiceError, "Unsupported service: '#{@service}'."
|
25
25
|
end
|
26
26
|
|
27
|
+
avoid_conflicting_credentials!(config[:credentials])
|
28
|
+
|
27
29
|
if config[:credentials][:api_key]
|
28
30
|
@authentication = :api_key
|
29
31
|
@api_key = config[:credentials][:api_key]
|
30
|
-
elsif config[:credentials][:file_path]
|
32
|
+
elsif config[:credentials][:file_path] || config[:credentials][:file_contents]
|
31
33
|
@authentication = :service_account
|
34
|
+
json_key_io = if config[:credentials][:file_path]
|
35
|
+
File.open(config[:credentials][:file_path])
|
36
|
+
else
|
37
|
+
StringIO.new(config[:credentials][:file_contents])
|
38
|
+
end
|
39
|
+
|
32
40
|
@authorizer = ::Google::Auth::ServiceAccountCredentials.make_creds(
|
33
|
-
json_key_io
|
41
|
+
json_key_io:,
|
34
42
|
scope: 'https://www.googleapis.com/auth/cloud-platform'
|
35
43
|
)
|
36
44
|
else
|
@@ -46,12 +54,19 @@ module Gemini
|
|
46
54
|
|
47
55
|
@service_version = config.dig(:credentials, :version) || DEFAULT_SERVICE_VERSION
|
48
56
|
|
49
|
-
@
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
57
|
+
@base_address = case @service
|
58
|
+
when 'vertex-ai-api'
|
59
|
+
"https://#{config[:credentials][:region]}-aiplatform.googleapis.com/#{@service_version}/projects/#{@project_id}/locations/#{config[:credentials][:region]}"
|
60
|
+
when 'generative-language-api'
|
61
|
+
"https://generativelanguage.googleapis.com/#{@service_version}"
|
62
|
+
end
|
63
|
+
|
64
|
+
@model_address = case @service
|
65
|
+
when 'vertex-ai-api'
|
66
|
+
"publishers/google/models/#{config[:options][:model]}"
|
67
|
+
when 'generative-language-api'
|
68
|
+
"models/#{config[:options][:model]}"
|
69
|
+
end
|
55
70
|
|
56
71
|
@server_sent_events = config.dig(:options, :server_sent_events)
|
57
72
|
|
@@ -68,21 +83,74 @@ module Gemini
|
|
68
83
|
end
|
69
84
|
end
|
70
85
|
|
86
|
+
def avoid_conflicting_credentials!(credentials)
|
87
|
+
conflicting_keys = %i[api_key file_path file_contents]
|
88
|
+
|
89
|
+
found = credentials.keys.filter { |key| conflicting_keys.include?(key) }
|
90
|
+
|
91
|
+
return unless found.size > 1
|
92
|
+
|
93
|
+
message = found.sort.each_with_index.map do |key, i|
|
94
|
+
i == found.size - 1 ? "or '#{key}'" : "'#{key}'"
|
95
|
+
end.join(', ')
|
96
|
+
|
97
|
+
raise Errors::ConflictingCredentialsError,
|
98
|
+
"You must choose either #{message}."
|
99
|
+
end
|
100
|
+
|
101
|
+
def predict(payload, server_sent_events: nil, &callback)
|
102
|
+
result = request(
|
103
|
+
"#{@model_address}:predict", payload,
|
104
|
+
server_sent_events:, &callback
|
105
|
+
)
|
106
|
+
|
107
|
+
return result.first if result.is_a?(Array) && result.size == 1
|
108
|
+
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
def embed_content(payload, server_sent_events: nil, &callback)
|
113
|
+
result = request(
|
114
|
+
"#{@model_address}:embedContent", payload,
|
115
|
+
server_sent_events:, &callback
|
116
|
+
)
|
117
|
+
|
118
|
+
return result.first if result.is_a?(Array) && result.size == 1
|
119
|
+
|
120
|
+
result
|
121
|
+
end
|
122
|
+
|
71
123
|
def stream_generate_content(payload, server_sent_events: nil, &callback)
|
72
|
-
request(
|
124
|
+
request("#{@model_address}:streamGenerateContent", payload, server_sent_events:, &callback)
|
125
|
+
end
|
126
|
+
|
127
|
+
def models(_server_sent_events: nil, &callback)
|
128
|
+
result = request(
|
129
|
+
'models',
|
130
|
+
nil, server_sent_events: false, request_method: 'GET', &callback
|
131
|
+
)
|
132
|
+
|
133
|
+
return result.first if result.is_a?(Array) && result.size == 1
|
134
|
+
|
135
|
+
result
|
73
136
|
end
|
74
137
|
|
75
138
|
def generate_content(payload, server_sent_events: nil, &callback)
|
76
|
-
result = request(
|
139
|
+
result = request(
|
140
|
+
"#{@model_address}:generateContent", payload,
|
141
|
+
server_sent_events:, &callback
|
142
|
+
)
|
77
143
|
|
78
144
|
return result.first if result.is_a?(Array) && result.size == 1
|
79
145
|
|
80
146
|
result
|
81
147
|
end
|
82
148
|
|
83
|
-
def request(path, payload, server_sent_events: nil, &callback)
|
149
|
+
def request(path, payload, server_sent_events: nil, request_method: 'POST', &callback)
|
84
150
|
server_sent_events_enabled = server_sent_events.nil? ? @server_sent_events : server_sent_events
|
85
|
-
|
151
|
+
|
152
|
+
url = "#{@base_address}/#{path}"
|
153
|
+
|
86
154
|
params = []
|
87
155
|
|
88
156
|
params << 'alt=sse' if server_sent_events_enabled
|
@@ -97,20 +165,21 @@ module Gemini
|
|
97
165
|
|
98
166
|
results = []
|
99
167
|
|
168
|
+
method_to_call = request_method.to_s.strip.downcase.to_sym
|
169
|
+
|
100
170
|
response = Faraday.new(request: @request_options) do |faraday|
|
101
171
|
faraday.adapter @faraday_adapter
|
102
172
|
faraday.response :raise_error
|
103
|
-
end.
|
173
|
+
end.send(method_to_call) do |request|
|
104
174
|
request.url url
|
105
175
|
request.headers['Content-Type'] = 'application/json'
|
106
176
|
if @authentication == :service_account || @authentication == :default_credentials
|
107
177
|
request.headers['Authorization'] = "Bearer #{@authorizer.fetch_access_token!['access_token']}"
|
108
178
|
end
|
109
179
|
|
110
|
-
request.body = payload.to_json
|
180
|
+
request.body = payload.to_json unless payload.nil?
|
111
181
|
|
112
182
|
if server_sent_events_enabled
|
113
|
-
|
114
183
|
partial_json = ''
|
115
184
|
|
116
185
|
parser = EventStreamParser::Parser.new
|
data/gemini-ai.gemspec
CHANGED
@@ -30,9 +30,13 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.require_paths = ['ports/dsl']
|
31
31
|
|
32
32
|
spec.add_dependency 'event_stream_parser', '~> 1.0'
|
33
|
-
spec.add_dependency 'faraday', '~> 2.9'
|
33
|
+
spec.add_dependency 'faraday', '~> 2.9', '>= 2.9.2'
|
34
34
|
spec.add_dependency 'faraday-typhoeus', '~> 1.1'
|
35
|
+
|
36
|
+
# Before upgrading, check this:
|
37
|
+
# https://github.com/gbaptista/gemini-ai/pull/10
|
35
38
|
spec.add_dependency 'googleauth', '~> 1.8'
|
39
|
+
|
36
40
|
spec.add_dependency 'typhoeus', '~> 1.4', '>= 1.4.1'
|
37
41
|
|
38
42
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
data/static/gem.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Gemini
|
4
4
|
GEM = {
|
5
5
|
name: 'gemini-ai',
|
6
|
-
version: '
|
6
|
+
version: '4.1.0',
|
7
7
|
author: 'gbaptista',
|
8
8
|
summary: "Interact with Google's Gemini AI.",
|
9
9
|
description: "A Ruby Gem for interacting with Gemini through Vertex AI, Generative Language API, or AI Studio, Google's generative AI services.",
|