Skip to content

Commit 6ba0ee2

Browse files
committed
Support claude
1 parent bb6569d commit 6ba0ee2

13 files changed

Lines changed: 179 additions & 15 deletions

File tree

.github/workflows/checker.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
distribution: 'temurin'
7272
- run: chmod 755 ./mvnw
7373
- run: |
74-
./mvnw clean install test -Dfindbugs.skip -Dcheckstyle.skip -Dgpg.skip -Dskip.yarn -Dopenai.token=${{ secrets.OPENAI_TOKEN }} -Dproxy.token=${{ secrets.PROXY_TOKEN }} -Dproxy.host=${{ secrets.PROXY_HOST }} -Dazure.token=${{ secrets.AZURE_TOKEN}}
74+
./mvnw clean install test -Dfindbugs.skip -Dcheckstyle.skip -Dgpg.skip -Dskip.yarn -Dopenai.token=${{ secrets.OPENAI_TOKEN }} -Dproxy.token=${{ secrets.PROXY_TOKEN }} -Dproxy.host=${{ secrets.PROXY_HOST }} -Dazure.token=${{ secrets.AZURE_TOKEN}} -Dclaude.token=${{ secrets.CLAUDE_TOKEN }}
7575
7676
before_checker_package:
7777
runs-on: ubuntu-latest
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: Completions
3+
---
4+
5+
!!! note
6+
7+
Support the claude, product address: [https://claude.ai/](https://claude.ai/)
8+
9+
### Create completion
10+
11+
---
12+
13+
Creates a completion for the provided prompt and parameters.
14+
15+
```java
16+
// Automatic resource release
17+
try(OpenAiClient client=OpenAiClient.builder()
18+
.apiKey(System.getProperty("claude.token"))
19+
.provider(ProviderModel.CLAUDE)
20+
.build())
21+
{
22+
CompletionEntity configure = CompletionEntity.builder()
23+
.model(CompletionModel.CLAUDE_2.getName())
24+
.prompt("How to create a completion")
25+
.build();
26+
client.createCompletion(configure).getChoices();
27+
}
28+
```
29+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
title: Completions
3+
---
4+
5+
!!! note
6+
7+
支持 claude,产品地址: [https://claude.ai/](https://claude.ai/)
8+
9+
### Create completion
10+
11+
---
12+
13+
为提供的提示和参数创建补全。
14+
15+
```java
16+
// Automatic resource release
17+
try(OpenAiClient client=OpenAiClient.builder()
18+
.apiKey(System.getProperty("claude.token"))
19+
.provider(ProviderModel.CLAUDE)
20+
.build())
21+
{
22+
CompletionEntity configure = CompletionEntity.builder()
23+
.model(CompletionModel.CLAUDE_2.getName())
24+
.prompt("How to create a completion")
25+
.build();
26+
client.createCompletion(configure).getChoices();
27+
}
28+
```

docs/mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,7 @@ nav:
8787
- Azure Open Ai:
8888
- reference/azure/completions.md
8989
- reference/azure/completions_chat.md
90+
- Anthropic Claude:
91+
- reference/anthropic/completions.md
9092
- released.md
9193
- powered_by.md

src/main/java/org/devlive/sdk/openai/OpenAiClient.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.apache.commons.lang3.StringUtils;
1010
import org.devlive.sdk.openai.exception.ParamException;
1111
import org.devlive.sdk.openai.interceptor.AzureInterceptor;
12+
import org.devlive.sdk.openai.interceptor.ClaudeInterceptor;
1213
import org.devlive.sdk.openai.interceptor.DefaultInterceptor;
1314
import org.devlive.sdk.openai.interceptor.OpenAiInterceptor;
1415
import org.devlive.sdk.openai.model.ProviderModel;
@@ -44,10 +45,10 @@ private OpenAiClient(OpenAiClientBuilder builder)
4445
}
4546

4647
if (ObjectUtils.isEmpty(builder.provider)) {
47-
builder.provider(ProviderModel.openai);
48+
builder.provider(ProviderModel.OPENAI);
4849
}
4950

50-
if (builder.provider.equals(ProviderModel.azure)) {
51+
if (builder.provider.equals(ProviderModel.AZURE)) {
5152
if (ObjectUtils.isEmpty(builder.model)) {
5253
throw new ParamException("Azure provider model not specified");
5354
}
@@ -93,7 +94,7 @@ public OpenAiClientBuilder apiKey(String apiKey)
9394
public OpenAiClientBuilder apiHost(String apiHost)
9495
{
9596
if (StringUtils.isEmpty(apiHost)) {
96-
apiHost = "https://api.openai.com";
97+
apiHost = this.getDefaultHost();
9798
}
9899
else {
99100
boolean flag = apiHost.startsWith("http") || apiHost.startsWith("https");
@@ -126,7 +127,7 @@ public OpenAiClientBuilder unit(TimeUnit unit)
126127
public OpenAiClientBuilder client(OkHttpClient client)
127128
{
128129
if (ObjectUtils.isEmpty(this.provider)) {
129-
this.provider = ProviderModel.openai;
130+
this.provider = ProviderModel.OPENAI;
130131
}
131132

132133
if (ObjectUtils.isEmpty(client)) {
@@ -140,11 +141,15 @@ public OpenAiClientBuilder client(OkHttpClient client)
140141
}
141142
// Add default interceptor
142143
DefaultInterceptor interceptor = new OpenAiInterceptor();
143-
if (this.provider.equals(ProviderModel.azure)) {
144+
if (this.provider.equals(ProviderModel.AZURE)) {
144145
interceptor = new AzureInterceptor();
145146
interceptor.setVersion(this.version);
146147
interceptor.setModel(this.model);
147148
}
149+
// Anthropic claude interceptor
150+
if (this.provider.equals(ProviderModel.CLAUDE)) {
151+
interceptor = new ClaudeInterceptor();
152+
}
148153
interceptor.setApiKey(apiKey);
149154
client = client.newBuilder()
150155
.addInterceptor(interceptor)
@@ -153,6 +158,14 @@ public OpenAiClientBuilder client(OkHttpClient client)
153158
return this;
154159
}
155160

161+
private String getDefaultHost()
162+
{
163+
if (this.provider.equals(ProviderModel.CLAUDE)) {
164+
return "https://api.anthropic.com";
165+
}
166+
return "https://api.openai.com";
167+
}
168+
156169
public OpenAiClient build()
157170
{
158171
return new OpenAiClient(this);

src/main/java/org/devlive/sdk/openai/entity/CompletionEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.devlive.sdk.openai.entity;
22

3+
import com.fasterxml.jackson.annotation.JsonAlias;
34
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
45
import com.fasterxml.jackson.annotation.JsonProperty;
56
import lombok.AllArgsConstructor;
@@ -31,6 +32,7 @@ public class CompletionEntity
3132
private Double temperature;
3233

3334
@JsonProperty(value = "max_tokens")
35+
@JsonAlias(value = {"max_tokens_to_sample"})
3436
private Integer maxTokens;
3537

3638
@JsonProperty(value = "top_p")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.devlive.sdk.openai.interceptor;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import okhttp3.Request;
5+
import org.apache.commons.lang3.StringUtils;
6+
import org.devlive.sdk.openai.exception.ParamException;
7+
8+
@Slf4j
9+
public class ClaudeInterceptor
10+
extends DefaultInterceptor
11+
{
12+
public ClaudeInterceptor()
13+
{
14+
log.debug("Claude Interceptor");
15+
}
16+
17+
@Override
18+
protected Request prepared(Request original)
19+
{
20+
log.debug("Claude interceptor request url {}", original.url());
21+
if (StringUtils.isEmpty(this.getApiKey())) {
22+
throw new ParamException("Invalid Claude token, must be non-empty");
23+
}
24+
return original.newBuilder()
25+
.header("x-api-key", this.getApiKey())
26+
.header("Content-Type", "application/json")
27+
.method(original.method(), original.body())
28+
.build();
29+
}
30+
}

src/main/java/org/devlive/sdk/openai/model/CompletionModel.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ public enum CompletionModel
8585
ADA("ada",
8686
"Capable of very simple tasks, usually the fastest model in the GPT-3 series, and lowest cost.",
8787
null,
88-
2049);
88+
2049),
89+
/* ================================ Claude ================================ */
90+
CLAUDE_2("claude-2",
91+
null,
92+
null,
93+
Integer.MAX_VALUE),
94+
CLAUDE_INSTANT_1("claude-instant-1",
95+
null,
96+
null,
97+
Integer.MAX_VALUE);
8998

9099
private final String name;
91100
private final String description;

src/main/java/org/devlive/sdk/openai/model/ProviderModel.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
public enum ProviderModel
44
{
5-
openai,
6-
azure
5+
/**
6+
* Open AI
7+
* https://openai.com
8+
*/
9+
OPENAI,
10+
/**
11+
* Azure OpenAI service
12+
* https://oai.azure.com/portal
13+
*/
14+
AZURE,
15+
/**
16+
* A next-generation AI assistant for your tasks, no matter the scale
17+
* https://www.anthropic.com/product
18+
*/
19+
CLAUDE
720
}

src/main/java/org/devlive/sdk/openai/utils/ProviderUtils.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class ProviderUtils
1212
{
1313
private static final Map<UrlModel, String> DEFAULT_PROVIDER = new HashMap<>();
1414
private static final Map<UrlModel, String> AZURE_PROVIDER = new HashMap<>();
15+
private static final Map<UrlModel, String> CLAUDE_PROVIDER = new HashMap<>();
1516

1617
static {
1718
DEFAULT_PROVIDER.put(UrlModel.FETCH_MODELS, "v1/models");
@@ -28,6 +29,8 @@ public class ProviderUtils
2829

2930
AZURE_PROVIDER.put(UrlModel.FETCH_COMPLETIONS, "completions");
3031
AZURE_PROVIDER.put(UrlModel.FETCH_CHAT_COMPLETIONS, "chat/completions");
32+
33+
CLAUDE_PROVIDER.put(UrlModel.FETCH_COMPLETIONS, "v1/complete");
3134
}
3235

3336
private ProviderUtils()
@@ -43,9 +46,14 @@ private ProviderUtils()
4346
*/
4447
public static String getUrl(ProviderModel provider, UrlModel model)
4548
{
46-
provider = Optional.ofNullable(provider).orElse(ProviderModel.openai);
47-
Map<UrlModel, String> selectedProvider = provider.equals(ProviderModel.azure) ? AZURE_PROVIDER : DEFAULT_PROVIDER;
48-
49+
provider = Optional.ofNullable(provider).orElse(ProviderModel.OPENAI);
50+
Map<UrlModel, String> selectedProvider = DEFAULT_PROVIDER;
51+
if (provider.equals(ProviderModel.AZURE)) {
52+
selectedProvider = AZURE_PROVIDER;
53+
}
54+
if (provider.equals(ProviderModel.CLAUDE)) {
55+
selectedProvider = CLAUDE_PROVIDER;
56+
}
4957
ProviderModel finalProvider = provider;
5058
return Optional.ofNullable(selectedProvider.get(model))
5159
.orElseThrow(() -> new RequestException(String.format("Provider %s not supported %s", finalProvider, model)));

0 commit comments

Comments
 (0)