From 2c4554eb3f21f8f7dc4260e9cad54eede3f29d32 Mon Sep 17 00:00:00 2001 From: Mark Pollack Date: Thu, 6 Jun 2024 16:06:25 -0400 Subject: [PATCH] more ser-deser fixes for openai and anthropic --- .../AnthropicChatResponseMetadata.java | 10 +++ .../metadata/OpenAiChatResponseMetadata.java | 10 +++ .../ai/openai/api/ChatResponseJsonTests.java | 85 +++++++++++++++++++ .../ai/chat/model/ChatResponse.java | 2 +- ...BedrockAnthropicChatAutoConfiguration.java | 4 +- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/ChatResponseJsonTests.java diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/metadata/AnthropicChatResponseMetadata.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/metadata/AnthropicChatResponseMetadata.java index 513c7dcd5..e7eed1d25 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/metadata/AnthropicChatResponseMetadata.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/metadata/AnthropicChatResponseMetadata.java @@ -15,6 +15,7 @@ */ package org.springframework.ai.anthropic.metadata; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.ai.anthropic.api.AnthropicApi; import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.metadata.EmptyRateLimit; @@ -89,4 +90,13 @@ public class AnthropicChatResponseMetadata extends HashMap imple return AI_METADATA_STRING.formatted(getClass().getName(), getId(), getUsage(), getRateLimit()); } + public static class Module extends SimpleModule { + + public Module() { + super("AnthropicChatResponseMetadata Module"); + this.registerSubtypes(AnthropicChatResponseMetadata.class); + } + + } + } diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/OpenAiChatResponseMetadata.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/OpenAiChatResponseMetadata.java index e934e0b50..71988d659 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/OpenAiChatResponseMetadata.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/metadata/OpenAiChatResponseMetadata.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.ai.chat.metadata.ChatResponseMetadata; import org.springframework.ai.chat.metadata.EmptyRateLimit; import org.springframework.ai.chat.metadata.EmptyUsage; @@ -124,4 +125,13 @@ public class OpenAiChatResponseMetadata implements ChatResponseMetadata { return Objects.hash(id, rateLimit, usage, promptMetadata); } + public static class Module extends SimpleModule { + + public Module() { + super("OpenAiChatResponseMetadata Module"); + this.registerSubtypes(OpenAiChatResponseMetadata.class); + } + + } + } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/ChatResponseJsonTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/ChatResponseJsonTests.java new file mode 100644 index 000000000..64ffc7ea5 --- /dev/null +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/api/ChatResponseJsonTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2024 - 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.openai.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.junit.jupiter.api.Test; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.openai.metadata.OpenAiChatResponseMetadata; + +public class ChatResponseJsonTests { + + @Test + void serDeserChatResponse() throws JsonProcessingException { + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.registerModule(new OpenAiChatResponseMetadata.Module()); + + String json = """ + { + "results" : [ { + "assistantMessage" : { + "messageType" : "ASSISTANT", + "content" : "Why couldn't the bicycle find its way home? Because it lost its bearings!", + "metadata" : { + "finishReason" : "STOP", + "role" : "ASSISTANT", + "id" : "chatcmpl-9XBoXJwhroi7d6vD8ncbNUl2vIOyk", + "messageType" : "ASSISTANT" + }, + "messageType" : "ASSISTANT", + "media" : [ ] + }, + "chatGenerationMetadata" : { + "type" : "default", + "finishReason" : "STOP", + "contentFilterMetadata" : null + } + } ], + "advisorContext" : { }, + "metadata" : { + "type" : "openai", + "id" : "chatcmpl-9XBoXJwhroi7d6vD8ncbNUl2vIOyk", + "usage" : { + "promptTokens" : 11, + "generationTokens" : 16, + "totalTokens" : 27 + }, + "rateLimit" : { + "requestsLimit" : 5000, + "requestsRemaining" : 4999, + "requestsReset" : 0.012000000, + "tokensLimit" : 160000, + "tokensRemaining" : 159979, + "tokensReset" : 0.007000000 + } + } + } + + """; + + ChatResponse deserializedChatResponse = objectMapper.readValue(json, ChatResponse.class); + System.out.println(deserializedChatResponse); + // assertThat(advisedRequest).usingRecursiveComparison().isEqualTo(deserialized); + + } + +} diff --git a/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ChatResponse.java b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ChatResponse.java index 954bedb41..6cc60e087 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ChatResponse.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/chat/model/ChatResponse.java @@ -64,7 +64,7 @@ public class ChatResponse implements ModelResponse { */ @JsonCreator public ChatResponse(@JsonProperty("results") List generations, - @JsonProperty("chatResponseMetadata") ChatResponseMetadata chatResponseMetadata, + @JsonProperty("metadata") ChatResponseMetadata chatResponseMetadata, @JsonProperty("advisorContext") Map advisorContext) { this.generations = generations; this.chatResponseMetadata = chatResponseMetadata; diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java index 3e3032454..0ccef446b 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java @@ -50,7 +50,7 @@ public class BedrockAnthropicChatAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public AnthropicChatBedrockApi anthropicApi(AwsCredentialsProvider credentialsProvider, + public AnthropicChatBedrockApi anthropicChatBedrockApi(AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider, BedrockAnthropicChatProperties properties, BedrockAwsConnectionProperties awsProperties) { return new AnthropicChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), @@ -59,7 +59,7 @@ public class BedrockAnthropicChatAutoConfiguration { @Bean @ConditionalOnBean(AnthropicChatBedrockApi.class) - public BedrockAnthropicChatModel anthropicChatModel(AnthropicChatBedrockApi anthropicApi, + public BedrockAnthropicChatModel bedrockAnthropicChatModel(AnthropicChatBedrockApi anthropicApi, BedrockAnthropicChatProperties properties) { return new BedrockAnthropicChatModel(anthropicApi, properties.getOptions()); }