From 4468e12c375f4fc36fd24d9ab4d9930e602e9a6d Mon Sep 17 00:00:00 2001 From: Mouaad Aallam Date: Tue, 8 Mar 2022 18:56:11 +0100 Subject: [PATCH] chore: support multiple native targets (#5) --- .gitignore | 5 ++- build-support/build.gradle.kts | 22 ++++++++++ build-support/settings.gradle.kts | 1 + build-support/src/main/kotlin/BuildSupport.kt | 8 ++++ build-support/src/main/kotlin/Platforms.kt | 21 +++++++++ build.gradle.kts | 27 +++++++++--- gradle.properties | 2 +- gradle/libs.versions.toml | 19 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- openai-client/build.gradle.kts | 43 ++++++------------- .../internal/HttpClient.kt | 16 +++---- .../internal/api/AnswersApi.kt | 7 ++- .../internal/api/ClassificationsApi.kt | 7 ++- .../internal/api/CompletionsApi.kt | 33 +++++++------- .../internal/api/EnginesApi.kt | 5 ++- .../internal/api/FilesApi.kt | 11 ++--- .../internal/api/SearchesApi.kt | 10 ++--- .../internal/extension/Log.kt | 6 +-- .../com/aallam/openai/client/TestOpenAI.kt | 20 ++++----- .../openai/client/internal/Coroutine.kt | 5 --- .../internal/Coroutine.kt | 10 ----- .../openai/client/internal/Coroutine.kt | 6 --- .../ClientFileSystem.kt | 1 - .../ClientFileSystem.kt | 5 +++ .../ClientFileSystem.kt | 5 +++ .../ClientFileSystem.kt | 5 +++ .../internal/Coroutine.kt | 6 --- openai-core/api/openai-core.api | 17 ++++++++ openai-core/build.gradle.kts | 32 +++----------- .../com.aallam.openai.api/engine/Engine.kt | 2 +- settings.gradle.kts | 4 +- 31 files changed, 207 insertions(+), 156 deletions(-) create mode 100644 build-support/build.gradle.kts create mode 100644 build-support/settings.gradle.kts create mode 100644 build-support/src/main/kotlin/BuildSupport.kt create mode 100644 build-support/src/main/kotlin/Platforms.kt delete mode 100644 openai-client/src/commonTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt delete mode 100644 openai-client/src/jsTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt delete mode 100644 openai-client/src/jvmTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt rename openai-client/src/{nativeMain/kotlin/com.aallam.openai.client/internal => linuxX64Main/kotlin/com.aallam.openai.client.internal}/ClientFileSystem.kt (79%) create mode 100644 openai-client/src/macosArm64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt create mode 100644 openai-client/src/macosX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt create mode 100644 openai-client/src/mingwX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt delete mode 100644 openai-client/src/nativeTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt diff --git a/.gitignore b/.gitignore index 6ed3b374..0de18f92 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,7 @@ coverage-error.log .DS_Store # Java -*.hprof \ No newline at end of file +*.hprof + +# kmp +kotlin-js-store \ No newline at end of file diff --git a/build-support/build.gradle.kts b/build-support/build.gradle.kts new file mode 100644 index 00000000..182bf712 --- /dev/null +++ b/build-support/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + `kotlin-dsl` + `java-gradle-plugin` +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly(kotlin("gradle-plugin")) + compileOnly(kotlin("gradle-plugin-api")) +} + +gradlePlugin { + plugins { + create("build-support") { + id = "build-support" + implementationClass = "BuildSupport" + } + } +} diff --git a/build-support/settings.gradle.kts b/build-support/settings.gradle.kts new file mode 100644 index 00000000..f97506fc --- /dev/null +++ b/build-support/settings.gradle.kts @@ -0,0 +1 @@ +// empty. \ No newline at end of file diff --git a/build-support/src/main/kotlin/BuildSupport.kt b/build-support/src/main/kotlin/BuildSupport.kt new file mode 100644 index 00000000..18fca5b8 --- /dev/null +++ b/build-support/src/main/kotlin/BuildSupport.kt @@ -0,0 +1,8 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project + +class BuildSupport : Plugin { + override fun apply(project: Project) { + // Do nothing. + } +} diff --git a/build-support/src/main/kotlin/Platforms.kt b/build-support/src/main/kotlin/Platforms.kt new file mode 100644 index 00000000..5dec41fa --- /dev/null +++ b/build-support/src/main/kotlin/Platforms.kt @@ -0,0 +1,21 @@ +import org.gradle.kotlin.dsl.creating +import org.gradle.kotlin.dsl.getValue +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + +fun KotlinMultiplatformExtension.native() { + val targets = mutableListOf().apply { + add(linuxX64()) + add(macosX64()) + add(macosArm64()) + add(mingwX64()) + } + sourceSets.apply { + val nativeMain by creating { dependsOn(getByName("commonMain")) } + val nativeTest by creating { dependsOn(getByName("commonTest")) } + targets.forEach { target -> + getByName("${target.name}Main").dependsOn(nativeMain) + getByName("${target.name}Test").dependsOn(nativeTest) + } + } +} diff --git a/build.gradle.kts b/build.gradle.kts index ab0c8e50..ff6a9381 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,19 +1,36 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent.* +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + buildscript { repositories { mavenCentral() } dependencies { - val kotlinVersion = "1.5.10" + val kotlinVersion = "1.6.10" classpath(kotlin("gradle-plugin", version = kotlinVersion)) classpath(kotlin("serialization", version = kotlinVersion)) - classpath("com.vanniktech:gradle-maven-publish-plugin:0.15.1") - classpath("org.jetbrains.kotlinx:binary-compatibility-validator:0.6.0") + classpath("com.vanniktech:gradle-maven-publish-plugin:0.18.0") + classpath("org.jetbrains.kotlinx:binary-compatibility-validator:0.8.0") } } -subprojects { +allprojects { repositories { mavenCentral() } - val javadoc by tasks.creating(Javadoc::class) + + tasks.withType().configureEach { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } + } + + tasks.withType { + testLogging { + events(STARTED, PASSED, SKIPPED, FAILED) + exceptionFormat = TestExceptionFormat.FULL + showStandardStreams = false + } + } } diff --git a/gradle.properties b/gradle.properties index 974dde73..744bc972 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ kotlin.code.style=official kotlin.mpp.stability.nowarn=true kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.mpp.enableCompatibilityMetadataVariant=true kotlin.native.enableDependencyPropagation=false -kotlin.js.generate.executable.default=false # Lib GROUP=com.aallam.openai diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d163ecc0..eb685b4c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,26 +1,29 @@ [versions] -coroutines = "1.5.0-native-mt" -serialization = "1.2.1" -ktor = "1.6.0" -okio = "3.0.0-alpha.6" +coroutines = "1.6.0-native-mt" +serialization = "1.3.1" +ktor = "2.0.0-beta-1" +okio = "3.0.0" logback = "1.2.3" [libraries] # Coroutines coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" } +coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" } # Serialization serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "serialization" } +serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" } # Ktor ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktor" } ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" } -ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serialization", version.ref = "ktor" } ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" } ktor-client-curl = { group = "io.ktor", name = "ktor-client-curl", version.ref = "ktor" } ktor-client-apache = { group = "io.ktor", name = "ktor-client-apache", version.ref = "ktor" } ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktor" } +ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" } +ktor-client-serialization-kotlinx = { group = "io.ktor", name = "ktor-serialization-kotlinx", version.ref = "ktor" } # Okio -okio-multiplatform = { group = "com.squareup.okio", name = "okio-multiplatform", version.ref = "okio" } -okio-nodefilesystem = { group = "com.squareup.okio", name = "okio-nodefilesystem-multiplatform", version.ref = "okio" } -okio-fakefilesystem = { group = "com.squareup.okio", name = "okio-fakefilesystem-multiplatform", version.ref = "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" } # Logback logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1acc777d..41dfb879 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/openai-client/build.gradle.kts b/openai-client/build.gradle.kts index 29ec4f86..73d8769a 100644 --- a/openai-client/build.gradle.kts +++ b/openai-client/build.gradle.kts @@ -3,56 +3,42 @@ plugins { kotlin("plugin.serialization") id("com.vanniktech.maven.publish") id("binary-compatibility-validator") + id("build-support") } kotlin { explicitApi() - jvm { - compilations.all { - kotlinOptions.jvmTarget = "1.8" - } - testRuns["test"].executionTask.configure { - useJUnit() - } - } - js(LEGACY) { - nodejs() - } - - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - val nativeTarget = when { - hostOs == "Mac OS X" -> macosX64("native") - hostOs == "Linux" -> linuxX64("native") - isMingwX64 -> mingwX64("native") - else -> throw GradleException("Host OS is not supported in Kotlin/Native.") - } - nativeTarget.apply { - binaries {} - } + jvm() + js { nodejs() } + native() sourceSets { all { - languageSettings.apply { - useExperimentalAnnotation("kotlin.RequiresOptIn") - useExperimentalAnnotation("okio.ExperimentalFileSystem") + languageSettings { + optIn("kotlin.RequiresOptIn") + optIn("okio.ExperimentalFileSystem") + optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") } } val commonMain by getting { dependencies { api(project(":openai-core")) api(libs.coroutines.core) + implementation(libs.serialization.json) implementation(libs.ktor.client.json) implementation(libs.ktor.client.logging) - implementation(libs.ktor.client.serialization) implementation(libs.ktor.client.auth) - implementation(libs.okio.multiplatform) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.client.serialization.kotlinx) + implementation(libs.okio) } } val commonTest by getting { dependencies { + implementation(project(":openai-core")) implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) + implementation(libs.coroutines.test) implementation(libs.okio.fakefilesystem) } } @@ -75,7 +61,6 @@ kotlin { implementation(kotlin("test-js")) } } - val nativeMain by getting val nativeTest by getting { dependencies { implementation(libs.ktor.client.curl) diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/HttpClient.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/HttpClient.kt index 16050610..a4e153e9 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/HttpClient.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/HttpClient.kt @@ -4,14 +4,13 @@ import com.aallam.openai.client.OpenAIConfig import com.aallam.openai.client.internal.extension.toKtorLogLevel import com.aallam.openai.client.internal.extension.toKtorLogger import io.ktor.client.* -import io.ktor.client.features.* -import io.ktor.client.features.auth.* -import io.ktor.client.features.auth.providers.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.logging.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.auth.* +import io.ktor.client.plugins.auth.providers.* +import io.ktor.client.plugins.logging.* import io.ktor.client.request.* import io.ktor.http.* +import io.ktor.serialization.kotlinx.* import kotlinx.serialization.json.Json /** @@ -19,8 +18,8 @@ import kotlinx.serialization.json.Json */ internal fun createHttpClient(config: OpenAIConfig): HttpClient { return HttpClient { - install(JsonFeature) { - serializer = KotlinxSerializer(JsonLenient) + install(ContentNegotiation) { + register(ContentType.Application.Json, KotlinxSerializationConverter(JsonLenient)) } install(Logging) { logger = config.logger.toKtorLogger() @@ -49,5 +48,4 @@ internal fun createHttpClient(config: OpenAIConfig): HttpClient { internal val JsonLenient = Json { isLenient = true ignoreUnknownKeys = true - useAlternativeNames = false // TODO: remove after https://github.com/Kotlin/kotlinx.serialization/issues/1450 } diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/AnswersApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/AnswersApi.kt index 4ca32dcd..ae734a3f 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/AnswersApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/AnswersApi.kt @@ -5,6 +5,7 @@ import com.aallam.openai.api.answer.Answer import com.aallam.openai.api.answer.AnswerRequest import com.aallam.openai.client.Answers import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.http.* @@ -15,9 +16,11 @@ internal class AnswersApi(private val httpClient: HttpClient) : Answers { @ExperimentalOpenAI override suspend fun answers(request: AnswerRequest): Answer { - return httpClient.post(path = AnswersPath, body = request) { + return httpClient.post { + url(path = AnswersPath) + setBody(request) contentType(ContentType.Application.Json) - } + }.body() } companion object { diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/ClassificationsApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/ClassificationsApi.kt index 1e601c19..0dfecb42 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/ClassificationsApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/ClassificationsApi.kt @@ -5,6 +5,7 @@ import com.aallam.openai.api.classification.Classification import com.aallam.openai.api.classification.ClassificationRequest import com.aallam.openai.client.Classifications import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.http.* @@ -15,9 +16,11 @@ internal class ClassificationsApi(private val httpClient: HttpClient) : Classifi @ExperimentalOpenAI override suspend fun classifications(request: ClassificationRequest): Classification { - return httpClient.post(path = ClassificationsPath, body = request) { + return httpClient.post { + url(path = ClassificationsPath) + setBody(request) contentType(ContentType.Application.Json) - } + }.body() } companion object { diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/CompletionsApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/CompletionsApi.kt index 969bb544..3d974b18 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/CompletionsApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/CompletionsApi.kt @@ -12,6 +12,7 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.client.utils.* +import io.ktor.client.utils.EmptyContent.contentType import io.ktor.http.* import io.ktor.utils.io.* import kotlinx.coroutines.flow.Flow @@ -24,29 +25,29 @@ import kotlinx.serialization.decodeFromString internal class CompletionsApi(private val httpClient: HttpClient) : Completions { override suspend fun completion(engineId: EngineId, request: CompletionRequest?): TextCompletion { - return httpClient.post(path = "$EnginesPath/$engineId/completions", body = request ?: EmptyContent) { + return httpClient.post { + url(path = "$EnginesPath/$engineId/completions") + setBody(request ?: EmptyContent) contentType(ContentType.Application.Json) - } + }.body() } override fun completions(engineId: EngineId, request: CompletionRequest?): Flow { return flow { - httpClient.post( - path = "$EnginesPath/$engineId/completions", - body = request.toStreamRequest() - ) { + val response = httpClient.post { + url(path = "$EnginesPath/$engineId/completions") + setBody(request.toStreamRequest()) contentType(ContentType.Application.Json) - }.execute { response -> - val readChannel = response.receive() - while (!readChannel.isClosedForRead) { - val line = readChannel.readUTF8Line() ?: "" - val value: TextCompletion = when { - line.startsWith(StreamEndToken) -> break - line.startsWith(StreamPrefix) -> JsonLenient.decodeFromString(line.removePrefix(StreamPrefix)) - else -> continue - } - emit(value) + } + val readChannel = response.body() + while (!readChannel.isClosedForRead) { + val line = readChannel.readUTF8Line() ?: "" + val value: TextCompletion = when { + line.startsWith(StreamEndToken) -> break + line.startsWith(StreamPrefix) -> JsonLenient.decodeFromString(line.removePrefix(StreamPrefix)) + else -> continue } + emit(value) } } } diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/EnginesApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/EnginesApi.kt index a72c1473..7b98756a 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/EnginesApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/EnginesApi.kt @@ -5,6 +5,7 @@ import com.aallam.openai.api.engine.EngineId import com.aallam.openai.api.engine.EnginesResponse import com.aallam.openai.client.Engines import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* /** @@ -13,11 +14,11 @@ import io.ktor.client.request.* internal class EnginesApi(private val httpClient: HttpClient) : Engines { override suspend fun engines(): List { - return httpClient.get(path = EnginesPath).data + return httpClient.get { url(path = EnginesPath) }.body().data } override suspend fun engine(engineId: EngineId): Engine { - return httpClient.get(path = "$EnginesPath/$engineId") + return httpClient.get { url(path = "$EnginesPath/$engineId") }.body() } companion object { diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/FilesApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/FilesApi.kt index 6363e297..f639366e 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/FilesApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/FilesApi.kt @@ -6,7 +6,8 @@ import com.aallam.openai.api.file.FileRequest import com.aallam.openai.api.file.FileResponse import com.aallam.openai.client.Files import io.ktor.client.* -import io.ktor.client.features.* +import io.ktor.client.call.* +import io.ktor.client.plugins.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* @@ -27,16 +28,16 @@ internal class FilesApi( appendFile(fileSystem, "file", request.file) append("purpose", request.purpose.raw) } - return httpClient.submitFormWithBinaryData(url = FilesPath, formData = data) + return httpClient.submitFormWithBinaryData(url = FilesPath, formData = data).body() } override suspend fun files(): List { - return httpClient.get(path = FilesPath).data + return httpClient.get { url(path = FilesPath) }.body().data } override suspend fun file(fileId: FileId): File? { return try { - httpClient.get(path = "$FilesPath/$fileId") + httpClient.get { url(path = "$FilesPath/$fileId") }.body() } catch (exception: ClientRequestException) { if (exception.response.status == HttpStatusCode.NotFound) return null throw exception @@ -44,7 +45,7 @@ internal class FilesApi( } override suspend fun delete(fileId: FileId) { - return httpClient.delete(path = "$FilesPath/$fileId") + httpClient.delete { url(path = "$FilesPath/$fileId") } } /** diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/SearchesApi.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/SearchesApi.kt index ea2d7b2c..1ead4837 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/SearchesApi.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/SearchesApi.kt @@ -7,6 +7,7 @@ import com.aallam.openai.api.search.SearchResult import com.aallam.openai.client.Searches import com.aallam.openai.client.internal.api.EnginesApi.Companion.EnginesPath import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.http.* @@ -19,11 +20,10 @@ internal class SearchesApi(private val httpClient: HttpClient) : Searches { engineId: EngineId, request: SearchRequest ): List { - return httpClient.post( - path = "${EnginesPath}/$engineId/search", - body = request - ) { + return httpClient.post { + url(path = "${EnginesPath}/$engineId/search") contentType(ContentType.Application.Json) - }.data + setBody(request) + }.body().data } } diff --git a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/extension/Log.kt b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/extension/Log.kt index cc2db68a..3ace7840 100644 --- a/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/extension/Log.kt +++ b/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/extension/Log.kt @@ -2,9 +2,9 @@ package com.aallam.openai.client.internal.extension import com.aallam.openai.api.logging.LogLevel import com.aallam.openai.api.logging.Logger -import io.ktor.client.features.logging.* -import io.ktor.client.features.logging.LogLevel as KLogLevel -import io.ktor.client.features.logging.Logger as KLogger +import io.ktor.client.plugins.logging.* +import io.ktor.client.plugins.logging.LogLevel as KLogLevel +import io.ktor.client.plugins.logging.Logger as KLogger /** * Convert Logger to a Ktor's Logger. diff --git a/openai-client/src/commonTest/kotlin/com/aallam/openai/client/TestOpenAI.kt b/openai-client/src/commonTest/kotlin/com/aallam/openai/client/TestOpenAI.kt index 100488ca..73336297 100644 --- a/openai-client/src/commonTest/kotlin/com/aallam/openai/client/TestOpenAI.kt +++ b/openai-client/src/commonTest/kotlin/com/aallam/openai/client/TestOpenAI.kt @@ -16,11 +16,11 @@ import com.aallam.openai.api.file.FileRequest import com.aallam.openai.api.file.Processed import com.aallam.openai.api.search.SearchRequest import com.aallam.openai.client.internal.OpenAIApi -import com.aallam.openai.client.internal.runBlockingTest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.runTest import kotlinx.coroutines.withContext import okio.Path import okio.Path.Companion.toPath @@ -49,7 +49,7 @@ class TestOpenAI { @Test fun search() { - runBlockingTest { + runTest { val documents = listOf("White House", "hospital", "school") val query = "the president" val request = SearchRequest(documents, query) @@ -60,7 +60,7 @@ class TestOpenAI { @Test fun engines() { - runBlockingTest { + runTest { val response = openAI.engines() assertNotEquals(0, response.size) } @@ -68,7 +68,7 @@ class TestOpenAI { @Test fun engine() { - runBlockingTest { + runTest { val engineId = Davinci val response = openAI.engine(engineId) assertEquals(engineId, response.id) @@ -77,7 +77,7 @@ class TestOpenAI { @Test fun completion() { - runBlockingTest { + runTest { val request = CompletionRequest( prompt = "Once upon a time", maxTokens = 5, @@ -95,7 +95,7 @@ class TestOpenAI { @Test fun completions() { - runBlockingTest { + runTest { val request = CompletionRequest( prompt = "Once upon a time", maxTokens = 5, @@ -119,7 +119,7 @@ class TestOpenAI { @ExperimentalOpenAI @Test fun classifications() { - runBlockingTest { + runTest { val request = ClassificationRequest( model = Curie, query = "It is a raining day :(", @@ -139,7 +139,7 @@ class TestOpenAI { @ExperimentalOpenAI @Test fun answers() { - runBlockingTest { + runTest { val request = AnswerRequest( model = Curie, question = "which puppy is happy?", @@ -162,7 +162,7 @@ class TestOpenAI { @Test fun file() { - runBlockingTest { + runTest { val request = FileRequest( file = filePath.toString(), purpose = Answers @@ -189,7 +189,7 @@ class TestOpenAI { @Test fun files() { - runBlockingTest { + runTest { val response = openAI.files() assertNotNull(response) } diff --git a/openai-client/src/commonTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt b/openai-client/src/commonTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt deleted file mode 100644 index 547c59dd..00000000 --- a/openai-client/src/commonTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.aallam.openai.client.internal - -import kotlinx.coroutines.CoroutineScope - -expect fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) diff --git a/openai-client/src/jsTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt b/openai-client/src/jsTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt deleted file mode 100644 index 1ded66a7..00000000 --- a/openai-client/src/jsTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.aallam.openai.client.internal - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.asPromise -import kotlinx.coroutines.async - -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit): dynamic { - return GlobalScope.async(block = block).asPromise() -} diff --git a/openai-client/src/jvmTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt b/openai-client/src/jvmTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt deleted file mode 100644 index 0c80d516..00000000 --- a/openai-client/src/jvmTest/kotlin/com/aallam/openai/client/internal/Coroutine.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.aallam.openai.client.internal - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) = runBlocking { block() } diff --git a/openai-client/src/nativeMain/kotlin/com.aallam.openai.client/internal/ClientFileSystem.kt b/openai-client/src/linuxX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt similarity index 79% rename from openai-client/src/nativeMain/kotlin/com.aallam.openai.client/internal/ClientFileSystem.kt rename to openai-client/src/linuxX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt index f71eb836..fb18c478 100644 --- a/openai-client/src/nativeMain/kotlin/com.aallam.openai.client/internal/ClientFileSystem.kt +++ b/openai-client/src/linuxX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt @@ -1,6 +1,5 @@ package com.aallam.openai.client.internal -import okio.ExperimentalFileSystem import okio.FileSystem internal actual val ClientFileSystem: FileSystem = FileSystem.SYSTEM diff --git a/openai-client/src/macosArm64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt b/openai-client/src/macosArm64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt new file mode 100644 index 00000000..fb18c478 --- /dev/null +++ b/openai-client/src/macosArm64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt @@ -0,0 +1,5 @@ +package com.aallam.openai.client.internal + +import okio.FileSystem + +internal actual val ClientFileSystem: FileSystem = FileSystem.SYSTEM diff --git a/openai-client/src/macosX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt b/openai-client/src/macosX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt new file mode 100644 index 00000000..fb18c478 --- /dev/null +++ b/openai-client/src/macosX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt @@ -0,0 +1,5 @@ +package com.aallam.openai.client.internal + +import okio.FileSystem + +internal actual val ClientFileSystem: FileSystem = FileSystem.SYSTEM diff --git a/openai-client/src/mingwX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt b/openai-client/src/mingwX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt new file mode 100644 index 00000000..fb18c478 --- /dev/null +++ b/openai-client/src/mingwX64Main/kotlin/com.aallam.openai.client.internal/ClientFileSystem.kt @@ -0,0 +1,5 @@ +package com.aallam.openai.client.internal + +import okio.FileSystem + +internal actual val ClientFileSystem: FileSystem = FileSystem.SYSTEM diff --git a/openai-client/src/nativeTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt b/openai-client/src/nativeTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt deleted file mode 100644 index 0c80d516..00000000 --- a/openai-client/src/nativeTest/kotlin/com.aallam.openai.client/internal/Coroutine.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.aallam.openai.client.internal - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) = runBlocking { block() } diff --git a/openai-core/api/openai-core.api b/openai-core/api/openai-core.api index 3ab93ccc..21a03f1a 100644 --- a/openai-core/api/openai-core.api +++ b/openai-core/api/openai-core.api @@ -20,6 +20,7 @@ public final class com/aallam/openai/api/answer/Answer { public final fun getSelectedDocuments ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/answer/Answer;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/answer/Answer$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -82,6 +83,7 @@ public final class com/aallam/openai/api/answer/AnswerRequest { public final fun getTemperature ()Ljava/lang/Double; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/answer/AnswerRequest;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/answer/AnswerRequest$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -113,6 +115,7 @@ public final class com/aallam/openai/api/answer/Document { public final fun getText ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/answer/Document;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/answer/Document$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -168,6 +171,7 @@ public final class com/aallam/openai/api/classification/Classification { public final fun getSelectedExamples ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/classification/Classification;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/classification/Classification$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -222,6 +226,7 @@ public final class com/aallam/openai/api/classification/ClassificationRequest { public final fun getTemperature ()Ljava/lang/Double; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/classification/ClassificationRequest;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/classification/ClassificationRequest$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -255,6 +260,7 @@ public final class com/aallam/openai/api/classification/Example { public final fun getText ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/classification/Example;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/classification/Example$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -308,6 +314,7 @@ public final class com/aallam/openai/api/completion/Choice { public final fun getText ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/completion/Choice;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/completion/Choice$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -345,6 +352,7 @@ public final class com/aallam/openai/api/completion/CompletionRequest { public final fun getStream ()Ljava/lang/Boolean; public final fun getTemperature ()Ljava/lang/Double; public final fun getTopP ()Ljava/lang/Double; + public static final fun write$Self (Lcom/aallam/openai/api/completion/CompletionRequest;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/completion/CompletionRequest$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -380,6 +388,7 @@ public final class com/aallam/openai/api/completion/Logprobs { public final fun getTopLogprobs ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/completion/Logprobs;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/completion/Logprobs$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -415,6 +424,7 @@ public final class com/aallam/openai/api/completion/TextCompletion { public final fun getModel ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/completion/TextCompletion;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/completion/TextCompletion$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -448,6 +458,7 @@ public final class com/aallam/openai/api/engine/Engine { public final fun getReady ()Z public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/engine/Engine;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/engine/Engine$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -497,6 +508,7 @@ public final class com/aallam/openai/api/engine/EnginesResponse { public synthetic fun (ILjava/util/List;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V public fun (Ljava/util/List;)V public final fun getData ()Ljava/util/List; + public static final fun write$Self (Lcom/aallam/openai/api/engine/EnginesResponse;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/engine/EnginesResponse$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -539,6 +551,7 @@ public final class com/aallam/openai/api/file/File { public final fun getStatus-uAY0Nxo ()Ljava/lang/String; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/file/File;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/file/File$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -612,6 +625,7 @@ public final class com/aallam/openai/api/file/FileResponse { public final fun getData ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/file/FileResponse;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/file/FileResponse$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -703,6 +717,7 @@ public final class com/aallam/openai/api/search/SearchRequest { public fun (Ljava/util/List;Ljava/lang/String;)V public final fun getDocuments ()Ljava/util/List; public final fun getQuery ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/search/SearchRequest;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/search/SearchRequest$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -727,6 +742,7 @@ public final class com/aallam/openai/api/search/SearchResponse { public fun (Ljava/util/List;Ljava/lang/String;)V public final fun getData ()Ljava/util/List; public final fun getModel ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/search/SearchResponse;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/search/SearchResponse$$serializer : kotlinx/serialization/internal/GeneratedSerializer { @@ -758,6 +774,7 @@ public final class com/aallam/openai/api/search/SearchResult { public final fun getScore ()D public fun hashCode ()I public fun toString ()Ljava/lang/String; + public static final fun write$Self (Lcom/aallam/openai/api/search/SearchResult;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V } public final class com/aallam/openai/api/search/SearchResult$$serializer : kotlinx/serialization/internal/GeneratedSerializer { diff --git a/openai-core/build.gradle.kts b/openai-core/build.gradle.kts index 360ca91a..4e320ef0 100644 --- a/openai-core/build.gradle.kts +++ b/openai-core/build.gradle.kts @@ -3,36 +3,18 @@ plugins { kotlin("plugin.serialization") id("com.vanniktech.maven.publish") id("binary-compatibility-validator") + id("build-support") } kotlin { explicitApi() - jvm { - compilations.all { - kotlinOptions.jvmTarget = "1.8" - } - testRuns["test"].executionTask.configure { - useJUnit() - } - } - js(BOTH) { - nodejs() - } - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - val nativeTarget = when { - hostOs == "Mac OS X" -> macosX64("native") - hostOs == "Linux" -> linuxX64("native") - isMingwX64 -> mingwX64("native") - else -> throw GradleException("Host OS is not supported in Kotlin/Native.") - } - nativeTarget.apply { - binaries {} - } + jvm() + js { nodejs() } + native() sourceSets { all { - languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") + languageSettings.optIn("kotlin.RequiresOptIn") } val commonMain by getting { dependencies { @@ -45,19 +27,15 @@ kotlin { implementation(kotlin("test-annotations-common")) } } - val jvmMain by getting val jvmTest by getting { dependencies { implementation(kotlin("test-junit")) } } - val jsMain by getting val jsTest by getting { dependencies { implementation(kotlin("test-js")) } } - val nativeMain by getting - val nativeTest by getting } } diff --git a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/engine/Engine.kt b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/engine/Engine.kt index e7421718..dcdb157e 100644 --- a/openai-core/src/commonMain/kotlin/com.aallam.openai.api/engine/Engine.kt +++ b/openai-core/src/commonMain/kotlin/com.aallam.openai.api/engine/Engine.kt @@ -21,5 +21,5 @@ public data class Engine( /** * Whether the engine is ready to process requests or not. */ - @SerialName("ready") public val ready: Boolean + @SerialName("ready") public val ready: Boolean? ) diff --git a/settings.gradle.kts b/settings.gradle.kts index e37c588e..e9c22496 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,5 @@ rootProject.name = "OpenAI-Kotlin" -enableFeaturePreview("VERSION_CATALOGS") +includeBuild("build-support") include(":openai-core") include(":openai-client") @@ -7,3 +7,5 @@ include(":openai-client") include(":sample:jvm") include(":sample:js") include(":sample:native") + +enableFeaturePreview("VERSION_CATALOGS")