diff --git a/openai-client/client/.openapi-generator/FILES b/openai-client/client/.openapi-generator/FILES index f647d69e0..1069164fa 100644 --- a/openai-client/client/.openapi-generator/FILES +++ b/openai-client/client/.openapi-generator/FILES @@ -51,37 +51,48 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/CreateAssistantFileRequ src/commonMain/kotlin/com/xebia/functional/openai/models/CreateAssistantRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestFunctionCall.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestResponseFormat.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionResponseChoicesInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionStreamResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionStreamResponseChoicesInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionResponseChoicesInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionResponseChoicesInnerLogprobs.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditResponseChoicesInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingResponseUsage.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequestHyperparameters.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequestHyperparameters.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequestModel.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageEditRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateMessageRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationResponseResultsInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationResponseResultsInnerCategories.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationResponseResultsInnerCategoryScores.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateRunRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateThreadAndRunRequest.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateThreadAndRunRequestToolsInner.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateThreadRequest.kt +src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranscriptionRequestModel.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranscriptionResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranslationResponse.kt src/commonMain/kotlin/com/xebia/functional/openai/models/DeleteAssistantFileResponse.kt diff --git a/openai-client/client/src/commonMain/kotlin/FormBuilderOps.kt b/openai-client/client/src/commonMain/kotlin/FormBuilderOps.kt index e34abb989..be45a7bdf 100644 --- a/openai-client/client/src/commonMain/kotlin/FormBuilderOps.kt +++ b/openai-client/client/src/commonMain/kotlin/FormBuilderOps.kt @@ -25,4 +25,4 @@ fun FormBuilder.appendGen(key: String, value: T, headers: Headers = He @OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class) fun > serialNameOrEnumValue(v: Enum): String = - v::class.serializerOrNull()?.descriptor?.getElementName(v.ordinal) ?: v.name + v::class.serializerOrNull()?.descriptor?.getElementName(v.ordinal) ?: v.toString() diff --git a/openai-client/client/src/commonMain/kotlin/OpenAIModel.kt b/openai-client/client/src/commonMain/kotlin/OpenAIModel.kt new file mode 100644 index 000000000..020deb344 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/OpenAIModel.kt @@ -0,0 +1,44 @@ +package ai.xef.openai + +import kotlin.jvm.JvmInline +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(with = OpenAIModelSerializer::class) +sealed interface OpenAIModel { + + fun value(): String = + when (this) { + is CustomModel -> model + is StandardModel -> model.toString() + } +} + +@Serializable @JvmInline value class CustomModel(val model: String) : OpenAIModel + +@Serializable @JvmInline value class StandardModel(val model: T) : OpenAIModel + +class OpenAIModelSerializer(private val dataSerializer: KSerializer) : + KSerializer> { + override val descriptor: SerialDescriptor = dataSerializer.descriptor + + override fun serialize(encoder: Encoder, value: OpenAIModel) = + when (value) { + is CustomModel -> String.serializer().serialize(encoder, value.model) + is StandardModel -> dataSerializer.serialize(encoder, value.model) + } + + override fun deserialize(decoder: Decoder) = + try { + StandardModel(dataSerializer.deserialize(decoder)) + } catch (e: SerializationException) { + CustomModel(String.serializer().deserialize(decoder)) + } catch (e: IllegalArgumentException) { + CustomModel(String.serializer().deserialize(decoder)) + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/AudioApi.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/AudioApi.kt index 613c49304..6ca93b273 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/AudioApi.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/AudioApi.kt @@ -8,6 +8,7 @@ package com.xebia.functional.openai.apis import com.xebia.functional.openai.infrastructure.* import com.xebia.functional.openai.models.CreateSpeechRequest +import com.xebia.functional.openai.models.CreateTranscriptionRequestModel import com.xebia.functional.openai.models.CreateTranscriptionResponse import com.xebia.functional.openai.models.CreateTranslationResponse import io.ktor.client.HttpClient @@ -104,8 +105,7 @@ open class AudioApi : ApiClient { @Suppress("UNCHECKED_CAST") open suspend fun createTranscription( file: io.ktor.client.request.forms.InputProvider, - model: - com.xebia.functional.openai.models.ext.transcription.create.CreateTranscriptionRequestModel, + model: CreateTranscriptionRequestModel, language: kotlin.String? = null, prompt: kotlin.String? = null, responseFormat: ResponseFormatCreateTranscription? = ResponseFormatCreateTranscription.json, @@ -160,8 +160,7 @@ open class AudioApi : ApiClient { @Suppress("UNCHECKED_CAST") open suspend fun createTranslation( file: io.ktor.client.request.forms.InputProvider, - model: - com.xebia.functional.openai.models.ext.transcription.create.CreateTranscriptionRequestModel, + model: CreateTranscriptionRequestModel, prompt: kotlin.String? = null, responseFormat: kotlin.String? = "json", temperature: kotlin.Double? = 0.toDouble() diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/ImagesApi.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/ImagesApi.kt index 1714f11cd..52feddd00 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/ImagesApi.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/apis/ImagesApi.kt @@ -7,6 +7,7 @@ package com.xebia.functional.openai.apis import com.xebia.functional.openai.infrastructure.* +import com.xebia.functional.openai.models.CreateImageEditRequestModel import com.xebia.functional.openai.models.CreateImageRequest import com.xebia.functional.openai.models.ImagesResponse import io.ktor.client.HttpClient @@ -109,8 +110,7 @@ open class ImagesApi : ApiClient { image: io.ktor.client.request.forms.InputProvider, prompt: kotlin.String, mask: io.ktor.client.request.forms.InputProvider? = null, - model: com.xebia.functional.openai.models.ext.image.edit.create.CreateImageEditRequestModel? = - null, + model: CreateImageEditRequestModel? = null, n: kotlin.Int? = 1, size: PropertySizeCreateImageEdit? = PropertySizeCreateImageEdit._1024x1024, responseFormat: ResponseFormatCreateImageEdit? = ResponseFormatCreateImageEdit.url, @@ -182,8 +182,7 @@ open class ImagesApi : ApiClient { @Suppress("UNCHECKED_CAST") open suspend fun createImageVariation( image: io.ktor.client.request.forms.InputProvider, - model: com.xebia.functional.openai.models.ext.image.edit.create.CreateImageEditRequestModel? = - null, + model: CreateImageEditRequestModel? = null, n: kotlin.Int? = 1, responseFormat: ResponseFormatCreateImageVariation? = ResponseFormatCreateImageVariation.url, size: PropertySizeCreateImageVariation? = PropertySizeCreateImageVariation._1024x1024, diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/infrastructure/ApiClient.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/infrastructure/ApiClient.kt index f0457a8a5..6cd882af5 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/infrastructure/ApiClient.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/infrastructure/ApiClient.kt @@ -19,7 +19,7 @@ import kotlinx.serialization.json.Json open class ApiClient(private val baseUrl: String) { - private lateinit var client: HttpClient + lateinit var client: HttpClient constructor( baseUrl: String, diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequest.kt index 0b54b2e6c..d71acf50d 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequest.kt @@ -72,7 +72,7 @@ data class CreateChatCompletionRequest( >, @SerialName(value = "model") @Required - val model: com.xebia.functional.openai.models.ext.chat.create.CreateChatCompletionRequestModel, + val model: ai.xef.openai.OpenAIModel, /* Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. [See more information about frequency and presence penalties.](/docs/guides/gpt/parameter-details) */ @SerialName(value = "frequency_penalty") val frequencyPenalty: kotlin.Double? = (0).toDouble(), diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestModel.kt new file mode 100644 index 000000000..2ed4c7b2f --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionRequestModel.kt @@ -0,0 +1,61 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * ID of the model to use. See the + * [model endpoint compatibility](/docs/models/model-endpoint-compatibility) table for details on + * which models work with the Chat API. + * + * Values: + * gptMinus4Minus1106MinusPreview,gptMinus4MinusVisionMinusPreview,gptMinus4,gptMinus4Minus0314,gptMinus4Minus0613,gptMinus4Minus32k,gptMinus4Minus32kMinus0314,gptMinus4Minus32kMinus0613,gptMinus3Period5MinusTurbo,gptMinus3Period5MinusTurboMinus16k,gptMinus3Period5MinusTurboMinus0301,gptMinus3Period5MinusTurboMinus0613,gptMinus3Period5MinusTurboMinus16kMinus0613 + */ +@Serializable +enum class CreateChatCompletionRequestModel(val value: kotlin.String) { + + @SerialName(value = "gpt-4-1106-preview") gptMinus4Minus1106MinusPreview("gpt-4-1106-preview"), + @SerialName(value = "gpt-4-vision-preview") + gptMinus4MinusVisionMinusPreview("gpt-4-vision-preview"), + @SerialName(value = "gpt-4") gptMinus4("gpt-4"), + @SerialName(value = "gpt-4-0314") gptMinus4Minus0314("gpt-4-0314"), + @SerialName(value = "gpt-4-0613") gptMinus4Minus0613("gpt-4-0613"), + @SerialName(value = "gpt-4-32k") gptMinus4Minus32k("gpt-4-32k"), + @SerialName(value = "gpt-4-32k-0314") gptMinus4Minus32kMinus0314("gpt-4-32k-0314"), + @SerialName(value = "gpt-4-32k-0613") gptMinus4Minus32kMinus0613("gpt-4-32k-0613"), + @SerialName(value = "gpt-3.5-turbo") gptMinus3Period5MinusTurbo("gpt-3.5-turbo"), + @SerialName(value = "gpt-3.5-turbo-16k") gptMinus3Period5MinusTurboMinus16k("gpt-3.5-turbo-16k"), + @SerialName(value = "gpt-3.5-turbo-0301") + gptMinus3Period5MinusTurboMinus0301("gpt-3.5-turbo-0301"), + @SerialName(value = "gpt-3.5-turbo-0613") + gptMinus3Period5MinusTurboMinus0613("gpt-3.5-turbo-0613"), + @SerialName(value = "gpt-3.5-turbo-16k-0613") + gptMinus3Period5MinusTurboMinus16kMinus0613("gpt-3.5-turbo-16k-0613"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateChatCompletionRequestModel) "$data" else null + + /** Returns a valid [CreateChatCompletionRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateChatCompletionRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequest.kt index b05f6d7bc..b946b1e49 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequest.kt @@ -72,7 +72,7 @@ import kotlinx.serialization.encoding.* data class CreateCompletionRequest( @SerialName(value = "model") @Required - val model: com.xebia.functional.openai.models.ext.completion.create.CreateCompletionRequestModel, + val model: ai.xef.openai.OpenAIModel, @SerialName(value = "prompt") @Required val prompt: diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequestModel.kt new file mode 100644 index 000000000..0c9480190 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateCompletionRequestModel.kt @@ -0,0 +1,55 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see + * all of your available models, or see our [Model overview](/docs/models/overview) for descriptions + * of them. + * + * Values: + * babbageMinus002,davinciMinus002,gptMinus3Period5MinusTurboMinusInstruct,textMinusDavinciMinus003,textMinusDavinciMinus002,textMinusDavinciMinus001,codeMinusDavinciMinus002,textMinusCurieMinus001,textMinusBabbageMinus001,textMinusAdaMinus001 + */ +@Serializable +enum class CreateCompletionRequestModel(val value: kotlin.String) { + + @SerialName(value = "babbage-002") babbageMinus002("babbage-002"), + @SerialName(value = "davinci-002") davinciMinus002("davinci-002"), + @SerialName(value = "gpt-3.5-turbo-instruct") + gptMinus3Period5MinusTurboMinusInstruct("gpt-3.5-turbo-instruct"), + @SerialName(value = "text-davinci-003") textMinusDavinciMinus003("text-davinci-003"), + @SerialName(value = "text-davinci-002") textMinusDavinciMinus002("text-davinci-002"), + @SerialName(value = "text-davinci-001") textMinusDavinciMinus001("text-davinci-001"), + @SerialName(value = "code-davinci-002") codeMinusDavinciMinus002("code-davinci-002"), + @SerialName(value = "text-curie-001") textMinusCurieMinus001("text-curie-001"), + @SerialName(value = "text-babbage-001") textMinusBabbageMinus001("text-babbage-001"), + @SerialName(value = "text-ada-001") textMinusAdaMinus001("text-ada-001"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateCompletionRequestModel) "$data" else null + + /** Returns a valid [CreateCompletionRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateCompletionRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequest.kt index 1b881360f..636ac43df 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequest.kt @@ -30,7 +30,7 @@ data class CreateEditRequest( @SerialName(value = "instruction") @Required val instruction: kotlin.String, @SerialName(value = "model") @Required - val model: com.xebia.functional.openai.models.ext.edit.create.CreateEditRequestModel, + val model: ai.xef.openai.OpenAIModel, /* The input text to use as a starting point for the edit. */ @SerialName(value = "input") val input: kotlin.String? = "", diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequestModel.kt new file mode 100644 index 000000000..d43b0f081 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEditRequestModel.kt @@ -0,0 +1,46 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * ID of the model to use. You can use the `text-davinci-edit-001` or `code-davinci-edit-001` model + * with this endpoint. + * + * Values: textMinusDavinciMinusEditMinus001,codeMinusDavinciMinusEditMinus001 + */ +@Serializable +enum class CreateEditRequestModel(val value: kotlin.String) { + + @SerialName(value = "text-davinci-edit-001") + textMinusDavinciMinusEditMinus001("text-davinci-edit-001"), + @SerialName(value = "code-davinci-edit-001") + codeMinusDavinciMinusEditMinus001("code-davinci-edit-001"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateEditRequestModel) "$data" else null + + /** Returns a valid [CreateEditRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateEditRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequest.kt index e790cadf3..a4163496a 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequest.kt @@ -25,7 +25,7 @@ data class CreateEmbeddingRequest( val input: com.xebia.functional.openai.models.ext.embedding.create.CreateEmbeddingRequestInput, @SerialName(value = "model") @Required - val model: com.xebia.functional.openai.models.ext.embedding.create.CreateEmbeddingRequestModel, + val model: ai.xef.openai.OpenAIModel, /* The format to return the embeddings in. Can be either `float` or [`base64`](https://pypi.org/project/pybase64/). */ @SerialName(value = "encoding_format") diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequestModel.kt new file mode 100644 index 000000000..92d58bcd6 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateEmbeddingRequestModel.kt @@ -0,0 +1,45 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * ID of the model to use. You can use the [List models](/docs/api-reference/models/list) API to see + * all of your available models, or see our [Model overview](/docs/models/overview) for descriptions + * of them. + * + * Values: textMinusEmbeddingMinusAdaMinus002 + */ +@Serializable +enum class CreateEmbeddingRequestModel(val value: kotlin.String) { + + @SerialName(value = "text-embedding-ada-002") + textMinusEmbeddingMinusAdaMinus002("text-embedding-ada-002"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateEmbeddingRequestModel) "$data" else null + + /** Returns a valid [CreateEmbeddingRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateEmbeddingRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequest.kt index df864cf48..797e01161 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequest.kt @@ -89,8 +89,7 @@ data class CreateFineTuneRequest( /* The learning rate multiplier to use for training. The fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value. By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final `batch_size` (larger learning rates tend to perform better with larger batch sizes). We recommend experimenting with values in the range 0.02 to 0.2 to see what produces the best results. */ @SerialName(value = "learning_rate_multiplier") val learningRateMultiplier: kotlin.Double? = null, @SerialName(value = "model") - val model: com.xebia.functional.openai.models.ext.finetune.create.CreateFineTuneRequestModel? = - null, + val model: ai.xef.openai.OpenAIModel? = null, /* The weight to use for loss on the prompt tokens. This controls how much the model tries to learn to generate the prompt (as compared to the completion which always has a weight of 1.0), and can add a stabilizing effect to training when completions are short. If prompts are extremely long (relative to completions), it may make sense to reduce this weight so as to avoid over-prioritizing learning the prompt. */ @SerialName(value = "prompt_loss_weight") diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequestModel.kt new file mode 100644 index 000000000..419859c3d --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuneRequestModel.kt @@ -0,0 +1,47 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * The name of the base model to fine-tune. You can select one of \"ada\", \"babbage\", \"curie\", + * \"davinci\", or a fine-tuned model created after 2022-04-21 and before 2023-08-22. To learn more + * about these models, see the [Models](/docs/models) documentation. + * + * Values: ada,babbage,curie,davinci + */ +@Serializable +enum class CreateFineTuneRequestModel(val value: kotlin.String) { + + @SerialName(value = "ada") ada("ada"), + @SerialName(value = "babbage") babbage("babbage"), + @SerialName(value = "curie") curie("curie"), + @SerialName(value = "davinci") davinci("davinci"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateFineTuneRequestModel) "$data" else null + + /** Returns a valid [CreateFineTuneRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateFineTuneRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequest.kt index 61d19d472..76ec9a84f 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequest.kt @@ -31,8 +31,7 @@ import kotlinx.serialization.encoding.* data class CreateFineTuningJobRequest( @SerialName(value = "model") @Required - val model: - com.xebia.functional.openai.models.ext.finetune.job.create.CreateFineTuningJobRequestModel, + val model: ai.xef.openai.OpenAIModel, /* The ID of an uploaded file that contains training data. See [upload file](/docs/api-reference/files/upload) for how to upload a file. Your dataset must be formatted as a JSONL file. Additionally, you must upload your file with the purpose `fine-tune`. See the [fine-tuning guide](/docs/guides/fine-tuning) for more details. */ @SerialName(value = "training_file") @Required val trainingFile: kotlin.String, diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequestModel.kt new file mode 100644 index 000000000..6323edac0 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateFineTuningJobRequestModel.kt @@ -0,0 +1,45 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * The name of the model to fine-tune. You can select one of the + * [supported models](/docs/guides/fine-tuning/what-models-can-be-fine-tuned). + * + * Values: babbageMinus002,davinciMinus002,gptMinus3Period5MinusTurbo + */ +@Serializable +enum class CreateFineTuningJobRequestModel(val value: kotlin.String) { + + @SerialName(value = "babbage-002") babbageMinus002("babbage-002"), + @SerialName(value = "davinci-002") davinciMinus002("davinci-002"), + @SerialName(value = "gpt-3.5-turbo") gptMinus3Period5MinusTurbo("gpt-3.5-turbo"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateFineTuningJobRequestModel) "$data" else null + + /** Returns a valid [CreateFineTuningJobRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateFineTuningJobRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageEditRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageEditRequestModel.kt new file mode 100644 index 000000000..ceb2473a9 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageEditRequestModel.kt @@ -0,0 +1,42 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * The model to use for image generation. Only `dall-e-2` is supported at this time. + * + * Values: dallMinusEMinus2 + */ +@Serializable +enum class CreateImageEditRequestModel(val value: kotlin.String) { + + @SerialName(value = "dall-e-2") dallMinusEMinus2("dall-e-2"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateImageEditRequestModel) "$data" else null + + /** Returns a valid [CreateImageEditRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateImageEditRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequest.kt index 9bcc62e8f..6d33fdc82 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequest.kt @@ -36,7 +36,7 @@ data class CreateImageRequest( /* A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2` and 4000 characters for `dall-e-3`. */ @SerialName(value = "prompt") @Required val prompt: kotlin.String, @SerialName(value = "model") - val model: com.xebia.functional.openai.models.ext.image.create.CreateImageRequestModel? = null, + val model: ai.xef.openai.OpenAIModel? = null, /* The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. */ @SerialName(value = "n") val n: kotlin.Int? = 1, diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequestModel.kt new file mode 100644 index 000000000..47ad7d638 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateImageRequestModel.kt @@ -0,0 +1,43 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * The model to use for image generation. + * + * Values: dallMinusEMinus2,dallMinusEMinus3 + */ +@Serializable +enum class CreateImageRequestModel(val value: kotlin.String) { + + @SerialName(value = "dall-e-2") dallMinusEMinus2("dall-e-2"), + @SerialName(value = "dall-e-3") dallMinusEMinus3("dall-e-3"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateImageRequestModel) "$data" else null + + /** Returns a valid [CreateImageRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateImageRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequest.kt index ec7f1d6a6..00cfa6105 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequest.kt @@ -20,7 +20,5 @@ data class CreateModerationRequest( @Required val input: com.xebia.functional.openai.models.ext.moderation.create.CreateModerationRequestInput, @SerialName(value = "model") - val model: - com.xebia.functional.openai.models.ext.moderation.create.CreateModerationRequestModel? = - null + val model: ai.xef.openai.OpenAIModel? = null ) diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequestModel.kt new file mode 100644 index 000000000..1159eb749 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateModerationRequestModel.kt @@ -0,0 +1,49 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * Two content moderations models are available: `text-moderation-stable` and + * `text-moderation-latest`. The default is `text-moderation-latest` which will be automatically + * upgraded over time. This ensures you are always using our most accurate model. If you use + * `text-moderation-stable`, we will provide advanced notice before updating the model. Accuracy of + * `text-moderation-stable` may be slightly lower than for `text-moderation-latest`. + * + * Values: textMinusModerationMinusLatest,textMinusModerationMinusStable + */ +@Serializable +enum class CreateModerationRequestModel(val value: kotlin.String) { + + @SerialName(value = "text-moderation-latest") + textMinusModerationMinusLatest("text-moderation-latest"), + @SerialName(value = "text-moderation-stable") + textMinusModerationMinusStable("text-moderation-stable"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateModerationRequestModel) "$data" else null + + /** Returns a valid [CreateModerationRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateModerationRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequest.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequest.kt index 429ea710f..30954a9ac 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequest.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequest.kt @@ -24,7 +24,7 @@ import kotlinx.serialization.encoding.* data class CreateSpeechRequest( @SerialName(value = "model") @Required - val model: com.xebia.functional.openai.models.ext.speech.create.CreateSpeechRequestModel, + val model: ai.xef.openai.OpenAIModel, /* The text to generate audio for. The maximum length is 4096 characters. */ @SerialName(value = "input") @Required val input: kotlin.String, diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequestModel.kt new file mode 100644 index 000000000..eb7e23995 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateSpeechRequestModel.kt @@ -0,0 +1,43 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * One of the available [TTS models](/docs/models/tts): `tts-1` or `tts-1-hd` + * + * Values: ttsMinus1,ttsMinus1MinusHd + */ +@Serializable +enum class CreateSpeechRequestModel(val value: kotlin.String) { + + @SerialName(value = "tts-1") ttsMinus1("tts-1"), + @SerialName(value = "tts-1-hd") ttsMinus1MinusHd("tts-1-hd"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateSpeechRequestModel) "$data" else null + + /** Returns a valid [CreateSpeechRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateSpeechRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranscriptionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranscriptionRequestModel.kt new file mode 100644 index 000000000..0cf845032 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/CreateTranscriptionRequestModel.kt @@ -0,0 +1,42 @@ +/** + * Please note: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * Do not edit this file manually. + */ +@file:Suppress("ArrayInDataClass", "EnumEntryName", "RemoveRedundantQualifierName", "UnusedImport") + +package com.xebia.functional.openai.models + +import kotlinx.serialization.* + +/** + * ID of the model to use. Only `whisper-1` is currently available. + * + * Values: whisperMinus1 + */ +@Serializable +enum class CreateTranscriptionRequestModel(val value: kotlin.String) { + + @SerialName(value = "whisper-1") whisperMinus1("whisper-1"); + + /** + * Override [toString()] to avoid using the enum variable name as the value, and instead use the + * actual value defined in the API spec file. + * + * This solves a problem when the variable name and its value are different, and ensures that the + * client sends the correct enum values to the server always. + */ + override fun toString(): kotlin.String = value + + companion object { + /** Converts the provided [data] to a [String] on success, null otherwise. */ + fun encode(data: kotlin.Any?): kotlin.String? = + if (data is CreateTranscriptionRequestModel) "$data" else null + + /** Returns a valid [CreateTranscriptionRequestModel] for [data], null otherwise. */ + fun decode(data: kotlin.Any?): CreateTranscriptionRequestModel? = + data?.let { + val normalizedData = "$it".lowercase() + values().firstOrNull { value -> it == value || normalizedData == "$value".lowercase() } + } + } +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/MessageContentTextObjectTextAnnotationsInner.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/MessageContentTextObjectTextAnnotationsInner.kt index 2f16c688a..b093652de 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/MessageContentTextObjectTextAnnotationsInner.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/MessageContentTextObjectTextAnnotationsInner.kt @@ -39,11 +39,11 @@ data class MessageContentTextObjectTextAnnotationsInner( /** * Always `file_citation`. * - * Values: citation,path + * Values: fileCitation,filePath */ @Serializable enum class Type(val value: kotlin.String) { - @SerialName(value = "file_citation") citation("file_citation"), - @SerialName(value = "file_path") path("file_path") + @SerialName(value = "file_citation") fileCitation("file_citation"), + @SerialName(value = "file_path") filePath("file_path") } } diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/ChatCompletionRequestMessage.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/ChatCompletionRequestMessage.kt index 99d4ddef7..ac599e0c5 100644 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/ChatCompletionRequestMessage.kt +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/ChatCompletionRequestMessage.kt @@ -10,6 +10,34 @@ import kotlinx.serialization.Serializable @Serializable sealed interface ChatCompletionRequestMessage { + fun contentAsString(): String? = + when (this) { + is ChatCompletionRequestAssistantMessage -> content + is ChatCompletionRequestFunctionMessage -> content + is ChatCompletionRequestSystemMessage -> content + is ChatCompletionRequestToolMessage -> content + is ChatCompletionRequestUserMessage -> + when (content) { + is ChatCompletionRequestUserMessageContent.ChatCompletionRequestUserMessageContentImageArray -> + // TODO - Image array to String? + null + is ChatCompletionRequestUserMessageContent.ChatCompletionRequestUserMessageContentTextArray -> + // TODO - String array to String? + null + is ChatCompletionRequestUserMessageContent.TextContent -> content.s + null -> null + } + } + + fun completionRole(): ChatCompletionRole = + when (this) { + is ChatCompletionRequestAssistantMessage -> role.asRole + is ChatCompletionRequestFunctionMessage -> role.asRole + is ChatCompletionRequestSystemMessage -> role.asRole + is ChatCompletionRequestToolMessage -> role.asRole + is ChatCompletionRequestUserMessage -> role.asRole + } + /** * @param content The contents of the system message. * @param role The role of the messages author, in this case `system`. @@ -21,7 +49,7 @@ sealed interface ChatCompletionRequestMessage { @SerialName(value = "content") @Required val content: String?, /* The role of the messages author, in this case `system`. */ - @SerialName(value = "role") @Required val role: ChatCompletionRequestSystemMessage.Role + @SerialName(value = "role") @Required val role: Role = Role.system ) : ChatCompletionRequestMessage { /** @@ -46,7 +74,7 @@ sealed interface ChatCompletionRequestMessage { @SerialName(value = "content") @Required val content: ChatCompletionRequestUserMessageContent?, /* The role of the messages author, in this case `user`. */ - @SerialName(value = "role") @Required val role: ChatCompletionRequestUserMessage.Role + @SerialName(value = "role") @Required val role: Role = Role.user ) : ChatCompletionRequestMessage { /** @@ -75,14 +103,14 @@ sealed interface ChatCompletionRequestMessage { @SerialName(value = "content") @Required val content: String?, /* The role of the messages author, in this case `assistant`. */ - @SerialName(value = "role") @Required val role: ChatCompletionRequestAssistantMessage.Role, + @SerialName(value = "role") @Required val role: Role = Role.assistant, /* The tool calls generated by the model, such as function calls. */ @SerialName(value = "tool_calls") val toolCalls: List? = null, @Deprecated(message = "This property is deprecated.") @SerialName(value = "function_call") val functionCall: ChatCompletionRequestAssistantMessageFunctionCall? = null - ) { + ) : ChatCompletionRequestMessage { /** * The role of the messages author, in this case `assistant`. @@ -105,15 +133,15 @@ sealed interface ChatCompletionRequestMessage { @Serializable data class ChatCompletionRequestToolMessage( - /* The role of the messages author, in this case `tool`. */ - @SerialName(value = "role") @Required val role: ChatCompletionRequestToolMessage.Role, - /* The contents of the tool message. */ @SerialName(value = "content") @Required val content: String?, /* Tool call that this message is responding to. */ - @SerialName(value = "tool_call_id") @Required val toolCallId: String - ) { + @SerialName(value = "tool_call_id") @Required val toolCallId: String, + + /* The role of the messages author, in this case `tool`. */ + @SerialName(value = "role") @Required val role: Role = Role.tool + ) : ChatCompletionRequestMessage { /** * The role of the messages author, in this case `tool`. @@ -137,15 +165,15 @@ sealed interface ChatCompletionRequestMessage { @Deprecated(message = "This schema is deprecated.") data class ChatCompletionRequestFunctionMessage( - /* The role of the messages author, in this case `function`. */ - @SerialName(value = "role") @Required val role: ChatCompletionRequestFunctionMessage.Role, - /* The return value from the function call, to return to the model. */ @SerialName(value = "content") @Required val content: String?, /* The name of the function to call. */ - @SerialName(value = "name") @Required val name: String - ) { + @SerialName(value = "name") @Required val name: String, + + /* The role of the messages author, in this case `function`. */ + @SerialName(value = "role") @Required val role: Role = Role.function + ) : ChatCompletionRequestMessage { /** * The role of the messages author, in this case `function`. diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/create/CreateChatCompletionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/create/CreateChatCompletionRequestModel.kt deleted file mode 100644 index 7dbc523f4..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/create/CreateChatCompletionRequestModel.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.xebia.functional.openai.models.ext.chat.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateChatCompletionRequestModel(val value: String) { - @SerialName(value = "gpt-4") `gpt_4`("gpt-4"), - @SerialName(value = "gpt-4-0314") `gpt_4_0314`("gpt-4-0314"), - @SerialName(value = "gpt-4-0613") `gpt_4_0613`("gpt-4-0613"), - @SerialName(value = "gpt-4-32k") `gpt_4_32k`("gpt-4-32k"), - @SerialName(value = "gpt-4-32k-0314") `gpt_4_32k_0314`("gpt-4-32k-0314"), - @SerialName(value = "gpt-4-32k-0613") `gpt_4_32k_0613`("gpt-4-32k-0613"), - @SerialName(value = "gpt-3.5-turbo") `gpt_3_5_turbo`("gpt-3.5-turbo"), - @SerialName(value = "gpt-3.5-turbo-16k") `gpt_3_5_turbo_16k`("gpt-3.5-turbo-16k"), - @SerialName(value = "gpt-3.5-turbo-0301") `gpt_3_5_turbo_0301`("gpt-3.5-turbo-0301"), - @SerialName(value = "gpt-3.5-turbo-0613") `gpt_3_5_turbo_0613`("gpt-3.5-turbo-0613"), - @SerialName(value = "gpt-3.5-turbo-16k-0613") `gpt_3_5_turbo_16k_0613`("gpt-3.5-turbo-16k-0613") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/stream/ChatCompletionsStream.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/stream/ChatCompletionsStream.kt new file mode 100644 index 000000000..0b76212c9 --- /dev/null +++ b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/chat/stream/ChatCompletionsStream.kt @@ -0,0 +1,73 @@ +package com.xebia.functional.openai.models.ext.chat.stream + +import com.xebia.functional.openai.apis.ChatApi +import com.xebia.functional.openai.models.CreateChatCompletionRequest +import com.xebia.functional.openai.models.CreateChatCompletionStreamResponse +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.flow +import kotlinx.serialization.json.* + +fun ChatApi.createChatCompletionStream( + request: CreateChatCompletionRequest +): Flow { + val builder = + HttpRequestBuilder().apply { + method = HttpMethod.Post + url(path = "/chat/completions") + setBody(streamingRequestAsJson(request)) + contentType(ContentType.Application.Json) + accept(ContentType.Text.EventStream) + headers { + append(HttpHeaders.CacheControl, "no-cache") + append(HttpHeaders.Connection, "keep-alive") + } + } + return flow { client.execute(builder) { response -> emitDataEvents(response) } } +} + +private val json = Json { + isLenient = true + ignoreUnknownKeys = true +} + +private const val PREFIX = "data:" +private const val END = "$PREFIX [DONE]" + +private suspend inline fun FlowCollector.emitDataEvents(response: HttpResponse) { + val channel: ByteReadChannel = response.body() + while (!channel.isClosedForRead) { + val line = channel.readUTF8Line() ?: continue + val value: T = + when { + line.startsWith(END) -> break + line.startsWith(PREFIX) -> json.decodeFromString(line.removePrefix(PREFIX)) + else -> continue + } + emit(value) + } +} + +private suspend fun HttpClient.execute( + builder: HttpRequestBuilder, + block: suspend (response: HttpResponse) -> T +) { + try { + HttpStatement(builder = builder, client = this).execute(block) + } catch (e: Exception) { + throw e // TODO handle exception + } +} + +private inline fun streamingRequestAsJson(serializable: T): JsonElement { + val enableStream = "stream" to JsonPrimitive(true) + val json = json.encodeToJsonElement(serializable) + val map = json.jsonObject.toMutableMap().also { it += enableStream } + return JsonObject(map) +} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/completion/create/CreateCompletionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/completion/create/CreateCompletionRequestModel.kt deleted file mode 100644 index 1a5b09e76..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/completion/create/CreateCompletionRequestModel.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.xebia.functional.openai.models.ext.completion.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateCompletionRequestModel(val value: String) { - @SerialName(value = "babbage-002") `babbage_002`("babbage-002"), - @SerialName(value = "davinci-002") `davinci_002`("davinci-002"), - @SerialName(value = "gpt-3.5-turbo-instruct") `gpt_3_5_turbo_instruct`("gpt-3.5-turbo-instruct"), - @SerialName(value = "text-davinci-003") `text_davinci_003`("text-davinci-003"), - @SerialName(value = "text-davinci-002") `text_davinci_002`("text-davinci-002"), - @SerialName(value = "text-davinci-001") `text_davinci_001`("text-davinci-001"), - @SerialName(value = "code-davinci-002") `code_davinci_002`("code-davinci-002"), - @SerialName(value = "text-curie-001") `text_curie_001`("text-curie-001"), - @SerialName(value = "text-babbage-001") `text_babbage_001`("text-babbage-001"), - @SerialName(value = "text-ada-001") `text_ada_001`("text-ada-001") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/edit/create/CreateEditRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/edit/create/CreateEditRequestModel.kt deleted file mode 100644 index cf269cb58..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/edit/create/CreateEditRequestModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.openai.models.ext.edit.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateEditRequestModel(val value: String) { - @SerialName(value = "text-davinci-edit-001") `text_davinci_edit_001`("text-davinci-edit-001"), - @SerialName(value = "code-davinci-edit-001") `code_davinci_edit_001`("code-davinci-edit-001") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/embedding/create/CreateEmbeddingRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/embedding/create/CreateEmbeddingRequestModel.kt deleted file mode 100644 index 3643630e6..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/embedding/create/CreateEmbeddingRequestModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.xebia.functional.openai.models.ext.embedding.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateEmbeddingRequestModel(val value: String) { - @SerialName(value = "text-embedding-ada-002") `text_embedding_ada_002`("text-embedding-ada-002") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/create/CreateFineTuneRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/create/CreateFineTuneRequestModel.kt deleted file mode 100644 index 34f44bd72..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/create/CreateFineTuneRequestModel.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.xebia.functional.openai.models.ext.finetune.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateFineTuneRequestModel(val value: String) { - @SerialName(value = "ada") ada("ada"), - @SerialName(value = "babbage") babbage("babbage"), - @SerialName(value = "curie") curie("curie"), - @SerialName(value = "davinci") davinci("davinci") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/job/create/CreateFineTuningJobRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/job/create/CreateFineTuningJobRequestModel.kt deleted file mode 100644 index fe7c6f705..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/finetune/job/create/CreateFineTuningJobRequestModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.xebia.functional.openai.models.ext.finetune.job.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateFineTuningJobRequestModel(val value: String) { - @SerialName(value = "babbage-002") `babbage_002`("babbage-002"), - @SerialName(value = "davinci-002") `davinci_002`("davinci-002"), - @SerialName(value = "gpt-3.5-turbo") `gpt_3_5_turbo`("gpt-3.5-turbo") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/create/CreateImageRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/create/CreateImageRequestModel.kt deleted file mode 100644 index a1c8500f2..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/create/CreateImageRequestModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.openai.models.ext.image.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateImageRequestModel(val value: String) { - @SerialName(value = "dall-e-2") `dall_e_2`("dall-e-2"), - @SerialName(value = "dall-e-3") `dall_e_3`("dall-e-3") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/edit/create/CreateImageEditRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/edit/create/CreateImageEditRequestModel.kt deleted file mode 100644 index fbaa42a58..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/image/edit/create/CreateImageEditRequestModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.xebia.functional.openai.models.ext.image.edit.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateImageEditRequestModel(val value: String) { - @SerialName(value = "dall-e-2") `dall_e_2`("dall-e-2") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/moderation/create/CreateModerationRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/moderation/create/CreateModerationRequestModel.kt deleted file mode 100644 index cfcaf98c5..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/moderation/create/CreateModerationRequestModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.openai.models.ext.moderation.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateModerationRequestModel(val value: String) { - @SerialName(value = "text-moderation-latest") `text_moderation_latest`("text-moderation-latest"), - @SerialName(value = "text-moderation-stable") `text_moderation_stable`("text-moderation-stable") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/speech/create/CreateSpeechRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/speech/create/CreateSpeechRequestModel.kt deleted file mode 100644 index 575f5b55b..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/speech/create/CreateSpeechRequestModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.openai.models.ext.speech.create - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateSpeechRequestModel(val value: String) { - @SerialName(value = "tts-1") `tts_1`("tts-1"), - @SerialName(value = "tts-1-hd") `tts_1_hd`("tts-1-hd") -} diff --git a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/transcription/create/CreateTranscriptionRequestModel.kt b/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/transcription/create/CreateTranscriptionRequestModel.kt deleted file mode 100644 index 305e63e03..000000000 --- a/openai-client/client/src/commonMain/kotlin/com/xebia/functional/openai/models/ext/transcription/create/CreateTranscriptionRequestModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.xebia.functional.openai.models.ext.transcription.create - -import io.ktor.utils.io.charsets.* -import io.ktor.utils.io.core.* -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -enum class CreateTranscriptionRequestModel(val value: String) { - @SerialName(value = "whisper-1") `whisper_1`("whisper-1"); - - fun asByteArray(): ByteArray = this.value.toByteArray(Charsets.UTF_8) -} diff --git a/openai-client/generator/build.gradle.kts b/openai-client/generator/build.gradle.kts index e5b07caa1..68e0782da 100644 --- a/openai-client/generator/build.gradle.kts +++ b/openai-client/generator/build.gradle.kts @@ -35,4 +35,4 @@ task("openaiClientGenerate", JavaExec::class) { "config/openai-config.json", ) classpath = sourceSets["main"].runtimeClasspath -} \ No newline at end of file +}.finalizedBy(":xef-openai-client:spotlessApply") \ No newline at end of file diff --git a/openai-client/generator/config/libraries/multiplatform/infrastructure/ApiClient.kt.mustache b/openai-client/generator/config/libraries/multiplatform/infrastructure/ApiClient.kt.mustache new file mode 100644 index 000000000..4b89dd1c9 --- /dev/null +++ b/openai-client/generator/config/libraries/multiplatform/infrastructure/ApiClient.kt.mustache @@ -0,0 +1,194 @@ +package {{packageName}}.infrastructure + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.request.* +import io.ktor.client.request.forms.FormDataContent +import io.ktor.client.request.forms.MultiPartFormDataContent +import io.ktor.client.request.header +import io.ktor.client.request.parameter +import io.ktor.client.statement.HttpResponse +import io.ktor.serialization.kotlinx.json.json +import io.ktor.http.* +import io.ktor.http.content.PartData +import kotlin.Unit +import kotlinx.serialization.json.Json + +import {{packageName}}.auth.* + +{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient( + private val baseUrl: String +) { + + lateinit var client: HttpClient + + constructor( + baseUrl: String, + httpClientEngine: HttpClientEngine?, + httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null, + jsonBlock: Json, + ) : this(baseUrl = baseUrl) { + val clientConfig: (HttpClientConfig<*>) -> Unit by lazy { + { + it.install(ContentNegotiation) { json(jsonBlock) } + httpClientConfig?.invoke(it) + } + } + + client = httpClientEngine?.let { HttpClient(it, clientConfig) } ?: HttpClient(clientConfig) + } + + constructor( + baseUrl: String, + httpClient: HttpClient + ): this(baseUrl = baseUrl) { + this.client = httpClient + } + + {{#hasAuthMethods}} + private val authentications: kotlin.collections.Map by lazy { + mapOf({{#authMethods}}{{#isBasic}}{{#isBasicBasic}} + "{{name}}" to HttpBasicAuth(){{/isBasicBasic}}{{#isBasicBearer}} + "{{name}}" to HttpBearerAuth("{{scheme}}"){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}} + "{{name}}" to ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"){{/isApiKey}}{{#isOAuth}} + "{{name}}" to OAuth(){{/isOAuth}}{{^-last}}, {{/-last}}{{/authMethods}}) + } + {{/hasAuthMethods}} + {{^hasAuthMethods}} + private val authentications: kotlin.collections.Map? = null + {{/hasAuthMethods}} + + {{#nonPublicApi}}internal {{/nonPublicApi}}companion object { + const val BASE_URL = "{{{basePath}}}" + val JSON_DEFAULT = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } + protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType) + } + + /** + * Set the username for the first HTTP basic authentication. + * + * @param username Username + */ + fun setUsername(username: String) { + val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + ?: throw Exception("No HTTP basic authentication configured") + auth.username = username + } + + /** + * Set the password for the first HTTP basic authentication. + * + * @param password Password + */ + fun setPassword(password: String) { + val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth? + ?: throw Exception("No HTTP basic authentication configured") + auth.password = password + } + + /** + * Set the API key value for the first API key authentication. + * + * @param apiKey API key + * @param paramName The name of the API key parameter, or null or set the first key. + */ + fun setApiKey(apiKey: String, paramName: String? = null) { + val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth? + ?: throw Exception("No API key authentication configured") + auth.apiKey = apiKey + } + + /** + * Set the API key prefix for the first API key authentication. + * + * @param apiKeyPrefix API key prefix + * @param paramName The name of the API key parameter, or null or set the first key. + */ + fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) { + val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth? + ?: throw Exception("No API key authentication configured") + auth.apiKeyPrefix = apiKeyPrefix + } + + /** + * Set the access token for the first OAuth2 authentication. + * + * @param accessToken Access token + */ + fun setAccessToken(accessToken: String) { + val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth? + ?: throw Exception("No OAuth2 authentication configured") + auth.accessToken = accessToken + } + + /** + * Set the access token for the first Bearer authentication. + * + * @param bearerToken The bearer token. + */ + fun setBearerToken(bearerToken: String) { + val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth? + ?: throw Exception("No Bearer authentication configured") + auth.bearerToken = bearerToken + } + + protected suspend fun multipartFormRequest(requestConfig: RequestConfig, body: kotlin.collections.List?, authNames: kotlin.collections.List): HttpResponse { + return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames) + } + + protected suspend fun urlEncodedFormRequest(requestConfig: RequestConfig, body: Parameters?, authNames: kotlin.collections.List): HttpResponse { + return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames) + } + + protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse = request(requestConfig, body, authNames) + + protected suspend fun request(requestConfig: RequestConfig, body: Any? = null, authNames: kotlin.collections.List): HttpResponse { + requestConfig.updateForAuth(authNames) + val headers = requestConfig.headers + + return client.request { + this.url { + this.takeFrom(URLBuilder(baseUrl)) + appendPath(requestConfig.path.trimStart('/').split('/')) + requestConfig.query.forEach { query -> + query.value.forEach { value -> + parameter(query.key, value) + } + } + } + this.method = requestConfig.method.httpMethod + headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) } + if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) { + this.setBody(body) + } + } + } + + private fun RequestConfig.updateForAuth(authNames: kotlin.collections.List) { + for (authName in authNames) { + val auth = authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName") + auth.apply(query, headers) + } + } + + private fun URLBuilder.appendPath(components: kotlin.collections.List): URLBuilder = apply { + encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() } + } + + private val RequestMethod.httpMethod: HttpMethod + get() = when (this) { + RequestMethod.DELETE -> HttpMethod.Delete + RequestMethod.GET -> HttpMethod.Get + RequestMethod.HEAD -> HttpMethod.Head + RequestMethod.PATCH -> HttpMethod.Patch + RequestMethod.PUT -> HttpMethod.Put + RequestMethod.POST -> HttpMethod.Post + RequestMethod.OPTIONS -> HttpMethod.Options + } +} diff --git a/openai-client/generator/config/openai-config.json b/openai-client/generator/config/openai-config.json index ae7caa6a2..7dc5e5b7d 100644 --- a/openai-client/generator/config/openai-config.json +++ b/openai-client/generator/config/openai-config.json @@ -3,32 +3,22 @@ "library": "multiplatform", "groupId": "com.xebia.functional", "artifactId": "openai-client", - "packageName": "com.xebia.functional.openai" + "packageName": "com.xebia.functional.openai", + "removeEnumValuePrefix": false }, "schemaMappings": { "FunctionParameters": "kotlinx.serialization.json.JsonObject", "ChatCompletionRequestMessage": "com.xebia.functional.openai.models.ext.chat.ChatCompletionRequestMessage", "ChatCompletionRequestUserMessage_content": "com.xebia.functional.openai.models.ext.chat.ChatCompletionRequestUserMessageContent", - "CreateChatCompletionRequest_model": "com.xebia.functional.openai.models.ext.chat.create.CreateChatCompletionRequestModel", "CreateChatCompletionRequest_stop": "com.xebia.functional.openai.models.ext.chat.create.CreateChatCompletionRequestStop", - "CreateCompletionRequest_model": "com.xebia.functional.openai.models.ext.completion.create.CreateCompletionRequestModel", "CreateCompletionRequest_prompt": "com.xebia.functional.openai.models.ext.completion.create.CreateCompletionRequestPrompt", "CreateCompletionRequest_stop": "com.xebia.functional.openai.models.ext.completion.create.CreateCompletionRequestStop", - "CreateEditRequest_model": "com.xebia.functional.openai.models.ext.edit.create.CreateEditRequestModel", "CreateEmbeddingRequest_input": "com.xebia.functional.openai.models.ext.embedding.create.CreateEmbeddingRequestInput", - "CreateEmbeddingRequest_model": "com.xebia.functional.openai.models.ext.embedding.create.CreateEmbeddingRequestModel", - "CreateFineTuneRequest_model": "com.xebia.functional.openai.models.ext.finetune.create.CreateFineTuneRequestModel", "CreateFineTuneRequest_hyperparameters_n_epochs": "com.xebia.functional.openai.models.ext.finetune.create.CreateFineTuneRequestHyperparametersNEpochs", "CreateFineTuningJobRequest_hyperparameters_batch_size": "com.xebia.functional.openai.models.ext.finetune.job.create.CreateFineTuningJobRequestHyperparametersBatchSize", "CreateFineTuningJobRequest_hyperparameters_learning_rate_multiplier": "com.xebia.functional.openai.models.ext.finetune.job.create.CreateFineTuningJobRequestHyperparametersLearningRateMultiplier", "CreateFineTuningJobRequest_hyperparameters_n_epochs": "com.xebia.functional.openai.models.ext.finetune.job.create.CreateFineTuningJobRequestHyperparametersNEpochs", - "CreateFineTuningJobRequest_model": "com.xebia.functional.openai.models.ext.finetune.job.create.CreateFineTuningJobRequestModel", - "CreateImageEditRequest_model": "com.xebia.functional.openai.models.ext.image.edit.create.CreateImageEditRequestModel", - "CreateImageRequest_model": "com.xebia.functional.openai.models.ext.image.create.CreateImageRequestModel", "CreateModerationRequest_input": "com.xebia.functional.openai.models.ext.moderation.create.CreateModerationRequestInput", - "CreateModerationRequest_model": "com.xebia.functional.openai.models.ext.moderation.create.CreateModerationRequestModel", - "CreateSpeechRequest_model": "com.xebia.functional.openai.models.ext.speech.create.CreateSpeechRequestModel", - "CreateTranscriptionRequest_model": "com.xebia.functional.openai.models.ext.transcription.create.CreateTranscriptionRequestModel", "FineTuningJobRequest_hyperparameters_n_epochs": "com.xebia.functional.openai.models.ext.finetune.job.FineTuningJobRequestHyperparametersNEpochs", "FineTuningJob_hyperparameters_n_epochs": "com.xebia.functional.openai.models.ext.finetune.job.FineTuningJobHyperparametersNEpochs" }, @@ -37,6 +27,11 @@ "api.mustache": { "templateType": "API", "destinationFilename": ".kt" + }, + "infrastructure/ApiClient.kt.mustache": { + "folder": "src/commonMain/kotlin/com/xebia/functional/openai/infrastructure", + "destinationFilename": "ApiClient.kt", + "templateType": "SupportingFiles" } } } diff --git a/openai-client/generator/src/main/java/ai/xef/openai/generator/KMMGeneratorConfig.java b/openai-client/generator/src/main/java/ai/xef/openai/generator/KMMGeneratorConfig.java index bf45999ac..684e028a8 100644 --- a/openai-client/generator/src/main/java/ai/xef/openai/generator/KMMGeneratorConfig.java +++ b/openai-client/generator/src/main/java/ai/xef/openai/generator/KMMGeneratorConfig.java @@ -1,6 +1,14 @@ package ai.xef.openai.generator; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; import org.openapitools.codegen.languages.KotlinClientCodegen; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; + +import java.util.HashSet; +import java.util.List; +import java.util.Optional; public class KMMGeneratorConfig extends KotlinClientCodegen { @@ -8,6 +16,47 @@ public KMMGeneratorConfig() { super(); } + private Optional readEnumModel(List all) { + if (all.size() == 2) { + CodegenProperty first = all.get(0); + CodegenProperty second = all.get(1); + if (first.isString && second.isEnum) { + return Optional.of(second); + } + } + return Optional.empty(); + } + + @Override + public ModelsMap postProcessModels(ModelsMap objs) { + for (ModelMap mo : objs.getModels()) { + CodegenModel cm = mo.getModel(); + if (cm.anyOf != null && !cm.anyOf.isEmpty()) { + Optional codegenProperty = readEnumModel(cm.getComposedSchemas().getAnyOf()); + codegenProperty.ifPresent((enumProp) -> { + cm.modelJson = enumProp.jsonSchema; + cm.interfaces = null; + cm.anyOf = new HashSet<>(); + cm.dataType = enumProp.dataType; + cm.isString = enumProp.isString; + cm.allowableValues = enumProp.allowableValues; + cm.isEnum = enumProp.isEnum; + cm.setIsAnyType(enumProp.isAnyType); + cm.setComposedSchemas(null); + }); + } else if (cm.name.endsWith("Request")) { + cm + .allVars + .stream() + .filter(p -> p.name.equalsIgnoreCase("model")) + .findFirst() + .filter(p -> !p.dataType.equals("kotlin.String")) + .ifPresent(p -> p.dataType = String.format("ai.xef.openai.OpenAIModel<%s>", p.dataType)); + } + } + return super.postProcessModels(objs); + } + @Override public String toEnumVarName(String value, String datatype) { String varName;