-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds Anthropic Connector for Anthropic LLM support
- Loading branch information
1 parent
1c9a019
commit 09c9295
Showing
13 changed files
with
518 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="http://maven.apache.org/POM/4.0.0" | ||
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>de.l3s.interweb</groupId> | ||
<artifactId>interweb-parent</artifactId> | ||
<version>4.0.0-SNAPSHOT</version> | ||
<relativePath>../../pom.xml</relativePath> | ||
</parent> | ||
|
||
<artifactId>connector-anthropic</artifactId> | ||
<version>4.0.0-SNAPSHOT</version> | ||
<packaging>jar</packaging> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>de.l3s.interweb</groupId> | ||
<artifactId>interweb-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-rest-client-reactive-jackson</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-junit5</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>jandex-maven-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<id>make-index</id> | ||
<goals> | ||
<goal>jandex</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
35 changes: 35 additions & 0 deletions
35
...AnthropicConnector/src/main/java/de/l3s/interweb/connector/anthropic/AnthropicClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package de.l3s.interweb.connector.anthropic; | ||
|
||
import jakarta.ws.rs.*; | ||
import jakarta.ws.rs.core.MediaType; | ||
import jakarta.ws.rs.core.Response; | ||
|
||
import io.quarkus.rest.client.reactive.ClientExceptionMapper; | ||
import io.smallrye.mutiny.Uni; | ||
import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; | ||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; | ||
|
||
import de.l3s.interweb.connector.anthropic.entity.CompletionResponse; | ||
import de.l3s.interweb.connector.anthropic.entity.CompletionBody; | ||
import de.l3s.interweb.core.ConnectorException; | ||
|
||
@Path("") | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
@Produces(MediaType.APPLICATION_JSON) | ||
@RegisterRestClient(configKey = "anthropic") | ||
@ClientHeaderParam(name = "x-api-key", value = "${connector.anthropic.apikey}") | ||
public interface AnthropicClient { | ||
|
||
/** | ||
* Anthropic Completion API | ||
* https://docs.anthropic.com/en/api/messages | ||
*/ | ||
@POST | ||
@Path("/v1/messages") | ||
Uni<CompletionResponse> chatCompletions(@HeaderParam("anthropic-version") String version, CompletionBody body); | ||
|
||
@ClientExceptionMapper | ||
static RuntimeException toException(Response response) { | ||
return new ConnectorException("Remote service responded with HTTP " + response.getStatus(), response.readEntity(String.class)); | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
...hropicConnector/src/main/java/de/l3s/interweb/connector/anthropic/AnthropicConnector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package de.l3s.interweb.connector.anthropic; | ||
|
||
import java.time.Instant; | ||
import java.util.Map; | ||
import java.util.List; | ||
import java.util.ArrayList; | ||
|
||
import jakarta.enterprise.context.Dependent; | ||
|
||
import io.smallrye.mutiny.Uni; | ||
import org.eclipse.microprofile.rest.client.inject.RestClient; | ||
|
||
import de.l3s.interweb.connector.anthropic.entity.AnthropicContent; | ||
import de.l3s.interweb.connector.anthropic.entity.CompletionBody; | ||
import de.l3s.interweb.core.ConnectorException; | ||
import de.l3s.interweb.core.completion.CompletionConnector; | ||
import de.l3s.interweb.core.completion.CompletionQuery; | ||
import de.l3s.interweb.core.completion.CompletionResults; | ||
import de.l3s.interweb.core.completion.Message; | ||
import de.l3s.interweb.core.completion.UsagePrice; | ||
import de.l3s.interweb.core.completion.Usage; | ||
import de.l3s.interweb.core.completion.Choice; | ||
|
||
@Dependent | ||
public class AnthropicConnector implements CompletionConnector { | ||
|
||
private static final String version = "2023-06-01"; | ||
private static final Map<String, UsagePrice> models = Map.of( | ||
"claude-3-opus-20240229", new UsagePrice(0.015, 0.075), | ||
"claude-3-sonnet-20240229", new UsagePrice(0.003, 0.015), | ||
"claude-3-haiku-20240307", new UsagePrice(0.00025, 0.00125) | ||
); | ||
|
||
@Override | ||
public String getName() { | ||
return "Anthropic"; | ||
} | ||
|
||
@Override | ||
public String getBaseUrl() { | ||
return "https://api.anthropic.com/"; | ||
} | ||
|
||
@Override | ||
public String[] getModels() { | ||
return models.keySet().toArray(new String[0]); | ||
} | ||
|
||
@Override | ||
public UsagePrice getPrice(String model) { | ||
return models.get(model); | ||
} | ||
|
||
@RestClient | ||
AnthropicClient anthropic; | ||
|
||
@Override | ||
public Uni<CompletionResults> complete(CompletionQuery query) throws ConnectorException { | ||
return anthropic.chatCompletions(version, new CompletionBody(query.getModel(), query)).map(response -> { | ||
CompletionResults results = new CompletionResults(); | ||
results.setModel(query.getModel()); | ||
results.setCreated(Instant.now()); | ||
|
||
List<Choice> choices = new ArrayList<>(); | ||
Choice choice = new Choice(); | ||
AnthropicContent content = response.getContent().get(0); | ||
Message message = new Message(); | ||
message.setContent(content.getText()); | ||
message.setRole(Message.Role.assistant); | ||
choice.setMessage(message); | ||
choice.setIndex(0); | ||
choice.setFinishReason(response.getStopReason()); | ||
choices.add(choice); | ||
results.setChoices(choices); | ||
|
||
Usage usage = new Usage(); | ||
usage.setPromptTokens(response.getUsage().getInputTokens()); | ||
usage.setCompletionTokens(response.getUsage().getOutputTokens()); | ||
usage.setTotalTokens(response.getUsage().getInputTokens() + response.getUsage().getOutputTokens()); | ||
results.setUsage(usage); | ||
return results; | ||
}); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...cConnector/src/main/java/de/l3s/interweb/connector/anthropic/entity/AnthropicContent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package de.l3s.interweb.connector.anthropic.entity; | ||
|
||
import io.quarkus.runtime.annotations.RegisterForReflection; | ||
|
||
|
||
@RegisterForReflection | ||
public class AnthropicContent { | ||
private String type; | ||
private String text; | ||
|
||
public String getType() { | ||
return type; | ||
} | ||
|
||
public void setType(String type) { | ||
this.type = type; | ||
} | ||
|
||
public String getText() { | ||
return text; | ||
} | ||
|
||
public void setText(String text) { | ||
this.text = text; | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...picConnector/src/main/java/de/l3s/interweb/connector/anthropic/entity/AnthropicUsage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package de.l3s.interweb.connector.anthropic.entity; | ||
|
||
import io.quarkus.runtime.annotations.RegisterForReflection; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
@RegisterForReflection | ||
public class AnthropicUsage { | ||
|
||
@JsonProperty("input_tokens") | ||
private int inputTokens; | ||
@JsonProperty("output_tokens") | ||
private int outputTokens; | ||
|
||
public int getInputTokens() { | ||
return inputTokens; | ||
} | ||
|
||
public void setInputTokens(int inputTokens) { | ||
this.inputTokens = inputTokens; | ||
} | ||
|
||
public int getOutputTokens() { | ||
return outputTokens; | ||
} | ||
|
||
public void setOutputTokens(int outputTokens) { | ||
this.outputTokens = outputTokens; | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...picConnector/src/main/java/de/l3s/interweb/connector/anthropic/entity/CompletionBody.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package de.l3s.interweb.connector.anthropic.entity; | ||
|
||
import java.util.List; | ||
|
||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
|
||
import io.quarkus.runtime.annotations.RegisterForReflection; | ||
|
||
import de.l3s.interweb.core.completion.CompletionQuery; | ||
import de.l3s.interweb.core.completion.Message; | ||
import de.l3s.interweb.core.completion.Message.Role; | ||
|
||
@JsonInclude(JsonInclude.Include.NON_NULL) | ||
@RegisterForReflection | ||
public final class CompletionBody { | ||
|
||
private List<CompletionMessage> messages; | ||
|
||
private String model; | ||
|
||
private String system; | ||
|
||
private Double temperature; | ||
|
||
@JsonProperty("top_p") | ||
private Double topP; | ||
|
||
@JsonProperty("max_tokens") | ||
private Integer maxTokens; | ||
|
||
public CompletionBody(String model, CompletionQuery query) { | ||
this.model = model; | ||
System.out.println("model: " + model); | ||
if (this.model == null) { | ||
throw new IllegalArgumentException("model must be set"); | ||
} | ||
|
||
this.messages = query.getMessages().stream().filter( | ||
m -> m.getRole() != Role.system | ||
).map(CompletionMessage::new).toList(); | ||
this.system = query.getMessages().stream().filter( | ||
m -> m.getRole() == Role.system | ||
).findFirst().map(Message::getContent).orElse(null); | ||
|
||
this.temperature = query.getTemperature(); | ||
this.topP = query.getTopP(); | ||
this.maxTokens = query.getMaxTokens(); | ||
|
||
if (this.maxTokens == null) { | ||
throw new IllegalArgumentException("maxTokens must be set"); | ||
} | ||
} | ||
|
||
public String getModel() { | ||
return model; | ||
} | ||
|
||
public List<CompletionMessage> getMessages() { | ||
return messages; | ||
} | ||
|
||
public String getSystem() { | ||
return system; | ||
} | ||
|
||
public Double getTemperature() { | ||
return temperature; | ||
} | ||
|
||
public Double getTopP() { | ||
return topP; | ||
} | ||
|
||
public Integer getMaxTokens() { | ||
return maxTokens; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...Connector/src/main/java/de/l3s/interweb/connector/anthropic/entity/CompletionMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package de.l3s.interweb.connector.anthropic.entity; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnore; | ||
|
||
import io.quarkus.runtime.annotations.RegisterForReflection; | ||
|
||
import de.l3s.interweb.core.completion.Message; | ||
|
||
@RegisterForReflection | ||
public final class CompletionMessage { | ||
private String role; | ||
@JsonIgnore | ||
private String name; | ||
private String content; | ||
|
||
public CompletionMessage(Message message) { | ||
this.role = message.getRole().name(); | ||
this.name = message.getName(); | ||
this.content = message.getContent(); | ||
} | ||
|
||
public String getRole() { | ||
return role; | ||
} | ||
|
||
public void setRole(String role) { | ||
this.role = role; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getContent() { | ||
return content; | ||
} | ||
|
||
public void setContent(String content) { | ||
this.content = content; | ||
} | ||
} |
Oops, something went wrong.