From b6a57c8d8f943c291ed66dd937f7aa7cf8273d05 Mon Sep 17 00:00:00 2001 From: Joshua Oladokun Date: Tue, 15 Oct 2024 11:14:07 +0100 Subject: [PATCH] add ai prompt fine-tuning methods --- src/main/java/com/crowdin/client/Client.java | 4 + .../java/com/crowdin/client/ai/AIApi.java | 150 +++++++++++++++ .../ai/model/FineTuningDatasetDownload.java | 10 + .../FineTuningDatasetDownloadResponse.java | 9 + .../ai/model/FineTuningDatasetRequest.java | 17 ++ .../ai/model/FineTuningDatasetResponse.java | 33 ++++ .../client/ai/model/FineTuningEvent.java | 22 +++ .../ai/model/FineTuningEventResponseList.java | 24 +++ .../model/FineTuningEventResponseObject.java | 8 + .../client/ai/model/FineTuningJob.java | 56 ++++++ .../client/ai/model/FineTuningJobRequest.java | 31 +++ .../ai/model/FineTuningJobResponseList.java | 24 +++ .../ai/model/FineTuningJobResponseObject.java | 8 + .../client/ai/model/FineTuningJobStatus.java | 4 + .../java/com/crowdin/client/ai/AIApiTest.java | 178 ++++++++++++++++++ .../api/ai/downloadFineTuningDataset.json | 6 + .../ai/fineTuningDatasetGenerationStatus.json | 25 +++ .../api/ai/fineTuningEventsResponse.json | 23 +++ .../api/ai/fineTuningJobListResponse.json | 63 +++++++ .../api/ai/fineTuningJobRequest.json | 8 + .../api/ai/fineTuningJobResponse.json | 55 ++++++ .../api/ai/fineTuningJobStatusResponse.json | 55 ++++++ .../ai/generateFineTuningDatasetRequest.json | 12 ++ .../ai/generateFineTuningDatasetResponse.json | 25 +++ 24 files changed, 850 insertions(+) create mode 100644 src/main/java/com/crowdin/client/ai/AIApi.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownload.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownloadResponse.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningDatasetRequest.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningDatasetResponse.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningEvent.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseList.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseObject.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningJob.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningJobRequest.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseList.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseObject.java create mode 100644 src/main/java/com/crowdin/client/ai/model/FineTuningJobStatus.java create mode 100644 src/test/java/com/crowdin/client/ai/AIApiTest.java create mode 100644 src/test/resources/api/ai/downloadFineTuningDataset.json create mode 100644 src/test/resources/api/ai/fineTuningDatasetGenerationStatus.json create mode 100644 src/test/resources/api/ai/fineTuningEventsResponse.json create mode 100644 src/test/resources/api/ai/fineTuningJobListResponse.json create mode 100644 src/test/resources/api/ai/fineTuningJobRequest.json create mode 100644 src/test/resources/api/ai/fineTuningJobResponse.json create mode 100644 src/test/resources/api/ai/fineTuningJobStatusResponse.json create mode 100644 src/test/resources/api/ai/generateFineTuningDatasetRequest.json create mode 100644 src/test/resources/api/ai/generateFineTuningDatasetResponse.json diff --git a/src/main/java/com/crowdin/client/Client.java b/src/main/java/com/crowdin/client/Client.java index a0cae4d1..4b71fece 100644 --- a/src/main/java/com/crowdin/client/Client.java +++ b/src/main/java/com/crowdin/client/Client.java @@ -1,5 +1,6 @@ package com.crowdin.client; +import com.crowdin.client.ai.AIApi; import com.crowdin.client.applications.ApplicationsApi; import com.crowdin.client.branches.BranchesApi; import com.crowdin.client.bundles.BundlesApi; @@ -72,6 +73,7 @@ public class Client extends CrowdinApi { private final ApplicationsApi applicationsApi; private final ClientsApi clientsApi; private final BranchesApi branchesApi; + private final AIApi aiApi; public Client(Credentials credentials) { super(credentials); @@ -107,6 +109,7 @@ public Client(Credentials credentials) { this.applicationsApi = new ApplicationsApi(credentials); this.clientsApi = new ClientsApi(credentials); this.branchesApi = new BranchesApi(credentials); + this.aiApi = new AIApi(credentials); } public Client(Credentials credentials, ClientConfig clientConfig) { @@ -143,6 +146,7 @@ public Client(Credentials credentials, ClientConfig clientConfig) { this.applicationsApi = new ApplicationsApi(credentials, clientConfig); this.clientsApi = new ClientsApi(credentials, clientConfig); this.branchesApi = new BranchesApi(credentials, clientConfig); + this.aiApi = new AIApi(credentials, clientConfig); } } diff --git a/src/main/java/com/crowdin/client/ai/AIApi.java b/src/main/java/com/crowdin/client/ai/AIApi.java new file mode 100644 index 00000000..f3f30ea5 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/AIApi.java @@ -0,0 +1,150 @@ +package com.crowdin.client.ai; + +import com.crowdin.client.ai.model.FineTuningDatasetDownload; +import com.crowdin.client.ai.model.FineTuningDatasetDownloadResponse; +import com.crowdin.client.ai.model.FineTuningDatasetRequest; +import com.crowdin.client.ai.model.FineTuningDatasetResponse; +import com.crowdin.client.ai.model.FineTuningDatasetResponse.FineTuningDatasetData; +import com.crowdin.client.ai.model.FineTuningEvent; +import com.crowdin.client.ai.model.FineTuningEventResponseList; +import com.crowdin.client.ai.model.FineTuningJob; +import com.crowdin.client.ai.model.FineTuningJobRequest; +import com.crowdin.client.ai.model.FineTuningJobResponseList; +import com.crowdin.client.ai.model.FineTuningJobResponseObject; +import com.crowdin.client.core.CrowdinApi; +import com.crowdin.client.core.http.HttpRequestConfig; +import com.crowdin.client.core.model.ClientConfig; +import com.crowdin.client.core.model.Credentials; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; + +public class AIApi extends CrowdinApi { + + public AIApi(Credentials credentials) { + super(credentials); + } + + public AIApi(Credentials credentials, ClientConfig clientConfig) { + super(credentials, clientConfig); + } + + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param jobIdentifier AI prompt fine-tuning dataset generation identifier, consists of 36 characters + * @return dataset generation status + * @see + * */ + + public ResponseObject getFineTuningDatasetGenerationStatus( + final long userId, final long aiPromptId, final String jobIdentifier) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/datasets/%s", this.url, userId, aiPromptId, jobIdentifier); + FineTuningDatasetResponse response = this.httpClient.get(url, new HttpRequestConfig(), FineTuningDatasetResponse.class); + return ResponseObject.of(response.getData()); + } + + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param request request body + * @return fine-tuning dataset + * @see + * */ + public ResponseObject generateFineTuningDataset( + final long userId, final long aiPromptId, final FineTuningDatasetRequest request) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/datasets", this.url, userId, aiPromptId); + FineTuningDatasetResponse response = this.httpClient.post(url, request, new HttpRequestConfig(), FineTuningDatasetResponse.class); + return ResponseObject.of(response.getData()); + } + + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param jobIdentifier AI prompt fine-tuning dataset generation identifier, consists of 36 characters + * @return fine-tuning event list + * @see + * */ + + public ResponseList getFineTuningEventList( + final long userId, final long aiPromptId, final String jobIdentifier) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/jobs/%s/events", this.url, userId, aiPromptId, jobIdentifier); + FineTuningEventResponseList responseList = this.httpClient.get(url, new HttpRequestConfig(), FineTuningEventResponseList.class); + return FineTuningEventResponseList.to(responseList); + } + + /** + * @param userId user identifier + * @return fine-tuning job list + * @see + * */ + + public ResponseList getFineTuningJobList(final long userId) { + String url = String.format("%s/users/%d/ai/prompts/fine-tuning/jobs", this.url, userId); + FineTuningJobResponseList responseList = this.httpClient.get(url, new HttpRequestConfig(), FineTuningJobResponseList.class); + return FineTuningJobResponseList.to(responseList); + } + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param request request body + * @return AI Prompt Fine-Tuning Dataset Job + * @see + * */ + + public ResponseObject createFineTuningJob(final long userId, final long aiPromptId, final FineTuningJobRequest request) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/jobs", this.url, userId, aiPromptId); + FineTuningJobResponseObject responseObject = this.httpClient.post(url, request, new HttpRequestConfig(), FineTuningJobResponseObject.class); + return ResponseObject.of(responseObject.getData()); + } + + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param jobIdentifier AI prompt fine-tuning dataset generation identifier, consists of 36 characters + * @return AI Prompt Fine-Tuning Dataset Job Status + * @see + * */ + + public ResponseObject getFineTuningJobStatus(final long userId, final long aiPromptId, final String jobIdentifier) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/jobs/%s", this.url, userId, aiPromptId, jobIdentifier); + FineTuningJobResponseObject responseObject = this.httpClient.get(url, new HttpRequestConfig(), FineTuningJobResponseObject.class); + return ResponseObject.of(responseObject.getData()); + } + + /** + * @param userId user identifier + * @param aiPromptId AI prompt identifier + * @param jobIdentifier AI prompt fine-tuning dataset generation identifier, consists of 36 characters + * @return AI Prompt Fine-Tuning Dataset Download URL + * @see + * */ + + public ResponseObject downloadFineTuningDatasetDownload(final long userId, final long aiPromptId, final String jobIdentifier) { + String url = String.format("%s/users/%d/ai/prompts/%d/fine-tuning/datasets/%s/download", this.url, userId, aiPromptId, jobIdentifier); + FineTuningDatasetDownloadResponse response = this.httpClient.get(url, new HttpRequestConfig(), FineTuningDatasetDownloadResponse.class); + return ResponseObject.of(response.getData()); + } + +} + diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownload.java b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownload.java new file mode 100644 index 00000000..58b98c10 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownload.java @@ -0,0 +1,10 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import lombok.Data; + +@Data +public class FineTuningDatasetDownload { + private String url; + private Date expireIn; +} \ No newline at end of file diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownloadResponse.java b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownloadResponse.java new file mode 100644 index 00000000..75299849 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetDownloadResponse.java @@ -0,0 +1,9 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import lombok.Data; + +@Data +public class FineTuningDatasetDownloadResponse { + private FineTuningDatasetDownload data; +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetRequest.java b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetRequest.java new file mode 100644 index 00000000..64420e0a --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetRequest.java @@ -0,0 +1,17 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import java.util.List; +import lombok.Data; + +@Data +public class FineTuningDatasetRequest { + private List projectIds; + private List tmIds; + private String purpose; + private Date dateFrom; + private Date dateTo; + private Long maxFileSize; + private Long minExamplesCount; + private Long maxExamplesCount; +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetResponse.java b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetResponse.java new file mode 100644 index 00000000..1cdb6c98 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningDatasetResponse.java @@ -0,0 +1,33 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import java.util.List; +import lombok.Data; + +@Data +public class FineTuningDatasetResponse { + private FineTuningDatasetData data; + + @Data + public static class FineTuningDatasetData { + private String identifier; + private String status; + private Long progress; + private DatasetAttributes attributes; + private Date createdAt; + private Date updatedAt; + private Date startedAt; + } + + @Data + public static class DatasetAttributes { + private List projectIds; + private List tmIds; + private String purpose; + private Date dateFrom; + private Date dateTo; + private Long maxFileSize; + private Long minExamplesCount; + private Long maxExamplesCount; + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningEvent.java b/src/main/java/com/crowdin/client/ai/model/FineTuningEvent.java new file mode 100644 index 00000000..d62790d5 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningEvent.java @@ -0,0 +1,22 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import lombok.Data; + +@Data +public class FineTuningEvent { + private String id; + private String type; + private String message; + private FineTuningEventData data; + private Date createdAt; + + @Data + public static class FineTuningEventData { + private Long step; + private Long totalSteps; + private Double trainingLoss; + private Double validationLoss; + private Double fullValidationLoss; + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseList.java b/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseList.java new file mode 100644 index 00000000..be53af5b --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseList.java @@ -0,0 +1,24 @@ +package com.crowdin.client.ai.model; + +import com.crowdin.client.core.model.Pagination; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Data; + +@Data +public class FineTuningEventResponseList { + private List data; + private Pagination pagination; + + public static ResponseList to(FineTuningEventResponseList eventResponseList) { + return ResponseList.of( + eventResponseList.getData() + .stream() + .map(FineTuningEventResponseObject::getData) + .map(ResponseObject::of).collect(Collectors.toList()), + eventResponseList.getPagination() + ); + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseObject.java b/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseObject.java new file mode 100644 index 00000000..ea107975 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningEventResponseObject.java @@ -0,0 +1,8 @@ +package com.crowdin.client.ai.model; + +import lombok.Data; + +@Data +public class FineTuningEventResponseObject { + private FineTuningEvent data; +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningJob.java b/src/main/java/com/crowdin/client/ai/model/FineTuningJob.java new file mode 100644 index 00000000..c0344450 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningJob.java @@ -0,0 +1,56 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import java.util.List; +import lombok.Data; + +@Data +public class FineTuningJob { + private String identifier; + private String status; + private Long progress; + private JobAttribute attributes; + private Date createdAt; + private Date updatedAt; + private Date startedAt; + private Date finishedAt; + + @Data + public static class JobAttribute { + private Boolean dryRun; + private Long aiPromptId; + private Hyperparameters hyperparameters; + private Options trainignOptions; + private Options validationOptions; + private String baseModel; + private String fineTunedModel; + private Long trainedTokensCount; + private String trainingDatasetUrl; + private String validationDatasetUrl; + private Metadata metadata; + } + + @Data + public static class Hyperparameters { + private Long batchSize; + private Long learningRateMultiplier; + private Long nEpochs; + } + + @Data + public static class Options { + private List projectIds; + private List tmIds; + private Date dateFrom; + private Date dateTo; + private Long maxFileSize; + private Long minExamplesCount; + private Long maxExamplesCount; + } + + @Data + public static class Metadata { + private Double cost; + private String costCurrency; + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningJobRequest.java b/src/main/java/com/crowdin/client/ai/model/FineTuningJobRequest.java new file mode 100644 index 00000000..17502670 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningJobRequest.java @@ -0,0 +1,31 @@ +package com.crowdin.client.ai.model; + +import java.util.Date; +import java.util.List; +import lombok.Data; + +@Data +public class FineTuningJobRequest { + private Boolean dryRun; + private Hyperparameters hyperparameters; + private Options trainingOptions; + private Options validationOptions; + + @Data + public static class Hyperparameters { + private Long batchSize; + private Long learningRateMultiplier; + private Long nEpochs; + } + + @Data + public static class Options { + private List projectIds; + private List tmIds; + private Date dateFrom; + private Date dateTo; + private Long maxFileSize; + private Long minExamplesCount; + private Long maxExamplesCount; + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseList.java b/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseList.java new file mode 100644 index 00000000..bf80d24c --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseList.java @@ -0,0 +1,24 @@ +package com.crowdin.client.ai.model; + +import com.crowdin.client.core.model.Pagination; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Data; + +@Data +public class FineTuningJobResponseList { + private List data; + private Pagination pagination; + + public static ResponseList to(FineTuningJobResponseList responseList) { + return ResponseList.of( + responseList.data.stream() + .map(FineTuningJobResponseObject::getData) + .map(ResponseObject::of) + .collect(Collectors.toList()), + responseList.pagination + ); + } +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseObject.java b/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseObject.java new file mode 100644 index 00000000..c607835c --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningJobResponseObject.java @@ -0,0 +1,8 @@ +package com.crowdin.client.ai.model; + +import lombok.Data; + +@Data +public class FineTuningJobResponseObject { + private FineTuningJob data; +} diff --git a/src/main/java/com/crowdin/client/ai/model/FineTuningJobStatus.java b/src/main/java/com/crowdin/client/ai/model/FineTuningJobStatus.java new file mode 100644 index 00000000..77116c83 --- /dev/null +++ b/src/main/java/com/crowdin/client/ai/model/FineTuningJobStatus.java @@ -0,0 +1,4 @@ +package com.crowdin.client.ai.model; + +public class FineTuningJobStatus { +} diff --git a/src/test/java/com/crowdin/client/ai/AIApiTest.java b/src/test/java/com/crowdin/client/ai/AIApiTest.java new file mode 100644 index 00000000..8d779741 --- /dev/null +++ b/src/test/java/com/crowdin/client/ai/AIApiTest.java @@ -0,0 +1,178 @@ +package com.crowdin.client.ai; + +import com.crowdin.client.ai.model.FineTuningDatasetDownload; +import com.crowdin.client.ai.model.FineTuningDatasetRequest; +import com.crowdin.client.ai.model.FineTuningDatasetResponse.FineTuningDatasetData; +import com.crowdin.client.ai.model.FineTuningEvent; +import com.crowdin.client.ai.model.FineTuningJob; +import com.crowdin.client.ai.model.FineTuningJobRequest; +import com.crowdin.client.ai.model.FineTuningJobRequest.Hyperparameters; +import com.crowdin.client.core.model.Pagination; +import com.crowdin.client.core.model.ResponseList; +import com.crowdin.client.core.model.ResponseObject; +import com.crowdin.client.framework.RequestMock; +import com.crowdin.client.framework.TestClient; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.TimeZone; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.junit.jupiter.api.Test; + + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class AIApiTest extends TestClient { + private static final long userId = 2L; + private static final long aiPromptId = 3L; + private static final long progress = 100L; + private static final int year = 2019; + private static final int month = Calendar.SEPTEMBER; + private static final int date = 23; + private static final int hour = 11; + private static final int minutes = 26; + private static final int seconds = 54; + private static final long limit = 25L; + private static final long offset = 0L; + private static final long size = 1L; + private static final String status = "finished"; + private static final String jobIdentifier = "50fb3506-4127-4ba8-8296-f97dc7e3e0c3"; + private static final TimeZone tz = TimeZone.getTimeZone("GMT"); + private final Calendar calendar = GregorianCalendar.getInstance(tz); + + + private static final String FINE_TUNING_DATASET_GENERATION_STATUS_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/datasets/%s"; + private static final String GENERATE_FINE_TUNING_DATASET_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/datasets"; + private static final String GET_FINE_TUNING_EVENT_LIST_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/jobs/%s/events"; + private static final String GET_FINE_TUNING_JOB_LIST_PATH = "%s/users/%d/ai/prompts/fine-tuning/jobs"; + private static final String CREATE_FINE_TUNING_JOB_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/jobs"; + private static final String GET_FINE_TUNING_JOB_STATUS_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/jobs/%s"; + private static final String FINE_TUNING_DATASET_DOWNLOAD_PATH = "%s/users/%d/ai/prompts/%d/fine-tuning/datasets/%s/download"; + + private Date getDateTime(int year, int month, int date, int hour, int minute, int second) { + calendar.set(year, month, date, hour, minute, second); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTime(); + } + @Override + public List getMocks() { + return Arrays.asList( + RequestMock.build(String.format(FINE_TUNING_DATASET_GENERATION_STATUS_PATH, this.url, userId, aiPromptId, jobIdentifier), HttpGet.METHOD_NAME, "api/ai/fineTuningDatasetGenerationStatus.json"), + RequestMock.build(String.format(GENERATE_FINE_TUNING_DATASET_PATH, this.url, userId, aiPromptId), HttpPost.METHOD_NAME, "api/ai/generateFineTuningDatasetRequest.json", "api/ai/generateFineTuningDatasetResponse.json"), + RequestMock.build(String.format(GET_FINE_TUNING_EVENT_LIST_PATH, this.url, userId, aiPromptId, jobIdentifier), HttpGet.METHOD_NAME, "api/ai/fineTuningEventsResponse.json"), + RequestMock.build(String.format(GET_FINE_TUNING_JOB_LIST_PATH, this.url, userId), HttpGet.METHOD_NAME, "api/ai/fineTuningJobListResponse.json"), + RequestMock.build(String.format(CREATE_FINE_TUNING_JOB_PATH, this.url, userId, aiPromptId), HttpPost.METHOD_NAME, "api/ai/fineTuningJobRequest.json", "api/ai/fineTuningJobResponse.json"), + RequestMock.build(String.format(GET_FINE_TUNING_JOB_STATUS_PATH, this.url, userId, aiPromptId, jobIdentifier), HttpGet.METHOD_NAME, "api/ai/fineTuningJobStatusResponse.json"), + RequestMock.build(String.format(FINE_TUNING_DATASET_DOWNLOAD_PATH, this.url, userId, aiPromptId, jobIdentifier), HttpGet.METHOD_NAME, "api/ai/downloadFineTuningDataset.json") + ); + } + + + @Test + public void datasetGenerationStatusTest() { + Date dateCreated = getDateTime(year, month, date, hour, minutes, seconds); + final ResponseObject responseObject = + this.getAiApi().getFineTuningDatasetGenerationStatus(userId, aiPromptId, jobIdentifier); + + final FineTuningDatasetData data = responseObject.getData(); + assertEquals(data.getIdentifier(), jobIdentifier); + assertEquals(data.getStatus(), status); + assertEquals(data.getProgress(), progress); + assertEquals(data.getCreatedAt(), dateCreated); + assertEquals(data.getStartedAt(), dateCreated); + assertEquals(data.getUpdatedAt(), dateCreated); + } + + @Test + public void generateFineTuningDatasetTest() { + Date dateCreated = getDateTime(year, month, date, hour, minutes, seconds); + FineTuningDatasetRequest datasetRequest = new FineTuningDatasetRequest(); + datasetRequest.setTmIds(Collections.singletonList(0L)); + datasetRequest.setProjectIds(Collections.singletonList(0L)); + datasetRequest.setPurpose("training"); + datasetRequest.setMaxExamplesCount(0L); + datasetRequest.setMaxFileSize(0L); + datasetRequest.setMinExamplesCount(0L); + + final ResponseObject responseObject = + this.getAiApi().generateFineTuningDataset(userId, aiPromptId, datasetRequest); + + final FineTuningDatasetData data = responseObject.getData(); + + assertEquals(data.getStatus(), status); + assertEquals(data.getProgress(), progress); + assertEquals(data.getCreatedAt(), dateCreated); + assertEquals(data.getStartedAt(), dateCreated); + assertEquals(data.getUpdatedAt(), dateCreated); + } + + @Test + public void getFineTuningEventListTest() { + ResponseList responseList = this.getAiApi().getFineTuningEventList(userId, aiPromptId, jobIdentifier); + Pagination pagination = responseList.getPagination(); + + assertEquals(pagination.getLimit(), limit); + assertEquals(pagination.getOffset(), offset); + assertEquals(responseList.getData().size(), size); + } + + @Test + public void getFineTuningJobListTest() { + ResponseList responseList = this.getAiApi().getFineTuningJobList(userId); + Pagination pagination = responseList.getPagination(); + + assertEquals(pagination.getLimit(), limit); + assertEquals(pagination.getOffset(), offset); + assertEquals(responseList.getData().size(), size); + } + + @Test + public void createFineTuningJobTest() { + final Hyperparameters hyperparameters = new Hyperparameters(); + hyperparameters.setBatchSize(0L); + hyperparameters.setNEpochs(0L); + hyperparameters.setLearningRateMultiplier(0L); + + final FineTuningJobRequest request = new FineTuningJobRequest(); + request.setDryRun(false); + request.setHyperparameters(hyperparameters); + + final Date dateCreated = getDateTime(year, month, date, hour, minutes, seconds); + final ResponseObject responseObject = this.getAiApi().createFineTuningJob(userId, aiPromptId, request); + assertEquals(responseObject.getData().getIdentifier(), jobIdentifier); + assertEquals(responseObject.getData().getStatus(), status); + assertEquals(responseObject.getData().getProgress(), progress); + assertEquals(responseObject.getData().getFinishedAt(), dateCreated); + assertEquals(responseObject.getData().getCreatedAt(), dateCreated); + assertEquals(responseObject.getData().getStartedAt(), dateCreated); + assertEquals(responseObject.getData().getUpdatedAt(), dateCreated); + } + + @Test + public void getFineTuningJobStatusTest() { + final ResponseObject responseObject = this.getAiApi().getFineTuningJobStatus(userId, aiPromptId, jobIdentifier); + FineTuningJob job = responseObject.getData(); + + final Date dateCreated = getDateTime(year, month, date, hour, minutes, seconds); + assertEquals(job.getProgress(), progress); + assertEquals(job.getStatus(), status); + assertEquals(job.getIdentifier(), jobIdentifier); + assertEquals(job.getCreatedAt(), dateCreated); + assertEquals(job.getStartedAt(), dateCreated); + assertEquals(job.getFinishedAt(), dateCreated); + assertEquals(job.getUpdatedAt(), dateCreated); + } + + @Test + public void downloadFineTuningDatasetTest() { + ResponseObject responseObject = this.getAiApi().downloadFineTuningDatasetDownload(userId, aiPromptId, jobIdentifier); + final Date dateCreated = getDateTime(2019, Calendar.SEPTEMBER, 20, 10, 31, 21); + assertEquals(responseObject.getData().getExpireIn(), dateCreated); + assertNotNull(responseObject.getData().getUrl()); + } +} diff --git a/src/test/resources/api/ai/downloadFineTuningDataset.json b/src/test/resources/api/ai/downloadFineTuningDataset.json new file mode 100644 index 00000000..25db78a3 --- /dev/null +++ b/src/test/resources/api/ai/downloadFineTuningDataset.json @@ -0,0 +1,6 @@ +{ + "data": { + "url": "https://production-enterprise-importer.downloads.crowdin.com/992000002/2/14.xliff?response-content-disposition=attachment%3B%20filename%3D%22APP.xliff%22&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIGJKLQV66ZXPMMEA%2F20190920%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190920T093121Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=439ebd69a1b7e4c23e6d17891a491c94f832e0c82e4692dedb35a6cd1e624b62", + "expireIn": "2019-09-20T10:31:21+00:00" + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningDatasetGenerationStatus.json b/src/test/resources/api/ai/fineTuningDatasetGenerationStatus.json new file mode 100644 index 00000000..8ae958d4 --- /dev/null +++ b/src/test/resources/api/ai/fineTuningDatasetGenerationStatus.json @@ -0,0 +1,25 @@ +{ + "data": { + "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3", + "status": "finished", + "progress": 100, + "attributes": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "purpose": "training", + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "createdAt": "2019-09-23T11:26:54+00:00", + "updatedAt": "2019-09-23T11:26:54+00:00", + "startedAt": "2019-09-23T11:26:54+00:00", + "finishedAt": "2019-09-23T11:26:54+00:00" + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningEventsResponse.json b/src/test/resources/api/ai/fineTuningEventsResponse.json new file mode 100644 index 00000000..10dcd7dd --- /dev/null +++ b/src/test/resources/api/ai/fineTuningEventsResponse.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "data": { + "id": "ftevent-0HOW0hqwQ7G1b70qOC8S7UsT", + "type": "message", + "message": "Created fine-tuning job: ftjob-EhnfVT9MnddMBLfjMcme71if", + "data": { + "step": 135, + "totalSteps": 135, + "trainingLoss": 0.0031, + "validationLoss": 0.0449, + "fullValidationLoss": 0.0275 + }, + "createdAt": "2019-09-23T11:26:54+00:00" + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningJobListResponse.json b/src/test/resources/api/ai/fineTuningJobListResponse.json new file mode 100644 index 00000000..d266adae --- /dev/null +++ b/src/test/resources/api/ai/fineTuningJobListResponse.json @@ -0,0 +1,63 @@ +{ + "data": [ + { + "data": { + "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3", + "status": "finished", + "progress": 100, + "attributes": { + "dryRun": true, + "aiPromptId": 0, + "hyperparameters": { + "batchSize": 0, + "learningRateMultiplier": 0, + "nEpochs": 0 + }, + "trainingOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "validationOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "baseModel": "gpt-4o-mini-2024-07-18", + "fineTunedModel": "ft:gpt-4o-mini-2024-07-18:2024-08-12:9vQgFOfp", + "trainedTokensCount": 0, + "trainingDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/training-dataset.jsonl", + "validationDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/validation-dataset.jsonl", + "metadata": { + "cost": 0.1, + "costCurrency": "USD" + } + }, + "createdAt": "2019-09-23T11:26:54+00:00", + "updatedAt": "2019-09-23T11:26:54+00:00", + "startedAt": "2019-09-23T11:26:54+00:00", + "finishedAt": "2019-09-23T11:26:54+00:00" + } + } + ], + "pagination": { + "offset": 0, + "limit": 25 + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningJobRequest.json b/src/test/resources/api/ai/fineTuningJobRequest.json new file mode 100644 index 00000000..e646e844 --- /dev/null +++ b/src/test/resources/api/ai/fineTuningJobRequest.json @@ -0,0 +1,8 @@ +{ + "dryRun": false, + "hyperparameters": { + "batchSize": 0, + "learningRateMultiplier": 0, + "nEpochs": 0 + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningJobResponse.json b/src/test/resources/api/ai/fineTuningJobResponse.json new file mode 100644 index 00000000..b59c8dd7 --- /dev/null +++ b/src/test/resources/api/ai/fineTuningJobResponse.json @@ -0,0 +1,55 @@ +{ + "data": { + "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3", + "status": "finished", + "progress": 100, + "attributes": { + "dryRun": true, + "aiPromptId": 0, + "hyperparameters": { + "batchSize": 0, + "learningRateMultiplier": 0, + "nEpochs": 0 + }, + "trainingOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "validationOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "baseModel": "gpt-4o-mini-2024-07-18", + "fineTunedModel": "ft:gpt-4o-mini-2024-07-18:2024-08-12:9vQgFOfp", + "trainedTokensCount": 0, + "trainingDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/training-dataset.jsonl", + "validationDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/validation-dataset.jsonl", + "metadata": { + "cost": 0.1, + "costCurrency": "USD" + } + }, + "createdAt": "2019-09-23T11:26:54+00:00", + "updatedAt": "2019-09-23T11:26:54+00:00", + "startedAt": "2019-09-23T11:26:54+00:00", + "finishedAt": "2019-09-23T11:26:54+00:00" + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/fineTuningJobStatusResponse.json b/src/test/resources/api/ai/fineTuningJobStatusResponse.json new file mode 100644 index 00000000..b59c8dd7 --- /dev/null +++ b/src/test/resources/api/ai/fineTuningJobStatusResponse.json @@ -0,0 +1,55 @@ +{ + "data": { + "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3", + "status": "finished", + "progress": 100, + "attributes": { + "dryRun": true, + "aiPromptId": 0, + "hyperparameters": { + "batchSize": 0, + "learningRateMultiplier": 0, + "nEpochs": 0 + }, + "trainingOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "validationOptions": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "baseModel": "gpt-4o-mini-2024-07-18", + "fineTunedModel": "ft:gpt-4o-mini-2024-07-18:2024-08-12:9vQgFOfp", + "trainedTokensCount": 0, + "trainingDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/training-dataset.jsonl", + "validationDatasetUrl": "https://crowdin-tmp.s3.eu-central-1.amazonaws.com/72057531/ai_fine_tuning/0fc00e9e-3a80-49d1-a8cb-39c9a81c0ae2/validation-dataset.jsonl", + "metadata": { + "cost": 0.1, + "costCurrency": "USD" + } + }, + "createdAt": "2019-09-23T11:26:54+00:00", + "updatedAt": "2019-09-23T11:26:54+00:00", + "startedAt": "2019-09-23T11:26:54+00:00", + "finishedAt": "2019-09-23T11:26:54+00:00" + } +} \ No newline at end of file diff --git a/src/test/resources/api/ai/generateFineTuningDatasetRequest.json b/src/test/resources/api/ai/generateFineTuningDatasetRequest.json new file mode 100644 index 00000000..ddedc9a6 --- /dev/null +++ b/src/test/resources/api/ai/generateFineTuningDatasetRequest.json @@ -0,0 +1,12 @@ +{ + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "purpose": "training", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 +} \ No newline at end of file diff --git a/src/test/resources/api/ai/generateFineTuningDatasetResponse.json b/src/test/resources/api/ai/generateFineTuningDatasetResponse.json new file mode 100644 index 00000000..8ae958d4 --- /dev/null +++ b/src/test/resources/api/ai/generateFineTuningDatasetResponse.json @@ -0,0 +1,25 @@ +{ + "data": { + "identifier": "50fb3506-4127-4ba8-8296-f97dc7e3e0c3", + "status": "finished", + "progress": 100, + "attributes": { + "projectIds": [ + 0 + ], + "tmIds": [ + 0 + ], + "purpose": "training", + "dateFrom": "2019-09-23T11:26:54+00:00", + "dateTo": "2019-09-23T11:26:54+00:00", + "maxFileSize": 0, + "minExamplesCount": 0, + "maxExamplesCount": 0 + }, + "createdAt": "2019-09-23T11:26:54+00:00", + "updatedAt": "2019-09-23T11:26:54+00:00", + "startedAt": "2019-09-23T11:26:54+00:00", + "finishedAt": "2019-09-23T11:26:54+00:00" + } +} \ No newline at end of file