Skip to content

Commit

Permalink
fix: add usage to completions, edits and embeddings (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
aallam authored Jan 20, 2023
1 parent 68db056 commit 7862377
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 66 deletions.
161 changes: 119 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[![Kotlin](https://img.shields.io/badge/kotlin-1.8.0-a97bff.svg?logo=kotlin)](https://kotlinlang.org/docs/releases.html#release-details)
[![Documentation](https://img.shields.io/badge/docs-openai--kotlin-lightgrey)](https://mouaad.aallam.com/openai-kotlin/)

Kotlin client for [OpenAI's API](https://beta.openai.com/docs/api-reference) with multiplatform and coroutines capabilities.
Kotlin client for [OpenAI's API](https://beta.openai.com/docs/api-reference) with multiplatform and coroutines
capabilities.

## 🛠 Setup

Expand All @@ -20,38 +21,49 @@ dependencies {
implementation "com.aallam.openai:openai-client:<version>"
}
```

2. Choose and add to your dependencies one of [Ktor's engines](https://ktor.io/docs/http-client-engines.html).

> Alternatively, you can use [openai-client-bom](openai-client-bom/)
### Multiplaform
In multiplatform projects, add openai client dependency to `commonMain`, and choose an [engine](https://ktor.io/docs/http-client-engines.html) for each target.

In multiplatform projects, add openai client dependency to `commonMain`, and choose
an [engine](https://ktor.io/docs/http-client-engines.html) for each target.

## 💡 Getting Started

Create an instance of `OpenAI` client:

```kotlin
val openAI = OpenAI(apiKey)
```

Use your `OpenAI` instance to make API requests:

#### Models

<details>
<summary><strong>List models</strong></summary>

```kotlin
val models: List<Model> = openAI.models()
```

</details>

<details>
<summary><strong>Retrieve an model</strong></summary>
<summary><strong>Retrieve a model</strong></summary>

```kotlin
val id = ModelId("text-ada-001")
val model: Model = openAI.model(id)
```

</details>


#### Completions

<details>
<summary><strong>Create completion</strong></summary>

Expand All @@ -63,8 +75,9 @@ val completionRequest = CompletionRequest(
)
val completion: TextCompletion = openAI.completion(Ada, completionRequest)
```

</details>

<details>
<summary><strong>Create completion stream</strong></summary>

Expand All @@ -80,8 +93,11 @@ val request = CompletionRequest(
)
val completions: Flow<TextCompletion> = openAI.completions(request)
```

</details>

#### Edits

<details>
<summary><strong>Create edits</strong></summary>

Expand All @@ -94,16 +110,60 @@ val edit = openAI.edit(
)
)
```

</details>

#### Images

<details>
<summary><strong>List files</strong></summary>
<summary><strong>Create images</strong></summary>

````kotlin
val files: List<File> = openAI.files()
val images = openAI.imageURL( // or openAI.imageJSON
creation = ImageCreation(
prompt = "A cute baby sea otter",
n = 2,
size = ImageSize.is1024x1024
)
)
````

</details>

<details>
<summary><strong>Edit images*</strong></summary>

````kotlin
val images = openAI.imageURL( // or openAI.imageJSON
edit = ImageEdit(
image = FileSource(name = "<filename>", source = imageSource),
mask = FileSource(name = "<filename>", source = maskSource),
prompt = "a sunlit indoor lounge area with a pool containing a flamingo",
n = 1,
size = ImageSize.is1024x1024
)
)
````

</details>

<details>
<summary><strong>Create image variants*</strong></summary>

````kotlin
val images = openAI.imageURL( // or openAI.imageJSON
variation = ImageVariation(
image = FileSource(name = "<filename>", source = imageSource),
n = 1,
size = ImageSize.is1024x1024
)
)
````

</details>

### Embeddings

<details>
<summary><strong>Create embeddings</strong></summary>

Expand All @@ -115,77 +175,94 @@ val embeddings: List<Embedding> = openAI.embeddings(
)
)
````
</details>

</details>

### Files

<details>
<summary><strong>Create moderation</strong></summary>
<summary><strong>List files</strong></summary>

````kotlin
val moderation = openAI.moderations(
request = ModerationRequest(
input = "I want to kill them."
)
)
val files: List<File> = openAI.files()
````
</details>

</details>

<details>
<summary><strong>Create fine-tunes</strong></summary>
<summary><strong>Upload file*</strong></summary>

````kotlin
val fineTune = openAI.fineTune(
request = FineTuneRequest(
trainingFile = trainingFile,
model = ModelId("ada")
val file = openAI.file(
request = FileUpload(
file = source,
purpose = Purpose("fine-tune")
)
)
````

</details>

<details>
<summary><strong>Create images</strong></summary>
<summary><strong>Delete file</strong></summary>

````kotlin
val images = openAI.image(
creation = ImageCreationURL(
prompt = "A cute baby sea otter",
n = 2,
size = ImageSize.is1024x1024
)
)
openAI.delete(fileId)
````

</details>

<details>
<summary><strong>Edit images</strong></summary>
<summary><strong>Retrieve file</strong></summary>

````kotlin
val images = openAI.image(
edit = ImageEditURL( // or 'ImageEditJSON'
image = FilePath(imagePath),
mask = FilePath(maskPath),
prompt = "a sunlit indoor lounge area with a pool containing a flamingo",
n = 1,
size = ImageSize.is1024x1024
val file = openAI.file(fileId)
````

</details>

<details>
<summary><strong>Retrieve file content</strong></summary>

````kotlin
val bytes = openAI.download(fileId)
````

</details>

### Fine-tunes

<details>
<summary><strong>Create fine-tunes</strong></summary>

````kotlin
val fineTune = openAI.fineTune(
request = FineTuneRequest(
trainingFile = trainingFile,
model = ModelId("ada")
)
)
````

</details>

### Moderations

<details>
<summary><strong>Create image variants</strong></summary>
<summary><strong>Create moderation</strong></summary>

````kotlin
val images = openAI.image(
variation = ImageVariationURL( // or, 'ImageVariationJSON'
image = FilePath(imagePath),
n = 1,
size = ImageSize.is1024x1024
val moderation = openAI.moderations(
request = ModerationRequest(
input = "I want to kill them."
)
)
````

</details>

_* requires [okio](https://square.github.io/okio/)_

## ℹ️ Sample apps

Sample apps are available under `sample`, please check the [README](sample/README.md) for running instructions.
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ kotlin = "1.8.0"
coroutines = "1.6.4"
serialization = "1.4.1"
ktor = "2.2.1"
okio = "3.2.0"
okio = "3.3.0"
logback = "1.4.4"

[libraries]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.aallam.openai.client

import com.aallam.openai.api.embedding.Embedding
import com.aallam.openai.api.embedding.EmbeddingRequest
import com.aallam.openai.api.embedding.EmbeddingResponse

/**
* Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms.
Expand All @@ -11,5 +11,5 @@ public interface Embeddings {
/**
* Creates an embedding vector representing the input text.
*/
public suspend fun embeddings(request: EmbeddingRequest): List<Embedding>
public suspend fun embeddings(request: EmbeddingRequest): EmbeddingResponse
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.aallam.openai.client.internal.api

import com.aallam.openai.api.core.ListResponse
import com.aallam.openai.api.embedding.Embedding
import com.aallam.openai.api.embedding.EmbeddingRequest
import com.aallam.openai.api.embedding.EmbeddingResponse
import com.aallam.openai.client.Embeddings
import com.aallam.openai.client.internal.http.HttpRequester
import com.aallam.openai.client.internal.http.perform
Expand All @@ -18,14 +17,14 @@ import io.ktor.http.contentType
*/
internal class EmbeddingsApi(private val requester: HttpRequester) : Embeddings {

override suspend fun embeddings(request: EmbeddingRequest): List<Embedding> {
return requester.perform<ListResponse<Embedding>> {
override suspend fun embeddings(request: EmbeddingRequest): EmbeddingResponse {
return requester.perform {
it.post {
url(path = EmbeddingsPathV1)
setBody(request)
contentType(ContentType.Application.Json)
}.body()
}.data
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.aallam.openai.client.internal.api
import com.aallam.openai.api.core.DeleteResponse
import com.aallam.openai.api.core.ListResponse
import com.aallam.openai.api.file.File
import com.aallam.openai.api.file.FileUpload
import com.aallam.openai.api.file.FileId
import com.aallam.openai.api.file.FileUpload
import com.aallam.openai.client.Files
import com.aallam.openai.client.internal.extension.appendFileSource
import com.aallam.openai.client.internal.http.HttpRequester
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue

class TestCompletions : TestOpenAI() {

@Test
fun completions() {
runTest {
val request = completionRequest {
model = ModelId("text-davinci-002")
model = ModelId("text-ada-001")
prompt = "Once upon a time"
maxTokens = 5
temperature = 1.0
Expand All @@ -24,6 +25,9 @@ class TestCompletions : TestOpenAI() {
stop = listOf("\n")
}

val completion = openAI.completion(request)
assertTrue { completion.choices.isNotEmpty() }

val results = mutableListOf<TextCompletion>()
openAI.completions(request)
.onEach { results += it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class TestEmbeddings : TestOpenAI() {
input = listOf("The food was delicious and the waiter...")
}
)
assertTrue { response.isNotEmpty() }
val embedding = response.first()
assertTrue { response.embeddings.isNotEmpty() }
val embedding = response.embeddings.first()
assertTrue { embedding.embedding.isNotEmpty() }
assertEquals(embedding.index, 0)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.aallam.openai.api.completion

import com.aallam.openai.api.core.Usage
import com.aallam.openai.api.model.ModelId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -30,4 +31,9 @@ public data class TextCompletion(
* A list of generated completions
*/
@SerialName("choices") public val choices: List<Choice>,

/**
* Text completion usage data.
*/
@SerialName("usage") public val usage: Usage? = null,
)
Loading

0 comments on commit 7862377

Please sign in to comment.