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