├── .github ├── dependabot.yml └── workflows │ └── commit-stage.yml ├── .gitignore ├── .sdkmanrc ├── LICENSE ├── README.md ├── buildSrc └── build.gradle ├── data-ingestion ├── document-readers │ ├── document-readers-json-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── DocumentReadersJsonOllamaApplication.java │ │ │ │ │ ├── IngestionPipeline.java │ │ │ │ │ └── SearchController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── documents │ │ │ │ ├── bikes-1.json │ │ │ │ ├── bikes-2.json │ │ │ │ └── bikes-3.json │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── DocumentReadersJsonOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── document-readers-markdown-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── DocumentReadersMarkdownOllamaApplication.java │ │ │ │ │ ├── IngestionPipeline.java │ │ │ │ │ └── SearchController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── documents │ │ │ │ ├── story1.md │ │ │ │ └── story2.md │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── DocumentReadersMarkdownOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── document-readers-pdf-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── DocumentReadersPdfOllamaApplication.java │ │ │ │ │ ├── IngestionPipeline.java │ │ │ │ │ └── SearchController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── documents │ │ │ │ ├── story1.pdf │ │ │ │ └── story2.pdf │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── DocumentReadersPdfOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── document-readers-text-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── DocumentReadersTextOllamaApplication.java │ │ │ │ │ ├── IngestionPipeline.java │ │ │ │ │ └── SearchController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── documents │ │ │ │ ├── story1.md │ │ │ │ └── story2.txt │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── DocumentReadersTextOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── document-readers-tika-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── DocumentReadersTikaOllamaApplication.java │ │ │ │ ├── IngestionPipeline.java │ │ │ │ └── SearchController.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── documents │ │ │ ├── story1.md │ │ │ └── story2.pdf │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── DocumentReadersTikaOllamaApplicationTests.java │ │ └── resources │ │ └── application-test.yml └── document-transformers │ ├── document-transformers-metadata-ollama │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── DocumentTransformersMetadataOllamaApplication.java │ │ │ │ ├── IngestionPipeline.java │ │ │ │ └── SearchController.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── documents │ │ │ ├── story1.md │ │ │ └── story2.txt │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── DocumentTransformersMetadataOllamaApplicationTests.java │ │ └── resources │ │ └── application-test.yml │ └── document-transformers-splitters-ollama │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── DocumentTransformersSplittersOllamaApplication.java │ │ │ ├── IngestionPipeline.java │ │ │ └── SearchController.java │ └── resources │ │ ├── application.yml │ │ └── documents │ │ ├── story1.md │ │ └── story2.txt │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── DocumentTransformersSplittersOllamaApplicationTests.java │ └── resources │ └── application-test.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mcp └── mcp-clients │ └── mcp-brave │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── ChatController.java │ │ │ ├── McpBraveApplication.java │ │ │ └── model │ │ │ └── ChatModelController.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── McpBraveApplicationTests.java │ └── resources │ └── application-test.yml ├── models ├── audio │ ├── speech-to-text-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── TextToSpeechOpenAiApplication.java │ │ │ │ │ └── TranscriptionController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ ├── speech1.mp3 │ │ │ │ └── speech2.mp3 │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── TextToSpeechOpenAiApplicationTests.java │ └── text-to-speech-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── SpeechController.java │ │ │ │ └── SpeechToTextOpenAiApplication.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── SpeechToTextOpenAiApplicationTests.java ├── chat │ ├── chat-mistral-ai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── ChatMistralAiApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── ChatMistralAiApplicationTests.java │ ├── chat-multiple-providers │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── ChatMultipleProvidersApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── ChatMultipleProvidersApplicationTests.java │ ├── chat-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── ChatOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── ChatOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── chat-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── ChatController.java │ │ │ │ ├── ChatOpenAiApplication.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── ChatOpenAiApplicationTests.java ├── embedding │ ├── embedding-mistral-ai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── EmbeddingController.java │ │ │ │ │ └── EmbeddingMistralAiApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── EmbeddingMistralAiApplicationTests.java │ ├── embedding-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── EmbeddingController.java │ │ │ │ │ └── EmbeddingOllamaApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── EmbeddingOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── embedding-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── EmbeddingController.java │ │ │ │ │ └── EmbeddingOpenAiApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── EmbeddingOpenAiApplicationTests.java │ └── embedding-transformers │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── EmbeddingController.java │ │ │ │ └── EmbeddingTransformersApplication.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── EmbeddingTransformersApplicationTests.java └── image │ └── image-openai │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── ImageController.java │ │ │ └── ImageOpenAiApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── thomasvitale │ └── ai │ └── spring │ └── ImageOpenAiApplicationTests.java ├── observability ├── models │ ├── observability-models-mistral-ai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── BookService.java │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── EmbeddingController.java │ │ │ │ │ ├── Functions.java │ │ │ │ │ └── ObservabilityModelsMistralAiApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── ObservabilityModelsMistralAiApplicationTests.java │ ├── observability-models-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── BookService.java │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── EmbeddingController.java │ │ │ │ │ ├── ObservabilityModelsOllamaApplication.java │ │ │ │ │ └── Tools.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── ObservabilityModelsOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── observability-models-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── BookService.java │ │ │ │ ├── ChatController.java │ │ │ │ ├── EmbeddingController.java │ │ │ │ ├── Functions.java │ │ │ │ ├── ImageController.java │ │ │ │ └── ObservabilityModelsOpenAiApplication.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── ObservabilityModelsOpenAiApplicationTests.java └── vector-stores │ └── observability-vector-stores-pgvector │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── ChatController.java │ │ │ ├── IngestionPipeline.java │ │ │ └── ObservabilityVectorStoresPgVector.java │ └── resources │ │ ├── application.yml │ │ └── documents │ │ ├── story1.md │ │ └── story2.md │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── ObservabilityVectorStoresPgVectorTests.java │ └── resources │ └── application-test.yml ├── patterns ├── guardrails │ ├── guardrails-input │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── GuardrailsInputApplication.java │ │ │ │ │ ├── SensitiveDataInputGuardrail.java │ │ │ │ │ └── guardrails │ │ │ │ │ ├── SensitiveDataInputGuardrailAdvisor.java │ │ │ │ │ └── package-info.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── GuardrailsInputApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── guardrails-output │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── ArtistInfo.java │ │ │ │ ├── GuardrailsOutputApplication.java │ │ │ │ ├── JsonOutputGuardrail.java │ │ │ │ ├── MusicQuestion.java │ │ │ │ └── guardrails │ │ │ │ ├── JsonOutputGuardrailAdvisor.java │ │ │ │ └── package-info.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── GuardrailsOutputApplicationTests.java │ │ └── resources │ │ └── application-test.yml ├── memory │ ├── memory-basics │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── MemoryBasicsApplication.java │ │ │ │ │ ├── MemoryControllerAdvisorMessages.java │ │ │ │ │ └── MemoryControllerAdvisorPrompt.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── MemoryBasicsApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── memory-jdbc │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── MemoryController.java │ │ │ │ │ └── MemoryJdbcApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── MemoryJdbcApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── memory-spring-security │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── MemoryController.java │ │ │ │ │ └── MemorySpringSecurityApplication.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── MemorySpringSecurityApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── memory-vector-store │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── MemoryControllerAdvisorVectorStore.java │ │ │ │ └── MemoryVectorStoreApplication.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── MemoryVectorStoreApplicationTests.java │ │ └── resources │ │ └── application-test.yml ├── multimodality │ ├── multimodality-mistral-ai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── MultimodalityMistralAiApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── tabby-cat.png │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── MultimodalityMistralAiApplicationTests.java │ ├── multimodality-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── MultimodalityOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── tabby-cat.png │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── MultimodalityOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── multimodality-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── ChatController.java │ │ │ │ ├── MultimodalityOpenAiApplication.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── speech.mp3 │ │ │ └── tabby-cat.png │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── MultimodalityOpenAiApplicationTests.java ├── prompts │ ├── prompts-basics-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── PromptsBasicsOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── PromptsBasicsOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── prompts-basics-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── PromptsBasicsOpenAiApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── PromptsBasicsOpenAiApplicationTests.java │ ├── prompts-messages-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── PromptsMessagesOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── prompts │ │ │ │ └── system-message.st │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── PromptsMessagesOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ ├── prompts-messages-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── PromptsMessagesOpenAiApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── prompts │ │ │ │ └── system-message.st │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── PromptsMessagesOpenAiApplicationTests.java │ ├── prompts-templates-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── MusicQuestion.java │ │ │ │ │ ├── PromptsTemplatesOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ ├── application.yml │ │ │ │ └── prompts │ │ │ │ └── system-message.st │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── PromptsTemplatesOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── prompts-templates-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── ChatController.java │ │ │ │ ├── MusicQuestion.java │ │ │ │ ├── PromptsTemplatesOpenAiApplication.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── prompts │ │ │ └── system-message.st │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── PromptsTemplatesOpenAiApplicationTests.java ├── structured-output │ ├── structured-output-ollama │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── thomasvitale │ │ │ │ │ └── ai │ │ │ │ │ └── spring │ │ │ │ │ ├── ArtistInfo.java │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── CountryInfo.java │ │ │ │ │ ├── MusicQuestion.java │ │ │ │ │ ├── OutputParsersOllamaApplication.java │ │ │ │ │ └── model │ │ │ │ │ └── ChatModelController.java │ │ │ └── resources │ │ │ │ └── application.yml │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ └── OutputParsersOllamaApplicationTests.java │ │ │ └── resources │ │ │ └── application-test.yml │ └── structured-output-openai │ │ ├── README.md │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── ArtistInfo.java │ │ │ │ ├── ArtistInfoVariant.java │ │ │ │ ├── ChatController.java │ │ │ │ ├── MusicQuestion.java │ │ │ │ ├── OutputParsersBeanOpenAiApplication.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── OutputParsersBeanOpenAiApplicationTests.java └── tool-calling │ ├── tool-calling-mistral-ai │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── BookService.java │ │ │ │ ├── ChatController.java │ │ │ │ ├── Functions.java │ │ │ │ ├── ToolCallingMistralAiApplication.java │ │ │ │ ├── Tools.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── ToolCallingMistralAiApplicationTests.java │ ├── tool-calling-ollama │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── BookService.java │ │ │ │ ├── ChatController.java │ │ │ │ ├── Functions.java │ │ │ │ ├── ToolCallingOllamaApplication.java │ │ │ │ ├── Tools.java │ │ │ │ └── model │ │ │ │ └── ChatModelController.java │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── ToolCallingOllamaApplicationTests.java │ │ └── resources │ │ └── application-test.yml │ └── tool-calling-openai │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── BookService.java │ │ │ ├── ChatController.java │ │ │ ├── Functions.java │ │ │ ├── ToolCallingOpenAiApplication.java │ │ │ ├── Tools.java │ │ │ └── model │ │ │ └── ChatModelController.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── thomasvitale │ └── ai │ └── spring │ └── ToolCallingOpenAiApplicationTests.java ├── rag ├── rag-branching │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── IngestionPipeline.java │ │ │ │ ├── RagBranching.java │ │ │ │ ├── RagControllerMultiQuery.java │ │ │ │ └── RagControllerOptimization.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── documents │ │ │ ├── story1.md │ │ │ └── story2.md │ │ └── test │ │ └── java │ │ ├── com │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── RagBranchingTests.java │ │ └── resources │ │ └── application-test.yml ├── rag-conditional │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── IngestionPipeline.java │ │ │ │ ├── RagConditional.java │ │ │ │ ├── RagControllerQueryRouting.java │ │ │ │ └── components │ │ │ │ └── SearchEngineDocumentRetriever.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── documents │ │ │ ├── story1.md │ │ │ └── story2.md │ │ └── test │ │ └── java │ │ ├── com │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── RagConditionalTests.java │ │ └── resources │ │ └── application-test.yml └── rag-sequential │ ├── rag-advanced │ ├── README.md │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── thomasvitale │ │ │ │ └── ai │ │ │ │ └── spring │ │ │ │ ├── IngestionPipeline.java │ │ │ │ ├── RagAdvanced.java │ │ │ │ ├── RagControllerDocumentCompression.java │ │ │ │ ├── RagControllerMemory.java │ │ │ │ ├── RagControllerQueryCompression.java │ │ │ │ ├── RagControllerQueryRewrite.java │ │ │ │ ├── RagControllerQueryTranslation.java │ │ │ │ ├── RagControllerVectorStore.java │ │ │ │ └── components │ │ │ │ └── CompressionDocumentPostProcessor.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── documents │ │ │ ├── story1.md │ │ │ └── story2.md │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ └── RagAdvancedTests.java │ │ └── resources │ │ └── application-test.yml │ └── rag-naive │ ├── README.md │ ├── build.gradle │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── IngestionPipeline.java │ │ │ ├── RagControllerEmptyContext.java │ │ │ ├── RagControllerSearchEngine.java │ │ │ ├── RagControllerVectorStore.java │ │ │ ├── RagNaive.java │ │ │ └── components │ │ │ └── SearchEngineDocumentRetriever.java │ └── resources │ │ ├── application.yml │ │ └── documents │ │ ├── story1.md │ │ └── story2.md │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── RagNaiveTests.java │ └── resources │ └── application-test.yml ├── settings.gradle └── use-cases ├── chatbot ├── README.md ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── Chatbot.java │ │ │ └── ChatbotController.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── ChatbotTests.java │ └── resources │ └── application-test.yml ├── question-answering ├── README.md ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── ChatController.java │ │ │ ├── IngestionPipeline.java │ │ │ └── QuestionAnswering.java │ └── resources │ │ ├── application.yml │ │ └── documents │ │ ├── story1.md │ │ └── story2.txt │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── QuestionAnsweringTests.java │ └── resources │ └── application-test.yml ├── semantic-search ├── README.md ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── IngestionPipeline.java │ │ │ ├── InstrumentNote.java │ │ │ ├── SemanticSearch.java │ │ │ └── SemanticSearchController.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── SemanticSearchTests.java │ └── resources │ └── application-test.yml ├── structured-data-extraction ├── README.md ├── build.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── thomasvitale │ │ │ └── ai │ │ │ └── spring │ │ │ ├── PatientJournal.java │ │ │ ├── StructuredDataExtraction.java │ │ │ └── StructuredDataExtractionController.java │ └── resources │ │ └── application.yml │ └── test │ ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ └── StructuredDataExtractionTests.java │ └── resources │ └── application-test.yml └── text-classification ├── README.md ├── build.gradle └── src ├── main ├── java │ └── com │ │ └── thomasvitale │ │ └── ai │ │ └── spring │ │ ├── ClassificationController.java │ │ ├── ClassificationType.java │ │ └── TextClassificationApplication.java └── resources │ └── application.yml └── test ├── java └── com │ └── thomasvitale │ └── ai │ └── spring │ ├── TextClassificationApplicationTests.java │ └── TextClassifierTests.java └── resources └── application-test.yml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "00:30" 8 | timezone: Europe/Copenhagen 9 | open-pull-requests-limit: 10 10 | labels: 11 | - "dependencies" 12 | commit-message: 13 | prefix: "deps:" 14 | -------------------------------------------------------------------------------- /.github/workflows/commit-stage.yml: -------------------------------------------------------------------------------- 1 | name: Commit Stage 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: ubuntu-24.04 17 | permissions: 18 | contents: read 19 | steps: 20 | - name: Check out source code 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | 23 | - name: Set up Java 24 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 25 | with: 26 | java-version: 23 27 | distribution: temurin 28 | cache: gradle 29 | 30 | - name: Compile and test 31 | run: ./gradlew clean assemble --no-daemon 32 | -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Use sdkman to run "sdk env" to initialize with correct JDK version 2 | # Enable auto-env through the sdkman_auto_env config 3 | # See https://sdkman.io/usage#config 4 | # A summary is to add the following to ~/.sdkman/etc/config 5 | # sdkman_auto_env=true 6 | java=24-graalce 7 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy-gradle-plugin' 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | ext { 10 | set("springBootVersion", '3.4.6') 11 | set("dependencyManagementVersion", '1.1.7') 12 | set("graalvmVersion", '0.10.6') 13 | } 14 | 15 | dependencies { 16 | implementation "io.spring.gradle:dependency-management-plugin:${dependencyManagementVersion}" 17 | implementation "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" 18 | implementation "org.graalvm.buildtools:native-gradle-plugin:${graalvmVersion}" 19 | } 20 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/README.md: -------------------------------------------------------------------------------- 1 | # JSON Document Readers: Ollama 2 | 3 | Reading and vectorizing JSON documents with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "Bike for city commuting" :8080/search/simple 36 | ``` 37 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-vector-store' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentReadersJsonOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class DocumentReadersJsonOllamaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(DocumentReadersJsonOllamaApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text 11 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentReadersJsonOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentReadersJsonOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-json-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/README.md: -------------------------------------------------------------------------------- 1 | # Markdown Document Readers: Ollama 2 | 3 | Reading and vectorizing Markdown documents with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-markdown-document-reader' 27 | implementation 'org.springframework.ai:spring-ai-vector-store' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentReadersMarkdownOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class DocumentReadersMarkdownOllamaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(DocumentReadersMarkdownOllamaApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentReadersMarkdownOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentReadersMarkdownOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-markdown-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/README.md: -------------------------------------------------------------------------------- 1 | # PDF Document Readers: Ollama 2 | 3 | Reading and vectorizing PDF documents with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-pdf-document-reader' 27 | implementation 'org.springframework.ai:spring-ai-vector-store' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentReadersPdfOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class DocumentReadersPdfOllamaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(DocumentReadersPdfOllamaApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/main/resources/documents/story1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/data-ingestion/document-readers/document-readers-pdf-ollama/src/main/resources/documents/story1.pdf -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/main/resources/documents/story2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/data-ingestion/document-readers/document-readers-pdf-ollama/src/main/resources/documents/story2.pdf -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentReadersPdfOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentReadersPdfOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-pdf-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/README.md: -------------------------------------------------------------------------------- 1 | # Text Document Readers: Ollama 2 | 3 | Reading and vectorizing text documents with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-vector-store' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentReadersTextOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class DocumentReadersTextOllamaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(DocumentReadersTextOllamaApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentReadersTextOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentReadersTextOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-text-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/README.md: -------------------------------------------------------------------------------- 1 | # Tika Document Readers: Ollama 2 | 3 | Reading and vectorizing documents with LLMs and Tika via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-tika-document-reader' 27 | implementation 'org.springframework.ai:spring-ai-vector-store' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentReadersTikaOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class DocumentReadersTikaOllamaApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(DocumentReadersTikaOllamaApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/main/resources/documents/story2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/data-ingestion/document-readers/document-readers-tika-ollama/src/main/resources/documents/story2.pdf -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentReadersTikaOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentReadersTikaOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-readers/document-readers-tika-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/README.md: -------------------------------------------------------------------------------- 1 | # Document Transformers - Metadata 2 | 3 | Enrich documents with keywords and summary metadata for enhanced retrieval. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-vector-store' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | options: 8 | model: granite3.2:2b 9 | embedding: 10 | options: 11 | model: nomic-embed-text 12 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentTransformersMetadataOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentTransformersMetadataOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-metadata-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/README.md: -------------------------------------------------------------------------------- 1 | # Document Transformers - Text Splitters 2 | 3 | Divide documents into chunks to fit the LLM context window. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will perform a semantic search based on your query. 33 | 34 | ```shell 35 | http --raw "What is Iorek's biggest dream?" :8080/search/simple 36 | ``` 37 | 38 | ```shell 39 | http --raw "Who is Lucio?" :8080/search/simple 40 | ``` 41 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-vector-store' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/src/main/java/com/thomasvitale/ai/spring/DocumentTransformersSplittersOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.DefaultContentFormatter; 4 | import org.springframework.ai.embedding.EmbeddingModel; 5 | import org.springframework.ai.vectorstore.SimpleVectorStore; 6 | import org.springframework.ai.vectorstore.VectorStore; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @SpringBootApplication 12 | public class DocumentTransformersSplittersOllamaApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(DocumentTransformersSplittersOllamaApplication.class, args); 16 | } 17 | 18 | @Bean 19 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 20 | return SimpleVectorStore.builder(embeddingModel).build(); 21 | } 22 | 23 | @Bean 24 | DefaultContentFormatter defaultContentFormatter() { 25 | return DefaultContentFormatter.builder() 26 | .withExcludedEmbedMetadataKeys("NewEmbedKey") 27 | .withExcludedInferenceMetadataKeys("NewInferenceKey") 28 | .build(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/src/main/java/com/thomasvitale/ai/spring/SearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.document.Document; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/search/simple") 21 | List searchSimilarDocuments(@RequestBody String query) { 22 | var documents = vectorStore.similaritySearch(query); 23 | return documents.stream() 24 | .map(document -> document.mutate().build()) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/src/test/java/com/thomasvitale/ai/spring/DocumentTransformersSplittersOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DocumentTransformersSplittersOllamaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /data-ingestion/document-transformers/document-transformers-splitters-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.configuration-cache=false 2 | org.gradle.caching=true 3 | org.gradle.parallel=true 4 | 5 | org.gradle.jvmargs=-Xmx8g 6 | 7 | arconiaVersion=0.12.0 8 | jSpecifyVersion=1.0.0 9 | springAiVersion=1.0.0 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | distributionSha256Sum=845952a9d6afa783db70bb3b0effaae45ae5542ca2bb7929619e8af49cb634cf 9 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | maven { 22 | name = 'Central Portal Snapshots' 23 | url = 'https://central.sonatype.com/repository/maven-snapshots/' 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation 'org.springframework.boot:spring-boot-starter-web' 29 | implementation "org.springframework.ai:spring-ai-starter-model-ollama" 30 | 31 | implementation "org.springframework.ai:spring-ai-starter-mcp-client" 32 | 33 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 34 | 35 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 36 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 37 | } 38 | 39 | dependencyManagement { 40 | imports { 41 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 42 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 43 | } 44 | } 45 | 46 | tasks.named('test') { 47 | useJUnitPlatform() 48 | } 49 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/src/main/java/com/thomasvitale/ai/spring/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import io.modelcontextprotocol.client.McpSyncClient; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Chat examples using the high-level ChatClient API. 13 | */ 14 | @RestController 15 | class ChatController { 16 | 17 | private final ChatClient chatClient; 18 | private final List mcpClients; 19 | 20 | ChatController(ChatClient.Builder chatClientBuilder, List mcpClients) { 21 | this.chatClient = chatClientBuilder.build(); 22 | this.mcpClients = mcpClients; 23 | } 24 | 25 | @GetMapping("/chat/mcp") 26 | String chat(String question) { 27 | return chatClient.prompt() 28 | .user(question) 29 | .toolCallbacks(new SyncMcpToolCallbackProvider(mcpClients).getToolCallbacks()) 30 | .call() 31 | .content(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/src/main/java/com/thomasvitale/ai/spring/McpBraveApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class McpBraveApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(McpBraveApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mcp: 4 | client: 5 | stdio: 6 | connections: 7 | brave-search: 8 | command: npx 9 | args: 10 | - "-y" 11 | - "@modelcontextprotocol/server-brave-search" 12 | env: 13 | BRAVE_API_KEY: ${BRAVE_API_KEY} 14 | ollama: 15 | init: 16 | pull-model-strategy: when_missing 17 | embedding: 18 | include: false 19 | chat: 20 | options: 21 | model: granite3.2:2b 22 | temperature: 0.7 23 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/src/test/java/com/thomasvitale/ai/spring/McpBraveApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; 4 | import org.junit.jupiter.params.ParameterizedTest; 5 | import org.junit.jupiter.params.provider.ValueSource; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.web.reactive.server.WebTestClient; 10 | 11 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 12 | @AutoConfigureWebTestClient(timeout = "180s") 13 | @EnabledIfEnvironmentVariable(named = "BRAVE_API_KEY", matches = ".*") 14 | class McpBraveApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/chat/mcp"}) 21 | void chat(String path) { 22 | webTestClient 23 | .get() 24 | .uri(uriBuilder -> uriBuilder 25 | .path(path) 26 | .queryParam("question", "Does Spring AI supports integrations with Ollama?") 27 | .build()) 28 | .exchange() 29 | .expectStatus().isOk(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /mcp/mcp-clients/mcp-brave/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/src/main/java/com/thomasvitale/ai/spring/TextToSpeechOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TextToSpeechOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TextToSpeechOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | audio: 6 | transcription: 7 | options: 8 | model: whisper-1 9 | -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/src/main/resources/speech1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/models/audio/speech-to-text-openai/src/main/resources/speech1.mp3 -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/src/main/resources/speech2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/models/audio/speech-to-text-openai/src/main/resources/speech2.mp3 -------------------------------------------------------------------------------- /models/audio/speech-to-text-openai/src/test/java/com/thomasvitale/ai/spring/TextToSpeechOpenAiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class TextToSpeechOpenAiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/audio/text-to-speech-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /models/audio/text-to-speech-openai/src/main/java/com/thomasvitale/ai/spring/SpeechController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.openai.OpenAiAudioSpeechOptions; 4 | import org.springframework.ai.openai.api.OpenAiAudioApi; 5 | import org.springframework.ai.openai.audio.speech.SpeechModel; 6 | import org.springframework.ai.openai.audio.speech.SpeechPrompt; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | class SpeechController { 12 | 13 | private final SpeechModel speechModel; 14 | 15 | SpeechController(SpeechModel speechModel) { 16 | this.speechModel = speechModel; 17 | } 18 | 19 | @GetMapping("/speech") 20 | byte[] speech(String message) { 21 | return speechModel.call(new SpeechPrompt(message)).getResult().getOutput(); 22 | } 23 | 24 | @GetMapping("/speech/provider-options") 25 | byte[] speechProviderOptions(String message) { 26 | var speechResponse = speechModel.call(new SpeechPrompt(message, OpenAiAudioSpeechOptions.builder() 27 | .model("tts-1") 28 | .voice(OpenAiAudioApi.SpeechRequest.Voice.ALLOY) 29 | .responseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3) 30 | .speed(1.0f) 31 | .build())); 32 | return speechResponse.getResult().getOutput(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /models/audio/text-to-speech-openai/src/main/java/com/thomasvitale/ai/spring/SpeechToTextOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpeechToTextOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpeechToTextOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/audio/text-to-speech-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | audio: 6 | speech: 7 | options: 8 | model: tts-1 9 | -------------------------------------------------------------------------------- /models/audio/text-to-speech-openai/src/test/java/com/thomasvitale/ai/spring/SpeechToTextOpenAiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpeechToTextOpenAiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/chat/chat-mistral-ai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-mistral-ai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /models/chat/chat-mistral-ai/src/main/java/com/thomasvitale/ai/spring/ChatMistralAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ChatMistralAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ChatMistralAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/chat/chat-mistral-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mistralai: 4 | api-key: ${MISTRALAI_API_KEY} 5 | chat: 6 | options: 7 | model: open-mistral-7b 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /models/chat/chat-multiple-providers/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-mistral-ai' 28 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 29 | 30 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 31 | 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /models/chat/chat-multiple-providers/src/main/java/com/thomasvitale/ai/spring/ChatMultipleProvidersApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ChatMultipleProvidersApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ChatMultipleProvidersApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/chat/chat-multiple-providers/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mistralai: 4 | api-key: ${MISTRALAI_API_KEY} 5 | chat: 6 | options: 7 | model: open-mistral-7b 8 | temperature: 0.7 9 | openai: 10 | api-key: ${OPENAI_API_KEY} 11 | chat: 12 | options: 13 | model: gpt-3.5-turbo 14 | temperature: 0.7 15 | -------------------------------------------------------------------------------- /models/chat/chat-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /models/chat/chat-ollama/src/main/java/com/thomasvitale/ai/spring/ChatOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ChatOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ChatOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/chat/chat-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | additional-models: 8 | - hf.co/HuggingFaceTB/SmolLM2-360M-Instruct-GGUF 9 | embedding: 10 | include: false 11 | chat: 12 | options: 13 | model: granite3.2:2b 14 | temperature: 0.7 15 | -------------------------------------------------------------------------------- /models/chat/chat-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /models/chat/chat-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /models/chat/chat-openai/src/main/java/com/thomasvitale/ai/spring/ChatOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ChatOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ChatOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/chat/chat-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /models/embedding/embedding-mistral-ai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-mistral-ai' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /models/embedding/embedding-mistral-ai/src/main/java/com/thomasvitale/ai/spring/EmbeddingMistralAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class EmbeddingMistralAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(EmbeddingMistralAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/embedding/embedding-mistral-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mistralai: 4 | api-key: ${MISTRALAI_API_KEY} 5 | embedding: 6 | options: 7 | model: mistral-embed 8 | -------------------------------------------------------------------------------- /models/embedding/embedding-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /models/embedding/embedding-ollama/src/main/java/com/thomasvitale/ai/spring/EmbeddingOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class EmbeddingOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(EmbeddingOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/embedding/embedding-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text 11 | -------------------------------------------------------------------------------- /models/embedding/embedding-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /models/embedding/embedding-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /models/embedding/embedding-openai/src/main/java/com/thomasvitale/ai/spring/EmbeddingOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class EmbeddingOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(EmbeddingOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/embedding/embedding-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | embedding: 6 | options: 7 | model: text-embedding-ada-002 8 | -------------------------------------------------------------------------------- /models/embedding/embedding-transformers/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-transformers' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testImplementation 'org.springframework:spring-webflux' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /models/embedding/embedding-transformers/src/main/java/com/thomasvitale/ai/spring/EmbeddingController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.embedding.EmbeddingOptionsBuilder; 5 | import org.springframework.ai.embedding.EmbeddingRequest; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class EmbeddingController { 13 | 14 | private final EmbeddingModel embeddingModel; 15 | 16 | EmbeddingController(EmbeddingModel embeddingModel) { 17 | this.embeddingModel = embeddingModel; 18 | } 19 | 20 | @GetMapping("/embed") 21 | String embed(String query) { 22 | var embeddings = embeddingModel.embed(query); 23 | return "Size of the embedding vector: " + embeddings.length; 24 | } 25 | 26 | @GetMapping("/embed/generic-options") 27 | String embedGenericOptions(String query) { 28 | var embeddings = embeddingModel.call(new EmbeddingRequest(List.of(query), EmbeddingOptionsBuilder.builder() 29 | .withDimensions(384) 30 | .build())) 31 | .getResult().getOutput(); 32 | return "Size of the embedding vector: " + embeddings.length; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /models/embedding/embedding-transformers/src/main/java/com/thomasvitale/ai/spring/EmbeddingTransformersApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class EmbeddingTransformersApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(EmbeddingTransformersApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/embedding/embedding-transformers/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | embedding: 4 | transformer: 5 | onnx: 6 | model-uri: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/onnx/model.onnx 7 | tokenizer: 8 | uri: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/raw/main/tokenizer.json 9 | -------------------------------------------------------------------------------- /models/embedding/embedding-transformers/src/test/java/com/thomasvitale/ai/spring/EmbeddingTransformersApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.ValueSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | @AutoConfigureWebTestClient(timeout = "60s") 14 | class EmbeddingTransformersApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/embed", "/embed/generic-options"}) 21 | void chat(String path) { 22 | webTestClient 23 | .get() 24 | .uri(uriBuilder -> uriBuilder 25 | .path(path) 26 | .queryParam("query", "Rivendell") 27 | .build()) 28 | .exchange() 29 | .expectStatus().isOk() 30 | .expectBody(String.class).value(result -> { 31 | assertThat(result).containsIgnoringCase("384"); 32 | }); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /models/image/image-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 24 | 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 27 | 28 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | tasks.named('test') { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /models/image/image-openai/src/main/java/com/thomasvitale/ai/spring/ImageOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImageOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImageOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /models/image/image-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | image: 6 | options: 7 | model: dall-e-2 8 | -------------------------------------------------------------------------------- /observability/models/observability-models-mistral-ai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-mistral-ai' 26 | 27 | implementation 'io.arconia:arconia-opentelemetry-spring-boot-starter' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-lgtm' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /observability/models/observability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/Functions.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Description; 8 | 9 | import java.util.List; 10 | import java.util.function.Function; 11 | 12 | @Configuration(proxyBeanMethods = false) 13 | public class Functions { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(Functions.class); 16 | 17 | @Bean 18 | @Description("Get the list of available books written by the given author") 19 | public Function> booksByAuthor(BookService bookService) { 20 | logger.info("Calling function to get books by author"); 21 | return bookService::getBooksByAuthor; 22 | } 23 | 24 | @Bean 25 | @Description("Get the bestseller book written by the given author") 26 | public Function bestsellerBookByAuthor(BookService bookService) { 27 | logger.info("Calling function to get bestseller book by author"); 28 | return bookService::getBestsellerByAuthor; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /observability/models/observability-models-mistral-ai/src/main/java/com/thomasvitale/ai/spring/ObservabilityModelsMistralAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ObservabilityModelsMistralAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ObservabilityModelsMistralAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/models/observability-models-mistral-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: observability-models-mistral-ai 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | mistralai: 10 | api-key: ${MISTRALAI_API_KEY} 11 | chat: 12 | options: 13 | model: mistral-small-latest 14 | temperature: 0.7 15 | embedding: 16 | options: 17 | model: mistral-embed 18 | 19 | management: 20 | endpoints: 21 | web: 22 | exposure: 23 | include: "*" 24 | -------------------------------------------------------------------------------- /observability/models/observability-models-mistral-ai/src/test/java/com/thomasvitale/ai/spring/ObservabilityModelsMistralAiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ObservabilityModelsMistralAiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 25 | 26 | implementation 'io.arconia:arconia-opentelemetry-spring-boot-starter' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-lgtm' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/main/java/com/thomasvitale/ai/spring/BookService.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | @Service 10 | public class BookService { 11 | 12 | private static final Map books = new ConcurrentHashMap<>(); 13 | 14 | static { 15 | books.put(1, new Book("His Dark Materials", "Philip Pullman")); 16 | books.put(2, new Book("Narnia", "C.S. Lewis")); 17 | books.put(3, new Book("The Hobbit", "J.R.R. Tolkien")); 18 | books.put(4, new Book("The Lord of The Rings", "J.R.R. Tolkien")); 19 | books.put(5, new Book("The Silmarillion", "J.R.R. Tolkien")); 20 | } 21 | 22 | List getBooksByAuthor(String author) { 23 | return books.values().stream() 24 | .filter(book -> author.equalsIgnoreCase(book.author())) 25 | .toList(); 26 | } 27 | 28 | Book getBestsellerByAuthor(String author) { 29 | return switch (author) { 30 | case "J.R.R. Tolkien" -> books.get(4); 31 | case "C.S. Lewis" -> books.get(2); 32 | case "Philip Pullman" -> books.get(1); 33 | default -> null; 34 | }; 35 | } 36 | 37 | public record Book(String title, String author) {} 38 | 39 | } 40 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/main/java/com/thomasvitale/ai/spring/ObservabilityModelsOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ObservabilityModelsOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ObservabilityModelsOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/main/java/com/thomasvitale/ai/spring/Tools.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.ai.tool.annotation.Tool; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | 10 | @Component 11 | public class Tools { 12 | 13 | private static final Logger logger = LoggerFactory.getLogger(Tools.class); 14 | 15 | private final BookService bookService; 16 | 17 | public Tools(BookService bookService) { 18 | this.bookService = bookService; 19 | } 20 | 21 | @Tool(description = "Get the list of available books written by the given author") 22 | List booksByAuthor(String author) { 23 | logger.info("Calling function to get books by author"); 24 | return bookService.getBooksByAuthor(author); 25 | } 26 | 27 | @Tool(description = "Get the bestseller book written by the given author") 28 | BookService.Book bestsellerBookByAuthor(String author) { 29 | logger.info("Calling function to get bestseller book by author"); 30 | return bookService.getBestsellerByAuthor(author); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: observability-models-ollama 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | ollama: 10 | init: 11 | pull-model-strategy: when_missing 12 | chat: 13 | options: 14 | model: granite3.2:2b 15 | temperature: 0.7 16 | embedding: 17 | options: 18 | model: nomic-embed-text 19 | 20 | management: 21 | endpoints: 22 | web: 23 | exposure: 24 | include: "*" 25 | 26 | arconia: 27 | otel: 28 | metrics: 29 | interval: 5s 30 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/test/java/com/thomasvitale/ai/spring/ObservabilityModelsOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class ObservabilityModelsOllamaApplicationTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /observability/models/observability-models-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /observability/models/observability-models-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 26 | 27 | implementation 'io.arconia:arconia-opentelemetry-spring-boot-starter' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-lgtm' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /observability/models/observability-models-openai/src/main/java/com/thomasvitale/ai/spring/BookService.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | @Service 10 | public class BookService { 11 | 12 | private static final Map books = new ConcurrentHashMap<>(); 13 | 14 | static { 15 | books.put(1, new Book("His Dark Materials", "Philip Pullman")); 16 | books.put(2, new Book("Narnia", "C.S. Lewis")); 17 | books.put(3, new Book("The Hobbit", "J.R.R. Tolkien")); 18 | books.put(4, new Book("The Lord of The Rings", "J.R.R. Tolkien")); 19 | books.put(5, new Book("The Silmarillion", "J.R.R. Tolkien")); 20 | } 21 | 22 | List getBooksByAuthor(Author author) { 23 | return books.values().stream() 24 | .filter(book -> author.name().equals(book.author())) 25 | .toList(); 26 | } 27 | 28 | Book getBestsellerByAuthor(Author author) { 29 | return switch (author.name()) { 30 | case "J.R.R. Tolkien" -> books.get(4); 31 | case "C.S. Lewis" -> books.get(2); 32 | case "Philip Pullman" -> books.get(1); 33 | default -> null; 34 | }; 35 | } 36 | 37 | public record Book(String title, String author) {} 38 | public record Author(String name) {} 39 | 40 | } 41 | -------------------------------------------------------------------------------- /observability/models/observability-models-openai/src/main/java/com/thomasvitale/ai/spring/Functions.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Description; 6 | 7 | import java.util.List; 8 | import java.util.function.Function; 9 | 10 | @Configuration(proxyBeanMethods = false) 11 | public class Functions { 12 | 13 | @Bean 14 | @Description("Get the list of available books written by the given author") 15 | public Function> booksByAuthor(BookService bookService) { 16 | return bookService::getBooksByAuthor; 17 | } 18 | 19 | @Bean 20 | @Description("Get the bestseller book written by the given author") 21 | public Function bestsellerBookByAuthor(BookService bookService) { 22 | return bookService::getBestsellerByAuthor; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /observability/models/observability-models-openai/src/main/java/com/thomasvitale/ai/spring/ObservabilityModelsOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ObservabilityModelsOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ObservabilityModelsOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/models/observability-models-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: observability-models-openai 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | image: 10 | observations: 11 | log-prompt: true 12 | openai: 13 | api-key: ${OPENAI_API_KEY} 14 | chat: 15 | options: 16 | model: gpt-4o-mini 17 | temperature: 0.7 18 | embedding: 19 | options: 20 | model: text-embedding-3-small 21 | image: 22 | options: 23 | model: dall-e-3 24 | http: 25 | client: 26 | read-timeout: 60s 27 | 28 | management: 29 | endpoints: 30 | web: 31 | exposure: 32 | include: "*" 33 | -------------------------------------------------------------------------------- /observability/models/observability-models-openai/src/test/java/com/thomasvitale/ai/spring/ObservabilityModelsOpenAiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ObservabilityModelsOpenAiApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/vector-stores/observability-vector-stores-pgvector/src/main/java/com/thomasvitale/ai/spring/ObservabilityVectorStoresPgVector.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ObservabilityVectorStoresPgVector { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ObservabilityVectorStoresPgVector.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /observability/vector-stores/observability-vector-stores-pgvector/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: observability-vector-stores-pgvector 4 | ai: 5 | chat: 6 | client: 7 | observations: 8 | log-prompt: true 9 | observations: 10 | log-completion: true 11 | log-prompt: true 12 | ollama: 13 | init: 14 | pull-model-strategy: when_missing 15 | chat: 16 | options: 17 | model: granite3.2:2b 18 | temperature: 0.7 19 | embedding: 20 | options: 21 | model: nomic-embed-text 22 | vectorstore: 23 | observations: 24 | log-query-response: true 25 | pgvector: 26 | initialize-schema: true 27 | dimensions: 768 28 | index-type: hnsw 29 | 30 | management: 31 | endpoints: 32 | web: 33 | exposure: 34 | include: "*" 35 | 36 | arconia: 37 | dev: 38 | services: 39 | postgresql: 40 | image-name: pgvector/pgvector:pg17 41 | otel: 42 | metrics: 43 | interval: 5s 44 | -------------------------------------------------------------------------------- /observability/vector-stores/observability-vector-stores-pgvector/src/test/java/com/thomasvitale/ai/spring/ObservabilityVectorStoresPgVectorTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class ObservabilityVectorStoresPgVectorTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /observability/vector-stores/observability-vector-stores-pgvector/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation "org.jspecify:jspecify:${jSpecifyVersion}" 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/src/main/java/com/thomasvitale/ai/spring/GuardrailsInputApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class GuardrailsInputApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(GuardrailsInputApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/src/main/java/com/thomasvitale/ai/spring/SensitiveDataInputGuardrail.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import com.thomasvitale.ai.spring.guardrails.SensitiveDataInputGuardrailAdvisor; 4 | import org.springframework.ai.chat.client.ChatClient; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | class SensitiveDataInputGuardrail { 11 | 12 | private final ChatClient chatClient; 13 | 14 | SensitiveDataInputGuardrail(ChatClient.Builder chatClientBuilder) { 15 | this.chatClient = chatClientBuilder.clone() 16 | .defaultAdvisors(SensitiveDataInputGuardrailAdvisor.builder() 17 | .chatClientBuilder(chatClientBuilder.clone()) 18 | .build()) 19 | .build(); 20 | } 21 | 22 | @PostMapping("/guardrails/input") 23 | String chat(@RequestBody String question) { 24 | return chatClient.prompt() 25 | .user(question) 26 | .call() 27 | .content(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/src/main/java/com/thomasvitale/ai/spring/guardrails/package-info.java: -------------------------------------------------------------------------------- 1 | @NullMarked 2 | package com.thomasvitale.ai.spring.guardrails; 3 | 4 | import org.jspecify.annotations.NullMarked; -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-input/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/README.md: -------------------------------------------------------------------------------- 1 | # Guardrails: Output 2 | 3 | Output guardrails with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. If you choose the first option, make sure you have Ollama installed and running on your laptop. Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, if they are not available yet on your machine. 8 | 9 | ## Running the application 10 | 11 | If you're using the native Ollama application, run the application as follows: 12 | 13 | ```shell 14 | ./gradlew bootRun 15 | ``` 16 | 17 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 18 | 19 | ```shell 20 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 21 | ``` 22 | 23 | ## Calling the application 24 | 25 | > [!NOTE] 26 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 27 | 28 | Call the application that will use a chat model to answer your question. 29 | 30 | ### Output Guardrail: JSON Structured Output 31 | 32 | ```shell 33 | http :8080/guardrails/output genre="rock" instrument="piano" -b 34 | ``` 35 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation "org.jspecify:jspecify:${jSpecifyVersion}" 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/main/java/com/thomasvitale/ai/spring/ArtistInfo.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record ArtistInfo(String name, String band) {} 4 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/main/java/com/thomasvitale/ai/spring/GuardrailsOutputApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class GuardrailsOutputApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(GuardrailsOutputApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/main/java/com/thomasvitale/ai/spring/MusicQuestion.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record MusicQuestion(String genre, String instrument){} 4 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/main/java/com/thomasvitale/ai/spring/guardrails/package-info.java: -------------------------------------------------------------------------------- 1 | @NullMarked 2 | package com.thomasvitale.ai.spring.guardrails; 3 | 4 | import org.jspecify.annotations.NullMarked; -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/test/java/com/thomasvitale/ai/spring/GuardrailsOutputApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.ValueSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | @AutoConfigureWebTestClient(timeout = "60s") 14 | class GuardrailsOutputApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/guardrails/output"}) 21 | void chat(String path) { 22 | webTestClient 23 | .post() 24 | .uri(path) 25 | .bodyValue(new MusicQuestion("rock", "piano")) 26 | .exchange() 27 | .expectStatus().isOk() 28 | .expectBody(ArtistInfo.class).value(result -> { 29 | assertThat(result).isNotNull(); 30 | assertThat(result.name()).isNotEmpty(); 31 | assertThat(result.band()).isNotEmpty(); 32 | }); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /patterns/guardrails/guardrails-output/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/memory/memory-basics/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/memory/memory-basics/src/main/java/com/thomasvitale/ai/spring/MemoryBasicsApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MemoryBasicsApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MemoryBasicsApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/memory/memory-basics/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/memory/memory-basics/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/memory/memory-jdbc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-jdbc' 27 | 28 | runtimeOnly 'org.postgresql:postgresql' 29 | 30 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 31 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql' 32 | 33 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 34 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 35 | } 36 | 37 | dependencyManagement { 38 | imports { 39 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 40 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 41 | } 42 | } 43 | 44 | tasks.named('test') { 45 | useJUnitPlatform() 46 | } 47 | -------------------------------------------------------------------------------- /patterns/memory/memory-jdbc/src/main/java/com/thomasvitale/ai/spring/MemoryController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 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.web.bind.annotation.PathVariable; 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 | import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID; 12 | 13 | /** 14 | * Chat examples using the high-level ChatClient API. 15 | */ 16 | @RestController 17 | class MemoryController { 18 | 19 | private final ChatClient chatClient; 20 | 21 | MemoryController(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory) { 22 | this.chatClient = chatClientBuilder.clone() 23 | .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) 24 | .build(); 25 | } 26 | 27 | @PostMapping("/memory/jdbc/{conversationId}") 28 | String chat(@PathVariable String conversationId, @RequestBody String question) { 29 | return chatClient.prompt() 30 | .user(question) 31 | .advisors(a -> a.param(CONVERSATION_ID, conversationId)) 32 | .call() 33 | .content(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /patterns/memory/memory-jdbc/src/main/java/com/thomasvitale/ai/spring/MemoryJdbcApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.chat.memory.ChatMemory; 4 | import org.springframework.ai.chat.memory.MessageWindowChatMemory; 5 | import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class MemoryJdbcApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(MemoryJdbcApplication.class, args); 15 | } 16 | 17 | @Bean 18 | ChatMemory jdbcChatMemory(JdbcChatMemoryRepository chatMemoryRepository) { 19 | return MessageWindowChatMemory.builder() 20 | .chatMemoryRepository(chatMemoryRepository) 21 | .build(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /patterns/memory/memory-jdbc/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/memory/memory-jdbc/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/memory/memory-spring-security/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-security' 25 | implementation 'org.springframework.boot:spring-boot-starter-web' 26 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 27 | implementation 'io.arconia:arconia-spring-boot-starter' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /patterns/memory/memory-spring-security/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/memory/memory-spring-security/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/memory/memory-vector-store/README.md: -------------------------------------------------------------------------------- 1 | # Memory with Vector Store 2 | 3 | Using chat memory stored in a vector store with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will use a chat model to answer your question. 33 | 34 | ```shell 35 | http --raw "My name is Bond. James Bond." :8080/memory/vector/007 -b --pretty none 36 | ``` 37 | 38 | ```shell 39 | http --raw "What's my name?" :8080/memory/vector/007 -b --pretty none 40 | ``` 41 | -------------------------------------------------------------------------------- /patterns/memory/memory-vector-store/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | implementation "org.springframework.ai:spring-ai-vector-store" 27 | implementation 'org.springframework.ai:spring-ai-advisors-vector-store' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /patterns/memory/memory-vector-store/src/main/java/com/thomasvitale/ai/spring/MemoryVectorStoreApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.embedding.EmbeddingModel; 4 | import org.springframework.ai.vectorstore.SimpleVectorStore; 5 | import org.springframework.ai.vectorstore.VectorStore; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @SpringBootApplication 11 | public class MemoryVectorStoreApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(MemoryVectorStoreApplication.class, args); 15 | } 16 | 17 | @Bean 18 | VectorStore vectorStore(EmbeddingModel embeddingModel) { 19 | return SimpleVectorStore.builder(embeddingModel).build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /patterns/memory/memory-vector-store/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | options: 8 | model: granite3.2:2b 9 | temperature: 0.7 10 | embedding: 11 | options: 12 | model: nomic-embed-text 13 | -------------------------------------------------------------------------------- /patterns/memory/memory-vector-store/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-mistral-ai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation "org.springframework.ai:spring-ai-starter-model-mistral-ai" 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-mistral-ai/src/main/java/com/thomasvitale/ai/spring/MultimodalityMistralAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MultimodalityMistralAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MultimodalityMistralAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-mistral-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mistralai: 4 | api-key: ${MISTRALAI_API_KEY} 5 | chat: 6 | options: 7 | model: pixtral-large-latest 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-mistral-ai/src/main/resources/tabby-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/patterns/multimodality/multimodality-mistral-ai/src/main/resources/tabby-cat.png -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/src/main/java/com/thomasvitale/ai/spring/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.chat.client.ChatClient; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.core.io.Resource; 6 | import org.springframework.util.MimeTypeUtils; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * Chat examples using the high-level ChatClient API. 12 | */ 13 | @RestController 14 | class ChatController { 15 | 16 | private final ChatClient chatClient; 17 | 18 | @Value("classpath:tabby-cat.png") 19 | private Resource image; 20 | 21 | public ChatController(ChatClient.Builder chatClientBuilder) { 22 | this.chatClient = chatClientBuilder.build(); 23 | } 24 | 25 | @GetMapping("/chat/image/file") 26 | String chatImageFile(String question) { 27 | return chatClient.prompt() 28 | .user(userSpec -> userSpec 29 | .text(question) 30 | .media(MimeTypeUtils.IMAGE_PNG, image) 31 | ) 32 | .call() 33 | .content(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/src/main/java/com/thomasvitale/ai/spring/MultimodalityOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MultimodalityOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MultimodalityOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2-vision:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/src/main/resources/tabby-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/patterns/multimodality/multimodality-ollama/src/main/resources/tabby-cat.png -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-openai/src/main/java/com/thomasvitale/ai/spring/MultimodalityOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MultimodalityOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MultimodalityOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-4o 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-openai/src/main/resources/speech.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/patterns/multimodality/multimodality-openai/src/main/resources/speech.mp3 -------------------------------------------------------------------------------- /patterns/multimodality/multimodality-openai/src/main/resources/tabby-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasVitale/llm-apps-java-spring-ai/475958721df81f7f791407f24a823e10117e372a/patterns/multimodality/multimodality-openai/src/main/resources/tabby-cat.png -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/src/main/java/com/thomasvitale/ai/spring/PromptsBasicsOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsBasicsOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsBasicsOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/src/main/java/com/thomasvitale/ai/spring/model/ChatModelController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring.model; 2 | 3 | import org.springframework.ai.chat.model.ChatModel; 4 | import org.springframework.ai.chat.model.ChatResponse; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * Chat examples using the low-level ChatModel API. 13 | */ 14 | @RestController 15 | @RequestMapping("/model") 16 | class ChatModelController { 17 | 18 | private final ChatModel chatModel; 19 | 20 | ChatModelController(ChatModel chatModel) { 21 | this.chatModel = chatModel; 22 | } 23 | 24 | @PostMapping("/chat/simple") 25 | String chatText(@RequestBody String question) { 26 | return chatModel.call(question); 27 | } 28 | 29 | @PostMapping("/chat/prompt") 30 | String chatPrompt(@RequestBody String question) { 31 | return chatModel.call(new Prompt(question)).getResult().getOutput().getText(); 32 | } 33 | 34 | @PostMapping("/chat/full") 35 | ChatResponse chatFullResponse(@RequestBody String question) { 36 | return chatModel.call(new Prompt(question)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/src/test/java/com/thomasvitale/ai/spring/PromptsBasicsOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.ValueSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | @AutoConfigureWebTestClient(timeout = "60s") 14 | class PromptsBasicsOllamaApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/chat/simple", "/model/chat/simple", "/chat/prompt", "/model/chat/prompt", "/chat/full", "/model/chat/full"}) 21 | void chat(String path) { 22 | webTestClient 23 | .post() 24 | .uri(path) 25 | .bodyValue("What is the capital of Italy?") 26 | .exchange() 27 | .expectStatus().isOk() 28 | .expectBody(String.class).value(result -> { 29 | assertThat(result).containsIgnoringCase("Rome"); 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-openai/README.md: -------------------------------------------------------------------------------- 1 | # Prompts Basic: OpenAI 2 | 3 | Prompting using simple text with LLMs via OpenAI. 4 | 5 | ## OpenAI 6 | 7 | The application consumes models from the [OpenAI](https://openai.com) platform. 8 | 9 | ### Create an account 10 | 11 | Visit [platform.openai.com](https://platform.openai.com) and sign up for a new account. 12 | 13 | ### Configure API Key 14 | 15 | In the OpenAI console, navigate to _Dashboard > API Keys_ and generate a new API key. 16 | Copy and securely store your API key on your machine as an environment variable. 17 | The application will use it to access the OpenAI API. 18 | 19 | ```shell 20 | export OPENAI_API_KEY= 21 | ``` 22 | 23 | ## Running the application 24 | 25 | Run the application. 26 | 27 | ```shell 28 | ./gradlew bootRun 29 | ``` 30 | 31 | ## Calling the application 32 | 33 | > [!NOTE] 34 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 35 | 36 | Call the application that will use a chat model to answer your question. 37 | 38 | ```shell 39 | http --raw "What is the capital of Italy?" :8080/chat/simple -b --pretty none 40 | ``` 41 | 42 | ```shell 43 | http --raw "What is the capital of Italy?" :8080/chat/prompt -b --pretty none 44 | ``` 45 | 46 | ```shell 47 | http --raw "What is the capital of Italy?" :8080/chat/full -b 48 | ``` 49 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-openai/src/main/java/com/thomasvitale/ai/spring/PromptsBasicsOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsBasicsOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsBasicsOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-openai/src/main/java/com/thomasvitale/ai/spring/model/ChatModelController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring.model; 2 | 3 | import org.springframework.ai.chat.model.ChatModel; 4 | import org.springframework.ai.chat.model.ChatResponse; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * Chat examples using the low-level ChatModel API. 13 | */ 14 | @RestController 15 | @RequestMapping("/model") 16 | class ChatModelController { 17 | 18 | private final ChatModel chatModel; 19 | 20 | ChatModelController(ChatModel chatModel) { 21 | this.chatModel = chatModel; 22 | } 23 | 24 | @PostMapping("/chat/simple") 25 | String chatText(@RequestBody String question) { 26 | return chatModel.call(question); 27 | } 28 | 29 | @PostMapping("/chat/prompt") 30 | String chatPrompt(@RequestBody String question) { 31 | return chatModel.call(new Prompt(question)).getResult().getOutput().getText(); 32 | } 33 | 34 | @PostMapping("/chat/full") 35 | ChatResponse chatFullResponse(@RequestBody String question) { 36 | return chatModel.call(new Prompt(question)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-basics-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/src/main/java/com/thomasvitale/ai/spring/PromptsMessagesOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsMessagesOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsMessagesOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/src/main/resources/prompts/system-message.st: -------------------------------------------------------------------------------- 1 | You are a funny and hilarious assistant. 2 | Answer in one sentence using a very informal language 3 | and start the answer with a knock knowck joke. -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/src/test/java/com/thomasvitale/ai/spring/PromptsMessagesOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.ValueSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | @AutoConfigureWebTestClient(timeout = "60s") 14 | class PromptsMessagesOllamaApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/chat/single", "/model/chat/single", "/chat/multiple", "/model/chat/multiple", "/chat/external", "/model/chat/external"}) 21 | void chat(String path) { 22 | webTestClient 23 | .post() 24 | .uri(path) 25 | .bodyValue("What is the capital of Italy?") 26 | .exchange() 27 | .expectStatus().isOk() 28 | .expectBody(String.class).value(result -> { 29 | assertThat(result).containsIgnoringCase("Rome"); 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-openai/README.md: -------------------------------------------------------------------------------- 1 | # Prompts Messages: OpenAI 2 | 3 | Prompting using structured messages and roles with LLMs via OpenAI. 4 | 5 | ## OpenAI 6 | 7 | The application consumes models from the [OpenAI](https://openai.com) platform. 8 | 9 | ### Create an account 10 | 11 | Visit [platform.openai.com](https://platform.openai.com) and sign up for a new account. 12 | 13 | ### Configure API Key 14 | 15 | In the OpenAI console, navigate to _Dashboard > API Keys_ and generate a new API key. 16 | Copy and securely store your API key on your machine as an environment variable. 17 | The application will use it to access the OpenAI API. 18 | 19 | ```shell 20 | export OPENAI_API_KEY= 21 | ``` 22 | 23 | ## Running the application 24 | 25 | Run the application. 26 | 27 | ```shell 28 | ./gradlew bootRun 29 | ``` 30 | 31 | ## Calling the application 32 | 33 | > [!NOTE] 34 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 35 | 36 | Call the application that will use a chat model to answer your question. 37 | 38 | ```shell 39 | http --raw "What is the capital of Italy?" :8080/chat/single -b --pretty none 40 | ``` 41 | 42 | ```shell 43 | http --raw "What is the capital of Italy?" :8080/chat/multiple -b --pretty none 44 | ``` 45 | 46 | ```shell 47 | http --raw "What is the capital of Italy?" :8080/chat/external -b --pretty none 48 | ``` 49 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-openai/src/main/java/com/thomasvitale/ai/spring/PromptsMessagesOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsMessagesOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsMessagesOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-messages-openai/src/main/resources/prompts/system-message.st: -------------------------------------------------------------------------------- 1 | You are a funny and hilarious assistant. 2 | Answer in one sentence using a very informal language 3 | and start the answer with a knock knowck joke. -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/main/java/com/thomasvitale/ai/spring/MusicQuestion.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record MusicQuestion(String genre, String instrument) {} 4 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/main/java/com/thomasvitale/ai/spring/PromptsTemplatesOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsTemplatesOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsTemplatesOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/main/resources/prompts/system-message.st: -------------------------------------------------------------------------------- 1 | You are a helpful assistant that always replies starting with {greeting} 2 | and a knock knock joke. -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/test/java/com/thomasvitale/ai/spring/PromptsTemplatesOllamaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.ValueSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.web.reactive.server.WebTestClient; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 13 | @AutoConfigureWebTestClient(timeout = "60s") 14 | class PromptsTemplatesOllamaApplicationTests { 15 | 16 | @Autowired 17 | WebTestClient webTestClient; 18 | 19 | @ParameterizedTest 20 | @ValueSource(strings = {"/chat/system", "/model/chat/system", "/chat/external", "/model/chat/external"}) 21 | void chat(String path) { 22 | webTestClient 23 | .post() 24 | .uri(path) 25 | .bodyValue("What is the capital of Italy?") 26 | .exchange() 27 | .expectStatus().isOk() 28 | .expectBody(String.class).value(result -> { 29 | assertThat(result).containsIgnoringCase("Rome"); 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/README.md: -------------------------------------------------------------------------------- 1 | # Prompts Templates: OpenAI 2 | 3 | Prompting using templates with LLMs via OpenAI. 4 | 5 | ## OpenAI 6 | 7 | The application consumes models from the [OpenAI](https://openai.com) platform. 8 | 9 | ### Create an account 10 | 11 | Visit [platform.openai.com](https://platform.openai.com) and sign up for a new account. 12 | 13 | ### Configure API Key 14 | 15 | In the OpenAI console, navigate to _Dashboard > API Keys_ and generate a new API key. 16 | Copy and securely store your API key on your machine as an environment variable. 17 | The application will use it to access the OpenAI API. 18 | 19 | ```shell 20 | export OPENAI_API_KEY= 21 | ``` 22 | 23 | ## Running the application 24 | 25 | Run the application. 26 | 27 | ```shell 28 | ./gradlew bootRun 29 | ``` 30 | 31 | ## Calling the application 32 | 33 | > [!NOTE] 34 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 35 | 36 | Call the application that will use a chat model to answer your question. 37 | 38 | ```shell 39 | http :8080/chat/user genre="rock" instrument="piano" -b --pretty none 40 | ``` 41 | 42 | ```shell 43 | http --raw "What is the capital of Italy?" :8080/chat/system -b --pretty none 44 | ``` 45 | 46 | ```shell 47 | http --raw "What is the capital of Italy?" :8080/chat/external -b --pretty none 48 | ``` 49 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/src/main/java/com/thomasvitale/ai/spring/MusicQuestion.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record MusicQuestion(String genre, String instrument) {} 4 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/src/main/java/com/thomasvitale/ai/spring/PromptsTemplatesOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PromptsTemplatesOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PromptsTemplatesOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/prompts/prompts-templates-openai/src/main/resources/prompts/system-message.st: -------------------------------------------------------------------------------- 1 | You are a helpful assistant that always replies starting with {greeting} 2 | and a knock knock joke. -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/main/java/com/thomasvitale/ai/spring/ArtistInfo.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record ArtistInfo(String name, String band) {} 4 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/main/java/com/thomasvitale/ai/spring/CountryInfo.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | public record CountryInfo( 8 | @JsonProperty(required = true) String name, 9 | @JsonProperty(required = true) String capital, 10 | @JsonProperty(required = true) List languages 11 | ) {} 12 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/main/java/com/thomasvitale/ai/spring/MusicQuestion.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record MusicQuestion(String genre, String instrument){} 4 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/main/java/com/thomasvitale/ai/spring/OutputParsersOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class OutputParsersOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(OutputParsersOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/README.md: -------------------------------------------------------------------------------- 1 | # Structured Output: OpenAI 2 | 3 | Converting the LLM output to structured Java objects via OpenAI. 4 | 5 | ## OpenAI 6 | 7 | The application consumes models from the [OpenAI](https://openai.com) platform. 8 | 9 | ### Create an account 10 | 11 | Visit [platform.openai.com](https://platform.openai.com) and sign up for a new account. 12 | 13 | ### Configure API Key 14 | 15 | In the OpenAI console, navigate to _Dashboard > API Keys_ and generate a new API key. 16 | Copy and securely store your API key on your machine as an environment variable. 17 | The application will use it to access the OpenAI API. 18 | 19 | ```shell 20 | export OPENAI_API_KEY= 21 | ``` 22 | 23 | ## Running the application 24 | 25 | Run the application. 26 | 27 | ```shell 28 | ./gradlew bootRun 29 | ``` 30 | 31 | ## Calling the application 32 | 33 | > [!NOTE] 34 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 35 | 36 | Call the application that will use a chat model to answer your question. 37 | 38 | ```shell 39 | http :8080/chat/bean genre="rock" instrument="piano" -b 40 | ``` 41 | 42 | ```shell 43 | http POST :8080/chat/map -b 44 | ``` 45 | 46 | ```shell 47 | http :8080/chat/list genre="rock" instrument="piano" -b 48 | ``` 49 | 50 | OpenAI has also a native structured output feature, available through the Spring AI `ChatModel` API. 51 | 52 | ```shell 53 | http :8080/model/chat/json genre="rock" instrument="piano" -b 54 | ``` 55 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation 'org.springframework.ai:spring-ai-starter-model-openai' 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/src/main/java/com/thomasvitale/ai/spring/ArtistInfo.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record ArtistInfo(String name, String band) {} 4 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/src/main/java/com/thomasvitale/ai/spring/ArtistInfoVariant.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public record ArtistInfoVariant(@JsonProperty(required = true) String name, @JsonProperty(required = true) String band) {} 6 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/src/main/java/com/thomasvitale/ai/spring/MusicQuestion.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record MusicQuestion(String genre, String instrument){} 4 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/src/main/java/com/thomasvitale/ai/spring/OutputParsersBeanOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class OutputParsersBeanOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(OutputParsersBeanOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/structured-output/structured-output-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-mistral-ai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation "org.springframework.ai:spring-ai-starter-model-mistral-ai" 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-mistral-ai/src/main/java/com/thomasvitale/ai/spring/ToolCallingMistralAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ToolCallingMistralAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ToolCallingMistralAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-mistral-ai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | mistralai: 4 | api-key: ${MISTRALAI_API_KEY} 5 | chat: 6 | options: 7 | model: mistral-small-latest 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-ollama/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation "org.springframework.ai:spring-ai-starter-model-ollama" 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-ollama/src/main/java/com/thomasvitale/ai/spring/ToolCallingOllamaApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ToolCallingOllamaApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ToolCallingOllamaApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-ollama/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | temperature: 0.7 12 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-ollama/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-openai/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation platform("org.springframework.ai:spring-ai-bom:${springAiVersion}") 25 | 26 | implementation 'org.springframework.boot:spring-boot-starter-web' 27 | implementation "org.springframework.ai:spring-ai-starter-model-openai" 28 | 29 | developmentOnly 'org.springframework.boot:spring-boot-devtools' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-openai/src/main/java/com/thomasvitale/ai/spring/ToolCallingOpenAiApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ToolCallingOpenAiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ToolCallingOpenAiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /patterns/tool-calling/tool-calling-openai/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | openai: 4 | api-key: ${OPENAI_API_KEY} 5 | chat: 6 | options: 7 | model: gpt-3.5-turbo 8 | temperature: 0.7 9 | -------------------------------------------------------------------------------- /rag/rag-branching/src/main/java/com/thomasvitale/ai/spring/RagBranching.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RagBranching { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RagBranching.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /rag/rag-branching/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: rag-branching 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | ollama: 10 | init: 11 | pull-model-strategy: when_missing 12 | chat: 13 | options: 14 | model: granite3.2:2b 15 | num-ctx: 4096 16 | embedding: 17 | options: 18 | model: nomic-embed-text 19 | vectorstore: 20 | observations: 21 | log-query-response: true 22 | pgvector: 23 | initialize-schema: true 24 | dimensions: 768 25 | index-type: hnsw 26 | http: 27 | client: 28 | read-timeout: 60s 29 | threads: 30 | virtual: 31 | enabled: true 32 | 33 | logging: 34 | level: 35 | org.springframework.ai.rag: debug 36 | 37 | management: 38 | endpoints: 39 | web: 40 | exposure: 41 | include: "*" 42 | 43 | arconia: 44 | dev: 45 | services: 46 | postgresql: 47 | image-name: pgvector/pgvector:pg17 48 | otel: 49 | metrics: 50 | interval: 5s 51 | -------------------------------------------------------------------------------- /rag/rag-branching/src/test/java/com/thomasvitale/ai/spring/RagBranchingTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class RagBranchingTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /rag/rag-branching/src/test/java/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /rag/rag-conditional/src/main/java/com/thomasvitale/ai/spring/RagConditional.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RagConditional { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RagConditional.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /rag/rag-conditional/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: rag-branching 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | ollama: 10 | init: 11 | pull-model-strategy: when_missing 12 | chat: 13 | options: 14 | model: granite3.2:2b 15 | num-ctx: 4096 16 | embedding: 17 | options: 18 | model: nomic-embed-text 19 | vectorstore: 20 | observations: 21 | log-query-response: true 22 | pgvector: 23 | initialize-schema: true 24 | dimensions: 768 25 | index-type: hnsw 26 | http: 27 | client: 28 | read-timeout: 60s 29 | threads: 30 | virtual: 31 | enabled: true 32 | 33 | logging: 34 | level: 35 | org.springframework.ai.rag: debug 36 | 37 | management: 38 | endpoints: 39 | web: 40 | exposure: 41 | include: "*" 42 | 43 | arconia: 44 | dev: 45 | services: 46 | postgresql: 47 | image-name: pgvector/pgvector:pg17 48 | otel: 49 | metrics: 50 | interval: 5s 51 | -------------------------------------------------------------------------------- /rag/rag-conditional/src/test/java/com/thomasvitale/ai/spring/RagConditionalTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class RagConditionalTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /rag/rag-conditional/src/test/java/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /rag/rag-sequential/rag-advanced/src/main/java/com/thomasvitale/ai/spring/RagAdvanced.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RagAdvanced { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RagAdvanced.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-advanced/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: rag-advanced 4 | ai: 5 | chat: 6 | observations: 7 | log-completion: true 8 | log-prompt: true 9 | ollama: 10 | init: 11 | pull-model-strategy: when_missing 12 | chat: 13 | options: 14 | model: granite3.2:2b 15 | num-ctx: 4096 16 | embedding: 17 | options: 18 | model: nomic-embed-text 19 | vectorstore: 20 | observations: 21 | log-query-response: true 22 | pgvector: 23 | initialize-schema: true 24 | dimensions: 768 25 | index-type: hnsw 26 | http: 27 | client: 28 | read-timeout: 60s 29 | threads: 30 | virtual: 31 | enabled: true 32 | 33 | logging: 34 | level: 35 | org.springframework.ai.rag: debug 36 | 37 | management: 38 | endpoints: 39 | web: 40 | exposure: 41 | include: "*" 42 | 43 | arconia: 44 | dev: 45 | services: 46 | postgresql: 47 | image-name: pgvector/pgvector:pg17 48 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-advanced/src/test/java/com/thomasvitale/ai/spring/RagAdvancedTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class RagAdvancedTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-advanced/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /rag/rag-sequential/rag-naive/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 25 | implementation 'org.springframework.ai:spring-ai-starter-vector-store-pgvector' 26 | implementation 'org.springframework.ai:spring-ai-markdown-document-reader' 27 | implementation 'org.springframework.ai:spring-ai-rag' 28 | 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 30 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql' 31 | 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | dependencyManagement { 37 | imports { 38 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 39 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 40 | } 41 | } 42 | 43 | tasks.named('test') { 44 | useJUnitPlatform() 45 | } 46 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-naive/src/main/java/com/thomasvitale/ai/spring/RagNaive.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RagNaive { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RagNaive.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-naive/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | options: 8 | model: granite3.2:2b 9 | num-ctx: 4096 10 | embedding: 11 | options: 12 | model: nomic-embed-text 13 | vectorstore: 14 | pgvector: 15 | initialize-schema: true 16 | dimensions: 768 17 | index-type: hnsw 18 | threads: 19 | virtual: 20 | enabled: true 21 | 22 | logging: 23 | level: 24 | org.springframework.ai.rag: debug 25 | 26 | arconia: 27 | dev: 28 | services: 29 | postgresql: 30 | image-name: pgvector/pgvector:pg17 31 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-naive/src/test/java/com/thomasvitale/ai/spring/RagNaiveTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Disabled; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | @Disabled 9 | class RagNaiveTests { 10 | 11 | @Test 12 | void contextLoads() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /rag/rag-sequential/rag-naive/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true 6 | -------------------------------------------------------------------------------- /use-cases/chatbot/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /use-cases/chatbot/src/main/java/com/thomasvitale/ai/spring/Chatbot.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Chatbot { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Chatbot.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/chatbot/src/main/java/com/thomasvitale/ai/spring/ChatbotController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 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.web.bind.annotation.PathVariable; 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 | import static org.springframework.ai.chat.memory.ChatMemory.CONVERSATION_ID; 12 | 13 | @RestController 14 | class ChatbotController { 15 | 16 | private final ChatClient chatClient; 17 | 18 | ChatbotController(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory) { 19 | this.chatClient = chatClientBuilder.clone() 20 | .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) 21 | .build(); 22 | } 23 | 24 | @PostMapping("/chat/{conversationId}") 25 | String chat(@PathVariable String conversationId, @RequestBody String question) { 26 | return chatClient 27 | .prompt() 28 | .user(question) 29 | .advisors(a -> a.param(CONVERSATION_ID, conversationId)) 30 | .call() 31 | .content(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /use-cases/chatbot/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | -------------------------------------------------------------------------------- /use-cases/chatbot/src/test/java/com/thomasvitale/ai/spring/ChatbotTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ChatbotTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/chatbot/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /use-cases/question-answering/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 25 | implementation 'org.springframework.ai:spring-ai-starter-vector-store-pgvector' 26 | implementation 'org.springframework.ai:spring-ai-rag' 27 | 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 29 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql' 30 | 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testImplementation 'org.springframework:spring-webflux' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | dependencyManagement { 37 | imports { 38 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 39 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 40 | } 41 | } 42 | 43 | tasks.named('test') { 44 | useJUnitPlatform() 45 | } 46 | -------------------------------------------------------------------------------- /use-cases/question-answering/src/main/java/com/thomasvitale/ai/spring/QuestionAnswering.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class QuestionAnswering { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(QuestionAnswering.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/question-answering/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | options: 8 | model: granite3.2:2b 9 | num-ctx: 4096 10 | embedding: 11 | options: 12 | model: nomic-embed-text 13 | vectorstore: 14 | pgvector: 15 | initialize-schema: true 16 | dimensions: 768 17 | index-type: hnsw 18 | 19 | arconia: 20 | dev: 21 | services: 22 | postgresql: 23 | image-name: pgvector/pgvector:pg17 24 | -------------------------------------------------------------------------------- /use-cases/question-answering/src/test/java/com/thomasvitale/ai/spring/QuestionAnsweringTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class QuestionAnsweringTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/question-answering/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /use-cases/semantic-search/README.md: -------------------------------------------------------------------------------- 1 | # Semantic Search 2 | 3 | Semantic search with LLMs via Ollama and PGVector. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | Under the hood, the Arconia framework will automatically spin up a PostgreSQL database using Testcontainers. 22 | 23 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 24 | 25 | ```shell 26 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 27 | ``` 28 | 29 | ## Calling the application 30 | 31 | > [!NOTE] 32 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 33 | 34 | Call the application that will perform semantic searches. 35 | 36 | ```shell 37 | http --raw "happiness" :8080/semantic-search -b 38 | ``` 39 | -------------------------------------------------------------------------------- /use-cases/semantic-search/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 25 | implementation 'org.springframework.ai:spring-ai-starter-vector-store-pgvector' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql' 29 | 30 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 31 | testImplementation 'org.springframework:spring-webflux' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 38 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 39 | } 40 | } 41 | 42 | tasks.named('test') { 43 | useJUnitPlatform() 44 | } 45 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/main/java/com/thomasvitale/ai/spring/InstrumentNote.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public record InstrumentNote(String content) {} 4 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/main/java/com/thomasvitale/ai/spring/SemanticSearch.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SemanticSearch { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SemanticSearch.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/main/java/com/thomasvitale/ai/spring/SemanticSearchController.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.ai.vectorstore.SearchRequest; 4 | import org.springframework.ai.vectorstore.VectorStore; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | class SemanticSearchController { 13 | 14 | private final VectorStore vectorStore; 15 | 16 | SemanticSearchController(VectorStore vectorStore) { 17 | this.vectorStore = vectorStore; 18 | } 19 | 20 | @PostMapping("/semantic-search") 21 | List semanticSearch(@RequestBody String query) { 22 | return vectorStore.similaritySearch(SearchRequest.builder().query(query).topK(3).build()) 23 | .stream() 24 | .map(document -> new InstrumentNote(document.getText())) 25 | .toList(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | chat: 7 | include: false 8 | embedding: 9 | options: 10 | model: nomic-embed-text 11 | vectorstore: 12 | pgvector: 13 | initialize-schema: true 14 | dimensions: 768 15 | index-type: hnsw 16 | 17 | arconia: 18 | dev: 19 | services: 20 | postgresql: 21 | image-name: pgvector/pgvector:pg17 22 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/test/java/com/thomasvitale/ai/spring/SemanticSearchTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SemanticSearchTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/semantic-search/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/README.md: -------------------------------------------------------------------------------- 1 | # Structured Data Extraction 2 | 3 | Structured data extraction with LLMs via Ollama. 4 | 5 | ## Ollama 6 | 7 | The application consumes models from an [Ollama](https://ollama.ai) inference server. You can either run Ollama locally on your laptop, 8 | or rely on the Testcontainers support in Spring Boot to spin up an Ollama service automatically. 9 | If you choose the first option, make sure you have Ollama installed and running on your laptop. 10 | Either way, Spring AI will take care of pulling the needed Ollama models when the application starts, 11 | if they are not available yet on your machine. 12 | 13 | ## Running the application 14 | 15 | If you're using the native Ollama application, run the application as follows: 16 | 17 | ```shell 18 | ./gradlew bootRun 19 | ``` 20 | 21 | If instead you want to rely on the Ollama Dev Service via Testcontainers, run the application as follows. 22 | 23 | ```shell 24 | ./gradlew bootRun -Darconia.dev.services.ollama.enabled=true 25 | ``` 26 | 27 | ## Calling the application 28 | 29 | > [!NOTE] 30 | > These examples use the [httpie](https://httpie.io) CLI to send HTTP requests. 31 | 32 | Call the application that will use a chat model to extract structured data from unstructured text. 33 | 34 | ```shell 35 | http --raw "I'm visiting Jon Snow. The blood pressure looks fine: 120/80. The temperature is 36 degrees. The diagnosis is: he knows nothing." :8080/extract 36 | ``` 37 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | } 6 | 7 | group = 'com.thomasvitale' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(24) 13 | nativeImageCapable = true 14 | } 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | maven { url 'https://repo.spring.io/snapshot' } 20 | } 21 | 22 | dependencies { 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 25 | 26 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 27 | 28 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 29 | testImplementation 'org.springframework:spring-webflux' 30 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 31 | } 32 | 33 | dependencyManagement { 34 | imports { 35 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 36 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/src/main/java/com/thomasvitale/ai/spring/PatientJournal.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import java.util.List; 4 | 5 | public record PatientJournal(String fullName, List observations, Diagnosis diagnosis) { 6 | public record Observation(Type type, String content) {} 7 | public record Diagnosis(String content) {} 8 | 9 | enum Type { 10 | BODY_WEIGHT, 11 | TEMPERATURE, 12 | VITAL_SIGNS, 13 | OTHER 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/src/main/java/com/thomasvitale/ai/spring/StructuredDataExtraction.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StructuredDataExtraction { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(StructuredDataExtraction.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/src/test/java/com/thomasvitale/ai/spring/StructuredDataExtractionTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 7 | class StructuredDataExtractionTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/structured-data-extraction/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true -------------------------------------------------------------------------------- /use-cases/text-classification/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' 4 | id 'io.spring.dependency-management' 5 | id 'org.graalvm.buildtools.native' 6 | } 7 | 8 | group = 'com.thomasvitale' 9 | version = '0.0.1-SNAPSHOT' 10 | 11 | java { 12 | toolchain { 13 | languageVersion = JavaLanguageVersion.of(24) 14 | nativeImageCapable = true 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/snapshot' } 21 | } 22 | 23 | dependencies { 24 | implementation 'org.springframework.boot:spring-boot-starter-web' 25 | implementation 'org.springframework.ai:spring-ai-starter-model-ollama' 26 | 27 | testAndDevelopmentOnly 'io.arconia:arconia-dev-services-ollama' 28 | 29 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 30 | testImplementation 'org.springframework:spring-webflux' 31 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "io.arconia:arconia-bom:${arconiaVersion}" 37 | mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}" 38 | } 39 | } 40 | 41 | tasks.named('test') { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /use-cases/text-classification/src/main/java/com/thomasvitale/ai/spring/ClassificationType.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | public enum ClassificationType { 4 | BUSINESS, SPORT, TECHNOLOGY, OTHER; 5 | } 6 | -------------------------------------------------------------------------------- /use-cases/text-classification/src/main/java/com/thomasvitale/ai/spring/TextClassificationApplication.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TextClassificationApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TextClassificationApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/text-classification/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | ai: 3 | ollama: 4 | init: 5 | pull-model-strategy: when_missing 6 | embedding: 7 | include: false 8 | chat: 9 | options: 10 | model: granite3.2:2b 11 | -------------------------------------------------------------------------------- /use-cases/text-classification/src/test/java/com/thomasvitale/ai/spring/TextClassificationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.thomasvitale.ai.spring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 7 | class TextClassificationApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /use-cases/text-classification/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | arconia: 2 | dev: 3 | services: 4 | ollama: 5 | enabled: true --------------------------------------------------------------------------------