Skip to content

Commit ae9d3f4

Browse files
committed
Updgrade Vertex AI Gemini to 26.37.0
- Adjust to the new, breaking, API changes. - Update the docs adding the transport endpoint and scopes to the connection properties.
1 parent 0b04c89 commit ae9d3f4

File tree

8 files changed

+94
-49
lines changed

8 files changed

+94
-49
lines changed

models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatClient.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import com.fasterxml.jackson.annotation.JsonInclude;
2525
import com.fasterxml.jackson.annotation.JsonInclude.Include;
26-
import com.google.cloud.vertexai.Transport;
2726
import com.google.cloud.vertexai.VertexAI;
2827
import com.google.cloud.vertexai.api.Content;
2928
import com.google.cloud.vertexai.api.FunctionCall;
@@ -146,8 +145,6 @@ public ChatResponse call(Prompt prompt) {
146145

147146
var geminiRequest = createGeminiRequest(prompt);
148147

149-
// GenerateContentResponse response =
150-
// this.chatCompletionWithFunctionCallSupport(geminiRequest);
151148
GenerateContentResponse response = this.callWithFunctionSupport(geminiRequest);
152149

153150
List<Generation> generations = response.getCandidatesList()
@@ -168,7 +165,7 @@ public Flux<ChatResponse> stream(Prompt prompt) {
168165
var request = createGeminiRequest(prompt);
169166

170167
ResponseStream<GenerateContentResponse> responseStream = request.model
171-
.generateContentStream(request.contents, request.config);
168+
.generateContentStream(request.contents);
172169

173170
return Flux.fromStream(responseStream.stream()).map(response -> {
174171
response = handleFunctionCallOrReturn(request, response);
@@ -193,7 +190,7 @@ private VertexAiChatResponseMetadata toChatResponseMetadata(GenerateContentRespo
193190
}
194191

195192
@JsonInclude(Include.NON_NULL)
196-
public record GeminiRequest(List<Content> contents, GenerativeModel model, GenerationConfig config) {
193+
public record GeminiRequest(List<Content> contents, GenerativeModel model) {
197194
}
198195

199196
private GeminiRequest createGeminiRequest(Prompt prompt) {
@@ -202,7 +199,8 @@ private GeminiRequest createGeminiRequest(Prompt prompt) {
202199

203200
GenerationConfig generationConfig = this.generationConfig;
204201

205-
GenerativeModel generativeModel = new GenerativeModel(this.defaultOptions.getModel(), this.vertexAI);
202+
var generativeModelBuilder = new GenerativeModel.Builder().setModelName(this.defaultOptions.getModel())
203+
.setVertexAi(this.vertexAI);
206204

207205
VertexAiGeminiChatOptions updatedRuntimeOptions = null;
208206

@@ -237,14 +235,8 @@ private GeminiRequest createGeminiRequest(Prompt prompt) {
237235

238236
if (StringUtils.hasText(updatedRuntimeOptions.getModel())
239237
&& !updatedRuntimeOptions.getModel().equals(this.defaultOptions.getModel())) {
240-
generativeModel = new GenerativeModel(updatedRuntimeOptions.getModel(), vertexAI);
241-
}
242-
243-
if (updatedRuntimeOptions.getTransportType() != null) {
244-
Transport transport = (updatedRuntimeOptions
245-
.getTransportType() == VertexAiGeminiChatOptions.TransportType.GRPC) ? Transport.GRPC
246-
: Transport.REST;
247-
generativeModel.setTransport(transport);
238+
// Override model name
239+
generativeModelBuilder.setModelName(updatedRuntimeOptions.getModel());
248240
}
249241

250242
generationConfig = toGenerationConfig(updatedRuntimeOptions);
@@ -253,10 +245,14 @@ private GeminiRequest createGeminiRequest(Prompt prompt) {
253245
// Add the enabled functions definitions to the request's tools parameter.
254246
if (!CollectionUtils.isEmpty(functionsForThisRequest)) {
255247
List<Tool> tools = this.getFunctionTools(functionsForThisRequest);
256-
generativeModel.setTools(tools);
248+
generativeModelBuilder.setTools(tools);
257249
}
258250

259-
return new GeminiRequest(toGeminiContent(prompt), generativeModel, generationConfig);
251+
generativeModelBuilder.setGenerationConfig(generationConfig);
252+
253+
GenerativeModel generativeModel = generativeModelBuilder.build();
254+
255+
return new GeminiRequest(toGeminiContent(prompt), generativeModel);
260256
}
261257

262258
private GenerationConfig toGenerationConfig(VertexAiGeminiChatOptions options) {
@@ -429,7 +425,7 @@ protected GeminiRequest doCreateToolResponseRequest(GeminiRequest previousReques
429425

430426
conversationHistory.add(contentFnResp);
431427

432-
return new GeminiRequest(conversationHistory, previousRequest.model(), previousRequest.config());
428+
return new GeminiRequest(conversationHistory, previousRequest.model());
433429
}
434430

435431
@Override
@@ -445,7 +441,7 @@ protected Content doGetToolResponseMessage(GenerateContentResponse response) {
445441
@Override
446442
protected GenerateContentResponse doChatCompletion(GeminiRequest request) {
447443
try {
448-
return request.model.generateContent(request.contents, request.config);
444+
return request.model.generateContent(request.contents);
449445
}
450446
catch (Exception e) {
451447
throw new RuntimeException("Failed to generate content", e);

models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatOptions.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ public enum TransportType {
9999
@JsonIgnore
100100
private Set<String> functions = new HashSet<>();
101101

102-
/**
103-
* The transport type to use for the Gemini Chat Client.
104-
*/
105-
private TransportType transportType = TransportType.GRPC;
106102
// @formatter:on
107103

108104
public static Builder builder() {
@@ -165,11 +161,6 @@ public Builder withFunction(String functionName) {
165161
return this;
166162
}
167163

168-
public Builder withTransportType(TransportType transportType) {
169-
this.options.setTransportType(transportType);
170-
return this;
171-
}
172-
173164
public VertexAiGeminiChatOptions build() {
174165
return this.options;
175166
}
@@ -257,14 +248,6 @@ public void setFunctions(Set<String> functions) {
257248
this.functions = functions;
258249
}
259250

260-
public TransportType getTransportType() {
261-
return this.transportType;
262-
}
263-
264-
public void setTransportType(TransportType transportType) {
265-
this.transportType = transportType;
266-
}
267-
268251
@Override
269252
public int hashCode() {
270253
final int prime = 31;
@@ -278,7 +261,6 @@ public int hashCode() {
278261
result = prime * result + ((model == null) ? 0 : model.hashCode());
279262
result = prime * result + ((functionCallbacks == null) ? 0 : functionCallbacks.hashCode());
280263
result = prime * result + ((functions == null) ? 0 : functions.hashCode());
281-
result = prime * result + ((transportType == null) ? 0 : transportType.hashCode());
282264
return result;
283265
}
284266

@@ -345,8 +327,6 @@ else if (!functionCallbacks.equals(other.functionCallbacks))
345327
}
346328
else if (!functions.equals(other.functions))
347329
return false;
348-
if (transportType != other.transportType)
349-
return false;
350330
return true;
351331
}
352332

models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatClientIT.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Map;
2222
import java.util.stream.Collectors;
2323

24+
import com.google.cloud.vertexai.Transport;
2425
import com.google.cloud.vertexai.VertexAI;
2526
import org.junit.jupiter.api.Test;
2627
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
@@ -37,7 +38,6 @@
3738
import org.springframework.ai.parser.BeanOutputParser;
3839
import org.springframework.ai.parser.ListOutputParser;
3940
import org.springframework.ai.parser.MapOutputParser;
40-
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions.TransportType;
4141
import org.springframework.beans.factory.annotation.Autowired;
4242
import org.springframework.beans.factory.annotation.Value;
4343
import org.springframework.boot.SpringBootConfiguration;
@@ -224,15 +224,17 @@ public static class TestConfiguration {
224224
public VertexAI vertexAiApi() {
225225
String projectId = System.getenv("VERTEX_AI_GEMINI_PROJECT_ID");
226226
String location = System.getenv("VERTEX_AI_GEMINI_LOCATION");
227-
return new VertexAI(projectId, location);
227+
return new VertexAI.Builder().setProjectId(projectId)
228+
.setLocation(location)
229+
.setTransport(Transport.REST)
230+
.build();
228231
}
229232

230233
@Bean
231234
public VertexAiGeminiChatClient vertexAiEmbedding(VertexAI vertexAi) {
232235
return new VertexAiGeminiChatClient(vertexAi,
233236
VertexAiGeminiChatOptions.builder()
234237
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO_VISION.getValue())
235-
.withTransportType(TransportType.REST)
236238
.build());
237239
}
238240

models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/function/VertexAiGeminiChatClientFunctionCallingIT.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.List;
2020
import java.util.stream.Collectors;
2121

22+
import com.google.cloud.vertexai.Transport;
2223
import com.google.cloud.vertexai.VertexAI;
2324
import org.junit.jupiter.api.AfterEach;
2425
import org.junit.jupiter.api.Test;
@@ -37,7 +38,6 @@
3738
import org.springframework.ai.model.function.FunctionCallbackWrapper.Builder.SchemaType;
3839
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient;
3940
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions;
40-
import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatOptions.TransportType;
4141
import org.springframework.beans.factory.annotation.Autowired;
4242
import org.springframework.boot.SpringBootConfiguration;
4343
import org.springframework.boot.test.context.SpringBootTest;
@@ -185,7 +185,10 @@ public static class TestConfiguration {
185185
public VertexAI vertexAiApi() {
186186
String projectId = System.getenv("VERTEX_AI_GEMINI_PROJECT_ID");
187187
String location = System.getenv("VERTEX_AI_GEMINI_LOCATION");
188-
return new VertexAI(projectId, location);
188+
return new VertexAI.Builder().setLocation(location)
189+
.setProjectId(projectId)
190+
.setTransport(Transport.REST)
191+
.build();
189192
}
190193

191194
@Bean
@@ -194,7 +197,6 @@ public VertexAiGeminiChatClient vertexAiEmbedding(VertexAI vertexAi) {
194197
VertexAiGeminiChatOptions.builder()
195198
.withModel(VertexAiGeminiChatClient.ChatModel.GEMINI_PRO.getValue())
196199
.withTemperature(0.9f)
197-
.withTransportType(TransportType.REST)
198200
.build());
199201
}
200202

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
<jackson.version>2.16.1</jackson.version>
128128
<djl.version>0.26.0</djl.version>
129129
<onnxruntime.version>1.17.0</onnxruntime.version>
130-
<com.google.cloud.version>26.34.0</com.google.cloud.version>
130+
<com.google.cloud.version>26.37.0</com.google.cloud.version>
131131
<qdrant.version>1.7.1</qdrant.version>
132132
<spring-retry.version>2.0.5</spring-retry.version>
133133
<ibm.sdk.version>9.20.0</ibm.sdk.version>

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/vertexai-gemini-chat.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ The prefix `spring.ai.vertex.ai.gemini` is used as the property prefix that lets
5454
| spring.ai.vertex.ai.gemini.projectId | Google Cloud Platform project ID | -
5555
| spring.ai.vertex.ai.gemini.location | Region | -
5656
| spring.ai.vertex.ai.gemini.credentialsUri | URI to Vertex AI Gemini credentials. When provided it is used to create an a `GoogleCredentials` instance to authenticate the `VertexAI`. | -
57+
| spring.ai.vertex.ai.gemini.apiEndpoint | Vertex AI Gemini API endpoint. | -
58+
| spring.ai.vertex.ai.gemini.scopes | | -
59+
| spring.ai.vertex.ai.gemini.transport | API transport. GRPC or REST. | GRPC
5760
|====
5861

5962
The prefix `spring.ai.vertex.ai.gemini.chat` is the property prefix that lets you configure the chat client implementation for VertexAI Gemini Chat.

spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vertexai/gemini/VertexAiGeminiAutoConfiguration.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.context.annotation.Bean;
3333
import org.springframework.util.Assert;
3434
import org.springframework.util.CollectionUtils;
35+
import org.springframework.util.StringUtils;
3536

3637
/**
3738
* Auto-configuration for Vertex AI Gemini Chat.
@@ -49,15 +50,26 @@ public VertexAI vertexAi(VertexAiGeminiConnectionProperties connectionProperties
4950

5051
Assert.hasText(connectionProperties.getProjectId(), "Vertex AI project-id must be set!");
5152
Assert.hasText(connectionProperties.getLocation(), "Vertex AI location must be set!");
53+
Assert.notNull(connectionProperties.getTransport(), "Vertex AI transport must be set!");
54+
55+
var vertexAIBuilder = new VertexAI.Builder().setProjectId(connectionProperties.getProjectId())
56+
.setLocation(connectionProperties.getLocation())
57+
.setTransport(com.google.cloud.vertexai.Transport.valueOf(connectionProperties.getTransport().name()));
58+
59+
if (StringUtils.hasText(connectionProperties.getApiEndpoint())) {
60+
vertexAIBuilder.setApiEndpoint(connectionProperties.getApiEndpoint());
61+
}
62+
if (!CollectionUtils.isEmpty(connectionProperties.getScopes())) {
63+
vertexAIBuilder.setScopes(connectionProperties.getScopes());
64+
}
5265

5366
if (connectionProperties.getCredentialsUri() != null) {
5467
GoogleCredentials credentials = GoogleCredentials
5568
.fromStream(connectionProperties.getCredentialsUri().getInputStream());
56-
return new VertexAI(connectionProperties.getProjectId(), connectionProperties.getLocation(), credentials);
57-
}
58-
else {
59-
return new VertexAI(connectionProperties.getProjectId(), connectionProperties.getLocation());
69+
70+
vertexAIBuilder.setCredentials(credentials);
6071
}
72+
return vertexAIBuilder.build();
6173
}
6274

6375
@Bean

spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vertexai/gemini/VertexAiGeminiConnectionProperties.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.ai.autoconfigure.vertexai.gemini;
1717

18+
import java.util.List;
19+
1820
import org.springframework.boot.context.properties.ConfigurationProperties;
1921
import org.springframework.core.io.Resource;
2022

@@ -44,6 +46,30 @@ public class VertexAiGeminiConnectionProperties {
4446
*/
4547
private Resource credentialsUri;
4648

49+
/**
50+
* Vertex AI Gemini API endpoint.
51+
*/
52+
private String apiEndpoint;
53+
54+
/**
55+
*
56+
*/
57+
private List<String> scopes = List.of();
58+
59+
private Transport transport = Transport.GRPC;
60+
61+
public enum Transport {
62+
63+
/** When used, the clients will send REST requests to the backing service. */
64+
REST,
65+
/**
66+
* When used, the clients will send gRPC to the backing service. This is usually
67+
* more efficient and is the default transport.
68+
*/
69+
GRPC
70+
71+
}
72+
4773
public String getProjectId() {
4874
return this.projectId;
4975
}
@@ -68,4 +94,28 @@ public void setCredentialsUri(Resource credentialsUri) {
6894
this.credentialsUri = credentialsUri;
6995
}
7096

97+
public String getApiEndpoint() {
98+
return this.apiEndpoint;
99+
}
100+
101+
public List<String> getScopes() {
102+
return this.scopes;
103+
}
104+
105+
public void setScopes(List<String> scopes) {
106+
this.scopes = scopes;
107+
}
108+
109+
public void setApiEndpoint(String apiEndpoint) {
110+
this.apiEndpoint = apiEndpoint;
111+
}
112+
113+
public Transport getTransport() {
114+
return this.transport;
115+
}
116+
117+
public void setTransport(Transport transport) {
118+
this.transport = transport;
119+
}
120+
71121
}

0 commit comments

Comments
 (0)