Skip to content

Commit

Permalink
OpenAI Client update (#673)
Browse files Browse the repository at this point in the history
* OpenAI Client Update

* Fixes array of enums

---------

Co-authored-by: Fede Fernández <720923+fedefernandez@users.noreply.github.com>
  • Loading branch information
javipacheco and fedefernandez committed Mar 5, 2024
1 parent b80a4f5 commit e42d443
Show file tree
Hide file tree
Showing 38 changed files with 444 additions and 165 deletions.
Expand Up @@ -29,7 +29,7 @@ fun chatFunctions(descriptors: List<SerialDescriptor>): List<FunctionObject> =
descriptors.map(::chatFunction)

fun chatFunction(fnName: String, schema: JsonObject): FunctionObject =
FunctionObject(fnName, schema, "Generated function for $fnName")
FunctionObject(fnName, "Generated function for $fnName", schema)

@AiDsl
suspend fun <A> ChatApi.prompt(
Expand Down
Expand Up @@ -61,65 +61,72 @@ sealed class StreamedFunction<out A> {
val schema = function.parameters
// we create an example from the schema from which we can expect and infer the paths
// as the LLM is sending us chunks with malformed JSON
val example = createExampleFromSchema(schema)
chat
.createChatCompletionStream(request)
.onCompletion {
val newMessages = prompt.messages + messages
newMessages.addToMemory(
scope,
prompt.configuration.messagePolicy.addMessagesToConversation
)
}
.collect { responseChunk ->
// Each chunk is emitted from the LLM and it will include a delta.parameters with
// the function is streaming, the JSON received will be partial and usually malformed
// and needs to be inspected and clean up to stream properties before
// the final result is ready
if (schema != null) {
val example = createExampleFromSchema(schema)
chat
.createChatCompletionStream(request)
.onCompletion {
val newMessages = prompt.messages + messages
newMessages.addToMemory(
scope,
prompt.configuration.messagePolicy.addMessagesToConversation
)
}
.collect { responseChunk ->
// Each chunk is emitted from the LLM and it will include a delta.parameters with
// the function is streaming, the JSON received will be partial and usually malformed
// and needs to be inspected and clean up to stream properties before
// the final result is ready

// every response chunk contains a list of choices
if (responseChunk.choices.isNotEmpty()) {
// the delta contains the last emission while emitting the json character by character
val delta = responseChunk.choices.first().delta
// at any point the delta may be the last one
val finishReason = responseChunk.choices.first().finishReason
val toolCalls = delta.toolCalls.orEmpty()
toolCalls.forEach { toolCall ->
val fn = toolCall.function
val functionName = fn?.name
val arguments = fn?.arguments.orEmpty()
if (functionName != null)
// update the function name with the latest one
functionCall = functionCall.copy(name = functionName)
if (arguments.isNotEmpty()) {
// update the function arguments with the latest ones
functionCall = mergeArgumentsWithDelta(functionCall, toolCall)
// once we have info about the args we detect the last property referenced
// while streaming the arguments for the function call
val currentArg = getLastReferencedPropertyInArguments(functionCall)
if (currentProperty != currentArg && currentArg != null) {
// if the current property is different than the last one
// we update the path
// a change of property happens and we try to stream it
// every response chunk contains a list of choices
if (responseChunk.choices.isNotEmpty()) {
// the delta contains the last emission while emitting the json character by character
val delta = responseChunk.choices.first().delta
// at any point the delta may be the last one
val finishReason = responseChunk.choices.first().finishReason
val toolCalls = delta.toolCalls.orEmpty()
toolCalls.forEach { toolCall ->
val fn = toolCall.function
val functionName = fn?.name
val arguments = fn?.arguments.orEmpty()
if (functionName != null)
// update the function name with the latest one
functionCall = functionCall.copy(name = functionName)
if (arguments.isNotEmpty()) {
// update the function arguments with the latest ones
functionCall = mergeArgumentsWithDelta(functionCall, toolCall)
// once we have info about the args we detect the last property referenced
// while streaming the arguments for the function call
val currentArg = getLastReferencedPropertyInArguments(functionCall)
if (currentProperty != currentArg && currentArg != null) {
// if the current property is different than the last one
// we update the path
// a change of property happens and we try to stream it
streamProperty(
path,
currentProperty,
functionCall.arguments,
streamedProperties
)
path = findPropertyPath(example, currentArg) ?: listOf(currentArg)
}
// update the current property being evaluated
currentProperty = currentArg
}
if (finishReason != null) {
// the stream is finished and we try to stream the last property
// because the previous chunk may had a partial property whose body
// may had not been fully streamed
streamProperty(path, currentProperty, functionCall.arguments, streamedProperties)
path = findPropertyPath(example, currentArg) ?: listOf(currentArg)
}
// update the current property being evaluated
currentProperty = currentArg
}
if (finishReason != null) {
// the stream is finished and we try to stream the last property
// because the previous chunk may had a partial property whose body
// may had not been fully streamed
streamProperty(path, currentProperty, functionCall.arguments, streamedProperties)
// we stream the result
streamResult(functionCall, messages, serializer)
}
}
if (finishReason != null) {
// we stream the result
streamResult(functionCall, messages, serializer)
}
}
}
}
}

private suspend fun <A> FlowCollector<StreamedFunction<A>>.streamResult(
Expand Down
Expand Up @@ -117,7 +117,8 @@ class AssistantThread(
instructions = "",
tools = emptyList(),
fileIds = emptyList(),
metadata = null
metadata = null,
usage = null
)
)
)
Expand Down
Expand Up @@ -47,7 +47,8 @@ class TestChatApi(
)
),
finishReason = CreateChatCompletionResponseChoicesInner.FinishReason.stop,
index = 0
index = 0,
logprobs = null
)
),
usage = CompletionUsage(0, 0, 0)
Expand Down
20 changes: 5 additions & 15 deletions openai-client/client/.openapi-generator/FILES
@@ -1,12 +1,9 @@
src/commonMain/kotlin/com/xebia/functional/openai/apis/AssistantApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/AssistantsApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/AudioApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/ChatApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/CompletionsApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/EditsApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/EmbeddingsApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/FilesApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/FineTunesApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/FineTuningApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/ImagesApi.kt
src/commonMain/kotlin/com/xebia/functional/openai/apis/ModelsApi.kt
Expand Down Expand Up @@ -40,6 +37,8 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionResponseM
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionRole.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionStreamResponseDelta.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionStreamResponseDeltaFunctionCall.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionTokenLogprob.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionTokenLogprobTopLogprobsInner.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ChatCompletionTool.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/CompletionUsage.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/CreateAssistantFileRequest.kt
Expand All @@ -50,24 +49,18 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/CreateChatCompletionReq
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/CreateChatCompletionResponseChoicesInnerLogprobs.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
Expand Down Expand Up @@ -99,9 +92,6 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/DeleteThreadResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/Embedding.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/Error.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ErrorResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTune.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTuneEvent.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTuneHyperparams.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTuningJob.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTuningJobError.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/FineTuningJobEvent.kt
Expand All @@ -112,8 +102,6 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/ImagesResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListAssistantFilesResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListAssistantsResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListFilesResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListFineTuneEventsResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListFineTunesResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListFineTuningJobEventsResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListMessageFilesResponse.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ListMessagesResponse.kt
Expand All @@ -140,10 +128,12 @@ src/commonMain/kotlin/com/xebia/functional/openai/models/ModifyMessageRequest.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ModifyRunRequest.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/ModifyThreadRequest.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/OpenAIFile.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunCompletionUsage.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunObject.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunObjectLastError.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunObjectRequiredAction.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunObjectRequiredActionSubmitToolOutputs.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunStepCompletionUsage.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunStepDetailsMessageCreationObjectMessageCreation.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunStepDetailsToolCallsCodeObject.kt
src/commonMain/kotlin/com/xebia/functional/openai/models/RunStepDetailsToolCallsCodeObjectCodeInterpreter.kt
Expand Down
Expand Up @@ -26,6 +26,7 @@ import com.xebia.functional.openai.models.ListRunStepsResponse
import com.xebia.functional.openai.models.ListRunsResponse
import com.xebia.functional.openai.models.MessageFileObject
import com.xebia.functional.openai.models.MessageObject
import com.xebia.functional.openai.models.ModifyAssistantRequest
import com.xebia.functional.openai.models.ModifyMessageRequest
import com.xebia.functional.openai.models.ModifyRunRequest
import com.xebia.functional.openai.models.ModifyThreadRequest
Expand Down Expand Up @@ -957,6 +958,38 @@ open class AssistantsApi : ApiClient {
return request(localVariableConfig, localVariableBody, localVariableAuthNames).wrap()
}

/**
* Modifies an assistant.
*
* @param assistantId The ID of the assistant to modify.
* @param modifyAssistantRequest
* @return AssistantObject
*/
@Suppress("UNCHECKED_CAST")
open suspend fun modifyAssistant(
assistantId: kotlin.String,
modifyAssistantRequest: ModifyAssistantRequest
): HttpResponse<AssistantObject> {

val localVariableAuthNames = listOf<String>("ApiKeyAuth")

val localVariableBody = modifyAssistantRequest

val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()

val localVariableConfig =
RequestConfig<kotlin.Any?>(
RequestMethod.POST,
"/assistants/{assistant_id}".replace("{" + "assistant_id" + "}", "$assistantId"),
query = localVariableQuery,
headers = localVariableHeaders,
requiresAuthentication = true,
)

return jsonRequest(localVariableConfig, localVariableBody, localVariableAuthNames).wrap()
}

/**
* Modifies a message.
*
Expand Down
Expand Up @@ -80,6 +80,14 @@ open class AudioApi : ApiClient {
@SerialName(value = "vtt") vtt("vtt")
}

/** enum for parameter timestampGranularities */
@Serializable
enum class TimestampGranularitiesCreateTranscription(val value: kotlin.String) {

@SerialName(value = "word") word("word"),
@SerialName(value = "segment") segment("segment")
}

/**
* Transcribes audio into the input language.
*
Expand All @@ -100,6 +108,10 @@ open class AudioApi : ApiClient {
* deterministic. If set to 0, the model will use
* [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase
* the temperature until certain thresholds are hit. (optional, default to 0)
* @param timestampGranularities The timestamp granularities to populate for this transcription.
* Any of these options: &#x60;word&#x60;, or &#x60;segment&#x60;. Note: There is no additional
* latency for segment timestamps, but generating word timestamps incurs additional latency.
* (optional, default to segment)
* @return CreateTranscriptionResponse
*/
@Suppress("UNCHECKED_CAST")
Expand All @@ -109,7 +121,9 @@ open class AudioApi : ApiClient {
language: kotlin.String? = null,
prompt: kotlin.String? = null,
responseFormat: ResponseFormatCreateTranscription? = ResponseFormatCreateTranscription.json,
temperature: kotlin.Double? = 0.toDouble()
temperature: kotlin.Double? = 0.toDouble(),
timestampGranularities: kotlin.collections.List<TimestampGranularitiesCreateTranscription>? =
TimestampGranularitiesCreateTranscription.segment.asListOfOne()
): HttpResponse<CreateTranscriptionResponse> {

val localVariableAuthNames = listOf<String>("ApiKeyAuth")
Expand All @@ -121,6 +135,7 @@ open class AudioApi : ApiClient {
prompt?.apply { appendGen("prompt", prompt) }
responseFormat?.apply { appendGen("response_format", responseFormat) }
temperature?.apply { appendGen("temperature", temperature) }
timestampGranularities?.onEach { appendGen("timestamp_granularities[][]", it) }
}

val localVariableQuery = mutableMapOf<String, List<String>>()
Expand Down
Expand Up @@ -47,11 +47,12 @@ open class FilesApi : ApiClient {
}

/**
* Upload a file that can be used across various endpoints/features. The size of all the files
* uploaded by one organization can be up to 100 GB. The size of individual files for can be a
* maximum of 512MB. See the [Assistants Tools guide](/docs/assistants/tools) to learn more about
* the types of files supported. The Fine-tuning API only supports &#x60;.jsonl&#x60; files.
* Please [contact us](https://help.openai.com/) if you need to increase these storage limits.
* Upload a file that can be used across various endpoints. The size of all the files uploaded by
* one organization can be up to 100 GB. The size of individual files can be a maximum of 512 MB
* or 2 million tokens for Assistants. See the [Assistants Tools guide](/docs/assistants/tools) to
* learn more about the types of files supported. The Fine-tuning API only supports
* &#x60;.jsonl&#x60; files. Please [contact us](https://help.openai.com/) if you need to increase
* these storage limits.
*
* @param file The File object (not file name) to be uploaded.
* @param purpose The intended purpose of the uploaded file. Use \\\&quot;fine-tune\\\&quot; for
Expand Down
Expand Up @@ -70,9 +70,9 @@ open class FineTuningApi : ApiClient {
}

/**
* Creates a job that fine-tunes a specified model from a given dataset. Response includes details
* of the enqueued job including job status and the name of the fine-tuned models once complete.
* [Learn more about fine-tuning](/docs/guides/fine-tuning)
* Creates a fine-tuning job which begins the process of creating a new model from a given
* dataset. Response includes details of the enqueued job including job status and the name of the
* fine-tuned models once complete. [Learn more about fine-tuning](/docs/guides/fine-tuning)
*
* @param createFineTuningJobRequest
* @return FineTuningJob
Expand Down
@@ -0,0 +1,3 @@
package com.xebia.functional.openai.infrastructure

fun <A> A.asListOfOne(): List<A> = listOf(this)

0 comments on commit e42d443

Please sign in to comment.