├── slides.pdf ├── devoxx-genai-langchain4j ├── README.md ├── src │ └── test │ │ ├── java │ │ └── devoxx │ │ │ └── demo │ │ │ ├── _7_functions │ │ │ └── _71_CallFunctionTest.java │ │ │ ├── _5_vectorsearch │ │ │ ├── _51_EmbeddingModel.java │ │ │ ├── _54_CassandraVectorStore.java │ │ │ ├── _55_AstraVectorTest.java │ │ │ ├── _52_CassandraVectorDbTest.java │ │ │ └── _53_CassIOVectorDbTest.java │ │ │ ├── utils │ │ │ ├── Assistant.java │ │ │ ├── Utils.java │ │ │ └── AbstractDevoxxTestSupport.java │ │ │ ├── _1_vertexai │ │ │ ├── _11_LanguageModel_SayHelloTest.java │ │ │ ├── _16_PromptTemplateTest.java │ │ │ ├── _12_LanguageModel_ModelTuningTest.java │ │ │ ├── _15_ChatLanguageModel_SayHelloTest.java │ │ │ ├── _14_ImageModel_GenerateTest.java │ │ │ └── _13_LanguageModel_ExtractTextTest.java │ │ │ ├── _2_gemma │ │ │ └── _21_GemmaChat.java │ │ │ └── _6_rag │ │ │ ├── _63_AdvancedRag_AugmentWithMetadata.java │ │ │ ├── _64_AdvancedRag_QueryRouting.java │ │ │ ├── _65_AdvancedRag_QueryCompression.java │ │ │ ├── _66_AdvancedRag_QueryReranking.java │ │ │ ├── _62_NaiveRag_RetrievalTest.java │ │ │ └── _61_NaiveRag_IngestionTest.java │ │ └── resources │ │ ├── logback-test.xml │ │ ├── shadow.txt │ │ └── johnny.txt └── pom.xml ├── devoxx-genai-langchain4j-gemini ├── README.md ├── src │ └── test │ │ ├── resources │ │ ├── img1.png │ │ ├── logback-test.xml │ │ ├── doc.MD │ │ ├── story-about-happy-carrot.txt │ │ └── johnny.txt │ │ └── java │ │ └── devoxx │ │ └── demo │ │ └── gemini │ │ ├── _1_vertexai │ │ └── _10_LanguageModelSayHello.java │ │ └── _7_functions │ │ └── _71_CallFunctionTest.java └── pom.xml ├── libs ├── langchain4j-astradb-0.29.1.jar ├── langchain4j-cassandra-0.29.1.jar └── commands.md ├── devoxx-genai-utilities ├── src │ └── main │ │ └── java │ │ └── devoxx │ │ └── demo │ │ └── devoxx │ │ ├── Product.java │ │ ├── Quote.java │ │ └── Utilities.java └── pom.xml ├── devoxx-genai-vertexai-client ├── src │ └── test │ │ ├── resources │ │ ├── img1.png │ │ └── logback-test.xml │ │ └── java │ │ └── devoxx │ │ └── demo │ │ └── gemini │ │ ├── Demo01_VertexClientChat.java │ │ └── Demo02_VertexClientVisionPro.java ├── README.md └── pom.xml ├── devoxx-genai-springai ├── src │ ├── test │ │ ├── resources │ │ │ ├── prompts │ │ │ │ └── system-message.st │ │ │ └── logback-test.xml │ │ └── java │ │ │ └── devoxx │ │ │ └── demo │ │ │ ├── _02_PromptTemplateTest.java │ │ │ └── _01_LanguageModel_SayHelloTest.java │ └── main │ │ ├── java │ │ └── devoxx │ │ │ └── demo │ │ │ └── DevoxxSpringAiGeminiApplication.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── .gitignore ├── bedtimestories-gke ├── k8s │ └── manifests.yaml └── README.md ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── README.MD ├── pom.xml └── LICENSE.md /slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/conference-2024-devoxx-france/main/slides.pdf -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/README.md: -------------------------------------------------------------------------------- 1 | # langchain4j-astradb-demo 2 | Sample Codes to use AstraDB as VectorStore for Langchain4j 3 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/README.md: -------------------------------------------------------------------------------- 1 | # langchain4j-astradb-demo 2 | Sample Codes to use AstraDB as VectorStore for Langchain4j 3 | -------------------------------------------------------------------------------- /libs/langchain4j-astradb-0.29.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/conference-2024-devoxx-france/main/libs/langchain4j-astradb-0.29.1.jar -------------------------------------------------------------------------------- /libs/langchain4j-cassandra-0.29.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/conference-2024-devoxx-france/main/libs/langchain4j-cassandra-0.29.1.jar -------------------------------------------------------------------------------- /devoxx-genai-utilities/src/main/java/devoxx/demo/devoxx/Product.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.devoxx; 2 | 3 | public record Product(String productId, String productName, Object vector) {} 4 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/src/test/resources/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/conference-2024-devoxx-france/main/devoxx-genai-vertexai-client/src/test/resources/img1.png -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/resources/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/conference-2024-devoxx-france/main/devoxx-genai-langchain4j-gemini/src/test/resources/img1.png -------------------------------------------------------------------------------- /devoxx-genai-utilities/src/main/java/devoxx/demo/devoxx/Quote.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.devoxx; 2 | 3 | import java.util.List; 4 | 5 | public record Quote(String rowId, String author, List tags, String body) {} 6 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/test/resources/prompts/system-message.st: -------------------------------------------------------------------------------- 1 | "You are a helpful AI assistant. Your name is {name}. 2 | You are an AI assistant that helps people find information. 3 | Your name is {name} 4 | You should reply to the user's request with your name and also in the style of a {voice}. -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_7_functions/_71_CallFunctionTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._7_functions; 2 | 3 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 4 | 5 | public class _71_CallFunctionTest extends AbstractDevoxxTestSupport { 6 | 7 | // CF IN GEMINI, ONLY GEMINI IS SUPPORTED 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | astra-sdk-java.wiki/ 2 | .env 3 | .astrarc 4 | sec 5 | 6 | # eclipse conf file 7 | .settings 8 | .classpath 9 | .project 10 | .cache 11 | 12 | # idea conf files 13 | .idea 14 | *.ipr 15 | *.iws 16 | *.iml 17 | 18 | # building 19 | target 20 | build 21 | tmp 22 | dist 23 | 24 | # misc 25 | .DS_Store 26 | 27 | .factorypath 28 | .sts4-cache 29 | *.log 30 | 31 | release.properties 32 | pom.xml.releaseBackup 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/main/java/devoxx/demo/DevoxxSpringAiGeminiApplication.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DevoxxSpringAiGeminiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DevoxxSpringAiGeminiApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.ai.vertex.ai.gemini.projectId=devoxxfrance 2 | spring.ai.vertex.ai.gemini.location=us-central1 3 | spring.ai.vertex.ai.gemini.chat.options.model=gemini-pro 4 | spring.ai.vertex.ai.gemini.chat.options.temperature=0.8 5 | spring.ai.vertex.ai.gemini.chat.options.topK=2 6 | spring.ai.vertex.ai.gemini.chat.options.topP=0.9 7 | spring.ai.vertex.ai.gemini.chat.options.maxTokens=100 8 | 9 | #spring.ai.vertex.ai.gemini.credentialsUri= -------------------------------------------------------------------------------- /libs/commands.md: -------------------------------------------------------------------------------- 1 | 2 | Jars to install (until it is merged into the main repo): 3 | 4 | ```console 5 | mvn install:install-file \ 6 | -Dfile=langchain4j-cassandra-0.29.1.jar \ 7 | -DgroupId=dev.langchain4j \ 8 | -DartifactId=langchain4j-cassandra \ 9 | -Dversion=0.29.1 \ 10 | -Dpackaging=jar 11 | ``` 12 | 13 | ```console 14 | mvn install:install-file \ 15 | -Dfile=langchain4j-astradb-0.29.1.jar \ 16 | -DgroupId=dev.langchain4j \ 17 | -DartifactId=langchain4j-astradb \ 18 | -Dversion=0.29.1 \ 19 | -Dpackaging=jar 20 | ``` 21 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-20logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-20logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-20logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-20logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/README.md: -------------------------------------------------------------------------------- 1 | # langchain4j-astradb-demo 2 | 3 | Sample Codes to use VertexAI directly from Java using the Google Libraries 4 | 5 | ## Setup 6 | 7 | gcloud config set project devoxxfrance 8 | gcloud auth login 9 | gcloud auth application-default login 10 | 11 | ## Build dependencies 12 | 13 | Run from the parent folder 14 | 15 | ``` 16 | mvn clean 17 | ``` 18 | 19 | ## Run VertexAI chat with gemini-pro 20 | 21 | ``` 22 | mvn test -Dtest=Demo01_VertexClientChat#testChat 23 | ``` 24 | 25 | ## Run VertexAI image recognition with gemini-pro-vision 26 | 27 | ``` 28 | mvn test -Dtest=Demo02_VertexClientVisionPro#testVision 29 | ``` 30 | 31 | To try an other picture replace ```img1.png``` in the ```/resources``` folder 32 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_5_vectorsearch/_51_EmbeddingModel.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._5_vectorsearch; 2 | 3 | import dev.langchain4j.data.embedding.Embedding; 4 | import dev.langchain4j.model.output.Response; 5 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.jupiter.api.Test; 8 | 9 | @Slf4j 10 | public class _51_EmbeddingModel extends AbstractDevoxxTestSupport { 11 | 12 | @Test 13 | public void testEmbeddingModel() { 14 | Response embedding = getEmbeddingModelGecko().embed("Hello, World!"); 15 | log.info("Dimension: {}", embedding.content().dimension()); 16 | log.info("Vector: {}", embedding.content().vectorAsList()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/resources/doc.MD: -------------------------------------------------------------------------------- 1 | 2 | ### Setup Google 3 | 4 | - Authenticate with the browser 5 | 6 | ```console 7 | gcloud auth application-default login 8 | ``` 9 | 10 | - List Projects 11 | 12 | ```console 13 | gcloud projects list 14 | ``` 15 | 16 | > Output 17 | > 18 | > ```console 19 | > PROJECT_ID NAME PROJECT_NUMBER 20 | > datastax-gcp-mp-dev datastax-gcp-mp-dev 345489893840 21 | > datastax-gcp-mp-test datastax-gcp-mp-test 90574246729 22 | > devoxxfrance devoxxfrance 55199250840 23 | > ``` 24 | 25 | - Set Project 26 | 27 | ```console 28 | gcloud config set project 55199250840 29 | ``` 30 | 31 | - Set the quota for the project 32 | ```console 33 | gcloud auth application-default set-quota-project 55199250840 34 | gcloud compute project-info describe --project devoxxfrance 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/utils/Assistant.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.utils; 2 | 3 | /** 4 | * This is an "AI Service". It is a Java service with AI capabilities/features. 5 | * It can be integrated into your code like any other service, acting as a bean, and can be mocked for testing. 6 | * The goal is to seamlessly integrate AI functionality into your (existing) codebase with minimal friction. 7 | * It's conceptually similar to Spring Data JPA or Retrofit. 8 | * You define an interface and optionally customize it with annotations. 9 | * LangChain4j then provides an implementation for this interface using proxy and reflection. 10 | * This approach abstracts away all the complexity and boilerplate. 11 | * So you won't need to juggle the model, messages, memory, RAG components, tools, output parsers, etc. 12 | * However, don't worry. It's quite flexible and configurable, so you'll be able to tailor it 13 | * to your specific use case. 14 | *
15 | * More info here: https://docs.langchain4j.dev/tutorials/ai-services 16 | */ 17 | public interface Assistant { 18 | 19 | String answer(String query); 20 | } -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_11_LanguageModel_SayHelloTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.model.language.LanguageModel; 4 | import dev.langchain4j.model.output.Response; 5 | import dev.langchain4j.model.vertexai.VertexAiLanguageModel; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 9 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 10 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 11 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 12 | 13 | class _11_LanguageModel_SayHelloTest { 14 | 15 | @Test 16 | public void shouldSayHelloToLLM() { 17 | LanguageModel llm = VertexAiLanguageModel.builder() 18 | .publisher(GCP_PROJECT_PUBLISHER) 19 | .project(GCP_PROJECT_ID) 20 | .endpoint(GCP_PROJECT_ENDPOINT) 21 | .location(GCP_PROJECT_LOCATION) 22 | .publisher(GCP_PROJECT_PUBLISHER) 23 | .modelName("text-bison") 24 | .build(); 25 | Response response = llm.generate("Hello, LLM!"); 26 | System.out.println(response.content()); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/resources/shadow.txt: -------------------------------------------------------------------------------- 1 | Shadow, a sleek black Labrador with a shining coat and wise, deep-set eyes, lives in a quaint village surrounded by vast, rolling fields. Known for his loyalty and intelligence, Shadow belongs to Emily, a young veterinarian who adores him. One brisk autumn morning, Shadow discovers an abandoned litter of kittens in the old barn beside Emily's clinic. His protective instincts kick in, and he guards the kittens, refusing to leave their side until Emily finds him. 2 | 3 | Emily, moved by Shadow's compassion, takes the kittens into her care, but one little kitten is particularly frail. Shadow becomes a constant presence by the kitten's side, gently nudging it to eat and comforting it with his warmth. The villagers soon hear of Shadow's heroics, and his story spreads, warming the hearts of many and highlighting the unspoken bond between animals. 4 | 5 | As the seasons change, the kitten grows stronger under the vigilant care of Shadow and Emily. Shadow's story becomes a testament to loyalty and the nurturing spirit that animals can possess. His days are filled with adventures around the village, but he always returns to check on his now thriving feline friend. Shadow's life exemplifies that even in the smallest creatures, a big heart can be found. -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_16_PromptTemplateTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.model.input.Prompt; 4 | import dev.langchain4j.model.input.PromptTemplate; 5 | import dev.langchain4j.model.output.Response; 6 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * This test demonstrates how to use a prompt template to generate a prompt for a language model. 14 | * MUSTACHE 15 | */ 16 | class _16_PromptTemplateTest extends AbstractDevoxxTestSupport { 17 | 18 | @Test 19 | void prompt() { 20 | PromptTemplate promptTemplate = PromptTemplate.from(""" 21 | Explain me why a {{profile}} should attend conference {{conference}}. 22 | The conference is on {{current_date}} at {{current_time}} with {{current_date_time}} 23 | """); 24 | 25 | Map variables = new HashMap<>(); 26 | variables.put("profile", "Java Developer"); 27 | variables.put("conference", "Devoxx France"); 28 | 29 | Prompt prompt = promptTemplate.apply(variables); 30 | Response response = getLanguageModelTextBison().generate(prompt); 31 | System.out.println(response.content()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_12_LanguageModel_ModelTuningTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.model.language.LanguageModel; 4 | import dev.langchain4j.model.output.Response; 5 | import dev.langchain4j.model.vertexai.VertexAiLanguageModel; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 9 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 10 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 11 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 12 | 13 | public class _12_LanguageModel_ModelTuningTest { 14 | 15 | @Test 16 | public void shouldFineTuneYourRequest() { 17 | 18 | LanguageModel llm = VertexAiLanguageModel.builder() 19 | .publisher(GCP_PROJECT_PUBLISHER) 20 | .project(GCP_PROJECT_ID) 21 | .endpoint(GCP_PROJECT_ENDPOINT) 22 | .location(GCP_PROJECT_LOCATION) 23 | 24 | .modelName("text-bison") 25 | .temperature(0.7) 26 | .topK(3) 27 | .topP(.8) // no both at same time 28 | .maxRetries(3) 29 | .maxOutputTokens(2000) 30 | 31 | .build(); 32 | Response response = llm.generate("What it the capital of France?"); 33 | System.out.println(response.content()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/src/test/java/devoxx/demo/gemini/Demo01_VertexClientChat.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.gemini; 2 | 3 | import com.google.cloud.vertexai.VertexAI; 4 | import com.google.cloud.vertexai.api.GenerateContentResponse; 5 | import com.google.cloud.vertexai.generativeai.ChatSession; 6 | import com.google.cloud.vertexai.generativeai.GenerativeModel; 7 | import com.google.cloud.vertexai.generativeai.ResponseHandler; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 11 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 12 | 13 | public class Demo01_VertexClientChat { 14 | 15 | @Test 16 | public void testChat() throws Exception { 17 | try (VertexAI vertexAI = new VertexAI(GCP_PROJECT_ID, GCP_PROJECT_LOCATION)) { 18 | GenerateContentResponse response; 19 | 20 | GenerativeModel model = new GenerativeModel("gemini-pro", vertexAI); 21 | ChatSession chatSession = new ChatSession(model); 22 | 23 | response = chatSession.sendMessage("Hello."); 24 | System.out.println(ResponseHandler.getText(response)); 25 | 26 | response = chatSession.sendMessage("What are all the colors in a rainbow?"); 27 | System.out.println(ResponseHandler.getText(response)); 28 | 29 | response = chatSession.sendMessage("Why does it appear when it rains?"); 30 | System.out.println(ResponseHandler.getText(response)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_2_gemma/_21_GemmaChat.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._2_gemma; 2 | 3 | import dev.langchain4j.model.chat.ChatLanguageModel; 4 | import dev.langchain4j.model.ollama.OllamaChatModel; 5 | import org.junit.jupiter.api.Test; 6 | 7 | /** 8 | * OLLAMA 9 | * 10 | * Installation 11 | * https://ollama.com/download/mac 12 | * 13 | * Install & Test Gemma 14 | * ollama run gemma:7b 15 | * ollama list 16 | * 17 | * Test Gemma 18 | * 19 | * 20 | curl http://localhost:11434/api/generate -d '{ 21 | "model": "gemma:7b", 22 | "prompt": "Why is the sky blue?" 23 | }' 24 | 25 | clear 26 | curl -N -s http://localhost:11434/api/generate -d '{ 27 | "model": "gemma:7b", 28 | "prompt": "Why is the sky b 29 | clear 30 | curl -N -s http://localhost:11434/api/generate -d '{ 31 | "model": "gemma:7b", 32 | "prompt": "Why is the sky blue?" 33 | }' | while IFS= read -r line; do 34 | echo "$line" | jq -r '.response' 2>/dev/null | tr '\n' ' ' | cut -b 1-50 35 | donelue?" 36 | }' | while IFS= read -r line; do 37 | echo "$line" | jq -r '.response' 2>/dev/null | tr '\n' ' ' | cut -b 1-50 38 | done 39 | 40 | */ 41 | public class _21_GemmaChat { 42 | 43 | @Test 44 | public void talkWithGemma() { 45 | ChatLanguageModel gemma = OllamaChatModel.builder() 46 | .baseUrl("http://localhost:11434/api/") 47 | .modelName("gemma:7b") 48 | .build(); 49 | 50 | System.out.println(gemma.generate("Present yourself , the name of the model, who trained you ?")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_15_ChatLanguageModel_SayHelloTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.data.message.AiMessage; 4 | import dev.langchain4j.data.message.UserMessage; 5 | import dev.langchain4j.model.chat.ChatLanguageModel; 6 | import dev.langchain4j.model.output.Response; 7 | import dev.langchain4j.model.vertexai.VertexAiChatModel; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 11 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 12 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 13 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 14 | 15 | public class _15_ChatLanguageModel_SayHelloTest { 16 | 17 | @Test 18 | public void shouldFineTuneYourRequest() { 19 | 20 | ChatLanguageModel chatModel = VertexAiChatModel.builder() 21 | .publisher(GCP_PROJECT_PUBLISHER) 22 | .project(GCP_PROJECT_ID) 23 | .endpoint(GCP_PROJECT_ENDPOINT) 24 | .location(GCP_PROJECT_LOCATION) 25 | .modelName("chat-bison") 26 | .temperature(0.7) 27 | .topK(3) 28 | .topP(.8) // no both at same time 29 | .maxRetries(3) 30 | .maxOutputTokens(2000) 31 | .build(); 32 | 33 | Response response = chatModel.generate(new UserMessage("What it the capital of France?")); 34 | System.out.println(response.content()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.net.URISyntaxException; 7 | import java.net.URL; 8 | import java.nio.file.FileSystems; 9 | import java.nio.file.Path; 10 | import java.nio.file.PathMatcher; 11 | import java.nio.file.Paths; 12 | import java.util.Scanner; 13 | 14 | 15 | public class Utils { 16 | 17 | public static void startConversationWith(Assistant assistant) { 18 | Logger log = LoggerFactory.getLogger(Assistant.class); 19 | try (Scanner scanner = new Scanner(System.in)) { 20 | while (true) { 21 | log.info("=================================================="); 22 | log.info("User: "); 23 | String userQuery = scanner.nextLine(); 24 | log.info("=================================================="); 25 | 26 | if ("exit".equalsIgnoreCase(userQuery)) { 27 | break; 28 | } 29 | 30 | String agentAnswer = assistant.answer(userQuery); 31 | log.info("=================================================="); 32 | log.info("Assistant: " + agentAnswer); 33 | } 34 | } 35 | } 36 | 37 | public static Path toPath(String relativePath) { 38 | try { 39 | URL fileUrl = Utils.class.getClassLoader().getResource(relativePath); 40 | return Paths.get(fileUrl.toURI()); 41 | } catch (URISyntaxException e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_14_ImageModel_GenerateTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.data.image.Image; 4 | import dev.langchain4j.model.image.ImageModel; 5 | import dev.langchain4j.model.output.Response; 6 | import dev.langchain4j.model.vertexai.VertexAiImageModel; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.util.List; 10 | 11 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 12 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 13 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 14 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | class _14_ImageModel_GenerateTest { 18 | 19 | @Test 20 | public void shouldSayHelloToImageModel() { 21 | ImageModel imagenModel = VertexAiImageModel.builder() 22 | .project(GCP_PROJECT_ID) 23 | .endpoint(GCP_PROJECT_ENDPOINT) 24 | .location(GCP_PROJECT_LOCATION) 25 | .publisher(GCP_PROJECT_PUBLISHER) 26 | .modelName("imagegeneration@005") 27 | .maxRetries(2) 28 | .withPersisting() 29 | .build(); 30 | 31 | Response> imageListResponse = imagenModel.generate("photo of a sunset over Malibu beach", 3); 32 | assertThat(imageListResponse.content()).hasSize(3); 33 | imageListResponse.content().forEach(img -> { 34 | assertThat(img.url()).isNotNull(); 35 | assertThat(img.base64Data()).isNotNull(); 36 | System.out.println(img.url()); 37 | }); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /devoxx-genai-utilities/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | devoxx-genai-utilities 6 | Utilities 7 | 1.0-SNAPSHOT 8 | 9 | 10 | com.google 11 | devoxx-genai-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | provided 22 | 23 | 24 | 25 | com.fasterxml.jackson.core 26 | jackson-core 27 | 28 | 29 | com.fasterxml.jackson.core 30 | jackson-databind 31 | 32 | 33 | 34 | 35 | org.slf4j 36 | slf4j-api 37 | test 38 | 39 | 40 | ch.qos.logback 41 | logback-classic 42 | test 43 | 44 | 45 | 46 | org.junit.jupiter 47 | junit-jupiter-engine 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/test/java/devoxx/demo/_02_PromptTemplateTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.ai.chat.ChatResponse; 5 | import org.springframework.ai.chat.prompt.Prompt; 6 | import org.springframework.ai.chat.prompt.PromptTemplate; 7 | import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.core.io.Resource; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * This test demonstrates how to use a prompt template to generate a prompt for a language model. 18 | * MUSTACHE 19 | */ 20 | @SpringBootTest 21 | public class _02_PromptTemplateTest { 22 | 23 | @Autowired 24 | private VertexAiGeminiChatClient client; 25 | 26 | @Value("classpath:/prompts/system-message.st") 27 | private Resource systemResource; 28 | 29 | @Test 30 | public void prompt() { 31 | 32 | PromptTemplate promptTemplate = new PromptTemplate(""" 33 | Explain me why a {{profile}} should attend conference {{conference}}. 34 | The conference is on {{current_date}} at {{current_time}} with {{current_date_time}} 35 | """); 36 | 37 | Map variables = new HashMap<>(); 38 | variables.put("profile", "Java Developer"); 39 | variables.put("conference", "Devoxx France"); 40 | 41 | Prompt prompt = promptTemplate.create(variables); 42 | ChatResponse response = client.call(prompt); 43 | System.out.println(response.getResult().getOutput().getContent()); 44 | 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /devoxx-genai-springai/src/test/java/devoxx/demo/_01_LanguageModel_SayHelloTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.ai.chat.ChatResponse; 5 | import org.springframework.ai.chat.messages.Message; 6 | import org.springframework.ai.chat.messages.UserMessage; 7 | import org.springframework.ai.chat.prompt.Prompt; 8 | import org.springframework.ai.chat.prompt.SystemPromptTemplate; 9 | import org.springframework.ai.vertexai.gemini.VertexAiGeminiChatClient; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.core.io.Resource; 14 | 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | import static org.assertj.core.api.Assertions.assertThat; 19 | 20 | @SpringBootTest 21 | public class _01_LanguageModel_SayHelloTest { 22 | 23 | @Autowired 24 | private VertexAiGeminiChatClient client; 25 | 26 | @Value("classpath:/prompts/system-message.st") 27 | private Resource systemResource; 28 | 29 | @Test 30 | void roleTest() { 31 | String request = "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."; 32 | String name = "Bob"; 33 | String voice = "pirate"; 34 | UserMessage userMessage = new UserMessage(request); 35 | SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource); 36 | Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice)); 37 | Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); 38 | ChatResponse response = client.call(prompt); 39 | System.out.println(response.getResult().getOutput().getContent()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /bedtimestories-gke/k8s/manifests.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: tgi-gemma-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: gemma-server 10 | template: 11 | metadata: 12 | labels: 13 | app: gemma-server 14 | ai.gke.io/model: gemma-2b-it 15 | ai.gke.io/inference-server: text-generation-inference 16 | examples.ai.gke.io/source: user-guide 17 | spec: 18 | containers: 19 | - name: inference-server 20 | image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-hf-tgi-serve:20240220_0936_RC01 21 | resources: 22 | requests: 23 | cpu: "2" 24 | memory: "7Gi" 25 | ephemeral-storage: "20Gi" 26 | nvidia.com/gpu: 1 27 | limits: 28 | cpu: "2" 29 | memory: "7Gi" 30 | ephemeral-storage: "20Gi" 31 | nvidia.com/gpu: 1 32 | args: 33 | - --model-id=$(MODEL_ID) 34 | - --num-shard=1 35 | env: 36 | - name: MODEL_ID 37 | value: google/gemma-2b-it 38 | - name: PORT 39 | value: "8000" 40 | - name: HUGGING_FACE_HUB_TOKEN 41 | valueFrom: 42 | secretKeyRef: 43 | name: hf-secret 44 | key: hf_api_token 45 | volumeMounts: 46 | - mountPath: /dev/shm 47 | name: dshm 48 | volumes: 49 | - name: dshm 50 | emptyDir: 51 | medium: Memory 52 | nodeSelector: 53 | cloud.google.com/gke-accelerator: nvidia-l4 54 | --- 55 | apiVersion: v1 56 | kind: Service 57 | metadata: 58 | name: llm-service 59 | spec: 60 | selector: 61 | app: gemma-server 62 | type: ClusterIP 63 | ports: 64 | - protocol: TCP 65 | port: 8000 66 | targetPort: 8000 67 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | devoxx-genai-vertexai-client 6 | VertexAI Gemini Client 7 | 1.0-SNAPSHOT 8 | 9 | 10 | com.google 11 | devoxx-genai-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | libraries-bom 19 | com.google.cloud 20 | import 21 | pom 22 | 26.37.0 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | com.google 32 | devoxx-genai-utilities 33 | ${project.version} 34 | 35 | 36 | 37 | 38 | com.google.cloud 39 | google-cloud-vertexai 40 | 41 | 42 | ch.qos.logback 43 | logback-classic 44 | test 45 | 46 | 47 | 48 | 49 | org.assertj 50 | assertj-core 51 | test 52 | 53 | 54 | org.junit.jupiter 55 | junit-jupiter-engine 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_1_vertexai/_13_LanguageModel_ExtractTextTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._1_vertexai; 2 | 3 | import dev.langchain4j.model.output.Response; 4 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class _13_LanguageModel_ExtractTextTest extends AbstractDevoxxTestSupport { 8 | 9 | @Test 10 | public void test() { 11 | /* 12 | LanguageModel model = VertexAiLanguageModel.builder() 13 | .project(GCP_PROJECT_ID) 14 | .endpoint(GCP_PROJECT_ENDPOINT) 15 | .location(GCP_PROJECT_LOCATION) 16 | .publisher(GCP_PROJECT_PUBLISHER) 17 | .modelName("text-bison") 18 | .build(); 19 | */ 20 | 21 | Response response = getLanguageModelTextBison().generate(""" 22 | Extract the name and age of the person described below. 23 | Return a JSON document with a "name" and an "age" property, \ 24 | following this structure: {"name": "John Doe", "age": 34} 25 | Return only JSON, without any markdown markup surrounding it. 26 | Here is the document describing the person: 27 | --- 28 | Anna is a 23 year old artist based in Brooklyn, New York. She was born and 29 | raised in the suburbs of Chicago, where she developed a love for art at a 30 | young age. She attended the School of the Art Institute of Chicago, where 31 | she studied painting and drawing. After graduating, she moved to New York 32 | City to pursue her art career. Anna's work is inspired by her personal 33 | experiences and observations of the world around her. She often uses bright 34 | colors and bold lines to create vibrant and energetic paintings. Her work 35 | has been exhibited in galleries and museums in New York City and Chicago. 36 | --- 37 | JSON: 38 | """ 39 | ); 40 | System.out.println(response.content()); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /devoxx-genai-vertexai-client/src/test/java/devoxx/demo/gemini/Demo02_VertexClientVisionPro.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.gemini; 2 | 3 | import com.google.cloud.vertexai.VertexAI; 4 | import com.google.cloud.vertexai.api.GenerateContentResponse; 5 | import com.google.cloud.vertexai.generativeai.ContentMaker; 6 | import com.google.cloud.vertexai.generativeai.GenerativeModel; 7 | import com.google.cloud.vertexai.generativeai.PartMaker; 8 | import com.google.cloud.vertexai.generativeai.ResponseHandler; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | 14 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 15 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | public class Demo02_VertexClientVisionPro { 19 | 20 | @Test 21 | public void testVision() throws Exception { 22 | 23 | // Load the image 24 | byte[] imageBytes;// = Files.readAllBytes(Paths.get(imageName)); 25 | 26 | String resourcePath = "/img1.png"; // Resource path in the classpath 27 | 28 | try (InputStream is = Demo02_VertexClientVisionPro.class.getResourceAsStream(resourcePath)) { 29 | assertThat(is).isNotNull(); 30 | imageBytes = is.readAllBytes(); 31 | System.out.println("Image bytes read successfully. Length: " + imageBytes.length); 32 | try (VertexAI vertexAI = new VertexAI(GCP_PROJECT_ID, GCP_PROJECT_LOCATION)) { 33 | GenerativeModel model = new GenerativeModel("gemini-pro-vision", vertexAI); 34 | GenerateContentResponse response = model.generateContent( 35 | ContentMaker.fromMultiModalData( 36 | "What is this image about?", 37 | PartMaker.fromMimeTypeAndData("image/jpg", imageBytes) 38 | )); 39 | 40 | System.out.println(ResponseHandler.getText(response)); 41 | } 42 | } catch (IOException e) { 43 | System.out.println("Error reading the image file."); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /devoxx-genai-springai/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.google 6 | devoxx-genai-springai 7 | 0.0.1-SNAPSHOT 8 | Spring AI with Gemini 9 | Demo project for Spring Boot 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 3.2.4 15 | 16 | 17 | 18 | 19 | 21 20 | 0.8.1 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.ai 27 | spring-ai-vertex-ai-gemini-spring-boot-starter 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.ai 40 | spring-ai-bom 41 | ${spring-ai.version} 42 | pom 43 | import 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | 56 | 57 | 58 | spring-milestones 59 | Spring Milestones 60 | https://repo.spring.io/milestone 61 | 62 | false 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_5_vectorsearch/_54_CassandraVectorStore.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._5_vectorsearch; 2 | 3 | import dev.langchain4j.data.embedding.Embedding; 4 | import dev.langchain4j.data.segment.TextSegment; 5 | import dev.langchain4j.model.embedding.EmbeddingModel; 6 | import dev.langchain4j.store.embedding.EmbeddingSearchRequest; 7 | import dev.langchain4j.store.embedding.EmbeddingStore; 8 | import dev.langchain4j.store.embedding.cassandra.CassandraCassioEmbeddingStore; 9 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey; 14 | import static devoxx.demo.devoxx.Utilities.EMBEDDING_DIMENSION; 15 | import static devoxx.demo.devoxx.Utilities.TABLE_NAME; 16 | 17 | @Slf4j 18 | public class _54_CassandraVectorStore extends AbstractDevoxxTestSupport { 19 | 20 | @Test 21 | public void langchain4jEmbeddingStore() { 22 | // I have to create a EmbeddingModel 23 | EmbeddingModel embeddingModel = getEmbeddingModelGecko(); 24 | 25 | // Embed the question 26 | Embedding questionEmbedding = embeddingModel 27 | .embed("We struggle all our life for nothing") 28 | .content(); 29 | 30 | // We need the store 31 | EmbeddingStore embeddingStore = new CassandraCassioEmbeddingStore( 32 | getCassandraSession(), TABLE_NAME, EMBEDDING_DIMENSION); 33 | 34 | // Query (1) 35 | log.info("Querying the store"); 36 | embeddingStore 37 | .findRelevant(questionEmbedding, 3, 0.8d) 38 | .stream().map(r -> r.embedded().text()) 39 | .forEach(System.out::println); 40 | 41 | // Query with a filter(2) 42 | log.info("Querying with filter"); 43 | embeddingStore.search(EmbeddingSearchRequest.builder() 44 | .queryEmbedding(questionEmbedding) 45 | .filter(metadataKey("author").isEqualTo("nietzsche")) 46 | .maxResults(3).minScore(0.8d).build()) 47 | .matches() 48 | .stream().map(r -> r.embedded().text()) 49 | .forEach(System.out::println); 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_6_rag/_63_AdvancedRag_AugmentWithMetadata.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._6_rag; 2 | 3 | import dev.langchain4j.memory.chat.MessageWindowChatMemory; 4 | import dev.langchain4j.rag.DefaultRetrievalAugmentor; 5 | import dev.langchain4j.rag.RetrievalAugmentor; 6 | import dev.langchain4j.rag.content.injector.DefaultContentInjector; 7 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 8 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 9 | import dev.langchain4j.service.AiServices; 10 | import dev.langchain4j.store.embedding.astradb.AstraDbEmbeddingStore; 11 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 12 | import devoxx.demo.utils.Assistant; 13 | import org.junit.jupiter.api.Test; 14 | 15 | import static java.util.Arrays.asList; 16 | import static java.util.stream.Collectors.joining; 17 | 18 | 19 | public class _63_AdvancedRag_AugmentWithMetadata extends AbstractDevoxxTestSupport { 20 | 21 | @Test 22 | public void shouldRetrieveDocument() { 23 | 24 | ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder() 25 | .embeddingStore(new AstraDbEmbeddingStore(getCollectionRAG())) 26 | .embeddingModel(getEmbeddingModelGecko()) 27 | .maxResults(2) 28 | .minScore(0.5) 29 | .build(); 30 | 31 | // Enhance the content retriever to add meta data in the prompt 32 | RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder() 33 | .contentRetriever(contentRetriever) 34 | 35 | // Query Transformation 36 | .contentInjector(DefaultContentInjector 37 | .builder() 38 | .metadataKeysToInclude(asList("document_format", "md5")) 39 | .build()) 40 | 41 | .build(); 42 | 43 | // configuring it to use the components we've created above. 44 | Assistant ai = AiServices.builder(Assistant.class) 45 | //.contentRetriever(contentRetriever) 46 | .retrievalAugmentor(retrievalAugmentor) 47 | .chatLanguageModel(getChatLanguageModelChatBison()) 48 | .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) 49 | .build(); 50 | 51 | 52 | String response = ai.answer("Who is Johnny?"); 53 | System.out.println(response); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/java/devoxx/demo/gemini/_1_vertexai/_10_LanguageModelSayHello.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.gemini._1_vertexai; 2 | 3 | import dev.langchain4j.data.message.AiMessage; 4 | import dev.langchain4j.data.message.ChatMessage; 5 | import dev.langchain4j.data.message.UserMessage; 6 | import dev.langchain4j.model.chat.ChatLanguageModel; 7 | import dev.langchain4j.model.chat.StreamingChatLanguageModel; 8 | import dev.langchain4j.model.chat.TestStreamingResponseHandler; 9 | import dev.langchain4j.model.output.Response; 10 | import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel; 11 | import dev.langchain4j.model.vertexai.VertexAiGeminiStreamingChatModel; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 18 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 19 | 20 | class _10_LanguageModelSayHello { 21 | 22 | @Test 23 | public void shouldSayHelloToLLM() { 24 | ChatLanguageModel chatLanguageModel= VertexAiGeminiChatModel.builder() 25 | .project(GCP_PROJECT_ID) 26 | .location(GCP_PROJECT_LOCATION) 27 | .modelName("gemini-pro") 28 | .build(); 29 | List messages = new ArrayList<>(); 30 | messages.add(new UserMessage("Hi, tell ma joke ")); 31 | 32 | Response response = chatLanguageModel.generate(messages); 33 | System.out.println(response.content()); 34 | System.out.println(response.finishReason()); 35 | System.out.println(response.tokenUsage().inputTokenCount()); 36 | System.out.println(response.tokenUsage().outputTokenCount()); 37 | System.out.println(response.tokenUsage().totalTokenCount()); 38 | } 39 | 40 | @Test 41 | public void shouldSayHelloToLLMStreaming() { 42 | 43 | StreamingChatLanguageModel model = VertexAiGeminiStreamingChatModel.builder() 44 | .project(GCP_PROJECT_ID) 45 | .location(GCP_PROJECT_LOCATION) 46 | .modelName("gemini-pro") 47 | .build(); 48 | 49 | String userMessage = "What is the capital of Germany?"; 50 | 51 | // when 52 | TestStreamingResponseHandler handler = new TestStreamingResponseHandler<>(); 53 | model.generate(userMessage, handler); 54 | Response response = handler.get(); 55 | 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | devoxx-genai-langchain4j 6 | Langchain4j and Palm 7 | 1.0-SNAPSHOT 8 | 9 | 10 | com.google 11 | devoxx-genai-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | com.google 19 | devoxx-genai-utilities 20 | ${project.version} 21 | 22 | 23 | 24 | 25 | dev.langchain4j 26 | langchain4j 27 | 28 | 29 | dev.langchain4j 30 | langchain4j-vertex-ai 31 | 32 | 33 | dev.langchain4j 34 | langchain4j-cohere 35 | 36 | 37 | dev.langchain4j 38 | langchain4j-cassandra 39 | 40 | 41 | dev.langchain4j 42 | langchain4j-astradb 43 | 44 | 45 | dev.langchain4j 46 | langchain4j-ollama 47 | 48 | 49 | 50 | org.junit.jupiter 51 | junit-jupiter-engine 52 | test 53 | 54 | 55 | ch.qos.logback 56 | logback-classic 57 | test 58 | 59 | 60 | org.assertj 61 | assertj-core 62 | test 63 | 64 | 65 | 66 | com.datastax.astra 67 | astra-sdk-devops 68 | 1.2.7 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /devoxx-genai-utilities/src/main/java/devoxx/demo/devoxx/Utilities.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.devoxx; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.LinkedHashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | public class Utilities { 14 | 15 | public static final String GCP_PROJECT_ID = "devoxxfrance"; 16 | public static final String GCP_PROJECT_PUBLISHER = "google"; 17 | public static final String GCP_PROJECT_ENDPOINT = "us-central1-aiplatform.googleapis.com:443"; 18 | public static final String GCP_PROJECT_LOCATION = "us-central1"; 19 | 20 | public static final Integer EMBEDDING_DIMENSION = 768; 21 | public static final String TABLE_NAME = "vector_store"; 22 | 23 | public static final String ASTRA_TOKEN = System.getenv("ASTRA_DB_APPLICATION_TOKEN"); 24 | public static final String ASTRA_DB_ID = "bace77c5-80ea-4bc4-a0f4-529121918cd4"; 25 | public static final String ASTRA_DB_REGION = "us-east1"; 26 | public static final String ASTRA_KEYSPACE = "default_keyspace"; 27 | public static final String ASTRA_API_ENDPOINT = "https://"+ ASTRA_DB_ID +"-"+ ASTRA_DB_REGION +".apps.astra.datastax.com/api/json"; 28 | 29 | private Utilities() {} 30 | 31 | @SuppressWarnings("unchecked") 32 | public static List loadQuotes(String filePath) throws IOException { 33 | File inputFile = new File(Utilities.class.getClassLoader().getResource(filePath).getFile()); 34 | LinkedHashMap sampleQuotes = new ObjectMapper().readValue(inputFile, LinkedHashMap.class); 35 | List result = new ArrayList<>(); 36 | AtomicInteger quote_idx = new AtomicInteger(0); 37 | ((LinkedHashMap) sampleQuotes.get("quotes")).forEach((k,v) -> { 38 | ((ArrayList)v).forEach(q -> { 39 | Map entry = (Map) q; 40 | String author = (String) k;//(String) entry.get("author"); 41 | String body = (String) entry.get("body"); 42 | List tags = (List) entry.get("tags"); 43 | String rowId = "q_" + author + "_" + quote_idx.getAndIncrement(); 44 | result.add(new Quote(rowId, author, tags, body)); 45 | }); 46 | }); 47 | return result; 48 | } 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_6_rag/_64_AdvancedRag_QueryRouting.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._6_rag; 2 | 3 | import dev.langchain4j.data.document.parser.TextDocumentParser; 4 | import dev.langchain4j.data.document.splitter.DocumentSplitters; 5 | import dev.langchain4j.data.segment.TextSegment; 6 | import dev.langchain4j.memory.chat.MessageWindowChatMemory; 7 | import dev.langchain4j.rag.DefaultRetrievalAugmentor; 8 | import dev.langchain4j.rag.RetrievalAugmentor; 9 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 10 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 11 | import dev.langchain4j.rag.query.Query; 12 | import dev.langchain4j.rag.query.router.QueryRouter; 13 | import dev.langchain4j.service.AiServices; 14 | import dev.langchain4j.store.embedding.EmbeddingStore; 15 | import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; 16 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 17 | import devoxx.demo.utils.Assistant; 18 | import org.junit.jupiter.api.Test; 19 | 20 | import java.io.File; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.Objects; 24 | 25 | import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument; 26 | 27 | public class _64_AdvancedRag_QueryRouting extends AbstractDevoxxTestSupport { 28 | 29 | 30 | @Test 31 | public void testQueryRouting() { 32 | // Our guy for advanced RAG 33 | RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder() 34 | .queryRouter(new MyRouter()) 35 | .build(); 36 | 37 | Assistant assistant = AiServices.builder(Assistant.class) 38 | .retrievalAugmentor(retrievalAugmentor) 39 | .chatLanguageModel(getChatLanguageModelChatBison()) 40 | .build(); 41 | 42 | System.out.println(assistant.answer("Give me the name of the horse")); 43 | System.out.println(assistant.answer("Give me the name of the dog")); 44 | 45 | } 46 | 47 | private static class MyRouter extends AbstractDevoxxTestSupport implements QueryRouter { 48 | 49 | @Override 50 | public Collection route(Query query) { 51 | if (query.text().contains("horse")) { 52 | return List.of(createRetriever("/johnny.txt")); 53 | } else if (query.text().contains("dog")) { 54 | return List.of(createRetriever("/shadow.txt")); 55 | } 56 | return List.of(); 57 | } 58 | 59 | } 60 | } -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | devoxx-genai-langchain4j-gemini 6 | Langchain4j and Gemini and Astra 7 | 1.0-SNAPSHOT 8 | 9 | 10 | com.google 11 | devoxx-genai-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | 19 | dev.langchain4j 20 | langchain4j 21 | 22 | 23 | 24 | dev.langchain4j 25 | langchain4j-core 26 | tests 27 | 0.29.1 28 | test-jar 29 | test 30 | 31 | 32 | 33 | dev.langchain4j 34 | langchain4j-vertex-ai-gemini 35 | 36 | 37 | 38 | dev.langchain4j 39 | langchain4j-astradb 40 | 41 | 42 | 43 | dev.langchain4j 44 | langchain4j-ollama 45 | 46 | 47 | 48 | 49 | com.google 50 | devoxx-genai-utilities 51 | ${project.version} 52 | 53 | 54 | ch.qos.logback 55 | logback-classic 56 | test 57 | 58 | 59 | 60 | 61 | org.assertj 62 | assertj-core 63 | test 64 | 65 | 66 | org.junit.jupiter 67 | junit-jupiter-engine 68 | test 69 | 70 | 71 | org.mockito 72 | mockito-core 73 | 4.11.0 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/resources/story-about-happy-carrot.txt: -------------------------------------------------------------------------------- 1 | Once upon a time in the town of VeggieVille, there lived a cheerful carrot named Charlie. 2 | Charlie was a radiant carrot, always beaming with joy and positivity. 3 | His vibrant orange skin and lush green top were a sight to behold, but it was his infectious laughter and warm personality that really set him apart. 4 | 5 | Charlie had a diverse group of friends, each a vegetable with their own unique characteristics. 6 | There was Bella the blushing beetroot, always ready with a riddle or two; Timmy the timid tomato, a gentle soul with a heart of gold; and Percy the prankster potato, whose jokes always brought a smile to everyone's faces. 7 | Despite their differences, they shared a close bond, their friendship as robust as their natural goodness. 8 | 9 | Their lives were filled with delightful adventures, from playing hide-and-seek amidst the leafy lettuce to swimming in the dewy droplets that pooled on the cabbage leaves. 10 | Their favorite place, though, was the sunlit corner of the vegetable patch, where they would bask in the warmth of the sun, share stories, and have hearty laughs. 11 | 12 | One day, a bunch of pesky caterpillars invaded VeggieVille. 13 | The vegetables were terrified, fearing they would be nibbled to nothingness. 14 | But Charlie, with his usual sunny disposition, had an idea. 15 | He proposed they host a grand feast for the caterpillars, with the juiciest leaves from the outskirts of the town. 16 | Charlie's optimism was contagious, and his friends eagerly joined in to prepare the feast. 17 | 18 | When the caterpillars arrived, they were pleasantly surprised. 19 | They enjoyed the feast and were so impressed with the vegetables' hospitality that they promised not to trouble VeggieVille again. 20 | In return, they agreed to help pollinate the flowers, contributing to a more lush and vibrant VeggieVille. 21 | 22 | Charlie's idea had saved the day, but he humbly attributed the success to their teamwork and friendship. 23 | They celebrated their victory with a grand party, filled with laughter, dance, and merry games. 24 | That night, under the twinkling stars, they made a pact to always stand by each other, come what may. 25 | 26 | From then on, the story of the happy carrot and his friends spread far and wide, a tale of friendship, unity, and positivity. 27 | Charlie, Bella, Timmy, and Percy continued to live their joyful lives, their laughter echoing through VeggieVille. 28 | And so, the tale of the happy carrot and his friends serves as a reminder that no matter the challenge, with optimism, teamwork, and a bit of creativity, anything is possible. -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_6_rag/_65_AdvancedRag_QueryCompression.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._6_rag; 2 | 3 | import dev.langchain4j.data.document.Document; 4 | import dev.langchain4j.data.document.parser.TextDocumentParser; 5 | import dev.langchain4j.data.document.splitter.DocumentSplitters; 6 | import dev.langchain4j.data.segment.TextSegment; 7 | import dev.langchain4j.memory.chat.MessageWindowChatMemory; 8 | import dev.langchain4j.model.chat.ChatLanguageModel; 9 | import dev.langchain4j.model.embedding.EmbeddingModel; 10 | import dev.langchain4j.model.vertexai.VertexAiChatModel; 11 | import dev.langchain4j.model.vertexai.VertexAiEmbeddingModel; 12 | import dev.langchain4j.rag.DefaultRetrievalAugmentor; 13 | import dev.langchain4j.rag.RetrievalAugmentor; 14 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 15 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 16 | import dev.langchain4j.rag.query.transformer.CompressingQueryTransformer; 17 | import dev.langchain4j.rag.query.transformer.QueryTransformer; 18 | import dev.langchain4j.service.AiServices; 19 | import dev.langchain4j.store.embedding.EmbeddingStore; 20 | import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; 21 | import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; 22 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 23 | import devoxx.demo.utils.Assistant; 24 | import org.junit.jupiter.api.Test; 25 | 26 | import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument; 27 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 28 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 29 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 30 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 31 | import static devoxx.demo.utils.Utils.startConversationWith; 32 | import static devoxx.demo.utils.Utils.toPath; 33 | 34 | public class _65_AdvancedRag_QueryCompression extends AbstractDevoxxTestSupport { 35 | 36 | 37 | @Test 38 | public void shouldTestQueryCompression() { 39 | 40 | RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder() 41 | // Commons Retriever 42 | .contentRetriever(createRetriever("/johnny.txt")) 43 | // Add a Query Transformation 44 | .queryTransformer(new CompressingQueryTransformer(getChatLanguageModelChatBison())) 45 | .build(); 46 | 47 | Assistant assistant = AiServices.builder(Assistant.class) 48 | .chatLanguageModel(getChatLanguageModelChatBison()) 49 | .retrievalAugmentor(retrievalAugmentor) 50 | .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) 51 | .build(); 52 | 53 | System.out.println(assistant.answer("Give me the name of the horse")); 54 | System.out.println(assistant.answer("Can you tell where he lives ?")); 55 | System.out.println(assistant.answer("What does he do ?")); 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a [Code of Conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project. 7 | 8 | ## Found an Issue? 9 | If you find a bug in the source code or a mistake in the documentation, you can help us by 10 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can 11 | [submit a Pull Request](#submit-pr) with a fix. 12 | 13 | ## Want a Feature? 14 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub 15 | Repository. If you would like to *implement* a new feature, please submit an issue with 16 | a proposal for your work first, to be sure that we can use it. 17 | 18 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). 19 | 20 | ## Contribution Guidelines 21 | 22 | ### Submitting an Issue 23 | Before you submit an issue, search the archive, maybe your question was already answered. 24 | 25 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 26 | Help us to maximize the effort we can spend fixing issues and adding new 27 | features, by not reporting duplicate issues. Providing the following information will increase the 28 | chances of your issue being dealt with quickly: 29 | 30 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 31 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you 32 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps 33 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 34 | causing the problem (line of code or commit) 35 | 36 | ### Submitting a Pull Request (PR) 37 | Before you submit your Pull Request (PR) consider the following guidelines: 38 | 39 | * Search the repository (https://github.com/stargate/stargate-sdk-java/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate effort. 40 | 41 | * Create a fork of the repo 42 | * Navigate to the repo you want to fork 43 | * In the top right corner of the page click **Fork**: 44 | ![](https://help.github.com/assets/images/help/repository/fork_button.jpg) 45 | 46 | * Make your changes in the forked repo 47 | * Commit your changes using a descriptive commit message 48 | * In GitHub, create a pull request: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork 49 | * If we suggest changes then: 50 | * Make the required updates. 51 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): 52 | 53 | ```shell 54 | git rebase master -i 55 | git push -f 56 | ``` 57 | 58 | That's it! Thank you for your contribution! 59 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/java/devoxx/demo/gemini/_7_functions/_71_CallFunctionTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.gemini._7_functions; 2 | 3 | import dev.langchain4j.agent.tool.Tool; 4 | import dev.langchain4j.agent.tool.ToolExecutionRequest; 5 | import dev.langchain4j.agent.tool.ToolSpecification; 6 | import dev.langchain4j.agent.tool.ToolSpecifications; 7 | import dev.langchain4j.data.message.AiMessage; 8 | import dev.langchain4j.data.message.UserMessage; 9 | import dev.langchain4j.memory.chat.MessageWindowChatMemory; 10 | import dev.langchain4j.model.chat.ChatLanguageModel; 11 | import dev.langchain4j.model.output.Response; 12 | import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel; 13 | import dev.langchain4j.service.AiServices; 14 | import org.junit.jupiter.api.Test; 15 | 16 | import java.util.List; 17 | 18 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 19 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 20 | import static java.util.Collections.singletonList; 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | 23 | public class _71_CallFunctionTest { 24 | 25 | // Get the model 26 | static ChatLanguageModel model= VertexAiGeminiChatModel.builder() 27 | .project(GCP_PROJECT_ID) 28 | .location(GCP_PROJECT_LOCATION) 29 | .modelName("gemini-pro") 30 | .build(); 31 | 32 | static class Calculator { 33 | @Tool("Adds two given numbers") 34 | double add(double a, double b) { 35 | System.out.printf("Called add(%s, %s)%n", a, b); 36 | return a + b; 37 | } 38 | } 39 | 40 | interface Assistant { 41 | String chat(String userMessage); 42 | } 43 | 44 | @Test 45 | public void testFunctionCalling1() { 46 | 47 | 48 | 49 | Calculator calculator = new Calculator(); 50 | 51 | Assistant assistant = AiServices.builder(Assistant.class) 52 | .chatLanguageModel(model) 53 | .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) 54 | .tools(calculator) 55 | .build(); 56 | 57 | String answer = assistant.chat("How much is 754 + 926?"); 58 | System.out.println(answer); 59 | } 60 | 61 | @Test 62 | void Low_level_Tools_Example() { 63 | 64 | List toolSpecifications = ToolSpecifications.toolSpecificationsFrom(new Calculator()); 65 | 66 | UserMessage userMessage = new UserMessage("How much is 754 + 926?"); 67 | 68 | Response response = model.generate(singletonList(userMessage), toolSpecifications); 69 | 70 | AiMessage aiMessage = response.content(); 71 | assertThat(aiMessage.hasToolExecutionRequests()).isTrue(); 72 | assertThat(aiMessage.toolExecutionRequests()).hasSize(1); 73 | 74 | ToolExecutionRequest toolExecutionRequest = aiMessage.toolExecutionRequests().get(0); 75 | assertThat(toolExecutionRequest.name()).isEqualTo("add"); 76 | assertThat(toolExecutionRequest.arguments()).isEqualToIgnoringWhitespace("{\"arg1\":926.0,\"arg0\":754.0}"); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /bedtimestories-gke/README.md: -------------------------------------------------------------------------------- 1 | # LLM with Gemma on GKE 2 | 3 | ## Prepare the GKE Cluster 4 | 5 | gcloud services enable container.googleapis.com 6 | 7 | gcloud config set project devoxxfrance 8 | export PROJECT_ID=$(gcloud config get project) 9 | export REGION=europe-west1 10 | export CLUSTER_NAME=tgi2 11 | export HF_TOKEN=HF_TOKEN 12 | 13 | gcloud container clusters create-auto ${CLUSTER_NAME} \ 14 | --project=${PROJECT_ID} \ 15 | --region=${REGION} \ 16 | --release-channel=rapid \ 17 | --cluster-version=1.28 18 | 19 | kubectl create secret generic hf-secret \ 20 | --from-literal=hf_api_token=${HF_TOKEN} \ 21 | --dry-run=client -o yaml | kubectl apply -f - 22 | 23 | kubectx gke_devoxxfrance_europe-west1_tgi2 24 | 25 | kubectl apply -f k8s/manifests.yaml 26 | 27 | kubectl logs -f -l app=gemma-server 28 | 29 | kubectl port-forward service/llm-service 8000:8000 30 | 31 | USER_PROMPT="Java is a" 32 | 33 | curl -X POST http://localhost:8000/generate \ 34 | -H "Content-Type: application/json" \ 35 | -d @- < mapAsDocument(embeddingModel, quote))// no chunking (single sentences) 31 | .forEach(doc -> {getCollectionQuote().insertOne(doc); 32 | try { 33 | Thread.sleep(100); 34 | } catch (InterruptedException e) { 35 | throw new RuntimeException(e); 36 | } 37 | }); 38 | 39 | //createCollectionQuote().insertMany( 40 | // loadQuotes("philo_quotes.json") // extraction 41 | // .stream() 42 | // .map(quote -> mapAsDocument(embeddingModel, quote))// no chunking (single sentences) 43 | // .toList() 44 | //); 45 | } 46 | 47 | @Test 48 | void langchain4jEmbeddingStore() { 49 | // I have to create a EmbeddingModel 50 | EmbeddingModel embeddingModel = getEmbeddingModelGecko(); 51 | 52 | // Embed the question 53 | Embedding questionEmbedding = embeddingModel.embed("We struggle all our life for nothing").content(); 54 | 55 | // We need the store 56 | EmbeddingStore embeddingStore = new AstraDbEmbeddingStore(getCollectionQuote()); 57 | 58 | // Query with a filter(2) 59 | log.info("Querying with filter"); 60 | embeddingStore.search(EmbeddingSearchRequest.builder() 61 | .queryEmbedding(questionEmbedding) 62 | .filter(metadataKey("authors").isEqualTo("aristotle")) 63 | .maxResults(3).minScore(0.1d).build()) 64 | .matches() 65 | .stream().map(r -> r.embedded().text()) 66 | .forEach(System.out::println); 67 | } 68 | 69 | 70 | Document mapAsDocument(EmbeddingModel embeddingModel , Quote quote) { 71 | log.info("Mapping quote: {}", quote.rowId()); 72 | return new Document(quote.rowId()) 73 | .append("content", quote.body()) 74 | .append("authors", quote.author()) 75 | .append("tags", quote.tags()) 76 | .vector(embeddingModel.embed(quote.body()).content().vector()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_6_rag/_62_NaiveRag_RetrievalTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._6_rag; 2 | 3 | import dev.langchain4j.data.segment.TextSegment; 4 | import dev.langchain4j.memory.chat.MessageWindowChatMemory; 5 | import dev.langchain4j.model.input.Prompt; 6 | import dev.langchain4j.model.input.PromptTemplate; 7 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 8 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 9 | import dev.langchain4j.service.AiServices; 10 | import dev.langchain4j.store.embedding.EmbeddingMatch; 11 | import dev.langchain4j.store.embedding.EmbeddingSearchRequest; 12 | import dev.langchain4j.store.embedding.astradb.AstraDbEmbeddingStore; 13 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 14 | import devoxx.demo.utils.Assistant; 15 | import org.junit.jupiter.api.Test; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey; 24 | import static java.util.stream.Collectors.joining; 25 | 26 | 27 | public class _62_NaiveRag_RetrievalTest extends AbstractDevoxxTestSupport { 28 | 29 | private static final Logger log = LoggerFactory.getLogger(_62_NaiveRag_RetrievalTest.class); 30 | 31 | @Test 32 | public void shouldRetrieveContent1() { 33 | 34 | PromptTemplate promptTemplate = PromptTemplate.from( 35 | "Answer the following question to the best of your ability:\n" 36 | + "\n" 37 | + "Question:\n" 38 | + "{{question}}\n" 39 | + "\n" 40 | + "Base your answer on the following information:\n" 41 | + "{{rag-context}}"); 42 | 43 | String question = "Who is Johnny?"; 44 | 45 | // RAG CONTEXT 46 | List> relevantEmbeddings = new AstraDbEmbeddingStore(getCollectionRAG()) 47 | .search(EmbeddingSearchRequest.builder() 48 | //.filter(metadataKey("document_format").isEqualTo("text")) 49 | .queryEmbedding(getEmbeddingModelGecko().embed(question).content()) 50 | .minScore(0.5) 51 | .maxResults(2) 52 | .build()).matches(); 53 | 54 | Map variables = new HashMap<>(); 55 | variables.put("question", question); 56 | variables.put("rag-context", relevantEmbeddings.stream() 57 | .map(match -> match.embedded().text()) 58 | .collect(joining("\n\n"))); 59 | log.info("{}", variables); 60 | 61 | Prompt prompt = promptTemplate.apply(variables); 62 | 63 | // See an answer from the model 64 | log.info(getChatLanguageModelChatBison().generate(prompt.toUserMessage()).content().text()); 65 | } 66 | 67 | @Test 68 | public void shouldRetrieveContent2() { 69 | 70 | ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder() 71 | .embeddingStore(new AstraDbEmbeddingStore(getCollectionRAG())) 72 | .embeddingModel(getEmbeddingModelGecko()) 73 | .maxResults(2) 74 | .minScore(0.5) 75 | .build(); 76 | 77 | // configuring it to use the components we've created above. 78 | Assistant ai = AiServices.builder(Assistant.class) 79 | .contentRetriever(contentRetriever) 80 | .chatLanguageModel(getChatLanguageModelChatBison()) 81 | .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) 82 | .build(); 83 | 84 | String response = ai.answer("Who is Johnny?"); 85 | System.out.println(response); 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | ## 🧑🏻‍💻 🧑🏾‍💻 Generative AI with Java beyond simple chatbot™ 👩🏿‍💻 👩‍💻 2 | 3 | [![License Apache2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 4 | ![Java](https://img.shields.io/badge/Java-17%20&%20GraalVM-00CC00?style=flat) 5 | 6 | ℹ️ **About this Session** 7 | 8 | > Discover how to integrate generative artificial intelligence into your Java applications without expertise in machine learning or Python. This university will introduce you to Large Language Models (LLMs) and prompting techniques. Learn to code in Java with LangChain4J to use Google's Gemini LLM in your projects. 9 | We will cover the Retrieval Augmented Generation (RAG) approach and integration with a vector database like Apache Cassandra, to generate responses with your own data. The session will include strategies to minimize errors and hallucinations from LLMs (e.g., FLARE) but will also introduce more advanced multimodal models (LMM). 10 | Ideal for Java developers eager to add AI capabilities to their applications and who want to go beyond the simple "hello world" chatbot! 11 | 12 | ![](img/splash.png) 13 | 14 | ⏲️ **Duration :** `3 hours` 15 | 16 | 🎓 **Level** `Intermediate` 17 | 18 | ## 📋 Table of Demos 19 | 20 | * [_10_LanguageModelSayHello.java](devoxx-genai-langchain4j-gemini%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2Fgemini%2F_1_vertexai%2F_10_LanguageModelSayHello.java) 21 | * [_11_LanguageModel_SayHelloTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_11_LanguageModel_SayHelloTest.java) 22 | * [_12_LanguageModel_ModelTuningTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_12_LanguageModel_ModelTuningTest.java) 23 | * [_13_LanguageModel_ExtractTextTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_13_LanguageModel_ExtractTextTest.java) 24 | * [_14_ImageModel_GenerateTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_14_ImageModel_GenerateTest.java) 25 | * [_15_ChatLanguageModel_SayHelloTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_15_ChatLanguageModel_SayHelloTest.java) 26 | * [_16_PromptTemplateTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_1_vertexai%2F_16_PromptTemplateTest.java) 27 | * [_21_GemmaChat.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_2_gemma%2F_21_GemmaChat.java) 28 | * [_51_EmbeddingModel.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_5_vectorsearch%2F_51_EmbeddingModel.java) 29 | * [_52_CassandraVectorDbTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_5_vectorsearch%2F_52_CassandraVectorDbTest.java) 30 | * [_53_CassIOVectorDbTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_5_vectorsearch%2F_53_CassIOVectorDbTest.java) 31 | * [_54_CassandraVectorStore.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_5_vectorsearch%2F_54_CassandraVectorStore.java) 32 | * [_55_AstraVectorTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_5_vectorsearch%2F_55_AstraVectorTest.java) 33 | * [_61_NaiveRag_IngestionTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_61_NaiveRag_IngestionTest.java) 34 | * [_62_NaiveRag_RetrievalTest.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_62_NaiveRag_RetrievalTest.java) 35 | * [_63_AdvancedRag_AugmentWithMetadata.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_63_AdvancedRag_AugmentWithMetadata.java) 36 | * [_64_AdvancedRag_QueryRouting.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_64_AdvancedRag_QueryRouting.java) 37 | * [_65_AdvancedRag_QueryCompression.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_65_AdvancedRag_QueryCompression.java) 38 | * [_66_AdvancedRag_QueryReranking.java](devoxx-genai-langchain4j%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2F_6_rag%2F_66_AdvancedRag_QueryReranking.java) 39 | * [_71_CallFunctionTest.java](devoxx-genai-langchain4j-gemini%2Fsrc%2Ftest%2Fjava%2Fdevoxx%2Fdemo%2Fgemini%2F_7_functions%2F_71_CallFunctionTest.java) -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_6_rag/_61_NaiveRag_IngestionTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._6_rag; 2 | 3 | import dev.langchain4j.data.document.Document; 4 | import dev.langchain4j.data.document.DocumentSplitter; 5 | import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; 6 | import dev.langchain4j.data.document.parser.TextDocumentParser; 7 | import dev.langchain4j.data.document.splitter.DocumentSplitters; 8 | import dev.langchain4j.data.segment.TextSegment; 9 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 10 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 11 | import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; 12 | import dev.langchain4j.store.embedding.astradb.AstraDbEmbeddingStore; 13 | import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; 14 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import java.io.File; 18 | import java.math.BigInteger; 19 | import java.nio.file.Path; 20 | import java.security.MessageDigest; 21 | import java.security.NoSuchAlgorithmException; 22 | import java.util.Date; 23 | import java.util.List; 24 | import java.util.Objects; 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | 28 | public class _61_NaiveRag_IngestionTest extends AbstractDevoxxTestSupport { 29 | 30 | @Test 31 | public void shouldIngestDocument() throws Exception { 32 | 33 | // Parse Document 34 | Path path = new File(Objects.requireNonNull(getClass().getResource("/johnny.txt")).getFile()).toPath(); 35 | Document document = FileSystemDocumentLoader.loadDocument(path, new TextDocumentParser()); 36 | 37 | // QUICK QUICK 38 | DocumentSplitter splitter = DocumentSplitters.recursive(300, 0); 39 | 40 | createCollectionRAG(); 41 | getCollectionRAG().deleteAll(); 42 | MessageDigest md = MessageDigest.getInstance("MD5"); 43 | 44 | AtomicInteger counter = new AtomicInteger(0); 45 | EmbeddingStoreIngestor.builder() 46 | .documentSplitter(splitter) 47 | .embeddingModel(getEmbeddingModelGecko()) 48 | .embeddingStore(new AstraDbEmbeddingStore(getCollectionRAG())) 49 | .textSegmentTransformer(ts -> { 50 | //ts.metadata().add("_id", "doc-johnny"); 51 | ts.metadata().add("document_id", "doc-johnny"); 52 | ts.metadata().add("document_format", "text"); 53 | ts.metadata().add("chunk_id", counter.incrementAndGet()); 54 | ts.metadata().add("index_date", new Date()); 55 | ts.metadata().add("granted_roles", List.of("USER", "ADMIN")); 56 | ts.metadata().add("md5", hashString(ts.text())); 57 | 58 | return ts; 59 | }).build().ingest(document); 60 | } 61 | 62 | public static String hashString(String input) { 63 | try { 64 | MessageDigest md = MessageDigest.getInstance("MD5"); 65 | byte[] hashedBytes = md.digest(input.getBytes()); 66 | 67 | // Convert byte array into signum representation 68 | BigInteger no = new BigInteger(1, hashedBytes); 69 | 70 | // Convert message digest into hex value 71 | String hashtext = no.toString(16); 72 | while (hashtext.length() < 32) { 73 | hashtext = "0" + hashtext; 74 | } 75 | return hashtext; 76 | } catch (NoSuchAlgorithmException e) { 77 | throw new RuntimeException(e); 78 | } 79 | } 80 | 81 | private static ContentRetriever createContentRetriever(List documents) { 82 | 83 | // Here, we create and empty in-memory store for our documents and their embeddings. 84 | InMemoryEmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); 85 | 86 | // Here, we are ingesting our documents into the store. 87 | // Under the hood, a lot of "magic" is happening, but we can ignore it for now. 88 | EmbeddingStoreIngestor.ingest(documents, embeddingStore); 89 | 90 | // Lastly, let's create a content retriever from an embedding store. 91 | return EmbeddingStoreContentRetriever.from(embeddingStore); 92 | } 93 | } -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/resources/johnny.txt: -------------------------------------------------------------------------------- 1 | In the heart of the verdant countryside, where the air is filled with the scent of fresh grass and the tranquil melody of birdsong, there lived a pony named Johnny. Unlike any ordinary pony, Johnny possessed a fiery spirit and an unyielding determination that set him apart from his peers. With a sleek, chestnut coat and eyes gleaming with ambition, he was the embodiment of grace and agility. 2 | 3 | Johnny's journey to greatness began in the small, tight-knit community of Greenwood, where he spent his early days galloping through meadows and leaping over brooks. His owner, an elderly farmer named Mr. Harrison, quickly noticed Johnny's extraordinary talents. Seeing potential for greatness, Mr. Harrison decided to train Johnny for the local horse races, an event that brought together the finest equines from all around. 4 | 5 | The training was rigorous. Each morning, as the first rays of sunlight pierced through the mist, Johnny would be out on the field, pushing his limits. He learned to navigate through complex courses, increase his speed, and conserve his energy for the final burst towards the finish line. Mr. Harrison, with years of experience in horse training, guided Johnny with a gentle but firm hand, instilling in him the virtues of patience, discipline, and resilience. 6 | 7 | Months of hard work culminated in Johnny's first race. The air buzzed with excitement as spectators from neighboring towns gathered to witness the spectacle. Johnny, standing among larger and seemingly more powerful horses, did not let the sight daunt him. Instead, it fueled his resolve. When the starting signal blared, he shot forward like an arrow, his hooves barely touching the ground. The race was intense, with lead changes that kept the audience on the edge of their seats. In the final stretch, Johnny summoned every ounce of his strength and surged ahead, crossing the finish line a clear winner. The crowd erupted in cheers, marveling at the small pony who had outrun the fastest horses in the land. 8 | 9 | Johnny's victory at the local race was just the beginning. Word of his incredible speed and agility spread far and wide, attracting attention from race organizers across the country. With Mr. Harrison by his side, Johnny embarked on a journey that took him to larger, more competitive races. Each victory added to his fame, and soon, Johnny became a household name, celebrated as a symbol of hope and perseverance. 10 | 11 | One of the most defining moments in Johnny's career came when he qualified for the National Equine Championship, a prestigious event that attracted the elite of the horse racing world. The competition was fierce, with seasoned racers and prodigious talents vying for the coveted title. Johnny, undeterred by the high stakes and the intense scrutiny, remained focused on his training, honing his skills and strengthening his resolve. 12 | 13 | The day of the championship arrived, a day that would be etched in the annals of horse racing history. The racetrack was a spectacle to behold, with flags fluttering and an air of anticipation so thick it could be cut with a knife. Johnny, amidst the lineup of champions, stood poised and ready. As the race commenced, he found himself trailing behind, each horse as determined as he to claim victory. But Johnny was a fighter, born of grit and molded by hardship. Gradually, he began to overtake his competitors, one by one, with a grace and speed that left the audience in awe. 14 | 15 | The final seconds of the race were a blur of motion and emotion. Johnny, with a burst of unparalleled speed, took the lead, crossing the finish line to a thunderous applause. He had done the unthinkable, winning the National Equine Championship against all odds. Johnny had not only proven himself as a champion racehorse but had also become a legend, a beacon of inspiration for all who dared to dream big. 16 | 17 | In the years that followed, Johnny continued to compete, each race adding to his legacy. But his impact went beyond the racetracks. He became a symbol of hope, courage, and the indomitable spirit of perseverance. Johnny's story was told and retold, inspiring generations to come. 18 | 19 | As the sun set on his racing career, Johnny retired to Greenwood, where it all began. Surrounded by lush meadows and the affection of Mr. Harrison and the townsfolk, he lived out his days in peace. But the legend of Johnny, the pony who raced with the heart of a lion and the speed of the wind, would live on forever, a timeless tale of victory against all odds. 20 | 21 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j-gemini/src/test/resources/johnny.txt: -------------------------------------------------------------------------------- 1 | In the heart of the verdant countryside, where the air is filled with the scent of fresh grass and the tranquil melody of birdsong, there lived a pony named Johnny. Unlike any ordinary pony, Johnny possessed a fiery spirit and an unyielding determination that set him apart from his peers. With a sleek, chestnut coat and eyes gleaming with ambition, he was the embodiment of grace and agility. 2 | 3 | Johnny's journey to greatness began in the small, tight-knit community of Greenwood, where he spent his early days galloping through meadows and leaping over brooks. His owner, an elderly farmer named Mr. Harrison, quickly noticed Johnny's extraordinary talents. Seeing potential for greatness, Mr. Harrison decided to train Johnny for the local horse races, an event that brought together the finest equines from all around. 4 | 5 | The training was rigorous. Each morning, as the first rays of sunlight pierced through the mist, Johnny would be out on the field, pushing his limits. He learned to navigate through complex courses, increase his speed, and conserve his energy for the final burst towards the finish line. Mr. Harrison, with years of experience in horse training, guided Johnny with a gentle but firm hand, instilling in him the virtues of patience, discipline, and resilience. 6 | 7 | Months of hard work culminated in Johnny's first race. The air buzzed with excitement as spectators from neighboring towns gathered to witness the spectacle. Johnny, standing among larger and seemingly more powerful horses, did not let the sight daunt him. Instead, it fueled his resolve. When the starting signal blared, he shot forward like an arrow, his hooves barely touching the ground. The race was intense, with lead changes that kept the audience on the edge of their seats. In the final stretch, Johnny summoned every ounce of his strength and surged ahead, crossing the finish line a clear winner. The crowd erupted in cheers, marveling at the small pony who had outrun the fastest horses in the land. 8 | 9 | Johnny's victory at the local race was just the beginning. Word of his incredible speed and agility spread far and wide, attracting attention from race organizers across the country. With Mr. Harrison by his side, Johnny embarked on a journey that took him to larger, more competitive races. Each victory added to his fame, and soon, Johnny became a household name, celebrated as a symbol of hope and perseverance. 10 | 11 | One of the most defining moments in Johnny's career came when he qualified for the National Equine Championship, a prestigious event that attracted the elite of the horse racing world. The competition was fierce, with seasoned racers and prodigious talents vying for the coveted title. Johnny, undeterred by the high stakes and the intense scrutiny, remained focused on his training, honing his skills and strengthening his resolve. 12 | 13 | The day of the championship arrived, a day that would be etched in the annals of horse racing history. The racetrack was a spectacle to behold, with flags fluttering and an air of anticipation so thick it could be cut with a knife. Johnny, amidst the lineup of champions, stood poised and ready. As the race commenced, he found himself trailing behind, each horse as determined as he to claim victory. But Johnny was a fighter, born of grit and molded by hardship. Gradually, he began to overtake his competitors, one by one, with a grace and speed that left the audience in awe. 14 | 15 | The final seconds of the race were a blur of motion and emotion. Johnny, with a burst of unparalleled speed, took the lead, crossing the finish line to a thunderous applause. He had done the unthinkable, winning the National Equine Championship against all odds. Johnny had not only proven himself as a champion racehorse but had also become a legend, a beacon of inspiration for all who dared to dream big. 16 | 17 | In the years that followed, Johnny continued to compete, each race adding to his legacy. But his impact went beyond the racetracks. He became a symbol of hope, courage, and the indomitable spirit of perseverance. Johnny's story was told and retold, inspiring generations to come. 18 | 19 | As the sun set on his racing career, Johnny retired to Greenwood, where it all began. Surrounded by lush meadows and the affection of Mr. Harrison and the townsfolk, he lived out his days in peace. But the legend of Johnny, the pony who raced with the heart of a lion and the speed of the wind, would live on forever, a timeless tale of victory against all odds. 20 | 21 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_5_vectorsearch/_52_CassandraVectorDbTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._5_vectorsearch; 2 | 3 | import com.datastax.oss.driver.api.core.CqlSession; 4 | import com.datastax.oss.driver.api.core.cql.ResultSet; 5 | import com.datastax.oss.driver.api.core.cql.Row; 6 | import com.datastax.oss.driver.api.core.cql.SimpleStatement; 7 | import devoxx.demo.devoxx.Product; 8 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 9 | import org.junit.jupiter.api.Disabled; 10 | import org.junit.jupiter.api.Test; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.io.IOException; 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | public class _52_CassandraVectorDbTest extends AbstractDevoxxTestSupport { 19 | 20 | Logger log = LoggerFactory.getLogger(_52_CassandraVectorDbTest.class); 21 | 22 | @Test 23 | @Disabled 24 | public void cassandraVectorSearchTest() throws IOException { 25 | 26 | // Connection to the Cassandra 27 | try (CqlSession cqlSession = getCassandraSession()) { 28 | log.info("Connected to Cassandra"); 29 | 30 | // Create a Table with Embeddings 31 | cqlSession.execute( 32 | "CREATE TABLE IF NOT EXISTS pet_supply_vectors (" + 33 | " product_id TEXT PRIMARY KEY," + 34 | " product_name TEXT," + 35 | " product_vector vector)"); 36 | log.info("Table created."); 37 | 38 | // Create a Search Index 39 | cqlSession.execute( 40 | "CREATE CUSTOM INDEX IF NOT EXISTS idx_vector " + 41 | "ON pet_supply_vectors(product_vector) " + 42 | "USING 'StorageAttachedIndex'"); 43 | log.info("Index Created."); 44 | 45 | // Insert rows 46 | cqlSession.execute( 47 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 48 | "VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])"); 49 | cqlSession.execute( 50 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 51 | "VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])"); 52 | cqlSession.execute( 53 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 54 | "VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0])"); 55 | cqlSession.execute( 56 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 57 | "VALUES ('pt0041','Dog Ring Chew Toy',[0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])"); 58 | cqlSession.execute( 59 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 60 | "VALUES ('pf7043','PupperSausage Bacon dog Treats',[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1])"); 61 | cqlSession.execute( 62 | "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " + 63 | "VALUES ('pf7044','PupperSausage Beef dog Treats',[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0])"); 64 | 65 | // Find By ID (primary KEY) 66 | Row row = cqlSession.execute(SimpleStatement 67 | .builder("SELECT * FROM pet_supply_vectors WHERE product_id = ?") 68 | .addPositionalValue("pf1843").build()).one(); 69 | Product p = Optional.ofNullable(row) 70 | .map(this::mapCassandraRow2Product) 71 | .orElseThrow(() -> new RuntimeException("Product not found")); 72 | log.info("Product Found ! looking for similar products"); 73 | 74 | // Semantic Search 75 | ResultSet resultSet = cqlSession.execute(SimpleStatement 76 | .builder("SELECT * FROM pet_supply_vectors " + 77 | "ORDER BY product_vector ANN OF ? LIMIT 2;") 78 | .addPositionalValue(p.vector()) 79 | .build()); 80 | List similarProducts = resultSet.all() 81 | .stream().map(this::mapCassandraRow2Product).toList(); 82 | log.info("Similar Products : {}", similarProducts); 83 | } 84 | } 85 | 86 | private Product mapCassandraRow2Product(Row row) { 87 | return new Product( 88 | row.getString("product_id"), 89 | row.getString("product_name"), 90 | row.getObject("product_vector")); 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/_5_vectorsearch/_53_CassIOVectorDbTest.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo._5_vectorsearch; 2 | 3 | import dev.langchain4j.model.input.Prompt; 4 | import dev.langchain4j.model.input.PromptTemplate; 5 | import dev.langchain4j.model.output.Response; 6 | import dev.langchain4j.store.cassio.AnnQuery; 7 | import dev.langchain4j.store.cassio.AnnResult; 8 | import dev.langchain4j.store.cassio.MetadataVectorRecord; 9 | import dev.langchain4j.store.cassio.MetadataVectorTable; 10 | import devoxx.demo.devoxx.Quote; 11 | import devoxx.demo.utils.AbstractDevoxxTestSupport; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.jupiter.api.Disabled; 14 | import org.junit.jupiter.api.Test; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.stream.Collectors; 23 | import java.util.stream.Stream; 24 | 25 | import static dev.langchain4j.store.cassio.SimilarityMetric.COSINE; 26 | import static devoxx.demo.devoxx.Utilities.ASTRA_KEYSPACE; 27 | import static devoxx.demo.devoxx.Utilities.EMBEDDING_DIMENSION; 28 | import static devoxx.demo.devoxx.Utilities.TABLE_NAME; 29 | import static devoxx.demo.devoxx.Utilities.loadQuotes; 30 | 31 | @Slf4j 32 | public class _53_CassIOVectorDbTest extends AbstractDevoxxTestSupport { 33 | 34 | @Test 35 | @Disabled 36 | public void shouldIngestDocuments() throws IOException { 37 | getVectorTable().create(); 38 | getVectorTable().clear(); 39 | loadQuotes("philo_quotes.json") // extraction 40 | .stream().parallel() // no chunking (single sentences) 41 | .map(this::mapQuoteToCassandraRecord) // bean-> db record 42 | .forEach(getVectorTable()::put); // persist 43 | } 44 | 45 | @Test 46 | public void shouldFindSimilarQuotes() { 47 | // Encode question 48 | List vector = getEmbeddingModelGecko() 49 | .embed("We struggle all our life for nothing") 50 | .content() 51 | .vectorAsList(); 52 | 53 | // Build Query 54 | AnnQuery query = AnnQuery.builder() 55 | .metric(COSINE) 56 | .topK(3).threshold(.8) 57 | .embeddings(vector) // add vector here 58 | .build(); 59 | 60 | // Execute query 61 | Stream results = getVectorTable() 62 | .similaritySearch(query) 63 | .stream() 64 | .map(AnnResult::getEmbedded); 65 | 66 | // Display Results 67 | results.map(MetadataVectorRecord::getBody) 68 | .forEach(System.out::println); 69 | } 70 | 71 | @Test 72 | public void shouldFindSimilarQuotesWithFilter() { 73 | log.info("Sample Search"); 74 | findSimilarQuotes("We struggle all our life for nothing", 3, .8, null) 75 | .map(Quote::body).forEach(System.out::println); 76 | 77 | log.info("Search with filter"); 78 | findSimilarQuotes("We struggle all our life for nothing", 2, .5, "politics") 79 | .map(Quote::body).forEach(System.out::println); 80 | } 81 | 82 | @Test 83 | public void shouldGenerateQuotes() { 84 | log.info("Generate Quotes"); 85 | MetadataVectorTable vectorTable = getVectorTable(); 86 | 87 | PromptTemplate promptTemplate = PromptTemplate.from(""" 88 | Generate a single short philosophical quote on the given topic, 89 | similar in spirit and form to the provided actual example quotes. 90 | Do not exceed 20-30 words in your quote. 91 | REFERENCE TOPIC: \n {{topic}} \n 92 | ACTUAL EXAMPLES:\n{{examples}} 93 | """); 94 | 95 | Map variables = new HashMap<>(); 96 | variables.put("topic", "politics"); 97 | variables.put("examples", findSimilarQuotes("We struggle all our life for nothing", 2, .8, "politics") 98 | .map(Quote::body) 99 | .collect(Collectors.joining(","))); 100 | 101 | Prompt prompt = promptTemplate.apply(variables); 102 | System.out.println(prompt.toSystemMessage().text()); 103 | Response response = getLanguageModelTextBison().generate(prompt); 104 | System.out.println(response.content()); 105 | } 106 | 107 | private Stream findSimilarQuotes(String quote, int topK, double threshold, String topic) { 108 | AnnQuery.AnnQueryBuilder builder = AnnQuery.builder() 109 | .metric(COSINE) 110 | .topK(topK) 111 | .threshold(threshold) 112 | .metaData(topic != null ? Map.of(topic, "true") : null) 113 | .embeddings(getEmbeddingModelGecko() 114 | .embed(quote) 115 | .content().vectorAsList()); 116 | return getVectorTable().similaritySearch(builder.build()).stream() 117 | .map(AnnResult::getEmbedded) 118 | .map(embedded -> (MetadataVectorRecord) embedded) 119 | .map(this::mapCassandraRowToQuote); 120 | } 121 | 122 | private MetadataVectorRecord mapQuoteToCassandraRecord(Quote quote) { 123 | System.out.println("◾ " + quote ); 124 | MetadataVectorRecord record = new MetadataVectorRecord(); 125 | record.setBody(quote.body()); 126 | record.getMetadata().put("author", quote.author()); 127 | quote.tags().forEach(tag -> record.getMetadata().put(tag, "true")); 128 | record.setVector(getEmbeddingModelGecko().embed(quote.body()).content().vectorAsList()); 129 | record.setRowId(quote.rowId()); 130 | return record; 131 | } 132 | 133 | private Quote mapCassandraRowToQuote(MetadataVectorRecord r) { 134 | // Removing the brackets and trimming unnecessary spaces 135 | List tags = new ArrayList<>(); 136 | String myTags = r.getMetadata().get("tags"); 137 | if (myTags != null) { 138 | String trimmed =myTags.substring(1, myTags.length() - 1).trim(); 139 | tags.addAll(Arrays.stream(trimmed.split(",")).map(String::trim).toList()); 140 | } 141 | return new Quote( 142 | r.getRowId(), 143 | r.getMetadata().get("author"), 144 | tags , 145 | r.getBody()); 146 | } 147 | 148 | private MetadataVectorTable getVectorTable() { 149 | return new MetadataVectorTable(getCassandraSession(), ASTRA_KEYSPACE, TABLE_NAME, EMBEDDING_DIMENSION); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.google 6 | devoxx-genai-parent 7 | Collection of snippets for devoxx talk 8 | Generative Ai with Java 9 | pom 10 | 2024 11 | 1.0-SNAPSHOT 12 | 13 | 14 | 21 15 | 21 16 | 1.18.32 17 | 2.0.12 18 | 1.5.2 19 | 2.17.0 20 | 21 | 0.29.1 22 | 1.0.0 23 | 24 | 25 | 3.25.3 26 | 5.10.2 27 | 28 | 29 | 30 | 31 | devoxx-genai-vertexai-client 32 | devoxx-genai-langchain4j 33 | devoxx-genai-langchain4j-gemini 34 | devoxx-genai-springai 35 | devoxx-genai-utilities 36 | 37 | 38 | 39 | 40 | 41 | com.fasterxml.jackson 42 | jackson-bom 43 | ${jackson.version} 44 | import 45 | pom 46 | 47 | 48 | com.fasterxml.jackson.core 49 | jackson-databind 50 | ${jackson.version} 51 | 52 | 53 | com.fasterxml.jackson.core 54 | jackson-core 55 | ${jackson.version} 56 | 57 | 58 | com.fasterxml.jackson.core 59 | jackson-annotations 60 | ${jackson.version} 61 | 62 | 63 | com.fasterxml.jackson.datatype 64 | jackson-datatype-jsr310 65 | ${jackson.version} 66 | 67 | 68 | 69 | 70 | com.datastax.astra 71 | astra-db-java 72 | ${astra-db-java.version} 73 | provided 74 | 75 | 76 | 77 | 78 | org.projectlombok 79 | lombok 80 | ${lombok.version} 81 | provided 82 | 83 | 84 | 85 | 86 | org.slf4j 87 | slf4j-api 88 | ${slf4j.version} 89 | test 90 | 91 | 92 | ch.qos.logback 93 | logback-classic 94 | ${logback.version} 95 | test 96 | 97 | 98 | 99 | dev.langchain4j 100 | langchain4j 101 | ${langchain4j.version} 102 | 103 | 104 | dev.langchain4j 105 | langchain4j-astradb 106 | ${langchain4j.version} 107 | 108 | 109 | dev.langchain4j 110 | langchain4j-ollama 111 | ${langchain4j.version} 112 | 113 | 114 | dev.langchain4j 115 | langchain4j-cohere 116 | ${langchain4j.version} 117 | 118 | 119 | dev.langchain4j 120 | langchain4j-cassandra 121 | ${langchain4j.version} 122 | 123 | 124 | dev.langchain4j 125 | langchain4j-vertex-ai 126 | ${langchain4j.version} 127 | 128 | 129 | dev.langchain4j 130 | langchain4j-vertex-ai-gemini 131 | ${langchain4j.version} 132 | 133 | 134 | org.junit.jupiter 135 | junit-jupiter-engine 136 | ${junit-jupiter.version} 137 | test 138 | 139 | 140 | org.assertj 141 | assertj-core 142 | ${assertj.version} 143 | test 144 | 145 | 146 | 147 | 148 | 149 | DataStax 150 | http://datastax.com 151 | 152 | 153 | 154 | 155 | Apache 2 156 | http://www.apache.org/licenses/LICENSE-2.0.html 157 | repo 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /devoxx-genai-langchain4j/src/test/java/devoxx/demo/utils/AbstractDevoxxTestSupport.java: -------------------------------------------------------------------------------- 1 | package devoxx.demo.utils; 2 | 3 | import com.datastax.astra.client.Collection; 4 | import com.datastax.astra.client.DataAPIClient; 5 | import com.datastax.astra.client.model.Document; 6 | import com.datastax.astra.internal.command.LoggingCommandObserver; 7 | import com.datastax.oss.driver.api.core.CqlSession; 8 | import com.dtsx.astra.sdk.db.AstraDBOpsClient; 9 | import dev.langchain4j.data.document.parser.TextDocumentParser; 10 | import dev.langchain4j.data.document.splitter.DocumentSplitters; 11 | import dev.langchain4j.data.segment.TextSegment; 12 | import dev.langchain4j.model.chat.ChatLanguageModel; 13 | import dev.langchain4j.model.embedding.EmbeddingModel; 14 | import dev.langchain4j.model.language.LanguageModel; 15 | import dev.langchain4j.model.vertexai.VertexAiChatModel; 16 | import dev.langchain4j.model.vertexai.VertexAiEmbeddingModel; 17 | import dev.langchain4j.model.vertexai.VertexAiLanguageModel; 18 | import dev.langchain4j.rag.content.retriever.ContentRetriever; 19 | import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; 20 | import dev.langchain4j.store.embedding.EmbeddingStore; 21 | import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; 22 | 23 | import java.io.File; 24 | import java.nio.file.Paths; 25 | import java.util.List; 26 | import java.util.Objects; 27 | 28 | import static com.datastax.astra.client.model.SimilarityMetric.COSINE; 29 | import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument; 30 | import static devoxx.demo.devoxx.Utilities.ASTRA_API_ENDPOINT; 31 | import static devoxx.demo.devoxx.Utilities.ASTRA_DB_ID; 32 | import static devoxx.demo.devoxx.Utilities.ASTRA_DB_REGION; 33 | import static devoxx.demo.devoxx.Utilities.ASTRA_KEYSPACE; 34 | import static devoxx.demo.devoxx.Utilities.ASTRA_TOKEN; 35 | import static devoxx.demo.devoxx.Utilities.EMBEDDING_DIMENSION; 36 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ENDPOINT; 37 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_ID; 38 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_LOCATION; 39 | import static devoxx.demo.devoxx.Utilities.GCP_PROJECT_PUBLISHER; 40 | 41 | public class AbstractDevoxxTestSupport { 42 | 43 | protected LanguageModel getLanguageModel(final String modelName) { 44 | return VertexAiLanguageModel.builder() 45 | .project(GCP_PROJECT_ID) 46 | .endpoint(GCP_PROJECT_ENDPOINT) 47 | .location(GCP_PROJECT_LOCATION) 48 | .publisher(GCP_PROJECT_PUBLISHER) 49 | .modelName(modelName) 50 | .build(); 51 | } 52 | 53 | protected EmbeddingModel getEmbeddingModel(final String modelName) { 54 | return VertexAiEmbeddingModel.builder() 55 | .project(GCP_PROJECT_ID) 56 | .endpoint(GCP_PROJECT_ENDPOINT) 57 | .location(GCP_PROJECT_LOCATION) 58 | .publisher(GCP_PROJECT_PUBLISHER) 59 | .modelName(modelName) 60 | .build(); 61 | } 62 | 63 | protected ChatLanguageModel getChatLanguageModel(final String modelName) { 64 | return VertexAiChatModel.builder() 65 | .publisher(GCP_PROJECT_PUBLISHER) 66 | .project(GCP_PROJECT_ID) 67 | .endpoint(GCP_PROJECT_ENDPOINT) 68 | .location(GCP_PROJECT_LOCATION) 69 | .modelName(modelName) 70 | .temperature(0.7) 71 | .topK(3) 72 | .topP(.8) 73 | .maxRetries(3) 74 | .maxOutputTokens(2000) 75 | .build(); 76 | }; 77 | 78 | protected ChatLanguageModel getChatLanguageModelChatBison() { 79 | return getChatLanguageModel("chat-bison"); 80 | } 81 | 82 | protected LanguageModel getLanguageModelTextBison() { 83 | return getLanguageModel("text-bison"); 84 | } 85 | 86 | protected EmbeddingModel getEmbeddingModelGecko() { 87 | return getEmbeddingModel("textembedding-gecko@001"); 88 | } 89 | 90 | 91 | // ======== Cassandra Session =========== 92 | 93 | CqlSession cqlSession; 94 | 95 | public synchronized CqlSession getCassandraSession() { 96 | if (cqlSession == null) { 97 | String secureConnectBundleFolder = System.getProperty("user.home") + File.separator + ".astra" + File.separator + "scb"; 98 | if (!new File(secureConnectBundleFolder).exists()) new File(secureConnectBundleFolder).mkdirs(); 99 | new AstraDBOpsClient(ASTRA_TOKEN) 100 | .database(ASTRA_DB_ID) 101 | .downloadAllSecureConnectBundles(secureConnectBundleFolder); 102 | String scb = secureConnectBundleFolder + File.separator + "scb_" + ASTRA_DB_ID + "_" + ASTRA_DB_REGION + ".zip"; 103 | cqlSession = CqlSession.builder() 104 | .withAuthCredentials("token", ASTRA_TOKEN) 105 | .withCloudSecureConnectBundle(Paths.get(scb)) 106 | .withKeyspace(ASTRA_KEYSPACE) 107 | .build(); 108 | } 109 | return cqlSession; 110 | } 111 | 112 | public Collection getCollectionQuote() { 113 | Collection col = new DataAPIClient(ASTRA_TOKEN) 114 | .getDatabase(ASTRA_API_ENDPOINT) 115 | .getCollection("quote_store", Document.class); 116 | col.registerListener("logger", new LoggingCommandObserver(AbstractDevoxxTestSupport.class)); 117 | return col; 118 | } 119 | 120 | 121 | public Collection createCollectionQuote() { 122 | return new DataAPIClient(ASTRA_TOKEN) 123 | .getDatabase(ASTRA_API_ENDPOINT) 124 | .createCollection("quote_store", EMBEDDING_DIMENSION, COSINE); 125 | } 126 | 127 | public Collection createCollectionRAG() { 128 | return new DataAPIClient(ASTRA_TOKEN) 129 | .getDatabase(ASTRA_API_ENDPOINT) 130 | .createCollection("rag_store", EMBEDDING_DIMENSION, COSINE); 131 | } 132 | 133 | public Collection getCollectionRAG() { 134 | return new DataAPIClient(ASTRA_TOKEN) 135 | .getDatabase(ASTRA_API_ENDPOINT) 136 | .getCollection("rag_store"); 137 | } 138 | 139 | protected ContentRetriever createRetriever(String fileName) { 140 | List segments = DocumentSplitters 141 | .recursive(300, 0) 142 | .split(loadDocument(new File(Objects.requireNonNull(getClass() 143 | .getResource(fileName)) 144 | .getFile()).toPath(), new TextDocumentParser())); 145 | EmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); 146 | embeddingStore.addAll(getEmbeddingModelGecko().embedAll(segments).content(), segments); 147 | return EmbeddingStoreContentRetriever.builder() 148 | .embeddingStore(embeddingStore) 149 | .embeddingModel(getEmbeddingModelGecko()) 150 | .maxResults(2) 151 | .minScore(0.6) 152 | .build(); 153 | } 154 | 155 | protected EmbeddingStoreContentRetriever.EmbeddingStoreContentRetrieverBuilder createRetrieverBuilder(String fileName) { 156 | List segments = DocumentSplitters 157 | .recursive(300, 0) 158 | .split(loadDocument(new File(Objects.requireNonNull(getClass() 159 | .getResource(fileName)) 160 | .getFile()).toPath(), new TextDocumentParser())); 161 | EmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); 162 | embeddingStore.addAll(getEmbeddingModelGecko().embedAll(segments).content(), segments); 163 | return EmbeddingStoreContentRetriever.builder() 164 | .embeddingStore(embeddingStore) 165 | .embeddingModel(getEmbeddingModelGecko()) 166 | .maxResults(2) 167 | .minScore(0.6); 168 | } 169 | 170 | 171 | 172 | 173 | 174 | } 175 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------