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

feat: update to kotlin 2.0 & ktor 3.0 #387

Merged
merged 7 commits into from
Oct 6, 2024
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## Unreleased

### Added
- WasmJs target (#387)

### Changed
- Upgrade to Kotlin 2.0 (#387)
- Update Ktor to 3.0 (#387)

### Breaking Changes
- Replace okio by kotlinx.io (#387)

## 3.8.2

### Added
Expand Down
4 changes: 3 additions & 1 deletion build-support/src/main/kotlin/Platforms.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ fun KotlinMultiplatformExtension.native() {

@OptIn(ExperimentalWasmDsl::class)
fun KotlinMultiplatformExtension.jsWasm() {
wasmJs()
wasmJs {
nodejs()
}
}

fun KotlinMultiplatformExtension.jsNode() {
Expand Down
3 changes: 1 addition & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true
kotlin.mpp.commonizerLogLevel=info
kotlin.js.compiler=ir

# Lib
GROUP=com.aallam.openai
VERSION_NAME=3.9.0
VERSION_NAME=4.0.0-SNAPSHOT

# OSS
SONATYPE_HOST=DEFAULT
Expand Down
15 changes: 7 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[versions]
kotlin = "2.0.0"
kotlin = "2.0.20"
coroutines = "1.8.1"
serialization = "1.6.3"
ktor = "3.0.0-beta-2"
okio = "3.9.0"
serialization = "1.7.3"
ktor = "3.0.0-rc-2"
kotlinio = "0.5.4"
logback = "1.4.8"

[libraries]
Expand All @@ -28,10 +28,9 @@ ktor-client-jetty = { group = "io.ktor", name = "ktor-client-jetty", version.ref
ktor-client-mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" }
ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" }
# Okio
okio = { group = "com.squareup.okio", name = "okio", version.ref = "okio" }
okio-nodefilesystem = { group = "com.squareup.okio", name = "okio-nodefilesystem", version.ref = "okio" }
okio-fakefilesystem = { group = "com.squareup.okio", name = "okio-fakefilesystem", version.ref = "okio" }
# IO
kotlinx-io-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-io-core", version.ref = "kotlinio" }
kotlinx-io-bytestring = { group = "org.jetbrains.kotlinx", name = "kotlinx-io-bytestring", version.ref = "kotlinio" }
# Logback
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
# ulid
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
5 changes: 2 additions & 3 deletions openai-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ kotlin {
dependencies {
api(projects.openaiCore)
api(libs.coroutines.core)
api(libs.okio)
api(libs.kotlinx.io.core)
implementation(libs.kotlinx.io.bytestring)
implementation(libs.serialization.json)
api(libs.ktor.client.core)
implementation(libs.ktor.client.logging)
Expand All @@ -47,7 +48,6 @@ kotlin {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
implementation(libs.coroutines.test)
implementation(libs.okio.fakefilesystem)
}
}
val jvmMain by getting
Expand All @@ -61,7 +61,6 @@ kotlin {

val jsMain by getting {
dependencies {
implementation(libs.okio.nodefilesystem)
}
}
val jsTest by getting {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlin.time.Duration.Companion.seconds
* OpenAI API.
*/
public interface OpenAI : Completions, Files, Edits, Embeddings, Models, Moderations, FineTunes, Images, Chat, Audio,
FineTuning, Assistants, Threads, Runs, Messages, VectorStores, Closeable
FineTuning, Assistants, Threads, Runs, Messages, VectorStores, AutoCloseable

/**
* Creates an instance of [OpenAI].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ internal class OpenAIApi(
Messages by MessagesApi(requester),
VectorStores by VectorStoresApi(requester),
Batch by BatchApi(requester),
Closeable by requester
AutoCloseable by requester
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ internal class AudioApi(val requester: HttpRequester) : Audio {
@BetaOpenAI
override suspend fun transcription(request: TranscriptionRequest, requestOptions: RequestOptions?): Transcription {
return when (request.responseFormat) {
AudioResponseFormat.Json, AudioResponseFormat.VerboseJson, null -> transcriptionAsJson(
request,
requestOptions
)

AudioResponseFormat.Json, AudioResponseFormat.VerboseJson, null ->
transcriptionAsJson(request, requestOptions)
else -> transcriptionAsString(request, requestOptions)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import com.aallam.openai.client.internal.JsonLenient
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.utils.io.core.*
import io.ktor.utils.io.core.readAvailable
import io.ktor.utils.io.core.writeFully
import kotlinx.io.buffered
import kotlinx.serialization.json.*
import okio.buffer
import okio.use

/**
* Adds `stream` parameter to the request.
Expand All @@ -27,14 +27,13 @@ internal inline fun <reified T> streamRequestOf(serializable: T): JsonElement {
}

internal fun FormBuilder.appendFileSource(key: String, fileSource: FileSource) {
append(key, fileSource.name, ContentType.Application.OctetStream) {
fileSource.source.buffer().use { source ->
append(key = key, filename = fileSource.name, contentType = ContentType.Application.OctetStream) {
fileSource.source.buffered().use { source ->
val buffer = ByteArray(8192) // 8 KiB
var bytesRead: Int
while (source.read(buffer).also { bytesRead = it } != -1) {
writeFully(src = buffer, offset = 0, length = bytesRead)
while (source.readAvailable(buffer).also { bytesRead = it } != 0) {
writeFully(buffer = buffer, offset = 0, length = bytesRead)
}

}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.aallam.openai.client.internal.http

import com.aallam.openai.client.Closeable
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
Expand All @@ -9,7 +8,7 @@ import io.ktor.util.reflect.*
/**
* Http request performer.
*/
internal interface HttpRequester : Closeable {
internal interface HttpRequester : AutoCloseable {

/**
* Perform an HTTP request and get a result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import com.aallam.openai.api.file.FileSource
import com.aallam.openai.api.model.ModelId
import com.aallam.openai.client.internal.TestFileSystem
import com.aallam.openai.client.internal.testFilePath
import okio.FileSystem
import okio.Path.Companion.toPath
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ import com.aallam.openai.api.file.FileSource
import com.aallam.openai.client.internal.JsonLenient
import com.aallam.openai.client.internal.TestFileSystem
import com.aallam.openai.client.internal.testFilePath
import kotlinx.io.buffered
import kotlinx.io.readByteArray
import kotlin.test.Test
import okio.buffer

class TestChatCompletionChunk {
@Test
fun testContentFilterDeserialization() {
val json = FileSource(path = testFilePath("json/azureContentFilterChunk.json"), fileSystem = TestFileSystem)
val actualJson = json.source.buffer().readByteArray().decodeToString()
val actualJson = json.source.buffered().readByteArray().decodeToString()
JsonLenient.decodeFromString<ChatCompletionChunk>(actualJson)
}

@Test
fun testDeserialization() {
val json = FileSource(path = testFilePath("json/chatChunk.json"), fileSystem = TestFileSystem)
val actualJson = json.source.buffer().readByteArray().decodeToString()
val actualJson = json.source.buffered().readByteArray().decodeToString()
JsonLenient.decodeFromString<ChatCompletionChunk>(actualJson)
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package com.aallam.openai.client.internal

import okio.FileSystem
import okio.Path
import okio.Path.Companion.toPath
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem

/**
* File system to access test files.
*/
internal expect val TestFileSystem: FileSystem
internal val TestFileSystem = SystemFileSystem

/**
* Get [Path] of a given [fileName] test file.
*/
fun testFilePath(fileName: String): Path = libRoot / "openai-client/src/commonTest/resources" / fileName
fun testFilePath(fileName: String): Path = Path(libRoot, "openai-client/src/commonTest/resources", fileName)

/**
* Get the library lib root.
*/
private val libRoot
get() = env("LIB_ROOT")?.toPath() ?: error("Can't find `LIB_ROOT` environment variable")
private val libRoot: String
get() = env("LIB_ROOT") ?: error("Can't find `LIB_ROOT` environment variable")
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.aallam.openai.client.internal

import okio.Buffer
import okio.Source
import kotlinx.io.Buffer
import kotlinx.io.Source
import kotlinx.io.writeString

internal fun String.asSource(): Source {
val buffer = Buffer()
buffer.writeUtf8(this)
buffer.writeString(this)
return buffer
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@ package com.aallam.openai.client

import com.aallam.openai.api.chat.*
import com.aallam.openai.api.model.ModelId
import okio.FileSystem
import okio.Path.Companion.toPath
import kotlinx.io.buffered
import kotlinx.io.bytestring.encode
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.readByteString
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi

import kotlin.test.*

class TestChatVisionJVM : TestOpenAI() {

@OptIn(ExperimentalEncodingApi::class)
@Test
fun encoded() = test {
val byteString = FileSystem.RESOURCES.read("nature.jpeg".toPath()) {
readByteString()
val byteString = SystemFileSystem.source(path = Path("src/jvmTest/resources/nature.jpeg")).buffered().use {
it.readByteString()
}
val encoded = byteString.base64()
val encoded = Base64.encode(source = byteString)
val request = chatCompletionRequest {
model = ModelId("gpt-4-vision-preview")
messages {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.aallam.openai.client.internal

internal actual fun env(name: String): String? {
return getEnv(name)
}

fun getEnv(value: String): String? = js("""globalThis.process.env[value]""")
2 changes: 1 addition & 1 deletion openai-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ kotlin {
}
val commonMain by getting {
dependencies {
api(libs.okio)
api(libs.kotlinx.io.core)
api(libs.serialization.json)
implementation(libs.serialization.core)
}
Expand Down
Loading
Loading