Skip to content
Merged
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
49 changes: 4 additions & 45 deletions core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,6 @@ public class ZaiConfig {
*/
private String apiKey;

/**
* API id component.
*/
private String apiId;

/**
* API secret component.
*/
private String apiSecret;

/**
* Custom Http Request Headers
*/
Expand All @@ -84,7 +74,8 @@ public class ZaiConfig {
/**
* Flag to disable token caching.
*/
private boolean disableTokenCache;
@Builder.Default
private boolean disableTokenCache = true;

/**
* Maximum number of idle connections in the connection pool.
Expand All @@ -96,7 +87,7 @@ public class ZaiConfig {
* Keep alive duration for connections in the pool (in seconds).
*/
@Builder.Default
private long connectionPoolKeepAliveDuration = 1;
private long connectionPoolKeepAliveDuration = 10;

/**
* Time unit for connection pool keep alive duration.
Expand Down Expand Up @@ -149,10 +140,8 @@ public ZaiConfig(String apiKey) {
this.apiKey = apiKey;
String[] arrStr = apiKey.split("\\.");
if (arrStr.length != 2) {
throw new RuntimeException("invalid apiSecretKey");
throw new RuntimeException("invalid api Key");
}
this.apiId = arrStr[0];
this.apiSecret = arrStr[1];
}

/**
Expand All @@ -166,8 +155,6 @@ public void setApiKey(String apiKey) {
if (arrStr.length != 2) {
throw new RuntimeException("invalid api Key");
}
this.apiId = arrStr[0];
this.apiSecret = arrStr[1];
}

/**
Expand All @@ -194,38 +181,10 @@ public String getApiKey() {
if (value != null && !value.isEmpty()) {
// Parse value and set components
this.apiKey = value;
String[] arrStr = value.split("\\.");
if (arrStr.length == 2) {
this.apiId = arrStr[0];
this.apiSecret = arrStr[1];
}
return value;
}
return apiKey;
}

/**
* Gets API key with system property and environment variable fallback.
*/
public String getApiId() {
if (apiId != null && !apiId.isEmpty()) {
return apiId;
}
getApiKey();
return apiId;
}

/**
* Gets API secret with system property and environment variable fallback.
*/
public String getApiSecret() {
if (apiSecret != null && !apiSecret.isEmpty()) {
return apiSecret;
}
getApiKey();
return apiSecret;
}

/**
* Gets expire millis with system property and environment variable fallback.
*/
Expand Down
17 changes: 14 additions & 3 deletions core/src/main/java/ai/z/openapi/core/token/TokenManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ public TokenManager(ICache cache) {
* @return valid JWT token
*/
public String getToken(ZaiConfig config) {
String tokenCacheKey = genTokenCacheKey(config.getApiId());
String[] arrStr = config.getApiKey().split("\\.");
if (arrStr.length != 2) {
throw new RuntimeException("invalid api Key");
}
String appId = arrStr[0];
String tokenCacheKey = genTokenCacheKey(appId);
String cacheToken = cache.get(tokenCacheKey);
if (StringUtils.isNotEmpty(cacheToken)) {
return cacheToken;
Expand All @@ -62,9 +67,15 @@ public String getToken(ZaiConfig config) {
private static String createJwt(ZaiConfig config) {
Algorithm alg;
String algId = config.getAlg();
String[] arrStr = config.getApiKey().split("\\.");
if (arrStr.length != 2) {
throw new RuntimeException("invalid api Key");
}
String appId = arrStr[0];
String apiSecret = arrStr[1];
if ("HS256".equals(algId)) {
try {
alg = Algorithm.HMAC256(config.getApiSecret().getBytes(StandardCharsets.UTF_8));
alg = Algorithm.HMAC256(apiSecret.getBytes(StandardCharsets.UTF_8));
}
catch (Exception e) {
logger.error("Failed to create HMAC256 algorithm", e);
Expand All @@ -79,7 +90,7 @@ private static String createJwt(ZaiConfig config) {

Map<String, Object> payload = new HashMap<>();
// here the api_key is the apiId
payload.put("api_key", config.getApiId());
payload.put("api_key", appId);
payload.put("exp", System.currentTimeMillis() + config.getExpireMillis() + DELAY_EXPIRE_TIME);
payload.put("timestamp", Calendar.getInstance().getTimeInMillis());
Map<String, Object> headerClaims = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ public static void main(String[] args) {
.build()
))
.stream(false)
.temperature(0.7f)
.maxTokens(1024)
.temperature(1.0f)
.build();

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ public static void main(String[] args) {
.stream(false)
.thinking(ChatThinking.builder().type(ChatThinkingType.ENABLED.value()).build())
.responseFormat(ResponseFormat.builder().type(ResponseFormatType.TEXT.value()).build())
.temperature(0.7f)
.maxTokens(1024)
.temperature(1.0f)
.build();

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ public static void main(String[] args) {
.build()
))
.stream(true) // Enable streaming for custom headers support
.temperature(0.7f)
.maxTokens(1024)
.build();

// Create custom headers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package ai.z.openapi.samples;

import ai.z.openapi.ZhipuAiClient;
import ai.z.openapi.service.model.ChatCompletionCreateParams;
import ai.z.openapi.service.model.ChatCompletionResponse;
import ai.z.openapi.service.model.ChatMessage;
import ai.z.openapi.service.model.ChatMessageRole;
import ai.z.openapi.service.model.ChatThinking;
import ai.z.openapi.service.model.ChatThinkingType;
import ai.z.openapi.service.model.ChatTool;
import ai.z.openapi.service.model.ChatToolType;
import ai.z.openapi.service.model.MCPTool;
import ai.z.openapi.service.model.ResponseFormat;
import ai.z.openapi.service.model.ResponseFormatType;

import java.util.Collections;

/**
* Chat Completion Example
* Demonstrates how to use ZaiClient for basic chat conversations
*/
public class ChatCompletionWithMcpServerUrlExample {

public static void main(String[] args) {
// Create client, recommended to set API Key via environment variable
// export ZAI_API_KEY=your.api_key
// for Z.ai use the `ZaiClient`, for Zhipu AI use the ZhipuAiClient
ZhipuAiClient client = ZhipuAiClient.builder().build();

// Or set API Key via code
// ZaiClient client = ZaiClient.builder()
// .apiKey("your.api_key")
// .build();

// Create chat request
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
.model("glm-4.6")
.messages(Collections.singletonList(
ChatMessage.builder()
.role(ChatMessageRole.USER.value())
.content("Hello, how to learn english?")
.build()
))
.stream(false)
.thinking(ChatThinking.builder().type(ChatThinkingType.ENABLED.value()).build())
.responseFormat(ResponseFormat.builder().type(ResponseFormatType.TEXT.value()).build())
.temperature(1.0f)
.maxTokens(1024)
.tools(Collections.singletonList(ChatTool.builder()
.type(ChatToolType.MCP.value())
.mcp(MCPTool.builder()
.server_url("https://open.bigmodel.cn/api/mcp-broker/proxy/sogou-baike/sse")
.server_label("sogou-baike")
.transport_type("sse")
.headers(Collections.singletonMap("Authorization", "Bearer " + System.getProperty("ZAI_API_KEY")))
.build())
.build()))
.build();

try {
// Execute request
ChatCompletionResponse response = client.chat().createChatCompletion(request);

if (response.isSuccess()) {
Object content = response.getData().getChoices().get(0).getMessage();
System.out.println("Response: " + content);
} else {
System.err.println("Error: " + response.getMsg());
}
} catch (Exception e) {
System.err.println("Exception occurred: " + e.getMessage());
e.printStackTrace();
}
}
}
108 changes: 108 additions & 0 deletions samples/src/main/ai.z.openapi.samples/CustomClientExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package ai.z.openapi.samples;

import ai.z.openapi.ZhipuAiClient;
import ai.z.openapi.core.Constants;
import ai.z.openapi.core.config.ZaiConfig;
import ai.z.openapi.service.model.ChatCompletionCreateParams;
import ai.z.openapi.service.model.ChatCompletionResponse;
import ai.z.openapi.service.model.ChatMessage;
import ai.z.openapi.service.model.ChatMessageRole;
import ai.z.openapi.service.model.ChatThinking;
import ai.z.openapi.service.model.ChatThinkingType;
import ai.z.openapi.service.model.Choice;
import ai.z.openapi.service.model.Delta;
import ai.z.openapi.service.model.ResponseFormat;
import ai.z.openapi.service.model.ResponseFormatType;

import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
* Chat Completion Example
* Demonstrates how to use ZaiClient for basic chat conversations
*/
public class CustomClientExample {

public static void main(String[] args) throws Exception {
// Create client, recommended to set API Key via environment variable
// export ZAI_API_KEY=your.api_key
// for Z.ai use the `ZaiClient`, for Zhipu AI use the ZhipuAiClient
ZaiConfig zaiConfig = ZaiConfig.builder()
.apiKey(System.getenv("ZAI_API_KEY"))
.baseUrl(Constants.ZHIPU_AI_BASE_URL)
.customHeaders(Collections.emptyMap())
.disableTokenCache(true)
.requestTimeOut(600)
.timeOutTimeUnit(TimeUnit.SECONDS)
.connectTimeout(60)
.connectionPoolKeepAliveDuration(10)
.connectionPoolTimeUnit(TimeUnit.SECONDS)
.connectionPoolMaxIdleConnections(20)
.build();

ZhipuAiClient client = new ZhipuAiClient(zaiConfig);

// Or set API Key via code
// ZaiClient client = ZaiClient.builder()
// .apiKey("your.api_key")
// .build();

// Create chat request
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
.model("glm-4.6")
.messages(Arrays.asList(
ChatMessage.builder()
.role(ChatMessageRole.USER.value())
.content("Hello, are you there")
.build()
))
.stream(true)
.thinking(ChatThinking.builder().type(ChatThinkingType.ENABLED.value()).build())
.responseFormat(ResponseFormat.builder().type(ResponseFormatType.TEXT.value()).build())
.temperature(1.0f)
.build();

// Create latch to wait for streaming completion
CountDownLatch latch = new CountDownLatch(1);

try {
// Execute request
ChatCompletionResponse response = client.chat().createChatCompletion(request);

if (response.isSuccess() && response.getFlowable() != null) {
System.out.println("Starting streaming response...");
response.getFlowable().subscribe(
data -> {
// Process each streaming response chunk
if (data.getChoices() != null && !data.getChoices().isEmpty()) {
// Get content of current chunk
Choice choice = data.getChoices().get(0);
System.out.print(choice + "\n");
}
},
error -> {
System.err.println("\nStream error: " + error.getMessage());
latch.countDown(); // Release latch on error
},
// Process streaming response completion event
() -> {
System.out.println("\nStreaming response completed");
latch.countDown(); // Release latch on completion
}
);

// Wait for streaming to complete (max 60 seconds)
latch.await(60, TimeUnit.SECONDS);
} else {
System.err.println("Error: " + response.getMsg());
}
} catch (Exception e) {
System.err.println("Exception occurred: " + e.getMessage());
e.printStackTrace();
} finally {
client.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static void main(String[] args) {

// Create chat request
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
.model(Constants.ModelChatGLM4_5)
.model("glm-4.6")
.messages(Arrays.asList(
ChatMessage.builder()
.role(ChatMessageRole.USER.value())
Expand All @@ -40,8 +40,6 @@ public static void main(String[] args) {
.stream(false)
.thinking(ChatThinking.builder().type(ChatThinkingType.ENABLED.value()).build())
.responseFormat(ResponseFormat.builder().type(ResponseFormatType.TEXT.value()).build())
.temperature(0.7f)
.maxTokens(1024)
.build();

try {
Expand Down