Skip to content

Commit 67bd991

Browse files
code-c-lightmengqian
andauthored
feat: support file parsing (#59)
Co-authored-by: mengqian <cherish_a_meng@163.com>
1 parent e5660e3 commit 67bd991

File tree

14 files changed

+791
-3
lines changed

14 files changed

+791
-3
lines changed

core/src/main/java/ai/z/openapi/AbstractAiClient.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package ai.z.openapi;
22

33
import ai.z.openapi.service.AbstractClientBaseService;
4+
import ai.z.openapi.service.fileparsing.FileParsingService;
5+
import ai.z.openapi.service.fileparsing.FileParsingServiceImpl;
46
import ai.z.openapi.service.model.ChatError;
57
import ai.z.openapi.service.model.ZAiHttpException;
68
import ai.z.openapi.service.chat.ChatService;
@@ -106,6 +108,9 @@ public abstract class AbstractAiClient extends AbstractClientBaseService {
106108
/** Voice clone service for voice cloning operations */
107109
private VoiceCloneService voiceCloneService;
108110

111+
/** FileParsing service for fileParsing operations */
112+
private FileParsingService fileParsingService;
113+
109114
/** Moderation service for content safety detection */
110115
private ModerationService moderationService;
111116

@@ -261,6 +266,18 @@ public synchronized VoiceCloneService voiceClone() {
261266
return voiceCloneService;
262267
}
263268

269+
/**
270+
* Returns the file service for file operations. This service handles file uploads,
271+
* downloads, and management.
272+
* @return the FileParsingService instance (lazily initialized)
273+
*/
274+
public synchronized FileParsingService fileParsing() {
275+
if (fileParsingService == null) {
276+
this.fileParsingService = new FileParsingServiceImpl(this);
277+
}
278+
return fileParsingService;
279+
}
280+
264281
/**
265282
* Returns the moderation service for content safety detection. This service handles
266283
* content moderation for text, image, video, and audio inputs.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package ai.z.openapi.api.fileparsing;
2+
3+
import ai.z.openapi.service.fileparsing.FileParsingUploadResp;
4+
import ai.z.openapi.service.fileparsing.FileParsingDownloadResp;
5+
import io.reactivex.rxjava3.core.Single;
6+
import okhttp3.MultipartBody;
7+
import okhttp3.ResponseBody;
8+
import retrofit2.Call;
9+
import retrofit2.http.Body;
10+
import retrofit2.http.GET;
11+
import retrofit2.http.POST;
12+
import retrofit2.http.Path;
13+
import retrofit2.http.Query;
14+
import retrofit2.http.Streaming;
15+
import retrofit2.http.Part;
16+
import retrofit2.http.Multipart;
17+
import retrofit2.http.Header;
18+
19+
import java.io.File;
20+
21+
/**
22+
* File Parsing API Provides functionality for uploading files for parsing, and retrieving
23+
* the parsing results.
24+
*/
25+
public interface FileParsingApi {
26+
27+
/**
28+
* Create a file parsing task. Uploads a file and creates a document parsing job using
29+
* specific tool type and file type.
30+
* @param multipartBody File data with metadata including tool_type and file_type
31+
* @return Information and status of the parsing job
32+
*/
33+
// @Multipart
34+
@POST("files/parser/create")
35+
Single<FileParsingUploadResp> createParseTask(@Body MultipartBody multipartBody);
36+
37+
/**
38+
* Get a file parsing result. Retrieves the parsing result by taskId and format type.
39+
* @param taskId The unique task ID for the parsing job
40+
* @param formatType The format type of the parsing result
41+
* @return Parsing result content (JSON or raw format)
42+
*/
43+
@Streaming
44+
@GET("files/parser/result/{taskId}/{formatType}")
45+
Call<ResponseBody> downloadParseResult(@Path("taskId") String taskId, @Path("formatType") String formatType);
46+
47+
}

core/src/main/java/ai/z/openapi/service/file/FileDelRequest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import ai.z.openapi.service.batches.BatchRequest;
66
import ai.z.openapi.service.model.ChatError;
77
import lombok.AllArgsConstructor;
8-
import lombok.Builder;
98
import lombok.Data;
109
import lombok.EqualsAndHashCode;
1110
import lombok.NoArgsConstructor;
@@ -16,7 +15,6 @@
1615
@NoArgsConstructor
1716
@AllArgsConstructor
1817
@Data
19-
@Builder
2018
public class FileDelRequest implements ClientRequest<FileDelRequest> {
2119

2220
private String fileId;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
import ai.z.openapi.core.model.ClientRequest;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Data;
6+
import lombok.EqualsAndHashCode;
7+
import lombok.NoArgsConstructor;
8+
import lombok.experimental.SuperBuilder;
9+
10+
/**
11+
* File parsing result download request parameters
12+
*/
13+
@EqualsAndHashCode(callSuper = false)
14+
@SuperBuilder
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@Data
18+
public class FileParsingDownloadReq implements ClientRequest<FileParsingDownloadReq> {
19+
20+
/**
21+
* Parsing task ID (required)
22+
*/
23+
private String taskId;
24+
25+
/**
26+
* Returned content format type (e.g., "download_link", "txt", required)
27+
*/
28+
private String formatType;
29+
30+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Data;
6+
import lombok.EqualsAndHashCode;
7+
import lombok.NoArgsConstructor;
8+
import lombok.experimental.SuperBuilder;
9+
10+
/**
11+
* File parsing result response DTO
12+
*/
13+
@EqualsAndHashCode(callSuper = false)
14+
@SuperBuilder
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@Data
18+
public class FileParsingDownloadResp {
19+
20+
/**
21+
* Parsing task ID
22+
*/
23+
@JsonProperty("task_id")
24+
private String taskId;
25+
26+
/**
27+
* Result status (e.g., succeeded, failed, etc.)
28+
*/
29+
@JsonProperty("status")
30+
private String status;
31+
32+
/**
33+
* Response message
34+
*/
35+
@JsonProperty("message")
36+
private String message;
37+
38+
/**
39+
* Parsed result content
40+
*/
41+
@JsonProperty("content")
42+
private String content;
43+
44+
/**
45+
* Parsing result download link (if available)
46+
*/
47+
@JsonProperty("parsing_result_url")
48+
private String parsingResultUrl;
49+
50+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
import ai.z.openapi.core.model.ClientResponse;
4+
import ai.z.openapi.service.model.ChatError;
5+
import lombok.Data;
6+
7+
@Data
8+
public class FileParsingDownloadResponse implements ClientResponse<FileParsingDownloadResp> {
9+
10+
/**
11+
* Response status code.
12+
*/
13+
private int code;
14+
15+
/**
16+
* Response message.
17+
*/
18+
private String msg;
19+
20+
/**
21+
* Indicates whether the request was successful.
22+
*/
23+
private boolean success;
24+
25+
/**
26+
* The FileParsing result data.
27+
*/
28+
private FileParsingDownloadResp data;
29+
30+
/**
31+
* Error information if the request failed.
32+
*/
33+
private ChatError error;
34+
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
import ai.z.openapi.core.model.ClientResponse;
4+
import ai.z.openapi.service.model.ChatError;
5+
import lombok.Data;
6+
7+
@Data
8+
public class FileParsingResponse implements ClientResponse<FileParsingUploadResp> {
9+
10+
/**
11+
* Response status code.
12+
*/
13+
private int code;
14+
15+
/**
16+
* Response message.
17+
*/
18+
private String msg;
19+
20+
/**
21+
* Indicates whether the request was successful.
22+
*/
23+
private boolean success;
24+
25+
/**
26+
* The FileParsing result data.
27+
*/
28+
private FileParsingUploadResp data;
29+
30+
/**
31+
* Error information if the request failed.
32+
*/
33+
private ChatError error;
34+
35+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
/**
4+
* File parsing service interface
5+
*/
6+
public interface FileParsingService {
7+
8+
/**
9+
* Submits a file parsing task to the server.
10+
* @param request The file parsing upload request
11+
* @return FileParsingUploadResp containing the parsing task info
12+
*/
13+
FileParsingResponse createParseTask(FileParsingUploadReq request);
14+
15+
/**
16+
* Retrieves the result of a parsing task.
17+
* @param request The parsing result query request (can include taskId, formatType
18+
* etc)
19+
* @return FileParsingDownloadResp containing the result content
20+
*/
21+
FileParsingDownloadResponse getParseResult(FileParsingDownloadReq request);
22+
23+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package ai.z.openapi.service.fileparsing;
2+
3+
import ai.z.openapi.AbstractAiClient;
4+
import ai.z.openapi.api.fileparsing.FileParsingApi;
5+
import ai.z.openapi.core.response.HttpxBinaryResponseContent;
6+
import ai.z.openapi.utils.RequestSupplier;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
import io.reactivex.rxjava3.core.Single;
9+
import okhttp3.MediaType;
10+
import okhttp3.MultipartBody;
11+
import okhttp3.RequestBody;
12+
import okhttp3.ResponseBody;
13+
import retrofit2.Response;
14+
15+
import java.io.File;
16+
import java.io.IOException;
17+
18+
/**
19+
* File parsing service implementation
20+
*/
21+
public class FileParsingServiceImpl implements FileParsingService {
22+
23+
private final AbstractAiClient zAiClient;
24+
25+
private final FileParsingApi fileParsingApi;
26+
27+
public FileParsingServiceImpl(AbstractAiClient zAiClient) {
28+
this.zAiClient = zAiClient;
29+
this.fileParsingApi = zAiClient.retrofit().create(FileParsingApi.class);
30+
}
31+
32+
@Override
33+
public FileParsingResponse createParseTask(FileParsingUploadReq request) {
34+
if (request == null) {
35+
throw new IllegalArgumentException("request cannot be null");
36+
}
37+
if (request.getFilePath() == null) {
38+
throw new IllegalArgumentException("file path cannot be null");
39+
}
40+
if (request.getToolType() == null) {
41+
throw new IllegalArgumentException("toolType cannot be null");
42+
}
43+
// 构建 multipart/form-data
44+
RequestSupplier<FileParsingUploadReq, FileParsingUploadResp> supplier = params -> {
45+
try {
46+
File file = new File(params.getFilePath());
47+
if (!file.exists()) {
48+
throw new RuntimeException("file not found");
49+
}
50+
51+
String toolType = params.getToolType();
52+
String fileType = params.getFileType() == null ? "" : params.getFileType();
53+
54+
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(),
55+
RequestBody.create(MediaType.parse("application/octet-stream"), file));
56+
MultipartBody.Builder formBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
57+
formBodyBuilder.addPart(filePart);
58+
formBodyBuilder.addFormDataPart("tool_type", toolType);
59+
formBodyBuilder.addFormDataPart("file_type", fileType);
60+
61+
MultipartBody multipartBody = formBodyBuilder.build();
62+
63+
return fileParsingApi.createParseTask(multipartBody);
64+
}
65+
catch (Exception e) {
66+
throw new RuntimeException(e);
67+
}
68+
};
69+
return this.zAiClient.executeRequest(request, supplier, FileParsingResponse.class);
70+
}
71+
72+
@Override
73+
public FileParsingDownloadResponse getParseResult(FileParsingDownloadReq request) {
74+
if (request == null) {
75+
throw new IllegalArgumentException("request cannot be null");
76+
}
77+
if (request.getTaskId() == null) {
78+
throw new IllegalArgumentException("taskId cannot be null");
79+
}
80+
if (request.getFormatType() == null) {
81+
throw new IllegalArgumentException("formatType cannot be null");
82+
}
83+
84+
RequestSupplier<FileParsingDownloadReq, FileParsingDownloadResp> supplier = params -> {
85+
try {
86+
retrofit2.Call<ResponseBody> call = fileParsingApi.downloadParseResult(request.getTaskId(),
87+
request.getFormatType());
88+
Response<ResponseBody> execute = call.execute();
89+
if (!execute.isSuccessful() || execute.body() == null) {
90+
throw new IOException("Failed to download parse result");
91+
}
92+
93+
HttpxBinaryResponseContent httpxBinaryResponseContent = new HttpxBinaryResponseContent(execute);
94+
String result = httpxBinaryResponseContent.getText();
95+
96+
ObjectMapper mapper = new ObjectMapper();
97+
FileParsingDownloadResp fileParsingDownloadResp = mapper.readValue(result,
98+
FileParsingDownloadResp.class);
99+
100+
return Single.just(fileParsingDownloadResp);
101+
}
102+
catch (Exception e) {
103+
throw new RuntimeException(e);
104+
}
105+
};
106+
107+
return this.zAiClient.executeRequest(request, supplier, FileParsingDownloadResponse.class);
108+
}
109+
110+
}

0 commit comments

Comments
 (0)