Skip to content

Commit 7e14398

Browse files
committed
use required=true for json properties to fail fast
1 parent eaec578 commit 7e14398

30 files changed

+195
-93
lines changed

examples/src/main/kotlin/files/Files.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package files
22

33
import com.cjcrafter.openai.files.FilePurpose
4-
import com.cjcrafter.openai.files.ListFilesRequest
5-
import com.cjcrafter.openai.files.fileUploadRequest
4+
import com.cjcrafter.openai.files.uploadFileRequest
65
import com.cjcrafter.openai.files.listFilesRequest
76
import com.cjcrafter.openai.openAI
87
import io.github.cdimascio.dotenv.dotenv
98
import java.io.File
10-
import java.util.Scanner
119

1210
// To use dotenv, you need to add the "io.github.cdimascio:dotenv-kotlin:version"
1311
// dependency. Then you can add a .env file in your project directory.
@@ -44,7 +42,7 @@ fun uploadFile() {
4442
print("Enter the file name: ")
4543
val fileName = readln()
4644
val input = File(fileName)
47-
val request = fileUploadRequest {
45+
val request = uploadFileRequest {
4846
file(input)
4947
purpose(FilePurpose.ASSISTANTS)
5048
}

src/main/kotlin/com/cjcrafter/openai/OpenAI.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ interface OpenAI {
138138
* @return The OpenAI file object created
139139
*/
140140
@ApiStatus.Experimental
141-
fun uploadFile(request: FileUploadRequest): FileObject
141+
fun uploadFile(request: UploadFileRequest): FileObject
142142

143143
@ApiStatus.Experimental
144144
fun deleteFile(fileId: String): FileDeletionStatus

src/main/kotlin/com/cjcrafter/openai/OpenAIImpl.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ import okhttp3.*
1313
import okhttp3.HttpUrl.Companion.toHttpUrl
1414
import okhttp3.MediaType.Companion.toMediaType
1515
import okhttp3.RequestBody.Companion.toRequestBody
16-
import org.intellij.lang.annotations.Language
1716
import org.jetbrains.annotations.ApiStatus
1817
import java.io.BufferedReader
19-
import java.io.File
2018
import java.io.IOException
2119

2220
open class OpenAIImpl @ApiStatus.Internal constructor(
@@ -188,7 +186,7 @@ open class OpenAIImpl @ApiStatus.Internal constructor(
188186
return executeRequest(httpRequest, ListFilesResponse::class.java)
189187
}
190188

191-
override fun uploadFile(request: FileUploadRequest): FileObject {
189+
override fun uploadFile(request: UploadFileRequest): FileObject {
192190
val httpRequest = buildMultipartRequest(FILES_ENDPOINT) {
193191
addFormDataPart("purpose", OpenAI.createObjectMapper().writeValueAsString(request.purpose).trim('"'))
194192
addFormDataPart("file", request.fileName, request.requestBody)

src/main/kotlin/com/cjcrafter/openai/chat/ChatChoice.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
2121
* @see FinishReason
2222
*/
2323
data class ChatChoice(
24-
val index: Int,
25-
val message: ChatMessage,
26-
@JsonProperty("finish_reason") val finishReason: FinishReason
24+
@JsonProperty(required = true) val index: Int,
25+
@JsonProperty(required = true) val message: ChatMessage,
26+
@JsonProperty("finish_reason", required = true) val finishReason: FinishReason
2727
)

src/main/kotlin/com/cjcrafter/openai/chat/ChatChoiceChunk.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ import java.lang.IllegalArgumentException
2929
* @since 1.2.0
3030
*/
3131
data class ChatChoiceChunk(
32-
val index: Int,
33-
var delta: ChatMessageDelta? = null,
34-
@JsonProperty("finish_reason") var finishReason: FinishReason?
32+
@JsonProperty(required = true) val index: Int,
33+
@JsonProperty(required = true) var delta: ChatMessageDelta? = null,
34+
@JsonProperty("finish_reason", required = true) var finishReason: FinishReason?
3535
) {
3636
val message: ChatMessage = ChatMessage(delta?.role!!, delta?.content, delta?.toolCalls?.map { it.toToolCall() })
3737

src/main/kotlin/com/cjcrafter/openai/chat/ChatResponse.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cjcrafter.openai.chat
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
34
import java.time.Instant
45
import java.time.ZoneId
56
import java.time.ZonedDateTime
@@ -17,10 +18,10 @@ import java.util.*
1718
* @constructor Create Chat response (for internal usage).
1819
*/
1920
data class ChatResponse(
20-
val id: String,
21-
val created: Long,
22-
val choices: List<ChatChoice>,
23-
val usage: ChatUsage
21+
@JsonProperty(required = true) val id: String,
22+
@JsonProperty(required = true) val created: Long,
23+
@JsonProperty(required = true) val choices: List<ChatChoice>,
24+
@JsonProperty(required = true) val usage: ChatUsage
2425
) {
2526

2627
/**

src/main/kotlin/com/cjcrafter/openai/chat/ChatResponseChunk.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cjcrafter.openai.chat
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
34
import com.fasterxml.jackson.databind.JsonNode
45
import com.fasterxml.jackson.databind.node.ArrayNode
56
import com.fasterxml.jackson.databind.node.ObjectNode
@@ -25,9 +26,9 @@ import java.util.*
2526
* @since 1.2.0
2627
*/
2728
data class ChatResponseChunk(
28-
val id: String,
29-
val created: Long,
30-
val choices: List<ChatChoiceChunk>,
29+
@JsonProperty(required = true) val id: String,
30+
@JsonProperty(required = true) val created: Long,
31+
@JsonProperty(required = true) val choices: List<ChatChoiceChunk>,
3132
) {
3233
internal fun update(json: ObjectNode) {
3334
val choicesArray = json.get("choices") as? ArrayNode

src/main/kotlin/com/cjcrafter/openai/chat/ChatUsage.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
1616
* @see <a href="https://platform.openai.com/docs/guides/chat/managing-tokens">Managing Tokens Guide</a>
1717
*/
1818
data class ChatUsage(
19-
@JsonProperty("prompt_tokens") val promptTokens: Int,
20-
@JsonProperty("completion_tokens") val completionTokens: Int,
21-
@JsonProperty("total_tokens") val totalTokens: Int
19+
@JsonProperty("prompt_tokens", required = true) val promptTokens: Int,
20+
@JsonProperty("completion_tokens", required = true) val completionTokens: Int,
21+
@JsonProperty("total_tokens", required = true) val totalTokens: Int
2222
)

src/main/kotlin/com/cjcrafter/openai/completions/CompletionChoice.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import com.fasterxml.jackson.annotation.JsonProperty
2121
* @see FinishReason
2222
*/
2323
data class CompletionChoice(
24-
val text: String,
25-
val index: Int,
26-
val logprobs: List<Float>?,
27-
@JsonProperty("finish_reason") val finishReason: FinishReason
24+
@JsonProperty(required = true) val text: String,
25+
@JsonProperty(required = true) val index: Int,
26+
@JsonProperty(required = true) val logprobs: List<Float>?,
27+
@JsonProperty("finish_reason", required = true) val finishReason: FinishReason
2828
)

src/main/kotlin/com/cjcrafter/openai/completions/CompletionChoiceChunk.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import com.fasterxml.jackson.annotation.JsonProperty
2121
* @see FinishReason
2222
*/
2323
data class CompletionChoiceChunk(
24-
val text: String,
25-
val index: Int,
26-
val logprobs: List<Float>?,
27-
@JsonProperty("finish_reason") val finishReason: FinishReason?
24+
@JsonProperty(required = true) val text: String,
25+
@JsonProperty(required = true) val index: Int,
26+
@JsonProperty(required = true) val logprobs: List<Float>?,
27+
@JsonProperty("finish_reason", required = true) val finishReason: FinishReason?
2828
) {
2929
/**
3030
* Returns `true` if this message chunk is complete. Once complete, no more

src/main/kotlin/com/cjcrafter/openai/completions/CompletionResponse.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cjcrafter.openai.completions
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
34
import java.time.Instant
45
import java.time.ZoneId
56
import java.time.ZonedDateTime
@@ -18,11 +19,11 @@ import java.util.*
1819
* @constructor Create Completion response (for internal usage)
1920
*/
2021
data class CompletionResponse(
21-
val id: String,
22-
val created: Long,
23-
val model: String,
24-
val choices: List<CompletionChoice>,
25-
val usage: CompletionUsage
22+
@JsonProperty(required = true) val id: String,
23+
@JsonProperty(required = true) val created: Long,
24+
@JsonProperty(required = true) val model: String,
25+
@JsonProperty(required = true) val choices: List<CompletionChoice>,
26+
@JsonProperty(required = true) val usage: CompletionUsage
2627
) {
2728

2829
/**

src/main/kotlin/com/cjcrafter/openai/completions/CompletionResponseChunk.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.cjcrafter.openai.completions
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
34
import java.time.Instant
45
import java.time.ZoneId
56
import java.time.ZonedDateTime
@@ -17,10 +18,10 @@ import java.util.*
1718
* @constructor Create Completion response (for internal usage)
1819
*/
1920
data class CompletionResponseChunk(
20-
val id: String,
21-
val created: Long,
22-
val model: String,
23-
val choices: List<CompletionChoiceChunk>,
21+
@JsonProperty(required = true) val id: String,
22+
@JsonProperty(required = true) val created: Long,
23+
@JsonProperty(required = true) val model: String,
24+
@JsonProperty(required = true) val choices: List<CompletionChoiceChunk>,
2425
) {
2526

2627
/**

src/main/kotlin/com/cjcrafter/openai/completions/CompletionUsage.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
1515
* @param totalTokens How many tokens in total.
1616
*/
1717
data class CompletionUsage(
18-
@JsonProperty("prompt_tokens") val promptTokens: Int,
19-
@JsonProperty("completion_tokens") val completionTokens: Int,
20-
@JsonProperty("total_tokens") val totalTokens: Int
18+
@JsonProperty("prompt_tokens", required = true) val promptTokens: Int,
19+
@JsonProperty("completion_tokens", required = true) val completionTokens: Int,
20+
@JsonProperty("total_tokens", required = true) val totalTokens: Int
2121
)

src/main/kotlin/com/cjcrafter/openai/embeddings/Embedding.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package com.cjcrafter.openai.embeddings
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
35
/**
46
* Represents 1 embedding as a vector of floats or strings.
57
*
68
* @property embedding The embedding as a list of floats or strings
79
* @property index The index of the embedding in the list of embeddings
810
*/
911
data class Embedding(
10-
val embedding: List<Any>,
11-
val index: Int,
12+
@JsonProperty(required = true) val embedding: List<Any>,
13+
@JsonProperty(required = true) val index: Int,
1214
) {
1315
/**
1416
* Returns the embedding as a list of floats. Make sure to use [EncodingFormat.FLOAT].

src/main/kotlin/com/cjcrafter/openai/embeddings/EmbeddingsResponse.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.cjcrafter.openai.embeddings
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
35
/**
46
* The API response from the [EmbeddingsRequest].
57
*
@@ -8,9 +10,9 @@ package com.cjcrafter.openai.embeddings
810
* @property usage How many tokens were used by the API request
911
*/
1012
data class EmbeddingsResponse(
11-
val data: List<Embedding>,
12-
val model: String,
13-
val usage: EmbeddingsUsage,
13+
@JsonProperty(required = true) val data: List<Embedding>,
14+
@JsonProperty(required = true) val model: String,
15+
@JsonProperty(required = true) val usage: EmbeddingsUsage,
1416
) {
1517
/**
1618
* Returns the [data] at the given [index].

src/main/kotlin/com/cjcrafter/openai/embeddings/EmbeddingsUsage.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ import com.fasterxml.jackson.annotation.JsonProperty
1010
* @property totalTokens The total number of tokens used
1111
*/
1212
data class EmbeddingsUsage(
13-
@JsonProperty("prompt_tokens") val promptTokens: Int,
14-
@JsonProperty("total_tokens") val totalTokens: Int,
13+
@JsonProperty("prompt_tokens", required = true) val promptTokens: Int,
14+
@JsonProperty("total_tokens", required = true) val totalTokens: Int,
1515
)
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.cjcrafter.openai.files
22

3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
35
/**
46
* The returned result after attempting to delete a file.
57
*
68
* @property id The unique id of the file
79
* @property deleted Whether the file was deleted
810
*/
911
data class FileDeletionStatus(
10-
val id: String,
11-
val deleted: Boolean,
12+
@JsonProperty(required = true) val id: String,
13+
@JsonProperty(required = true) val deleted: Boolean,
1214
)

src/main/kotlin/com/cjcrafter/openai/files/FileObject.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import java.util.*
1717
* @constructor Create empty File object
1818
*/
1919
data class FileObject(
20-
val id: String,
21-
val bytes: Int,
22-
@JsonProperty("created_at") val createdAt: Int,
23-
@JsonProperty("filename") val fileName: String,
24-
val purpose: FilePurpose,
20+
@JsonProperty(required = true) val id: String,
21+
@JsonProperty(required = true) val bytes: Int,
22+
@JsonProperty("created_at", required = true) val createdAt: Int,
23+
@JsonProperty("filename", required = true) val fileName: String,
24+
@JsonProperty(required = true) val purpose: FilePurpose,
2525
) {
2626

2727
/**

src/main/kotlin/com/cjcrafter/openai/files/FilePurpose.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ import com.fasterxml.jackson.annotation.JsonProperty
88
enum class FilePurpose {
99

1010
/**
11-
* A file used to create/validate a fine-tuned model.
11+
* A file used to create/validate a fine-tuned model. When uploading a file
12+
* for this purpose, the uploaded file must be a `.jsonl` (JSON list) file,
13+
* where each line of the file is a separate training example. No other file
14+
* types are accepted.
1215
*/
1316
@JsonProperty("fine-tune")
1417
FINE_TUNE,
1518

1619
/**
17-
* Files resulting from a fine-tuning task.
20+
* Files resulting from a fine-tuning task. This is used internally by OpenAI,
21+
* If you try to upload a file with this purpose, you will get an error.
1822
*/
1923
@JsonProperty("fine-tune-results")
2024
FINE_TUNE_RESULTS,
@@ -26,7 +30,8 @@ enum class FilePurpose {
2630
ASSISTANTS,
2731

2832
/**
29-
* A file output from an assistant.
33+
* A file output from an assistant. This is used internally by OpenAI, if
34+
* you try to upload a file with this purpose, you will get an error.
3035
*/
3136
@JsonProperty("assistants_output")
3237
ASSISTANTS_OUTPUT

src/main/kotlin/com/cjcrafter/openai/files/FileUploadRequestDsl.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/main/kotlin/com/cjcrafter/openai/files/ListFilesResponse.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ import com.fasterxml.jackson.annotation.JsonProperty
99
* @property data The list of files.
1010
*/
1111
data class ListFilesResponse(
12-
@JsonProperty("has_more") val hasMore: Boolean,
13-
val data: List<FileObject>,
14-
)//: List<FileObject> by data
12+
@JsonProperty("has_more", required = true) val hasMore: Boolean,
13+
@JsonProperty(required = true) val data: List<FileObject>,
14+
)

src/main/kotlin/com/cjcrafter/openai/files/FileUploadRequest.kt renamed to src/main/kotlin/com/cjcrafter/openai/files/UploadFileRequest.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import okhttp3.RequestBody.Companion.asRequestBody
55
import okhttp3.RequestBody.Companion.toRequestBody
66
import java.io.InputStream
77

8-
data class FileUploadRequest internal constructor(
8+
data class UploadFileRequest internal constructor(
99
var fileName: String,
1010
var requestBody: RequestBody,
1111
var purpose: FilePurpose,
@@ -21,7 +21,8 @@ data class FileUploadRequest internal constructor(
2121
fun purpose(purpose: FilePurpose) = apply { this.purpose = purpose }
2222

2323
/**
24-
* Uploads a java.io.File as a file.
24+
* Uploads a java.io.File as a file. Note that the specific [FilePurpose]
25+
* can only have specific file types.
2526
*
2627
* @param file The file to upload
2728
*/
@@ -64,19 +65,19 @@ data class FileUploadRequest internal constructor(
6465
requestBody = string.toRequestBody()
6566
}
6667

67-
fun build(): FileUploadRequest {
68-
return FileUploadRequest(
68+
fun build(): UploadFileRequest {
69+
return UploadFileRequest(
6970
fileName = fileName ?: throw IllegalStateException("fileName must be defined to use FileUploadRequest"),
70-
requestBody = requestBody!!,
71-
purpose = purpose!!
71+
requestBody = requestBody ?: throw IllegalStateException("requestBody must be defined to use FileUploadRequest"),
72+
purpose = purpose ?: throw IllegalStateException("purpose must be defined to use FileUploadRequest")
7273
)
7374
}
7475
}
7576

7677
companion object {
7778

7879
/**
79-
* Creates a [FileUploadRequest.Builder] to build a [FileUploadRequest].
80+
* Creates a [UploadFileRequest.Builder] to build a [UploadFileRequest].
8081
*/
8182
@JvmStatic
8283
fun builder() = Builder()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.cjcrafter.openai.files
2+
3+
fun uploadFileRequest(block: UploadFileRequest.Builder.() -> Unit) = UploadFileRequest.builder().apply(block).build()

0 commit comments

Comments
 (0)