Skip to content

Commit d3eb94b

Browse files
feat: add support for supported ai provider models (#353)
1 parent 550e91f commit d3eb94b

File tree

6 files changed

+167
-1
lines changed

6 files changed

+167
-1
lines changed

src/main/java/com/crowdin/client/ai/AIApi.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,32 @@ public ResponseObject<Map<String, Object>> createProxyChatCompletion(final Long
561561
return ResponseObject.of(response.getData());
562562
}
563563

564+
/**
565+
* @param userId user identifier
566+
* @param limit maximum numbers of items to retrieve (default 25)
567+
* @param offset starting offset in the collection (default 0)
568+
* @param providerType provider (e.g. open_ai)
569+
* @param enabled filter by enabled providers
570+
* @param orderBy
571+
* @return List of supported AI models for a specific AI provider
572+
* @see <ul>
573+
* <li><a href="https://developer.crowdin.com/api/v2/#tag/AI/operation/api.ai.providers.supported-models.crowdin.getMany" target="_blank"><b>API Documentation</b></a></li>
574+
* <li><a href="https://developer.crowdin.com/enterprise/api/v2/#tag/AI/operation/api.ai.providers.supported-models.enterprise.getMany" target="_blank"><b>Enterprise API Documentation</b></a></li>
575+
* </ul>
576+
*/
577+
public ResponseList<AiSupportedModel> listSupportedAiProviderModels(Long userId, Integer limit, Integer offset, String providerType, Boolean enabled, String orderBy) throws HttpException, HttpBadRequestException {
578+
Map<String, Optional<Object>> queryParams = HttpRequestConfig.buildUrlParams(
579+
"limit", Optional.ofNullable(limit),
580+
"offset", Optional.ofNullable(offset),
581+
"providerType", Optional.ofNullable(providerType),
582+
"enabled", Optional.ofNullable(enabled),
583+
"orderBy", Optional.ofNullable(orderBy)
584+
);
585+
String url = getAIPath(userId, "ai/providers/supported-models");
586+
AiSupportedModelResponseList responseList = this.httpClient.get(url, new HttpRequestConfig(queryParams), AiSupportedModelResponseList.class);
587+
return AiSupportedModelResponseList.to(responseList);
588+
}
589+
564590
private String getAIPath(Long userId, String path) {
565591
return userId != null ? String.format("%s/users/%d/%s", this.url, userId, path) : String.format("%s/%s", this.url, path);
566592
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.crowdin.client.ai.model;
2+
3+
import lombok.Data;
4+
5+
import java.util.Date;
6+
7+
@Data
8+
public class AiSupportedModel {
9+
private Long providerId;
10+
private String providerType;
11+
private String providerName;
12+
private String id;
13+
private String displayName;
14+
private Boolean supportReasoning;
15+
private Integer intelligence;
16+
private Integer speed;
17+
private Price price;
18+
private Modality modalities;
19+
private Integer contextWindow;
20+
private Integer maxOutputTokens;
21+
private Date knowledgeCutoff;
22+
private Date releaseDate;
23+
private Feature features;
24+
25+
@Data
26+
public static class Price {
27+
private Double input;
28+
private Double output;
29+
}
30+
31+
@Data
32+
public static class Modality {
33+
private ModalityConfig input;
34+
private ModalityConfig output;
35+
36+
@Data
37+
public static class ModalityConfig {
38+
private Boolean text;
39+
private Boolean image;
40+
private Boolean audio;
41+
}
42+
}
43+
44+
@Data
45+
public static class Feature {
46+
private Boolean streaming;
47+
private Boolean structuredOutput;
48+
private Boolean functionCalling;
49+
}
50+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.crowdin.client.ai.model;
2+
3+
import com.crowdin.client.core.model.Pagination;
4+
import com.crowdin.client.core.model.ResponseList;
5+
import com.crowdin.client.core.model.ResponseObject;
6+
import lombok.Data;
7+
8+
import java.util.List;
9+
import java.util.stream.Collectors;
10+
11+
@Data
12+
public class AiSupportedModelResponseList {
13+
private List<AiSupportedModelResponseObject> data;
14+
private Pagination pagination;
15+
16+
public static ResponseList<AiSupportedModel> to(AiSupportedModelResponseList responseList) {
17+
return ResponseList.of(
18+
responseList.data.stream()
19+
.map(AiSupportedModelResponseObject::getData)
20+
.map(ResponseObject::of)
21+
.collect(Collectors.toList()),
22+
responseList.getPagination()
23+
);
24+
}
25+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.crowdin.client.ai.model;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class AiSupportedModelResponseObject {
7+
private AiSupportedModel data;
8+
}

src/test/java/com/crowdin/client/ai/AIApiTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class AIApiTest extends TestClient {
2525
private static final long userId = 2L;
2626
private static final long customPlaceholderId = 2L;
2727
private static final long aiPromptId = 3L;
28+
private static final long providerId = 0L;
2829
private static final long progress = 100L;
2930
private static final int year = 119;
3031
private static final int month = Calendar.SEPTEMBER;
@@ -64,6 +65,7 @@ public class AIApiTest extends TestClient {
6465
private static final String AI_PROMPT_COMPLETION = "%s/users/%d/ai/prompts/%d/completions/%s";
6566
private static final String AI_PROMPT_COMPLETION_DOWNLOAD = "%s/users/%d/ai/prompts/%d/completions/%s/download";
6667
private static final String PROXY_CHAT = "%s/users/%d/ai/providers/%d/chat/completions";
68+
private static final String LIST_SUPPORTED_AI_PROVIDER_MODELS = "%s/users/%d/ai/providers/supported-models";
6769

6870
@Override
6971
public List<RequestMock> getMocks() {
@@ -103,7 +105,8 @@ public List<RequestMock> getMocks() {
103105
RequestMock.build(String.format(AI_PROMPT, this.url, userId, aiPromptId), HttpGet.METHOD_NAME, "api/ai/promptResponse.json"),
104106
RequestMock.build(String.format(AI_PROMPT, this.url, userId, aiPromptId), HttpDelete.METHOD_NAME),
105107
RequestMock.build(String.format(AI_PROMPT, this.url, userId, aiPromptId), HttpPatch.METHOD_NAME, "api/ai/editPromptRequest.json", "api/ai/promptResponse.json"),
106-
RequestMock.build(String.format(PROXY_CHAT, this.url, userId, aiPromptId), HttpPost.METHOD_NAME, "api/ai/proxyChatCompletionRequest.json", "api/ai/proxyChatCompletionResponse.json")
108+
RequestMock.build(String.format(PROXY_CHAT, this.url, userId, aiPromptId), HttpPost.METHOD_NAME, "api/ai/proxyChatCompletionRequest.json", "api/ai/proxyChatCompletionResponse.json"),
109+
RequestMock.build(String.format(LIST_SUPPORTED_AI_PROVIDER_MODELS, this.url, userId), HttpGet.METHOD_NAME, "api/ai/listSupportedAiProviderModels.json")
107110
);
108111
}
109112

@@ -515,4 +518,17 @@ public void createProxyChatCompletionTest() {
515518

516519
assertEquals(proxyChatCompletion.getData().size(), 0);
517520
}
521+
522+
@Test
523+
public void listSupportedAiProviderModelsTest() {
524+
ResponseList<AiSupportedModel> response = this.getAiApi().listSupportedAiProviderModels(userId, null, null, null, null, null);
525+
526+
assertEquals(1, response.getData().size());
527+
assertEquals(providerId, response.getData().get(0).getData().getProviderId());
528+
assertTrue(response.getData().get(0).getData().getFeatures().getStreaming());
529+
assertEquals(new Date(year, Calendar.AUGUST, 24, 14, 15, 22), response.getData().get(0).getData().getKnowledgeCutoff());
530+
assertTrue(response.getData().get(0).getData().getModalities().getInput().getText());
531+
assertTrue(response.getData().get(0).getData().getModalities().getOutput().getImage());
532+
assertEquals(0.1, response.getData().get(0).getData().getPrice().getInput());
533+
}
518534
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"data": [
3+
{
4+
"data": {
5+
"providerId": 0,
6+
"providerType": "string",
7+
"providerName": "string",
8+
"id": "string",
9+
"displayName": "string",
10+
"supportReasoning": true,
11+
"intelligence": 0,
12+
"speed": 0,
13+
"price": {
14+
"input": 0.1,
15+
"output": 0.1
16+
},
17+
"modalities": {
18+
"input": {
19+
"text": true,
20+
"image": true,
21+
"audio": true
22+
},
23+
"output": {
24+
"text": true,
25+
"image": true,
26+
"audio": true
27+
}
28+
},
29+
"contextWindow": 0,
30+
"maxOutputTokens": 0,
31+
"knowledgeCutoff": "2019-08-24T14:15:22Z",
32+
"releaseDate": "2019-08-24T14:15:22Z",
33+
"features": {
34+
"streaming": true,
35+
"structuredOutput": true,
36+
"functionCalling": true
37+
}
38+
}
39+
}
40+
]
41+
}

0 commit comments

Comments
 (0)