feat: support file parsing (#59)
Co-authored-by: mengqian <cherish_a_meng@163.com>
This commit is contained in:
parent
e5660e39bf
commit
67bd9910e1
14 changed files with 791 additions and 3 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
package ai.z.openapi;
|
package ai.z.openapi;
|
||||||
|
|
||||||
import ai.z.openapi.service.AbstractClientBaseService;
|
import ai.z.openapi.service.AbstractClientBaseService;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingService;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingServiceImpl;
|
||||||
import ai.z.openapi.service.model.ChatError;
|
import ai.z.openapi.service.model.ChatError;
|
||||||
import ai.z.openapi.service.model.ZAiHttpException;
|
import ai.z.openapi.service.model.ZAiHttpException;
|
||||||
import ai.z.openapi.service.chat.ChatService;
|
import ai.z.openapi.service.chat.ChatService;
|
||||||
|
|
@ -106,6 +108,9 @@ public abstract class AbstractAiClient extends AbstractClientBaseService {
|
||||||
/** Voice clone service for voice cloning operations */
|
/** Voice clone service for voice cloning operations */
|
||||||
private VoiceCloneService voiceCloneService;
|
private VoiceCloneService voiceCloneService;
|
||||||
|
|
||||||
|
/** FileParsing service for fileParsing operations */
|
||||||
|
private FileParsingService fileParsingService;
|
||||||
|
|
||||||
/** Moderation service for content safety detection */
|
/** Moderation service for content safety detection */
|
||||||
private ModerationService moderationService;
|
private ModerationService moderationService;
|
||||||
|
|
||||||
|
|
@ -261,6 +266,18 @@ public abstract class AbstractAiClient extends AbstractClientBaseService {
|
||||||
return voiceCloneService;
|
return voiceCloneService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file service for file operations. This service handles file uploads,
|
||||||
|
* downloads, and management.
|
||||||
|
* @return the FileParsingService instance (lazily initialized)
|
||||||
|
*/
|
||||||
|
public synchronized FileParsingService fileParsing() {
|
||||||
|
if (fileParsingService == null) {
|
||||||
|
this.fileParsingService = new FileParsingServiceImpl(this);
|
||||||
|
}
|
||||||
|
return fileParsingService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the moderation service for content safety detection. This service handles
|
* Returns the moderation service for content safety detection. This service handles
|
||||||
* content moderation for text, image, video, and audio inputs.
|
* content moderation for text, image, video, and audio inputs.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package ai.z.openapi.api.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingUploadResp;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingDownloadResp;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
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.Query;
|
||||||
|
import retrofit2.http.Streaming;
|
||||||
|
import retrofit2.http.Part;
|
||||||
|
import retrofit2.http.Multipart;
|
||||||
|
import retrofit2.http.Header;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File Parsing API Provides functionality for uploading files for parsing, and retrieving
|
||||||
|
* the parsing results.
|
||||||
|
*/
|
||||||
|
public interface FileParsingApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a file parsing task. Uploads a file and creates a document parsing job using
|
||||||
|
* specific tool type and file type.
|
||||||
|
* @param multipartBody File data with metadata including tool_type and file_type
|
||||||
|
* @return Information and status of the parsing job
|
||||||
|
*/
|
||||||
|
// @Multipart
|
||||||
|
@POST("files/parser/create")
|
||||||
|
Single<FileParsingUploadResp> createParseTask(@Body MultipartBody multipartBody);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file parsing result. Retrieves the parsing result by taskId and format type.
|
||||||
|
* @param taskId The unique task ID for the parsing job
|
||||||
|
* @param formatType The format type of the parsing result
|
||||||
|
* @return Parsing result content (JSON or raw format)
|
||||||
|
*/
|
||||||
|
@Streaming
|
||||||
|
@GET("files/parser/result/{taskId}/{formatType}")
|
||||||
|
Call<ResponseBody> downloadParseResult(@Path("taskId") String taskId, @Path("formatType") String formatType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import ai.z.openapi.core.model.ClientResponse;
|
||||||
import ai.z.openapi.service.batches.BatchRequest;
|
import ai.z.openapi.service.batches.BatchRequest;
|
||||||
import ai.z.openapi.service.model.ChatError;
|
import ai.z.openapi.service.model.ChatError;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
@ -16,7 +15,6 @@ import lombok.experimental.SuperBuilder;
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
|
||||||
public class FileDelRequest implements ClientRequest<FileDelRequest> {
|
public class FileDelRequest implements ClientRequest<FileDelRequest> {
|
||||||
|
|
||||||
private String fileId;
|
private String fileId;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.core.model.ClientRequest;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File parsing result download request parameters
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class FileParsingDownloadReq implements ClientRequest<FileParsingDownloadReq> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsing task ID (required)
|
||||||
|
*/
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returned content format type (e.g., "download_link", "txt", required)
|
||||||
|
*/
|
||||||
|
private String formatType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File parsing result response DTO
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class FileParsingDownloadResp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsing task ID
|
||||||
|
*/
|
||||||
|
@JsonProperty("task_id")
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result status (e.g., succeeded, failed, etc.)
|
||||||
|
*/
|
||||||
|
@JsonProperty("status")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response message
|
||||||
|
*/
|
||||||
|
@JsonProperty("message")
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsed result content
|
||||||
|
*/
|
||||||
|
@JsonProperty("content")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsing result download link (if available)
|
||||||
|
*/
|
||||||
|
@JsonProperty("parsing_result_url")
|
||||||
|
private String parsingResultUrl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.core.model.ClientResponse;
|
||||||
|
import ai.z.openapi.service.model.ChatError;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class FileParsingDownloadResponse implements ClientResponse<FileParsingDownloadResp> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response status code.
|
||||||
|
*/
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response message.
|
||||||
|
*/
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the request was successful.
|
||||||
|
*/
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FileParsing result data.
|
||||||
|
*/
|
||||||
|
private FileParsingDownloadResp data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error information if the request failed.
|
||||||
|
*/
|
||||||
|
private ChatError error;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.core.model.ClientResponse;
|
||||||
|
import ai.z.openapi.service.model.ChatError;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class FileParsingResponse implements ClientResponse<FileParsingUploadResp> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response status code.
|
||||||
|
*/
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response message.
|
||||||
|
*/
|
||||||
|
private String msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the request was successful.
|
||||||
|
*/
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FileParsing result data.
|
||||||
|
*/
|
||||||
|
private FileParsingUploadResp data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error information if the request failed.
|
||||||
|
*/
|
||||||
|
private ChatError error;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File parsing service interface
|
||||||
|
*/
|
||||||
|
public interface FileParsingService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits a file parsing task to the server.
|
||||||
|
* @param request The file parsing upload request
|
||||||
|
* @return FileParsingUploadResp containing the parsing task info
|
||||||
|
*/
|
||||||
|
FileParsingResponse createParseTask(FileParsingUploadReq request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the result of a parsing task.
|
||||||
|
* @param request The parsing result query request (can include taskId, formatType
|
||||||
|
* etc)
|
||||||
|
* @return FileParsingDownloadResp containing the result content
|
||||||
|
*/
|
||||||
|
FileParsingDownloadResponse getParseResult(FileParsingDownloadReq request);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.AbstractAiClient;
|
||||||
|
import ai.z.openapi.api.fileparsing.FileParsingApi;
|
||||||
|
import ai.z.openapi.core.response.HttpxBinaryResponseContent;
|
||||||
|
import ai.z.openapi.utils.RequestSupplier;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File parsing service implementation
|
||||||
|
*/
|
||||||
|
public class FileParsingServiceImpl implements FileParsingService {
|
||||||
|
|
||||||
|
private final AbstractAiClient zAiClient;
|
||||||
|
|
||||||
|
private final FileParsingApi fileParsingApi;
|
||||||
|
|
||||||
|
public FileParsingServiceImpl(AbstractAiClient zAiClient) {
|
||||||
|
this.zAiClient = zAiClient;
|
||||||
|
this.fileParsingApi = zAiClient.retrofit().create(FileParsingApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileParsingResponse createParseTask(FileParsingUploadReq request) {
|
||||||
|
if (request == null) {
|
||||||
|
throw new IllegalArgumentException("request cannot be null");
|
||||||
|
}
|
||||||
|
if (request.getFilePath() == null) {
|
||||||
|
throw new IllegalArgumentException("file path cannot be null");
|
||||||
|
}
|
||||||
|
if (request.getToolType() == null) {
|
||||||
|
throw new IllegalArgumentException("toolType cannot be null");
|
||||||
|
}
|
||||||
|
// 构建 multipart/form-data
|
||||||
|
RequestSupplier<FileParsingUploadReq, FileParsingUploadResp> supplier = params -> {
|
||||||
|
try {
|
||||||
|
File file = new File(params.getFilePath());
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new RuntimeException("file not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
String toolType = params.getToolType();
|
||||||
|
String fileType = params.getFileType() == null ? "" : params.getFileType();
|
||||||
|
|
||||||
|
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(),
|
||||||
|
RequestBody.create(MediaType.parse("application/octet-stream"), file));
|
||||||
|
MultipartBody.Builder formBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
|
||||||
|
formBodyBuilder.addPart(filePart);
|
||||||
|
formBodyBuilder.addFormDataPart("tool_type", toolType);
|
||||||
|
formBodyBuilder.addFormDataPart("file_type", fileType);
|
||||||
|
|
||||||
|
MultipartBody multipartBody = formBodyBuilder.build();
|
||||||
|
|
||||||
|
return fileParsingApi.createParseTask(multipartBody);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return this.zAiClient.executeRequest(request, supplier, FileParsingResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileParsingDownloadResponse getParseResult(FileParsingDownloadReq request) {
|
||||||
|
if (request == null) {
|
||||||
|
throw new IllegalArgumentException("request cannot be null");
|
||||||
|
}
|
||||||
|
if (request.getTaskId() == null) {
|
||||||
|
throw new IllegalArgumentException("taskId cannot be null");
|
||||||
|
}
|
||||||
|
if (request.getFormatType() == null) {
|
||||||
|
throw new IllegalArgumentException("formatType cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestSupplier<FileParsingDownloadReq, FileParsingDownloadResp> supplier = params -> {
|
||||||
|
try {
|
||||||
|
retrofit2.Call<ResponseBody> call = fileParsingApi.downloadParseResult(request.getTaskId(),
|
||||||
|
request.getFormatType());
|
||||||
|
Response<ResponseBody> execute = call.execute();
|
||||||
|
if (!execute.isSuccessful() || execute.body() == null) {
|
||||||
|
throw new IOException("Failed to download parse result");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpxBinaryResponseContent httpxBinaryResponseContent = new HttpxBinaryResponseContent(execute);
|
||||||
|
String result = httpxBinaryResponseContent.getText();
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
FileParsingDownloadResp fileParsingDownloadResp = mapper.readValue(result,
|
||||||
|
FileParsingDownloadResp.class);
|
||||||
|
|
||||||
|
return Single.just(fileParsingDownloadResp);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.zAiClient.executeRequest(request, supplier, FileParsingDownloadResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.core.model.ClientRequest;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File parsing task upload request parameters
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class FileParsingUploadReq implements ClientRequest<FileParsingUploadReq> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local file path
|
||||||
|
*/
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool type, e.g. "lite"
|
||||||
|
*/
|
||||||
|
private String toolType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File type, e.g. "pdf", "doc", etc.
|
||||||
|
*/
|
||||||
|
private String fileType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File Parsing Task Upload Response DTO Compatible with multiple response structures
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class FileParsingUploadResp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task ID (API field: task_id or taskId)
|
||||||
|
*/
|
||||||
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return message (API field: message)
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,254 @@
|
||||||
|
package ai.z.openapi.service.fileparsing;
|
||||||
|
|
||||||
|
import ai.z.openapi.ZaiClient;
|
||||||
|
import ai.z.openapi.core.config.ZaiConfig;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Base64;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileParsingService test class for testing various functionalities of FileParsingService
|
||||||
|
* and FileParsingServiceImpl
|
||||||
|
*/
|
||||||
|
@DisplayName("FileParsingService Tests")
|
||||||
|
public class FileParsingServiceTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FileParsingServiceTest.class);
|
||||||
|
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
private FileParsingService fileParsingService;
|
||||||
|
|
||||||
|
// Request ID template
|
||||||
|
private static final String REQUEST_ID_TEMPLATE = "fileparsing-test-%d";
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
ZaiConfig zaiConfig = new ZaiConfig();
|
||||||
|
String apiKey = zaiConfig.getApiKey();
|
||||||
|
if (apiKey == null) {
|
||||||
|
zaiConfig.setApiKey("id.test-api-key");
|
||||||
|
}
|
||||||
|
ZaiClient client = new ZaiClient(zaiConfig);
|
||||||
|
fileParsingService = client.fileParsing(); // 假设你的 client 有 fileParsing() 方法
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test FileParsingService Instantiation")
|
||||||
|
void testFileParsingServiceInstantiation() {
|
||||||
|
assertNotNull(fileParsingService, "FileParsingService should be properly instantiated");
|
||||||
|
assertInstanceOf(FileParsingServiceImpl.class, fileParsingService,
|
||||||
|
"FileParsingService should be an instance of FileParsingServiceImpl");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test File Parsing Task Creation - Basic Functionality")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testCreateParseTask() throws JsonProcessingException {
|
||||||
|
// Prepare test data
|
||||||
|
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
|
||||||
|
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder()
|
||||||
|
.toolType("excel")
|
||||||
|
.fileType("xlsx")
|
||||||
|
.filePath("src/test/resources/test.xlsx") // 确保有测试文件
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
FileParsingResponse response = fileParsingService.createParseTask(request);
|
||||||
|
|
||||||
|
// Verify results
|
||||||
|
assertNotNull(response, "Response should not be null");
|
||||||
|
assertEquals(200, response.getCode());
|
||||||
|
assertTrue(response.isSuccess(), "Response should be successful");
|
||||||
|
assertNotNull(response.getData(), "Response data should not be null");
|
||||||
|
assertNotNull(response.getData().getTaskId(), "Response data taskId should not be null");
|
||||||
|
assertNull(response.getError(), "Response error should be null");
|
||||||
|
logger.info("File parsing task create response: {}", mapper.writeValueAsString(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test File Parsing Result Retrieval")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testGetParseResult() throws JsonProcessingException {
|
||||||
|
// First create a file parsing task
|
||||||
|
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
|
||||||
|
|
||||||
|
FileParsingUploadReq uploadRequest = FileParsingUploadReq.builder()
|
||||||
|
.toolType("excel")
|
||||||
|
.fileType("xlsx")
|
||||||
|
.filePath("src/test/resources/test.xlsx")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingResponse createResp = fileParsingService.createParseTask(uploadRequest);
|
||||||
|
|
||||||
|
assertNotNull(createResp, "Create response should not be null");
|
||||||
|
assertTrue(createResp.isSuccess(), "Create response should be successful");
|
||||||
|
assertNotNull(createResp.getData(), "Create response data should not be null");
|
||||||
|
assertNotNull(createResp.getData().getTaskId(), "Task ID should not be null");
|
||||||
|
|
||||||
|
// Retrieve the result using task ID
|
||||||
|
String taskId = createResp.getData().getTaskId();
|
||||||
|
FileParsingDownloadReq downloadReq = FileParsingDownloadReq.builder().taskId(taskId).formatType("json").build();
|
||||||
|
|
||||||
|
FileParsingDownloadResponse downloadResp = fileParsingService.getParseResult(downloadReq);
|
||||||
|
|
||||||
|
assertNotNull(downloadResp, "Download response should not be null");
|
||||||
|
assertEquals(200, downloadResp.getCode());
|
||||||
|
assertNotNull(downloadResp.getData(), "Download response data should not be null");
|
||||||
|
logger.info("File parsing result: taskId={}, response={}", taskId, mapper.writeValueAsString(downloadResp));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test File Parsing Result Error")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testGetParseResultError() {
|
||||||
|
// Use a mock task ID that doesn't exist
|
||||||
|
String mockTaskId = "mock-task-id-" + System.currentTimeMillis();
|
||||||
|
|
||||||
|
FileParsingDownloadReq downloadReq = FileParsingDownloadReq.builder()
|
||||||
|
.taskId(mockTaskId)
|
||||||
|
.formatType("json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingDownloadResponse response = fileParsingService.getParseResult(downloadReq);
|
||||||
|
|
||||||
|
assertNotNull(response, "Response should not be null");
|
||||||
|
// For non-existent task, we expect either an error or unsuccessful response
|
||||||
|
if (!response.isSuccess()) {
|
||||||
|
assertNotNull(response.getError(), "Error should be present for non-existent task");
|
||||||
|
}
|
||||||
|
logger.info("File parsing result error test: taskId={}, response={}", mockTaskId, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = { "excel", "csv", "pdf" })
|
||||||
|
@DisplayName("Test Different File Tool Types")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testDifferentToolTypes(String toolType) throws JsonProcessingException {
|
||||||
|
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
|
||||||
|
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder()
|
||||||
|
.toolType(toolType)
|
||||||
|
.fileType("xlsx")
|
||||||
|
.filePath("src/test/resources/test.xlsx")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingResponse response = fileParsingService.createParseTask(request);
|
||||||
|
|
||||||
|
assertNotNull(response, "Response should not be null");
|
||||||
|
assertEquals(200, response.getCode());
|
||||||
|
logger.info("ToolType {} response: {}", toolType, mapper.writeValueAsString(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null Request for Create")
|
||||||
|
void testValidation_NullRequest_Create() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.createParseTask(null);
|
||||||
|
}, "Null request should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null FilePath")
|
||||||
|
void testValidation_NullFilePath() {
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder().toolType("excel").fileType("xlsx").build();
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.createParseTask(request);
|
||||||
|
}, "Null file path should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null ToolType")
|
||||||
|
void testValidation_NullToolType() {
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder()
|
||||||
|
.fileType("xlsx")
|
||||||
|
.filePath("src/test/resources/test.xlsx")
|
||||||
|
.build();
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.createParseTask(request);
|
||||||
|
}, "Null toolType should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null Request for Download")
|
||||||
|
void testValidation_NullRequest_Download() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.getParseResult(null);
|
||||||
|
}, "Null download request should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null Task ID Download")
|
||||||
|
void testValidation_NullTaskId_Download() {
|
||||||
|
FileParsingDownloadReq downloadReq = FileParsingDownloadReq.builder().formatType("json").build();
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.getParseResult(downloadReq);
|
||||||
|
}, "Null taskId should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test Parameter Validation - Null FormatType Download")
|
||||||
|
void testValidation_NullFormatType_Download() {
|
||||||
|
FileParsingDownloadReq downloadReq = FileParsingDownloadReq.builder().taskId("test-task-id").build();
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
fileParsingService.getParseResult(downloadReq);
|
||||||
|
}, "Null formatType should throw IllegalArgumentException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test File Parsing with Image Input")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testCreateParseTaskWithImage() throws IOException {
|
||||||
|
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
|
||||||
|
String file = ClassLoader.getSystemResource("image_file.png").getFile();
|
||||||
|
byte[] bytes = Files.readAllBytes(new File(file).toPath());
|
||||||
|
Base64.Encoder encoder = Base64.getEncoder();
|
||||||
|
String imageBase64 = encoder.encodeToString(bytes);
|
||||||
|
// 假设解析接口支持 imageBase64 字段
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder()
|
||||||
|
.toolType("image")
|
||||||
|
.fileType("png")
|
||||||
|
.filePath(file) // 或文件路径
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingResponse response = fileParsingService.createParseTask(request);
|
||||||
|
|
||||||
|
assertNotNull(response, "Response should not be null");
|
||||||
|
assertEquals(200, response.getCode());
|
||||||
|
logger.info("File parsing with image input response: {}", mapper.writeValueAsString(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test File Parsing Create Task with Custom Settings")
|
||||||
|
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
|
||||||
|
void testCreateParseTaskWithCustomSettings() throws JsonProcessingException {
|
||||||
|
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
|
||||||
|
|
||||||
|
FileParsingUploadReq request = FileParsingUploadReq.builder()
|
||||||
|
.toolType("excel")
|
||||||
|
.fileType("xlsx")
|
||||||
|
.filePath("src/test/resources/test.xlsx")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingResponse response = fileParsingService.createParseTask(request);
|
||||||
|
|
||||||
|
assertNotNull(response, "Response should not be null");
|
||||||
|
assertEquals(200, response.getCode());
|
||||||
|
logger.info("File parsing with custom settings response: {}", mapper.writeValueAsString(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
pom.xml
2
pom.xml
|
|
@ -45,7 +45,7 @@
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>0.0.6</revision>
|
<revision>0.0.6.1</revision>
|
||||||
<java.version>8</java.version>
|
<java.version>8</java.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
|
|
||||||
125
samples/src/main/ai.z.openapi.samples/FileParsingExample.java
Normal file
125
samples/src/main/ai.z.openapi.samples/FileParsingExample.java
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
package ai.z.openapi.samples;
|
||||||
|
|
||||||
|
import ai.z.openapi.ZaiClient;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingDownloadReq;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingDownloadResponse;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingResponse;
|
||||||
|
import ai.z.openapi.service.fileparsing.FileParsingUploadReq;
|
||||||
|
import ai.z.openapi.utils.StringUtils;
|
||||||
|
|
||||||
|
public class FileParsingExample {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 建议通过环境变量设置 API Key
|
||||||
|
// export ZAI_API_KEY=your.api_key
|
||||||
|
// ZaiClient client = ZaiClient.builder().build();
|
||||||
|
|
||||||
|
// 也可在代码中直接指定 API Key
|
||||||
|
ZaiClient client = ZaiClient.builder()
|
||||||
|
.apiKey("API Key")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 示例1: 创建解析任务
|
||||||
|
System.out.println("=== 文件解析任务创建示例 ===");
|
||||||
|
String filePath = "your file path";
|
||||||
|
String taskId = createFileParsingTaskExample(client, filePath, "pdf", "lite");
|
||||||
|
|
||||||
|
// 示例2: 获取解析结果
|
||||||
|
System.out.println("\n=== 获取解析结果示例 ===");
|
||||||
|
getFileParsingResultExample(client, taskId);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("发生异常: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:创建解析任务(上传文件并解析)
|
||||||
|
*
|
||||||
|
* @param client ZaiClient 实例
|
||||||
|
* @return 解析任务的 taskId
|
||||||
|
*/
|
||||||
|
private static String createFileParsingTaskExample(ZaiClient client, String filePath, String fileType, String toolType) {
|
||||||
|
if (StringUtils.isEmpty(filePath)) {
|
||||||
|
System.err.println("无效的文件路径。");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
FileParsingUploadReq uploadReq = FileParsingUploadReq.builder()
|
||||||
|
.filePath(filePath)
|
||||||
|
.fileType(fileType) // 支持: pdf, docx 等
|
||||||
|
.toolType(toolType) // 解析工具类型: lite, prime, expert
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println("正在上传并创建解析任务...");
|
||||||
|
FileParsingResponse response = client.fileParsing().createParseTask(uploadReq);
|
||||||
|
if (response.isSuccess()) {
|
||||||
|
if (null != response.getData().getTaskId()) {
|
||||||
|
String taskId = response.getData().getTaskId();
|
||||||
|
System.out.println("解析任务创建成功,TaskId: " + taskId);
|
||||||
|
return taskId;
|
||||||
|
} else {
|
||||||
|
System.err.println("解析任务创建失败: " + response.getData().getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("解析任务创建失败: " + response.getMsg());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("文件解析任务错误: " + e.getMessage());
|
||||||
|
}
|
||||||
|
// 返回 null 表示创建失败
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:获取解析结果
|
||||||
|
*
|
||||||
|
* @param client ZaiClient 实例
|
||||||
|
* @param taskId 解析任务ID
|
||||||
|
*/
|
||||||
|
private static void getFileParsingResultExample(ZaiClient client, String taskId) {
|
||||||
|
if (taskId == null || taskId.isEmpty()) {
|
||||||
|
System.err.println("无效的任务ID,无法获取解析结果。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int maxRetry = 100; // 最多轮询100次
|
||||||
|
int intervalMs = 3000; // 每次间隔3秒
|
||||||
|
for (int i = 0; i < maxRetry; i++) {
|
||||||
|
FileParsingDownloadReq downloadReq = FileParsingDownloadReq.builder()
|
||||||
|
.taskId(taskId)
|
||||||
|
.formatType("text")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
FileParsingDownloadResponse response = client.fileParsing().getParseResult(downloadReq);
|
||||||
|
|
||||||
|
if (response.isSuccess()) {
|
||||||
|
String status = response.getData().getStatus();
|
||||||
|
System.out.println("当前任务状态: " + status);
|
||||||
|
|
||||||
|
if ("succeeded".equalsIgnoreCase(status)) {
|
||||||
|
System.out.println("解析结果获取成功!");
|
||||||
|
System.out.println("解析内容: " + response.getData().getContent());
|
||||||
|
System.out.println("内容下载链接: " + response.getData().getParsingResultUrl());
|
||||||
|
return;
|
||||||
|
} else if ("processing".equalsIgnoreCase(status)) {
|
||||||
|
System.out.println("解析进行中,请稍候...");
|
||||||
|
Thread.sleep(intervalMs);
|
||||||
|
} else {
|
||||||
|
System.out.println("解析任务异常,状态: " + status + ",消息: " + response.getData().getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("解析结果获取失败: " + response.getMsg());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("等待超时,请稍后自行查询解析结果。");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("获取解析结果时异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue