Skip to content

Commit 512dff7

Browse files
authored
BAEL-9368: Google Cloud and Spring AI (#18744)
1 parent b1586ab commit 512dff7

13 files changed

+304
-2
lines changed

spring-ai-4/pom.xml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161
<groupId>org.springframework.ai</groupId>
6262
<artifactId>spring-ai-starter-model-openai</artifactId>
6363
</dependency>
64+
<dependency>
65+
<groupId>org.springframework.ai</groupId>
66+
<artifactId>spring-ai-starter-model-vertex-ai-gemini</artifactId>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.springframework.ai</groupId>
70+
<artifactId>spring-ai-starter-model-vertex-ai-embedding</artifactId>
71+
</dependency>
6472
<dependency>
6573
<groupId>org.springframework.ai</groupId>
6674
<artifactId>spring-ai-model-chat-memory-repository-jdbc</artifactId>
@@ -89,6 +97,12 @@
8997
<spring.boot.mainclass>com.baeldung.springai.memory.Application</spring.boot.mainclass>
9098
</properties>
9199
</profile>
100+
<profile>
101+
<id>vertexai</id>
102+
<properties>
103+
<spring.boot.mainclass>com.baeldung.springai.vertexai.Application</spring.boot.mainclass>
104+
</properties>
105+
</profile>
92106
</profiles>
93107

94108
<build>
@@ -113,7 +127,7 @@
113127
<properties>
114128
<junit-jupiter.version>5.9.0</junit-jupiter.version>
115129
<spring-boot.version>3.5.0</spring-boot.version>
116-
<spring-ai.version>1.0.0</spring-ai.version>
130+
<spring-ai.version>1.0.1</spring-ai.version>
117131
</properties>
118132

119133
</project>

spring-ai-4/src/main/java/com/baeldung/springai/memory/Application.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55

6-
@SpringBootApplication
6+
@SpringBootApplication(exclude = {
7+
org.springframework.ai.model.vertexai.autoconfigure.embedding.VertexAiMultiModalEmbeddingAutoConfiguration.class,
8+
org.springframework.ai.model.vertexai.autoconfigure.embedding.VertexAiTextEmbeddingAutoConfiguration.class,
9+
org.springframework.ai.model.vertexai.autoconfigure.gemini.VertexAiGeminiChatAutoConfiguration.class,
10+
})
711
public class Application {
812

913
public static void main(String[] args) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication(exclude = {
7+
org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration.class,
8+
org.springframework.ai.model.openai.autoconfigure.OpenAiAudioTranscriptionAutoConfiguration.class,
9+
org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration.class,
10+
org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration.class,
11+
org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration.class,
12+
org.springframework.ai.model.openai.autoconfigure.OpenAiModerationAutoConfiguration.class
13+
})
14+
public class Application {
15+
16+
public static void main(String[] args) {
17+
SpringApplication app = new SpringApplication(Application.class);
18+
app.setAdditionalProfiles("vertexai");
19+
app.run(args);
20+
}
21+
22+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import javax.validation.constraints.NotNull;
4+
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.PostMapping;
7+
import org.springframework.web.bind.annotation.RequestBody;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
@RestController
11+
public class ChatController {
12+
13+
private final ChatService chatService;
14+
15+
public ChatController(ChatService chatService) {
16+
this.chatService = chatService;
17+
}
18+
19+
@PostMapping("/chat")
20+
public ResponseEntity<String> chat(@RequestBody @NotNull String prompt) {
21+
String response = chatService.chat(prompt);
22+
return ResponseEntity.ok(response);
23+
}
24+
25+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import org.springframework.ai.chat.client.ChatClient;
4+
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
5+
import org.springframework.ai.chat.memory.ChatMemory;
6+
import org.springframework.ai.chat.model.ChatModel;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.web.context.annotation.SessionScope;
9+
10+
@Component
11+
@SessionScope
12+
public class ChatService {
13+
14+
private final ChatClient chatClient;
15+
16+
public ChatService(ChatModel chatModel, ChatMemory chatMemory) {
17+
this.chatClient = ChatClient.builder(chatModel)
18+
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
19+
.build();
20+
}
21+
22+
public String chat(String prompt) {
23+
return chatClient.prompt()
24+
.user(userMessage -> userMessage.text(prompt))
25+
.call()
26+
.content();
27+
}
28+
29+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import javax.validation.constraints.NotNull;
4+
5+
import org.springframework.ai.embedding.EmbeddingResponse;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.util.MimeType;
8+
import org.springframework.web.bind.annotation.PostMapping;
9+
import org.springframework.web.bind.annotation.RequestParam;
10+
import org.springframework.web.bind.annotation.RestController;
11+
import org.springframework.web.multipart.MultipartFile;
12+
13+
@RestController
14+
public class MultiModalEmbeddingController {
15+
16+
private final MultiModalEmbeddingService embeddingService;
17+
18+
public MultiModalEmbeddingController(MultiModalEmbeddingService embeddingService) {
19+
this.embeddingService = embeddingService;
20+
}
21+
22+
@PostMapping("/embedding/image")
23+
public ResponseEntity<EmbeddingResponse> getEmbedding(@RequestParam("image") @NotNull MultipartFile imageFile) {
24+
EmbeddingResponse response = embeddingService.getEmbedding(
25+
MimeType.valueOf(imageFile.getContentType()),
26+
imageFile.getResource());
27+
return ResponseEntity.ok(response);
28+
}
29+
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
import org.springframework.ai.content.Media;
7+
import org.springframework.ai.document.Document;
8+
import org.springframework.ai.embedding.DocumentEmbeddingModel;
9+
import org.springframework.ai.embedding.DocumentEmbeddingRequest;
10+
import org.springframework.ai.embedding.EmbeddingResponse;
11+
import org.springframework.core.io.Resource;
12+
import org.springframework.stereotype.Service;
13+
import org.springframework.util.MimeType;
14+
15+
@Service
16+
public class MultiModalEmbeddingService {
17+
18+
private final DocumentEmbeddingModel documentEmbeddingModel;
19+
20+
public MultiModalEmbeddingService(DocumentEmbeddingModel documentEmbeddingModel) {
21+
this.documentEmbeddingModel = documentEmbeddingModel;
22+
}
23+
24+
public EmbeddingResponse getEmbedding(MimeType mimeType, Resource resource) {
25+
Document document = new Document(new Media(mimeType, resource), Map.of());
26+
DocumentEmbeddingRequest request = new DocumentEmbeddingRequest(List.of(document));
27+
return documentEmbeddingModel.call(request);
28+
}
29+
30+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import javax.validation.constraints.NotNull;
4+
5+
import org.springframework.ai.embedding.EmbeddingResponse;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.web.bind.annotation.PostMapping;
8+
import org.springframework.web.bind.annotation.RequestBody;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
@RestController
12+
public class TextEmbeddingController {
13+
14+
private final TextEmbeddingService textEmbeddingService;
15+
16+
public TextEmbeddingController(TextEmbeddingService textEmbeddingService) {
17+
this.textEmbeddingService = textEmbeddingService;
18+
}
19+
20+
@PostMapping("/embedding/text")
21+
public ResponseEntity<EmbeddingResponse> getEmbedding(@RequestBody @NotNull String text) {
22+
EmbeddingResponse response = textEmbeddingService.getEmbedding(text);
23+
return ResponseEntity.ok(response);
24+
}
25+
26+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.springai.vertexai;
2+
3+
import java.util.Arrays;
4+
5+
import org.springframework.ai.embedding.EmbeddingModel;
6+
import org.springframework.ai.embedding.EmbeddingRequest;
7+
import org.springframework.ai.embedding.EmbeddingResponse;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
public class TextEmbeddingService {
12+
13+
private final EmbeddingModel embeddingModel;
14+
15+
public TextEmbeddingService(EmbeddingModel embeddingModel) {
16+
this.embeddingModel = embeddingModel;
17+
}
18+
19+
public EmbeddingResponse getEmbedding(String... texts) {
20+
EmbeddingRequest request = new EmbeddingRequest(Arrays.asList(texts), null);
21+
return embeddingModel.call(request);
22+
}
23+
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
spring:
2+
ai:
3+
vertex:
4+
ai:
5+
gemini:
6+
project-id: "c1-lumion"
7+
location: "europe-west1"
8+
model: "gemini-2.0-flash-lite"
9+
embedding:
10+
project-id: "c1-lumion"
11+
location: "europe-west1"
12+
text:
13+
options:
14+
model: "gemini-embedding-001"

0 commit comments

Comments
 (0)