Skip to content

Commit

Permalink
Spring Boot starter for Anthropic
Browse files Browse the repository at this point in the history
  • Loading branch information
LangChain4j committed Mar 14, 2024
1 parent a7fa4ac commit fdca650
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 9 deletions.
67 changes: 67 additions & 0 deletions langchain4j-anthropic-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring</artifactId>
<version>0.29.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>langchain4j-anthropic-spring-boot-starter</artifactId>
<name>LangChain4j Spring Boot starter for Anthropic</name>

<dependencies>

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-anthropic</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>

<!-- should be listed before spring-boot-configuration-processor -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

<!-- needed to generate automatic metadata about available config properties -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<licenses>
<license>
<name>Apache-2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dev.langchain4j.anthropic.spring;

import dev.langchain4j.model.anthropic.AnthropicChatModel;
import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import static dev.langchain4j.anthropic.spring.Properties.PREFIX;

@AutoConfiguration
@EnableConfigurationProperties(Properties.class)
public class AutoConfig {

@Bean
@ConditionalOnProperty(PREFIX + ".chat-model.api-key")
AnthropicChatModel anthropicChatModel(Properties properties) {
ChatModelProperties chatModelProperties = properties.getChatModel();
return AnthropicChatModel.builder()
.baseUrl(chatModelProperties.getBaseUrl())
.apiKey(chatModelProperties.getApiKey())
.version(chatModelProperties.getVersion())
.modelName(chatModelProperties.getModelName())
.temperature(chatModelProperties.getTemperature())
.topP(chatModelProperties.getTopP())
.topK(chatModelProperties.getTopK())
.maxTokens(chatModelProperties.getMaxTokens())
.stopSequences(chatModelProperties.getStopSequences())
.timeout(chatModelProperties.getTimeout())
.maxRetries(chatModelProperties.getMaxRetries())
.logRequests(chatModelProperties.getLogRequests())
.logResponses(chatModelProperties.getLogResponses())
.build();
}

@Bean
@ConditionalOnProperty(PREFIX + ".streaming-chat-model.api-key")
AnthropicStreamingChatModel anthropicStreamingChatModel(Properties properties) {
ChatModelProperties chatModelProperties = properties.getStreamingChatModel();
return AnthropicStreamingChatModel.builder()
.baseUrl(chatModelProperties.getBaseUrl())
.apiKey(chatModelProperties.getApiKey())
.version(chatModelProperties.getVersion())
.modelName(chatModelProperties.getModelName())
.temperature(chatModelProperties.getTemperature())
.topP(chatModelProperties.getTopP())
.topK(chatModelProperties.getTopK())
.maxTokens(chatModelProperties.getMaxTokens())
.stopSequences(chatModelProperties.getStopSequences())
.timeout(chatModelProperties.getTimeout())
.logRequests(chatModelProperties.getLogRequests())
.logResponses(chatModelProperties.getLogResponses())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;

import java.time.Duration;
import java.util.List;

@Getter
@Setter
class ChatModelProperties {

String baseUrl;
String apiKey;
String version;
String modelName;
Double temperature;
Double topP;
Integer topK;
Integer maxTokens;
List<String> stopSequences;
Duration timeout;
Integer maxRetries;
Boolean logRequests;
Boolean logResponses;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@Getter
@Setter
@ConfigurationProperties(prefix = Properties.PREFIX)
public class Properties {

static final String PREFIX = "langchain4j.anthropic";

@NestedConfigurationProperty
ChatModelProperties chatModel;

@NestedConfigurationProperty
ChatModelProperties streamingChatModel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=dev.langchain4j.anthropic.spring.AutoConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dev.langchain4j.anthropic.spring.AutoConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package dev.langchain4j.anthropic.spring;

import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.anthropic.AnthropicChatModel;
import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.output.Response;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

import java.util.concurrent.CompletableFuture;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.assertj.core.api.Assertions.assertThat;

class AutoConfigIT {

private static final String API_KEY = System.getenv("ANTHROPIC_API_KEY");

ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AutoConfig.class));

@Test
void should_provide_chat_model() {
contextRunner
.withPropertyValues(
"langchain4j.anthropic.chat-model.api-key=" + API_KEY,
"langchain4j.anthropic.chat-model.max-tokens=20"
)
.run(context -> {

ChatLanguageModel chatLanguageModel = context.getBean(ChatLanguageModel.class);
assertThat(chatLanguageModel).isInstanceOf(AnthropicChatModel.class);
assertThat(chatLanguageModel.generate("What is the capital of Germany?")).contains("Berlin");

assertThat(context.getBean(AnthropicChatModel.class)).isSameAs(chatLanguageModel);
});
}

@Test
void should_provide_streaming_chat_model() {
contextRunner
.withPropertyValues(
"langchain4j.anthropic.streaming-chat-model.api-key=" + API_KEY,
"langchain4j.anthropic.streaming-chat-model.max-tokens=20"
)
.run(context -> {

StreamingChatLanguageModel streamingChatLanguageModel = context.getBean(StreamingChatLanguageModel.class);
assertThat(streamingChatLanguageModel).isInstanceOf(AnthropicStreamingChatModel.class);
CompletableFuture<Response<AiMessage>> future = new CompletableFuture<>();
streamingChatLanguageModel.generate("What is the capital of Germany?", new StreamingResponseHandler<AiMessage>() {

@Override
public void onNext(String token) {
}

@Override
public void onComplete(Response<AiMessage> response) {
future.complete(response);
}

@Override
public void onError(Throwable error) {
}
});
Response<AiMessage> response = future.get(60, SECONDS);
assertThat(response.content().text()).contains("Berlin");

assertThat(context.getBean(AnthropicStreamingChatModel.class)).isSameAs(streamingChatLanguageModel);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import dev.langchain4j.model.openai.*;
import org.springframework.boot.autoconfigure.AutoConfiguration;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.langchain4j.openai.spring;
package dev.langchain4j.anthropic.spring;

import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.StreamingResponseHandler;
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<url>https://github.com/langchain4j/langchain4j-spring</url>

<modules>
<module>langchain4j-anthropic-spring-boot-starter</module>
<module>langchain4j-ollama-spring-boot-starter</module>
<module>langchain4j-open-ai-spring-boot-starter</module>
</modules>
Expand Down

0 comments on commit fdca650

Please sign in to comment.