diff --git a/core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java b/core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java index b2f7d08..ac8856d 100644 --- a/core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java +++ b/core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java @@ -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 */ @@ -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. @@ -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. @@ -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]; } /** @@ -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]; } /** @@ -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. */ diff --git a/core/src/main/java/ai/z/openapi/core/token/TokenManager.java b/core/src/main/java/ai/z/openapi/core/token/TokenManager.java index 33a24f9..44e543a 100644 --- a/core/src/main/java/ai/z/openapi/core/token/TokenManager.java +++ b/core/src/main/java/ai/z/openapi/core/token/TokenManager.java @@ -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; @@ -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); @@ -79,7 +90,7 @@ private static String createJwt(ZaiConfig config) { Map 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 headerClaims = new HashMap<>(); diff --git a/samples/src/main/ai.z.openapi.samples/ChatAsyncCompletionExample.java b/samples/src/main/ai.z.openapi.samples/ChatAsyncCompletionExample.java index 2af9aef..e56eae9 100644 --- a/samples/src/main/ai.z.openapi.samples/ChatAsyncCompletionExample.java +++ b/samples/src/main/ai.z.openapi.samples/ChatAsyncCompletionExample.java @@ -38,8 +38,7 @@ public static void main(String[] args) { .build() )) .stream(false) - .temperature(0.7f) - .maxTokens(1024) + .temperature(1.0f) .build(); try { diff --git a/samples/src/main/ai.z.openapi.samples/ChatCompletionExample.java b/samples/src/main/ai.z.openapi.samples/ChatCompletionExample.java index 423c93f..cf6b796 100644 --- a/samples/src/main/ai.z.openapi.samples/ChatCompletionExample.java +++ b/samples/src/main/ai.z.openapi.samples/ChatCompletionExample.java @@ -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 { diff --git a/samples/src/main/ai.z.openapi.samples/ChatCompletionWithCustomHeadersExample.java b/samples/src/main/ai.z.openapi.samples/ChatCompletionWithCustomHeadersExample.java index ff51652..ec337a3 100644 --- a/samples/src/main/ai.z.openapi.samples/ChatCompletionWithCustomHeadersExample.java +++ b/samples/src/main/ai.z.openapi.samples/ChatCompletionWithCustomHeadersExample.java @@ -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 diff --git a/samples/src/main/ai.z.openapi.samples/ChatCompletionWithMcpServerUrlExample.java b/samples/src/main/ai.z.openapi.samples/ChatCompletionWithMcpServerUrlExample.java new file mode 100644 index 0000000..b9a2a1a --- /dev/null +++ b/samples/src/main/ai.z.openapi.samples/ChatCompletionWithMcpServerUrlExample.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/samples/src/main/ai.z.openapi.samples/CustomClientExample.java b/samples/src/main/ai.z.openapi.samples/CustomClientExample.java new file mode 100644 index 0000000..14d9101 --- /dev/null +++ b/samples/src/main/ai.z.openapi.samples/CustomClientExample.java @@ -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(); + } + } +} \ No newline at end of file diff --git a/samples/src/main/ai.z.openapi.samples/CustomTimeoutExample.java b/samples/src/main/ai.z.openapi.samples/CustomTimeoutExample.java index 7bee654..5bdfdda 100644 --- a/samples/src/main/ai.z.openapi.samples/CustomTimeoutExample.java +++ b/samples/src/main/ai.z.openapi.samples/CustomTimeoutExample.java @@ -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()) @@ -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 {