diff --git a/src/ai/index.ts b/src/ai/index.ts index 163ebdcaf..5cd566635 100644 --- a/src/ai/index.ts +++ b/src/ai/index.ts @@ -466,6 +466,60 @@ export class Ai extends CrowdinApi { return this.post(url, request, this.defaultConfig()); } + /** + * @param request request body + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.file-translations.post + */ + startAiOrganizationFileTranslation( + request: AiModel.AiFileTranslationRequest, + ): Promise>> { + const url = `${this.url}/ai/file-translations`; + + return this.post(url, request, this.defaultConfig()); + } + + /** + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.file-translations.get + */ + getAiOrganizationFileTranslationStatus( + jobIdentifier: string, + ): Promise>> { + const url = `${this.url}/ai/file-translations/${jobIdentifier}`; + + return this.get(url, this.defaultConfig()); + } + + /** + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.file-translations.delete + */ + cancelAiOrganizationFileTranslation(jobIdentifier: string): Promise { + const url = `${this.url}/ai/file-translations/${jobIdentifier}`; + + return this.delete(url, this.defaultConfig()); + } + + /** + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.file-translations.download + */ + downloadAiOrganizationFileTranslation(jobIdentifier: string): Promise> { + const url = `${this.url}/ai/file-translations/${jobIdentifier}/download`; + + return this.get(url, this.defaultConfig()); + } + + /** + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.file-translations.download-strings + */ + downloadAiOrganizationFileTranslationStrings(jobIdentifier: string): Promise> { + const url = `${this.url}/ai/file-translations/${jobIdentifier}/translations`; + + return this.get(url, this.defaultConfig()); + } + // Community /** @@ -997,6 +1051,67 @@ export class Ai extends CrowdinApi { return this.post(url, request, this.defaultConfig()); } + + /** + * @param userId user identifier + * @param request request body + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.file-translations.post + */ + startAiUserFileTranslation( + userId: number, + request: AiModel.AiFileTranslationRequest, + ): Promise>> { + const url = `${this.url}/users/${userId}/ai/file-translations`; + + return this.post(url, request, this.defaultConfig()); + } + + /** + * @param userId user identifier + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.file-translations.get + */ + getAiUserFileTranslationStatus( + userId: number, + jobIdentifier: string, + ): Promise>> { + const url = `${this.url}/users/${userId}/ai/file-translations/${jobIdentifier}`; + + return this.get(url, this.defaultConfig()); + } + + /** + * @param userId user identifier + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.file-translations.delete + */ + cancelAiUserFileTranslation(userId: number, jobIdentifier: string): Promise { + const url = `${this.url}/users/${userId}/ai/file-translations/${jobIdentifier}`; + + return this.delete(url, this.defaultConfig()); + } + + /** + * @param userId user identifier + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.file-translations.download + */ + downloadAiUserFileTranslation(userId: number, jobIdentifier: string): Promise> { + const url = `${this.url}/users/${userId}/ai/file-translations/${jobIdentifier}/download`; + + return this.get(url, this.defaultConfig()); + } + + /** + * @param userId user identifier + * @param jobIdentifier job identifier + * @see https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.file-translations.download-strings + */ + downloadAiUserFileTranslationStrings(userId: number, jobIdentifier: string): Promise> { + const url = `${this.url}/users/${userId}/ai/file-translations/${jobIdentifier}/translations`; + + return this.get(url, this.defaultConfig()); + } } export namespace AiModel { @@ -1432,6 +1547,37 @@ export namespace AiModel { } /* ai Settings Section END*/ + /* ai File Translation Section START*/ + export interface AiFileTranslationRequest { + storageId: number; + targetLanguageId: string; + sourceLanguageId?: string; + type?: string; + parserVersion?: number; + tmIds?: number[]; + glossaryIds?: number[]; + aiPromptId?: number; + aiProviderId?: number; + aiModelId?: string; + instructions?: string[]; + attachmentIds?: number[]; + } + + export interface AiFileTranslationAttribute { + stage: string; + error: { + stage: string; + message: string; + } | null; + downloadName: string | null; + sourceLanguageId: string | null; + targetLanguageId: string; + originalFileName: string; + detectedType: string | null; + parserVersion: number | null; + } + /* ai File Translation Section END*/ + /* ai Translate Strings Section START*/ export interface AiTranslateStringsRequest { strings: string[]; diff --git a/tests/ai/api.test.ts b/tests/ai/api.test.ts index 9dec20b28..b49fcb39f 100644 --- a/tests/ai/api.test.ts +++ b/tests/ai/api.test.ts @@ -573,6 +573,59 @@ describe('AI API', () => { translations: ['Перекладений текст'], }, }) + .post( + '/ai/file-translations', + { + storageId: 1, + targetLanguageId: 'uk', + }, + { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }, + ) + .reply(200, { + data: { + identifier: jobId, + }, + }) + .get(`/ai/file-translations/${jobId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + identifier: jobId, + }, + }) + .delete(`/ai/file-translations/${jobId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200) + .get(`/ai/file-translations/${jobId}/download`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + url: link, + }, + }) + .get(`/ai/file-translations/${jobId}/translations`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + url: link, + }, + }) .get(`/users/${userId}/ai/settings/custom-placeholders`, undefined, { reqheaders: { Authorization: `Bearer ${api.token}`, @@ -1079,6 +1132,59 @@ describe('AI API', () => { targetLanguageId: 'uk', translations: ['Перекладений текст'], }, + }) + .post( + `/users/${userId}/ai/file-translations`, + { + storageId: 1, + targetLanguageId: 'uk', + }, + { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }, + ) + .reply(200, { + data: { + identifier: jobId, + }, + }) + .get(`/users/${userId}/ai/file-translations/${jobId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + identifier: jobId, + }, + }) + .delete(`/users/${userId}/ai/file-translations/${jobId}`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200) + .get(`/users/${userId}/ai/file-translations/${jobId}/download`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + url: link, + }, + }) + .get(`/users/${userId}/ai/file-translations/${jobId}/translations`, undefined, { + reqheaders: { + Authorization: `Bearer ${api.token}`, + }, + }) + .reply(200, { + data: { + url: link, + }, }); }); @@ -1328,6 +1434,33 @@ describe('AI API', () => { expect(res.data.translations).toStrictEqual(['Перекладений текст']); }); + it('Start AI Organization File Translation', async () => { + const res = await api.startAiOrganizationFileTranslation({ + storageId: 1, + targetLanguageId: 'uk', + }); + expect(res.data.identifier).toBe(jobId); + }); + + it('Get AI Organization File Translation Status', async () => { + const res = await api.getAiOrganizationFileTranslationStatus(jobId); + expect(res.data.identifier).toBe(jobId); + }); + + it('Cancel AI Organization File Translation', async () => { + await api.cancelAiOrganizationFileTranslation(jobId); + }); + + it('Download AI Organization File Translation', async () => { + const res = await api.downloadAiOrganizationFileTranslation(jobId); + expect(res.data.url).toBe(link); + }); + + it('Download AI Organization File Translation Strings', async () => { + const res = await api.downloadAiOrganizationFileTranslationStrings(jobId); + expect(res.data.url).toBe(link); + }); + it('List AI User Custom Placeholders', async () => { const placeholders = await api.listAiUserCustomPlaceholders(userId); expect(placeholders.data.length).toBe(1); @@ -1569,4 +1702,31 @@ describe('AI API', () => { expect(res.data.targetLanguageId).toBe('uk'); expect(res.data.translations).toStrictEqual(['Перекладений текст']); }); + + it('Start AI User File Translation', async () => { + const res = await api.startAiUserFileTranslation(userId, { + storageId: 1, + targetLanguageId: 'uk', + }); + expect(res.data.identifier).toBe(jobId); + }); + + it('Get AI User File Translation Status', async () => { + const res = await api.getAiUserFileTranslationStatus(userId, jobId); + expect(res.data.identifier).toBe(jobId); + }); + + it('Cancel AI User File Translation', async () => { + await api.cancelAiUserFileTranslation(userId, jobId); + }); + + it('Download AI User File Translation', async () => { + const res = await api.downloadAiUserFileTranslation(userId, jobId); + expect(res.data.url).toBe(link); + }); + + it('Download AI User File Translation Strings', async () => { + const res = await api.downloadAiUserFileTranslationStrings(userId, jobId); + expect(res.data.url).toBe(link); + }); });