Skip to content

Commit

Permalink
feat: ai api updates
Browse files Browse the repository at this point in the history
  • Loading branch information
yevheniyJ committed Jul 7, 2024
1 parent 07984eb commit 0b9a080
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 16 deletions.
127 changes: 111 additions & 16 deletions src/ai/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { CrowdinApi, PaginationOptions, PatchRequest, ResponseList, ResponseObject } from '../core';

export class Ai extends CrowdinApi {
/**
* @param aiPromptId ai prompt identifier
* @param request request body
* @see https://developer.crowdin.com/enterprise/api/v2/#operation/api.ai.prompts.clones.post
*/
cloneAiOrganizationPrompt(
aiPromptId: number,
request: { name?: string } = {},
): Promise<ResponseObject<AiModel.AiPromptResponse>> {
const url = `${this.url}/ai/prompts/${aiPromptId}/clones`;

return this.post(url, request, this.defaultConfig());
}

/**
* @param options optional parameters for the request
* @see https://developer.crowdin.com/enterprise/api/v2/#operation/api.ai.prompts.getMany
Expand Down Expand Up @@ -143,6 +157,42 @@ export class Ai extends CrowdinApi {
return this.post(url, request, this.defaultConfig());
}

/**
* @see https://developer.crowdin.com/enterprise/api/v2/#operation/api.ai.settings.get
*/
getAiOrganizationSettings(): Promise<ResponseObject<AiModel.AiSettings>> {
const url = `${this.url}/ai/settings`;
return this.get(url);
}

/**
* @param request request body
* @see https://developer.crowdin.com/enterprise/api/v2/#operation/api.ai.settings.patch
*/
editAiOrganizationSettings(request: PatchRequest[]): Promise<ResponseObject<AiModel.AiSettings>> {
const url = `${this.url}/ai/settings`;

return this.patch(url, request, this.defaultConfig());
}

// Community

/**
* @param userId user identifier
* @param aiPromptId ai prompt identifier
* @param request request body
* @see https://developer.crowdin.com/api/v2/#operation/api.users.ai.prompts.clones.post
*/
cloneAiUserPrompt(
userId: number,
aiPromptId: number,
request: { name?: string } = {},
): Promise<ResponseObject<AiModel.AiPromptResponse>> {
const url = `${this.url}/users/${userId}/ai/prompts/${aiPromptId}/clones`;

return this.post(url, request, this.defaultConfig());
}

/**
* @param userId user identifier
* @param options optional parameters for the request
Expand Down Expand Up @@ -311,6 +361,26 @@ export class Ai extends CrowdinApi {

return this.post(url, request, this.defaultConfig());
}

/**
* @param userId user Identifier
* @see https://developer.crowdin.com/api/v2/#operation/api.users.ai.settings.get
*/
getAiUsertSettings(userId: number): Promise<ResponseObject<AiModel.AiSettings>> {
const url = `${this.url}/users/${userId}/ai/settings`;
return this.get(url);
}

/**
* @param userId user Identifier
* @param request request body
* @see https://developer.crowdin.com/api/v2/#operation/api.users.ai.settings.patch
*/
editAiUserSettings(userId: number, request: PatchRequest[]): Promise<ResponseObject<AiModel.AiSettings>> {
const url = `${this.url}/users/${userId}/ai/settings`;

return this.patch(url, request, this.defaultConfig());
}
}

export namespace AiModel {
Expand All @@ -325,10 +395,11 @@ export namespace AiModel {
name: string;
action: string;
aiProviderId: number;
AiModelId: string;
aiModelId: string;
isEnabled: boolean;
enabledProjectIds: number[];
config: AiModel.AiPromptConfigBasic | AiModel.AiPromptConfigAdvanced;
config: AiModel.AiPromptConfigBasic | AiModel.AiPromptConfigAdvanced | AiModel.AiPromptConfigExternal;
promptPreview: string;
createdAt: string;
updatedAt: string;
}
Expand All @@ -347,23 +418,33 @@ export namespace AiModel {
glossaryTerms?: boolean;
tmSuggestions?: boolean;
fileContent?: boolean;
fileContext?: boolean;
screenshots?: boolean;
publicProjectDescription?: boolean;
siblingsStrings?: boolean;
filteredStrings?: boolean;
}

export interface AiPromptConfigAdvanced {
mode: 'advanced';
prompt: string;
screenshots?: boolean;
}

export interface AiPromptConfigExternal {
mode: 'external';
external: string;
key: string;
options?: any;

Check warning on line 437 in src/ai/index.ts

View workflow job for this annotation

GitHub Actions / code-coverage

Unexpected any. Specify a different type

Check warning on line 437 in src/ai/index.ts

View workflow job for this annotation

GitHub Actions / code-coverage

Unexpected any. Specify a different type
}

export interface AddAiPromptRequest {
name: string;
action: string;
aiProviderId: number;
aiModelId: string;
aiProviderId?: number;
aiModelId?: string;
isEnabled?: boolean;
enabledProjectIds?: number[];
config: AiModel.AiPromptConfigBasic | AiModel.AiPromptConfigAdvanced;
config: AiModel.AiPromptConfigBasic | AiModel.AiPromptConfigAdvanced | AiPromptConfigExternal;
}
/* ai Prompts Section END*/

Expand All @@ -373,22 +454,24 @@ export namespace AiModel {
name: string;
type: string;
credentials:
| AiModel.AiProviderCredentialsOpenAi
| AiModel.AiProviderCredentialsBasic
| AiModel.AiProviderCredentialsAzureOpenAi
| AiProviderCredentialsGoogleGemini;
| AiProviderCredentialsGoogleGemini
| AiProviderCredentialsCustom;
config: AiModel.AiProviderConfig;
isEnabled: boolean;
useSystemCredentials: boolean;
createdAt: string;
updatedAt: string;
promptsCount: string;
}

export interface AiProviderCredentialsOpenAi {
export interface AiProviderCredentialsBasic {
apiKey: string;
}

export interface AiProviderCredentialsAzureOpenAi {
export interface AiProviderCredentialsAzureOpenAi extends AiProviderCredentialsBasic {
resourceName: string;
apiKey: string;
deploymentName: string;
apiVersion: string;
}
Expand All @@ -399,24 +482,31 @@ export namespace AiModel {
serviceAccountKey: string;
}

export interface AiProviderCredentialsCustom {
identifier: string;
key: string;
}

export interface AiProviderConfig {
actionRules?: AiModel.AiProviderConfigActionRule[];
}

export interface AiProviderConfigActionRule {
action?: string;
action?: 'pre_translate' | 'assist';
availableAiModelIds?: string[];
}

export interface AddAiProviderRequest {
name: string;
type: string;
credentials:
| AiModel.AiProviderCredentialsOpenAi
credentials?:
| AiModel.AiProviderCredentialsBasic
| AiModel.AiProviderCredentialsAzureOpenAi
| AiProviderCredentialsGoogleGemini;
| AiProviderCredentialsGoogleGemini
| AiProviderCredentialsCustom;
config?: AiModel.AiProviderConfig;
isEnabled?: boolean;
useSystemCredentials?: boolean;
}
/* ai Providers Section END*/

Expand All @@ -432,8 +522,13 @@ export namespace AiModel {
}
/* ai Provider Models Section END*/

export interface AiSettings {
assistActionAiPromptId: number;
}

export interface OtherChatCompletionRequest {
[key: string]: object | string;
stream?: boolean;
[key: string]: any;

Check warning on line 531 in src/ai/index.ts

View workflow job for this annotation

GitHub Actions / code-coverage

Unexpected any. Specify a different type

Check warning on line 531 in src/ai/index.ts

View workflow job for this annotation

GitHub Actions / code-coverage

Unexpected any. Specify a different type
}

export interface GoogleGeminiChatCompletionRequest extends OtherChatCompletionRequest {
Expand Down
132 changes: 132 additions & 0 deletions tests/ai/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,26 @@ describe('AI API', () => {
apiKey,
};
const field = { send: 'to AI' };
const assistActionAiPromptId = 2;

const limit = 25;

beforeAll(() => {
scope = nock(api.url)
.post(
`/ai/prompts/${aiPromptId}/clones`,
{},
{
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
},
)
.reply(200, {
data: {
id: aiPromptId,
},
})
.get('/ai/prompts', undefined, {
reqheaders: {
Authorization: `Bearer ${api.token}`,
Expand Down Expand Up @@ -205,6 +220,50 @@ describe('AI API', () => {
.reply(200, {
data: field,
})
.get('/ai/settings', undefined, {
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
})
.reply(200, {
data: {
assistActionAiPromptId,
},
})
.patch(
'/ai/settings',
[
{
value: name,
op: 'replace',
path: '/name',
},
],
{
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
},
)
.reply(200, {
data: {
assistActionAiPromptId,
},
})
.post(
`/users/${userId}/ai/prompts/${aiPromptId}/clones`,
{},
{
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
},
)
.reply(200, {
data: {
id: aiPromptId,
},
})
.get(`/users/${userId}/ai/prompts`, undefined, {
reqheaders: {
Authorization: `Bearer ${api.token}`,
Expand Down Expand Up @@ -376,12 +435,48 @@ describe('AI API', () => {
})
.reply(200, {
data: field,
})
.get(`/users/${userId}/ai/settings`, undefined, {
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
})
.reply(200, {
data: {
assistActionAiPromptId,
},
})
.patch(
`/users/${userId}/ai/settings`,
[
{
value: name,
op: 'replace',
path: '/name',
},
],
{
reqheaders: {
Authorization: `Bearer ${api.token}`,
},
},
)
.reply(200, {
data: {
assistActionAiPromptId,
},
});
});

afterAll(() => {
scope.done();
});

it('Clone AI Organization Prompt', async () => {
const prompt = await api.cloneAiOrganizationPrompt(aiPromptId);
expect(prompt.data.id).toBe(aiPromptId);
});

it('List AI Organization Prompts', async () => {
const prompts = await api.listAiOrganizationPrompts();
expect(prompts.data.length).toBe(1);
Expand Down Expand Up @@ -468,6 +563,27 @@ describe('AI API', () => {
expect(proxy.data).toStrictEqual(field);
});

it('Get AI Organization Settings', async () => {
const settings = await api.getAiOrganizationSettings();
expect(settings.data.assistActionAiPromptId).toBe(assistActionAiPromptId);
});

it('Edit AI Organization Settings', async () => {
const settings = await api.editAiOrganizationSettings([
{
op: 'replace',
path: '/name',
value: name,
},
]);
expect(settings.data.assistActionAiPromptId).toBe(assistActionAiPromptId);
});

it('Clone AI User Prompt', async () => {
const prompt = await api.cloneAiUserPrompt(userId, aiPromptId);
expect(prompt.data.id).toBe(aiPromptId);
});

it('List AI User Prompts', async () => {
const prompts = await api.listAiUserPrompts(userId);
expect(prompts.data.length).toBe(1);
Expand Down Expand Up @@ -553,4 +669,20 @@ describe('AI API', () => {
const proxy = await api.createAiUserProxyChatCompletion(userId, aiProviderId, field);
expect(proxy.data).toStrictEqual(field);
});

it('Get AI User Settings', async () => {
const settings = await api.getAiUsertSettings(userId);
expect(settings.data.assistActionAiPromptId).toBe(assistActionAiPromptId);
});

it('Edit AI User Settings', async () => {
const settings = await api.editAiUserSettings(userId, [
{
op: 'replace',
path: '/name',
value: name,
},
]);
expect(settings.data.assistActionAiPromptId).toBe(assistActionAiPromptId);
});
});

0 comments on commit 0b9a080

Please sign in to comment.