Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CM-1279] Implements retrieve model entrypoint #57

Merged
merged 4 commits into from
Mar 31, 2023
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 @@ -86,6 +86,7 @@ try {
### Features

- [ListModels](guides/Features.md#listmodels)
- [RetrieveModel](guides/Features.md#retrieveModel)
- [Completions](guides/Features.md#completion)
- [ChatCompletions](guides/Features.md#chatcompletions)
- [ImageGenerations](guides/Features.md#imagegenerations)
Expand Down
46 changes: 38 additions & 8 deletions guides/Features.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Features

- [ListModels](#listModels)
- [RetrieveModel](#retrieveModel)
- [Completion](#completion)
- [ChatCompletions](#chatcompletions)
- [ImageGenerations](#imagegenerations)
Expand Down Expand Up @@ -39,6 +40,39 @@ try {
}
```

## RetrieveModel

The retrieveModel api retrieve the currently model based on the given id, and provides basic information about it such as the owner and availability.

### Swift

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

do {
let result = try await yChat.retrieveModel().execute(id: "babbage")
} 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.retrieveModel().execute("babbage")

} 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 All @@ -51,7 +85,7 @@ var yChat: YChat {
}

do {
let result = try await chatGpt.completion()
let result = try await yChat.completion()
.setInput(input: "Say this is a test.")
.setMaxTokens(tokens: 1024)
.set... // you can set more parameters
Expand All @@ -74,7 +108,6 @@ try {
.setMaxTokens(1024)
.set... // you can set more parameters
.execute()

} catch (e: exception) {
// catch any error that may occurs on api call.
}
Expand All @@ -92,7 +125,7 @@ var yChat: YChat {
}

do {
let result = try await chatGpt.chatCompletions()
let result = try await yChat.chatCompletions()
.setMaxTokens(tokens: 1024)
.addMessage(
role: "assistant",
Expand Down Expand Up @@ -121,7 +154,6 @@ try {
)
.set... // you can set more parameters
.execute("What is the best exercise for building muscle?")

} catch (e: exception) {
// catch any error that may occurs on api call.
}
Expand All @@ -139,7 +171,7 @@ var yChat: YChat {
}

do {
let result = try await chatGpt.imageGenerations()
let result = try await yChat.imageGenerations()
.setResults(results: 2)
.setSize(size: "1024x1024")
.set... // you can set more parameters
Expand All @@ -162,7 +194,6 @@ try {
.setSize("1024x1024")
.set... // you can set more parameters
.execute("ocean")

} catch (e: exception) {
// catch any error that may occurs on api call.
}
Expand All @@ -180,7 +211,7 @@ var yChat: YChat {
}

do {
let result = try await chatGpt.edits()
let result = try await yChat.edits()
.setInput(input: "What day of the wek is it?")
.setResults(result: 1)
.set... // you can set more parameters
Expand All @@ -203,7 +234,6 @@ try {
.setResults(1)
.set... // you can set more parameters
.execute("Fix the spelling mistakes")

} catch (e: exception) {
// catch any error that may occurs on api call.
}
Expand Down
12 changes: 11 additions & 1 deletion sample/jvm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,14 @@ This endpoint retrieve a list of currently available artificial intelligence mod

##### Example:

`GET http://localhost:8080/api/ychat/models`
`GET http://localhost:8080/api/ychat/models`

### Model Endpoint

This endpoint retrieve the artificial intelligence model based on the given ID.

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

##### Example:

`GET http://localhost:8080/api/ychat/models/babbage`
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -57,6 +58,12 @@ public ResponseEntity<List<AIModel>> models() throws Exception {
return ResponseEntity.ok(result);
}

@GetMapping("models/{id}")
public ResponseEntity<AIModel> model(@PathVariable String id) throws Exception {
AIModel result = YChatService.getModel(id);
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,13 +1,13 @@
package co.yml.ychat.jvm.services;

import co.yml.ychat.YChat;
import co.yml.ychat.domain.model.AIModel;
import co.yml.ychat.domain.model.ChatMessage;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import co.yml.ychat.YChat;

@Service
public class YChatService {
Expand Down Expand Up @@ -58,6 +58,13 @@ public List<AIModel> getModels() throws Exception {
return future.get();
}

public AIModel getModel(String id) throws Exception {
final CompletableFuture<AIModel> future = new CompletableFuture<>();
ychat.retrieveModel()
.execute(id, 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 @@ -5,6 +5,7 @@ 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.features.RetrieveModel
import co.yml.ychat.entrypoint.impl.YChatImpl
import kotlin.jvm.JvmStatic
import kotlin.jvm.Volatile
Expand Down Expand Up @@ -32,6 +33,19 @@ interface YChat {
*/
fun listModels(): ListModels

/**
* The retrieveModel api retrieve the currently model based on the given id, and provides basic
* information about it such as the owner and availability.
*
* Example usage:
* ```
* val result = YChat.create(apiKey)
* .retrieveModel()
* .execute("gpt-3")
* ```
*/
fun retrieveModel(): RetrieveModel

/**
* 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.ModelDto
import co.yml.ychat.data.dto.ModelListDto
import co.yml.ychat.data.infrastructure.ApiResult

Expand All @@ -22,4 +23,6 @@ internal interface ChatGptApi {
suspend fun edits(paramsDto: EditsParamsDto): ApiResult<EditsDto>

suspend fun models(): ApiResult<ModelListDto>

suspend fun model(id: String): ApiResult<ModelDto>
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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.ModelDto
import co.yml.ychat.data.dto.ModelListDto
import co.yml.ychat.data.infrastructure.ApiExecutor
import co.yml.ychat.data.infrastructure.ApiResult
Expand Down Expand Up @@ -54,4 +55,11 @@ internal class ChatGptApiImpl(private val apiExecutor: ApiExecutor) : ChatGptApi
.setHttpMethod(HttpMethod.Get)
.execute()
}

override suspend fun model(id: String): ApiResult<ModelDto> {
return apiExecutor
.setEndpoint("v1/models/$id")
.setHttpMethod(HttpMethod.Get)
.execute()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import co.yml.ychat.domain.usecases.CompletionUseCase
import co.yml.ychat.domain.usecases.EditsUseCase
import co.yml.ychat.domain.usecases.ImageGenerationsUseCase
import co.yml.ychat.domain.usecases.ListModelsUseCase
import co.yml.ychat.domain.usecases.RetrieveModelUseCase
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.features.RetrieveModel
import co.yml.ychat.entrypoint.impl.ChatCompletionsImpl
import co.yml.ychat.entrypoint.impl.CompletionImpl
import co.yml.ychat.entrypoint.impl.EditsImpl
import co.yml.ychat.entrypoint.impl.ImageGenerationsImpl
import co.yml.ychat.entrypoint.impl.ListModelsImpl
import co.yml.ychat.entrypoint.impl.RetrieveModelImpl
import kotlinx.coroutines.Dispatchers
import org.koin.core.module.Module
import org.koin.dsl.module
Expand All @@ -31,6 +34,7 @@ internal class LibraryModule(private val apiKey: String) {

private val entrypointModule = module {
factory<ListModels> { ListModelsImpl(Dispatchers.Default, get()) }
factory<RetrieveModel> { RetrieveModelImpl(Dispatchers.Default, get()) }
factory<Completion> { CompletionImpl(Dispatchers.Default, get()) }
factory<ChatCompletions> { ChatCompletionsImpl(Dispatchers.Default, get()) }
factory<ImageGenerations> { ImageGenerationsImpl(Dispatchers.Default, get()) }
Expand All @@ -39,6 +43,7 @@ internal class LibraryModule(private val apiKey: String) {

private val domainModule = module {
factory { ListModelsUseCase(get()) }
factory { RetrieveModelUseCase(get()) }
factory { CompletionUseCase(get(), get()) }
factory { ChatCompletionsUseCase(get()) }
factory { ImageGenerationsUseCase(get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import co.yml.ychat.domain.mapper.toChatMessages
import co.yml.ychat.domain.model.ChatCompletionsParams
import co.yml.ychat.domain.model.ChatMessage

internal data class ChatCompletionsUseCase(private val chatGptApi: ChatGptApi) {
internal class ChatCompletionsUseCase(private val chatGptApi: ChatGptApi) {

suspend fun requestChatCompletions(params: ChatCompletionsParams): List<ChatMessage> {
val requestDto = params.toChatCompletionParamsDto()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import co.yml.ychat.domain.mapper.toEditsModel
import co.yml.ychat.domain.mapper.toEditsParamsDto
import co.yml.ychat.domain.model.EditsParams

internal data class EditsUseCase(private val chatGptApi: ChatGptApi) {
internal class EditsUseCase(private val chatGptApi: ChatGptApi) {

suspend fun requestEdits(params: EditsParams): List<String> {
val requestDto = params.toEditsParamsDto()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import co.yml.ychat.domain.mapper.toImageGenerated
import co.yml.ychat.domain.mapper.toImageGenerationsParamsDto
import co.yml.ychat.domain.model.ImageGenerationsParams

internal data class ImageGenerationsUseCase(private val chatGptApi: ChatGptApi) {
internal class ImageGenerationsUseCase(private val chatGptApi: ChatGptApi) {

suspend fun requestImageGenerations(params: ImageGenerationsParams): List<String> {
val requestDto = params.toImageGenerationsParamsDto()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import co.yml.ychat.data.api.ChatGptApi
import co.yml.ychat.domain.mapper.toModel
import co.yml.ychat.domain.model.AIModel

internal data class ListModelsUseCase(private val chatGptApi: ChatGptApi) {
internal class ListModelsUseCase(private val chatGptApi: ChatGptApi) {

suspend fun getListModels(): List<AIModel> {
val response = chatGptApi.models()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package co.yml.ychat.domain.usecases

import co.yml.ychat.data.api.ChatGptApi
import co.yml.ychat.domain.mapper.toModel
import co.yml.ychat.domain.model.AIModel

internal class RetrieveModelUseCase(private val chatGptApi: ChatGptApi) {

suspend fun getModel(id: String): AIModel {
val response = chatGptApi.model(id)
return response.getBodyOrThrow().toModel()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package co.yml.ychat.entrypoint.features

import co.yml.ychat.YChat
import co.yml.ychat.data.exception.ChatGptException
import co.yml.ychat.domain.model.AIModel
import kotlin.coroutines.cancellation.CancellationException

interface RetrieveModel {

/**
* Retrieves an artificial intelligence model based on the given [id] and provides basic
* information about it, such as the owner and availability.
*
* @param id The ID of the model to retrieve.
* @return The artificial intelligence model with the given [id].
* @throws CancellationException if the operation is cancelled.
* @throws ChatGptException if there is an error generating chat completions.
*/
@Throws(CancellationException::class, ChatGptException::class)
suspend fun execute(id: String): AIModel

/**
* Retrieves an artificial intelligence model based on the given [id], and passes it to
* the provided callback.
*
* @param callback The callback to receive the model.
*/
fun execute(id: String, callback: YChat.Callback<AIModel>)
}
Loading