Skip to content

Commit 0da7aba

Browse files
authored
Merge pull request #56 from yml-org/feature/CM-1274/list-models
[CM-1275] Implements List Models Entrypoint
2 parents 221a1bf + 29a4a89 commit 0da7aba

File tree

30 files changed

+618
-19
lines changed

30 files changed

+618
-19
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ try {
8585

8686
### Features
8787

88+
- [ListModels](guides/Features.md#listmodels)
8889
- [Completions](guides/Features.md#completion)
8990
- [ChatCompletions](guides/Features.md#chatcompletions)
9091
- [ImageGenerations](guides/Features.md#imagegenerations)

guides/Features.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,44 @@
11
# Features
22

3+
- [ListModels](#listModels)
34
- [Completion](#completion)
45
- [ChatCompletions](#chatcompletions)
56
- [ImageGenerations](#imagegenerations)
67
- [Edits](#edits)
78

9+
## ListModels
10+
11+
The listModels api lists the currently available models, and provides basic information about each one such as the owner and availability.
12+
13+
### Swift
14+
15+
```swift
16+
var yChat: YChat {
17+
YChatCompanion.shared.create(apiKey: "your-api-key")
18+
}
19+
20+
do {
21+
let result = try await yChat.listModels().execute()
22+
} catch {
23+
// catch any error that may occurs on api call.
24+
}
25+
```
26+
27+
### Kotlin
28+
29+
```kotlin
30+
val yChat by lazy {
31+
YChat.create("your-api-key")
32+
}
33+
34+
try {
35+
val result = yChat.listModels().execute()
36+
37+
} catch (e: exception) {
38+
// catch any error that may occurs on api call.
39+
}
40+
```
41+
842
## Completion
943

1044
The completions api can be used for a wide variety of tasks. You input some text as a prompt, and the model will generate a text completion that attempts to match whatever context or pattern you gave it. For example, if you give the API the prompt, "As Descartes said, I think, therefore", it will return the completion " I am" with high probability.

sample/android/src/main/java/co/yml/ychat/android/di/AppModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import co.yml.ychat.YChat
44
import co.yml.ychat.android.BuildConfig
55
import co.yml.ychat.android.presentation.chatcompletions.viewmodel.ChatCompletionsViewModel
66
import co.yml.ychat.android.presentation.home.viewmodel.HomeViewModel
7+
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel
78
import org.koin.androidx.viewmodel.dsl.viewModelOf
89
import org.koin.dsl.module
910

1011
val appModule = module {
1112
single { YChat.create(BuildConfig.API_KEY) }
1213
viewModelOf(::HomeViewModel)
1314
viewModelOf(::ChatCompletionsViewModel)
15+
viewModelOf(::ModelsViewModel)
1416
}
Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,78 @@
11
package co.yml.ychat.android.presentation.models
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.layout.Arrangement
5-
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Spacer
66
import androidx.compose.foundation.layout.fillMaxHeight
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.foundation.lazy.LazyColumn
10+
import androidx.compose.foundation.lazy.items
11+
import androidx.compose.material.CircularProgressIndicator
712
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.collectAsState
14+
import androidx.compose.ui.Alignment
815
import androidx.compose.ui.Modifier
916
import androidx.compose.ui.tooling.preview.Preview
17+
import co.yml.ychat.YChat
18+
import co.yml.ychat.android.BuildConfig
19+
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel
20+
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel.State
1021
import co.yml.ychat.android.ui.components.feedback.Feedback
1122
import co.yml.ychat.android.ui.components.feedback.model.FeedbackState
23+
import co.yml.ychat.android.ui.components.itemmenu.ItemMenu
24+
import co.yml.ychat.android.ui.theme.Dimens
1225
import co.yml.ychat.android.ui.theme.YChatTheme
26+
import co.yml.ychat.domain.model.AIModel
27+
import org.koin.androidx.compose.getViewModel
1328

1429
@Composable
15-
internal fun ModelsScreen() {
16-
Column(
30+
internal fun ModelsScreen(viewModel: ModelsViewModel = getViewModel()) {
31+
val state = viewModel.state.collectAsState().value
32+
Box(
1733
modifier = Modifier
1834
.background(YChatTheme.colors.background)
19-
.fillMaxHeight(),
20-
verticalArrangement = Arrangement.Center,
35+
.fillMaxHeight()
36+
.fillMaxWidth()
2137
) {
22-
Feedback(feedbackState = FeedbackState.CONSTRUCTION)
38+
when (state) {
39+
is State.Loading ->
40+
CircularProgressIndicator(
41+
modifier = Modifier.align(Alignment.Center)
42+
)
43+
is State.Error ->
44+
Feedback(
45+
modifier = Modifier.align(Alignment.Center),
46+
feedbackState = FeedbackState.ERROR,
47+
onButtonClick = { viewModel.fetchModels() }
48+
)
49+
is State.Success ->
50+
ModelListContent(state.models)
51+
}
52+
}
53+
}
54+
55+
@Composable
56+
private fun ModelListContent(models: List<AIModel>) {
57+
LazyColumn {
58+
item { Spacer(modifier = Modifier.padding(top = Dimens.MD)) }
59+
items(models) {
60+
val enableDivider = models.last() != it
61+
ItemMenu(
62+
startText = it.id,
63+
caption = it.ownedBy,
64+
isDividerVisible = enableDivider,
65+
)
66+
}
2367
}
2468
}
2569

2670
@Preview
2771
@Composable
2872
private fun ModelsScreenPreview() {
2973
YChatTheme {
30-
ModelsScreen()
74+
val yChat = YChat.create(BuildConfig.API_KEY)
75+
val viewModel = ModelsViewModel(yChat)
76+
ModelsScreen(viewModel)
3177
}
3278
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package co.yml.ychat.android.presentation.models.viewmodel
2+
3+
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.viewModelScope
5+
import co.yml.ychat.YChat
6+
import co.yml.ychat.domain.model.AIModel
7+
import kotlinx.coroutines.flow.MutableStateFlow
8+
import kotlinx.coroutines.flow.StateFlow
9+
import kotlinx.coroutines.flow.asStateFlow
10+
import kotlinx.coroutines.launch
11+
12+
internal class ModelsViewModel(private val yChat: YChat) : ViewModel() {
13+
14+
private val yChatListModels by lazy { yChat.listModels() }
15+
16+
private val _state = MutableStateFlow<State>(State.Loading)
17+
val state: StateFlow<State> = _state.asStateFlow()
18+
19+
init {
20+
fetchModels()
21+
}
22+
23+
fun fetchModels() = viewModelScope.launch {
24+
_state.value = State.Loading
25+
runCatching { yChatListModels.execute() }
26+
.onSuccess { _state.value = State.Success(it) }
27+
.onFailure { _state.value = State.Error }
28+
}
29+
30+
sealed class State {
31+
object Loading : State()
32+
data class Success(val models: List<AIModel>) : State()
33+
object Error : State()
34+
}
35+
}

sample/android/src/main/java/co/yml/ychat/android/ui/components/feedback/Feedback.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ private const val ICON_SIZE = 128
2424
@Composable
2525
fun Feedback(
2626
feedbackState: FeedbackState,
27+
modifier: Modifier = Modifier,
2728
onButtonClick: (() -> Unit)? = null,
2829
) {
2930
Feedback(
31+
modifier = modifier,
3032
icons = feedbackState.icon,
3133
title = stringResource(id = feedbackState.title),
3234
message = stringResource(id = feedbackState.message),
@@ -37,6 +39,7 @@ fun Feedback(
3739

3840
@Composable
3941
fun Feedback(
42+
modifier: Modifier,
4043
icons: Icons,
4144
title: String,
4245
message: String,
@@ -45,7 +48,7 @@ fun Feedback(
4548
) {
4649
Column(
4750
horizontalAlignment = Alignment.CenterHorizontally,
48-
modifier = Modifier.padding(horizontal = Dimens.XXXL)
51+
modifier = modifier.padding(horizontal = Dimens.XXXL)
4952
) {
5053
icons.Icon(
5154
modifier = Modifier
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package co.yml.ychat.android.ui.components.itemmenu
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxHeight
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.tooling.preview.Preview
12+
import androidx.compose.ui.unit.dp
13+
import co.yml.ychat.android.ui.components.divider.HorizontalDivider
14+
import co.yml.ychat.android.ui.theme.Dimens
15+
import co.yml.ychat.android.ui.theme.TypographyStyle
16+
import co.yml.ychat.android.ui.theme.YChatTheme
17+
18+
@Composable
19+
fun ItemMenu(
20+
startText: String,
21+
caption: String,
22+
isDividerVisible: Boolean = true,
23+
) {
24+
Column {
25+
Column(
26+
modifier = Modifier
27+
.fillMaxWidth()
28+
.padding(horizontal = Dimens.MD, vertical = 14.dp),
29+
verticalArrangement = Arrangement.spacedBy(Dimens.XXS)
30+
) {
31+
TypographyStyle.MediumBody.Text(text = startText)
32+
TypographyStyle.SmallBody.Text(text = caption, color = YChatTheme.colors.text2)
33+
}
34+
if (isDividerVisible) {
35+
HorizontalDivider(modifier = Modifier.padding(horizontal = Dimens.MD))
36+
}
37+
}
38+
}
39+
40+
@Preview
41+
@Composable
42+
private fun ItemMenuPreview() {
43+
YChatTheme {
44+
Column(
45+
modifier = Modifier
46+
.background(YChatTheme.colors.background)
47+
.fillMaxHeight()
48+
) {
49+
ItemMenu(startText = "Label one line", caption = "Caption one line")
50+
}
51+
}
52+
}

sample/jvm/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ This endpoint generates images based on the provided prompt.
5656

5757
##### Example:
5858

59-
`GET http://localhost:8080/api/ychat/generations?prompt="ocean"
59+
`GET http://localhost:8080/api/ychat/generations?prompt="ocean"`
6060

6161
### Edits Endpoint
6262

@@ -71,4 +71,14 @@ This endpoint edits the prompt based on the provided instruction.
7171

7272
##### Example:
7373

74-
`GET http://localhost:8080/api/ychat/edits?input=What day of the wek is it?&instruction=Fix the spelling mistakes
74+
`GET http://localhost:8080/api/ychat/edits?input=What day of the wek is it?&instruction=Fix the spelling mistakes`
75+
76+
### List Models Endpoint
77+
78+
This endpoint retrieve a list of currently available artificial intelligence models.
79+
80+
##### Endpoint: http://localhost:[port_number]/api/ychat/models
81+
82+
##### Example:
83+
84+
`GET http://localhost:8080/api/ychat/models`

sample/jvm/src/main/java/co/yml/ychat/jvm/controller/YChatController.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package co.yml.ychat.jvm.controller;
22

3+
import co.yml.ychat.domain.model.AIModel;
4+
import co.yml.ychat.jvm.services.YChatService;
5+
import java.util.List;
36
import org.springframework.beans.factory.annotation.Autowired;
47
import org.springframework.http.ResponseEntity;
58
import org.springframework.web.bind.annotation.GetMapping;
69
import org.springframework.web.bind.annotation.RequestMapping;
710
import org.springframework.web.bind.annotation.RequestParam;
811
import org.springframework.web.bind.annotation.RestController;
9-
import co.yml.ychat.jvm.services.YChatService;
1012

1113
@RestController
1214
@RequestMapping("api/ychat")
@@ -49,6 +51,12 @@ public ResponseEntity<String> edits(
4951
return ResponseEntity.ok(result);
5052
}
5153

54+
@GetMapping("models")
55+
public ResponseEntity<List<AIModel>> models() throws Exception {
56+
List<AIModel> result = YChatService.getModels();
57+
return ResponseEntity.ok(result);
58+
}
59+
5260
private static class Defaults {
5361
static final String COMPLETION_INPUT = "Say this is a test.";
5462
static final String CHAT_COMPLETION_INPUT = "Tell me one strength exercise";

sample/jvm/src/main/java/co/yml/ychat/jvm/services/YChatService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package co.yml.ychat.jvm.services;
22

3+
import co.yml.ychat.domain.model.AIModel;
34
import co.yml.ychat.domain.model.ChatMessage;
45
import java.util.List;
56
import org.jetbrains.annotations.NotNull;
@@ -50,6 +51,13 @@ public String getEditsAnswer(String input, String instruction) throws Exception
5051
return future.get().get(0);
5152
}
5253

54+
public List<AIModel> getModels() throws Exception {
55+
final CompletableFuture<List<AIModel>> future = new CompletableFuture<>();
56+
ychat.listModels()
57+
.execute(new CompletionCallbackResult<>(future));
58+
return future.get();
59+
}
60+
5361
private static class CompletionCallbackResult<T> implements YChat.Callback<T> {
5462

5563
private final CompletableFuture<T> future;

0 commit comments

Comments
 (0)