diff --git a/build.bat b/build.bat new file mode 100644 index 00000000..f02e2997 --- /dev/null +++ b/build.bat @@ -0,0 +1,7 @@ +@echo off +setlocal +set SCRIPT_DIR=%~dp0 +cd /d "%SCRIPT_DIR%" +:: Without enforcer.skip, the quartus example cannot compile successfully +mvn install -DskipTests -Denforcer.skip=true -U +endlocal diff --git a/build.sh b/build.sh new file mode 100644 index 00000000..1bab53af --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" +# Without enforcer.skip, the quartus example cannot compile successfully +mvn install -DskipTests -Denforcer.skip=true -U diff --git a/elasticsearch-example/pom.xml b/elasticsearch-example/pom.xml index c24e494c..ce19e28c 100644 --- a/elasticsearch-example/pom.xml +++ b/elasticsearch-example/pom.xml @@ -12,6 +12,7 @@ 8 8 UTF-8 + 2.22.1 @@ -28,12 +29,24 @@ 0.33.0 + org.testcontainers elasticsearch - 1.19.6 + 1.19.7 + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j.version} + \ No newline at end of file diff --git a/elasticsearch-example/src/main/java/ElasticsearchEmbeddingStoreExample.java b/elasticsearch-example/src/main/java/ElasticsearchEmbeddingStoreExample.java index ce3cdaae..3fe82b74 100644 --- a/elasticsearch-example/src/main/java/ElasticsearchEmbeddingStoreExample.java +++ b/elasticsearch-example/src/main/java/ElasticsearchEmbeddingStoreExample.java @@ -5,20 +5,37 @@ import dev.langchain4j.store.embedding.EmbeddingMatch; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.elasticsearch.ElasticsearchEmbeddingStore; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.utility.DockerImageName; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; public class ElasticsearchEmbeddingStoreExample { - public static void main(String[] args) throws InterruptedException { + private static final Logger LOGGER = LogManager.getLogger(ElasticsearchEmbeddingStoreExample.class); - try (ElasticsearchContainer elastic = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.9.0") - .withEnv("xpack.security.enabled", "false")) { + /** + * To run this example, ensure you have Elasticsearch running locally. If not, then: + * - Execute "docker pull docker.elastic.co/elasticsearch/elasticsearch:8.9.0" + * - Execute "docker run -d -p 9200:9200 -p 9300:9300 -e discovery.type=single-node -e xpack.security.enabled=false docker.elastic.co/elasticsearch/elasticsearch:8.9.0" + * - Wait until Elasticsearch is ready to serve (may take a few minutes) + */ + public static void main(String[] args) { + DockerImageName imageName = DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:8.9.0"); + Map env = new HashMap<>(); + env.put("xpack.security.enabled", "false"); + env.put("discovery.type", "single-node"); + + try (ElasticsearchContainer elastic = new ElasticsearchContainer(imageName).withCertPath(null).withEnv(env)) { elastic.start(); EmbeddingStore embeddingStore = ElasticsearchEmbeddingStore.builder() - .serverUrl("http://" + elastic.getHttpHostAddress()) + .serverUrl(elastic.getHttpHostAddress()) .dimension(384) .build(); @@ -32,14 +49,19 @@ public static void main(String[] args) throws InterruptedException { Embedding embedding2 = embeddingModel.embed(segment2).content(); embeddingStore.add(embedding2, segment2); - Thread.sleep(1000); // to be sure that embeddings were persisted + // to be sure that embeddings were persisted + TimeUnit.MILLISECONDS.sleep(1000); Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content(); List> relevant = embeddingStore.findRelevant(queryEmbedding, 1); EmbeddingMatch embeddingMatch = relevant.get(0); - System.out.println(embeddingMatch.score()); // 0.81442887 - System.out.println(embeddingMatch.embedded().text()); // I like football. + // expected 0.8144288659095 + LOGGER.info("Score: {}", embeddingMatch.score()); + // expected "I like football." + LOGGER.info("Embedded: {}", embeddingMatch.embedded().text()); + } catch (Exception e) { + LOGGER.error("Error: {}", e.getMessage()); } } } diff --git a/elasticsearch-example/src/main/resources/log4j2.xml b/elasticsearch-example/src/main/resources/log4j2.xml new file mode 100644 index 00000000..345ffd41 --- /dev/null +++ b/elasticsearch-example/src/main/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/neo4j-example/pom.xml b/neo4j-example/pom.xml index 67aac81c..52735bb6 100644 --- a/neo4j-example/pom.xml +++ b/neo4j-example/pom.xml @@ -12,6 +12,7 @@ 17 17 UTF-8 + 2.22.1 @@ -28,12 +29,24 @@ 0.33.0 + org.testcontainers neo4j - 1.19.6 + 1.19.7 + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j.version} + \ No newline at end of file diff --git a/neo4j-example/src/main/java/Neo4jEmbeddingStoreExample.java b/neo4j-example/src/main/java/Neo4jEmbeddingStoreExample.java index 5785f72d..0b23d4bc 100644 --- a/neo4j-example/src/main/java/Neo4jEmbeddingStoreExample.java +++ b/neo4j-example/src/main/java/Neo4jEmbeddingStoreExample.java @@ -5,17 +5,36 @@ import dev.langchain4j.store.embedding.EmbeddingMatch; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.neo4j.Neo4jEmbeddingStore; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.GraphDatabase; import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.utility.DockerImageName; import java.util.List; public class Neo4jEmbeddingStoreExample { + private static final Logger LOGGER = LogManager.getLogger(Neo4jEmbeddingStoreExample.class); + + /** + * To run this example, ensure you have Neo4j running locally, + * and change uri, username and password strings consistently. + * If not, then: + * - Execute "docker pull neo4j:latest" + * - Execute "docker run -d -p 7687:7687 --env NEO4J_AUTH=neo4j/password1234 neo4j:latest" + * - Wait until Neo4j is ready to serve (may take a few minutes) + */ + public static void main(String[] args) { - try (Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:5")) { - neo4j.start(); + String username = "neo4j"; + String password = "password1234"; + + try (Neo4jContainer neo4jContainer = new Neo4jContainer<>(DockerImageName.parse("neo4j:latest"))) { + neo4jContainer.withEnv("NEO4J_AUTH", username + "/" + password).start(); EmbeddingStore embeddingStore = Neo4jEmbeddingStore.builder() - .withBasicAuth(neo4j.getBoltUrl(), "neo4j", neo4j.getAdminPassword()) + .driver(GraphDatabase.driver(neo4jContainer.getBoltUrl(), AuthTokens.basic(username, password))) .dimension(384) .build(); @@ -33,8 +52,12 @@ public static void main(String[] args) { List> relevant = embeddingStore.findRelevant(queryEmbedding, 1); EmbeddingMatch embeddingMatch = relevant.get(0); - System.out.println(embeddingMatch.score()); // 0.8144289255142212 - System.out.println(embeddingMatch.embedded().text()); // I like football. + // expected 0.8144288659095 + LOGGER.info("Score: {}", embeddingMatch.score()); + // expected "I like football." + LOGGER.info("Embedded: {}", embeddingMatch.embedded().text()); + } catch (Exception e) { + LOGGER.error("Error: {}", e.getMessage()); } } } diff --git a/neo4j-example/src/main/resources/log4j2.xml b/neo4j-example/src/main/resources/log4j2.xml new file mode 100644 index 00000000..345ffd41 --- /dev/null +++ b/neo4j-example/src/main/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ollama-examples/pom.xml b/ollama-examples/pom.xml index 16bed3b3..cc4e596b 100644 --- a/ollama-examples/pom.xml +++ b/ollama-examples/pom.xml @@ -40,6 +40,7 @@ 5.10.0 + org.tinylog tinylog-impl diff --git a/ollama-examples/src/main/java/OllamaChatModelTest.java b/ollama-examples/src/main/java/OllamaChatModelTest.java index a179b6ac..20bce561 100644 --- a/ollama-examples/src/main/java/OllamaChatModelTest.java +++ b/ollama-examples/src/main/java/OllamaChatModelTest.java @@ -4,6 +4,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.tinylog.Logger; @Testcontainers class OllamaChatModelTest { @@ -21,40 +22,30 @@ class OllamaChatModelTest { * 2. Run "docker exec -it ollama ollama run mistral" <- specify the desired model here */ - static String MODEL_NAME = "orca-mini"; // try "mistral", "llama2", "codellama", "phi" or "tinyllama" - @Container - static GenericContainer ollama = new GenericContainer<>("langchain4j/ollama-" + MODEL_NAME + ":latest") - .withExposedPorts(11434); + private static GenericContainer ollama = new GenericContainer<>(OllamaContants.OLLAMA_IMAGE_NAME).withExposedPorts(OllamaContants.OLLAMA_PORT); @Test - void simple_example() { - + void example() { ChatLanguageModel model = OllamaChatModel.builder() - .baseUrl(baseUrl()) - .modelName(MODEL_NAME) + .baseUrl(baseUrl(ollama)) + .modelName(OllamaContants.MODEL_NAME) .build(); + simpleExample(model); + jsonOutputExample(model); + } + void simpleExample(ChatLanguageModel model) { String answer = model.generate("Provide 3 short bullet points explaining why Java is awesome"); - - System.out.println(answer); + Logger.info("Answer: {}", answer); } - @Test - void json_output_example() { - - ChatLanguageModel model = OllamaChatModel.builder() - .baseUrl(baseUrl()) - .modelName(MODEL_NAME) - .format("json") - .build(); - + void jsonOutputExample(ChatLanguageModel model) { String json = model.generate("Give me a JSON with 2 fields: name and age of a John Doe, 42"); - - System.out.println(json); + Logger.info("JSON: {}", json); } - static String baseUrl() { + static String baseUrl(GenericContainer ollama) { return String.format("http://%s:%d", ollama.getHost(), ollama.getFirstMappedPort()); } } diff --git a/ollama-examples/src/main/java/OllamaContants.java b/ollama-examples/src/main/java/OllamaContants.java new file mode 100644 index 00000000..7fd08ff8 --- /dev/null +++ b/ollama-examples/src/main/java/OllamaContants.java @@ -0,0 +1,14 @@ +public class OllamaContants { + + static final String MODEL_ORCA_MINI = "orca-mini"; + static final String MODEL_MISTRAL = "mistral"; + static final String MODEL_LLAMA2 = "llama2"; + static final String MODEL_CODE_LLAMA = "codellama"; + static final String MODEL_PHI = "phi"; + static final String MODEL_TINY_LLAMA = "tinyllama"; + + // try "mistral", "llama2", "codellama", "phi" or "tinyllama" + static final String MODEL_NAME = MODEL_ORCA_MINI; + public static final String OLLAMA_IMAGE_NAME = "langchain4j/ollama-" + MODEL_NAME + ":latest"; + public static final Integer OLLAMA_PORT = 11434; +} diff --git a/ollama-examples/src/main/java/OllamaStreamingChatModelTest.java b/ollama-examples/src/main/java/OllamaStreamingChatModelTest.java index 56a7f672..f3a2b19a 100644 --- a/ollama-examples/src/main/java/OllamaStreamingChatModelTest.java +++ b/ollama-examples/src/main/java/OllamaStreamingChatModelTest.java @@ -7,6 +7,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.tinylog.Logger; import java.util.concurrent.CompletableFuture; @@ -26,20 +27,15 @@ class OllamaStreamingChatModelTest { * 2. Run "docker exec -it ollama ollama run llama2" <- specify the desired model here */ - static String MODEL_NAME = "orca-mini"; // try "mistral", "llama2", "codellama" or "phi" - static String DOCKER_IMAGE_NAME = "langchain4j/ollama-" + MODEL_NAME + ":latest"; - static Integer PORT = 11434; - @Container - static GenericContainer ollama = new GenericContainer<>(DOCKER_IMAGE_NAME) - .withExposedPorts(PORT); + private static GenericContainer ollama = new GenericContainer<>(OllamaContants.OLLAMA_IMAGE_NAME).withExposedPorts(OllamaContants.OLLAMA_PORT); @Test - void streaming_example() { + void streamingExample() { StreamingChatLanguageModel model = OllamaStreamingChatModel.builder() - .baseUrl(String.format("http://%s:%d", ollama.getHost(), ollama.getMappedPort(PORT))) - .modelName(MODEL_NAME) + .baseUrl(String.format("http://%s:%d", ollama.getHost(), ollama.getMappedPort(OllamaContants.OLLAMA_PORT))) + .modelName(OllamaContants.MODEL_NAME) .temperature(0.0) .build(); @@ -50,7 +46,7 @@ void streaming_example() { @Override public void onNext(String token) { - System.out.print(token); + Logger.info("Token: {}", token); } @Override diff --git a/ollama-examples/src/main/resources/tinylog.properties b/ollama-examples/src/main/resources/tinylog.properties new file mode 100644 index 00000000..cc12392d --- /dev/null +++ b/ollama-examples/src/main/resources/tinylog.properties @@ -0,0 +1,4 @@ +#https://tinylog.org/v2/configuration/ +writer = console +writer.level = info +writer.format = {date: HH:mm:ss.SSS} {{level}:|min-size=8} {message} \ No newline at end of file diff --git a/open-ai-examples/src/main/java/OpenAiImageModelExamples.java b/open-ai-examples/src/main/java/OpenAiImageModelExamples.java index e90707d6..533f2450 100644 --- a/open-ai-examples/src/main/java/OpenAiImageModelExamples.java +++ b/open-ai-examples/src/main/java/OpenAiImageModelExamples.java @@ -2,15 +2,82 @@ import dev.langchain4j.model.image.ImageModel; import dev.langchain4j.model.openai.OpenAiImageModel; import dev.langchain4j.model.output.Response; +import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; +import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; + +import java.net.URISyntaxException; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static dev.ai4j.openai4j.image.ImageModel.DALL_E_QUALITY_HD; +import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument; public class OpenAiImageModelExamples { - public static void main(String[] args) { + static class Simple_Prompt { + + public static void main(String[] args) { + + ImageModel model = OpenAiImageModel.withApiKey(System.getenv("OPENAI_API_KEY")); + + Response response = model.generate("Donald Duck in New York, cartoon style"); + + System.out.println(response.content().url()); // Donald Duck is here :) + } + } + + static class Draw_Story_From_My_Document { + + public static void main(String[] args) throws URISyntaxException { + + ImageModel model = OpenAiImageModel.builder() + .apiKey(System.getenv("OPENAI_API_KEY")) + .quality(DALL_E_QUALITY_HD) + .logRequests(true) + .logResponses(true) + .withPersisting() + .build(); + + EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); + EmbeddingStore embeddingStore = new InMemoryEmbeddingStore<>(); + + EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor + .builder() + .documentSplitter(DocumentSplitters.recursive(1000, 0)) + .embeddingModel(embeddingModel) + .embeddingStore(embeddingStore) + .build(); + + Document document = loadDocument( + Paths.get( + Objects + .requireNonNull( + OpenAiImageModelExamples.class.getResource("example-files/story-about-happy-carrot.txt") + ) + .toURI() + ), + new TextDocumentParser() + ); + ingestor.ingest(document); + + ConversationalRetrievalChain chain = ConversationalRetrievalChain + .builder() + .chatLanguageModel(OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).build()) + .contentRetriever(new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel)) + .build(); + + PromptTemplate drawPromptTemplate = PromptTemplate.from( + "Draw {{object}}. Base the picture on following information:\n\n{{information}}" + ); - ImageModel model = OpenAiImageModel.withApiKey(System.getenv("OPENAI_API_KEY")); + ImageModel model = OpenAiImageModel.withApiKey(System.getenv("OPENAI_API_KEY")); - Response response = model.generate("Donald Duck in New York, cartoon style"); + Response response = model.generate("Donald Duck in New York, cartoon style"); - System.out.println(response.content().url()); // Donald Duck is here :) + System.out.println(response.content().url()); // Donald Duck is here :) } } diff --git a/redis-example/pom.xml b/redis-example/pom.xml index e5fe43e1..414ffe66 100644 --- a/redis-example/pom.xml +++ b/redis-example/pom.xml @@ -12,10 +12,10 @@ 8 8 UTF-8 + 2.22.1 - dev.langchain4j langchain4j-redis @@ -28,16 +28,22 @@ 0.33.0 + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + - org.slf4j - slf4j-simple - 2.0.7 + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j.version} - com.redis.testcontainers + com.redis testcontainers-redis - 1.6.4 + 2.0.1 @@ -47,5 +53,4 @@ - \ No newline at end of file diff --git a/redis-example/src/main/java/RedisEmbeddingStoreExample.java b/redis-example/src/main/java/RedisEmbeddingStoreExample.java index 99942cf9..bc5efd94 100644 --- a/redis-example/src/main/java/RedisEmbeddingStoreExample.java +++ b/redis-example/src/main/java/RedisEmbeddingStoreExample.java @@ -1,4 +1,5 @@ -import com.redis.testcontainers.RedisStackContainer; + +import com.redis.testcontainers.RedisContainer; import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel; @@ -6,42 +7,45 @@ import dev.langchain4j.store.embedding.EmbeddingMatch; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.redis.RedisEmbeddingStore; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.testcontainers.utility.DockerImageName; import java.util.List; -import static com.redis.testcontainers.RedisStackContainer.DEFAULT_IMAGE_NAME; -import static com.redis.testcontainers.RedisStackContainer.DEFAULT_TAG; public class RedisEmbeddingStoreExample { + private static final Logger LOGGER = LogManager.getLogger(RedisEmbeddingStoreExample.class); public static void main(String[] args) { - - RedisStackContainer redis = new RedisStackContainer(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); - redis.start(); - - EmbeddingStore embeddingStore = RedisEmbeddingStore.builder() - .host(redis.getHost()) - .port(redis.getFirstMappedPort()) - .dimension(384) - .build(); - - EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); - - TextSegment segment1 = TextSegment.from("I like football."); - Embedding embedding1 = embeddingModel.embed(segment1).content(); - embeddingStore.add(embedding1, segment1); - - TextSegment segment2 = TextSegment.from("The weather is good today."); - Embedding embedding2 = embeddingModel.embed(segment2).content(); - embeddingStore.add(embedding2, segment2); - - Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content(); - List> relevant = embeddingStore.findRelevant(queryEmbedding, 1); - EmbeddingMatch embeddingMatch = relevant.get(0); - - System.out.println(embeddingMatch.score()); // 0.8144288659095 - System.out.println(embeddingMatch.embedded().text()); // I like football. - - redis.stop(); + try (RedisContainer redis = new RedisContainer(DockerImageName.parse("redis/redis-stack-server:latest"))) { + redis.start(); + + EmbeddingStore embeddingStore = RedisEmbeddingStore.builder() + .host(redis.getHost()) + .port(redis.getFirstMappedPort()) + .dimension(384) + .build(); + + EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); + + TextSegment segment1 = TextSegment.from("I like football."); + Embedding embedding1 = embeddingModel.embed(segment1).content(); + embeddingStore.add(embedding1, segment1); + + TextSegment segment2 = TextSegment.from("The weather is good today."); + Embedding embedding2 = embeddingModel.embed(segment2).content(); + embeddingStore.add(embedding2, segment2); + + Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content(); + List> relevant = embeddingStore.findRelevant(queryEmbedding, 1); + EmbeddingMatch embeddingMatch = relevant.get(0); + // expected 0.8144288659095 + LOGGER.info("Score: {}", embeddingMatch.score()); + // expected "I like football." + LOGGER.info("Embedded: {}", embeddingMatch.embedded().text()); + } catch (Exception e) { + LOGGER.error("Error: {}", e.getMessage()); + } } } diff --git a/redis-example/src/main/resources/log4j2.xml b/redis-example/src/main/resources/log4j2.xml new file mode 100644 index 00000000..345ffd41 --- /dev/null +++ b/redis-example/src/main/resources/log4j2.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file