Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAI Client update #673

Merged
merged 2 commits into from Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)