feat: support file delete api (#45)

This commit is contained in:
tomsun28 2025-08-28 10:33:11 +08:00 committed by GitHub
parent ffa57e420f
commit 838c847d6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 113 additions and 26 deletions

View file

@ -33,6 +33,7 @@ import ai.z.openapi.core.model.FlowableClientResponse;
import ai.z.openapi.utils.FlowableRequestSupplier; import ai.z.openapi.utils.FlowableRequestSupplier;
import ai.z.openapi.utils.OkHttps; import ai.z.openapi.utils.OkHttps;
import ai.z.openapi.utils.RequestSupplier; import ai.z.openapi.utils.RequestSupplier;
import ai.z.openapi.utils.StringUtils;
import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
@ -318,7 +319,9 @@ public abstract class AbstractAiClient extends AbstractClientBaseService {
tResp.setMsg("Call Failed"); tResp.setMsg("Call Failed");
tResp.setSuccess(false); tResp.setSuccess(false);
ChatError chatError = new ChatError(); ChatError chatError = new ChatError();
chatError.setCode(Integer.parseInt(e.code)); if (StringUtils.isNotEmpty(e.code)) {
chatError.setCode(Integer.parseInt(e.code));
}
chatError.setMessage(e.getMessage()); chatError.setMessage(e.getMessage());
tResp.setError(chatError); tResp.setError(chatError);
} }

View file

@ -31,15 +31,6 @@ public interface FileApi {
@POST("files") @POST("files")
Single<File> uploadFile(@Body MultipartBody multipartBody); Single<File> uploadFile(@Body MultipartBody multipartBody);
/**
* Retrieve file metadata and information Gets detailed information about a previously
* uploaded file
* @param fileId Unique identifier of the file to retrieve
* @return File metadata including name, size, purpose, and creation time
*/
@GET("files/{file_id}")
Single<File> retrieveFile(@Path("file_id") String fileId);
/** /**
* Delete a file from the platform Permanently removes the file and all associated * Delete a file from the platform Permanently removes the file and all associated
* data * data

View file

@ -12,6 +12,7 @@ import ai.z.openapi.service.model.ZAiHttpException;
import ai.z.openapi.utils.FlowableRequestSupplier; import ai.z.openapi.utils.FlowableRequestSupplier;
import ai.z.openapi.utils.RequestSupplier; import ai.z.openapi.utils.RequestSupplier;
import ai.z.openapi.utils.StringUtils; import ai.z.openapi.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.reactivex.rxjava3.core.BackpressureStrategy; import io.reactivex.rxjava3.core.BackpressureStrategy;
import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Flowable;
@ -117,10 +118,41 @@ public abstract class AbstractClientBaseService {
if (StringUtils.isEmpty(errorBody)) { if (StringUtils.isEmpty(errorBody)) {
throw e; throw e;
} }
ZAiError error = mapper.readValue(errorBody, ZAiError.class); // here not only the ZAiError, also has {"error": "message"} and others
throw new ZAiHttpException(error, e, e.code()); JsonNode jsonNode = mapper.readTree(errorBody);
if (jsonNode.has("error")) {
JsonNode errorNode = jsonNode.get("error");
if (errorNode.isTextual()) {
JsonNode codeNode = jsonNode.get("code");
throw new ZAiHttpException(errorNode.asText(), codeNode == null ? null : codeNode.asText(), e,
e.code());
}
else {
ZAiError error = mapper.readValue(errorBody, ZAiError.class);
throw new ZAiHttpException(error, e, e.code());
}
}
else if (jsonNode.has("msg")) {
JsonNode msgNode = jsonNode.get("msg");
JsonNode codeNode = jsonNode.get("code");
throw new ZAiHttpException(msgNode.asText(), codeNode == null ? null : codeNode.asText(), e,
e.code());
}
else if (jsonNode.has("message")) {
JsonNode msgNode = jsonNode.get("message");
JsonNode codeNode = jsonNode.get("code");
throw new ZAiHttpException(msgNode.asText(), codeNode == null ? null : codeNode.asText(), e,
e.code());
}
else {
throw new ZAiHttpException(errorBody, null, e, e.code());
}
} }
catch (IOException ex) { catch (ZAiHttpException zAiHttpException) {
throw zAiHttpException;
}
catch (Exception ex) {
logger.error(ex.getMessage(), ex);
// couldn't parse ZAiError error // couldn't parse ZAiError error
throw e; throw e;
} }

View file

@ -0,0 +1,24 @@
package ai.z.openapi.service.file;
import ai.z.openapi.core.model.ClientRequest;
import ai.z.openapi.core.model.ClientResponse;
import ai.z.openapi.service.batches.BatchRequest;
import ai.z.openapi.service.model.ChatError;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@EqualsAndHashCode(callSuper = false)
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class FileDelRequest implements ClientRequest<FileDelRequest> {
private String fileId;
}

View file

@ -1,9 +1,11 @@
package ai.z.openapi.service.file; package ai.z.openapi.service.file;
import ai.z.openapi.core.model.ClientResponse;
import ai.z.openapi.service.model.ChatError;
import lombok.Data; import lombok.Data;
@Data @Data
public class FileDelResponse { public class FileDelResponse implements ClientResponse<FileDeleted> {
private int code; private int code;
@ -13,4 +15,6 @@ public class FileDelResponse {
private FileDeleted data; private FileDeleted data;
private ChatError error;
} }

View file

@ -15,6 +15,13 @@ public interface FileService {
*/ */
FileApiResponse uploadFile(FileUploadParams request); FileApiResponse uploadFile(FileUploadParams request);
/**
* Delete file by file ID.
* @param request the file id to delete.
* @return FileDelResponse containing the delete result
*/
FileDelResponse deleteFile(FileDelRequest request);
/** /**
* Lists all files. * Lists all files.
* @param queryFilesRequest FileListParams containing the query parameters for listing * @param queryFilesRequest FileListParams containing the query parameters for listing

View file

@ -70,6 +70,12 @@ public class FileServiceImpl implements FileService {
return this.zAiClient.executeRequest(request, supplier, FileApiResponse.class); return this.zAiClient.executeRequest(request, supplier, FileApiResponse.class);
} }
@Override
public FileDelResponse deleteFile(FileDelRequest request) {
RequestSupplier<FileDelRequest, FileDeleted> supplier = (params -> fileApi.deletedFile(params.getFileId()));
return this.zAiClient.executeRequest(request, supplier, FileDelResponse.class);
}
@Override @Override
public QueryFileApiResponse listFiles(FileListParams queryFilesRequest) { public QueryFileApiResponse listFiles(FileListParams queryFilesRequest) {
RequestSupplier<FileListParams, QueryFileResult> supplier = (params) -> fileApi.queryFileList(params.getAfter(), RequestSupplier<FileListParams, QueryFileResult> supplier = (params) -> fileApi.queryFileList(params.getAfter(),

View file

@ -30,12 +30,8 @@ public class ZAiError {
*/ */
String message; String message;
String type;
String param;
/** /**
* ZAI error code, for example "invalid_api_key" * ZAI error code, for example "401"
*/ */
String code; String code;

View file

@ -8,23 +8,27 @@ public class ZAiHttpException extends RuntimeException {
public final int statusCode; public final int statusCode;
/** /**
* ZAI error code, for example "invalid_api_key" * ZAI error code, for example "1233"
*/ */
public final String code; public final String code;
public final String param;
/** /**
* ZAI error type, for example "invalid_request_error" * ZAI error message
*/ */
public final String type; public final String msg;
public ZAiHttpException(ZAiError error, Exception parent, int statusCode) { public ZAiHttpException(ZAiError error, Exception parent, int statusCode) {
super(error.error.message, parent); super(error.error.message, parent);
this.statusCode = statusCode; this.statusCode = statusCode;
this.code = error.error.code; this.code = error.error.code;
this.param = error.error.param; this.msg = error.error.message;
this.type = error.error.type; }
public ZAiHttpException(String errorMsg, String errorCode, Exception parent, int statusCode) {
super(errorMsg, parent);
this.statusCode = statusCode;
this.code = errorCode;
this.msg = errorMsg;
} }
} }

View file

@ -174,6 +174,26 @@ public class FileServiceTest {
logger.info("List files response: {}", mapper.writeValueAsString(response)); logger.info("List files response: {}", mapper.writeValueAsString(response));
} }
@Test
@DisplayName("Test Delete File - Basic Functionality")
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")
void testDeleteFile() throws JsonProcessingException {
String fileId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis());
FileDelRequest request = FileDelRequest.builder().fileId(fileId).build();
// Execute test
FileDelResponse response = fileService.deleteFile(request);
// Verify results
assertNotNull(response, "Response should not be null");
assertFalse(response.isSuccess(), "Response should be failed");
assertNull(response.getData(), "Response data should not be null");
assertNotNull(response.getError(), "Response error should be null");
logger.info("Delete file response: {}", mapper.writeValueAsString(response));
}
@Test @Test
@DisplayName("Test List Files with Purpose Filter") @DisplayName("Test List Files with Purpose Filter")
@EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$") @EnabledIfEnvironmentVariable(named = "ZAI_API_KEY", matches = "^[^.]+\\.[^.]+$")