gemini-ai 3.2.0 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.",
|