Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 87 additions & 52 deletions samples/chatbot/pom.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-sample-chatbot</artifactId>
<name>Quarkus LangChain4j - Sample - Chatbot &amp; RAG</name>
<name>Quarkus LangChain4j - Sample - Chatbot &amp; RAG</name>
<version>1.0-SNAPSHOT</version>

<properties>
Expand All @@ -15,24 +16,12 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>3.20.0</quarkus.platform.version>
<quarkus.platform.version>3.26.4</quarkus.platform.version>
<skipITs>true</skipITs>
<skipTests>true</skipTests>
<surefire-plugin.version>3.2.5</surefire-plugin.version>
<quarkus-langchain4j.version>1.2.0.CR3</quarkus-langchain4j.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
Expand All @@ -43,14 +32,14 @@
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai</artifactId>
<version>${quarkus-langchain4j.version}</version>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-redis</artifactId>
<version>${quarkus-langchain4j.version}</version>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>

<!-- UI -->
Expand All @@ -71,34 +60,6 @@
<version>0.2.1</version>
<scope>runtime</scope>
</dependency>

<!-- Minimal dependencies to constrain the build -->
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai-deployment</artifactId>
<version>${quarkus-langchain4j.version}</version>
<scope>test</scope>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-redis-deployment</artifactId>
<version>${quarkus-langchain4j.version}</version>
<scope>test</scope>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down Expand Up @@ -132,6 +93,76 @@
</build>

<profiles>
<profile>
<id>default-project-deps</id>
<activation>
<property>
<name>!platform-deps</name>
</property>
</activation>
<properties>
<quarkus-langchain4j.version>1.2.0.CR3</quarkus-langchain4j.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai</artifactId>
<version>${quarkus-langchain4j.version}</version>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-redis</artifactId>
<version>${quarkus-langchain4j.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>platform-deps</id>
<activation>
<property>
<name>platform-deps</name>
</property>
</activation>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-langchain4j-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-redis</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>native</id>
<activation>
Expand All @@ -152,8 +183,11 @@
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager
</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
Expand All @@ -163,6 +197,7 @@
</plugins>
</build>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.quarkiverse.langchain4j.tests.rag;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class RAGIT extends RAGTest {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package io.quarkiverse.langchain4j.tests.rag;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;
import org.awaitility.Awaitility;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@QuarkusTest
public class RAGTest {
private static final Logger LOG = Logger.getLogger(RAGTest.class);

private List<String> answers;
private WebSocket webSocket;

@TestHTTPResource
URL url;

@BeforeEach
void setUp() throws URISyntaxException, ExecutionException, InterruptedException {
String socket = "/chatbot";
URI uri = new URI("ws", null,
url.getHost(),
url.getPort(),
socket, null, null);
LOG.info("Connecting to: " + socket + " at " + uri);
answers = Collections.synchronizedList(new ArrayList<>());
webSocket = HttpClient.newHttpClient().newWebSocketBuilder()
.buildAsync(uri, new WebSocketListener(answers)).get();
}

@AfterEach
void tearDown() throws ExecutionException, InterruptedException {
answers = null;
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "").get();
}

@Test
public void smoke() {
Awaitility.await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
Assertions.assertFalse(answers.isEmpty());
});
Assertions.assertEquals("Hello, I'm Bob, how can I help you?", answers.get(0));
}

@Test
public void documentBasedAnswer() throws InterruptedException {
// Input tokens are usually much cheaper, than output tokens, so let's stop the LLM from talking too much
String prompt = "What is the opening deposit (in USD) for a standard savings account? Answer with number only";
webSocket.sendText(prompt, true);

// The answer is split to many messages due to Multi<String> in the Bot.
// We need to wait for the end of the answer, detected as no new messages during a second.
// The prompt should protect against this, but it is not guaranteed.
int repeats = 0;
int lastSize=0;
while (answers.size() <= 1 || answers.size()!=lastSize) {
if (repeats++ > 10) {
LOG.warn("We have waited for: " + repeats + " seconds and it is too much!");
break;
}
lastSize=answers.size();
Thread.sleep(1000);
}

String response = String.join("", answers);
Assertions.assertTrue(response.contains("25"));
}

class WebSocketListener implements WebSocket.Listener {
private final List<String> answers;
private StringBuilder current;

WebSocketListener(List<String> answers) {
this.answers = answers;
}

@Override
public void onOpen(WebSocket webSocket) {
WebSocket.Listener.super.onOpen(webSocket);
}

@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
LOG.info("Message: " + data);
if (current == null) {
current = new StringBuilder();
}
current.append(data);
if (last) {
answers.add(current.toString());
current = null;
}
return WebSocket.Listener.super.onText(webSocket, data, last);
}
}
}
Loading