CODE WITH SIBIN

Solving Real Problems with Real Code


Spring Boot with Spring AI and Vertex AI Embedding Guide

This guide will help you set up and understand a Spring Boot application that integrates with Spring AI and Google Vertex AI's embedding capabilities.

Prerequisites

  • Java 17 JDK installed
  • Maven installed (version 3.6.3 or later)
  • Google Cloud account with Vertex AI enabled
  • Google Cloud SDK installed and configured (for local development)

1. Project Setup

Final pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>vertex-ai-embedding-service</artifactId>
    <version>1.0.0</version>
    <name>Vertex AI Embedding Service</name>

    <properties>
        <java.version>17</java.version>
        <spring-ai.version>0.8.1</spring-ai.version>
    </properties>

    <dependencies>
        <!-- Core -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Vertex AI Embedding -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-vertex-ai-embedding</artifactId>
        </dependency>

        <!-- Lombok (Optional) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. Configuration (application.yml)

spring:
  ai:
    vertex:
      ai:
        embedding:
          enabled: true
          project-id: ${GCP_PROJECT_ID:your-project-id}
          location: ${GCP_LOCATION:us-central1}
          credentials:
            resource: ${GCP_CREDENTIALS_PATH:classpath:gcp-service-account.json}
          options:
            model: textembedding-gecko@latest  # or textembedding-gecko@003
            dimensions: 768  # Optional: Match your model's output dimensions

logging:
  level:
    org.springframework.ai: DEBUG  # Useful for debugging API calls

3. Code Implementation

(A) Embedding Request/Response DTOs

// EmbeddingRequest.java
@Data  // Lombok (or manually write getters/setters)
public class EmbeddingRequest {
    @NotBlank
    private String text;
}
// EmbeddingResponse.java
@Data
public class EmbeddingResponse {
    private List<Double> embedding;
    private String model;
    private Integer tokenCount;
}

(B) Service Layer (EmbeddingService)

@Service
@RequiredArgsConstructor  // Lombok (or use constructor injection)
public class EmbeddingService {
    private final EmbeddingClient embeddingClient;

    public EmbeddingResponse generateEmbedding(String text) {
        EmbeddingResponse embeddingResponse = embeddingClient.embedForResponse(List.of(text));
        
        return EmbeddingResponse.builder()
                .embedding(embeddingResponse.getResults().get(0).getOutput())
                .model("textembedding-gecko")
                .tokenCount(embeddingResponse.getMetadata().getUsage().getPromptTokens())
                .build();
    }
}

(C) REST API (EmbeddingController)

@RestController
@RequestMapping("/api/embeddings")
@RequiredArgsConstructor
public class EmbeddingController {
    private final EmbeddingService embeddingService;

    @PostMapping
    public ResponseEntity<EmbeddingResponse> createEmbedding(
            @Valid @RequestBody EmbeddingRequest request
    ) {
        return ResponseEntity.ok(embeddingService.generateEmbedding(request.getText()));
    }
}

4. Testing

(A) Unit Test (EmbeddingServiceTest)

@ExtendWith(MockitoExtension.class)
class EmbeddingServiceTest {
    @Mock
    private EmbeddingClient embeddingClient;
    
    @InjectMocks
    private EmbeddingService embeddingService;

    @Test
    void testGenerateEmbedding() {
        // Mock response
        EmbeddingResponse mockResponse = new EmbeddingResponse(
            List.of(new Embedding(List.of(0.1, 0.2, 0.3), 1)),
            new Usage(10, 0, 10)
        );
        
        when(embeddingClient.embedForResponse(anyList()))
            .thenReturn(mockResponse);

        // Test
        EmbeddingResponse response = embeddingService.generateEmbedding("test");
        
        // Assertions
        assertEquals(3, response.getEmbedding().size());
        assertEquals(10, response.getTokenCount());
    }
}

(B) Integration Test (EmbeddingControllerIT)

@SpringBootTest
@AutoConfigureMockMvc
class EmbeddingControllerIT {
    @Autowired
    private MockMvc mockMvc;

    @Test
    void testEmbeddingEndpoint() throws Exception {
        mockMvc.perform(post("/api/embeddings")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"text\": \"sample text\"}"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.embedding").exists());
    }
}

5. Running

Run Locally

export GCP_PROJECT_ID=your-project-id
export GCP_LOCATION=us-central1
export GCP_CREDENTIALS_PATH=/path/to/service-account.json

mvn spring-boot:run

6. Postman Testing

  • EndpointPOST /api/embeddings
  • Body:
{
    "text": "This is a test sentence for embeddings."
}
  • Response:
{
    "embedding": [0.12, -0.34, ...],
    "model": "textembedding-gecko",
    "tokenCount": 8
}

Leave a Reply

Your email address will not be published. Required fields are marked *