init: initial the repo (#1)
* init project * init project * init project * init project * init project * init project * update action * update action * update action * update action * java format * java format * update code and format * update code and format * update code and format * update code and format * update code and format * update code and format * update version * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish * fix publish
This commit is contained in:
parent
94af104305
commit
0b09e46478
366 changed files with 24828 additions and 23 deletions
32
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: 🐞 Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
type: "Bug"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for stopping by to let us know something could be better!
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us what you expected to happen and how to reproduce the issue.
|
||||
placeholder: Tell us what you see!
|
||||
value: "A bug happened!"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/THUDM/z-ai-sdk-java/blob/main/CODE_OF_CONDUCT.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct
|
||||
required: true
|
||||
40
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
40
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
name: 💡 Feature Request
|
||||
description: Suggest an idea for this repository
|
||||
title: "[Feat]: "
|
||||
type: "Feature"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for stopping by to let us know something could be better!
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is.
|
||||
placeholder: Ex. I'm always frustrated when [...]
|
||||
- type: textarea
|
||||
id: describe
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/THUDM/z-ai-sdk-java/blob/main/CODE_OF_CONDUCT.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct
|
||||
required: true
|
||||
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Description
|
||||
|
||||
Thank you for opening a Pull Request!
|
||||
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
|
||||
|
||||
- [ ] Follow the [`CONTRIBUTING` Guide](https://github.com/THUDM/z-ai-sdk-java/blob/main/CONTRIBUTING.md).
|
||||
- [ ] Make your Pull Request title in the <https://www.conventionalcommits.org/> specification.
|
||||
- [ ] Ensure the tests pass (Run `mvn clean test` from the repository root)
|
||||
- [ ] Appropriate docs were updated (if necessary)
|
||||
|
||||
Fixes #<issue_number_goes_here>
|
||||
27
.github/workflows/build.yml
vendored
Normal file
27
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
name: Build and Test
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
push:
|
||||
branches:
|
||||
- 'action*'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
|
||||
- name: Validate Java Format
|
||||
run: mvn spring-javaformat:validate
|
||||
|
||||
- name: Build with Maven
|
||||
run: mvn -B package
|
||||
27
.github/workflows/lint-pr.yaml
vendored
Normal file
27
.github/workflows/lint-pr.yaml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
name: "Lint PR"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
lint-pr:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
subjectPattern: ^[a-zA-Z0-9!-_@#=*`.|+,\s]+$
|
||||
# If `subjectPattern` is configured, you can use this property to override
|
||||
# the default error message that is shown when the pattern doesn't match.
|
||||
# The variables `subject` and `title` can be used within the message.
|
||||
subjectPatternError: |
|
||||
The subject "{subject}" found in the pr title "{title}" didn't match the
|
||||
configured pattern. Can only chars, numbers and symbols !-_@#=*`|+.
|
||||
32
.github/workflows/release.yml
vendored
Normal file
32
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Publish package to the Maven Central Repository
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre-build:
|
||||
uses:
|
||||
./.github/workflows/build.yml
|
||||
publish-release:
|
||||
needs:
|
||||
- pre-build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Maven Central Repository
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
server-id: ossrh
|
||||
server-username: MAVEN_USERNAME
|
||||
server-password: MAVEN_PASSWORD
|
||||
gpg-passphrase: MAVEN_GPG_PASSPHRASE
|
||||
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
- name: Publish package to Maven Central
|
||||
run: mvn --batch-mode clean deploy -P release
|
||||
env:
|
||||
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
|
||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
59
.gitignore
vendored
59
.gitignore
vendored
|
|
@ -1,24 +1,45 @@
|
|||
# Compiled class file
|
||||
*.class
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**
|
||||
!**/src/test/**
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
### mvn release:prepare temp files
|
||||
/*/release.properties
|
||||
/*/pom.xml.releaseBackup
|
||||
/*/pom.xml.versionsBackup
|
||||
/release.properties
|
||||
/pom.xml.releaseBackup
|
||||
/pom.xml.versionsBackup
|
||||
.flattened-pom.xml
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
logs/data.log
|
||||
logs/error.log
|
||||
logs/
|
||||
app.pid
|
||||
/data/
|
||||
|
|
|
|||
1
.springjavaformatconfig
Normal file
1
.springjavaformatconfig
Normal file
|
|
@ -0,0 +1 @@
|
|||
java-baseline=8
|
||||
828
ARCHITECTURE.md
Normal file
828
ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,828 @@
|
|||
# Z.ai SDK Java - Architecture Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The Z.ai SDK Java provides a service-oriented architecture that offers clean separation of concerns, comprehensive configuration management, and support for both synchronous and streaming operations. The SDK is built around a client-service pattern with reactive programming support.
|
||||
|
||||
## Architecture Components
|
||||
|
||||
### 1. Core Client Architecture
|
||||
|
||||
#### ZaiClient
|
||||
The main client class that serves as the entry point for all AI services:
|
||||
|
||||
```java
|
||||
public class ZaiClient extends AbstractClientBaseService {
|
||||
// Service instances
|
||||
private ChatService chatService;
|
||||
private AgentService agentService;
|
||||
private EmbeddingService embeddingService;
|
||||
// ... other services
|
||||
|
||||
// Constructor
|
||||
public ZaiClient(ZaiConfig config) {
|
||||
// Initialize HTTP client and Retrofit
|
||||
}
|
||||
|
||||
// Service accessors
|
||||
public synchronized ChatService chat() { /* ... */ }
|
||||
public synchronized AgentService agents() { /* ... */ }
|
||||
// ... other service accessors
|
||||
}
|
||||
```
|
||||
|
||||
#### Base Request and Response Models
|
||||
|
||||
**ClientRequest Interface**: Base interface for all service requests
|
||||
```java
|
||||
public interface ClientRequest<T> {
|
||||
// Marker interface for type safety
|
||||
}
|
||||
```
|
||||
|
||||
**ClientResponse Interface**: Base interface for all service responses
|
||||
```java
|
||||
public interface ClientResponse<T> {
|
||||
T getData();
|
||||
void setData(T data);
|
||||
void setCode(int code);
|
||||
void setMsg(String msg);
|
||||
void setSuccess(boolean success);
|
||||
void setError(ChatError error);
|
||||
}
|
||||
```
|
||||
|
||||
**FlowableClientResponse Interface**: Extended interface for streaming responses
|
||||
```java
|
||||
public interface FlowableClientResponse<T> extends ClientResponse<T> {
|
||||
void setFlowable(Flowable<T> stream);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Configuration Management
|
||||
|
||||
#### ZaiConfig
|
||||
Main configuration class that contains all SDK settings:
|
||||
|
||||
```java
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ZaiConfig {
|
||||
private String baseUrl;
|
||||
private String apiSecretKey;
|
||||
private String apiKey;
|
||||
private String apiSecret;
|
||||
private int expireMillis = 30 * 60 * 1000; // 30 minutes
|
||||
private String alg = "HS256";
|
||||
private boolean disableTokenCache;
|
||||
|
||||
// Connection pool settings
|
||||
private int connectionPoolMaxIdleConnections = 5;
|
||||
private long connectionPoolKeepAliveDuration = 1;
|
||||
private TimeUnit connectionPoolTimeUnit = TimeUnit.SECONDS;
|
||||
|
||||
// Timeout settings
|
||||
private int requestTimeOut;
|
||||
private int connectTimeout;
|
||||
private int readTimeout;
|
||||
private int writeTimeout;
|
||||
private TimeUnit timeOutTimeUnit;
|
||||
|
||||
private String source_channel;
|
||||
}
|
||||
```
|
||||
|
||||
#### Configuration Features
|
||||
|
||||
1. **Authentication Settings**
|
||||
- API secret key in format `{apiKey}.{apiSecret}`
|
||||
- JWT token expiration and algorithm configuration
|
||||
- Token caching control
|
||||
|
||||
2. **Network Configuration**
|
||||
- Base URL for API endpoints
|
||||
- Connection pool settings (max idle connections, keep-alive duration)
|
||||
- Timeout configurations (request, connect, read, write)
|
||||
|
||||
3. **Token Management**
|
||||
- JWT token generation and caching
|
||||
- Configurable expiration times
|
||||
- Option to disable token caching for direct API key usage
|
||||
|
||||
### 3. Service Implementations
|
||||
|
||||
#### ChatService
|
||||
Provides chat completion functionality with support for synchronous, asynchronous, and streaming operations:
|
||||
|
||||
```java
|
||||
public interface ChatService {
|
||||
/**
|
||||
* Creates a chat completion, either streaming or non-streaming based on the request configuration.
|
||||
*/
|
||||
ChatCompletionResponse createChatCompletion(ChatCompletionCreateParams request);
|
||||
|
||||
/**
|
||||
* Creates an asynchronous chat completion.
|
||||
*/
|
||||
ChatCompletionResponse asyncChatCompletion(ChatCompletionCreateParams request);
|
||||
|
||||
/**
|
||||
* Retrieves the result of an asynchronous model operation.
|
||||
*/
|
||||
QueryModelResultResponse retrieveAsyncResult(AsyncResultRetrieveParams request);
|
||||
}
|
||||
```
|
||||
|
||||
#### Service Implementation Pattern
|
||||
All services follow a consistent implementation pattern:
|
||||
|
||||
```java
|
||||
public class ChatServiceImpl implements ChatService {
|
||||
private final ZaiClient zAiClient;
|
||||
private final ChatApi chatApi;
|
||||
|
||||
public ChatServiceImpl(ZaiClient zAiClient) {
|
||||
this.zAiClient = zAiClient;
|
||||
this.chatApi = this.zAiClient.retrofit().create(ChatApi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatCompletionResponse createChatCompletion(ChatCompletionCreateParams request) {
|
||||
// Parameter validation
|
||||
String paramMsg = validateParams(request);
|
||||
if (StringUtils.isNotEmpty(paramMsg)) {
|
||||
return new ChatCompletionResponse(-100, String.format("invalid param: %s", paramMsg));
|
||||
}
|
||||
|
||||
// Route to streaming or synchronous execution
|
||||
if (request.getStream()) {
|
||||
return streamChatCompletion(request);
|
||||
} else {
|
||||
return syncChatCompletion(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```java
|
||||
// Simple configuration with API secret key
|
||||
ZaiConfig config = new ZaiConfig("your.api.key.your.api.secret");
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
|
||||
// Or using separate API key and secret
|
||||
ZaiConfig config = new ZaiConfig("your.api.key", "your.api.secret");
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
```
|
||||
|
||||
### Builder Pattern Configuration
|
||||
|
||||
```java
|
||||
// Using the Builder pattern for advanced configuration
|
||||
ZaiClient client = new ZaiClient.Builder("your.api.key.your.api.secret")
|
||||
.enableTokenCache()
|
||||
.networkConfig(
|
||||
300, // request timeout
|
||||
100, // connect timeout
|
||||
100, // read timeout
|
||||
100, // write timeout
|
||||
TimeUnit.SECONDS
|
||||
)
|
||||
.connectionPool(
|
||||
10, // max idle connections
|
||||
5, // keep alive duration
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
.tokenExpire(3600000) // 1 hour in milliseconds
|
||||
.build();
|
||||
```
|
||||
|
||||
### Custom Configuration with ZaiConfig
|
||||
|
||||
```java
|
||||
ZaiConfig config = ZaiConfig.builder()
|
||||
.apiSecretKey("your.api.key.your.api.secret")
|
||||
.baseUrl("https://custom.api.endpoint")
|
||||
.requestTimeOut(60)
|
||||
.connectTimeout(30)
|
||||
.readTimeout(30)
|
||||
.writeTimeout(30)
|
||||
.timeOutTimeUnit(TimeUnit.SECONDS)
|
||||
.disableTokenCache(false)
|
||||
.expireMillis(7200000) // 2 hours
|
||||
.connectionPoolMaxIdleConnections(10)
|
||||
.connectionPoolKeepAliveDuration(5)
|
||||
.connectionPoolTimeUnit(TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
```
|
||||
|
||||
### Service Usage
|
||||
|
||||
```java
|
||||
// Get service instance
|
||||
ChatService chatService = client.chat();
|
||||
|
||||
// Create chat request
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model("glm-4")
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessage.Role.USER)
|
||||
.content("Hello, world!")
|
||||
.build()
|
||||
))
|
||||
.stream(false) // Set to true for streaming
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1024)
|
||||
.build();
|
||||
|
||||
// Execute request
|
||||
try {
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
ModelData data = response.getData();
|
||||
if (data != null && data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getMessage().getContent();
|
||||
System.out.println("Response: " + content);
|
||||
}
|
||||
} else {
|
||||
System.err.println("Error: " + response.getMsg());
|
||||
if (response.getError() != null) {
|
||||
System.err.println("Error details: " + response.getError().getMessage());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Request failed: " + e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
### Streaming Usage
|
||||
|
||||
```java
|
||||
// Create streaming request
|
||||
ChatCompletionCreateParams streamRequest = ChatCompletionCreateParams.builder()
|
||||
.model("glm-4")
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessage.Role.USER)
|
||||
.content("Tell me a story")
|
||||
.build()
|
||||
))
|
||||
.stream(true) // Enable streaming
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1024)
|
||||
.build();
|
||||
|
||||
// Execute streaming request
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(streamRequest);
|
||||
|
||||
if (response.isSuccess() && response.getFlowable() != null) {
|
||||
response.getFlowable().subscribe(
|
||||
data -> {
|
||||
// Handle streaming chunk
|
||||
if (data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getDelta().getContent();
|
||||
if (content != null) {
|
||||
System.out.print(content);
|
||||
}
|
||||
}
|
||||
},
|
||||
error -> System.err.println("\nStream error: " + error.getMessage()),
|
||||
() -> System.out.println("\nStream completed")
|
||||
);
|
||||
} else {
|
||||
System.err.println("Failed to start streaming: " + response.getMsg());
|
||||
}
|
||||
```
|
||||
|
||||
### Asynchronous Usage
|
||||
|
||||
```java
|
||||
// Create async request
|
||||
ChatCompletionCreateParams asyncRequest = ChatCompletionCreateParams.builder()
|
||||
.model("glm-4")
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessage.Role.USER)
|
||||
.content("Generate a long document")
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
// Execute async request
|
||||
ChatCompletionResponse asyncResponse = chatService.asyncChatCompletion(asyncRequest);
|
||||
|
||||
if (asyncResponse.isSuccess()) {
|
||||
String taskId = asyncResponse.getData().getTaskId();
|
||||
System.out.println("Async task started with ID: " + taskId);
|
||||
|
||||
// Poll for results
|
||||
AsyncResultRetrieveParams retrieveParams = new AsyncResultRetrieveParams();
|
||||
retrieveParams.setId(taskId);
|
||||
|
||||
QueryModelResultResponse result = chatService.retrieveAsyncResult(retrieveParams);
|
||||
// Handle result...
|
||||
}
|
||||
```
|
||||
|
||||
## Available Services
|
||||
|
||||
The ZaiClient provides access to multiple AI services:
|
||||
|
||||
```java
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
|
||||
// Chat completion service
|
||||
ChatService chatService = client.chat();
|
||||
|
||||
// Agent service for agent-based completions
|
||||
AgentService agentService = client.agents();
|
||||
|
||||
// Embedding service for text embeddings
|
||||
EmbeddingService embeddingService = client.embeddings();
|
||||
|
||||
// File management service
|
||||
FileService fileService = client.files();
|
||||
|
||||
// Audio processing service
|
||||
AudioService audioService = client.audio();
|
||||
|
||||
// Image generation service
|
||||
ImageService imageService = client.images();
|
||||
|
||||
// Batch processing service
|
||||
BatchService batchService = client.batches();
|
||||
|
||||
// Fine-tuning service
|
||||
FineTuningService fineTuningService = client.fineTuning();
|
||||
|
||||
// Web search service
|
||||
WebSearchService webSearchService = client.webSearch();
|
||||
|
||||
// Video processing service
|
||||
VideosService videosService = client.videos();
|
||||
|
||||
// Knowledge base service
|
||||
KnowledgeService knowledgeService = client.knowledge();
|
||||
|
||||
// Document management service
|
||||
DocumentService documentService = client.documents();
|
||||
|
||||
// Assistant service
|
||||
AssistantService assistantService = client.assistants();
|
||||
```
|
||||
|
||||
## Request and Response Models
|
||||
|
||||
### Common Request Structure
|
||||
All requests extend `CommonRequest` which provides common fields:
|
||||
|
||||
```java
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonRequest {
|
||||
@JsonProperty("request_id")
|
||||
private String requestId;
|
||||
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
// Additional common fields...
|
||||
}
|
||||
```
|
||||
|
||||
### Chat Request Example
|
||||
```java
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatCompletionCreateParams extends CommonRequest implements ClientRequest<ChatCompletionCreateParams> {
|
||||
private String model;
|
||||
private List<ChatMessage> messages;
|
||||
private Boolean stream;
|
||||
private Float temperature;
|
||||
@JsonProperty("max_tokens")
|
||||
private Integer maxTokens;
|
||||
private List<String> stop;
|
||||
private List<ChatTool> tools;
|
||||
// ... other fields
|
||||
}
|
||||
```
|
||||
|
||||
### Response Structure
|
||||
All responses implement `ClientResponse` or `FlowableClientResponse`:
|
||||
|
||||
```java
|
||||
@Data
|
||||
public class ChatCompletionResponse implements FlowableClientResponse<ModelData> {
|
||||
private int code;
|
||||
private String msg;
|
||||
private boolean success;
|
||||
private ModelData data;
|
||||
private Flowable<ModelData> flowable; // For streaming responses
|
||||
private ChatError error;
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Response Error Handling
|
||||
|
||||
```java
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(request);
|
||||
|
||||
// Check if the request was successful
|
||||
if (!response.isSuccess()) {
|
||||
int errorCode = response.getCode();
|
||||
String errorMessage = response.getMsg();
|
||||
|
||||
System.err.println("Request failed with code: " + errorCode);
|
||||
System.err.println("Error message: " + errorMessage);
|
||||
|
||||
// Check for detailed error information
|
||||
if (response.getError() != null) {
|
||||
ChatError error = response.getError();
|
||||
System.err.println("Error code: " + error.getCode());
|
||||
System.err.println("Error details: " + error.getMessage());
|
||||
|
||||
// Handle specific error types
|
||||
switch (errorCode) {
|
||||
case 400:
|
||||
System.err.println("Bad request - check your parameters");
|
||||
break;
|
||||
case 401:
|
||||
System.err.println("Authentication failed - check your API key");
|
||||
break;
|
||||
case 429:
|
||||
System.err.println("Rate limit exceeded - please retry later");
|
||||
break;
|
||||
case 500:
|
||||
System.err.println("Server error - please try again");
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unexpected error occurred");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Process successful response
|
||||
ModelData data = response.getData();
|
||||
if (data != null) {
|
||||
// Handle successful response data
|
||||
System.out.println("Request completed successfully");
|
||||
}
|
||||
```
|
||||
|
||||
### Exception Handling
|
||||
|
||||
```java
|
||||
try {
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(request);
|
||||
// Process response...
|
||||
} catch (ZAiHttpException e) {
|
||||
// Handle HTTP-specific errors
|
||||
System.err.println("HTTP Error: " + e.getMessage());
|
||||
System.err.println("Status Code: " + e.statusCode);
|
||||
System.err.println("Error Code: " + e.code);
|
||||
} catch (Exception e) {
|
||||
// Handle other exceptions
|
||||
System.err.println("Unexpected error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
```
|
||||
|
||||
## Extension Points
|
||||
|
||||
### Custom Service Implementation
|
||||
|
||||
```java
|
||||
public class CustomService implements AIService<CustomRequest, CustomResponse> {
|
||||
@Override
|
||||
public CustomResponse execute(CustomRequest request) throws Exception {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CustomResponse> executeAsync(CustomRequest request) {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flowable<CustomResponse> executeStream(CustomRequest request) throws Exception {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateRequest(CustomRequest request) throws IllegalArgumentException {
|
||||
// Validation logic
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceType() {
|
||||
return "CUSTOM_SERVICE";
|
||||
}
|
||||
}
|
||||
|
||||
// Register custom service
|
||||
client.registerService("CUSTOM_SERVICE", new CustomService());
|
||||
```
|
||||
|
||||
### Custom Configuration
|
||||
|
||||
```java
|
||||
// Extend configuration for custom needs
|
||||
ZaiConfiguration customConfig = ZaiConfigurationBuilder.newBuilder()
|
||||
.apiSecretKey("your.api.key")
|
||||
.baseUrl("https://custom.endpoint")
|
||||
// Add custom settings
|
||||
.build();
|
||||
|
||||
// Add custom metadata to configuration
|
||||
customConfig.getAuth().addMetadata("customAuth", "value");
|
||||
customConfig.getNetwork().addMetadata("customNetwork", "value");
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Configuration Management
|
||||
|
||||
```java
|
||||
// Use builder pattern for configuration
|
||||
ZaiConfig config = ZaiConfig.builder()
|
||||
.apiSecretKey("your.api.key.your.api.secret")
|
||||
.baseUrl("https://open.bigmodel.cn/")
|
||||
.requestTimeOut(60)
|
||||
.connectTimeout(30)
|
||||
.readTimeout(30)
|
||||
.writeTimeout(30)
|
||||
.timeOutTimeUnit(TimeUnit.SECONDS)
|
||||
.disableTokenCache(false)
|
||||
.expireMillis(3600000) // 1 hour
|
||||
.connectionPoolMaxIdleConnections(10)
|
||||
.connectionPoolKeepAliveDuration(5)
|
||||
.connectionPoolTimeUnit(TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
```
|
||||
|
||||
### Request Building
|
||||
|
||||
```java
|
||||
// Use builder pattern for creating requests
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model("glm-4")
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessage.Role.USER)
|
||||
.content("Hello, world!")
|
||||
.build()
|
||||
))
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1000)
|
||||
.stream(false)
|
||||
.build();
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```java
|
||||
// Comprehensive error handling
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(request);
|
||||
|
||||
if (!response.isSuccess()) {
|
||||
System.err.println("Request failed: " + response.getMsg());
|
||||
if (response.getError() != null) {
|
||||
System.err.println("Error details: " + response.getError().getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Process successful response
|
||||
ModelData data = response.getData();
|
||||
if (data != null && data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getMessage().getContent();
|
||||
System.out.println("Response: " + content);
|
||||
}
|
||||
```
|
||||
|
||||
### Streaming Best Practices
|
||||
|
||||
```java
|
||||
// Handle streaming responses properly
|
||||
ChatCompletionCreateParams streamRequest = request.toBuilder()
|
||||
.stream(true)
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(streamRequest);
|
||||
|
||||
if (response.isSuccess() && response.getFlowable() != null) {
|
||||
response.getFlowable()
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(
|
||||
data -> {
|
||||
// Process each streaming chunk
|
||||
if (data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getDelta().getContent();
|
||||
if (content != null) {
|
||||
System.out.print(content);
|
||||
}
|
||||
}
|
||||
},
|
||||
error -> {
|
||||
System.err.println("Streaming error: " + error.getMessage());
|
||||
},
|
||||
() -> {
|
||||
System.out.println("\nStreaming completed");
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Resource Management
|
||||
|
||||
```java
|
||||
// Properly manage client lifecycle
|
||||
try {
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
ChatService chatService = client.chat();
|
||||
|
||||
// Use the service...
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(request);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
} finally {
|
||||
// Clean up resources if needed
|
||||
}
|
||||
```
|
||||
|
||||
### Asynchronous Processing
|
||||
|
||||
```java
|
||||
// Use async operations for long-running tasks
|
||||
ChatCompletionResponse asyncResponse = chatService.asyncChatCompletion(request);
|
||||
|
||||
if (asyncResponse.isSuccess()) {
|
||||
String taskId = asyncResponse.getData().getTaskId();
|
||||
|
||||
// Poll for results
|
||||
AsyncResultRetrieveParams retrieveParams = new AsyncResultRetrieveParams();
|
||||
retrieveParams.setId(taskId);
|
||||
|
||||
// Implement polling logic with backoff
|
||||
CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
Thread.sleep(1000); // Wait before polling
|
||||
return chatService.retrieveAsyncResult(retrieveParams);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).thenAccept(result -> {
|
||||
// Handle result
|
||||
if (result.isSuccess()) {
|
||||
System.out.println("Async task completed");
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
1. **API Key Management**: Store API keys securely, never hardcode them
|
||||
2. **Token Caching**: Enable token caching to reduce authentication overhead
|
||||
3. **Request Validation**: Always validate input parameters
|
||||
4. **Error Logging**: Log errors but never log sensitive information
|
||||
5. **Timeout Configuration**: Set appropriate timeouts to prevent hanging requests
|
||||
6. **Connection Pooling**: Configure connection pools for optimal performance
|
||||
7. **Rate Limiting**: Implement client-side rate limiting to respect API limits
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Upgrading to Latest Version
|
||||
|
||||
This guide helps you migrate from older versions of the Z-AI SDK to the current architecture.
|
||||
|
||||
#### Key Changes in Current Version
|
||||
|
||||
1. **Unified Client Architecture**: All services are now accessed through `ZaiClient`
|
||||
2. **Improved Configuration**: `ZaiConfig` with builder pattern for better flexibility
|
||||
3. **Standardized Request/Response**: All requests implement `ClientRequest`, responses implement `ClientResponse`
|
||||
4. **Enhanced Streaming**: Better support for streaming responses with `FlowableClientResponse`
|
||||
5. **Comprehensive Service Coverage**: Support for Chat, Agents, Embeddings, Files, Audio, Images, and more
|
||||
|
||||
#### Configuration Migration
|
||||
|
||||
```java
|
||||
// If you were using basic configuration
|
||||
// Old approach (if applicable)
|
||||
String apiKey = "your-api-key";
|
||||
String apiSecret = "your-api-secret";
|
||||
|
||||
// New approach
|
||||
ZaiConfig config = ZaiConfig.builder()
|
||||
.apiKey(apiKey)
|
||||
.apiSecret(apiSecret)
|
||||
.baseUrl("https://open.bigmodel.cn/")
|
||||
.enableTokenCache(true)
|
||||
.tokenExpiredSeconds(3600)
|
||||
.build();
|
||||
|
||||
ZaiClient client = new ZaiClient(config);
|
||||
```
|
||||
|
||||
#### Service Usage Migration
|
||||
|
||||
```java
|
||||
// Modern service usage
|
||||
ChatService chatService = client.chat();
|
||||
EmbeddingService embeddingService = client.embeddings();
|
||||
FileService fileService = client.files();
|
||||
AudioService audioService = client.audio();
|
||||
ImageService imageService = client.images();
|
||||
// ... and more services
|
||||
```
|
||||
|
||||
#### Request Building Migration
|
||||
|
||||
```java
|
||||
// Use builder pattern for all requests
|
||||
ChatCompletionCreateParams chatRequest = ChatCompletionCreateParams.builder()
|
||||
.model("glm-4")
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessage.Role.USER)
|
||||
.content("Hello, world!")
|
||||
.build()
|
||||
))
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1000)
|
||||
.build();
|
||||
```
|
||||
|
||||
#### Response Handling Migration
|
||||
|
||||
```java
|
||||
// Standardized response handling
|
||||
ChatCompletionResponse response = chatService.createChatCompletion(chatRequest);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
ModelData data = response.getData();
|
||||
// Process successful response
|
||||
} else {
|
||||
System.err.println("Error: " + response.getMsg());
|
||||
if (response.getError() != null) {
|
||||
System.err.println("Details: " + response.getError().getMessage());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Streaming Migration
|
||||
|
||||
```java
|
||||
// Enhanced streaming support
|
||||
ChatCompletionCreateParams streamRequest = chatRequest.toBuilder()
|
||||
.stream(true)
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse streamResponse = chatService.createChatCompletion(streamRequest);
|
||||
|
||||
if (streamResponse.isSuccess() && streamResponse.getFlowable() != null) {
|
||||
streamResponse.getFlowable()
|
||||
.subscribe(
|
||||
data -> {
|
||||
// Process streaming data
|
||||
},
|
||||
error -> {
|
||||
// Handle streaming errors
|
||||
},
|
||||
() -> {
|
||||
// Streaming completed
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Best Practices for Migration
|
||||
|
||||
1. **Update Dependencies**: Ensure you're using the latest version of the SDK
|
||||
2. **Review Configuration**: Update your configuration to use `ZaiConfig.builder()`
|
||||
3. **Update Service Access**: Use `ZaiClient` to access all services
|
||||
4. **Standardize Error Handling**: Use the new response structure for error handling
|
||||
5. **Test Thoroughly**: Test all functionality after migration
|
||||
6. **Update Documentation**: Update your internal documentation to reflect the new patterns
|
||||
|
||||
This architecture provides a solid foundation for future enhancements while maintaining backward compatibility where possible.
|
||||
91
CODE_OF_CONDUCT.md
Normal file
91
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of
|
||||
experience, education, socio-economic status, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
||||
contributor for other behaviors that they deem inappropriate, threatening,
|
||||
offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
This Code of Conduct also applies outside the project spaces when the Project
|
||||
Steward has a reasonable belief that an individual's behavior may have a
|
||||
negative impact on the project or its community.
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
We do not believe that all conflict is bad; healthy debate and disagreement
|
||||
often yield positive results. However, it is never okay to be disrespectful or
|
||||
to engage in behavior that violates the project’s code of conduct.
|
||||
|
||||
If you see someone violating the code of conduct, you are encouraged to address
|
||||
the behavior directly with those involved. Many issues can be resolved quickly
|
||||
and easily, and this gives people more control over the outcome of their
|
||||
dispute. If you are unable to resolve the matter for any reason, or if the
|
||||
behavior is threatening or harassing, report it. We are dedicated to providing
|
||||
an environment where participants feel welcome and safe.
|
||||
|
||||
Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the
|
||||
Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to
|
||||
receive and address reported violations of the code of conduct. They will then
|
||||
work with a committee consisting of representatives from the Open Source
|
||||
Programs Office and the Z.ai Open Source Strategy team.
|
||||
|
||||
We will investigate every complaint, but you may not receive a direct response.
|
||||
We will use our discretion in determining when and how to follow up on reported
|
||||
incidents, which may range from not taking action to permanent expulsion from
|
||||
the project and project-sponsored spaces. We will notify the accused of the
|
||||
report and provide them an opportunity to discuss it before any action is taken.
|
||||
The identity of the reporter will be omitted from the details of the report
|
||||
supplied to the accused. In potentially harmful situations, such as ongoing
|
||||
harassment or threats to anyone's safety, we may take action without notice.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
||||
available at
|
||||
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
54
CONTRIBUTING.md
Normal file
54
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# How to contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project.
|
||||
|
||||
## Contribution process
|
||||
|
||||
### Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
|
||||
### Contributor Guide
|
||||
|
||||
You may follow these steps to contribute:
|
||||
|
||||
1. **Fork the official repository.** This will create a copy of the official repository in your own account.
|
||||
2. **Sync the branches.** This will ensure that your copy of the repository is up-to-date with the latest changes from the official repository.
|
||||
3. **Work on your forked repository's feature branch.** This is where you will make your changes to the code.
|
||||
4. **Commit your updates on your forked repository's feature branch.** This will save your changes to your copy of the repository.
|
||||
5. **Submit a pull request to the official repository's main branch.** This will request that your changes be merged into the official repository.
|
||||
6. **Resolve any linting errors.** This will ensure that your changes are formatted correctly.
|
||||
|
||||
Here are some additional things to keep in mind during the process:
|
||||
|
||||
- **Test your changes.** Before you submit a pull request, make sure that your changes work as expected.
|
||||
- **Be patient.** It may take some time for your pull request to be reviewed and merged.
|
||||
|
||||
|
||||
### Environment Setup
|
||||
For running unit tests, set up your environment variables with your API credentials:
|
||||
|
||||
```bash
|
||||
export ZAI_BASE_URL=https://api.z.ai/api/paas/v4/ # Default ZAI API endpoint
|
||||
export ZAI_API_KEY=your_api_key_here # Replace with your actual API key
|
||||
```
|
||||
|
||||
> ⚠️ **Note**: Running tests will consume a small amount of tokens from your API account.
|
||||
|
||||
### Dependencies
|
||||
|
||||
This SDK uses the following core dependencies:
|
||||
|
||||
| Library | Version |
|
||||
|---------|----------|
|
||||
| OkHttp | 3.14.9 |
|
||||
| Java JWT | 4.2.2 |
|
||||
| Jackson | 2.11.3 |
|
||||
| Retrofit2 | 2.9.0 |
|
||||
|
||||
|
||||
Have Fun!
|
||||
---
|
||||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Z.ai & THUKEG
|
||||
Copyright (c) Z.ai, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
370
README.md
370
README.md
|
|
@ -1,2 +1,368 @@
|
|||
# z-ai-sdk-java
|
||||
Java SDK for z.ai
|
||||
# Z.ai Open Platform Java SDK
|
||||
|
||||
[](https://search.maven.org/artifact/ai.z/z-ai-sdk)
|
||||
[](LICENSE)
|
||||
[](https://www.oracle.com/java/)
|
||||
|
||||
[中文文档](README_CN.md) | English
|
||||
|
||||
**Not yet released.**
|
||||
|
||||
The official Java SDK for Z.ai and ZHIPU AI platforms, providing a unified interface to access powerful AI capabilities including chat completion, embeddings, image generation, audio processing, and more.
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🚀 **Type-safe API**: All interfaces are fully type-encapsulated, no need to consult API documentation
|
||||
- 🔧 **Easy Integration**: Simple and intuitive API design for quick integration
|
||||
- ⚡ **High Performance**: Built with modern Java libraries for optimal performance
|
||||
- 🛡️ **Secure**: Built-in authentication and token management
|
||||
- 📦 **Lightweight**: Minimal dependencies for easy project integration
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
### Requirements
|
||||
- Java 1.8 or higher
|
||||
- Maven or Gradle
|
||||
- Not supported on Android platform
|
||||
|
||||
### Maven
|
||||
Add the following dependency to your `pom.xml`:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>ai.z</groupId>
|
||||
<artifactId>z-ai-sdk</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
Add the following dependency to your `build.gradle` (for Groovy DSL):
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation 'ai.z:z-ai-sdk:0.0.1'
|
||||
}
|
||||
```
|
||||
|
||||
Or `build.gradle.kts` (for Kotlin DSL):
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("ai.z:z-ai-sdk:0.0.1")
|
||||
}
|
||||
```
|
||||
|
||||
### 📋 Dependencies
|
||||
|
||||
This SDK uses the following core dependencies:
|
||||
|
||||
| Library | Version |
|
||||
|---------|----------|
|
||||
| OkHttp | 4.12.0 |
|
||||
| Java JWT | 4.4.0 |
|
||||
| Jackson | 2.17.2 |
|
||||
| Retrofit2 | 2.11.0 |
|
||||
| RxJava | 3.1.8 |
|
||||
| SLF4J | 2.0.16 |
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Basic Usage
|
||||
|
||||
1. **Create a ZaiClient** with your API credentials
|
||||
2. **Access services** through the client
|
||||
3. **Call API methods** with typed parameters
|
||||
|
||||
```java
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.service.model.*;
|
||||
import ai.z.openapi.core.Constants;
|
||||
|
||||
// Create client with API key, recommend export the ENV api-key
|
||||
// export ZAI_API_KEY=your.api.key
|
||||
ZaiClient client = ZaiClient.builder().build();
|
||||
|
||||
// Or set the api-key by code
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.build();
|
||||
|
||||
// Or create client for specific platform
|
||||
ZaiClient zhipuClient = ZaiClient.ofZHIPU("your.api.key.your.api.secret").build();
|
||||
```
|
||||
|
||||
### Client Configuration
|
||||
|
||||
The SDK provides a flexible builder pattern for customizing your client:
|
||||
|
||||
```java
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.baseUrl("https://api.z.ai/api/paas/v4/")
|
||||
.enableTokenCache()
|
||||
.tokenExpire(3600000) // 1 hour
|
||||
.connectionPool(10, 5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
```
|
||||
|
||||
## 💡 Examples
|
||||
|
||||
### Chat Completion
|
||||
|
||||
```java
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.service.model.*;
|
||||
import ai.z.openapi.core.Constants;
|
||||
import java.util.Arrays;
|
||||
|
||||
// Create client
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.build();
|
||||
|
||||
// Create chat request
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("Hello, how are you?")
|
||||
.build()
|
||||
))
|
||||
.stream(false)
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1024)
|
||||
.build();
|
||||
|
||||
// Execute request
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
String content = response.getData().getChoices().get(0).getMessage().getContent();
|
||||
System.out.println("Response: " + content);
|
||||
} else {
|
||||
System.err.println("Error: " + response.getMsg());
|
||||
}
|
||||
```
|
||||
|
||||
### Streaming Chat
|
||||
|
||||
```java
|
||||
// Create streaming request
|
||||
ChatCompletionCreateParams streamRequest = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("Tell me a story")
|
||||
.build()
|
||||
))
|
||||
.stream(true) // Enable streaming
|
||||
.build();
|
||||
|
||||
// Execute streaming request
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(streamRequest);
|
||||
|
||||
if (response.isSuccess() && response.getFlowable() != null) {
|
||||
response.getFlowable().subscribe(
|
||||
data -> {
|
||||
// Handle streaming chunk
|
||||
if (data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getDelta().getContent();
|
||||
if (content != null) {
|
||||
System.out.print(content);
|
||||
}
|
||||
}
|
||||
},
|
||||
error -> System.err.println("\nStream error: " + error.getMessage()),
|
||||
() -> System.out.println("\nStream completed")
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Function Calling
|
||||
|
||||
```java
|
||||
// Define function
|
||||
ChatTool weatherTool = ChatTool.builder()
|
||||
.type(ChatToolType.FUNCTION.value())
|
||||
.function(ChatFunction.builder()
|
||||
.name("get_weather")
|
||||
.description("Get current weather for a location")
|
||||
.parameters(ChatFunctionParameters.builder()
|
||||
.type("object")
|
||||
.properties(Map.of(
|
||||
"location", Map.of(
|
||||
"type", "string",
|
||||
"description", "City name"
|
||||
)
|
||||
))
|
||||
.required(Arrays.asList("location"))
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
// Create request with function
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("What's the weather like in Beijing?")
|
||||
.build()
|
||||
))
|
||||
.tools(Arrays.asList(weatherTool))
|
||||
.toolChoice("auto")
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(request);
|
||||
```
|
||||
|
||||
### Embeddings
|
||||
|
||||
```java
|
||||
import ai.z.openapi.service.embedding.*;
|
||||
|
||||
// Create embedding request
|
||||
EmbeddingCreateParams request = EmbeddingCreateParams.builder()
|
||||
.model(Constants.ModelEmbedding3)
|
||||
.input(Arrays.asList("Hello world", "How are you?"))
|
||||
.build();
|
||||
|
||||
// Execute request
|
||||
EmbeddingResponse response = client.embeddings().create(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
response.getData().getData().forEach(embedding -> {
|
||||
System.out.println("Embedding: " + embedding.getEmbedding());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Image Generation
|
||||
|
||||
```java
|
||||
import ai.z.openapi.service.image.*;
|
||||
|
||||
// Create image generation request
|
||||
CreateImageRequest request = CreateImageRequest.builder()
|
||||
.model(Constants.ModelCogView3Plus)
|
||||
.prompt("A beautiful sunset over mountains")
|
||||
.size("1024x1024")
|
||||
.quality("standard")
|
||||
.n(1)
|
||||
.build();
|
||||
|
||||
// Execute request
|
||||
ImageResponse response = client.images().generate(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
response.getData().getData().forEach(image -> {
|
||||
System.out.println("Image URL: " + image.getUrl());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Spring Boot Integration
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class AIController {
|
||||
|
||||
private final ZaiClient zaiClient;
|
||||
|
||||
public AIController() {
|
||||
this.zaiClient = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.enableTokenCache()
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping("/chat")
|
||||
public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
|
||||
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content(request.getMessage())
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse response = zaiClient.chat().createChatCompletion(params);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
String content = response.getData().getChoices().get(0).getMessage().getContent();
|
||||
return ResponseEntity.ok(content);
|
||||
} else {
|
||||
return ResponseEntity.badRequest().body(response.getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 Available Services
|
||||
|
||||
The ZaiClient provides access to comprehensive AI services:
|
||||
|
||||
| Service | Description | Key Features |
|
||||
|---------|-------------|-------------|
|
||||
| **Chat** | Text generation and conversation | Streaming, function calling, async support |
|
||||
| **Embeddings** | Text embeddings generation | Multiple embedding models |
|
||||
| **Images** | Image generation and processing | CogView models, various sizes |
|
||||
| **Audio** | Speech synthesis and recognition | Text-to-speech, speech-to-text |
|
||||
| **Files** | File management and processing | Upload, download, batch processing |
|
||||
| **Assistants** | AI assistant management | Create, configure, and manage assistants |
|
||||
| **Agents** | Agent-based completions | Specialized agent interactions |
|
||||
| **Knowledge** | Knowledge base operations | Document indexing and retrieval |
|
||||
| **Fine-tuning** | Model customization | Train custom models |
|
||||
| **Batch** | Batch processing | Bulk operations |
|
||||
| **Web Search** | Web search integration | Real-time web information |
|
||||
| **Videos** | Video processing | Video analysis and generation |
|
||||
|
||||
## 🎯 Supported Models
|
||||
|
||||
### Text Generation
|
||||
- `glm-4-plus` - Enhanced GLM-4 with improved capabilities
|
||||
- `glm-4` - Standard GLM-4 model
|
||||
- `glm-4-air` - Lightweight version for speed
|
||||
- `glm-4-flash` - Ultra-fast response model
|
||||
- `glm-4-long` - Optimized for long-context conversations
|
||||
- `glm-4-voice` - Specialized for voice interactions
|
||||
|
||||
### Vision Models
|
||||
- `glm-4v-plus` - Enhanced vision model
|
||||
- `glm-4v` - Standard vision model
|
||||
|
||||
### Image Generation
|
||||
- `cogview-3-plus` - Enhanced image generation
|
||||
- `cogview-3` - Standard image generation
|
||||
|
||||
### Embeddings
|
||||
- `embedding-3` - Latest embedding model
|
||||
- `embedding-2` - Previous generation embedding
|
||||
|
||||
### Specialized
|
||||
- `charglm-3` - Character interaction model
|
||||
- `cogtts` - Text-to-speech model
|
||||
|
||||
## 📈 Release Notes
|
||||
|
||||
For detailed release notes and version history, please see [Release-Note.md](Release-Note.md).
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions! Please feel free to submit a Pull Request.
|
||||
|
||||
## 📞 Support
|
||||
|
||||
For questions and support:
|
||||
- Visit [Z.ai Platform](https://z.ai/)
|
||||
- Visit [ZHIPU AI Open Platform](http://open.bigmodel.cn/)
|
||||
- Check our [Architecture Documentation](ARCHITECTURE.md)
|
||||
|
|
|
|||
396
README_CN.md
Normal file
396
README_CN.md
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
# Z.ai Open Platform Java SDK
|
||||
|
||||
[](https://search.maven.org/artifact/ai.z/z-ai-sdk)
|
||||
[](LICENSE)
|
||||
[](https://www.oracle.com/java/)
|
||||
|
||||
[English Readme](README.md)
|
||||
|
||||
Z.ai AI 平台官方 Java SDK,提供统一接口访问强大的AI能力,包括对话补全、向量嵌入、图像生成、音频处理等功能。
|
||||
|
||||
## ✨ 特性
|
||||
|
||||
- 🚀 **类型安全**: 所有接口完全类型封装,无需查阅API文档即可完成接入
|
||||
- 🔧 **简单易用**: 简洁直观的API设计,快速上手
|
||||
- ⚡ **高性能**: 基于现代Java库构建,性能优异
|
||||
- 🛡️ **安全可靠**: 内置身份验证和令牌管理
|
||||
- 📦 **轻量级**: 最小化依赖,易于项目集成
|
||||
|
||||
## 📦 安装
|
||||
|
||||
### 环境要求
|
||||
- Java 1.8 或更高版本
|
||||
- Maven 或 Gradle
|
||||
- 尚不支持在 Android 平台运行
|
||||
|
||||
### Maven 依赖
|
||||
在您的 `pom.xml` 中添加以下依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>ai.z</groupId>
|
||||
<artifactId>z-ai-sdk</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle 依赖
|
||||
在您的 `build.gradle` 中添加以下依赖(适用于 Groovy DSL):
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
implementation 'ai.z:z-ai-sdk:0.0.1'
|
||||
}
|
||||
```
|
||||
|
||||
或 `build.gradle.kts`(适用于 Kotlin DSL):
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("ai.z:z-ai-sdk:0.0.1")
|
||||
}
|
||||
```
|
||||
|
||||
### 📋 核心依赖
|
||||
|
||||
本SDK使用以下核心依赖库:
|
||||
|
||||
| 依赖库 | 版本 |
|
||||
|--------|------|
|
||||
| OkHttp | 4.12.0 |
|
||||
| Java JWT | 4.4.0 |
|
||||
| Jackson | 2.17.2 |
|
||||
| Retrofit2 | 2.11.0 |
|
||||
| RxJava | 3.1.8 |
|
||||
| SLF4J | 2.0.16 |
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 基本用法
|
||||
|
||||
1. **使用API凭证创建ZaiClient**
|
||||
2. **通过客户端访问服务**
|
||||
3. **使用类型化参数调用API方法**
|
||||
|
||||
```java
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.service.model.*;
|
||||
import ai.z.openapi.core.Constants;
|
||||
|
||||
// 创建客户端 推荐使用环境变量设置API凭证
|
||||
// export ZAI_API_KEY=your.api.key
|
||||
ZaiClient client = ZaiClient.builder().build();
|
||||
|
||||
// 或代码设置凭证
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.build();
|
||||
|
||||
// 或为特定平台创建客户端
|
||||
ZaiClient zhipuClient = ZaiClient.ofZHIPU("your.api.key.your.api.secret").build();
|
||||
```
|
||||
|
||||
### 客户端配置
|
||||
|
||||
SDK提供了灵活的构建器模式来自定义您的客户端:
|
||||
|
||||
```java
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.baseUrl("https://api.z.ai/api/paas/v4/")
|
||||
.enableTokenCache()
|
||||
.tokenExpire(3600000) // 1小时
|
||||
.connectionPool(10, 5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
```
|
||||
|
||||
## 💡 使用示例
|
||||
|
||||
### 对话补全
|
||||
|
||||
```java
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.service.model.*;
|
||||
import ai.z.openapi.core.Constants;
|
||||
import java.util.Arrays;
|
||||
|
||||
// 创建客户端
|
||||
ZaiClient client = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.build();
|
||||
|
||||
// 创建对话请求
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("你好,你怎么样?")
|
||||
.build()
|
||||
))
|
||||
.stream(false)
|
||||
.temperature(0.7f)
|
||||
.maxTokens(1024)
|
||||
.build();
|
||||
|
||||
// 执行请求
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
String content = response.getData().getChoices().get(0).getMessage().getContent();
|
||||
System.out.println("回复: " + content);
|
||||
} else {
|
||||
System.err.println("错误: " + response.getMsg());
|
||||
}
|
||||
```
|
||||
|
||||
### 流式对话
|
||||
|
||||
```java
|
||||
// 创建流式请求
|
||||
ChatCompletionCreateParams streamRequest = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("给我讲个故事")
|
||||
.build()
|
||||
))
|
||||
.stream(true) // 启用流式
|
||||
.build();
|
||||
|
||||
// 执行流式请求
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(streamRequest);
|
||||
|
||||
if (response.isSuccess() && response.getFlowable() != null) {
|
||||
response.getFlowable().subscribe(
|
||||
data -> {
|
||||
// 处理流式数据块
|
||||
if (data.getChoices() != null && !data.getChoices().isEmpty()) {
|
||||
String content = data.getChoices().get(0).getDelta().getContent();
|
||||
if (content != null) {
|
||||
System.out.print(content);
|
||||
}
|
||||
}
|
||||
},
|
||||
error -> System.err.println("\n流式错误: " + error.getMessage()),
|
||||
() -> System.out.println("\n流式完成")
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 函数调用
|
||||
|
||||
```java
|
||||
// 定义函数
|
||||
ChatTool weatherTool = ChatTool.builder()
|
||||
.type(ChatToolType.FUNCTION.value())
|
||||
.function(ChatFunction.builder()
|
||||
.name("get_weather")
|
||||
.description("获取指定地点的当前天气")
|
||||
.parameters(ChatFunctionParameters.builder()
|
||||
.type("object")
|
||||
.properties(Map.of(
|
||||
"location", Map.of(
|
||||
"type", "string",
|
||||
"description", "城市名称"
|
||||
)
|
||||
))
|
||||
.required(Arrays.asList("location"))
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
// 创建带函数的请求
|
||||
ChatCompletionCreateParams request = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content("北京的天气怎么样?")
|
||||
.build()
|
||||
))
|
||||
.tools(Arrays.asList(weatherTool))
|
||||
.toolChoice("auto")
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse response = client.chat().createChatCompletion(request);
|
||||
```
|
||||
|
||||
### 向量嵌入
|
||||
|
||||
```java
|
||||
import ai.z.openapi.service.embedding.*;
|
||||
|
||||
// 创建嵌入请求
|
||||
EmbeddingCreateParams request = EmbeddingCreateParams.builder()
|
||||
.model(Constants.ModelEmbedding3)
|
||||
.input(Arrays.asList("你好世界", "你好吗?"))
|
||||
.build();
|
||||
|
||||
// 执行请求
|
||||
EmbeddingResponse response = client.embeddings().create(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
response.getData().getData().forEach(embedding -> {
|
||||
System.out.println("嵌入向量: " + embedding.getEmbedding());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 图像生成
|
||||
|
||||
```java
|
||||
import ai.z.openapi.service.image.*;
|
||||
|
||||
// 创建图像生成请求
|
||||
CreateImageRequest request = CreateImageRequest.builder()
|
||||
.model(Constants.ModelCogView3Plus)
|
||||
.prompt("山间美丽的日落")
|
||||
.size("1024x1024")
|
||||
.quality("standard")
|
||||
.n(1)
|
||||
.build();
|
||||
|
||||
// 执行请求
|
||||
ImageResponse response = client.images().generate(request);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
response.getData().getData().forEach(image -> {
|
||||
System.out.println("图像URL: " + image.getUrl());
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Spring Boot 集成
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class AIController {
|
||||
|
||||
private final ZaiClient zaiClient;
|
||||
|
||||
public AIController() {
|
||||
this.zaiClient = ZaiClient.builder()
|
||||
.apiKey("your.api.key.your.api.secret")
|
||||
.enableTokenCache()
|
||||
.build();
|
||||
}
|
||||
|
||||
@PostMapping("/chat")
|
||||
public ResponseEntity<String> chat(@RequestBody ChatRequest request) {
|
||||
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
|
||||
.model(Constants.ModelChatGLM4)
|
||||
.messages(Arrays.asList(
|
||||
ChatMessage.builder()
|
||||
.role(ChatMessageRole.USER.value())
|
||||
.content(request.getMessage())
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
ChatCompletionResponse response = zaiClient.chat().createChatCompletion(params);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
String content = response.getData().getChoices().get(0).getMessage().getContent();
|
||||
return ResponseEntity.ok(content);
|
||||
} else {
|
||||
return ResponseEntity.badRequest().body(response.getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 可用服务
|
||||
|
||||
### Chat 服务
|
||||
- 对话补全(同步/异步)
|
||||
- 流式对话
|
||||
- 函数调用
|
||||
- 多模态对话(文本+图像)
|
||||
|
||||
### Embeddings 服务
|
||||
- 文本向量化
|
||||
- 批量嵌入
|
||||
- 多种嵌入模型
|
||||
|
||||
### Images 服务
|
||||
- 文本到图像生成
|
||||
- 图像编辑
|
||||
- 图像变体
|
||||
|
||||
### Audio 服务
|
||||
- 语音转文本
|
||||
- 文本转语音
|
||||
- 语音翻译
|
||||
|
||||
### Files 服务
|
||||
- 文件上传
|
||||
- 文件管理
|
||||
- 文件检索
|
||||
|
||||
### Assistants 服务
|
||||
- AI助手创建
|
||||
- 助手管理
|
||||
- 对话线程
|
||||
|
||||
### Agents 服务
|
||||
- 智能代理
|
||||
- 工作流管理
|
||||
- 任务执行
|
||||
|
||||
### Knowledge 服务
|
||||
- 知识库管理
|
||||
- 文档处理
|
||||
- 知识检索
|
||||
|
||||
### Batch 服务
|
||||
- 批量处理
|
||||
- 异步任务
|
||||
- 结果管理
|
||||
|
||||
## 🤖 支持的模型
|
||||
|
||||
### 文本生成模型
|
||||
- `glm-4-plus` - 最新的GLM-4 Plus模型
|
||||
- `glm-4-0520` - GLM-4标准版
|
||||
- `glm-4-long` - 长文本处理版本
|
||||
- `glm-4-airx` - 轻量级版本
|
||||
- `glm-4-air` - 快速响应版本
|
||||
- `glm-4-flashx` - 超快响应版本
|
||||
- `glm-4-flash` - 闪电版本
|
||||
|
||||
### 视觉模型
|
||||
- `glm-4v-plus` - 多模态理解模型
|
||||
- `glm-4v` - 视觉理解模型
|
||||
|
||||
### 图像生成模型
|
||||
- `cogview-3-plus` - 高质量图像生成
|
||||
- `cogview-3` - 标准图像生成
|
||||
|
||||
### 嵌入模型
|
||||
- `embedding-3` - 最新嵌入模型
|
||||
- `embedding-2` - 标准嵌入模型
|
||||
|
||||
### 专业模型
|
||||
- `charglm-3` - 角色扮演模型
|
||||
- `emohaa` - 情感分析模型
|
||||
|
||||
## 📈 版本更新
|
||||
|
||||
详细的版本更新记录和历史信息,请查看 [Release-Note.md](Release-Note.md)。
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目基于 MIT 许可证开源 - 详情请查看 [LICENSE](LICENSE) 文件。
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎贡献代码!请随时提交 Pull Request。
|
||||
|
||||
## 📞 支持
|
||||
|
||||
如有问题和技术支持:
|
||||
- Visit [Z.ai Platform](https://z.ai/)
|
||||
- Visit [ZHIPU AI Open Platform](http://open.bigmodel.cn/)
|
||||
- Check our [Architecture Documentation](ARCHITECTURE.md)
|
||||
4
Release-Note.md
Normal file
4
Release-Note.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Release Notes
|
||||
|
||||
### 0.0.1
|
||||
- ✅ Initial the Z.ai sdk refer from ZHIPU sdk
|
||||
237
core/pom.xml
Normal file
237
core/pom.xml
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
<?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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>ai.z.openapi</groupId>
|
||||
<artifactId>z-ai-sdk-parent</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>z-ai-sdk</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Java sdk for Z.ai open api</name>
|
||||
<description>Java SDK for Z.ai Open Platform API</description>
|
||||
<url>https://z.ai</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>https://www.opensource.org/licenses/mit-license.php</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>Z.ai</id>
|
||||
<name>Z.ai</name>
|
||||
<email>user_feedback@z.ai</email>
|
||||
<url>https://z.ai/model-api</url>
|
||||
<organization>Z.ai</organization>
|
||||
<organizationUrl>https://z.ai</organizationUrl>
|
||||
<roles>
|
||||
<role>architect</role>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
<timezone>Asia/Shanghai</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/THUDM/z-ai-sdk-java.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/THUDM/z-ai-sdk-java.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/THUDM/z-ai-sdk-java</url>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<slf4j.version>2.0.11</slf4j.version>
|
||||
<okhttp.version>3.14.9</okhttp.version>
|
||||
<jackson.version>2.11.3</jackson.version>
|
||||
<retrofit2.version>2.9.0</retrofit2.version>
|
||||
<rxjava.version>3.1.8</rxjava.version>
|
||||
<jwt.version>4.2.2</jwt.version>
|
||||
<lombok.version>1.18.32</lombok.version>
|
||||
<tika.version>2.9.0</tika.version>
|
||||
<junit.test.version>5.10.2</junit.test.version>
|
||||
<testcontainer.version>1.19.8</testcontainer.version>
|
||||
<mockserver.version>5.15.0</mockserver.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- slf4j -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- http -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-sse</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava3</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>adapter-rxjava2</artifactId>
|
||||
<version>${retrofit2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-jackson</artifactId>
|
||||
<version>${retrofit2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- jwt -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--file tika-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${tika.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test JUnit -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit.test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Containers -->
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>${testcontainer.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
<version>${testcontainer.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${testcontainer.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test MockServer -->
|
||||
<dependency>
|
||||
<groupId>org.mock-server</groupId>
|
||||
<artifactId>mockserver-netty</artifactId>
|
||||
<version>${mockserver.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mock-server</groupId>
|
||||
<artifactId>mockserver-client-java</artifactId>
|
||||
<version>${mockserver.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
646
core/src/main/java/ai/z/openapi/ZaiClient.java
Normal file
646
core/src/main/java/ai/z/openapi/ZaiClient.java
Normal file
|
|
@ -0,0 +1,646 @@
|
|||
package ai.z.openapi;
|
||||
|
||||
import ai.z.openapi.service.AbstractClientBaseService;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import ai.z.openapi.service.model.ZAiHttpException;
|
||||
import ai.z.openapi.service.chat.ChatService;
|
||||
import ai.z.openapi.service.chat.ChatServiceImpl;
|
||||
import ai.z.openapi.service.agents.AgentService;
|
||||
import ai.z.openapi.service.agents.AgentServiceImpl;
|
||||
import ai.z.openapi.service.embedding.EmbeddingService;
|
||||
import ai.z.openapi.service.embedding.EmbeddingServiceImpl;
|
||||
import ai.z.openapi.service.file.FileService;
|
||||
import ai.z.openapi.service.file.FileServiceImpl;
|
||||
import ai.z.openapi.service.audio.AudioService;
|
||||
import ai.z.openapi.service.audio.AudioServiceImpl;
|
||||
import ai.z.openapi.service.image.ImageService;
|
||||
import ai.z.openapi.service.image.ImageServiceImpl;
|
||||
import ai.z.openapi.service.batches.BatchService;
|
||||
import ai.z.openapi.service.batches.BatchServiceImpl;
|
||||
import ai.z.openapi.service.fine_turning.FineTuningService;
|
||||
import ai.z.openapi.service.fine_turning.FineTuningServiceImpl;
|
||||
import ai.z.openapi.service.web_search.WebSearchService;
|
||||
import ai.z.openapi.service.web_search.WebSearchServiceImpl;
|
||||
import ai.z.openapi.service.videos.VideosService;
|
||||
import ai.z.openapi.service.videos.VideosServiceImpl;
|
||||
import ai.z.openapi.service.knowledge.KnowledgeService;
|
||||
import ai.z.openapi.service.knowledge.KnowledgeServiceImpl;
|
||||
import ai.z.openapi.service.document.DocumentService;
|
||||
import ai.z.openapi.service.document.DocumentServiceImpl;
|
||||
import ai.z.openapi.service.assistant.AssistantService;
|
||||
import ai.z.openapi.service.assistant.AssistantServiceImpl;
|
||||
import ai.z.openapi.core.config.ZaiConfig;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.core.model.FlowableClientResponse;
|
||||
import ai.z.openapi.utils.FlowableRequestSupplier;
|
||||
import ai.z.openapi.utils.OkHttps;
|
||||
import ai.z.openapi.utils.RequestSupplier;
|
||||
import ai.z.openapi.utils.StringUtils;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.jackson.JacksonConverterFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static ai.z.openapi.core.Constants.ZHIPU_AI_BASE_URL;
|
||||
import static ai.z.openapi.core.Constants.Z_AI_BASE_URL;
|
||||
|
||||
/**
|
||||
* ZaiClient is the main entry point for interacting with the Z.ai API. This client
|
||||
* provides access to various AI services including chat, embeddings, file operations,
|
||||
* audio processing, image generation, and more.
|
||||
*
|
||||
* <p>
|
||||
* The client supports both Z.ai and ZHIPU AI endpoints and provides thread-safe lazy
|
||||
* initialization of services.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example usage:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* ZaiClient client = new ZaiClient.Builder("your-api-key")
|
||||
* .networkConfig(30, 10, 30, 30, TimeUnit.SECONDS)
|
||||
* .build();
|
||||
*
|
||||
* ChatService chatService = client.chat();
|
||||
* // Use the chat service...
|
||||
*
|
||||
* client.close(); // Don't forget to close when done
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public class ZaiClient extends AbstractClientBaseService {
|
||||
|
||||
/** Logger instance for this class */
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZaiClient.class);
|
||||
|
||||
/** HTTP client for making network requests */
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
/** Retrofit instance for API communication */
|
||||
private final Retrofit retrofit;
|
||||
|
||||
// Service instances - lazily initialized for thread safety and performance
|
||||
/** Chat service for conversational AI operations */
|
||||
private ChatService chatService;
|
||||
|
||||
/** Agent service for AI agent management */
|
||||
private AgentService agentService;
|
||||
|
||||
/** Embedding service for text embeddings */
|
||||
private EmbeddingService embeddingService;
|
||||
|
||||
/** File service for file operations */
|
||||
private FileService fileService;
|
||||
|
||||
/** Audio service for audio processing */
|
||||
private AudioService audioService;
|
||||
|
||||
/** Image service for image generation and processing */
|
||||
private ImageService imageService;
|
||||
|
||||
/** Batch service for batch processing operations */
|
||||
private BatchService batchService;
|
||||
|
||||
/** Fine-tuning service for model customization */
|
||||
private FineTuningService fineTuningService;
|
||||
|
||||
/** Web search service for internet search capabilities */
|
||||
private WebSearchService webSearchService;
|
||||
|
||||
/** Videos service for video processing */
|
||||
private VideosService videosService;
|
||||
|
||||
/** Knowledge service for knowledge base operations */
|
||||
private KnowledgeService knowledgeService;
|
||||
|
||||
/** Document service for document processing */
|
||||
private DocumentService documentService;
|
||||
|
||||
/** Assistant service for AI assistant functionality */
|
||||
private AssistantService assistantService;
|
||||
|
||||
/**
|
||||
* Constructs a new ZaiClient with the specified configuration. By default, this
|
||||
* client uses the Z.ai OpenAPI endpoint.
|
||||
* @param config the configuration object containing API keys, timeouts, and other
|
||||
* settings
|
||||
* @throws IllegalArgumentException if config is null or invalid
|
||||
*/
|
||||
public ZaiClient(ZaiConfig config) {
|
||||
this.httpClient = OkHttps.create(config);
|
||||
this.retrofit = new Retrofit.Builder()
|
||||
.baseUrl(StringUtils.isEmpty(config.getBaseUrl()) ? Z_AI_BASE_URL : config.getBaseUrl())
|
||||
.client(httpClient)
|
||||
.addConverterFactory(JacksonConverterFactory.create(mapper))
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
.build();
|
||||
}
|
||||
|
||||
// ==================== Service Accessor Methods ====================
|
||||
// All service methods use lazy initialization with synchronization for thread safety
|
||||
|
||||
/**
|
||||
* Returns the chat service for conversational AI operations. This service handles
|
||||
* chat completions, streaming conversations, and related functionality.
|
||||
* @return the ChatService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized ChatService chat() {
|
||||
if (chatService == null) {
|
||||
this.chatService = new ChatServiceImpl(this);
|
||||
}
|
||||
return chatService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the agent service for AI agent management. This service handles agent
|
||||
* creation, configuration, and execution.
|
||||
* @return the AgentService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized AgentService agents() {
|
||||
if (agentService == null) {
|
||||
this.agentService = new AgentServiceImpl(this);
|
||||
}
|
||||
return agentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the embedding service for text embeddings. This service converts text into
|
||||
* numerical vector representations.
|
||||
* @return the EmbeddingService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized EmbeddingService embeddings() {
|
||||
if (embeddingService == null) {
|
||||
this.embeddingService = new EmbeddingServiceImpl(this);
|
||||
}
|
||||
return embeddingService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file service for file operations. This service handles file uploads,
|
||||
* downloads, and management.
|
||||
* @return the FileService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized FileService files() {
|
||||
if (fileService == null) {
|
||||
this.fileService = new FileServiceImpl(this);
|
||||
}
|
||||
return fileService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the audio service for audio processing. This service handles
|
||||
* speech-to-text, text-to-speech, and audio analysis.
|
||||
* @return the AudioService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized AudioService audio() {
|
||||
if (audioService == null) {
|
||||
this.audioService = new AudioServiceImpl(this);
|
||||
}
|
||||
return audioService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image service for image generation and processing. This service handles
|
||||
* image creation, editing, and analysis.
|
||||
* @return the ImageService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized ImageService images() {
|
||||
if (imageService == null) {
|
||||
this.imageService = new ImageServiceImpl(this);
|
||||
}
|
||||
return imageService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the batch service for batch processing operations. This service handles
|
||||
* large-scale batch processing of requests.
|
||||
* @return the BatchService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized BatchService batches() {
|
||||
if (batchService == null) {
|
||||
this.batchService = new BatchServiceImpl(this);
|
||||
}
|
||||
return batchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fine-tuning service for model customization. This service handles
|
||||
* training custom models on user data.
|
||||
* @return the FineTuningService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized FineTuningService fineTuning() {
|
||||
if (fineTuningService == null) {
|
||||
this.fineTuningService = new FineTuningServiceImpl(this);
|
||||
}
|
||||
return fineTuningService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the web search service for internet search capabilities. This service
|
||||
* provides AI-powered web search functionality.
|
||||
* @return the WebSearchService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized WebSearchService webSearch() {
|
||||
if (webSearchService == null) {
|
||||
this.webSearchService = new WebSearchServiceImpl(this);
|
||||
}
|
||||
return webSearchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the videos service for video processing. This service handles video
|
||||
* analysis, generation, and manipulation.
|
||||
* @return the VideosService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized VideosService videos() {
|
||||
if (videosService == null) {
|
||||
this.videosService = new VideosServiceImpl(this);
|
||||
}
|
||||
return videosService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the knowledge service for knowledge base operations. This service manages
|
||||
* knowledge bases and retrieval operations.
|
||||
* @return the KnowledgeService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized KnowledgeService knowledge() {
|
||||
if (knowledgeService == null) {
|
||||
this.knowledgeService = new KnowledgeServiceImpl(this);
|
||||
}
|
||||
return knowledgeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document service for document processing. This service handles document
|
||||
* parsing, analysis, and manipulation.
|
||||
* @return the DocumentService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized DocumentService documents() {
|
||||
if (documentService == null) {
|
||||
this.documentService = new DocumentServiceImpl(this);
|
||||
}
|
||||
return documentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the assistant service for AI assistant functionality. This service provides
|
||||
* advanced AI assistant capabilities.
|
||||
* @return the AssistantService instance (lazily initialized)
|
||||
*/
|
||||
public synchronized AssistantService assistants() {
|
||||
if (assistantService == null) {
|
||||
this.assistantService = new AssistantServiceImpl(this);
|
||||
}
|
||||
return assistantService;
|
||||
}
|
||||
|
||||
// ==================== Utility Methods ====================
|
||||
|
||||
/**
|
||||
* Returns the underlying Retrofit instance used for API communication. This method is
|
||||
* primarily intended for advanced users who need direct access to the Retrofit client
|
||||
* for custom API calls.
|
||||
* @return the Retrofit instance
|
||||
*/
|
||||
public Retrofit retrofit() {
|
||||
return retrofit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the ZAi client and releases all associated resources. This method shuts down
|
||||
* the HTTP client's connection pool and executor service. After calling this method,
|
||||
* the client should not be used for further requests.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Important:</strong> Always call this method when you're done with the
|
||||
* client to prevent resource leaks.
|
||||
* </p>
|
||||
*/
|
||||
public void close() {
|
||||
if (httpClient != null) {
|
||||
httpClient.dispatcher().executorService().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Core Request Execution Methods ====================
|
||||
|
||||
/**
|
||||
* Executes a synchronous API request and returns the response. This method handles
|
||||
* the complete request lifecycle including error handling and response wrapping.
|
||||
* @param <Data> the type of data expected in the response
|
||||
* @param <Param> the type of parameters for the request
|
||||
* @param <TReq> the type of client request
|
||||
* @param <TResp> the type of client response
|
||||
* @param request the client request containing parameters
|
||||
* @param requestSupplier the supplier that creates the actual API call
|
||||
* @param tRespClass the class of the response type
|
||||
* @return the wrapped response containing either success data or error information
|
||||
*/
|
||||
@Override
|
||||
public <Data, Param, TReq extends ClientRequest<Param>, TResp extends ClientResponse<Data>> TResp executeRequest(
|
||||
TReq request, RequestSupplier<Param, Data> requestSupplier, Class<TResp> tRespClass) {
|
||||
Single<Data> apiCall = requestSupplier.get((Param) request);
|
||||
|
||||
TResp tResp = convertToClientResponse(tRespClass);
|
||||
try {
|
||||
// Execute the API call synchronously
|
||||
Data response = execute(apiCall);
|
||||
tResp.setCode(200);
|
||||
tResp.setMsg("Call successful");
|
||||
tResp.setData(response);
|
||||
tResp.setSuccess(true);
|
||||
}
|
||||
catch (ZAiHttpException e) {
|
||||
logger.error("API request failed with business error", e);
|
||||
tResp.setCode(e.statusCode);
|
||||
tResp.setMsg("Business error");
|
||||
tResp.setSuccess(false);
|
||||
ChatError chatError = new ChatError();
|
||||
chatError.setCode(Integer.parseInt(e.code));
|
||||
chatError.setMessage(e.getMessage());
|
||||
tResp.setError(chatError);
|
||||
}
|
||||
return tResp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a streaming API request and returns a response containing a Flowable
|
||||
* stream. This method is used for requests that return data as a continuous stream,
|
||||
* such as chat completions with streaming enabled.
|
||||
* @param <Data> the type of data expected in each stream element
|
||||
* @param <Param> the type of parameters for the request
|
||||
* @param <TReq> the type of client request
|
||||
* @param <TResp> the type of flowable client response
|
||||
* @param request the client request containing parameters
|
||||
* @param requestSupplier the supplier that creates the actual streaming API call
|
||||
* @param tRespClass the class of the response type
|
||||
* @param tDataClass the class of the data type for stream elements
|
||||
* @return the wrapped response containing either a success stream or error
|
||||
* information
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <Data, Param, TReq extends ClientRequest<Param>, TResp extends FlowableClientResponse<Data>> TResp streamRequest(
|
||||
TReq request, FlowableRequestSupplier<Param, retrofit2.Call<ResponseBody>> requestSupplier,
|
||||
Class<TResp> tRespClass, Class<Data> tDataClass) {
|
||||
retrofit2.Call<ResponseBody> apiCall = requestSupplier.get((Param) request);
|
||||
|
||||
TResp tResp = convertToClientResponse(tRespClass);
|
||||
try {
|
||||
// Create a streaming response using the provided API call
|
||||
Flowable<Data> stream = stream(apiCall, tDataClass);
|
||||
tResp.setCode(200);
|
||||
tResp.setMsg("Stream initialized successfully");
|
||||
tResp.setSuccess(true);
|
||||
tResp.setFlowable(stream);
|
||||
}
|
||||
catch (ZAiHttpException e) {
|
||||
logger.error("Streaming API request failed with business error", e);
|
||||
tResp.setCode(e.statusCode);
|
||||
tResp.setMsg("Business error");
|
||||
tResp.setSuccess(false);
|
||||
ChatError chatError = new ChatError();
|
||||
chatError.setCode(Integer.parseInt(e.code));
|
||||
chatError.setMessage(e.getMessage());
|
||||
tResp.setError(chatError);
|
||||
}
|
||||
return tResp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the specified response class using reflection. This
|
||||
* helper method is used to instantiate response objects dynamically.
|
||||
* @param <Data> the type of data contained in the response
|
||||
* @param <TResp> the type of client response
|
||||
* @param tRespClass the class of the response type to instantiate
|
||||
* @return a new instance of the response class
|
||||
* @throws RuntimeException if the response object cannot be created
|
||||
*/
|
||||
private <Data, TResp extends ClientResponse<Data>> TResp convertToClientResponse(Class<TResp> tRespClass) {
|
||||
try {
|
||||
return tRespClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
|
||||
throw new RuntimeException("Failed to create response object of type: " + tRespClass.getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Builder Pattern Implementation ====================
|
||||
|
||||
/**
|
||||
* Builder class for creating ZaiClient instances with custom configurations. This
|
||||
* builder provides a fluent API for setting up the client with various options
|
||||
* including authentication, network settings, and connection pooling.
|
||||
*
|
||||
* <p>
|
||||
* Example usage:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* ZaiClient client = new ZaiClient.Builder("your-api-key")
|
||||
* .networkConfig(30, 10, 30, 30, TimeUnit.SECONDS)
|
||||
* .connectionPool(10, 5, TimeUnit.MINUTES)
|
||||
* .enableTokenCache()
|
||||
* .build();
|
||||
* }</pre>
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
/** Configuration object that accumulates all builder settings */
|
||||
private final ZaiConfig config = new ZaiConfig();
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder with the specified API key.
|
||||
* @param apiKey the API key for authentication
|
||||
* @throws IllegalArgumentException if apiKey is null or empty
|
||||
*/
|
||||
public Builder(String apiKey) {
|
||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("API key cannot be null or empty");
|
||||
}
|
||||
config.setApiKey(apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder with a custom base URL and API secret key.
|
||||
* @param baseUrl the custom base URL for the API endpoint
|
||||
* @param apiKey the API secret key for authentication
|
||||
* @throws IllegalArgumentException if any parameter is null or empty
|
||||
*/
|
||||
public Builder(String baseUrl, String apiKey) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Base URL cannot be null or empty");
|
||||
}
|
||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("API secret key cannot be null or empty");
|
||||
}
|
||||
config.setBaseUrl(baseUrl);
|
||||
config.setApiKey(apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Config the api service base url
|
||||
* @param baseUrl base url
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder baseUrl(String baseUrl) {
|
||||
if (baseUrl == null || baseUrl.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Base URL cannot be null or empty");
|
||||
}
|
||||
config.setBaseUrl(baseUrl);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Config the apikey
|
||||
* @param apiKey api key
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder apiKey(String apiKey) {
|
||||
if (apiKey == null || apiKey.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("API secret key cannot be null or empty");
|
||||
}
|
||||
config.setApiKey(apiKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the ZHIPU AI base url
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder ofZHIPU() {
|
||||
config.setBaseUrl(ZHIPU_AI_BASE_URL);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the Z AI base url
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder ofZAI() {
|
||||
config.setBaseUrl(Z_AI_BASE_URL);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables token caching, forcing the client to use API keys for direct requests.
|
||||
* This is the default behavior.
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder disableTokenCache() {
|
||||
config.setDisableTokenCache(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables token caching, allowing the client to use access tokens for requests.
|
||||
* This can improve performance by reducing authentication overhead.
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder enableTokenCache() {
|
||||
config.setDisableTokenCache(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the HTTP connection pool settings.
|
||||
* @param maxIdleConnections maximum number of idle connections to keep in the
|
||||
* pool
|
||||
* @param keepAliveDuration how long to keep idle connections alive
|
||||
* @param timeUnit the time unit for the keep alive duration
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder connectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
|
||||
config.setConnectionPoolMaxIdleConnections(maxIdleConnections);
|
||||
config.setConnectionPoolKeepAliveDuration(keepAliveDuration);
|
||||
config.setConnectionPoolTimeUnit(timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token expiration time in milliseconds.
|
||||
* @param expireMillis the token expiration time in milliseconds
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder tokenExpire(int expireMillis) {
|
||||
config.setExpireMillis(expireMillis);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures network request timeout settings.
|
||||
* @param requestTimeOut the overall request timeout (see
|
||||
* {@link OkHttpClient.Builder#callTimeout(long, TimeUnit)})
|
||||
* @param connectTimeout the connection timeout (see
|
||||
* {@link OkHttpClient.Builder#connectTimeout(long, TimeUnit)})
|
||||
* @param readTimeout the read timeout (see
|
||||
* {@link OkHttpClient.Builder#readTimeout(long, TimeUnit)})
|
||||
* @param writeTimeout the write timeout (see
|
||||
* {@link OkHttpClient.Builder#writeTimeout(long, TimeUnit)})
|
||||
* @param timeUnit the time unit for all timeout values
|
||||
* @return this Builder instance for method chaining
|
||||
*/
|
||||
public Builder networkConfig(int requestTimeOut, int connectTimeout, int readTimeout, int writeTimeout,
|
||||
TimeUnit timeUnit) {
|
||||
config.setRequestTimeOut(requestTimeOut);
|
||||
config.setConnectTimeout(connectTimeout);
|
||||
config.setReadTimeout(readTimeout);
|
||||
config.setWriteTimeout(writeTimeout);
|
||||
config.setTimeOutTimeUnit(timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a new ZaiClient instance with the configured settings.
|
||||
* @return a new ZaiClient instance
|
||||
* @throws IllegalStateException if the configuration is invalid
|
||||
*/
|
||||
public ZaiClient build() {
|
||||
return new ZaiClient(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ==================== Static Factory Methods ====================
|
||||
|
||||
/**
|
||||
* Creates a new Builder instance for constructing ZaiClient.
|
||||
* @return a new Builder instance
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ZaiClient configured for ZHIPU AI platform with the specified API key.
|
||||
* @param apiKey the API key for authentication
|
||||
* @return a new ZaiClient instance configured for ZHIPU AI
|
||||
* @throws IllegalArgumentException if apiKey is null or empty
|
||||
*/
|
||||
public static Builder ofZHIPU(String apiKey) {
|
||||
return new Builder().apiKey(apiKey).ofZHIPU();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ZaiClient configured for ZHIPU AI platform with the specified API key.
|
||||
* @return a new ZaiClient instance configured for ZHIPU AI
|
||||
* @throws IllegalArgumentException if apiKey is null or empty
|
||||
*/
|
||||
public static Builder ofZHIPU() {
|
||||
return new Builder().ofZHIPU();
|
||||
}
|
||||
|
||||
}
|
||||
25
core/src/main/java/ai/z/openapi/api/agents/AgentsApi.java
Normal file
25
core/src/main/java/ai/z/openapi/api/agents/AgentsApi.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package ai.z.openapi.api.agents;
|
||||
|
||||
import ai.z.openapi.service.agents.AgentAsyncResultRetrieveParams;
|
||||
import ai.z.openapi.service.agents.AgentsCompletionRequest;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
public interface AgentsApi {
|
||||
|
||||
@Streaming
|
||||
@POST("v1/agents")
|
||||
Call<ResponseBody> agentsCompletionStream(@Body AgentsCompletionRequest request);
|
||||
|
||||
@POST("v1/agents")
|
||||
Single<ModelData> agentsCompletionSync(@Body AgentsCompletionRequest request);
|
||||
|
||||
@POST("v1/agents/async-result")
|
||||
Single<ModelData> queryAgentsAsyncResult(@Body AgentAsyncResultRetrieveParams request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ai.z.openapi.api.assistant;
|
||||
|
||||
import ai.z.openapi.service.assistant.AssistantCompletion;
|
||||
import ai.z.openapi.service.assistant.AssistantParameters;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationUsageListStatus;
|
||||
import ai.z.openapi.service.assistant.query_support.AssistantSupportStatus;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationParameters;
|
||||
import ai.z.openapi.service.assistant.query_support.QuerySupportParams;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
public interface AssistantApi {
|
||||
|
||||
@Streaming
|
||||
@POST("assistant")
|
||||
Call<ResponseBody> assistantCompletionStream(@Body AssistantParameters request);
|
||||
|
||||
@POST("assistant")
|
||||
Single<AssistantCompletion> assistantCompletion(@Body AssistantParameters request);
|
||||
|
||||
@POST("assistant/list")
|
||||
Single<AssistantSupportStatus> querySupport(@Body QuerySupportParams request);
|
||||
|
||||
@POST("assistant/conversation/list")
|
||||
Single<ConversationUsageListStatus> queryConversationUsage(@Body ConversationParameters request);
|
||||
|
||||
}
|
||||
50
core/src/main/java/ai/z/openapi/api/audio/AudioApi.java
Normal file
50
core/src/main/java/ai/z/openapi/api/audio/AudioApi.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package ai.z.openapi.api.audio;
|
||||
|
||||
import ai.z.openapi.service.audio.AudioSpeechRequest;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.Multipart;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Part;
|
||||
import retrofit2.http.PartMap;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface AudioApi {
|
||||
|
||||
/**
|
||||
* TTS interface (Text to speech)
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@POST("audio/speech")
|
||||
Single<ResponseBody> audioSpeech(@Body AudioSpeechRequest request);
|
||||
|
||||
/**
|
||||
* Voice cloning interface
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@Multipart
|
||||
@POST("audio/customization")
|
||||
Single<ResponseBody> audioCustomization(@PartMap Map<String, RequestBody> request,
|
||||
@Part MultipartBody.Part voiceData);
|
||||
|
||||
@Streaming
|
||||
@POST("audio/transcriptions")
|
||||
@Multipart
|
||||
Call<ResponseBody> audioTranscriptionsStream(@PartMap Map<String, RequestBody> request,
|
||||
@Part MultipartBody.Part file);
|
||||
|
||||
@POST("audio/transcriptions")
|
||||
@Multipart
|
||||
Single<ModelData> audioTranscriptions(@PartMap Map<String, RequestBody> request, @Part MultipartBody.Part file);
|
||||
|
||||
}
|
||||
27
core/src/main/java/ai/z/openapi/api/batches/BatchesApi.java
Normal file
27
core/src/main/java/ai/z/openapi/api/batches/BatchesApi.java
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package ai.z.openapi.api.batches;
|
||||
|
||||
import ai.z.openapi.service.batches.Batch;
|
||||
import ai.z.openapi.service.batches.BatchCreateParams;
|
||||
import ai.z.openapi.service.batches.BatchPage;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface BatchesApi {
|
||||
|
||||
@POST("batches")
|
||||
Single<Batch> batchesCreate(@Body BatchCreateParams batchCreateParams);
|
||||
|
||||
@GET("batches/{batch_id}")
|
||||
Single<Batch> batchesRetrieve(@Path("batch_id") String batchId);
|
||||
|
||||
@GET("batches")
|
||||
Single<BatchPage> batchesList(@Query("after") String after, @Query("limit") Integer limit);
|
||||
|
||||
@POST("batches/{batch_id}/cancel")
|
||||
Single<Batch> batchesCancel(@Path("batch_id") String batchId);
|
||||
|
||||
}
|
||||
29
core/src/main/java/ai/z/openapi/api/chat/ChatApi.java
Normal file
29
core/src/main/java/ai/z/openapi/api/chat/ChatApi.java
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package ai.z.openapi.api.chat;
|
||||
|
||||
import ai.z.openapi.service.model.ChatCompletionCreateParams;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
public interface ChatApi {
|
||||
|
||||
@Streaming
|
||||
@POST("chat/completions")
|
||||
Call<ResponseBody> createChatCompletionStream(@Body ChatCompletionCreateParams request);
|
||||
|
||||
@POST("async/chat/completions")
|
||||
Single<ModelData> createChatCompletionAsync(@Body ChatCompletionCreateParams request);
|
||||
|
||||
@POST("chat/completions")
|
||||
Single<ModelData> createChatCompletion(@Body ChatCompletionCreateParams request);
|
||||
|
||||
@GET("async-result/{id}")
|
||||
Single<ModelData> queryAsyncResult(@Path("id") String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package ai.z.openapi.api.embedding;
|
||||
|
||||
import ai.z.openapi.service.embedding.EmbeddingCreateParams;
|
||||
import ai.z.openapi.service.embedding.EmbeddingResult;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface EmbeddingApi {
|
||||
|
||||
@POST("embeddings")
|
||||
Single<EmbeddingResult> createEmbeddings(@Body EmbeddingCreateParams request);
|
||||
|
||||
}
|
||||
37
core/src/main/java/ai/z/openapi/api/file/FileApi.java
Normal file
37
core/src/main/java/ai/z/openapi/api/file/FileApi.java
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package ai.z.openapi.api.file;
|
||||
|
||||
import ai.z.openapi.service.file.File;
|
||||
import ai.z.openapi.service.file.FileDeleted;
|
||||
import ai.z.openapi.service.file.QueryFileResult;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
public interface FileApi {
|
||||
|
||||
@POST("files")
|
||||
Single<File> uploadFile(@Body MultipartBody multipartBody);
|
||||
|
||||
@GET("files/{file_id}")
|
||||
Single<File> retrieveFile(@Path("file_id") String fileId);
|
||||
|
||||
@DELETE("files/{file_id}")
|
||||
Single<FileDeleted> deletedFile(@Path("file_id") String fileId);
|
||||
|
||||
@GET("files")
|
||||
Single<QueryFileResult> queryFileList(@Query("after") String after, @Query("purpose") String purpose,
|
||||
@Query("order") String order, @Query("limit") Integer limit);
|
||||
|
||||
@Streaming
|
||||
@GET("files/{file_id}/content")
|
||||
Call<ResponseBody> fileContent(@Path("file_id") String fileId);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package ai.z.openapi.api.fine_tuning;
|
||||
|
||||
import ai.z.openapi.service.fine_turning.FineTunedModelsStatus;
|
||||
import ai.z.openapi.service.fine_turning.FineTuningEvent;
|
||||
import ai.z.openapi.service.fine_turning.FineTuningJob;
|
||||
import ai.z.openapi.service.fine_turning.FineTuningJobRequest;
|
||||
import ai.z.openapi.service.fine_turning.PersonalFineTuningJob;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface FineTuningApi {
|
||||
|
||||
@POST("fine_tuning/jobs")
|
||||
Single<FineTuningJob> createFineTuningJob(@Body FineTuningJobRequest request);
|
||||
|
||||
@GET("fine_tuning/jobs/{fine_tuning_job_id}/events")
|
||||
Single<FineTuningEvent> listFineTuningJobEvents(@Path("fine_tuning_job_id") String fineTuningJobId,
|
||||
@Query("limit") Integer limit, @Query("after") String after);
|
||||
|
||||
@GET("fine_tuning/jobs/{fine_tuning_job_id}")
|
||||
Single<FineTuningJob> retrieveFineTuningJob(@Path("fine_tuning_job_id") String fineTuningJobId,
|
||||
@Query("limit") Integer limit, @Query("after") String after);
|
||||
|
||||
@GET("fine_tuning/jobs")
|
||||
Single<PersonalFineTuningJob> queryPersonalFineTuningJobs(@Query("limit") Integer limit,
|
||||
@Query("after") String after);
|
||||
|
||||
@POST("fine_tuning/jobs/{fine_tuning_job_id}/cancel")
|
||||
Single<FineTuningJob> cancelFineTuningJob(@Path("fine_tuning_job_id") String fineTuningJobId);
|
||||
|
||||
@DELETE("fine_tuning/jobs/{fine_tuning_job_id}")
|
||||
Single<FineTuningJob> deleteFineTuningJob(@Path("fine_tuning_job_id") String fineTuningJobId);
|
||||
|
||||
@DELETE("fine_tuning/fine_tuned_models/{fine_tuned_model}")
|
||||
Single<FineTunedModelsStatus> deleteFineTuningModel(@Path("fine_tuned_model") String fineTunedModel);
|
||||
|
||||
}
|
||||
14
core/src/main/java/ai/z/openapi/api/images/ImagesApi.java
Normal file
14
core/src/main/java/ai/z/openapi/api/images/ImagesApi.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package ai.z.openapi.api.images;
|
||||
|
||||
import ai.z.openapi.service.image.CreateImageRequest;
|
||||
import ai.z.openapi.service.image.ImageResult;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface ImagesApi {
|
||||
|
||||
@POST("images/generations")
|
||||
Single<ImageResult> createImage(@Body CreateImageRequest request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package ai.z.openapi.api.knowledge;
|
||||
|
||||
import ai.z.openapi.service.knowledge.KnowledgeBaseParams;
|
||||
import ai.z.openapi.service.knowledge.KnowledgeInfo;
|
||||
import ai.z.openapi.service.knowledge.KnowledgePage;
|
||||
import ai.z.openapi.service.knowledge.KnowledgeUsed;
|
||||
import io.reactivex.Single;
|
||||
|
||||
import retrofit2.Response;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface KnowledgeApi {
|
||||
|
||||
@POST("knowledge")
|
||||
Single<KnowledgeInfo> knowledgeCreate(@Body KnowledgeBaseParams knowledgeBaseParams);
|
||||
|
||||
@PUT("knowledge/{knowledge_id}")
|
||||
Single<Response<Void>> knowledgeModify(@Path("knowledge_id") String knowledge_id,
|
||||
@Body KnowledgeBaseParams knowledgeBaseParams);
|
||||
|
||||
@GET("knowledge")
|
||||
Single<KnowledgePage> knowledgeQuery(@Query("page") Integer page, @Query("size") Integer size);
|
||||
|
||||
@DELETE("knowledge/{knowledge_id}")
|
||||
Single<Response<Void>> knowledgeDelete(@Path("knowledge_id") String knowledge_id);
|
||||
|
||||
@GET("knowledge/capacity")
|
||||
Single<KnowledgeUsed> knowledgeUsed();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ai.z.openapi.api.knowledge.document;
|
||||
|
||||
import ai.z.openapi.service.knowledge.document.DocumentData;
|
||||
import ai.z.openapi.service.knowledge.document.DocumentEditParams;
|
||||
import ai.z.openapi.service.knowledge.document.DocumentObject;
|
||||
import ai.z.openapi.service.knowledge.document.DocumentPage;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.MultipartBody;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.DELETE;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface DocumentApi {
|
||||
|
||||
@POST("files")
|
||||
Single<DocumentObject> createDocument(@Body MultipartBody document);
|
||||
|
||||
@PUT("document/{document_id}")
|
||||
Single<Response<Void>> modifyDocument(@Path("document_id") String documentId,
|
||||
@Body DocumentEditParams documentEditParams);
|
||||
|
||||
@DELETE("document/{document_id}")
|
||||
Single<Response<Void>> deleteDocument(@Path("document_id") String documentId);
|
||||
|
||||
@GET("files")
|
||||
Single<DocumentPage> queryDocumentList(@Query("knowledge_id") String knowledgeId, @Query("purpose") String purpose,
|
||||
@Query("page") Integer page, @Query("limit") Integer limit, @Query("order") String order);
|
||||
|
||||
@GET("document/{document_id}")
|
||||
Single<DocumentData> retrieveDocument(@Path("document_id") String documentId);
|
||||
|
||||
}
|
||||
21
core/src/main/java/ai/z/openapi/api/tools/ToolsApi.java
Normal file
21
core/src/main/java/ai/z/openapi/api/tools/ToolsApi.java
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package ai.z.openapi.api.tools;
|
||||
|
||||
import ai.z.openapi.service.tools.WebSearchParamsRequest;
|
||||
import ai.z.openapi.service.tools.WebSearchPro;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Streaming;
|
||||
|
||||
public interface ToolsApi {
|
||||
|
||||
@Streaming
|
||||
@POST("tools")
|
||||
Call<ResponseBody> webSearchStreaming(@Body WebSearchParamsRequest request);
|
||||
|
||||
@POST("tools")
|
||||
Single<WebSearchPro> webSearch(@Body WebSearchParamsRequest request);
|
||||
|
||||
}
|
||||
19
core/src/main/java/ai/z/openapi/api/videos/VideosApi.java
Normal file
19
core/src/main/java/ai/z/openapi/api/videos/VideosApi.java
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package ai.z.openapi.api.videos;
|
||||
|
||||
import ai.z.openapi.service.videos.VideoCreateParams;
|
||||
import ai.z.openapi.service.videos.VideoObject;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
public interface VideosApi {
|
||||
|
||||
@POST("videos/generations")
|
||||
Single<VideoObject> videoGenerations(@Body VideoCreateParams request);
|
||||
|
||||
@GET("async-result/{id}")
|
||||
Single<VideoObject> videoGenerationsResult(@Path("id") String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package ai.z.openapi.api.web_search;
|
||||
|
||||
import ai.z.openapi.service.web_search.WebSearchDTO;
|
||||
import ai.z.openapi.service.web_search.WebSearchRequest;
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface WebSearchApi {
|
||||
|
||||
@POST("web_search")
|
||||
Single<WebSearchDTO> webSearch(@Body WebSearchRequest request);
|
||||
|
||||
}
|
||||
155
core/src/main/java/ai/z/openapi/core/Constants.java
Normal file
155
core/src/main/java/ai/z/openapi/core/Constants.java
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
package ai.z.openapi.core;
|
||||
|
||||
/**
|
||||
* Constants class containing all the configuration values and model identifiers used
|
||||
* throughout the Z.AI OpenAPI SDK.
|
||||
*
|
||||
* This class provides centralized access to: - API base URLs - Model identifiers for
|
||||
* different AI capabilities - Invocation method constants
|
||||
*
|
||||
* @author Z.AI SDK Team
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
// Private constructor to prevent instantiation
|
||||
private Constants() {
|
||||
throw new UnsupportedOperationException("Constants class cannot be instantiated");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// API Configuration
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Base URL for the ZHIPU AI OpenAPI service. All API requests will be made to
|
||||
* endpoints under this base URL.
|
||||
*/
|
||||
public static final String ZHIPU_AI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4/";
|
||||
|
||||
/**
|
||||
* Base URL for the Z.AI OpenAPI service. All API requests will be made to endpoints
|
||||
* under this base URL.
|
||||
*/
|
||||
public static final String Z_AI_BASE_URL = "https://api.z.ai/api/paas/v4/";
|
||||
|
||||
// =============================================================================
|
||||
// Text Generation Models
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* GLM-4 Plus model - Enhanced version with improved capabilities.
|
||||
*/
|
||||
public static final String ModelChatGLM4Plus = "glm-4-plus";
|
||||
|
||||
/**
|
||||
* GLM-4 Air model - Lightweight version optimized for speed.
|
||||
*/
|
||||
public static final String ModelChatGLM4Air = "glm-4-air";
|
||||
|
||||
/**
|
||||
* GLM-4 Flash model - Ultra-fast response model.
|
||||
*/
|
||||
public static final String ModelChatGLM4Flash = "glm-4-flash";
|
||||
|
||||
/**
|
||||
* GLM-4 standard model - Balanced performance and capability.
|
||||
*/
|
||||
public static final String ModelChatGLM4 = "glm-4";
|
||||
|
||||
/**
|
||||
* GLM-4 model version 0520 - Specific version release.
|
||||
*/
|
||||
public static final String ModelChatGLM40520 = "glm-4-0520";
|
||||
|
||||
/**
|
||||
* GLM-4 AirX model - Extended Air model with additional features.
|
||||
*/
|
||||
public static final String ModelChatGLM4Airx = "glm-4-airx";
|
||||
|
||||
/**
|
||||
* GLM-4 Long model - Optimized for long-context conversations.
|
||||
*/
|
||||
public static final String ModelChatGLMLong = "glm-4-long";
|
||||
|
||||
/**
|
||||
* GLM-4 Voice model - Specialized for voice-related tasks.
|
||||
*/
|
||||
public static final String ModelChatGLM4Voice = "glm-4-voice";
|
||||
|
||||
// =============================================================================
|
||||
// Vision Models (Image Understanding)
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* GLM-4V Plus model - Enhanced vision model for image understanding.
|
||||
*/
|
||||
public static final String ModelChatGLM4VPlus = "glm-4v-plus";
|
||||
|
||||
/**
|
||||
* GLM-4V standard model - Standard vision model for image analysis.
|
||||
*/
|
||||
public static final String ModelChatGLM4V = "glm-4v";
|
||||
|
||||
// =============================================================================
|
||||
// Image Generation Models
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* CogView-3 Plus model - Enhanced image generation capabilities.
|
||||
*/
|
||||
public static final String ModelCogView3Plus = "cogview-3-plus";
|
||||
|
||||
/**
|
||||
* CogView-3 standard model - Standard image generation model.
|
||||
*/
|
||||
public static final String ModelCogView = "cogview-3";
|
||||
|
||||
// =============================================================================
|
||||
// Embedding Models
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Embedding model version 2 - Text embedding generation.
|
||||
*/
|
||||
public static final String ModelEmbedding2 = "embedding-2";
|
||||
|
||||
/**
|
||||
* Embedding model version 3 - Latest text embedding generation.
|
||||
*/
|
||||
public static final String ModelEmbedding3 = "embedding-3";
|
||||
|
||||
// =============================================================================
|
||||
// Specialized Models
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* CharGLM-3 model - Anthropomorphic character interaction model.
|
||||
*/
|
||||
public static final String ModelCharGLM3 = "charglm-3";
|
||||
|
||||
/**
|
||||
* CogTTS model - Text-to-Speech synthesis model.
|
||||
*/
|
||||
public static final String ModelTTS = "cogtts";
|
||||
|
||||
// =============================================================================
|
||||
// API Invocation Methods
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Asynchronous invocation method - For non-blocking API calls.
|
||||
*/
|
||||
public static final String INVOKE_METHOD_ASYNC = "async-invoke";
|
||||
|
||||
/**
|
||||
* Server-Sent Events invocation method - For streaming responses.
|
||||
*/
|
||||
public static final String INVOKE_METHOD_SSE = "sse-invoke";
|
||||
|
||||
/**
|
||||
* Standard synchronous invocation method - For blocking API calls.
|
||||
*/
|
||||
public static final String INVOKE_METHOD = "invoke";
|
||||
|
||||
}
|
||||
27
core/src/main/java/ai/z/openapi/core/cache/ICache.java
vendored
Normal file
27
core/src/main/java/ai/z/openapi/core/cache/ICache.java
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package ai.z.openapi.core.cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Token cache interface with default LocalCache implementation. Can be replaced with
|
||||
* distributed cache (e.g., Redis) as needed.
|
||||
*/
|
||||
public interface ICache {
|
||||
|
||||
/**
|
||||
* Retrieves cached value by key.
|
||||
* @param key the cache key
|
||||
* @return cached value or empty string if not found or expired
|
||||
*/
|
||||
String get(String key);
|
||||
|
||||
/**
|
||||
* Sets cache value with expiration time.
|
||||
* @param key the cache key
|
||||
* @param value the value to cache
|
||||
* @param expire expiration duration
|
||||
* @param timeUnit time unit for expiration
|
||||
*/
|
||||
void set(String key, String value, int expire, TimeUnit timeUnit);
|
||||
|
||||
}
|
||||
81
core/src/main/java/ai/z/openapi/core/cache/LocalCache.java
vendored
Normal file
81
core/src/main/java/ai/z/openapi/core/cache/LocalCache.java
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package ai.z.openapi.core.cache;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Thread-safe local cache implementation using ConcurrentHashMap. Provides basic caching
|
||||
* functionality with expiration support.
|
||||
*/
|
||||
public class LocalCache implements ICache {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalCache.class);
|
||||
|
||||
private static final ConcurrentMap<String, Value> CACHE = new ConcurrentHashMap<>(8);
|
||||
|
||||
/**
|
||||
* Private constructor to prevent direct instantiation.
|
||||
*/
|
||||
private LocalCache() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets singleton instance of LocalCache.
|
||||
* @return LocalCache instance
|
||||
*/
|
||||
public static LocalCache getInstance() {
|
||||
return Inner.LOCAL_CACHE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
Value v = LocalCache.CACHE.get(key);
|
||||
if (v == null || new Date().after(v.end)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
log.debug("Retrieved key: {}, time left: {}s", key, (v.end.getTime() - new Date().getTime()) / 1000);
|
||||
return v.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, int expire, TimeUnit timeUnit) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.SECOND, (int) timeUnit.toSeconds(expire));
|
||||
Value v = new Value(value, calendar.getTime());
|
||||
log.debug("Cached key: {}, expire time: {}", key, calendar.getTime());
|
||||
LocalCache.CACHE.put(key, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal value wrapper with expiration time.
|
||||
*/
|
||||
private static class Value {
|
||||
|
||||
final String value;
|
||||
|
||||
final Date end;
|
||||
|
||||
public Value(String value, Date time) {
|
||||
this.value = value;
|
||||
this.end = time;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton holder pattern for thread-safe lazy initialization.
|
||||
*/
|
||||
private static class Inner {
|
||||
|
||||
private static final LocalCache LOCAL_CACHE = new LocalCache();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
400
core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java
Normal file
400
core/src/main/java/ai/z/openapi/core/config/ZaiConfig.java
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
package ai.z.openapi.core.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static ai.z.openapi.core.Constants.Z_AI_BASE_URL;
|
||||
|
||||
/**
|
||||
* Configuration class for ZAI SDK containing API credentials, JWT settings, HTTP client
|
||||
* configurations, and cache settings. Supports reading configuration values from
|
||||
* environment variables with memory values taking priority.
|
||||
*/
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ZaiConfig {
|
||||
|
||||
// Environment variable names
|
||||
private static final String ENV_BASE_URL = "ZAI_BASE_URL";
|
||||
|
||||
private static final String ENV_API_KEY = "ZAI_API_KEY";
|
||||
|
||||
private static final String ENV_EXPIRE_MILLIS = "ZAI_EXPIRE_MILLIS";
|
||||
|
||||
private static final String ENV_ALG = "ZAI_ALG";
|
||||
|
||||
private static final String ENV_DISABLE_TOKEN_CACHE = "ZAI_DISABLE_TOKEN_CACHE";
|
||||
|
||||
private static final String ENV_CONNECTION_POOL_MAX_IDLE = "ZAI_CONNECTION_POOL_MAX_IDLE";
|
||||
|
||||
private static final String ENV_CONNECTION_POOL_KEEP_ALIVE = "ZAI_CONNECTION_POOL_KEEP_ALIVE";
|
||||
|
||||
private static final String ENV_REQUEST_TIMEOUT = "ZAI_REQUEST_TIMEOUT";
|
||||
|
||||
private static final String ENV_CONNECT_TIMEOUT = "ZAI_CONNECT_TIMEOUT";
|
||||
|
||||
private static final String ENV_READ_TIMEOUT = "ZAI_READ_TIMEOUT";
|
||||
|
||||
private static final String ENV_WRITE_TIMEOUT = "ZAI_WRITE_TIMEOUT";
|
||||
|
||||
/**
|
||||
* Base URL for API endpoints.
|
||||
*/
|
||||
private String baseUrl;
|
||||
|
||||
/**
|
||||
* Combined API secret key in format: {apiId}.{apiSecret}
|
||||
*/
|
||||
private String apiKey;
|
||||
|
||||
/**
|
||||
* API id component.
|
||||
*/
|
||||
private String apiId;
|
||||
|
||||
/**
|
||||
* API secret component.
|
||||
*/
|
||||
private String apiSecret;
|
||||
|
||||
/**
|
||||
* JWT token expiration time in milliseconds (default: 30 minutes).
|
||||
*/
|
||||
private int expireMillis = 30 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* JWT encryption algorithm (default: HS256).
|
||||
*/
|
||||
private String alg = "HS256";
|
||||
|
||||
/**
|
||||
* Flag to disable token caching.
|
||||
*/
|
||||
private boolean disableTokenCache;
|
||||
|
||||
/**
|
||||
* Maximum number of idle connections in the connection pool.
|
||||
*/
|
||||
private int connectionPoolMaxIdleConnections = 5;
|
||||
|
||||
/**
|
||||
* Keep alive duration for connections in the pool (in seconds).
|
||||
*/
|
||||
private long connectionPoolKeepAliveDuration = 1;
|
||||
|
||||
/**
|
||||
* Time unit for connection pool keep alive duration.
|
||||
*/
|
||||
private TimeUnit connectionPoolTimeUnit = TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* Request timeout in specified time unit.
|
||||
*/
|
||||
private int requestTimeOut = 300;
|
||||
|
||||
/**
|
||||
* Connection timeout in specified time unit.
|
||||
*/
|
||||
private int connectTimeout = 100;
|
||||
|
||||
/**
|
||||
* Read timeout in specified time unit.
|
||||
*/
|
||||
private int readTimeout = 100;
|
||||
|
||||
/**
|
||||
* Write timeout in specified time unit.
|
||||
*/
|
||||
private int writeTimeout = 100;
|
||||
|
||||
/**
|
||||
* Time unit for timeout configurations.
|
||||
*/
|
||||
private TimeUnit timeOutTimeUnit = TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* Source channel identifier for request tracking.
|
||||
*/
|
||||
private String source_channel = "java-sdk";
|
||||
|
||||
/**
|
||||
* Constructor with combined API secret key.
|
||||
* @param apiKey combined secret key in format {apiKey}.{apiSecret}
|
||||
* @throws RuntimeException if apiSecretKey format is invalid
|
||||
*/
|
||||
public ZaiConfig(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
String[] arrStr = apiKey.split("\\.");
|
||||
if (arrStr.length != 2) {
|
||||
throw new RuntimeException("invalid apiSecretKey");
|
||||
}
|
||||
this.apiId = arrStr[0];
|
||||
this.apiSecret = arrStr[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets API key and parses it into id and secret components.
|
||||
* @param apiKey combined secret key in format {apiId}.{apiSecret}
|
||||
* @throws RuntimeException if apiSecretKey format is invalid
|
||||
*/
|
||||
public void setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
String[] arrStr = apiKey.split("\\.");
|
||||
if (arrStr.length != 2) {
|
||||
throw new RuntimeException("invalid api Key");
|
||||
}
|
||||
this.apiId = arrStr[0];
|
||||
this.apiSecret = arrStr[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets base URL with system property and environment variable fallback.
|
||||
*/
|
||||
public String getBaseUrl() {
|
||||
if (baseUrl != null) {
|
||||
return baseUrl;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_BASE_URL);
|
||||
propValue = propValue != null ? propValue : System.getenv(ENV_BASE_URL);
|
||||
return propValue != null ? propValue : Z_AI_BASE_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets API secret key with system property and environment variable fallback.
|
||||
*/
|
||||
public String getApiKey() {
|
||||
if (apiKey != null && !apiKey.isEmpty()) {
|
||||
return apiKey;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_API_KEY);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_API_KEY);
|
||||
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.
|
||||
*/
|
||||
public int getExpireMillis() {
|
||||
if (expireMillis != 30 * 60 * 1000) { // If not default value
|
||||
return expireMillis;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_EXPIRE_MILLIS);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_EXPIRE_MILLIS);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return expireMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets algorithm with system property and environment variable fallback.
|
||||
*/
|
||||
public String getAlg() {
|
||||
if (!"HS256".equals(alg)) {
|
||||
return alg;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_ALG);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_ALG);
|
||||
return value != null ? value : alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets disable token cache flag with system property and environment variable
|
||||
* fallback.
|
||||
*/
|
||||
public boolean isDisableTokenCache() {
|
||||
if (disableTokenCache) {
|
||||
return true;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_DISABLE_TOKEN_CACHE);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_DISABLE_TOKEN_CACHE);
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets connection pool max idle connections with system property and environment
|
||||
* variable fallback.
|
||||
*/
|
||||
public int getConnectionPoolMaxIdleConnections() {
|
||||
if (connectionPoolMaxIdleConnections != 5) { // If not default value
|
||||
return connectionPoolMaxIdleConnections;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_CONNECTION_POOL_MAX_IDLE);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_CONNECTION_POOL_MAX_IDLE);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return connectionPoolMaxIdleConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets connection pool keep alive duration with system property and environment
|
||||
* variable fallback.
|
||||
*/
|
||||
public long getConnectionPoolKeepAliveDuration() {
|
||||
if (connectionPoolKeepAliveDuration != 1) { // If not default value
|
||||
return connectionPoolKeepAliveDuration;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_CONNECTION_POOL_KEEP_ALIVE);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_CONNECTION_POOL_KEEP_ALIVE);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return connectionPoolKeepAliveDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets connection pool time unit (always returns the set value or default).
|
||||
*/
|
||||
public TimeUnit getConnectionPoolTimeUnit() {
|
||||
return connectionPoolTimeUnit != null ? connectionPoolTimeUnit : TimeUnit.SECONDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets request timeout with system property and environment variable fallback.
|
||||
*/
|
||||
public int getRequestTimeOut() {
|
||||
if (requestTimeOut != 300) {
|
||||
return requestTimeOut;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_REQUEST_TIMEOUT);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_REQUEST_TIMEOUT);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return requestTimeOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets connect timeout with system property and environment variable fallback.
|
||||
*/
|
||||
public int getConnectTimeout() {
|
||||
if (connectTimeout != 100) {
|
||||
return connectTimeout;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_CONNECT_TIMEOUT);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_CONNECT_TIMEOUT);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets read timeout with system property and environment variable fallback.
|
||||
*/
|
||||
public int getReadTimeout() {
|
||||
if (readTimeout != 100) {
|
||||
return readTimeout;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_READ_TIMEOUT);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_READ_TIMEOUT);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets write timeout with system property and environment variable fallback.
|
||||
*/
|
||||
public int getWriteTimeout() {
|
||||
if (writeTimeout != 100) {
|
||||
return writeTimeout;
|
||||
}
|
||||
String propValue = System.getProperty(ENV_WRITE_TIMEOUT);
|
||||
String value = propValue != null ? propValue : System.getenv(ENV_WRITE_TIMEOUT);
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// Return default value if parsing fails
|
||||
}
|
||||
}
|
||||
return writeTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets timeout time unit (always returns the set value or null).
|
||||
*/
|
||||
public TimeUnit getTimeOutTimeUnit() {
|
||||
return timeOutTimeUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets source channel with system property.
|
||||
*/
|
||||
public String getSource_channel() {
|
||||
return source_channel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package ai.z.openapi.core.model;
|
||||
|
||||
public interface ClientRequest<T> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ai.z.openapi.core.model;
|
||||
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
|
||||
public interface ClientResponse<T> {
|
||||
|
||||
T getData();
|
||||
|
||||
void setData(T data);
|
||||
|
||||
void setCode(int code);
|
||||
|
||||
void setMsg(String msg);
|
||||
|
||||
void setSuccess(boolean b);
|
||||
|
||||
void setError(ChatError chatError);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ai.z.openapi.core.model;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
/**
|
||||
* Client response interface with reactive stream support. Extends ClientResponse to
|
||||
* provide Flowable stream functionality.
|
||||
*
|
||||
* @param <T> response data type
|
||||
*/
|
||||
public interface FlowableClientResponse<T> extends ClientResponse<T> {
|
||||
|
||||
/**
|
||||
* Sets the reactive stream for this response.
|
||||
* @param stream Flowable stream containing response data
|
||||
*/
|
||||
void setFlowable(Flowable<T> stream);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package ai.z.openapi.core.response;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import okhttp3.ResponseBody;
|
||||
import okio.BufferedSource;
|
||||
|
||||
public class HttpxBinaryResponseContent implements Closeable {
|
||||
|
||||
private final retrofit2.Response<ResponseBody> response;
|
||||
|
||||
public HttpxBinaryResponseContent(retrofit2.Response<ResponseBody> response) {
|
||||
if (response == null || response.body() == null) {
|
||||
throw new IllegalArgumentException("Response or ResponseBody cannot be null");
|
||||
}
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public byte[] getContent() throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
try (BufferedSource source = response.body().source()) {
|
||||
return source.readByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public String getText() throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
try (BufferedSource source = response.body().source()) {
|
||||
return source.readUtf8();
|
||||
}
|
||||
}
|
||||
|
||||
public String getEncoding() {
|
||||
return response.body() != null && response.body().contentType() != null
|
||||
? Objects.requireNonNull(Objects.requireNonNull(response.body().contentType()).charset()).toString()
|
||||
: null;
|
||||
}
|
||||
|
||||
public Iterator<byte[]> iterBytes(int chunkSize) throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
return new Iterator<byte[]>() {
|
||||
final BufferedSource source = response.body().source();
|
||||
|
||||
final byte[] buffer = new byte[chunkSize];
|
||||
|
||||
boolean hasMore = true;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
if (source.exhausted()) {
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
hasMore = false;
|
||||
}
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] next() {
|
||||
try {
|
||||
source.read(buffer);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Handle the exception
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Iterator<String> iterText(int chunkSize) throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
return new Iterator<String>() {
|
||||
final BufferedSource source = response.body().source();
|
||||
|
||||
final byte[] buffer = new byte[chunkSize];
|
||||
|
||||
boolean hasMore = true;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
if (source.exhausted()) {
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
hasMore = false;
|
||||
}
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
try {
|
||||
int bytesRead = source.read(buffer);
|
||||
return new String(buffer, 0, bytesRead);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Handle the exception
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void writeToFile(String file) throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
|
||||
try (BufferedSource source = response.body().source(); FileOutputStream fos = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = source.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void streamToFile(String file, int chunkSize) throws IOException {
|
||||
if (response.body() == null) {
|
||||
throw new IOException("ResponseBody is null");
|
||||
}
|
||||
|
||||
try (BufferedSource source = response.body().source(); FileOutputStream fos = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[chunkSize];
|
||||
int bytesRead;
|
||||
while ((bytesRead = source.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (response.body() != null) {
|
||||
response.body().close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ai.z.openapi.core.token;
|
||||
|
||||
import ai.z.openapi.core.config.ZaiConfig;
|
||||
import ai.z.openapi.utils.StringUtils;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* OkHttp Interceptor that adds an authorization token header
|
||||
*/
|
||||
public class AuthenticationInterceptor implements Interceptor {
|
||||
|
||||
private final ZaiConfig config;
|
||||
|
||||
public AuthenticationInterceptor(ZaiConfig config) {
|
||||
Objects.requireNonNull(config.getApiKey(), "Z.ai token required");
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
String accessToken;
|
||||
if (this.config.isDisableTokenCache()) {
|
||||
accessToken = this.config.getApiKey();
|
||||
}
|
||||
else {
|
||||
TokenManager tokenManager = GlobalTokenManager.getTokenManagerV4();
|
||||
accessToken = tokenManager.getToken(this.config);
|
||||
}
|
||||
String source_channel = "java-sdk";
|
||||
if (StringUtils.isNotEmpty(config.getSource_channel())) {
|
||||
source_channel = config.getSource_channel();
|
||||
}
|
||||
Request request = chain.request()
|
||||
.newBuilder()
|
||||
.header("Authorization", "Bearer " + accessToken)
|
||||
.header("x-source-channel", source_channel)
|
||||
.header("Accept-Language", "en-US,en")
|
||||
.build();
|
||||
return chain.proceed(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ai.z.openapi.core.token;
|
||||
|
||||
import ai.z.openapi.core.cache.LocalCache;
|
||||
|
||||
/**
|
||||
* Global token manager providing singleton access to TokenManager instance. Uses
|
||||
* LocalCache as default cache implementation.
|
||||
*/
|
||||
public class GlobalTokenManager {
|
||||
|
||||
/**
|
||||
* Global TokenManager instance with LocalCache.
|
||||
*/
|
||||
private static volatile TokenManager globalTokenManager = new TokenManager(LocalCache.getInstance());
|
||||
|
||||
/**
|
||||
* Gets the global TokenManager instance.
|
||||
* @return TokenManager instance
|
||||
*/
|
||||
public static TokenManager getTokenManagerV4() {
|
||||
return globalTokenManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom TokenManager implementation.
|
||||
* @param tokenManager custom TokenManager instance
|
||||
*/
|
||||
public static void setTokenManager(TokenManager tokenManager) {
|
||||
globalTokenManager = tokenManager;
|
||||
}
|
||||
|
||||
}
|
||||
100
core/src/main/java/ai/z/openapi/core/token/TokenManager.java
Normal file
100
core/src/main/java/ai/z/openapi/core/token/TokenManager.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package ai.z.openapi.core.token;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import ai.z.openapi.core.config.ZaiConfig;
|
||||
import ai.z.openapi.core.cache.ICache;
|
||||
import ai.z.openapi.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* JWT token manager for handling token generation and caching.
|
||||
*/
|
||||
public class TokenManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TokenManager.class);
|
||||
|
||||
private final ICache cache;
|
||||
|
||||
private static final String TOKEN_KEY_PREFIX = "zai_oapi_token";
|
||||
|
||||
/**
|
||||
* Additional delay time (5 minutes) to prevent token expiration issues.
|
||||
*/
|
||||
private static final Long DELAY_EXPIRE_TIME = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* Constructs TokenManager with specified cache implementation.
|
||||
* @param cache cache implementation for token storage
|
||||
*/
|
||||
public TokenManager(ICache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets valid JWT token, either from cache or generates new one.
|
||||
* @param config ZAI configuration containing API credentials
|
||||
* @return valid JWT token
|
||||
*/
|
||||
public String getToken(ZaiConfig config) {
|
||||
String tokenCacheKey = genTokenCacheKey(config.getApiId());
|
||||
String cacheToken = cache.get(tokenCacheKey);
|
||||
if (StringUtils.isNotEmpty(cacheToken)) {
|
||||
return cacheToken;
|
||||
}
|
||||
String newToken = createJwt(config);
|
||||
cache.set(tokenCacheKey, newToken, config.getExpireMillis(), TimeUnit.MILLISECONDS);
|
||||
return newToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates JWT token using HMAC256 algorithm.
|
||||
* @param config ZAI configuration
|
||||
* @return JWT token string or null if creation fails
|
||||
*/
|
||||
private static String createJwt(ZaiConfig config) {
|
||||
Algorithm alg;
|
||||
String algId = config.getAlg();
|
||||
if ("HS256".equals(algId)) {
|
||||
try {
|
||||
alg = Algorithm.HMAC256(config.getApiSecret().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Failed to create HMAC256 algorithm", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Currently only HS256 is supported
|
||||
logger.error("Algorithm: {} not supported", algId);
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
// here the api_key is the apiId
|
||||
payload.put("api_key", config.getApiId());
|
||||
payload.put("exp", System.currentTimeMillis() + config.getExpireMillis() + DELAY_EXPIRE_TIME);
|
||||
payload.put("timestamp", Calendar.getInstance().getTimeInMillis());
|
||||
Map<String, Object> headerClaims = new HashMap<>();
|
||||
headerClaims.put("alg", "HS256");
|
||||
headerClaims.put("sign_type", "SIGN");
|
||||
return JWT.create().withPayload(payload).withHeader(headerClaims).sign(alg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates cache key for token storage.
|
||||
* @param apiKey API key
|
||||
* @return formatted cache key
|
||||
*/
|
||||
private String genTokenCacheKey(String apiKey) {
|
||||
return String.format("%s-%s", TOKEN_KEY_PREFIX, apiKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package ai.z.openapi.service;
|
||||
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.core.model.FlowableClientResponse;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.model.ResponseBodyCallback;
|
||||
import ai.z.openapi.service.model.SSE;
|
||||
import ai.z.openapi.service.model.ZAiError;
|
||||
import ai.z.openapi.service.model.ZAiHttpException;
|
||||
import ai.z.openapi.utils.FlowableRequestSupplier;
|
||||
import ai.z.openapi.utils.RequestSupplier;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.reactivex.BackpressureStrategy;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.HttpException;
|
||||
import retrofit2.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Abstract base service class that provides common functionality for API client
|
||||
* implementations. This class handles request execution, response processing, and error
|
||||
* handling for both synchronous and streaming API calls.
|
||||
*/
|
||||
public abstract class AbstractClientBaseService {
|
||||
|
||||
protected final static Logger logger = LoggerFactory.getLogger(AbstractClientBaseService.class);
|
||||
|
||||
protected static final ObjectMapper mapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
|
||||
/**
|
||||
* Executes a synchronous API request.
|
||||
* @param <Data> the type of data returned by the API
|
||||
* @param <Param> the type of parameters sent to the API
|
||||
* @param <TReq> the type of the request object
|
||||
* @param <TResp> the type of the response object
|
||||
* @param request the request object containing parameters
|
||||
* @param requestSupplier the supplier that creates the API call
|
||||
* @param tRespClass the class of the response type
|
||||
* @return the response object containing the API result
|
||||
*/
|
||||
public abstract <Data, Param, TReq extends ClientRequest<Param>, TResp extends ClientResponse<Data>> TResp executeRequest(
|
||||
TReq request, RequestSupplier<Param, Data> requestSupplier, Class<TResp> tRespClass);
|
||||
|
||||
/**
|
||||
* Executes a streaming API request that returns a continuous stream of data.
|
||||
* @param <Data> the type of data returned by the API stream
|
||||
* @param <Param> the type of parameters sent to the API
|
||||
* @param <TReq> the type of the request object
|
||||
* @param <TResp> the type of the streaming response object
|
||||
* @param request the request object containing parameters
|
||||
* @param requestSupplier the supplier that creates the streaming API call
|
||||
* @param tRespClass the class of the response type
|
||||
* @param tDataClass the class of the data type in the stream
|
||||
* @return the streaming response object containing the API result stream
|
||||
*/
|
||||
public abstract <Data, Param, TReq extends ClientRequest<Param>, TResp extends FlowableClientResponse<Data>> TResp streamRequest(
|
||||
TReq request, FlowableRequestSupplier<Param, Call<ResponseBody>> requestSupplier, Class<TResp> tRespClass,
|
||||
Class<Data> tDataClass);
|
||||
|
||||
/**
|
||||
* Executes a Single API call synchronously and handles errors.
|
||||
* @param <T> the type of the response
|
||||
* @param apiCall the Single API call to execute
|
||||
* @return the response from the API call
|
||||
* @throws ZAiHttpException if an HTTP error occurs with a parseable error body
|
||||
* @throws HttpException if an HTTP error occurs that cannot be parsed
|
||||
*/
|
||||
public static <T> T execute(Single<T> apiCall) {
|
||||
try {
|
||||
T response = apiCall.blockingGet();
|
||||
|
||||
// Check status code if the response is a Response type object
|
||||
if (response instanceof Response) {
|
||||
handleResponse((Response<?>) response);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (HttpException e) {
|
||||
logger.error("HTTP exception: {}", e.getMessage());
|
||||
try {
|
||||
if (e.response() == null || e.response().errorBody() == null) {
|
||||
throw e;
|
||||
}
|
||||
String errorBody = e.response().errorBody().string();
|
||||
|
||||
ZAiError error = mapper.readValue(errorBody, ZAiError.class);
|
||||
|
||||
throw new ZAiHttpException(error, e, e.code());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// couldn't parse ZAiError error
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles HTTP response and throws exception if not successful.
|
||||
* @param response the HTTP response to handle
|
||||
* @throws HttpException if the response is not successful
|
||||
*/
|
||||
private static void handleResponse(Response<?> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new HttpException(response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a streaming Flowable that maps SSE data to the specified class type.
|
||||
* @param <T> the type to map the SSE data to
|
||||
* @param apiCall the API call that returns streaming data
|
||||
* @param cl the class to map the SSE data to
|
||||
* @return a Flowable of the specified type
|
||||
*/
|
||||
public <T> Flowable<T> stream(retrofit2.Call<ResponseBody> apiCall, Class<T> cl) {
|
||||
return stream(apiCall).map(sse -> mapper.readValue(sse.getData(), cl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a streaming Flowable of SSE events without emitting done events.
|
||||
* @param apiCall the API call that returns streaming data
|
||||
* @return a Flowable of SSE events
|
||||
*/
|
||||
public static Flowable<SSE> stream(retrofit2.Call<ResponseBody> apiCall) {
|
||||
return stream(apiCall, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a streaming Flowable of SSE events with optional done event emission.
|
||||
* @param apiCall the API call that returns streaming data
|
||||
* @param emitDone whether to emit done events
|
||||
* @return a Flowable of SSE events
|
||||
*/
|
||||
public static Flowable<SSE> stream(retrofit2.Call<ResponseBody> apiCall, boolean emitDone) {
|
||||
return Flowable.create(emitter -> apiCall.enqueue(new ResponseBodyCallback(emitter, emitDone)),
|
||||
BackpressureStrategy.BUFFER);
|
||||
}
|
||||
|
||||
}
|
||||
38
core/src/main/java/ai/z/openapi/service/CommonRequest.java
Normal file
38
core/src/main/java/ai/z/openapi/service/CommonRequest.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package ai.z.openapi.service;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Common request base class with extra JSON fields. Other ZAI request classes should
|
||||
* extend this class to inherit common request parameters.
|
||||
*/
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@SuperBuilder
|
||||
@Data
|
||||
public class CommonRequest {
|
||||
|
||||
/**
|
||||
* Request ID provided by the client, must be unique. Used to distinguish each
|
||||
* request. If not provided by the client, the platform will generate one by default.
|
||||
*/
|
||||
@JsonProperty("request_id")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* A unique identifier representing your end-user, which will help ZAI to monitor and
|
||||
* detect abuse.
|
||||
*/
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
private Map<String, Object> extraJson;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ai.z.openapi.service.agents;
|
||||
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Parameters for retrieving agent asynchronous task results. This class contains the
|
||||
* necessary parameters to query the result of an agent's async task.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AgentAsyncResultRetrieveParams implements ClientRequest<Map<String, Object>> {
|
||||
|
||||
/**
|
||||
* The ID of the agent async task to retrieve
|
||||
*/
|
||||
@JsonProperty("task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* The agent ID associated with the async task
|
||||
*/
|
||||
@JsonProperty("agent_id")
|
||||
private String agentId;
|
||||
|
||||
/**
|
||||
* Optional request ID for tracking
|
||||
*/
|
||||
@JsonProperty("request_id")
|
||||
private String requestId;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package ai.z.openapi.service.agents;
|
||||
|
||||
import ai.z.openapi.service.model.ChatCompletionResponse;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import io.reactivex.Single;
|
||||
|
||||
/**
|
||||
* Agent completion service interface
|
||||
*/
|
||||
public interface AgentService {
|
||||
|
||||
/**
|
||||
* Creates an agent completion, either streaming or non-streaming based on the request
|
||||
* configuration.
|
||||
* @param request the agents completion request
|
||||
* @return ChatCompletionResponse containing the agent completion result
|
||||
*/
|
||||
ChatCompletionResponse createAgentCompletion(AgentsCompletionRequest request);
|
||||
|
||||
/**
|
||||
* Retrieves the result of an asynchronous agent operation.
|
||||
* @param request the query request for the async agent result
|
||||
* @return Single<ModelData> containing the async agent operation result
|
||||
*/
|
||||
Single<ModelData> retrieveAgentAsyncResult(AgentAsyncResultRetrieveParams request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package ai.z.openapi.service.agents;
|
||||
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.api.agents.AgentsApi;
|
||||
import ai.z.openapi.service.model.ChatCompletionResponse;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import ai.z.openapi.utils.FlowableRequestSupplier;
|
||||
import ai.z.openapi.utils.RequestSupplier;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* Agent completion service implementation
|
||||
*/
|
||||
public class AgentServiceImpl implements AgentService {
|
||||
|
||||
private final ZaiClient zAiClient;
|
||||
|
||||
private final AgentsApi agentsApi;
|
||||
|
||||
public AgentServiceImpl(ZaiClient zAiClient) {
|
||||
this.zAiClient = zAiClient;
|
||||
this.agentsApi = zAiClient.retrofit().create(AgentsApi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatCompletionResponse createAgentCompletion(AgentsCompletionRequest request) {
|
||||
if (request.getStream()) {
|
||||
return streamAgentCompletion(request);
|
||||
}
|
||||
else {
|
||||
return syncAgentCompletion(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<ModelData> retrieveAgentAsyncResult(AgentAsyncResultRetrieveParams request) {
|
||||
return agentsApi.queryAgentsAsyncResult(request);
|
||||
}
|
||||
|
||||
private ChatCompletionResponse streamAgentCompletion(AgentsCompletionRequest request) {
|
||||
FlowableRequestSupplier<AgentsCompletionRequest, retrofit2.Call<ResponseBody>> supplier = agentsApi::agentsCompletionStream;
|
||||
;
|
||||
return this.zAiClient.streamRequest(request, supplier, ChatCompletionResponse.class, ModelData.class);
|
||||
}
|
||||
|
||||
private ChatCompletionResponse syncAgentCompletion(AgentsCompletionRequest request) {
|
||||
RequestSupplier<AgentsCompletionRequest, ModelData> supplier = agentsApi::agentsCompletionSync;
|
||||
return this.zAiClient.executeRequest(request, supplier, ChatCompletionResponse.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package ai.z.openapi.service.agents;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import ai.z.openapi.service.model.ChatMessage;
|
||||
import ai.z.openapi.service.model.SensitiveWordCheckRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Request parameters for agent completion API calls. This class contains all the
|
||||
* necessary parameters to initiate an agent completion request, including agent ID,
|
||||
* messages, streaming options, and custom variables.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AgentsCompletionRequest extends CommonRequest implements ClientRequest<AgentsCompletionRequest> {
|
||||
|
||||
/**
|
||||
* Agent ID
|
||||
*/
|
||||
@JsonProperty("agent_id")
|
||||
private String agent_id;
|
||||
|
||||
/**
|
||||
* Message body
|
||||
*/
|
||||
private List<ChatMessage> messages;
|
||||
|
||||
/**
|
||||
* Synchronous call: false, SSE call: true
|
||||
*/
|
||||
private Boolean stream;
|
||||
|
||||
/**
|
||||
* Sensitive word detection control
|
||||
*/
|
||||
@JsonProperty("sensitive_word_check")
|
||||
private SensitiveWordCheckRequest sensitiveWordCheck;
|
||||
|
||||
/**
|
||||
* Agent business fields
|
||||
* @return
|
||||
*/
|
||||
@JsonProperty("custom_variables")
|
||||
private ObjectNode custom_variables;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import ai.z.openapi.core.model.FlowableClientResponse;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import io.reactivex.Flowable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Response wrapper for Assistant API calls that supports both synchronous and streaming
|
||||
* responses. This class implements FlowableClientResponse to handle streaming assistant
|
||||
* completions.
|
||||
*/
|
||||
@Data
|
||||
public class AssistantApiResponse implements FlowableClientResponse<AssistantCompletion> {
|
||||
|
||||
/**
|
||||
* Response status code.
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* Response message.
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* Indicates whether the request was successful.
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* The assistant completion data for synchronous responses.
|
||||
*/
|
||||
private AssistantCompletion data;
|
||||
|
||||
/**
|
||||
* The flowable stream for streaming responses.
|
||||
*/
|
||||
private Flowable<AssistantCompletion> flowable;
|
||||
|
||||
/**
|
||||
* Error information if the request failed.
|
||||
*/
|
||||
private ChatError error;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public AssistantApiResponse() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with code and message.
|
||||
* @param code the response code
|
||||
* @param msg the response message
|
||||
*/
|
||||
public AssistantApiResponse(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents an attachment with a file ID.
|
||||
*/
|
||||
public class AssistantAttachments {
|
||||
|
||||
/**
|
||||
* The ID of the file attachment.
|
||||
*/
|
||||
@JsonProperty("file_id")
|
||||
private String fileId;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import ai.z.openapi.service.assistant.message.MessageContent;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.deserialize.assistant.AssistantChoiceDeserializer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents an assistant's choice output in conversation responses. This class contains
|
||||
* the response index, message content, finish reason, and metadata.
|
||||
*/
|
||||
@JsonDeserialize(using = AssistantChoiceDeserializer.class)
|
||||
public class AssistantChoice extends ObjectNode {
|
||||
|
||||
/**
|
||||
* Result index.
|
||||
*/
|
||||
@JsonProperty("index")
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Current conversation output message content.
|
||||
*/
|
||||
@JsonProperty("delta")
|
||||
private MessageContent delta;
|
||||
|
||||
/**
|
||||
* Reason for inference completion: - stop: inference naturally ended or triggered
|
||||
* stop words - sensitive: model inference content was blocked by security review -
|
||||
* network_error: model inference service exception
|
||||
*/
|
||||
@JsonProperty("finish_reason")
|
||||
private String finishReason;
|
||||
|
||||
/**
|
||||
* Metadata, extension field.
|
||||
*/
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
public AssistantChoice() {
|
||||
super(JsonNodeFactory.instance);
|
||||
}
|
||||
|
||||
public AssistantChoice(ObjectNode objectNode) {
|
||||
super(JsonNodeFactory.instance);
|
||||
|
||||
if (objectNode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
if (objectNode.has("index")) {
|
||||
this.setIndex(objectNode.get("index").asInt());
|
||||
}
|
||||
else {
|
||||
this.setIndex(0);
|
||||
}
|
||||
if (objectNode.has("delta")) {
|
||||
MessageContent delta = objectMapper.convertValue(objectNode.get("delta"), MessageContent.class);
|
||||
this.setDelta(delta);
|
||||
}
|
||||
else {
|
||||
this.setDelta(null);
|
||||
}
|
||||
if (objectNode.has("finish_reason")) {
|
||||
this.setFinishReason(objectNode.get("finish_reason").asText());
|
||||
|
||||
}
|
||||
else {
|
||||
this.setFinishReason(null);
|
||||
}
|
||||
if (objectNode.has("metadata")) {
|
||||
Map<String, Object> metadata = objectMapper.convertValue(objectNode.get("metadata"),
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
|
||||
this.setMetadata(metadata);
|
||||
}
|
||||
else {
|
||||
this.setMetadata(null);
|
||||
}
|
||||
|
||||
Iterator<String> fieldNames = objectNode.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
String fieldName = fieldNames.next();
|
||||
JsonNode field = objectNode.get(fieldName);
|
||||
this.set(fieldName, field);
|
||||
}
|
||||
}
|
||||
// Getters and Setters
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
this.put("index", index);
|
||||
}
|
||||
|
||||
public MessageContent getDelta() {
|
||||
return delta;
|
||||
}
|
||||
|
||||
public void setDelta(MessageContent delta) {
|
||||
this.delta = delta;
|
||||
this.putPOJO("delta", delta);
|
||||
}
|
||||
|
||||
public String getFinishReason() {
|
||||
return finishReason;
|
||||
}
|
||||
|
||||
public void setFinishReason(String finishReason) {
|
||||
this.finishReason = finishReason;
|
||||
this.put("finish_reason", finishReason);
|
||||
}
|
||||
|
||||
public Map<String, Object> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, Object> metadata) {
|
||||
this.metadata = metadata;
|
||||
this.putPOJO("metadata", metadata);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.deserialize.assistant.AssistantCompletionDeserializer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class represents the completion data returned by an assistant.
|
||||
*/
|
||||
@JsonDeserialize(using = AssistantCompletionDeserializer.class)
|
||||
public class AssistantCompletion extends ObjectNode {
|
||||
|
||||
/**
|
||||
* Request ID
|
||||
*/
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Conversation ID
|
||||
*/
|
||||
@JsonProperty("conversation_id")
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* Assistant ID
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* Request creation time, Unix timestamp
|
||||
*/
|
||||
@JsonProperty("created")
|
||||
private int created;
|
||||
|
||||
/**
|
||||
* Return status, including: `completed` indicates generation finished, `in_progress`
|
||||
* indicates generating, `failed` indicates generation exception
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* Error information
|
||||
*/
|
||||
@JsonProperty("last_error")
|
||||
private ErrorInfo lastError;
|
||||
|
||||
/**
|
||||
* Incremental return information
|
||||
*/
|
||||
@JsonProperty("choices")
|
||||
private List<AssistantChoice> choices;
|
||||
|
||||
/**
|
||||
* Metadata, extension field
|
||||
*/
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
/**
|
||||
* Token count statistics
|
||||
*/
|
||||
@JsonProperty("usage")
|
||||
private CompletionUsage usage;
|
||||
|
||||
public AssistantCompletion() {
|
||||
super(JsonNodeFactory.instance);
|
||||
}
|
||||
|
||||
public AssistantCompletion(ObjectNode objectNode) {
|
||||
super(JsonNodeFactory.instance);
|
||||
|
||||
ObjectMapper objectMapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
if (objectNode.has("id")) {
|
||||
this.setId(objectNode.get("id").asText());
|
||||
}
|
||||
else {
|
||||
this.setId(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("conversation_id")) {
|
||||
this.setConversationId(objectNode.get("conversation_id").asText());
|
||||
}
|
||||
else {
|
||||
this.setConversationId(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("assistant_id")) {
|
||||
this.setAssistantId(objectNode.get("assistant_id").asText());
|
||||
}
|
||||
else {
|
||||
this.setAssistantId(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("created")) {
|
||||
this.setCreated(objectNode.get("created").asInt());
|
||||
}
|
||||
else {
|
||||
this.setCreated(0);
|
||||
}
|
||||
|
||||
if (objectNode.has("status")) {
|
||||
this.setStatus(objectNode.get("status").asText());
|
||||
|
||||
}
|
||||
else {
|
||||
this.setStatus(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("last_error")) {
|
||||
this.setLastError(objectMapper.convertValue(objectNode.get("last_error"), ErrorInfo.class));
|
||||
}
|
||||
else {
|
||||
this.setLastError(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("choices")) {
|
||||
List<AssistantChoice> choices1 = objectMapper.convertValue(objectNode.get("choices"),
|
||||
new com.fasterxml.jackson.core.type.TypeReference<List<AssistantChoice>>() {
|
||||
});
|
||||
|
||||
this.setChoices(choices1);
|
||||
|
||||
}
|
||||
else {
|
||||
this.setChoices(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("metadata")) {
|
||||
this.setMetadata(objectMapper.convertValue(objectNode.get("metadata"), Map.class));
|
||||
}
|
||||
else {
|
||||
this.setMetadata(null);
|
||||
}
|
||||
|
||||
if (objectNode.has("usage")) {
|
||||
this.setUsage(objectMapper.convertValue(objectNode.get("usage"), CompletionUsage.class));
|
||||
}
|
||||
else {
|
||||
this.setUsage(null);
|
||||
}
|
||||
|
||||
Iterator<String> fieldNames = objectNode.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
String fieldName = fieldNames.next();
|
||||
JsonNode field = objectNode.get(fieldName);
|
||||
this.set(fieldName, field);
|
||||
}
|
||||
}
|
||||
// Getters and Setters
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
this.put("id", id);
|
||||
}
|
||||
|
||||
public String getConversationId() {
|
||||
return conversationId;
|
||||
}
|
||||
|
||||
public void setConversationId(String conversationId) {
|
||||
this.conversationId = conversationId;
|
||||
this.put("conversation_id", conversationId);
|
||||
}
|
||||
|
||||
public String getAssistantId() {
|
||||
return assistantId;
|
||||
}
|
||||
|
||||
public void setAssistantId(String assistantId) {
|
||||
this.assistantId = assistantId;
|
||||
this.put("assistant_id", assistantId);
|
||||
}
|
||||
|
||||
public int getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(int created) {
|
||||
this.created = created;
|
||||
this.put("created", created);
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
this.put("status", status);
|
||||
}
|
||||
|
||||
public ErrorInfo getLastError() {
|
||||
return lastError;
|
||||
}
|
||||
|
||||
public void setLastError(ErrorInfo lastError) {
|
||||
this.lastError = lastError;
|
||||
this.putPOJO("last_error", lastError);
|
||||
}
|
||||
|
||||
public List<AssistantChoice> getChoices() {
|
||||
return choices;
|
||||
}
|
||||
|
||||
public void setChoices(List<AssistantChoice> choices) {
|
||||
this.choices = choices;
|
||||
ArrayNode jsonNodes = this.putArray("choices");
|
||||
if (choices == null) {
|
||||
jsonNodes.removeAll();
|
||||
}
|
||||
else {
|
||||
|
||||
for (AssistantChoice choice : choices) {
|
||||
jsonNodes.add(choice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, Object> metadata) {
|
||||
this.metadata = metadata;
|
||||
this.putPOJO("metadata", metadata);
|
||||
}
|
||||
|
||||
public CompletionUsage getUsage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
public void setUsage(CompletionUsage usage) {
|
||||
this.usage = usage;
|
||||
this.putPOJO("usage", usage);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* Extra parameters for assistant configuration. This class contains additional optional
|
||||
* parameters that can be used to customize assistant behavior and functionality.
|
||||
*/
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AssistantExtraParameters {
|
||||
|
||||
/**
|
||||
* Translation agent parameters
|
||||
*/
|
||||
private TranslateParameters translate;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class represents the parameters for an assistant, including optional fields.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AssistantParameters extends CommonRequest implements ClientRequest<AssistantParameters> {
|
||||
|
||||
/**
|
||||
* The ID of the assistant.
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* The conversation ID. If not provided, a new conversation is created.
|
||||
*/
|
||||
@JsonProperty("conversation_id")
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* The name of the model, default is 'GLM-4-Assistant'.
|
||||
*/
|
||||
@JsonProperty("model")
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* Whether to support streaming SSE, should be set to True.
|
||||
*/
|
||||
@JsonProperty("stream")
|
||||
private boolean stream;
|
||||
|
||||
/**
|
||||
* The list of conversation messages.
|
||||
*/
|
||||
@JsonProperty("messages")
|
||||
private List<ConversationMessage> messages;
|
||||
|
||||
/**
|
||||
* The list of file attachments for the conversation, optional.
|
||||
*/
|
||||
@JsonProperty("attachments")
|
||||
private List<AssistantAttachments> attachments;
|
||||
|
||||
/**
|
||||
* Metadata or additional fields, optional.
|
||||
*/
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
@JsonProperty("extra_parameters")
|
||||
private AssistantExtraParameters extraParameters;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import ai.z.openapi.service.assistant.AssistantParameters;
|
||||
import ai.z.openapi.service.assistant.AssistantApiResponse;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationParameters;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationUsageListResponse;
|
||||
import ai.z.openapi.service.assistant.query_support.AssistantSupportResponse;
|
||||
import ai.z.openapi.service.assistant.query_support.QuerySupportParams;
|
||||
|
||||
/**
|
||||
* Assistant service interface
|
||||
*/
|
||||
public interface AssistantService {
|
||||
|
||||
/**
|
||||
* Creates a streaming assistant completion.
|
||||
* @param request the assistant completion request
|
||||
* @return AssistantApiResponse containing the completion result
|
||||
*/
|
||||
AssistantApiResponse assistantCompletionStream(AssistantParameters request);
|
||||
|
||||
/**
|
||||
* Creates a non-streaming assistant completion.
|
||||
* @param request the assistant completion request
|
||||
* @return AssistantApiResponse containing the completion result
|
||||
*/
|
||||
AssistantApiResponse assistantCompletion(AssistantParameters request);
|
||||
|
||||
/**
|
||||
* Queries assistant support status.
|
||||
* @param request the query support request
|
||||
* @return AssistantSupportResponse containing the support information
|
||||
*/
|
||||
AssistantSupportResponse querySupport(QuerySupportParams request);
|
||||
|
||||
/**
|
||||
* Queries conversation usage information.
|
||||
* @param request the conversation parameters
|
||||
* @return ConversationUsageListResponse containing the usage information
|
||||
*/
|
||||
ConversationUsageListResponse queryConversationUsage(ConversationParameters request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.api.assistant.AssistantApi;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationParameters;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationUsageListResponse;
|
||||
import ai.z.openapi.service.assistant.conversation.ConversationUsageListStatus;
|
||||
import ai.z.openapi.service.assistant.query_support.AssistantSupportResponse;
|
||||
import ai.z.openapi.service.assistant.query_support.AssistantSupportStatus;
|
||||
import ai.z.openapi.service.assistant.query_support.QuerySupportParams;
|
||||
import ai.z.openapi.utils.FlowableRequestSupplier;
|
||||
import ai.z.openapi.utils.RequestSupplier;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* Implementation of AssistantService
|
||||
*/
|
||||
public class AssistantServiceImpl implements AssistantService {
|
||||
|
||||
private final ZaiClient zAiClient;
|
||||
|
||||
private final AssistantApi assistantApi;
|
||||
|
||||
public AssistantServiceImpl(ZaiClient zAiClient) {
|
||||
this.zAiClient = zAiClient;
|
||||
this.assistantApi = zAiClient.retrofit().create(AssistantApi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistantApiResponse assistantCompletionStream(AssistantParameters request) {
|
||||
FlowableRequestSupplier<AssistantParameters, retrofit2.Call<ResponseBody>> supplier = assistantApi::assistantCompletionStream;
|
||||
return zAiClient.streamRequest(request, supplier, AssistantApiResponse.class, AssistantCompletion.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistantApiResponse assistantCompletion(AssistantParameters request) {
|
||||
RequestSupplier<AssistantParameters, AssistantCompletion> supplier = assistantApi::assistantCompletion;
|
||||
return zAiClient.executeRequest(request, supplier, AssistantApiResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssistantSupportResponse querySupport(QuerySupportParams request) {
|
||||
RequestSupplier<QuerySupportParams, AssistantSupportStatus> supplier = assistantApi::querySupport;
|
||||
return zAiClient.executeRequest(request, supplier, AssistantSupportResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversationUsageListResponse queryConversationUsage(ConversationParameters request) {
|
||||
RequestSupplier<ConversationParameters, ConversationUsageListStatus> supplier = assistantApi::queryConversationUsage;
|
||||
return zAiClient.executeRequest(request, supplier, ConversationUsageListResponse.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.deserialize.assistant.CompletionUsageDeserializer;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This class represents the usage statistics for a completion.
|
||||
*/
|
||||
@JsonDeserialize(using = CompletionUsageDeserializer.class)
|
||||
public class CompletionUsage extends ObjectNode {
|
||||
|
||||
/**
|
||||
* Number of tokens in the input (prompt).
|
||||
*/
|
||||
@JsonProperty("prompt_tokens")
|
||||
private int promptTokens;
|
||||
|
||||
/**
|
||||
* Number of tokens in the output (completion).
|
||||
*/
|
||||
@JsonProperty("completion_tokens")
|
||||
private int completionTokens;
|
||||
|
||||
/**
|
||||
* Total number of tokens used.
|
||||
*/
|
||||
@JsonProperty("total_tokens")
|
||||
private int totalTokens;
|
||||
|
||||
public CompletionUsage() {
|
||||
super(JsonNodeFactory.instance);
|
||||
}
|
||||
|
||||
public CompletionUsage(ObjectNode objectNode) {
|
||||
super(JsonNodeFactory.instance);
|
||||
|
||||
ObjectMapper objectMapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
if (objectNode.get("prompt_tokens") != null) {
|
||||
this.setPromptTokens(objectNode.get("prompt_tokens").asInt());
|
||||
}
|
||||
else {
|
||||
this.setPromptTokens(0);
|
||||
}
|
||||
if (objectNode.get("completion_tokens") != null) {
|
||||
this.setCompletionTokens(objectNode.get("completion_tokens").asInt());
|
||||
}
|
||||
else {
|
||||
this.setCompletionTokens(0);
|
||||
}
|
||||
if (objectNode.get("total_tokens") != null) {
|
||||
this.setTotalTokens(objectNode.get("total_tokens").asInt());
|
||||
}
|
||||
else {
|
||||
this.setTotalTokens(0);
|
||||
}
|
||||
|
||||
Iterator<String> fieldNames = objectNode.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
String fieldName = fieldNames.next();
|
||||
JsonNode field = objectNode.get(fieldName);
|
||||
this.set(fieldName, field);
|
||||
}
|
||||
}
|
||||
// Getters and Setters
|
||||
|
||||
public int getPromptTokens() {
|
||||
return promptTokens;
|
||||
}
|
||||
|
||||
public void setPromptTokens(int promptTokens) {
|
||||
this.promptTokens = promptTokens;
|
||||
this.put("prompt_tokens", promptTokens);
|
||||
}
|
||||
|
||||
public int getCompletionTokens() {
|
||||
return completionTokens;
|
||||
}
|
||||
|
||||
public void setCompletionTokens(int completionTokens) {
|
||||
this.completionTokens = completionTokens;
|
||||
this.put("completion_tokens", completionTokens);
|
||||
}
|
||||
|
||||
public int getTotalTokens() {
|
||||
return totalTokens;
|
||||
}
|
||||
|
||||
public void setTotalTokens(int totalTokens) {
|
||||
this.totalTokens = totalTokens;
|
||||
this.put("total_tokens", totalTokens);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a conversation message body.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class ConversationMessage {
|
||||
|
||||
/**
|
||||
* The role of the user input, e.g., 'user'.
|
||||
*/
|
||||
@JsonProperty("role")
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* The content of the conversation message.
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private List<MessageTextContent> content;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.deserialize.assistant.ErrorInfoDeserializer;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This class represents error information.
|
||||
*/
|
||||
@JsonDeserialize(using = ErrorInfoDeserializer.class)
|
||||
public class ErrorInfo extends ObjectNode {
|
||||
|
||||
/**
|
||||
* Error code.
|
||||
*/
|
||||
@JsonProperty("code")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* Error message.
|
||||
*/
|
||||
@JsonProperty("message")
|
||||
private String message;
|
||||
|
||||
public ErrorInfo() {
|
||||
super(JsonNodeFactory.instance);
|
||||
}
|
||||
|
||||
public ErrorInfo(ObjectNode objectNode) {
|
||||
super(JsonNodeFactory.instance);
|
||||
|
||||
ObjectMapper objectMapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
|
||||
if (objectNode.get("code") != null) {
|
||||
this.setCode(objectNode.get("code").asText());
|
||||
}
|
||||
else {
|
||||
this.setCode(null);
|
||||
}
|
||||
if (objectNode.get("message") != null) {
|
||||
this.setMessage(objectNode.get("message").asText());
|
||||
}
|
||||
else {
|
||||
this.setMessage(null);
|
||||
}
|
||||
Iterator<String> fieldNames = objectNode.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
String fieldName = fieldNames.next();
|
||||
JsonNode field = objectNode.get(fieldName);
|
||||
this.set(fieldName, field);
|
||||
}
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
this.put("code", code);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
this.put("message", message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* This class represents the text content of a message. Currently supports only type =
|
||||
* text.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class MessageTextContent {
|
||||
|
||||
/**
|
||||
* The type of the message content, currently only "text" is supported.
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* The text content of the message.
|
||||
*/
|
||||
@JsonProperty("text")
|
||||
private String text;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package ai.z.openapi.service.assistant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* Parameters for translation operations. This class contains the source and target
|
||||
* language settings for translation requests.
|
||||
*/
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class TranslateParameters {
|
||||
|
||||
/**
|
||||
* Source language for translation.
|
||||
*/
|
||||
private String from;
|
||||
|
||||
/**
|
||||
* Target language for translation.
|
||||
*/
|
||||
private String to;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* This class represents the parameters for a conversation, including pagination.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class ConversationParameters extends CommonRequest implements ClientRequest<ConversationParameters> {
|
||||
|
||||
/**
|
||||
* The Assistant ID.
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* The current page number for pagination.
|
||||
*/
|
||||
@JsonProperty("page")
|
||||
private int page;
|
||||
|
||||
/**
|
||||
* The number of items per page for pagination.
|
||||
*/
|
||||
@JsonProperty("page_size")
|
||||
private int pageSize;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* This class represents the usage data for a specific conversation.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ConversationUsage {
|
||||
|
||||
/**
|
||||
* The conversation ID.
|
||||
*/
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* The Assistant ID.
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* The creation time of the conversation.
|
||||
*/
|
||||
@JsonProperty("create_time")
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* The last update time of the conversation.
|
||||
*/
|
||||
@JsonProperty("update_time")
|
||||
private String updateTime;
|
||||
|
||||
/**
|
||||
* The usage statistics for the conversation.
|
||||
*/
|
||||
@JsonProperty("usage")
|
||||
private Usage usage;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a list of conversation usage data.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ConversationUsageList {
|
||||
|
||||
/**
|
||||
* The Assistant ID.
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* Whether there are more pages of results.
|
||||
*/
|
||||
@JsonProperty("has_more")
|
||||
private boolean hasMore;
|
||||
|
||||
/**
|
||||
* The list of conversation usage data.
|
||||
*/
|
||||
@JsonProperty("conversation_list")
|
||||
private List<ConversationUsage> conversationList;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Response for conversation usage list API calls. This class contains the response data
|
||||
* for retrieving conversation usage statistics.
|
||||
*/
|
||||
@Data
|
||||
public class ConversationUsageListResponse implements ClientResponse<ConversationUsageListStatus> {
|
||||
|
||||
/**
|
||||
* Response status code.
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* Response message.
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* Indicates if the request was successful.
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* The conversation usage list data.
|
||||
*/
|
||||
private ConversationUsageListStatus data;
|
||||
|
||||
/**
|
||||
* Error information if the request failed.
|
||||
*/
|
||||
private ChatError error;
|
||||
|
||||
public ConversationUsageListResponse() {
|
||||
}
|
||||
|
||||
public ConversationUsageListResponse(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* This class represents the response containing a list of conversation usage data.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ConversationUsageListStatus {
|
||||
|
||||
/**
|
||||
* The response code.
|
||||
*/
|
||||
@JsonProperty("code")
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* The response message.
|
||||
*/
|
||||
@JsonProperty("msg")
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* The data containing the conversation usage list.
|
||||
*/
|
||||
@JsonProperty("data")
|
||||
private ConversationUsageList data;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package ai.z.openapi.service.assistant.conversation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* This class represents the usage statistics for a conversation.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Usage {
|
||||
|
||||
/**
|
||||
* The number of tokens in the user's input.
|
||||
*/
|
||||
@JsonProperty("prompt_tokens")
|
||||
private int promptTokens;
|
||||
|
||||
/**
|
||||
* The number of tokens in the model's input.
|
||||
*/
|
||||
@JsonProperty("completion_tokens")
|
||||
private int completionTokens;
|
||||
|
||||
/**
|
||||
* The total number of tokens.
|
||||
*/
|
||||
@JsonProperty("total_tokens")
|
||||
private int totalTokens;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package ai.z.openapi.service.assistant.message;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeMapping;
|
||||
import ai.z.openapi.service.deserialize.assistant.message.MessageContentDeserializer;
|
||||
|
||||
@JsonTypeMapping({ ToolsDeltaBlock.class, TextContentBlock.class })
|
||||
@JsonDeserialize(using = MessageContentDeserializer.class)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public abstract class MessageContent {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package ai.z.openapi.service.assistant.message;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block of text content in a conversation.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("content")
|
||||
public class TextContentBlock extends MessageContent {
|
||||
|
||||
/**
|
||||
* The content of the text block.
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* The role of the speaker, default is "assistant".
|
||||
*/
|
||||
@JsonProperty("role")
|
||||
private String role = "assistant";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ai.z.openapi.service.assistant.message;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.assistant.message.tools.ToolsType;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a block of tool call data in a conversation.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("tool_calls")
|
||||
public class ToolsDeltaBlock extends MessageContent {
|
||||
|
||||
/**
|
||||
* A list of tool call types.
|
||||
*/
|
||||
@JsonProperty("tool_calls")
|
||||
private List<ToolsType> toolCalls;
|
||||
|
||||
/**
|
||||
* The role of the speaker, default is "tool".
|
||||
*/
|
||||
@JsonProperty("role")
|
||||
private String role = "tool";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public List<ToolsType> getToolCalls() {
|
||||
return toolCalls;
|
||||
}
|
||||
|
||||
public void setToolCalls(List<ToolsType> toolCalls) {
|
||||
this.toolCalls = toolCalls;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ai.z.openapi.service.assistant.message.tools;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import ai.z.openapi.service.assistant.message.tools.code_interpreter.CodeInterpreterToolBlock;
|
||||
import ai.z.openapi.service.assistant.message.tools.drawing_tool.DrawingToolBlock;
|
||||
import ai.z.openapi.service.assistant.message.tools.function.FunctionToolBlock;
|
||||
import ai.z.openapi.service.assistant.message.tools.retrieval.RetrievalToolBlock;
|
||||
import ai.z.openapi.service.assistant.message.tools.web_browser.WebBrowserToolBlock;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeMapping;
|
||||
import ai.z.openapi.service.deserialize.assistant.message.tools.ToolsTypeDeserializer;
|
||||
|
||||
@JsonTypeMapping({ WebBrowserToolBlock.class, RetrievalToolBlock.class, FunctionToolBlock.class, DrawingToolBlock.class,
|
||||
CodeInterpreterToolBlock.class, })
|
||||
@JsonDeserialize(using = ToolsTypeDeserializer.class)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public abstract class ToolsType {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.code_interpreter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a code interpreter that executes code and returns the results.
|
||||
*/
|
||||
public class CodeInterpreter {
|
||||
|
||||
/**
|
||||
* The generated code snippet that is input to the code sandbox.
|
||||
*/
|
||||
@JsonProperty("input")
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* The output results after the code execution.
|
||||
*/
|
||||
@JsonProperty("outputs")
|
||||
private List<CodeInterpreterToolOutput> outputs;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public List<CodeInterpreterToolOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public void setOutputs(List<CodeInterpreterToolOutput> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.code_interpreter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.assistant.message.tools.ToolsType;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block of code tool data.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("code_interpreter")
|
||||
public class CodeInterpreterToolBlock extends ToolsType {
|
||||
|
||||
/**
|
||||
* The code interpreter object.
|
||||
*/
|
||||
@JsonProperty("code_interpreter")
|
||||
private CodeInterpreter codeInterpreter;
|
||||
|
||||
/**
|
||||
* The type of tool being called, always "code_interpreter".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type = "code_interpreter";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public CodeInterpreter getCodeInterpreter() {
|
||||
return codeInterpreter;
|
||||
}
|
||||
|
||||
public void setCodeInterpreter(CodeInterpreter codeInterpreter) {
|
||||
this.codeInterpreter = codeInterpreter;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.code_interpreter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents the output result of a code tool.
|
||||
*/
|
||||
public class CodeInterpreterToolOutput {
|
||||
|
||||
/**
|
||||
* The type of output, currently only "logs".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* The log results from the code execution.
|
||||
*/
|
||||
@JsonProperty("logs")
|
||||
private String logs;
|
||||
|
||||
/**
|
||||
* Error message if any occurred during code execution.
|
||||
*/
|
||||
@JsonProperty("error_msg")
|
||||
private String errorMsg;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getLogs() {
|
||||
return logs;
|
||||
}
|
||||
|
||||
public void setLogs(String logs) {
|
||||
this.logs = logs;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public void setErrorMsg(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.drawing_tool;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The input string that was used to generate the drawing.
|
||||
*/
|
||||
public class DrawingTool {
|
||||
|
||||
/**
|
||||
* The input string that was used to generate the drawing.
|
||||
*/
|
||||
@JsonProperty("input")
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* A list of outputs generated by the drawing tool.
|
||||
*/
|
||||
@JsonProperty("outputs")
|
||||
private List<DrawingToolOutput> outputs;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public List<DrawingToolOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public void setOutputs(List<DrawingToolOutput> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.drawing_tool;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.assistant.message.tools.ToolsType;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block of drawing tool data.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("drawing_tool")
|
||||
public class DrawingToolBlock extends ToolsType {
|
||||
|
||||
/**
|
||||
* The drawing tool object that contains input and outputs.
|
||||
*/
|
||||
@JsonProperty("drawing_tool")
|
||||
private DrawingTool drawingTool;
|
||||
|
||||
/**
|
||||
* The type of tool being called, always "drawing_tool".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type = "drawing_tool";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public DrawingTool getDrawingTool() {
|
||||
return drawingTool;
|
||||
}
|
||||
|
||||
public void setDrawingTool(DrawingTool drawingTool) {
|
||||
this.drawingTool = drawingTool;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.drawing_tool;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents the output of a drawing tool, containing the generated image.
|
||||
*/
|
||||
public class DrawingToolOutput {
|
||||
|
||||
/**
|
||||
* The generated image in a string format.
|
||||
*/
|
||||
@JsonProperty("image")
|
||||
private String image;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.function;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a function tool with a name, arguments, and outputs.
|
||||
*/
|
||||
public class FunctionTool {
|
||||
|
||||
/**
|
||||
* The name of the function tool.
|
||||
*/
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The arguments for the function tool, which can be a string or a dictionary.
|
||||
*/
|
||||
@JsonProperty("arguments")
|
||||
private JsonNode arguments; // Union type in Java can be represented by Object, and
|
||||
// deserialization handles it accordingly
|
||||
|
||||
/**
|
||||
* A list of outputs generated by the function tool.
|
||||
*/
|
||||
@JsonProperty("outputs")
|
||||
private List<FunctionToolOutput> outputs;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public JsonNode getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public void setArguments(JsonNode arguments) {
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public List<FunctionToolOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public void setOutputs(List<FunctionToolOutput> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.function;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.assistant.message.tools.ToolsType;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block of function tool data.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("function")
|
||||
public class FunctionToolBlock extends ToolsType {
|
||||
|
||||
/**
|
||||
* The function tool object that contains the name, arguments, and outputs.
|
||||
*/
|
||||
@JsonProperty("function")
|
||||
private FunctionTool function;
|
||||
|
||||
/**
|
||||
* The type of tool being called, always "function".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type = "function";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public FunctionTool getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
public void setFunction(FunctionTool function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.function;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents the output of a function tool, containing the generated content.
|
||||
*/
|
||||
public class FunctionToolOutput {
|
||||
|
||||
/**
|
||||
* The generated content as a string.
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.retrieval;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the outputs of a retrieval tool.
|
||||
*/
|
||||
public class RetrievalTool {
|
||||
|
||||
/**
|
||||
* A list of text snippets and their respective document names retrieved from the
|
||||
* knowledge base.
|
||||
*/
|
||||
@JsonProperty("outputs")
|
||||
private List<RetrievalToolOutput> outputs;
|
||||
|
||||
public List<RetrievalToolOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public void setOutputs(List<RetrievalToolOutput> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.retrieval;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block for invoking the retrieval tool.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("retrieval")
|
||||
public class RetrievalToolBlock {
|
||||
|
||||
/**
|
||||
* An instance of the RetrievalTool class containing the retrieval outputs.
|
||||
*/
|
||||
@JsonProperty("retrieval")
|
||||
private RetrievalTool retrieval;
|
||||
|
||||
/**
|
||||
* The type of tool being used, always set to "retrieval".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type = "retrieval";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public RetrievalTool getRetrieval() {
|
||||
return retrieval;
|
||||
}
|
||||
|
||||
public void setRetrieval(RetrievalTool retrieval) {
|
||||
this.retrieval = retrieval;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.retrieval;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents the output of a retrieval tool.
|
||||
*/
|
||||
public class RetrievalToolOutput {
|
||||
|
||||
/**
|
||||
* The text snippet retrieved from the knowledge base.
|
||||
*/
|
||||
@JsonProperty("text")
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* The name of the document from which the text snippet was retrieved, returned only
|
||||
* in intelligent configuration.
|
||||
*/
|
||||
@JsonProperty("document")
|
||||
private String document;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
public void setDocument(String document) {
|
||||
this.document = document;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.web_browser;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the input and outputs of a web browser search.
|
||||
*/
|
||||
public class WebBrowser {
|
||||
|
||||
/**
|
||||
* The input query for the web browser search.
|
||||
*/
|
||||
@JsonProperty("input")
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* A list of search results returned by the web browser.
|
||||
*/
|
||||
@JsonProperty("outputs")
|
||||
private List<WebBrowserOutput> outputs;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public List<WebBrowserOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public void setOutputs(List<WebBrowserOutput> outputs) {
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.web_browser;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This class represents the output of a web browser search result.
|
||||
*/
|
||||
public class WebBrowserOutput {
|
||||
|
||||
/**
|
||||
* The title of the search result.
|
||||
*/
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* The URL link to the search result's webpage.
|
||||
*/
|
||||
@JsonProperty("link")
|
||||
private String link;
|
||||
|
||||
/**
|
||||
* The textual content extracted from the search result.
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* Any error message encountered during the search or retrieval process.
|
||||
*/
|
||||
@JsonProperty("error_msg")
|
||||
private String errorMsg;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public void setErrorMsg(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package ai.z.openapi.service.assistant.message.tools.web_browser;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.service.assistant.message.tools.ToolsType;
|
||||
import ai.z.openapi.service.deserialize.JsonTypeField;
|
||||
|
||||
/**
|
||||
* This class represents a block for invoking the web browser tool.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeField("web_browser")
|
||||
public class WebBrowserToolBlock extends ToolsType {
|
||||
|
||||
/**
|
||||
* An instance of the WebBrowser class containing the search input and outputs.
|
||||
*/
|
||||
@JsonProperty("web_browser")
|
||||
private WebBrowser webBrowser;
|
||||
|
||||
/**
|
||||
* The type of tool being used, always set to "web_browser".
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
private String type = "web_browser";
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public WebBrowser getWebBrowser() {
|
||||
return webBrowser;
|
||||
}
|
||||
|
||||
public void setWebBrowser(WebBrowser webBrowser) {
|
||||
this.webBrowser = webBrowser;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package ai.z.openapi.service.assistant.query_support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the details of an assistant.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AssistantSupport {
|
||||
|
||||
/**
|
||||
* The Assistant ID, used for assistant conversations.
|
||||
*/
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
/**
|
||||
* The creation time of the assistant.
|
||||
*/
|
||||
@JsonProperty("created_at")
|
||||
private String createdAt;
|
||||
|
||||
/**
|
||||
* The last update time of the assistant.
|
||||
*/
|
||||
@JsonProperty("updated_at")
|
||||
private String updatedAt;
|
||||
|
||||
/**
|
||||
* The name of the assistant.
|
||||
*/
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The avatar of the assistant.
|
||||
*/
|
||||
@JsonProperty("avatar")
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* The description of the assistant.
|
||||
*/
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* The status of the assistant, currently only "publish".
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* The list of tools supported by the assistant.
|
||||
*/
|
||||
@JsonProperty("tools")
|
||||
private List<String> tools;
|
||||
|
||||
/**
|
||||
* The list of recommended prompts to start the assistant.
|
||||
*/
|
||||
@JsonProperty("starter_prompts")
|
||||
private List<String> starterPrompts;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package ai.z.openapi.service.assistant.query_support;
|
||||
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Response for assistant support query API calls. This class contains the response data
|
||||
* for checking assistant support status.
|
||||
*/
|
||||
@Data
|
||||
public class AssistantSupportResponse implements ClientResponse<AssistantSupportStatus> {
|
||||
|
||||
/**
|
||||
* Response status code.
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* Response message.
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* Indicates if the request was successful.
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* The assistant support status data.
|
||||
*/
|
||||
private AssistantSupportStatus data;
|
||||
|
||||
/**
|
||||
* Error information if the request failed.
|
||||
*/
|
||||
private ChatError error;
|
||||
|
||||
public AssistantSupportResponse() {
|
||||
}
|
||||
|
||||
public AssistantSupportResponse(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package ai.z.openapi.service.assistant.query_support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the response containing a list of assistant supports.
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AssistantSupportStatus {
|
||||
|
||||
/**
|
||||
* The response code.
|
||||
*/
|
||||
@JsonProperty("code")
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* The response message.
|
||||
*/
|
||||
@JsonProperty("msg")
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* The list of assistant supports.
|
||||
*/
|
||||
@JsonProperty("data")
|
||||
private List<AssistantSupport> data;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ai.z.openapi.service.assistant.query_support;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parameters for querying assistant support status. This class contains the parameters
|
||||
* needed to query the support status of specific assistants.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class QuerySupportParams extends CommonRequest implements ClientRequest<QuerySupportParams> {
|
||||
|
||||
/**
|
||||
* List of assistant IDs to query support status for.
|
||||
*/
|
||||
@JsonProperty("assistant_id_list")
|
||||
private List<String> assistantIdList;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Response wrapper for audio customization API calls. This class contains the response
|
||||
* data for audio customization requests, including the generated audio file and status
|
||||
* information.
|
||||
*/
|
||||
@Data
|
||||
public class AudioCustomizationApiResponse implements ClientResponse<File> {
|
||||
|
||||
/**
|
||||
* Response status code.
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* Response message.
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* Indicates whether the request was successful.
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* The generated audio file.
|
||||
*/
|
||||
private File data;
|
||||
|
||||
/**
|
||||
* Error information if the request failed.
|
||||
*/
|
||||
private ChatError error;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import ai.z.openapi.service.model.SensitiveWordCheckRequest;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Request parameters for audio customization API calls. This class contains all the
|
||||
* necessary parameters for generating customized audio, including input text, model
|
||||
* selection, voice cloning data, and response format options.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AudioCustomizationRequest extends CommonRequest implements ClientRequest<AudioCustomizationRequest> {
|
||||
|
||||
/**
|
||||
* Text to generate audio from
|
||||
*/
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* Model code to call
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* Text description of the original audio to clone
|
||||
*/
|
||||
@JsonProperty("voice_text")
|
||||
private String voiceText;
|
||||
|
||||
/**
|
||||
* Original audio file to clone
|
||||
*/
|
||||
@JsonProperty("voice_data")
|
||||
private File voiceData;
|
||||
|
||||
/**
|
||||
* Audio response format
|
||||
*/
|
||||
@JsonProperty("response_format")
|
||||
private String responseFormat;
|
||||
|
||||
/**
|
||||
* Sensitive word detection control
|
||||
*/
|
||||
@JsonProperty("sensitive_word_check")
|
||||
private SensitiveWordCheckRequest sensitiveWordCheck;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.service.model.ChatCompletionResponse;
|
||||
|
||||
/**
|
||||
* Audio service interface
|
||||
*/
|
||||
public interface AudioService {
|
||||
|
||||
/**
|
||||
* Creates speech from text using text-to-speech.
|
||||
* @param request the speech generation request
|
||||
* @return AudioSpeechApiResponse containing the generated speech
|
||||
*/
|
||||
AudioSpeechApiResponse createSpeech(AudioSpeechRequest request);
|
||||
|
||||
/**
|
||||
* Creates customized speech with specific voice characteristics.
|
||||
* @param request the speech customization request
|
||||
* @return AudioCustomizationApiResponse containing the customized speech result
|
||||
*/
|
||||
AudioCustomizationApiResponse createCustomSpeech(AudioCustomizationRequest request);
|
||||
|
||||
/**
|
||||
* Creates audio transcriptions from audio files.
|
||||
* @param request the transcription request
|
||||
* @return ChatCompletionResponse containing the transcription result
|
||||
*/
|
||||
ChatCompletionResponse createTranscription(AudioTranscriptionsRequest request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.ZaiClient;
|
||||
import ai.z.openapi.api.audio.AudioApi;
|
||||
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
|
||||
import ai.z.openapi.service.model.ChatCompletionResponse;
|
||||
import ai.z.openapi.service.model.ModelData;
|
||||
import ai.z.openapi.utils.FlowableRequestSupplier;
|
||||
import ai.z.openapi.utils.RequestSupplier;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.reactivex.Single;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.apache.tika.Tika;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Audio service implementation
|
||||
*/
|
||||
@Slf4j
|
||||
public class AudioServiceImpl implements AudioService {
|
||||
|
||||
protected static final ObjectMapper mapper = MessageDeserializeFactory.defaultObjectMapper();
|
||||
|
||||
private final ZaiClient zAiClient;
|
||||
|
||||
private final AudioApi audioApi;
|
||||
|
||||
public AudioServiceImpl(ZaiClient zAiClient) {
|
||||
this.zAiClient = zAiClient;
|
||||
this.audioApi = zAiClient.retrofit().create(AudioApi.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioSpeechApiResponse createSpeech(AudioSpeechRequest request) {
|
||||
RequestSupplier<AudioSpeechRequest, java.io.File> supplier = (params) -> {
|
||||
try {
|
||||
Single<ResponseBody> responseBody = audioApi.audioSpeech(params);
|
||||
Path tempDirectory = Files.createTempFile("audio_speech" + UUID.randomUUID(), ".wav");
|
||||
java.io.File file = tempDirectory.toFile();
|
||||
writeResponseBodyToFile(responseBody.blockingGet(), file);
|
||||
return Single.just(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
return this.zAiClient.executeRequest(request, supplier, AudioSpeechApiResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioCustomizationApiResponse createCustomSpeech(AudioCustomizationRequest request) {
|
||||
RequestSupplier<AudioCustomizationRequest, java.io.File> supplier = (params) -> {
|
||||
try {
|
||||
java.io.File voiceFile = params.getVoiceData();
|
||||
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), voiceFile);
|
||||
MultipartBody.Part voiceData = MultipartBody.Part.createFormData("voice_data", voiceFile.getName(),
|
||||
requestFile);
|
||||
|
||||
Map<String, RequestBody> requestMap = new HashMap<>();
|
||||
if (params.getInput() != null) {
|
||||
requestMap.put("input", RequestBody.create(MediaType.parse("text/plain"), params.getInput()));
|
||||
}
|
||||
if (params.getModel() != null) {
|
||||
requestMap.put("model", RequestBody.create(MediaType.parse("text/plain"), params.getModel()));
|
||||
}
|
||||
if (params.getVoiceText() != null) {
|
||||
requestMap.put("voice_text",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getVoiceText()));
|
||||
}
|
||||
if (params.getResponseFormat() != null) {
|
||||
requestMap.put("response_format",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getResponseFormat()));
|
||||
}
|
||||
if (params.getSensitiveWordCheck() != null) {
|
||||
try {
|
||||
String sensitiveWordCheckJson = mapper.writeValueAsString(params.getSensitiveWordCheck());
|
||||
requestMap.put("sensitive_word_check",
|
||||
RequestBody.create(MediaType.parse("application/json"), sensitiveWordCheckJson));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Error serializing sensitive_word_check: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (params.getRequestId() != null) {
|
||||
requestMap.put("request_id",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getRequestId()));
|
||||
}
|
||||
if (params.getUserId() != null) {
|
||||
requestMap.put("user_id", RequestBody.create(MediaType.parse("text/plain"), params.getUserId()));
|
||||
}
|
||||
|
||||
Single<ResponseBody> responseBody = audioApi.audioCustomization(requestMap, voiceData);
|
||||
Path tempDirectory = Files.createTempFile("audio_customization" + UUID.randomUUID(), ".wav");
|
||||
java.io.File file = tempDirectory.toFile();
|
||||
writeResponseBodyToFile(responseBody.blockingGet(), file);
|
||||
return Single.just(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Error create custom speak: {}", e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
return this.zAiClient.executeRequest(request, supplier, AudioCustomizationApiResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatCompletionResponse createTranscription(AudioTranscriptionsRequest request) {
|
||||
if (request.getStream()) {
|
||||
return createTranscriptionStream(request);
|
||||
}
|
||||
else {
|
||||
return createTranscriptionSync(request);
|
||||
}
|
||||
}
|
||||
|
||||
private ChatCompletionResponse createTranscriptionStream(AudioTranscriptionsRequest request) {
|
||||
FlowableRequestSupplier<AudioTranscriptionsRequest, retrofit2.Call<ResponseBody>> supplier = params -> {
|
||||
try {
|
||||
java.io.File file = params.getFile();
|
||||
Tika tika = new Tika();
|
||||
String contentType = tika.detect(file);
|
||||
RequestBody requestFile = RequestBody.create(MediaType.parse(contentType), file);
|
||||
MultipartBody.Part fileData = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
|
||||
|
||||
Map<String, RequestBody> requestMap = new HashMap<>();
|
||||
if (params.getModel() != null) {
|
||||
requestMap.put("model", RequestBody.create(MediaType.parse("text/plain"), params.getModel()));
|
||||
}
|
||||
if (params.getStream() != null) {
|
||||
requestMap.put("stream",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getStream().toString()));
|
||||
}
|
||||
if (params.getRequestId() != null) {
|
||||
requestMap.put("request_id",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getRequestId()));
|
||||
}
|
||||
if (params.getUserId() != null) {
|
||||
requestMap.put("user_id", RequestBody.create(MediaType.parse("text/plain"), params.getUserId()));
|
||||
}
|
||||
|
||||
return audioApi.audioTranscriptionsStream(requestMap, fileData);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Error create transcription: {}", e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
return this.zAiClient.streamRequest(request, supplier, ChatCompletionResponse.class, ModelData.class);
|
||||
}
|
||||
|
||||
private ChatCompletionResponse createTranscriptionSync(AudioTranscriptionsRequest request) {
|
||||
RequestSupplier<AudioTranscriptionsRequest, ModelData> supplier = (params) -> {
|
||||
try {
|
||||
java.io.File file = params.getFile();
|
||||
Tika tika = new Tika();
|
||||
String contentType = tika.detect(file);
|
||||
RequestBody requestFile = RequestBody.create(MediaType.parse(contentType), file);
|
||||
MultipartBody.Part fileData = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
|
||||
|
||||
Map<String, RequestBody> requestMap = new HashMap<>();
|
||||
if (params.getModel() != null) {
|
||||
requestMap.put("model", RequestBody.create(MediaType.parse("text/plain"), params.getModel()));
|
||||
}
|
||||
if (params.getStream() != null) {
|
||||
requestMap.put("stream",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getStream().toString()));
|
||||
}
|
||||
if (params.getRequestId() != null) {
|
||||
requestMap.put("request_id",
|
||||
RequestBody.create(MediaType.parse("text/plain"), params.getRequestId()));
|
||||
}
|
||||
if (params.getUserId() != null) {
|
||||
requestMap.put("user_id", RequestBody.create(MediaType.parse("text/plain"), params.getUserId()));
|
||||
}
|
||||
|
||||
return audioApi.audioTranscriptions(requestMap, fileData);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Error create transcription: {}", e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
return this.zAiClient.executeRequest(request, supplier, ChatCompletionResponse.class);
|
||||
}
|
||||
|
||||
private void writeResponseBodyToFile(ResponseBody body, java.io.File file) {
|
||||
try (InputStream inputStream = body.byteStream();
|
||||
OutputStream outputStream = Files.newOutputStream(file.toPath())) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("writeResponseBodyToFile error,msg:{}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.core.model.ClientResponse;
|
||||
import ai.z.openapi.service.model.ChatError;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Data
|
||||
public class AudioSpeechApiResponse implements ClientResponse<File> {
|
||||
|
||||
private int code;
|
||||
|
||||
private String msg;
|
||||
|
||||
private boolean success;
|
||||
|
||||
private File data;
|
||||
|
||||
private ChatError error;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import ai.z.openapi.service.model.SensitiveWordCheckRequest;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AudioSpeechRequest extends CommonRequest implements ClientRequest<AudioSpeechRequest> {
|
||||
|
||||
/**
|
||||
* Model code to call
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* Text to generate speech from
|
||||
*/
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* Voice tone for speech generation
|
||||
*/
|
||||
private String voice;
|
||||
|
||||
/**
|
||||
* Format of the generated speech file
|
||||
*/
|
||||
@JsonProperty("response_format")
|
||||
private String responseFormat;
|
||||
|
||||
/**
|
||||
* Sensitive word detection control
|
||||
*/
|
||||
@JsonProperty("sensitive_word_check")
|
||||
private SensitiveWordCheckRequest sensitiveWordCheck;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package ai.z.openapi.service.audio;
|
||||
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import ai.z.openapi.service.CommonRequest;
|
||||
import ai.z.openapi.service.model.SensitiveWordCheckRequest;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class AudioTranscriptionsRequest extends CommonRequest implements ClientRequest<AudioTranscriptionsRequest> {
|
||||
|
||||
/**
|
||||
* Model code to call
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* Synchronous call: false, SSE call: true
|
||||
*/
|
||||
private Boolean stream;
|
||||
|
||||
private File file;
|
||||
|
||||
/**
|
||||
* Sampling temperature, controls output randomness, must be positive Range:
|
||||
* (0.0,1.0], cannot equal 0, default value is 0.95 Higher values make output more
|
||||
* random and creative; lower values make output more stable or deterministic It's
|
||||
* recommended to adjust either top_p or temperature parameter based on your use case,
|
||||
* but not both simultaneously
|
||||
*/
|
||||
private Float temperature;
|
||||
|
||||
/**
|
||||
* Sensitive word detection control
|
||||
*/
|
||||
@JsonProperty("sensitive_word_check")
|
||||
private SensitiveWordCheckRequest sensitiveWordCheck;
|
||||
|
||||
}
|
||||
113
core/src/main/java/ai/z/openapi/service/batches/Batch.java
Normal file
113
core/src/main/java/ai/z/openapi/service/batches/Batch.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package ai.z.openapi.service.batches;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class Batch {
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("completion_window")
|
||||
private String completionWindow;
|
||||
|
||||
@JsonProperty("created_at")
|
||||
private long createdAt;
|
||||
|
||||
@JsonProperty("endpoint")
|
||||
private String endpoint;
|
||||
|
||||
@JsonProperty("input_file_id")
|
||||
private String inputFileId;
|
||||
|
||||
@JsonProperty("object")
|
||||
private String object;
|
||||
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
@JsonProperty("cancelled_at")
|
||||
private Long cancelledAt;
|
||||
|
||||
@JsonProperty("cancelling_at")
|
||||
private Long cancellingAt;
|
||||
|
||||
@JsonProperty("completed_at")
|
||||
private Long completedAt;
|
||||
|
||||
@JsonProperty("error_file_id")
|
||||
private String errorFileId;
|
||||
|
||||
@JsonProperty("errors")
|
||||
private Errors errors;
|
||||
|
||||
@JsonProperty("expired_at")
|
||||
private Long expiredAt;
|
||||
|
||||
@JsonProperty("expires_at")
|
||||
private Long expiresAt;
|
||||
|
||||
@JsonProperty("failed_at")
|
||||
private Long failedAt;
|
||||
|
||||
@JsonProperty("finalizing_at")
|
||||
private Long finalizingAt;
|
||||
|
||||
@JsonProperty("in_progress_at")
|
||||
private Long inProgressAt;
|
||||
|
||||
@JsonProperty("metadata")
|
||||
private Object metadata;
|
||||
|
||||
@JsonProperty("output_file_id")
|
||||
private String outputFileId;
|
||||
|
||||
@JsonProperty("request_counts")
|
||||
private BatchRequestCounts requestCounts;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
class Errors {
|
||||
|
||||
@JsonProperty("data")
|
||||
private List<BatchError> data;
|
||||
|
||||
@JsonProperty("object")
|
||||
private String object;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
class BatchRequestCounts {
|
||||
|
||||
@JsonProperty("completed")
|
||||
private int completed;
|
||||
|
||||
@JsonProperty("failed")
|
||||
private int failed;
|
||||
|
||||
@JsonProperty("total")
|
||||
private int total;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
class BatchError {
|
||||
|
||||
@JsonProperty("code")
|
||||
private String code;
|
||||
|
||||
@JsonProperty("line")
|
||||
private Long line;
|
||||
|
||||
@JsonProperty("message")
|
||||
private String message;
|
||||
|
||||
@JsonProperty("param")
|
||||
private String param;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package ai.z.openapi.service.batches;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ai.z.openapi.core.model.ClientRequest;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Parameters for creating batch processing requests. This class contains all the
|
||||
* necessary parameters to create a batch job, including completion window, endpoint,
|
||||
* input file, and metadata.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@SuperBuilder
|
||||
@Data
|
||||
public class BatchCreateParams implements ClientRequest<BatchCreateParams> {
|
||||
|
||||
/**
|
||||
* The time frame within which the batch should be processed.
|
||||
*/
|
||||
@JsonProperty("completion_window")
|
||||
private String completionWindow;
|
||||
|
||||
/**
|
||||
* The API endpoint to be used for batch processing.
|
||||
*/
|
||||
@JsonProperty("endpoint")
|
||||
private String endpoint;
|
||||
|
||||
/**
|
||||
* The ID of the uploaded file containing batch requests. Must be the ID of the
|
||||
* uploaded file.
|
||||
*/
|
||||
@JsonProperty("input_file_id")
|
||||
private String inputFileId;
|
||||
|
||||
/**
|
||||
* Optional custom metadata for the batch job.
|
||||
*/
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, String> metadata;
|
||||
|
||||
public BatchCreateParams() {
|
||||
}
|
||||
|
||||
public BatchCreateParams(String completionWindow, String endpoint, String inputFileId,
|
||||
Map<String, String> metadata) {
|
||||
this.completionWindow = completionWindow;
|
||||
this.endpoint = endpoint;
|
||||
this.inputFileId = inputFileId;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package ai.z.openapi.service.batches;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class BatchPage {
|
||||
|
||||
private String object;
|
||||
|
||||
private List<Batch> data;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue