diff --git a/spring-ai-3/pom.xml b/spring-ai-3/pom.xml index 6070046f9d00..0f9130fff820 100644 --- a/spring-ai-3/pom.xml +++ b/spring-ai-3/pom.xml @@ -43,34 +43,6 @@ org.springframework.boot spring-boot-starter-web - - org.springframework.ai - spring-ai-markdown-document-reader - - - org.springframework.ai - spring-ai-mcp-client-spring-boot-starter - - - org.springframework.ai - spring-ai-mcp-server-webmvc-spring-boot-starter - - - org.springframework.ai - spring-ai-ollama-spring-boot-starter - - - org.springframework.ai - spring-ai-chroma-store-spring-boot-starter - - - org.springframework.ai - spring-ai-anthropic-spring-boot-starter - - - org.springframework.ai - spring-ai-bedrock-converse-spring-boot-starter - org.springframework.boot spring-boot-starter-data-jpa @@ -84,10 +56,6 @@ hsqldb runtime - - org.springframework.ai - spring-ai-pgvector-store-spring-boot-starter - org.springframework.ai spring-ai-starter-model-openai @@ -122,80 +90,20 @@ org.springframework.ai - spring-ai-starter-vector-store-mongodb-atlas + spring-ai-starter-vector-store-mongodb-atlas ${spring-ai-mongodb-atlas.version} - - chromadb - - true - - - com.baeldung.springai.chromadb.Application - - - - assistant - - com.baeldung.spring.ai.om.OrderManagementApplication - - - - anthropic - - com.baeldung.springai.anthropic.Application - - - - deepseek - - com.baeldung.springai.deepseek.Application - - - - evaluator - - com.baeldung.springai.evaluator.Application - - - - hugging-face - - com.baeldung.springai.huggingface.Application - - - - mcp-server - - com.baeldung.springai.mcp.server.ServerApplication - - - - mcp-client - - com.baeldung.springai.mcp.client.ClientApplication - - - - amazon-nova - - com.baeldung.springai.nova.Application - - - - pgvector - - com.baeldung.springai.semanticsearch.Application - - transcribe com.baeldung.springai.transcribe.Application + + true + diff --git a/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/Application.java b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/Application.java new file mode 100644 index 000000000000..2a42f2584e73 --- /dev/null +++ b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/Application.java @@ -0,0 +1,25 @@ +package com.baeldung.springai.embeddings; + +import org.springframework.ai.autoconfigure.chat.client.ChatClientAutoConfiguration; +import org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; + +@SpringBootApplication(exclude = { + ChatClientAutoConfiguration.class, + MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, + org.springframework.ai.autoconfigure.vectorstore.mongo.MongoDBAtlasVectorStoreAutoConfiguration.class, + org.springframework.ai.vectorstore.mongodb.autoconfigure.MongoDBAtlasVectorStoreAutoConfiguration.class, + OpenAiAudioSpeechAutoConfiguration.class}) +class Application { + + public static void main(String[] args) { + SpringApplication app = new SpringApplication(Application.class); + app.setAdditionalProfiles("embeddings"); + app.run(args); + } + +} \ No newline at end of file diff --git a/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingConfig.java b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingConfig.java new file mode 100644 index 000000000000..652599bc3362 --- /dev/null +++ b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingConfig.java @@ -0,0 +1,29 @@ +package com.baeldung.springai.embeddings; + +import org.springframework.ai.document.MetadataMode; +import org.springframework.ai.openai.OpenAiEmbeddingModel; +import org.springframework.ai.openai.OpenAiEmbeddingOptions; +import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EmbeddingConfig { + + @Bean + public OpenAiApi openAiApi(@Value("${spring.ai.openai.api-key}") String apiKey) { + return OpenAiApi.builder() + .apiKey(apiKey) + .build(); + } + + @Bean + public OpenAiEmbeddingModel openAiEmbeddingModel(OpenAiApi openAiApi) { + OpenAiEmbeddingOptions options = OpenAiEmbeddingOptions.builder() + .model("text-embedding-3-small") + .build(); + return new OpenAiEmbeddingModel(openAiApi, MetadataMode.EMBED, options); + } + +} diff --git a/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingController.java b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingController.java new file mode 100644 index 000000000000..61010b39ce7d --- /dev/null +++ b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingController.java @@ -0,0 +1,32 @@ +package com.baeldung.springai.embeddings; + +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class EmbeddingController { + + private final EmbeddingService embeddingService; + private final ManualEmbeddingService manualEmbeddingService; + + public EmbeddingController(EmbeddingService embeddingService, ManualEmbeddingService manualEmbeddingService) { + this.embeddingService = embeddingService; + this.manualEmbeddingService = manualEmbeddingService; + } + + @PostMapping("/embeddings") + public ResponseEntity getEmbeddings(@RequestBody String text) { + EmbeddingResponse response = embeddingService.getEmbeddings(text); + return ResponseEntity.ok(response); + } + + @PostMapping("/manual-embeddings") + public ResponseEntity getManualEmbeddings(@RequestBody String text) { + EmbeddingResponse response = manualEmbeddingService.getEmbeddings(text); + return ResponseEntity.ok(response); + } + +} diff --git a/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingService.java b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingService.java new file mode 100644 index 000000000000..6b97891c3b06 --- /dev/null +++ b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/EmbeddingService.java @@ -0,0 +1,24 @@ +package com.baeldung.springai.embeddings; + +import java.util.Arrays; + +import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.embedding.EmbeddingRequest; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.stereotype.Service; + +@Service +public class EmbeddingService { + + private final EmbeddingModel embeddingModel; + + public EmbeddingService(EmbeddingModel embeddingModel) { + this.embeddingModel = embeddingModel; + } + + public EmbeddingResponse getEmbeddings(String... texts) { + EmbeddingRequest request = new EmbeddingRequest(Arrays.asList(texts), null); + return embeddingModel.call(request); + } + +} diff --git a/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/ManualEmbeddingService.java b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/ManualEmbeddingService.java new file mode 100644 index 000000000000..4ffa84f502cd --- /dev/null +++ b/spring-ai-3/src/main/java/com/baeldung/springai/embeddings/ManualEmbeddingService.java @@ -0,0 +1,24 @@ +package com.baeldung.springai.embeddings; + +import java.util.Arrays; + +import org.springframework.ai.embedding.EmbeddingRequest; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.ai.openai.OpenAiEmbeddingModel; +import org.springframework.stereotype.Service; + +@Service +public class ManualEmbeddingService { + + private final OpenAiEmbeddingModel openAiEmbeddingModel; + + public ManualEmbeddingService(OpenAiEmbeddingModel openAiEmbeddingModel) { + this.openAiEmbeddingModel = openAiEmbeddingModel; + } + + public EmbeddingResponse getEmbeddings(String... texts) { + EmbeddingRequest request = new EmbeddingRequest(Arrays.asList(texts), null); + return openAiEmbeddingModel.call(request); + } + +} \ No newline at end of file diff --git a/spring-ai-3/src/main/resources/application-embeddings.yml b/spring-ai-3/src/main/resources/application-embeddings.yml new file mode 100644 index 000000000000..4f37323cb6e3 --- /dev/null +++ b/spring-ai-3/src/main/resources/application-embeddings.yml @@ -0,0 +1,12 @@ +spring: + ai: + openai: + api-key: "" + embedding: + options: + model: "text-embedding-3-small" + + # Avoid starting docker from the shared codebase + docker: + compose: + enabled: false diff --git a/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/EmbeddingServiceLiveTest.java b/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/EmbeddingServiceLiveTest.java new file mode 100644 index 000000000000..91405c322e43 --- /dev/null +++ b/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/EmbeddingServiceLiveTest.java @@ -0,0 +1,27 @@ +package com.baeldung.springai.embeddings; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("embeddings") +class EmbeddingServiceLiveTest { + + @Autowired + private EmbeddingService embeddingService; + + @Test + void whenGetEmbeddings_thenReturnEmbeddingResponse() { + String text = "This is a test string for embedding."; + EmbeddingResponse response = embeddingService.getEmbeddings(text); + assertThat(response).isNotNull(); + assertThat(response.getResults()).isNotNull(); + assertThat(response.getResults().isEmpty()).isFalse(); + } + +} \ No newline at end of file diff --git a/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/ManualEmbeddingServiceLiveTest.java b/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/ManualEmbeddingServiceLiveTest.java new file mode 100644 index 000000000000..fd8fe35a0d4f --- /dev/null +++ b/spring-ai-3/src/test/java/com/baeldung/springai/embeddings/ManualEmbeddingServiceLiveTest.java @@ -0,0 +1,27 @@ +package com.baeldung.springai.embeddings; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("embeddings") +class ManualEmbeddingServiceLiveTest { + + @Autowired + private ManualEmbeddingService embeddingService; + + @Test + void whenGetEmbeddings_thenReturnEmbeddingResponse() { + String text = "This is a test string for embedding."; + EmbeddingResponse response = embeddingService.getEmbeddings(text); + assertThat(response).isNotNull(); + assertThat(response.getResults()).isNotNull(); + assertThat(response.getResults().isEmpty()).isFalse(); + } + +} \ No newline at end of file