From cc94527c4137dfa3b8b1e2e6f19c8ebb7b53bb0e Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 15:39:47 +0200 Subject: [PATCH 01/17] Add initial test for structured output --- .gitignore | 6 ++++ api/.gitignore | 1 + .../completion/chat/ChatResponseFormat.java | 1 + client/.gitignore | 1 + service/.gitignore | 1 + .../openai/service/ChatCompletionTest.java | 34 +++++++++++++++---- 6 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 api/.gitignore create mode 100644 client/.gitignore create mode 100644 service/.gitignore diff --git a/.gitignore b/.gitignore index 848c1dd..a261919 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,12 @@ hs_err_pid* # IntelliJ Files # .idea/ *.iml + +# Eclipse Files # +.project +.settings +.classpath + # Ignore Gradle project-specific cache directory .gradle diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/api/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 8922802..b1d642c 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -38,6 +38,7 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); + public static final ChatResponseFormat JSON_SCHEMA = new ChatResponseFormat("json_schema"); @NoArgsConstructor public static class ChatResponseFormatSerializer extends JsonSerializer { diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/service/.gitignore b/service/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/service/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 11aaaa3..760bdee 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -10,6 +10,8 @@ import com.theokanning.openai.function.FunctionDefinition; import com.theokanning.openai.function.FunctionExecutorManager; import com.theokanning.openai.service.util.ToolUtil; + +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.time.Duration; @@ -106,7 +108,7 @@ void createChatCompletionWithJsonMode() { ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); assertTrue(isValidJson(choice.getMessage().getContent()), "Response is not valid JSON"); } - + private boolean isValidJson(String jsonString) { ObjectMapper objectMapper = new ObjectMapper(); try { @@ -116,6 +118,26 @@ private boolean isValidJson(String jsonString) { return false; } } + + @Test + @Disabled + void createChatCompletionWithStructuredOutput() { + final List messages = new ArrayList<>(); + final ChatMessage systemMessage = new SystemMessage("You will generate a random name and return it in JSON format."); + messages.add(systemMessage); + + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest + .builder() + .model("gpt-4o-2024-05-13") + .messages(messages) + .responseFormat(ChatResponseFormat.JSON_SCHEMA) + .maxTokens(50) + .logitBias(new HashMap<>()) + .build(); + + ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); + assertTrue(isValidJson(choice.getMessage().getContent()), "Response is not valid JSON"); + } @Test void createChatCompletionWithFunctions() { @@ -131,7 +153,7 @@ void createChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-3.5-turbo-0613") + .model("gpt-4o-2024-05-13") .messages(messages) .functions(functions) .n(1) @@ -163,7 +185,7 @@ void createChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest2 = ChatCompletionRequest .builder() - .model("gpt-3.5-turbo-0613") + .model("gpt-4o-2024-05-13") .messages(messages) .functions(functions) .n(1) @@ -205,7 +227,7 @@ void createChatCompletionWithDynamicFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-3.5-turbo-0613") + .model("gpt-4o-2024-05-13") .messages(messages) .functions(Collections.singletonList(function)) .n(1) @@ -290,7 +312,7 @@ void streamChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-3.5-turbo-0613") + .model("gpt-4o-2024-05-13") .messages(messages) .functions(functions) .n(1) @@ -324,7 +346,7 @@ void streamChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest2 = ChatCompletionRequest .builder() - .model("gpt-3.5-turbo-0613") + .model("gpt-4o-2024-05-13") .messages(messages) .functions(functions) .n(1) From 4a800463c4541a39fd2c6171c84d03d68fa1f6a8 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 17:24:10 +0200 Subject: [PATCH 02/17] First working test --- .../completion/chat/ChatResponseFormat.java | 39 ++++++- .../openai/service/ChatCompletionTest.java | 104 +++++++++++++++--- .../resources/math-reasoning-json-schema.json | 37 +++++++ 3 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 service/src/test/resources/math-reasoning-json-schema.json diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index b1d642c..e440349 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -1,19 +1,21 @@ package com.theokanning.openai.completion.chat; +import java.io.IOException; + import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.exc.InvalidFormatException; + import lombok.Data; import lombok.NoArgsConstructor; -import java.io.IOException; - /** * see {@link ChatCompletionRequest} documentation. */ @@ -24,6 +26,16 @@ public class ChatResponseFormat { * auto/text/json_object */ private String type; + + /** + * This is used together with type field set to "json_schema" + * to enable structured outputs. + * + * @see https://openai.com/index/introducing-structured-outputs-in-the-api/ + * + * @author BertilMuth + */ + private JsonNode json_schema; /** * 构造私有,只允许从静态变量获取 @@ -37,8 +49,12 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat TEXT = new ChatResponseFormat("text"); public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); - - public static final ChatResponseFormat JSON_SCHEMA = new ChatResponseFormat("json_schema"); + + public static ChatResponseFormat jsonSchema(JsonNode jsonSchema) { + ChatResponseFormat structuredOutputFormat = new ChatResponseFormat("json_schema"); + structuredOutputFormat.setJson_schema(jsonSchema); + return structuredOutputFormat; + } @NoArgsConstructor public static class ChatResponseFormatSerializer extends JsonSerializer { @@ -48,7 +64,20 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro gen.writeString(value.getType()); } else { gen.writeStartObject(); - gen.writeObjectField("type", (value).getType()); + + if (value.getType().equals("json_schema")) { + String schemaName = "SchemaName"; + + gen.writeObjectFieldStart("json_schema"); + gen.writeStringField("name", schemaName); + gen.writeBooleanField("strict", true); + + JsonNode jsonSchema = value.getJson_schema(); + if (jsonSchema != null) { + gen.writeTree(jsonSchema); + } + } + gen.writeEndObject(); } } diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 760bdee..6b66717 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -1,24 +1,53 @@ package com.theokanning.openai.service; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.theokanning.openai.assistants.run.ToolChoice; -import com.theokanning.openai.completion.chat.*; +import com.theokanning.openai.completion.chat.AssistantMessage; +import com.theokanning.openai.completion.chat.ChatCompletionChoice; +import com.theokanning.openai.completion.chat.ChatCompletionChunk; +import com.theokanning.openai.completion.chat.ChatCompletionRequest; +import com.theokanning.openai.completion.chat.ChatFunctionCall; +import com.theokanning.openai.completion.chat.ChatFunctionDynamic; +import com.theokanning.openai.completion.chat.ChatFunctionProperty; +import com.theokanning.openai.completion.chat.ChatMessage; +import com.theokanning.openai.completion.chat.ChatResponseFormat; +import com.theokanning.openai.completion.chat.ChatTool; +import com.theokanning.openai.completion.chat.ChatToolCall; +import com.theokanning.openai.completion.chat.StreamOption; +import com.theokanning.openai.completion.chat.SystemMessage; +import com.theokanning.openai.completion.chat.ToolMessage; +import com.theokanning.openai.completion.chat.UserMessage; import com.theokanning.openai.function.FunctionDefinition; import com.theokanning.openai.function.FunctionExecutorManager; import com.theokanning.openai.service.util.ToolUtil; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.time.Duration; -import java.time.LocalDate; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; +import lombok.Data; +import lombok.NoArgsConstructor; class ChatCompletionTest { @@ -120,25 +149,64 @@ private boolean isValidJson(String jsonString) { } @Test - @Disabled - void createChatCompletionWithStructuredOutput() { + void createChatCompletionWithStructuredOutput() throws JsonProcessingException { final List messages = new ArrayList<>(); - final ChatMessage systemMessage = new SystemMessage("You will generate a random name and return it in JSON format."); + final ChatMessage systemMessage = new SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."); + final ChatMessage userMessage = new UserMessage("how can I solve 8x + 7 = -23"); messages.add(systemMessage); + messages.add(userMessage); - ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest + ObjectMapper mapper = new ObjectMapper(); + ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(createMathReasoningSchema(mapper)); + + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) - .responseFormat(ChatResponseFormat.JSON_SCHEMA) - .maxTokens(50) + .responseFormat(responseFormat) + .maxTokens(1000) .logitBias(new HashMap<>()) .build(); ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); - assertTrue(isValidJson(choice.getMessage().getContent()), "Response is not valid JSON"); + String content = choice.getMessage().getContent(); + MathReasoning mathReasoning = mapper.readValue(content, MathReasoning.class); + String finalAnswer = mathReasoning.getFinal_answer(); + assertTrue(finalAnswer.contains("x")); + assertTrue(finalAnswer.contains("=")); } - + + private JsonNode createMathReasoningSchema(ObjectMapper mapper) { + ClassLoader classLoader = getClass().getClassLoader(); + File jsonSchemaFile = new File(classLoader.getResource("math-reasoning-json-schema.json").getFile()); + + JsonNode jsonSchemaNode; + try { + jsonSchemaNode = mapper.readTree(jsonSchemaFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + return jsonSchemaNode; + } + + @Data + @NoArgsConstructor + private static class MathReasoning { + @JsonProperty(required = true) + public List steps; + @JsonProperty(required = true) + public String final_answer; + } + + @Data + @NoArgsConstructor + private static class Step { + @JsonProperty(required = true) + public String explanation; + @JsonProperty(required = true) + public String output; + } + @Test void createChatCompletionWithFunctions() { final List functions = Collections.singletonList(ToolUtil.weatherFunction()); diff --git a/service/src/test/resources/math-reasoning-json-schema.json b/service/src/test/resources/math-reasoning-json-schema.json new file mode 100644 index 0000000..950f9d5 --- /dev/null +++ b/service/src/test/resources/math-reasoning-json-schema.json @@ -0,0 +1,37 @@ +{ + "name": "MathReasoning", + "strict": true, + "schema":{ + "$schema" : "http://json-schema.org/draft-04/schema#", + "title" : "Math Reasoning", + "type" : "object", + "additionalProperties" : false, + "properties" : { + "steps" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/Step" + } + }, + "final_answer" : { + "type" : "string" + } + }, + "required" : [ "steps", "final_answer" ], + "definitions" : { + "Step" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "explanation" : { + "type" : "string" + }, + "output" : { + "type" : "string" + } + }, + "required" : [ "explanation", "output" ] + } + } + } +} From d8649f162d709e1884ba642d5c2c7739d820ce8c Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 18:17:24 +0200 Subject: [PATCH 03/17] First working version --- .../chat/ChatCompletionRequest.java | 8 +++++- .../completion/chat/ChatResponseFormat.java | 27 ++++++++++++------- .../openai/service/ChatCompletionTest.java | 25 ++++------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java index 31e002d..dfe6d0f 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java @@ -1,7 +1,11 @@ package com.theokanning.openai.completion.chat; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.theokanning.openai.assistants.run.ToolChoice; +import com.theokanning.openai.completion.chat.ChatResponseFormat.ChatResponseFormatSerializer; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -29,10 +33,12 @@ public class ChatCompletionRequest { List messages; /** - * Must be either 'text' or 'json_object'.
+ * Must be either 'text', 'json_object' or 'json_schema'.
* When specifying 'json_object' as the request format it's still necessary to instruct the model to return JSON. */ @JsonProperty("response_format") + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonSerialize(using = ChatResponseFormat.ChatResponseFormatSerializer.class) ChatResponseFormat responseFormat; /** diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index e440349..55f9687 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -2,6 +2,7 @@ import java.io.IOException; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -10,8 +11,10 @@ import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.kjetland.jackson.jsonSchema.JsonSchemaGenerator; import lombok.Data; import lombok.NoArgsConstructor; @@ -50,10 +53,17 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); - public static ChatResponseFormat jsonSchema(JsonNode jsonSchema) { - ChatResponseFormat structuredOutputFormat = new ChatResponseFormat("json_schema"); - structuredOutputFormat.setJson_schema(jsonSchema); - return structuredOutputFormat; + public static ChatResponseFormat jsonSchema(Class rootClass) { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper); + JsonNode jsonSchema = schemaGen.generateJsonSchema(rootClass); + + ChatResponseFormat jsonSchemaFormat = new ChatResponseFormat("json_schema"); + jsonSchemaFormat.setJson_schema(jsonSchema); + + return jsonSchemaFormat; } @NoArgsConstructor @@ -64,6 +74,7 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro gen.writeString(value.getType()); } else { gen.writeStartObject(); + gen.writeObjectField("type", (value).getType()); if (value.getType().equals("json_schema")) { String schemaName = "SchemaName"; @@ -71,11 +82,9 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro gen.writeObjectFieldStart("json_schema"); gen.writeStringField("name", schemaName); gen.writeBooleanField("strict", true); - - JsonNode jsonSchema = value.getJson_schema(); - if (jsonSchema != null) { - gen.writeTree(jsonSchema); - } + gen.writeFieldName("schema"); + gen.writeTree(value.getJson_schema()); + gen.writeEndObject(); } gen.writeEndObject(); diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 6b66717..807f03f 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -7,8 +7,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.File; -import java.io.IOException; import java.time.Duration; import java.time.LocalDate; import java.util.ArrayList; @@ -149,15 +147,14 @@ private boolean isValidJson(String jsonString) { } @Test - void createChatCompletionWithStructuredOutput() throws JsonProcessingException { + void createChatCompletionWithJsonSchema() throws JsonProcessingException { final List messages = new ArrayList<>(); final ChatMessage systemMessage = new SystemMessage("You are a helpful math tutor. Guide the user through the solution step by step."); final ChatMessage userMessage = new UserMessage("how can I solve 8x + 7 = -23"); messages.add(systemMessage); messages.add(userMessage); - ObjectMapper mapper = new ObjectMapper(); - ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(createMathReasoningSchema(mapper)); + ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(MathReasoning.class); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() @@ -165,30 +162,18 @@ void createChatCompletionWithStructuredOutput() throws JsonProcessingException { .messages(messages) .responseFormat(responseFormat) .maxTokens(1000) - .logitBias(new HashMap<>()) .build(); ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); String content = choice.getMessage().getContent(); - MathReasoning mathReasoning = mapper.readValue(content, MathReasoning.class); + + MathReasoning mathReasoning = new ObjectMapper().readValue(content, MathReasoning.class); + String finalAnswer = mathReasoning.getFinal_answer(); assertTrue(finalAnswer.contains("x")); assertTrue(finalAnswer.contains("=")); } - private JsonNode createMathReasoningSchema(ObjectMapper mapper) { - ClassLoader classLoader = getClass().getClassLoader(); - File jsonSchemaFile = new File(classLoader.getResource("math-reasoning-json-schema.json").getFile()); - - JsonNode jsonSchemaNode; - try { - jsonSchemaNode = mapper.readTree(jsonSchemaFile); - } catch (IOException e) { - throw new RuntimeException(e); - } - return jsonSchemaNode; - } - @Data @NoArgsConstructor private static class MathReasoning { From ac0bfbb02734cf1327e04b1468fd6516d0ac0714 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 18:59:44 +0200 Subject: [PATCH 04/17] Clean up --- .../completion/chat/ChatResponseFormat.java | 4 +- .../resources/math-reasoning-json-schema.json | 37 ------------------- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 service/src/test/resources/math-reasoning-json-schema.json diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 55f9687..312edde 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -54,9 +54,7 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); public static ChatResponseFormat jsonSchema(Class rootClass) { - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - + ObjectMapper mapper = new ObjectMapper(); JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper); JsonNode jsonSchema = schemaGen.generateJsonSchema(rootClass); diff --git a/service/src/test/resources/math-reasoning-json-schema.json b/service/src/test/resources/math-reasoning-json-schema.json deleted file mode 100644 index 950f9d5..0000000 --- a/service/src/test/resources/math-reasoning-json-schema.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "MathReasoning", - "strict": true, - "schema":{ - "$schema" : "http://json-schema.org/draft-04/schema#", - "title" : "Math Reasoning", - "type" : "object", - "additionalProperties" : false, - "properties" : { - "steps" : { - "type" : "array", - "items" : { - "$ref" : "#/definitions/Step" - } - }, - "final_answer" : { - "type" : "string" - } - }, - "required" : [ "steps", "final_answer" ], - "definitions" : { - "Step" : { - "type" : "object", - "additionalProperties" : false, - "properties" : { - "explanation" : { - "type" : "string" - }, - "output" : { - "type" : "string" - } - }, - "required" : [ "explanation", "output" ] - } - } - } -} From 8a6b3d400808a365fbef24e2cae307d942af2a8c Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 19:08:37 +0200 Subject: [PATCH 05/17] Use common object mapper --- .../openai/completion/chat/ChatResponseFormat.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 312edde..3526d6c 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -2,7 +2,6 @@ import java.io.IOException; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -14,7 +13,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.kjetland.jackson.jsonSchema.JsonSchemaConfig; import com.kjetland.jackson.jsonSchema.JsonSchemaGenerator; +import com.theokanning.openai.utils.JsonUtil; import lombok.Data; import lombok.NoArgsConstructor; @@ -25,6 +26,10 @@ @Data @NoArgsConstructor public class ChatResponseFormat { + private static final ObjectMapper MAPPER = JsonUtil.getInstance(); + private static final JsonSchemaConfig CONFIG = JsonSchemaConfig.vanillaJsonSchemaDraft4(); + private static final JsonSchemaGenerator JSON_SCHEMA_GENERATOR = new JsonSchemaGenerator(MAPPER, CONFIG); + /** * auto/text/json_object */ @@ -54,13 +59,9 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); public static ChatResponseFormat jsonSchema(Class rootClass) { - ObjectMapper mapper = new ObjectMapper(); - JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper); - JsonNode jsonSchema = schemaGen.generateJsonSchema(rootClass); - + JsonNode jsonSchema = JSON_SCHEMA_GENERATOR.generateJsonSchema(rootClass); ChatResponseFormat jsonSchemaFormat = new ChatResponseFormat("json_schema"); jsonSchemaFormat.setJson_schema(jsonSchema); - return jsonSchemaFormat; } From da3c06ac5875fa3831c77cbec91407dac8f7b1fc Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Tue, 13 Aug 2024 23:42:49 +0200 Subject: [PATCH 06/17] Use @NotNull for fields --- .../chat/ChatCompletionRequest.java | 7 +++--- .../completion/chat/ChatResponseFormat.java | 8 +++--- .../openai/service/ChatCompletionTest.java | 25 ++++++++----------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java index dfe6d0f..9a5a4b6 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java @@ -1,19 +1,18 @@ package com.theokanning.openai.completion.chat; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.theokanning.openai.assistants.run.ToolChoice; -import com.theokanning.openai.completion.chat.ChatResponseFormat.ChatResponseFormatSerializer; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; -import java.util.Map; - @Data @Builder @AllArgsConstructor diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 3526d6c..18481ae 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -68,7 +68,7 @@ public static ChatResponseFormat jsonSchema(Class rootClass) { @NoArgsConstructor public static class ChatResponseFormatSerializer extends JsonSerializer { @Override - public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (value.getType().equals("auto")) { gen.writeString(value.getType()); } else { @@ -76,13 +76,13 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro gen.writeObjectField("type", (value).getType()); if (value.getType().equals("json_schema")) { - String schemaName = "SchemaName"; + JsonNode jsonSchema = value.getJson_schema(); gen.writeObjectFieldStart("json_schema"); - gen.writeStringField("name", schemaName); + gen.writeStringField("name", "ChatResponseFormat"); gen.writeBooleanField("strict", true); gen.writeFieldName("schema"); - gen.writeTree(value.getJson_schema()); + gen.writeTree(jsonSchema); gen.writeEndObject(); } diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 807f03f..6868bd7 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -16,9 +16,10 @@ import java.util.HashSet; import java.util.List; +import javax.validation.constraints.NotNull; + import org.junit.jupiter.api.Test; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -164,12 +165,12 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { .maxTokens(1000) .build(); - ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); - String content = choice.getMessage().getContent(); - + ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); + String content = choice.getMessage().getContent(); + MathReasoning mathReasoning = new ObjectMapper().readValue(content, MathReasoning.class); - - String finalAnswer = mathReasoning.getFinal_answer(); + + String finalAnswer = mathReasoning.getFinal_answer(); assertTrue(finalAnswer.contains("x")); assertTrue(finalAnswer.contains("=")); } @@ -177,19 +178,15 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { @Data @NoArgsConstructor private static class MathReasoning { - @JsonProperty(required = true) - public List steps; - @JsonProperty(required = true) - public String final_answer; + @NotNull private List steps; + @NotNull private String final_answer; } @Data @NoArgsConstructor private static class Step { - @JsonProperty(required = true) - public String explanation; - @JsonProperty(required = true) - public String output; + @NotNull private String explanation; + @NotNull private String output; } @Test From 178a957fe7897345aad9750da95d4e2dac18590e Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:01:23 +0200 Subject: [PATCH 07/17] Remove unnecessary @JsonInclude --- .../openai/completion/chat/ChatCompletionRequest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java index 9a5a4b6..3284f7c 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatCompletionRequest.java @@ -36,7 +36,6 @@ public class ChatCompletionRequest { * When specifying 'json_object' as the request format it's still necessary to instruct the model to return JSON. */ @JsonProperty("response_format") - @JsonInclude(JsonInclude.Include.NON_NULL) @JsonSerialize(using = ChatResponseFormat.ChatResponseFormatSerializer.class) ChatResponseFormat responseFormat; From 68ce2ceda2b064c6d917948c1a1303e3edb71642 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:02:53 +0200 Subject: [PATCH 08/17] Remove spaces --- .../theokanning/openai/completion/chat/ChatResponseFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 18481ae..56f1ed9 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -68,7 +68,7 @@ public static ChatResponseFormat jsonSchema(Class rootClass) { @NoArgsConstructor public static class ChatResponseFormatSerializer extends JsonSerializer { @Override - public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (value.getType().equals("auto")) { gen.writeString(value.getType()); } else { From 28e4098946aeb483e08d869de826269d73821911 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:06:42 +0200 Subject: [PATCH 09/17] Use latest gpt4o model (3.5 no longer supported) --- .../theokanning/openai/service/ChatCompletionTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 6868bd7..dcd82c6 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -203,7 +203,7 @@ void createChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) .functions(functions) .n(1) @@ -235,7 +235,7 @@ void createChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest2 = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) .functions(functions) .n(1) @@ -277,7 +277,7 @@ void createChatCompletionWithDynamicFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) .functions(Collections.singletonList(function)) .n(1) @@ -362,7 +362,7 @@ void streamChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) .functions(functions) .n(1) @@ -396,7 +396,7 @@ void streamChatCompletionWithFunctions() { ChatCompletionRequest chatCompletionRequest2 = ChatCompletionRequest .builder() - .model("gpt-4o-2024-05-13") + .model("gpt-4o-2024-08-06") .messages(messages) .functions(functions) .n(1) From cd91750ad019c9580aecbb5742a1507de8a39e09 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:25:27 +0200 Subject: [PATCH 10/17] Add parsed() method to AssistantMessage --- .../completion/chat/AssistantMessage.java | 21 +++++++++++++++++-- .../openai/service/ChatCompletionTest.java | 7 +++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java index 1685e54..fcc0e23 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java @@ -1,13 +1,15 @@ package com.theokanning.openai.completion.chat; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.theokanning.openai.utils.JsonUtil; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - /** * @author LiangTao * @date 2024年04月10 10:31 @@ -49,4 +51,19 @@ public AssistantMessage(String content, String name) { public String getTextContent() { return content; } + + /** + * Deserializes the message to an object of the specified target class. + * + * @param targetClass the type of the object + * @return the deserialized object + * @author BertilMuth + */ + public T parsed(Class targetClass) { + try { + return JsonUtil.getInstance().readValue(getTextContent(), targetClass); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index dcd82c6..838d68f 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -155,7 +155,8 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { messages.add(systemMessage); messages.add(userMessage); - ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(MathReasoning.class); + Class rootClass = MathReasoning.class; + ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(rootClass); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() @@ -166,9 +167,7 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { .build(); ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); - String content = choice.getMessage().getContent(); - - MathReasoning mathReasoning = new ObjectMapper().readValue(content, MathReasoning.class); + MathReasoning mathReasoning = choice.getMessage().parsed(rootClass); String finalAnswer = mathReasoning.getFinal_answer(); assertTrue(finalAnswer.contains("x")); From 36954308ec11ef9f9ba8cdba2185c158fe8ae08a Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:30:21 +0200 Subject: [PATCH 11/17] Prepare pull request --- .../theokanning/openai/completion/chat/AssistantMessage.java | 3 +-- .../theokanning/openai/completion/chat/ChatResponseFormat.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java index fcc0e23..a9b8f69 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java @@ -57,8 +57,7 @@ public String getTextContent() { * * @param targetClass the type of the object * @return the deserialized object - * @author BertilMuth - */ ++ */ public T parsed(Class targetClass) { try { return JsonUtil.getInstance().readValue(getTextContent(), targetClass); diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 56f1ed9..a680bc6 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -41,7 +41,6 @@ public class ChatResponseFormat { * * @see https://openai.com/index/introducing-structured-outputs-in-the-api/ * - * @author BertilMuth */ private JsonNode json_schema; From f52cb37ae3756e0a30791dd6e4ff3d8565eea3dc Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:42:48 +0200 Subject: [PATCH 12/17] Fix whitespace --- .../openai/service/ChatCompletionTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java index 838d68f..62bf988 100644 --- a/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java +++ b/service/src/test/java/com/theokanning/openai/service/ChatCompletionTest.java @@ -156,9 +156,9 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { messages.add(userMessage); Class rootClass = MathReasoning.class; - ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(rootClass); + ChatResponseFormat responseFormat = ChatResponseFormat.jsonSchema(rootClass); - ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest .builder() .model("gpt-4o-2024-08-06") .messages(messages) @@ -166,27 +166,27 @@ void createChatCompletionWithJsonSchema() throws JsonProcessingException { .maxTokens(1000) .build(); - ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); - MathReasoning mathReasoning = choice.getMessage().parsed(rootClass); - - String finalAnswer = mathReasoning.getFinal_answer(); - assertTrue(finalAnswer.contains("x")); - assertTrue(finalAnswer.contains("=")); + ChatCompletionChoice choice = service.createChatCompletion(chatCompletionRequest).getChoices().get(0); + MathReasoning mathReasoning = choice.getMessage().parsed(rootClass); + + String finalAnswer = mathReasoning.getFinal_answer(); + assertTrue(finalAnswer.contains("x")); + assertTrue(finalAnswer.contains("=")); } @Data @NoArgsConstructor private static class MathReasoning { - @NotNull private List steps; - @NotNull private String final_answer; - } + @NotNull private List steps; + @NotNull private String final_answer; + } @Data @NoArgsConstructor private static class Step { - @NotNull private String explanation; - @NotNull private String output; - } + @NotNull private String explanation; + @NotNull private String output; + } @Test void createChatCompletionWithFunctions() { From ff8689a0efd50cf8ed6cd79f3ac23f5fbce9959a Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:45:03 +0200 Subject: [PATCH 13/17] Fix whitespace --- .../openai/completion/chat/ChatResponseFormat.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index a680bc6..37c034d 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -56,12 +56,12 @@ private ChatResponseFormat(String type) { public static final ChatResponseFormat TEXT = new ChatResponseFormat("text"); public static final ChatResponseFormat JSON_OBJECT = new ChatResponseFormat("json_object"); - - public static ChatResponseFormat jsonSchema(Class rootClass) { - JsonNode jsonSchema = JSON_SCHEMA_GENERATOR.generateJsonSchema(rootClass); - ChatResponseFormat jsonSchemaFormat = new ChatResponseFormat("json_schema"); - jsonSchemaFormat.setJson_schema(jsonSchema); - return jsonSchemaFormat; + + public static ChatResponseFormat jsonSchema(Class rootClass) { + JsonNode jsonSchema = JSON_SCHEMA_GENERATOR.generateJsonSchema(rootClass); + ChatResponseFormat jsonSchemaFormat = new ChatResponseFormat("json_schema"); + jsonSchemaFormat.setJson_schema(jsonSchema); + return jsonSchemaFormat; } @NoArgsConstructor From 25592aa41150ee402111e0f83f214c013e7c511e Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:46:18 +0200 Subject: [PATCH 14/17] Fix whitespace --- .../openai/completion/chat/ChatResponseFormat.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 37c034d..9108804 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -26,9 +26,9 @@ @Data @NoArgsConstructor public class ChatResponseFormat { - private static final ObjectMapper MAPPER = JsonUtil.getInstance(); - private static final JsonSchemaConfig CONFIG = JsonSchemaConfig.vanillaJsonSchemaDraft4(); - private static final JsonSchemaGenerator JSON_SCHEMA_GENERATOR = new JsonSchemaGenerator(MAPPER, CONFIG); + private static final ObjectMapper MAPPER = JsonUtil.getInstance(); + private static final JsonSchemaConfig CONFIG = JsonSchemaConfig.vanillaJsonSchemaDraft4(); + private static final JsonSchemaGenerator JSON_SCHEMA_GENERATOR = new JsonSchemaGenerator(MAPPER, CONFIG); /** * auto/text/json_object From f757f5f5d207b62e8a2c1260f6ae274b6d488091 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:48:06 +0200 Subject: [PATCH 15/17] Fix whitespace --- .../openai/completion/chat/AssistantMessage.java | 14 +++++++------- .../openai/completion/chat/ChatResponseFormat.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java index a9b8f69..4a4e250 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java @@ -58,11 +58,11 @@ public String getTextContent() { * @param targetClass the type of the object * @return the deserialized object + */ - public T parsed(Class targetClass) { - try { - return JsonUtil.getInstance().readValue(getTextContent(), targetClass); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + public T parsed(Class targetClass) { + try { + return JsonUtil.getInstance().readValue(getTextContent(), targetClass); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 9108804..1f91a0c 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -78,7 +78,7 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro JsonNode jsonSchema = value.getJson_schema(); gen.writeObjectFieldStart("json_schema"); - gen.writeStringField("name", "ChatResponseFormat"); + gen.writeStringField("name", "ChatResponseFormat"); gen.writeBooleanField("strict", true); gen.writeFieldName("schema"); gen.writeTree(jsonSchema); From 8d6e5e2060e426c015f514aa1ab641c41047b472 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:51:25 +0200 Subject: [PATCH 16/17] Fix whitespace --- .../openai/completion/chat/AssistantMessage.java | 12 ++++++------ .../openai/completion/chat/ChatResponseFormat.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java index 4a4e250..139e9eb 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/AssistantMessage.java @@ -52,12 +52,12 @@ public String getTextContent() { return content; } - /** - * Deserializes the message to an object of the specified target class. - * - * @param targetClass the type of the object - * @return the deserialized object -+ */ + /** + * Deserializes the message to an object of the specified target class. + * + * @param targetClass the type of the object + * @return the deserialized object + **/ public T parsed(Class targetClass) { try { return JsonUtil.getInstance().readValue(getTextContent(), targetClass); diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index 1f91a0c..f95f0ea 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -81,7 +81,7 @@ public void serialize(ChatResponseFormat value, JsonGenerator gen, SerializerPro gen.writeStringField("name", "ChatResponseFormat"); gen.writeBooleanField("strict", true); gen.writeFieldName("schema"); - gen.writeTree(jsonSchema); + gen.writeTree(jsonSchema); gen.writeEndObject(); } From cb57ee999a47d5aa3254a55268b72f7d1457bc35 Mon Sep 17 00:00:00 2001 From: Bertil Muth Date: Wed, 14 Aug 2024 00:52:40 +0200 Subject: [PATCH 17/17] Fix whitespace --- .../theokanning/openai/completion/chat/ChatResponseFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java index f95f0ea..b7d2f48 100644 --- a/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java +++ b/api/src/main/java/com/theokanning/openai/completion/chat/ChatResponseFormat.java @@ -62,7 +62,7 @@ public static ChatResponseFormat jsonSchema(Class rootClass) { ChatResponseFormat jsonSchemaFormat = new ChatResponseFormat("json_schema"); jsonSchemaFormat.setJson_schema(jsonSchema); return jsonSchemaFormat; - } + } @NoArgsConstructor public static class ChatResponseFormatSerializer extends JsonSerializer {