Skip to content

Commit 6581a0d

Browse files
committed
Switch to LangChain4j
1 parent d0a72b3 commit 6581a0d

File tree

7 files changed

+285
-237
lines changed

7 files changed

+285
-237
lines changed

build.sbt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ libraryDependencies ++= Seq(
3636
"org.apache.pekko" %% "pekko-http-spray-json" % pekkoHTTPVersion,
3737
"org.apache.pekko" %% "pekko-http-xml" % pekkoHTTPVersion,
3838

39-
// JSON (un)marshalling in Java examples
40-
"org.json" % "json" % "20240303",
41-
4239
"io.circe" %% "circe-core" % circeVersion,
4340
"io.circe" %% "circe-generic" % circeVersion,
4441
"io.circe" %% "circe-parser" % circeVersion,
@@ -147,6 +144,12 @@ libraryDependencies ++= Seq(
147144
"org.apache.pekko" %% "pekko-testkit" % pekkoVersion % Test,
148145
"org.assertj" % "assertj-core" % "3.25.3" % Test,
149146

147+
"org.apache.poi" % "poi-ooxml" % "5.3.0",
148+
"dev.langchain4j" % "langchain4j-anthropic" % "1.0.0-beta2",
149+
"dev.langchain4j" % "langchain4j-open-ai" % "1.0.0-beta2",
150+
151+
152+
150153
// https://docs.gatling.io/reference/integrations/build-tools/sbt-plugin/
151154
"io.gatling" % "gatling-core" % gatlingVersion,
152155
"io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion,
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package tools;
2+
3+
import dev.langchain4j.data.message.SystemMessage;
4+
import dev.langchain4j.data.message.UserMessage;
5+
import dev.langchain4j.model.anthropic.AnthropicChatModel;
6+
import dev.langchain4j.model.chat.ChatLanguageModel;
7+
import dev.langchain4j.model.chat.response.ChatResponse;
8+
import org.apache.commons.lang3.tuple.ImmutablePair;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.time.Duration;
13+
14+
/**
15+
* Access Anthropic Claude models with LangChain4j
16+
* <br>
17+
* Doc:
18+
* https://docs.anthropic.com/claude/reference/getting-started-with-the-api
19+
* https://github.com/langchain4j/langchain4j
20+
*/
21+
public class AnthropicCompletions {
22+
private static final Logger LOGGER = LoggerFactory.getLogger(AnthropicCompletions.class);
23+
public static final String API_KEY = "***";
24+
public static final String MODEL_NAME = "claude-3-7-sonnet-20250219";
25+
26+
private final ChatLanguageModel model;
27+
private final String moviePlotContext;
28+
29+
public AnthropicCompletions() {
30+
this(CompletionsUtil.DEFAULT_TRANSLATOR_SYSTEM_MESSAGE);
31+
}
32+
33+
private AnthropicCompletions(String moviePlotContext) {
34+
this.model = AnthropicChatModel.builder()
35+
.apiKey(API_KEY)
36+
.modelName(MODEL_NAME)
37+
.temperature(0.2)
38+
.cacheSystemMessages(true)
39+
.cacheTools(true)
40+
.maxTokens(8192)
41+
.maxRetries(10)
42+
.timeout(Duration.ofMinutes(5))
43+
.build();
44+
this.moviePlotContext = moviePlotContext;
45+
}
46+
47+
/**
48+
* Creates a new AnthropicCompletions instance with movie context information.
49+
*
50+
* @param movieTitle The title of the movie
51+
* @param movieReleaseYear The release year of the movie
52+
* @return A new AnthropicCompletions instance with the resolved movie plot context
53+
*/
54+
public static AnthropicCompletions withContext(String movieTitle, int movieReleaseYear) {
55+
ChatLanguageModel contextModel = AnthropicChatModel.builder()
56+
.apiKey(API_KEY)
57+
.modelName(MODEL_NAME)
58+
.temperature(0.1)
59+
.maxTokens(1024)
60+
.build();
61+
62+
String contextPrompt = CompletionsUtil.createMovieContextPrompt(movieTitle, movieReleaseYear);
63+
ChatResponse response = contextModel.chat(
64+
UserMessage.from(contextPrompt)
65+
);
66+
67+
String movieContext = response.aiMessage().text();
68+
LOGGER.info("Generated movie context with: {} for: {} ({}):\n{}", MODEL_NAME, movieTitle, movieReleaseYear, movieContext);
69+
70+
return new AnthropicCompletions(movieContext);
71+
}
72+
73+
public ImmutablePair<String, Integer> runCompletions(String prompt) {
74+
ChatResponse response = model.chat(
75+
SystemMessage.systemMessage(moviePlotContext),
76+
UserMessage.from(prompt)
77+
);
78+
return new ImmutablePair<>(response.aiMessage().text(), response.tokenUsage().totalTokenCount());
79+
}
80+
81+
public static void main(String[] args) {
82+
String toTranslate = CompletionsUtil.createTranslationPrompt("This is fun.", "English", "German");
83+
84+
ImmutablePair<String, Integer> result = new AnthropicCompletions().runCompletions(toTranslate);
85+
CompletionsUtil.logCompletionResult(result.getLeft(), result.getRight(), "Translation");
86+
87+
ImmutablePair<String, Integer> resultWithContext = AnthropicCompletions.withContext("The Hangover", 2009).runCompletions(toTranslate);
88+
CompletionsUtil.logCompletionResult(resultWithContext.getLeft(), resultWithContext.getRight(), "Translation with context");
89+
}
90+
91+
public String toString() {
92+
return "Anthropic: " + MODEL_NAME;
93+
}
94+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package tools;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
/**
7+
* Utility class for common functionality used by different LLM completion implementations
8+
*/
9+
public class CompletionsUtil {
10+
private static final Logger LOGGER = LoggerFactory.getLogger(CompletionsUtil.class);
11+
12+
/**
13+
* Default system message for translation tasks
14+
*/
15+
public static final String DEFAULT_TRANSLATOR_SYSTEM_MESSAGE = "You are a translator";
16+
17+
/**
18+
* Creates a translation prompt
19+
*
20+
* @param text Text to translate
21+
* @param sourceLanguage Source language
22+
* @param targetLanguage Target language
23+
* @return Formatted translation prompt
24+
*/
25+
public static String createTranslationPrompt(String text, String sourceLanguage, String targetLanguage) {
26+
return String.format("Translate the following subtitle text from %s to %s: %s",
27+
sourceLanguage, targetLanguage, text);
28+
}
29+
30+
/**
31+
* Creates a movie context prompt
32+
*
33+
* @param movieTitle The title of the movie
34+
* @param movieReleaseYear The release year of the movie
35+
* @return Formatted movie context prompt
36+
*/
37+
public static String createMovieContextPrompt(String movieTitle, int movieReleaseYear) {
38+
return String.format(
39+
"Find movie metadata about the movie '%s' released in %d\n" +
40+
"If you don't know this movie or if the title or release year is ambiguous: Respond with \"N/A\", do not apologize." +
41+
"Structure of the response:\n" +
42+
"Plot summary: [Max 100 words]" +
43+
"Locations: [Max 3 key locations]" +
44+
"Key characters: [Max 5 main character names, no actor names]" +
45+
"Themes: [Max 3 main themes]" +
46+
"Notable scenes: [Max 3 brief descriptions of memorable scenes]",
47+
movieTitle, movieReleaseYear);
48+
}
49+
50+
/**
51+
* Logs completion results
52+
*
53+
* @param result The completion result
54+
* @param tokenCount The token count
55+
* @param context Additional context information (optional)
56+
*/
57+
public static void logCompletionResult(String result, int tokenCount, String context) {
58+
if (context != null && !context.isEmpty()) {
59+
LOGGER.info("{}: {}", context, result);
60+
} else {
61+
LOGGER.info("Result: {}", result);
62+
}
63+
LOGGER.info("Total tokens: {}", tokenCount);
64+
}
65+
}

src/main/scala/tools/HttpRequestRetryStrategyOpenAI.java

Lines changed: 0 additions & 87 deletions
This file was deleted.

0 commit comments

Comments
 (0)