Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ try {

### Features

- [ListModels](guides/Features.md#listmodels)
- [Completions](guides/Features.md#completion)
- [ChatCompletions](guides/Features.md#chatcompletions)
- [ImageGenerations](guides/Features.md#imagegenerations)
Expand Down
34 changes: 34 additions & 0 deletions guides/Features.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
# Features

- [ListModels](#listModels)
- [Completion](#completion)
- [ChatCompletions](#chatcompletions)
- [ImageGenerations](#imagegenerations)
- [Edits](#edits)

## ListModels

The listModels api lists the currently available models, and provides basic information about each one such as the owner and availability.

### Swift

```swift
var yChat: YChat {
YChatCompanion.shared.create(apiKey: "your-api-key")
}

do {
let result = try await yChat.listModels().execute()
} catch {
// catch any error that may occurs on api call.
}
```

### Kotlin

```kotlin
val yChat by lazy {
YChat.create("your-api-key")
}

try {
val result = yChat.listModels().execute()

} catch (e: exception) {
// catch any error that may occurs on api call.
}
```

## Completion

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import co.yml.ychat.YChat
import co.yml.ychat.android.BuildConfig
import co.yml.ychat.android.presentation.chatcompletions.viewmodel.ChatCompletionsViewModel
import co.yml.ychat.android.presentation.home.viewmodel.HomeViewModel
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.dsl.module

val appModule = module {
single { YChat.create(BuildConfig.API_KEY) }
viewModelOf(::HomeViewModel)
viewModelOf(::ChatCompletionsViewModel)
viewModelOf(::ModelsViewModel)
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,78 @@
package co.yml.ychat.android.presentation.models

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import co.yml.ychat.YChat
import co.yml.ychat.android.BuildConfig
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel
import co.yml.ychat.android.presentation.models.viewmodel.ModelsViewModel.State
import co.yml.ychat.android.ui.components.feedback.Feedback
import co.yml.ychat.android.ui.components.feedback.model.FeedbackState
import co.yml.ychat.android.ui.components.itemmenu.ItemMenu
import co.yml.ychat.android.ui.theme.Dimens
import co.yml.ychat.android.ui.theme.YChatTheme
import co.yml.ychat.domain.model.AIModel
import org.koin.androidx.compose.getViewModel

@Composable
internal fun ModelsScreen() {
Column(
internal fun ModelsScreen(viewModel: ModelsViewModel = getViewModel()) {
val state = viewModel.state.collectAsState().value
Box(
modifier = Modifier
.background(YChatTheme.colors.background)
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
.fillMaxHeight()
.fillMaxWidth()
) {
Feedback(feedbackState = FeedbackState.CONSTRUCTION)
when (state) {
is State.Loading ->
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center)
)
is State.Error ->
Feedback(
modifier = Modifier.align(Alignment.Center),
feedbackState = FeedbackState.ERROR,
onButtonClick = { viewModel.fetchModels() }
)
is State.Success ->
ModelListContent(state.models)
}
}
}

@Composable
private fun ModelListContent(models: List<AIModel>) {
LazyColumn {
item { Spacer(modifier = Modifier.padding(top = Dimens.MD)) }
items(models) {
val enableDivider = models.last() != it
ItemMenu(
startText = it.id,
caption = it.ownedBy,
isDividerVisible = enableDivider,
)
}
}
}

@Preview
@Composable
private fun ModelsScreenPreview() {
YChatTheme {
ModelsScreen()
val yChat = YChat.create(BuildConfig.API_KEY)
val viewModel = ModelsViewModel(yChat)
ModelsScreen(viewModel)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package co.yml.ychat.android.presentation.models.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.yml.ychat.YChat
import co.yml.ychat.domain.model.AIModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

internal class ModelsViewModel(private val yChat: YChat) : ViewModel() {

private val yChatListModels by lazy { yChat.listModels() }

private val _state = MutableStateFlow<State>(State.Loading)
val state: StateFlow<State> = _state.asStateFlow()

init {
fetchModels()
}

fun fetchModels() = viewModelScope.launch {
_state.value = State.Loading
runCatching { yChatListModels.execute() }
.onSuccess { _state.value = State.Success(it) }
.onFailure { _state.value = State.Error }
}

sealed class State {
object Loading : State()
data class Success(val models: List<AIModel>) : State()
object Error : State()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ private const val ICON_SIZE = 128
@Composable
fun Feedback(
feedbackState: FeedbackState,
modifier: Modifier = Modifier,
onButtonClick: (() -> Unit)? = null,
) {
Feedback(
modifier = modifier,
icons = feedbackState.icon,
title = stringResource(id = feedbackState.title),
message = stringResource(id = feedbackState.message),
Expand All @@ -37,6 +39,7 @@ fun Feedback(

@Composable
fun Feedback(
modifier: Modifier,
icons: Icons,
title: String,
message: String,
Expand All @@ -45,7 +48,7 @@ fun Feedback(
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(horizontal = Dimens.XXXL)
modifier = modifier.padding(horizontal = Dimens.XXXL)
) {
icons.Icon(
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package co.yml.ychat.android.ui.components.itemmenu

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import co.yml.ychat.android.ui.components.divider.HorizontalDivider
import co.yml.ychat.android.ui.theme.Dimens
import co.yml.ychat.android.ui.theme.TypographyStyle
import co.yml.ychat.android.ui.theme.YChatTheme

@Composable
fun ItemMenu(
startText: String,
caption: String,
isDividerVisible: Boolean = true,
) {
Column {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = Dimens.MD, vertical = 14.dp),
verticalArrangement = Arrangement.spacedBy(Dimens.XXS)
) {
TypographyStyle.MediumBody.Text(text = startText)
TypographyStyle.SmallBody.Text(text = caption, color = YChatTheme.colors.text2)
}
if (isDividerVisible) {
HorizontalDivider(modifier = Modifier.padding(horizontal = Dimens.MD))
}
}
}

@Preview
@Composable
private fun ItemMenuPreview() {
YChatTheme {
Column(
modifier = Modifier
.background(YChatTheme.colors.background)
.fillMaxHeight()
) {
ItemMenu(startText = "Label one line", caption = "Caption one line")
}
}
}
14 changes: 12 additions & 2 deletions sample/jvm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ This endpoint generates images based on the provided prompt.

##### Example:

`GET http://localhost:8080/api/ychat/generations?prompt="ocean"
`GET http://localhost:8080/api/ychat/generations?prompt="ocean"`

### Edits Endpoint

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

##### Example:

`GET http://localhost:8080/api/ychat/edits?input=What day of the wek is it?&instruction=Fix the spelling mistakes
`GET http://localhost:8080/api/ychat/edits?input=What day of the wek is it?&instruction=Fix the spelling mistakes`

### List Models Endpoint

This endpoint retrieve a list of currently available artificial intelligence models.

##### Endpoint: http://localhost:[port_number]/api/ychat/models

##### Example:

`GET http://localhost:8080/api/ychat/models`
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package co.yml.ychat.jvm.controller;

import co.yml.ychat.domain.model.AIModel;
import co.yml.ychat.jvm.services.YChatService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import co.yml.ychat.jvm.services.YChatService;

@RestController
@RequestMapping("api/ychat")
Expand Down Expand Up @@ -49,6 +51,12 @@ public ResponseEntity<String> edits(
return ResponseEntity.ok(result);
}

@GetMapping("models")
public ResponseEntity<List<AIModel>> models() throws Exception {
List<AIModel> result = YChatService.getModels();
return ResponseEntity.ok(result);
}

private static class Defaults {
static final String COMPLETION_INPUT = "Say this is a test.";
static final String CHAT_COMPLETION_INPUT = "Tell me one strength exercise";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package co.yml.ychat.jvm.services;

import co.yml.ychat.domain.model.AIModel;
import co.yml.ychat.domain.model.ChatMessage;
import java.util.List;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -50,6 +51,13 @@ public String getEditsAnswer(String input, String instruction) throws Exception
return future.get().get(0);
}

public List<AIModel> getModels() throws Exception {
final CompletableFuture<List<AIModel>> future = new CompletableFuture<>();
ychat.listModels()
.execute(new CompletionCallbackResult<>(future));
return future.get();
}

private static class CompletionCallbackResult<T> implements YChat.Callback<T> {

private final CompletableFuture<T> future;
Expand Down
14 changes: 14 additions & 0 deletions ychat/src/commonMain/kotlin/co/yml/ychat/YChat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import co.yml.ychat.entrypoint.features.ChatCompletions
import co.yml.ychat.entrypoint.features.Completion
import co.yml.ychat.entrypoint.features.Edits
import co.yml.ychat.entrypoint.features.ImageGenerations
import co.yml.ychat.entrypoint.features.ListModels
import co.yml.ychat.entrypoint.impl.YChatImpl
import kotlin.jvm.JvmStatic
import kotlin.jvm.Volatile
Expand All @@ -18,6 +19,19 @@ import kotlin.native.concurrent.ThreadLocal
*/
interface YChat {

/**
* The listModels api lists the currently available models, and provides basic information
* about each one such as the owner and availability.
*
* Example usage:
* ```
* val result = YChat.create(apiKey)
* .listModels()
* .execute()
* ```
*/
fun listModels(): ListModels

/**
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import co.yml.ychat.data.dto.EditsDto
import co.yml.ychat.data.dto.EditsParamsDto
import co.yml.ychat.data.dto.ImageGenerationsDto
import co.yml.ychat.data.dto.ImageGenerationsParamsDto
import co.yml.ychat.data.dto.ModelListDto
import co.yml.ychat.data.infrastructure.ApiResult

internal interface ChatGptApi {
Expand All @@ -19,4 +20,6 @@ internal interface ChatGptApi {
suspend fun imageGenerations(paramsDto: ImageGenerationsParamsDto): ApiResult<ImageGenerationsDto>

suspend fun edits(paramsDto: EditsParamsDto): ApiResult<EditsDto>

suspend fun models(): ApiResult<ModelListDto>
}
Loading