feat: support file delete api (#45)
This commit is contained in:
parent
ffa57e420f
commit
838c847d6c
10 changed files with 113 additions and 26 deletions
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 = "^[^.]+\\.[^.]+$")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue