Skip to content
Open
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
12 changes: 9 additions & 3 deletions neo4j-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>dev.langchain4j</groupId>
<artifactId>neo4j-example</artifactId>
<version>1.0.0-beta4</version>
<version>1.1.0-beta7</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
Expand All @@ -29,7 +29,7 @@
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.1.0-beta7</version>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
Expand All @@ -45,7 +45,7 @@
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-neo4j-retriever</artifactId>
<version>${project.version}</version>
<version>1.1.0-beta7</version>
</dependency>

<dependency>
Expand All @@ -64,6 +64,12 @@
<artifactId>langchain4j-open-ai</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embeddings-all-minilm-l6-v2-q</artifactId>
<version>1.1.0-beta7</version>
<scope>compile</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package agent;


import dev.langchain4j.community.store.embedding.neo4j.Neo4jEmbeddingStore;
import dev.langchain4j.community.store.memory.chat.neo4j.Neo4jChatMemoryStore;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.testcontainers.containers.Neo4jContainer;
import util.Utils;

import java.util.Scanner;
import java.util.UUID;

import static agent.CustomerUtil.createAssistant;
import static agent.CustomerUtil.createEmbeddingStore;
import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;


/**
* example prompt: `What is the cancellation policy?`
*/
public class CustomerSupportAgentNeo4jApplicationWithoutSpringBoot {

public static void main(String[] args) {
try (Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5.26.6-enterprise").withLabsPlugins("apoc").withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes").withAdminPassword("pass1234")) {
neo4j.start();

// Setup
String openAiApiKey = System.getenv("OPENAI_API_KEY");
String baseUrl = System.getenv("OPENAI_BASE_URL");

ChatModel chatModel = OpenAiChatModel.builder()
.apiKey(openAiApiKey)
.baseUrl(baseUrl)
.modelName(GPT_4_O_MINI)
.build();

AllMiniLmL6V2QuantizedEmbeddingModel embeddingModel = new AllMiniLmL6V2QuantizedEmbeddingModel();

Neo4jChatMemoryStore chatMemoryStore = Neo4jChatMemoryStore.builder()
.withBasicAuth(neo4j.getBoltUrl(), "neo4j", neo4j.getAdminPassword())
.build();

Neo4jEmbeddingStore embeddingStore = createEmbeddingStore(neo4j, embeddingModel);


Utils.Assistant assistant = createAssistant(chatModel, chatMemoryStore);

CustomerUtil.AssistantService service = new CustomerUtil.AssistantService(assistant, embeddingStore, embeddingModel);

// Interactive loop
try (Scanner scanner = new Scanner(System.in)) {
String sessionId = UUID.randomUUID().toString();

System.out.println("Welcome to the Customer Support Assistant!");
System.out.println("Type 'exit' to quit.");

while (true) {
System.out.print("\nYou: ");
String input = scanner.nextLine();

if ("exit".equalsIgnoreCase(input)) {
break;
}

String response = service.chat(sessionId, input);
System.out.println("Assistant: " + response);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package agent;


import dev.langchain4j.community.store.embedding.neo4j.Neo4jEmbeddingStore;
import dev.langchain4j.community.store.memory.chat.neo4j.Neo4jChatMemoryStore;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.testcontainers.containers.Neo4jContainer;
import util.Utils;

import java.util.Scanner;

import static agent.CustomerUtil.createAssistant;
import static agent.CustomerUtil.createEmbeddingStore;

/**
* example prompt: `What is the cancellation policy?`
*/
@SpringBootApplication
public class CustomerSupportAgentNeo4jWithSpringBoot {

private static final Logger log = LoggerFactory.getLogger(CustomerSupportAgentNeo4jWithSpringBoot.class);
private static Neo4jContainer container = new Neo4jContainer<>("neo4j:5.26.6-enterprise").withLabsPlugins("apoc").withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes").withAdminPassword("pass1234");

public static void main(String[] args) {
container.start();
SpringApplication.run(CustomerSupportAgentNeo4jWithSpringBoot.class, args);
container.stop();
}

@Configuration
public static class CustomerSupportAgentConfiguration {

@Bean
public Neo4jEmbeddingStore embeddingStore() {
return createEmbeddingStore(container, embeddingModel());
}

@Bean
public Neo4jChatMemoryStore chatMemoryStore() {
return Neo4jChatMemoryStore.builder()
.withBasicAuth(container.getBoltUrl(), "neo4j", container.getAdminPassword())
.build();
}

@Bean
public EmbeddingModel embeddingModel() {
return new AllMiniLmL6V2QuantizedEmbeddingModel();
}

@Bean
public ChatModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.baseUrl(System.getenv("OPENAI_BASE_URL"))
.build();
}

@Bean
public Utils.Assistant assistant(ChatModel chatLanguageModel, Neo4jChatMemoryStore chatMemoryStore) {
return createAssistant(chatLanguageModel, chatMemoryStore);
}

@Bean
public CustomerUtil.AssistantService assistantService(Utils.Assistant assistant, Neo4jEmbeddingStore embeddingStore,
EmbeddingModel embeddingModel) {
return new CustomerUtil.AssistantService(assistant, embeddingStore, embeddingModel);
}

@Bean
public ApplicationRunner runner(CustomerUtil.AssistantService assistantService) {
return args -> {
try (Scanner scanner = new Scanner(System.in)) {
String sessionId = "user-123";
while (true) {
log.info("==================================================");
log.info("User: ");
String userQuery = scanner.nextLine();
if ("exit".equalsIgnoreCase(userQuery)) break;
log.info("==================================================");
String response = assistantService.chat(sessionId, userQuery);
log.info("==================================================");
log.info("Assistant: " + response);
}
}
};
}
}
}
94 changes: 94 additions & 0 deletions neo4j-example/src/main/java/agent/CustomerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package agent;

import dev.langchain4j.community.store.embedding.neo4j.Neo4jEmbeddingStore;
import dev.langchain4j.community.store.memory.chat.neo4j.Neo4jChatMemoryStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import org.testcontainers.containers.Neo4jContainer;
import util.Utils;

import java.io.File;
import java.net.URI;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument;
import static util.Utils.toPath;

public class CustomerUtil {

public static Utils.Assistant createAssistant(ChatModel chatModel, Neo4jChatMemoryStore chatMemoryStore) {
return AiServices.builder(Utils.Assistant.class)
.chatModel(chatModel)
.chatMemoryProvider(sessionId -> MessageWindowChatMemory.builder()
.id(sessionId)
.chatMemoryStore(chatMemoryStore)
.maxMessages(10)
.build())
.build();
}

public static Neo4jEmbeddingStore createEmbeddingStore(Neo4jContainer<?> neo4j, EmbeddingModel embeddingModel) {
Neo4jEmbeddingStore embeddingStore = Neo4jEmbeddingStore.builder()
.withBasicAuth(neo4j.getBoltUrl(), "neo4j", neo4j.getAdminPassword())
.dimension(384)
.build();

Document document = loadDocument(toPath("miles-of-smiles-terms-of-use.txt"), new TextDocumentParser());
DocumentSplitter documentSplitter = DocumentSplitters.recursive(100, 0);
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(documentSplitter)
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(document);
return embeddingStore;
}

public static class AssistantService {

private final Utils.Assistant assistant;
private final Neo4jEmbeddingStore embeddingStore;
private final EmbeddingModel embeddingModel;

public AssistantService(Utils.Assistant assistant,
Neo4jEmbeddingStore embeddingStore,
EmbeddingModel embeddingModel) {
this.assistant = assistant;
this.embeddingStore = embeddingStore;
this.embeddingModel = embeddingModel;
}

public String chat(String sessionId, String userMessage) {
Embedding queryEmbedding = embeddingModel.embed(userMessage).content();
final EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.build();
final List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(request).matches();
String context = matches.stream().map(i -> i.embedded().text()).collect(Collectors.joining("\n---\n"));

String prompt = """
You are a helpful customer support agent.
Use the following context to answer the user:
%s
User: %s
""".formatted(context, userMessage);


return assistant.chat(prompt);
}
}
}
22 changes: 22 additions & 0 deletions neo4j-example/src/main/java/util/Utils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package util;

import dev.langchain4j.service.UserMessage;

import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Utils {

public interface Assistant {
String chat(@UserMessage String userMessage);
}

public static Path toPath(String fileName) {
try {
return Paths.get(Utils.class.getClassLoader().getResource(fileName).toURI());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
37 changes: 37 additions & 0 deletions neo4j-example/src/main/resources/miles-of-smiles-terms-of-use.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Miles of Smiles Car Rental Services Terms of Use

1. Introduction
These Terms of Service (“Terms”) govern the access or use by you, an individual, from within any country in the world, of applications, websites, content, products, and services (“Services”) made available by Miles of Smiles Car Rental Services, a company registered in the United States of America.

2. The Services
Miles of Smiles rents out vehicles to the end user. We reserve the right to temporarily or permanently discontinue the Services at any time and are not liable for any modification, suspension or discontinuation of the Services.

3. Bookings
3.1 Users may make a booking through our website or mobile application.
3.2 You must provide accurate, current and complete information during the reservation process. You are responsible for all charges incurred under your account.
3.3 All bookings are subject to vehicle availability.

4. Cancellation Policy
4.1 Reservations can be cancelled up to 7 days prior to the start of the booking period.
4.2 If the booking period is less than 3 days, cancellations are not permitted.

5. Use of Vehicle
5.1 All cars rented from Miles of Smiles must not be used:
for any illegal purpose or in connection with any criminal offense.
for teaching someone to drive.
in any race, rally or contest.
while under the influence of alcohol or drugs.

6. Liability
6.1 Users will be held liable for any damage, loss, or theft that occurs during the rental period.
6.2 We do not accept liability for any indirect or consequential loss, damage, or expense including but not limited to loss of profits.

7. Governing Law
These terms will be governed by and construed in accordance with the laws of the United States of America, and any disputes relating to these terms will be subject to the exclusive jurisdiction of the courts of United States.

8. Changes to These Terms
We may revise these terms of use at any time by amending this page. You are expected to check this page from time to time to take notice of any changes we made.

9. Acceptance of These Terms
By using the Services, you acknowledge that you have read and understand these Terms and agree to be bound by them.
If you do not agree to these Terms, please do not use or access our Services.