omniai-google 3.21.0 → 3.22.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce2434a17917341984b99049670ef65083443c2c04b8937d2b8d4af688a5b631
4
- data.tar.gz: 6c22fa11d66efc7df6ca393bc7f167c5f682ac0398a934a6b25a8674920a6905
3
+ metadata.gz: bdc1ade66e25bb33aca449a360b70e9e0df885996022ce6ed6bc8350137cf69c
4
+ data.tar.gz: f54782298b7bd730164e437564ac3184b23eeebb5df7779c429d9cc978d68983
5
5
  SHA512:
6
- metadata.gz: f935566b3cae177f1bd445f19e2a2b87ae32d9acc274d5a5a4cb470b867c36d3e2382d9ca945f5b8e5a00a617806a1c1d4399905b642c716b2c10e9bf6dfd568
7
- data.tar.gz: b183524e4139f0a2470749fde7bb0fb837dc32cd0ca9f810af1559d44a2fbef4e62a3e5fe98e8b385de4f66559b55026a643a04371477f909ffd9bb1d45adaca
6
+ metadata.gz: 0d7b57da0258da82684ac694c35d056b77b60ac2edbf6b3146c674f84b2906d42457915672276a5c19a8ea24ec6aa7108359e224ce33660e2c5eb6bbb110b692
7
+ data.tar.gz: b577e9ce548f3cae58d0fbffea9a933c648855f48a5455c277f04d77fd842b839de095e767da1f235f648994fe265fc7814d9b7acfb1412d91d91c4b5667349d
data/README.md CHANGED
@@ -58,6 +58,30 @@ OmniAI::Google.configure do |config|
58
58
  end
59
59
  ```
60
60
 
61
+ #### Vertex Locations per Model
62
+
63
+ No single Vertex location serves every model. To route each model to its own location, set `locations`; the host is
64
+ derived from the location the way Google's SDKs do it (`global`, the `us` / `eu` multi-regions, or a single region):
65
+
66
+ ```ruby
67
+ OmniAI::Google.configure do |config|
68
+ config.credentials = File.open("./credentials.json")
69
+ config.project_id = '...'
70
+ config.locations = {
71
+ 'gemini-3.8-flash' => 'us', # https://aiplatform.us.rep.googleapis.com
72
+ 'gemini-2.5-flash' => 'us-central1', # https://us-central1-aiplatform.googleapis.com
73
+ 'gemini-embedding-001' => 'us-central1',
74
+ 'chirp_3' => 'us',
75
+ }
76
+ end
77
+ ```
78
+
79
+ - Applies to chat (including streaming), embed, transcribe and live. A mapped location is used as given.
80
+ - A model missing from the map raises `OmniAI::Google::UnknownLocationError` (with `#model`) before any request.
81
+ List every model you call, including any default you rely on (`Chat::DEFAULT_MODEL`, `Embed::DEFAULT_MODEL`,
82
+ `Transcribe::DEFAULT_MODEL`).
83
+ - A client built with an explicit `host:` or `location_id:` ignores the map.
84
+
61
85
  **Note for Transcription**: When using transcription features, ensure your service account has the necessary permissions for Google Cloud Speech-to-Text API and Google Cloud Storage (for automatic file uploads). See the [GCS Setup](#gcs-setup-for-transcription) section below for detailed configuration.
62
86
 
63
87
  Credentials may be configured using:
@@ -76,6 +76,11 @@ module OmniAI
76
76
  context.deserializers[:thinking] = ThinkingSerializer.method(:deserialize)
77
77
  end
78
78
 
79
+ # `client` is swapped for `client.for_model(model)`, so `locations` routes the request.
80
+ def initialize(prompt = nil, client:, model:, **, &)
81
+ super(prompt, client: client.for_model(model), model:, **, &)
82
+ end
83
+
79
84
  protected
80
85
 
81
86
  # @return [Context]
@@ -20,6 +20,10 @@ module OmniAI
20
20
  #
21
21
  # client = OmniAI::Google::Client.new
22
22
  class Client < OmniAI::Client
23
+ # Marks `host` / `location_id` as not passed, so an explicit value can take precedence over `locations`.
24
+ UNSET = Object.new.freeze
25
+ private_constant :UNSET
26
+
23
27
  # @!attribute [rw] version
24
28
  # @return [String, nil]
25
29
  attr_accessor :version
@@ -32,28 +36,56 @@ module OmniAI
32
36
  # @param version [String] default is `OmniAI::Google.config.version`
33
37
  # @param logger [Logger] default is `OmniAI::Google.config.logger`
34
38
  # @param timeout [Integer] default is `OmniAI::Google.config.timeout`
39
+ # @param locations [Hash{String => String}, nil] default is `OmniAI::Google.config.locations`; ignored when
40
+ # `host` or `location_id` is passed
35
41
  def initialize(
36
42
  api_key: OmniAI::Google.config.api_key,
37
43
  project_id: OmniAI::Google.config.project_id,
38
- location_id: OmniAI::Google.config.location_id,
44
+ location_id: UNSET,
39
45
  credentials: OmniAI::Google.config.credentials,
40
46
  logger: OmniAI::Google.config.logger,
41
- host: OmniAI::Google.config.host,
47
+ host: UNSET,
42
48
  version: nil,
43
- timeout: OmniAI::Google.config.timeout
49
+ timeout: OmniAI::Google.config.timeout,
50
+ locations: OmniAI::Google.config.locations
44
51
  )
45
52
  if api_key.nil? && credentials.nil?
46
53
  raise(ArgumentError, "either an `api_key` or `credentials` must be provided")
47
54
  end
48
55
 
56
+ pinned = !(UNSET.equal?(host) && UNSET.equal?(location_id))
57
+ @locations = locations unless pinned
58
+ host = OmniAI::Google.config.host if UNSET.equal?(host)
59
+ location_id = OmniAI::Google.config.location_id if UNSET.equal?(location_id)
60
+
49
61
  super(api_key:, host:, logger:, timeout:)
50
62
 
51
63
  @project_id = project_id
52
64
  @location_id = location_id
53
65
  @credentials = Credentials.parse(credentials)
66
+ @version_override = version
54
67
  @version = version || default_version
55
68
  end
56
69
 
70
+ # A copy of this client pointed at the model's location in `locations`, or this client when no map applies.
71
+ #
72
+ # @param model [String]
73
+ #
74
+ # @raise [UnknownLocationError] when the map has no entry for the model
75
+ #
76
+ # @return [Client]
77
+ def for_model(model)
78
+ return self if @locations.nil?
79
+
80
+ location_id = @locations.fetch(model) { raise UnknownLocationError, model }
81
+ dup.tap { |client| client.locate!(location_id) }
82
+ end
83
+
84
+ # @return [Boolean] true for a client returned by `#for_model`
85
+ def located?
86
+ @located || false
87
+ end
88
+
57
89
  # @raise [OmniAI::Error]
58
90
  #
59
91
  # @param messages [String] optional
@@ -155,6 +187,16 @@ module OmniAI
155
187
  false
156
188
  end
157
189
 
190
+ protected
191
+
192
+ # @param location_id [String]
193
+ def locate!(location_id)
194
+ @location_id = location_id
195
+ @host = Vertex.host(location_id)
196
+ @version = @version_override || Config::Version::STABLE
197
+ @located = true
198
+ end
199
+
158
200
  private
159
201
 
160
202
  # Vertex AI serves `v1`; the Gemini API serves `v1beta`. `OmniAI::Google.config.version` derives from the
@@ -19,6 +19,12 @@ module OmniAI
19
19
  # @return [String, nil]
20
20
  attr_accessor :location_id
21
21
 
22
+ # @!attribute [rw] locations
23
+ # Vertex location per model, e.g. `{ "gemini-3.8-flash" => "us" }`. When set, each request derives its host
24
+ # from the model's location, and a model missing from the map raises `UnknownLocationError`.
25
+ # @return [Hash{String => String}, nil]
26
+ attr_accessor :locations
27
+
22
28
  # @param api_key [String, nil] optional - defaults to `ENV['GOOGLE_API_KEY']`
23
29
  # @param project_id [String, nil] optional - defaults to `ENV['GOOGLE_PROJECT_ID']`
24
30
  # @param location_id [String, nil] optional - defaults to `ENV['GOOGLE_LOCATION_ID']`
@@ -72,6 +72,11 @@ module OmniAI
72
72
  context.deserializers[:usage] = USAGE_METADATA_DESERIALIZER
73
73
  end
74
74
 
75
+ # `client` is swapped for `client.for_model(model)`, so `locations` routes the request.
76
+ def initialize(input, client:, model:, **)
77
+ super(input, client: client.for_model(model), model:, **)
78
+ end
79
+
75
80
  protected
76
81
 
77
82
  # Determines which endpoint to use based on client and model configuration.
@@ -76,7 +76,7 @@ module OmniAI
76
76
  # @yieldparam event [Live::Event::*]
77
77
  def initialize(client:, model: DEFAULT_MODEL, system: nil, tools: nil, tool_behavior: :blocking, voice: nil,
78
78
  transcription: true, vad: nil, compression: false, resumption: nil, write_timeout: WRITE_TIMEOUT, &handler)
79
- @client = client
79
+ @client = client.for_model(model)
80
80
  @model = model
81
81
  @system = system
82
82
  @tools = tools || []
@@ -54,7 +54,7 @@ module OmniAI
54
54
  def initialize(io, client:, model:, language: nil, format: nil, diarization: false, word_timestamps: false,
55
55
  vocabulary: nil)
56
56
  @io = io
57
- @client = client
57
+ @client = client.for_model(model)
58
58
  @model = model
59
59
  @language = language
60
60
  @format = format || OmniAI::Transcribe::Format::JSON
@@ -92,8 +92,12 @@ module OmniAI
92
92
  # Served from the global endpoint and the us/eu multi-regions, never a single region, so a zonal Vertex
93
93
  # location_id maps to its multi-region (same rule as Chirp 3); `us` is the default.
94
94
  #
95
- # @return [String] "global", "us" or "eu"
95
+ # A location from `locations` is used as given.
96
+ #
97
+ # @return [String] "global", "us" or "eu", unless mapped
96
98
  def gemini_location_id
99
+ return @client.instance_variable_get(:@location_id) if @client.located?
100
+
97
101
  case @client.instance_variable_get(:@location_id)
98
102
  when "global" then "global"
99
103
  when /\A(eu|europe)/i then "eu"
@@ -103,8 +107,7 @@ module OmniAI
103
107
 
104
108
  # @return [String]
105
109
  def host
106
- location = gemini_location_id
107
- location == "global" ? "https://aiplatform.googleapis.com" : "https://aiplatform.#{location}.rep.googleapis.com"
110
+ Vertex.host(gemini_location_id)
108
111
  end
109
112
 
110
113
  # @return [String]
@@ -49,6 +49,11 @@ module OmniAI
49
49
  super
50
50
  end
51
51
 
52
+ # `client` is swapped for `client.for_model(model)`, so `locations` routes the request.
53
+ def initialize(io, client:, model:, **)
54
+ super(io, client: client.for_model(model), model:, **)
55
+ end
56
+
52
57
  # @raise [HTTPError]
53
58
  #
54
59
  # @return [OmniAI::Transcribe::Transcription]
@@ -12,8 +12,12 @@ module OmniAI
12
12
  raise(ArgumentError, "project_id is required for transcription")
13
13
  end
14
14
 
15
+ # A location from `locations` is used as given; otherwise it is derived per model.
16
+ #
15
17
  # @return [String]
16
18
  def location_id
19
+ return @client.instance_variable_get(:@location_id) if @client.located?
20
+
17
21
  case @model
18
22
  when "chirp_2"
19
23
  "us-central1"
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ module Google
5
+ # Raised before any request when `locations` is configured but has no entry for the model.
6
+ class UnknownLocationError < OmniAI::Error
7
+ # @return [String]
8
+ attr_reader :model
9
+
10
+ # @param model [String]
11
+ def initialize(model)
12
+ @model = model
13
+ super("no location configured for model #{model.inspect}")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAI
4
4
  module Google
5
- VERSION = "3.21.0"
5
+ VERSION = "3.22.0"
6
6
  end
7
7
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ module Google
5
+ # Vertex AI endpoints.
6
+ module Vertex
7
+ MULTI_REGIONS = %w[us eu].freeze
8
+
9
+ # The host serving a location, derived the way Google's own SDKs do (google-genai, vertexai).
10
+ #
11
+ # @param location_id [String] e.g. "global", "us" or "us-central1"
12
+ #
13
+ # @return [String]
14
+ def self.host(location_id)
15
+ if location_id.eql?("global")
16
+ "https://aiplatform.googleapis.com"
17
+ elsif MULTI_REGIONS.include?(location_id)
18
+ "https://aiplatform.#{location_id}.rep.googleapis.com"
19
+ else
20
+ "https://#{location_id}-aiplatform.googleapis.com"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniai-google
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.21.0
4
+ version: 3.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
@@ -144,9 +144,11 @@ files:
144
144
  - lib/omniai/google/transcribe.rb
145
145
  - lib/omniai/google/transcribe/gemini.rb
146
146
  - lib/omniai/google/transcribe_helpers.rb
147
+ - lib/omniai/google/unknown_location_error.rb
147
148
  - lib/omniai/google/upload.rb
148
149
  - lib/omniai/google/upload/file.rb
149
150
  - lib/omniai/google/version.rb
151
+ - lib/omniai/google/vertex.rb
150
152
  homepage: https://github.com/ksylvest/omniai-google
151
153
  licenses:
152
154
  - MIT