Enabling checkstyle on spring-ai-openai

This commit is contained in:
Soby Chacko
2024-10-25 16:10:15 -04:00
committed by Mark Pollack
parent 5d8c032bb7
commit cdc1cecb57
44 changed files with 292 additions and 259 deletions

View File

@@ -36,6 +36,10 @@
<developerConnection>git@github.com:spring-projects/spring-ai.git</developerConnection>
</scm>
<properties>
<disable.checks>false</disable.checks>
</properties>
<dependencies>
<!-- production dependencies -->

View File

@@ -132,7 +132,7 @@ public class OpenAiAudioSpeechModel implements SpeechModel, StreamingSpeechModel
var speech = speechEntity.getBody();
if (speech == null) {
this.logger.warn("No speech response returned for speechRequest: {}", speechRequest);
logger.warn("No speech response returned for speechRequest: {}", speechRequest);
return new SpeechResponse(new Speech(new byte[0]));
}

View File

@@ -118,7 +118,7 @@ public class OpenAiAudioTranscriptionModel implements Model<AudioTranscriptionPr
var transcription = transcriptionEntity.getBody();
if (transcription == null) {
this.logger.warn("No transcription returned for request: {}", audioResource);
logger.warn("No transcription returned for request: {}", audioResource);
return new AudioTranscriptionResponse(null);
}
@@ -139,7 +139,7 @@ public class OpenAiAudioTranscriptionModel implements Model<AudioTranscriptionPr
var transcription = transcriptionEntity.getBody();
if (transcription == null) {
this.logger.warn("No transcription returned for request: {}", audioResource);
logger.warn("No transcription returned for request: {}", audioResource);
return new AudioTranscriptionResponse(null);
}

View File

@@ -122,37 +122,48 @@ public class OpenAiAudioTranscriptionOptions implements AudioTranscriptionOption
@Override
public boolean equals(Object obj) {
if (this == obj)
if (this == obj) {
return true;
if (obj == null)
}
if (obj == null) {
return false;
if (getClass() != obj.getClass())
}
if (getClass() != obj.getClass()) {
return false;
}
OpenAiAudioTranscriptionOptions other = (OpenAiAudioTranscriptionOptions) obj;
if (this.model == null) {
if (other.model != null)
if (other.model != null) {
return false;
}
}
else if (!this.model.equals(other.model))
else if (!this.model.equals(other.model)) {
return false;
}
if (this.prompt == null) {
if (other.prompt != null)
if (other.prompt != null) {
return false;
}
}
else if (!this.prompt.equals(other.prompt))
else if (!this.prompt.equals(other.prompt)) {
return false;
}
if (this.language == null) {
if (other.language != null)
if (other.language != null) {
return false;
}
}
else if (!this.language.equals(other.language))
else if (!this.language.equals(other.language)) {
return false;
}
if (this.responseFormat == null) {
if (other.responseFormat != null)
if (other.responseFormat != null) {
return false;
}
}
else if (!this.responseFormat.equals(other.responseFormat))
else if (!this.responseFormat.equals(other.responseFormat)) {
return false;
}
return true;
}

View File

@@ -307,8 +307,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
@SuppressWarnings("null")
String id = chatCompletion2.id();
List<Generation> generations = chatCompletion2.choices().stream().map(choice -> {// @formatter:off
List<Generation> generations = chatCompletion2.choices().stream().map(choice -> { // @formatter:off
if (choice.message().role() != null) {
roleMap.putIfAbsent(id, choice.message().role().name());
}
@@ -347,9 +346,7 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
}
})
.doOnError(observation::error)
.doFinally(s -> {
observation.stop();
})
.doFinally(s -> observation.stop())
.contextWrite(ctx -> ctx.put(ObservationThreadLocalAccessor.KEY, observation));
// @formatter:on
@@ -454,10 +451,8 @@ public class OpenAiChatModel extends AbstractToolCallSupport implements ChatMode
else if (message.getMessageType() == MessageType.TOOL) {
ToolResponseMessage toolMessage = (ToolResponseMessage) message;
toolMessage.getResponses().forEach(response -> {
Assert.isTrue(response.id() != null, "ToolResponseMessage must have an id");
});
toolMessage.getResponses()
.forEach(response -> Assert.isTrue(response.id() != null, "ToolResponseMessage must have an id"));
return toolMessage.getResponses()
.stream()
.map(tr -> new ChatCompletionMessage(tr.responseData(), ChatCompletionMessage.Role.TOOL, tr.name(),

View File

@@ -169,10 +169,11 @@ public class OpenAiImageModel implements ImageModel {
return new ImageResponse(List.of());
}
List<ImageGeneration> imageGenerationList = imageApiResponse.data().stream().map(entry -> {
return new ImageGeneration(new Image(entry.url(), entry.b64Json()),
new OpenAiImageGenerationMetadata(entry.revisedPrompt()));
}).toList();
List<ImageGeneration> imageGenerationList = imageApiResponse.data()
.stream()
.map(entry -> new ImageGeneration(new Image(entry.url(), entry.b64Json()),
new OpenAiImageGenerationMetadata(entry.revisedPrompt())))
.toList();
ImageResponseMetadata openAiImageResponseMetadata = new ImageResponseMetadata(imageApiResponse.created());
return new ImageResponse(imageGenerationList, openAiImageResponseMetadata);

View File

@@ -234,7 +234,7 @@ public class OpenAiImageOptions implements ImageOptions {
+ ", user='" + this.user + '\'' + '}';
}
public static class Builder {
public static final class Builder {
private final OpenAiImageOptions options;

View File

@@ -106,7 +106,7 @@ public class OpenAiModerationModel implements ModerationModel {
OpenAiModerationApi.OpenAiModerationRequest openAiModerationRequest) {
OpenAiModerationApi.OpenAiModerationResponse moderationApiResponse = moderationResponseEntity.getBody();
if (moderationApiResponse == null) {
this.logger.warn("No moderation response returned for request: {}", openAiModerationRequest);
logger.warn("No moderation response returned for request: {}", openAiModerationRequest);
return new ModerationResponse(new Generation());
}

View File

@@ -50,7 +50,7 @@ public class OpenAiModerationOptions implements ModerationOptions {
this.model = model;
}
public static class Builder {
public static final class Builder {
private final OpenAiModerationOptions options;

View File

@@ -48,12 +48,15 @@ public class OpenAiRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {
var mcs = MemberCategory.values();
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiApi.class)))
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiApi.class))) {
hints.reflection().registerType(tr, mcs);
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiAudioApi.class)))
}
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiAudioApi.class))) {
hints.reflection().registerType(tr, mcs);
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiImageApi.class)))
}
for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiImageApi.class))) {
hints.reflection().registerType(tr, mcs);
}
}
}

View File

@@ -171,7 +171,7 @@ public class OpenAiApi {
this.webClient = webClientBuilder
.baseUrl(baseUrl)
.defaultHeaders(finalHeaders)
.build();// @formatter:on
.build(); // @formatter:on
}
public static String getTextContent(List<ChatCompletionMessage.MediaContent> content) {
@@ -556,7 +556,8 @@ public class OpenAiApi {
/**
* Function tool type.
*/
@JsonProperty("function") FUNCTION
@JsonProperty("function")
FUNCTION
}
/**
@@ -585,7 +586,7 @@ public class OpenAiApi {
this(description, name, ModelOptionsUtils.jsonToMap(jsonSchema));
}
}
}// @formatter:on
} // @formatter:on
/**
* Creates a model response for the given chat conversation.
@@ -779,7 +780,7 @@ public class OpenAiApi {
@JsonInclude(Include.NON_NULL)
public record ResponseFormat(
@JsonProperty("type") Type type,
@JsonProperty("json_schema") JsonSchema jsonSchema ) {
@JsonProperty("json_schema") JsonSchema jsonSchema) {
public ResponseFormat(Type type) {
this(type, (JsonSchema) null);
@@ -790,7 +791,7 @@ public class OpenAiApi {
}
public ResponseFormat(Type type, String name, String schema, Boolean strict) {
this(type, StringUtils.hasText(schema)? new JsonSchema(name, schema, strict): null);
this(type, StringUtils.hasText(schema) ? new JsonSchema(name, schema, strict) : null);
}
public enum Type {
@@ -833,7 +834,7 @@ public class OpenAiApi {
}
public JsonSchema(String name, String schema, Boolean strict) {
this(StringUtils.hasText(name)? name : "custom_schema", ModelOptionsUtils.jsonToMap(schema), strict);
this(StringUtils.hasText(name) ? name : "custom_schema", ModelOptionsUtils.jsonToMap(schema), strict);
}
}
@@ -852,7 +853,7 @@ public class OpenAiApi {
public static StreamOptions INCLUDE_USAGE = new StreamOptions(true);
}
}// @formatter:on
} // @formatter:on
/**
* Message comprising the conversation.
@@ -876,7 +877,7 @@ public class OpenAiApi {
@JsonProperty("name") String name,
@JsonProperty("tool_call_id") String toolCallId,
@JsonProperty("tool_calls") List<ToolCall> toolCalls,
@JsonProperty("refusal") String refusal) {// @formatter:on
@JsonProperty("refusal") String refusal) { // @formatter:on
/**
* Create a chat completion message with the given content and role. All other
@@ -995,7 +996,7 @@ public class OpenAiApi {
@JsonProperty("index") Integer index,
@JsonProperty("id") String id,
@JsonProperty("type") String type,
@JsonProperty("function") ChatCompletionFunction function) {// @formatter:on
@JsonProperty("function") ChatCompletionFunction function) { // @formatter:on
public ToolCall(String id, String type, ChatCompletionFunction function) {
this(null, id, type, function);
@@ -1013,7 +1014,7 @@ public class OpenAiApi {
@JsonInclude(Include.NON_NULL)
public record ChatCompletionFunction(// @formatter:off
@JsonProperty("name") String name,
@JsonProperty("arguments") String arguments) {// @formatter:on
@JsonProperty("arguments") String arguments) { // @formatter:on
}
}
@@ -1042,7 +1043,7 @@ public class OpenAiApi {
@JsonProperty("model") String model,
@JsonProperty("system_fingerprint") String systemFingerprint,
@JsonProperty("object") String object,
@JsonProperty("usage") Usage usage) {// @formatter:on
@JsonProperty("usage") Usage usage) { // @formatter:on
/**
* Chat completion choice.
@@ -1057,7 +1058,7 @@ public class OpenAiApi {
@JsonProperty("finish_reason") ChatCompletionFinishReason finishReason,
@JsonProperty("index") Integer index,
@JsonProperty("message") ChatCompletionMessage message,
@JsonProperty("logprobs") LogProbs logprobs) {// @formatter:on
@JsonProperty("logprobs") LogProbs logprobs) { // @formatter:on
}
@@ -1090,7 +1091,7 @@ public class OpenAiApi {
@JsonProperty("token") String token,
@JsonProperty("logprob") Float logprob,
@JsonProperty("bytes") List<Integer> probBytes,
@JsonProperty("top_logprobs") List<TopLogProbs> topLogprobs) {// @formatter:on
@JsonProperty("top_logprobs") List<TopLogProbs> topLogprobs) { // @formatter:on
/**
* The most likely tokens and their log probability, at this token position.
@@ -1107,7 +1108,7 @@ public class OpenAiApi {
public record TopLogProbs(// @formatter:off
@JsonProperty("token") String token,
@JsonProperty("logprob") Float logprob,
@JsonProperty("bytes") List<Integer> probBytes) {// @formatter:on
@JsonProperty("bytes") List<Integer> probBytes) { // @formatter:on
}
}
@@ -1133,7 +1134,7 @@ public class OpenAiApi {
@JsonProperty("prompt_tokens") Integer promptTokens,
@JsonProperty("total_tokens") Integer totalTokens,
@JsonProperty("prompt_tokens_details") PromptTokensDetails promptTokensDetails,
@JsonProperty("completion_tokens_details") CompletionTokenDetails completionTokenDetails) {// @formatter:on
@JsonProperty("completion_tokens_details") CompletionTokenDetails completionTokenDetails) { // @formatter:on
public Usage(Integer completionTokens, Integer promptTokens, Integer totalTokens) {
this(completionTokens, promptTokens, totalTokens, null, null);
@@ -1146,7 +1147,7 @@ public class OpenAiApi {
*/
@JsonInclude(Include.NON_NULL)
public record PromptTokensDetails(// @formatter:off
@JsonProperty("cached_tokens") Integer cachedTokens) {// @formatter:on
@JsonProperty("cached_tokens") Integer cachedTokens) { // @formatter:on
}
/**
@@ -1156,7 +1157,7 @@ public class OpenAiApi {
*/
@JsonInclude(Include.NON_NULL)
public record CompletionTokenDetails(// @formatter:off
@JsonProperty("reasoning_tokens") Integer reasoningTokens) {// @formatter:on
@JsonProperty("reasoning_tokens") Integer reasoningTokens) { // @formatter:on
}
}
@@ -1186,7 +1187,7 @@ public class OpenAiApi {
@JsonProperty("model") String model,
@JsonProperty("system_fingerprint") String systemFingerprint,
@JsonProperty("object") String object,
@JsonProperty("usage") Usage usage) {// @formatter:on
@JsonProperty("usage") Usage usage) { // @formatter:on
/**
* Chat completion choice.
@@ -1201,7 +1202,7 @@ public class OpenAiApi {
@JsonProperty("finish_reason") ChatCompletionFinishReason finishReason,
@JsonProperty("index") Integer index,
@JsonProperty("delta") ChatCompletionMessage delta,
@JsonProperty("logprobs") LogProbs logprobs) {// @formatter:on
@JsonProperty("logprobs") LogProbs logprobs) { // @formatter:on
}
}
@@ -1218,7 +1219,7 @@ public class OpenAiApi {
public record Embedding(// @formatter:off
@JsonProperty("index") Integer index,
@JsonProperty("embedding") float[] embedding,
@JsonProperty("object") String object) {// @formatter:on
@JsonProperty("object") String object) { // @formatter:on
/**
* Create an embedding with the given index, embedding and object type set to
@@ -1255,7 +1256,7 @@ public class OpenAiApi {
@JsonProperty("model") String model,
@JsonProperty("encoding_format") String encodingFormat,
@JsonProperty("dimensions") Integer dimensions,
@JsonProperty("user") String user) {// @formatter:on
@JsonProperty("user") String user) { // @formatter:on
/**
* Create an embedding request with the given input, model and encoding format set
@@ -1292,7 +1293,7 @@ public class OpenAiApi {
@JsonProperty("object") String object,
@JsonProperty("data") List<T> data,
@JsonProperty("model") String model,
@JsonProperty("usage") Usage usage) {// @formatter:on
@JsonProperty("usage") Usage usage) { // @formatter:on
}
}

View File

@@ -256,11 +256,13 @@ public class OpenAiAudioApi {
/**
* The latest text to speech model, optimized for speed.
*/
@JsonProperty("tts-1") TTS_1("tts-1"),
@JsonProperty("tts-1")
TTS_1("tts-1"),
/**
* The latest text to speech model, optimized for quality.
*/
@JsonProperty("tts-1-hd") TTS_1_HD("tts-1-hd");
@JsonProperty("tts-1-hd")
TTS_1_HD("tts-1-hd");
// @formatter:on
public final String value;
@@ -286,7 +288,8 @@ public class OpenAiAudioApi {
public enum WhisperModel {
// @formatter:off
@JsonProperty("whisper-1") WHISPER_1("whisper-1");
@JsonProperty("whisper-1")
WHISPER_1("whisper-1");
// @formatter:on
public final String value;
@@ -308,11 +311,16 @@ public class OpenAiAudioApi {
public enum TranscriptResponseFormat {
// @formatter:off
@JsonProperty("json") JSON("json", StructuredResponse.class),
@JsonProperty("text") TEXT("text", String.class),
@JsonProperty("srt") SRT("srt", String.class),
@JsonProperty("verbose_json") VERBOSE_JSON("verbose_json", StructuredResponse.class),
@JsonProperty("vtt") VTT("vtt", String.class);
@JsonProperty("json")
JSON("json", StructuredResponse.class),
@JsonProperty("text")
TEXT("text", String.class),
@JsonProperty("srt")
SRT("srt", String.class),
@JsonProperty("verbose_json")
VERBOSE_JSON("verbose_json", StructuredResponse.class),
@JsonProperty("vtt")
VTT("vtt", String.class);
// @formatter:on
public final String value;
@@ -373,17 +381,23 @@ public class OpenAiAudioApi {
public enum Voice {
// @formatter:off
@JsonProperty("alloy") ALLOY("alloy"),
@JsonProperty("echo") ECHO("echo"),
@JsonProperty("fable") FABLE("fable"),
@JsonProperty("onyx") ONYX("onyx"),
@JsonProperty("nova") NOVA("nova"),
@JsonProperty("shimmer") SHIMMER("shimmer");
@JsonProperty("alloy")
ALLOY("alloy"),
@JsonProperty("echo")
ECHO("echo"),
@JsonProperty("fable")
FABLE("fable"),
@JsonProperty("onyx")
ONYX("onyx"),
@JsonProperty("nova")
NOVA("nova"),
@JsonProperty("shimmer")
SHIMMER("shimmer");
// @formatter:on
public final String value;
private Voice(String value) {
Voice(String value) {
this.value = value;
}
@@ -400,10 +414,14 @@ public class OpenAiAudioApi {
public enum AudioResponseFormat {
// @formatter:off
@JsonProperty("mp3") MP3("mp3"),
@JsonProperty("opus") OPUS("opus"),
@JsonProperty("aac") AAC("aac"),
@JsonProperty("flac") FLAC("flac");
@JsonProperty("mp3")
MP3("mp3"),
@JsonProperty("opus")
OPUS("opus"),
@JsonProperty("aac")
AAC("aac"),
@JsonProperty("flac")
FLAC("flac");
// @formatter:on
public final String value;
@@ -511,8 +529,10 @@ public class OpenAiAudioApi {
public enum GranularityType {
// @formatter:off
@JsonProperty("word") WORD("word"),
@JsonProperty("segment") SEGMENT("segment");
@JsonProperty("word")
WORD("word"),
@JsonProperty("segment")
SEGMENT("segment");
// @formatter:on
public final String value;

View File

@@ -139,7 +139,7 @@ public class OpenAiImageApi {
// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
public record OpenAiImageRequest (
public record OpenAiImageRequest(
@JsonProperty("prompt") String prompt,
@JsonProperty("model") String model,
@JsonProperty("n") Integer n,

View File

@@ -77,7 +77,7 @@ public class OpenAiModerationApi {
// @formatter:off
@JsonInclude(JsonInclude.Include.NON_NULL)
public record OpenAiModerationRequest (
public record OpenAiModerationRequest(
@JsonProperty("input") String prompt,
@JsonProperty("model") String model
) {

View File

@@ -31,4 +31,4 @@ public class OpenAiApiClientErrorException extends RuntimeException {
super(message, cause);
}
}
}

View File

@@ -31,4 +31,8 @@ public final class OpenAiApiConstants {
public static final String PROVIDER_NAME = AiProvider.OPENAI.value();
private OpenAiApiConstants() {
}
}

View File

@@ -51,4 +51,4 @@ public interface StreamingSpeechModel extends StreamingModel<SpeechPrompt, Speec
@Override
Flux<SpeechResponse> stream(SpeechPrompt prompt);
}
}

View File

@@ -47,10 +47,14 @@ import static org.springframework.ai.openai.metadata.support.OpenAiApiResponseHe
* @author Christian Tzolov
* @since 0.7.0
*/
public class OpenAiResponseHeaderExtractor {
public final class OpenAiResponseHeaderExtractor {
private static final Logger logger = LoggerFactory.getLogger(OpenAiResponseHeaderExtractor.class);
private OpenAiResponseHeaderExtractor() {
}
public static RateLimit extractAiResponseHeaders(ResponseEntity<?> response) {
Long requestsLimit = getHeaderAsLong(response, REQUESTS_LIMIT_HEADER.getName());

View File

@@ -70,7 +70,7 @@ public class ChatCompletionRequestTests {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName(TOOL_FUNCTION_NAME)
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build()),
false);
@@ -97,7 +97,7 @@ public class ChatCompletionRequestTests {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName(TOOL_FUNCTION_NAME)
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build());

View File

@@ -25,8 +25,6 @@ import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.springframework.ai.aot.AiRuntimeHints.findJsonAnnotatedClassesInPackage;
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
class OpenAiRuntimeHintsTests {
@@ -36,9 +34,11 @@ class OpenAiRuntimeHintsTests {
OpenAiRuntimeHints openAiRuntimeHints = new OpenAiRuntimeHints();
openAiRuntimeHints.registerHints(runtimeHints, null);
Set<TypeReference> jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage(OpenAiApi.class);
Set<TypeReference> jsonAnnotatedClasses = org.springframework.ai.aot.AiRuntimeHints
.findJsonAnnotatedClassesInPackage(OpenAiApi.class);
for (TypeReference jsonAnnotatedClass : jsonAnnotatedClasses) {
assertThat(runtimeHints).matches(reflection().onType(jsonAnnotatedClass));
assertThat(runtimeHints).matches(org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection()
.onType(jsonAnnotatedClass));
}
}

View File

@@ -65,7 +65,7 @@ public class MockWeatherService implements Function<MockWeatherService.Request,
*/
public final String unitName;
private Unit(String text) {
Unit(String text) {
this.unitName = text;
}

View File

@@ -138,7 +138,7 @@ public class OpenAiApiToolFunctionCallIT {
ResponseEntity<ChatCompletion> chatCompletion2 = this.completionApi
.chatCompletionEntity(functionResponseRequest);
this.logger.info("Final response: " + chatCompletion2.getBody());
logger.info("Final response: " + chatCompletion2.getBody());
assertThat(chatCompletion2.getBody().choices()).isNotEmpty();
@@ -147,11 +147,8 @@ public class OpenAiApiToolFunctionCallIT {
.containsAnyOf("30.0°C", "30°C");
assertThat(chatCompletion2.getBody().choices().get(0).message().content()).contains("Tokyo")
.containsAnyOf("10.0°C", "10°C");
;
assertThat(chatCompletion2.getBody().choices().get(0).message().content()).contains("Paris")
.containsAnyOf("15.0°C", "15°C");
;
}
}

View File

@@ -130,24 +130,24 @@ public class OpenAiTranscriptionModelWithTranscriptionResponseMetadataTests {
private String getJson() {
return """
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "I surrender!"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "I surrender!"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
""";
}

View File

@@ -29,12 +29,11 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
/**
* Unit Tests for {@link TranscriptionModel}.
@@ -54,11 +53,11 @@ class TranscriptionModelTests {
// Create a mock Transcript
AudioTranscription transcript = Mockito.mock(AudioTranscription.class);
when(transcript.getOutput()).thenReturn(mockTranscription);
given(transcript.getOutput()).willReturn(mockTranscription);
// Create a mock TranscriptionResponse with the mock Transcript
AudioTranscriptionResponse response = Mockito.mock(AudioTranscriptionResponse.class);
when(response.getResult()).thenReturn(transcript);
given(response.getResult()).willReturn(transcript);
// Transcript transcript = spy(new Transcript(responseMessage));
// TranscriptionResponse response = spy(new
@@ -66,16 +65,14 @@ class TranscriptionModelTests {
doCallRealMethod().when(mockClient).call(any(Resource.class));
doAnswer(invocationOnMock -> {
AudioTranscriptionPrompt transcriptionRequest = invocationOnMock.getArgument(0);
given(mockClient.call(any(AudioTranscriptionPrompt.class))).will(invocation -> {
AudioTranscriptionPrompt transcriptionRequest = invocation.getArgument(0);
assertThat(transcriptionRequest).isNotNull();
assertThat(transcriptionRequest.getInstructions()).isEqualTo(mockAudioFile);
return response;
}).when(mockClient).call(any(AudioTranscriptionPrompt.class));
});
assertThat(mockClient.call(mockAudioFile)).isEqualTo(mockTranscription);

View File

@@ -44,7 +44,7 @@ import org.springframework.util.MimeTypeUtils;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.BDDMockito.given;
/**
* @author Christian Tzolov
@@ -65,7 +65,7 @@ public class MessageTypeContentTests {
ArgumentCaptor<MultiValueMap<String, String>> headersCaptor;
Flux<ChatCompletionChunk> fluxResponse = Flux
.generate(() -> new ChatCompletionChunk("id", List.of(), 0l, "model", "fp", "object", null), (state, sink) -> {
.generate(() -> new ChatCompletionChunk("id", List.of(), 0L, "model", "fp", "object", null), (state, sink) -> {
sink.next(state);
sink.complete();
return state;
@@ -79,8 +79,8 @@ public class MessageTypeContentTests {
@Test
public void systemMessageSimpleContentType() {
when(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.thenReturn(Mockito.mock(ResponseEntity.class));
given(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.willReturn(Mockito.mock(ResponseEntity.class));
this.chatModel.call(new Prompt(List.of(new SystemMessage("test message"))));
@@ -91,8 +91,8 @@ public class MessageTypeContentTests {
@Test
public void userMessageSimpleContentType() {
when(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.thenReturn(Mockito.mock(ResponseEntity.class));
given(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.willReturn(Mockito.mock(ResponseEntity.class));
this.chatModel.call(new Prompt(List.of(new UserMessage("test message"))));
@@ -102,8 +102,8 @@ public class MessageTypeContentTests {
@Test
public void streamUserMessageSimpleContentType() {
when(this.openAiApi.chatCompletionStream(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.thenReturn(this.fluxResponse);
given(this.openAiApi.chatCompletionStream(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.willReturn(this.fluxResponse);
this.chatModel.stream(new Prompt(List.of(new UserMessage("test message")))).subscribe();
@@ -122,8 +122,8 @@ public class MessageTypeContentTests {
@Test
public void userMessageWithMediaType() throws MalformedURLException {
when(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.thenReturn(Mockito.mock(ResponseEntity.class));
given(this.openAiApi.chatCompletionEntity(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.willReturn(Mockito.mock(ResponseEntity.class));
URL mediaUrl = new URL("http://test");
this.chatModel.call(new Prompt(
@@ -135,8 +135,8 @@ public class MessageTypeContentTests {
@Test
public void streamUserMessageWithMediaType() throws MalformedURLException {
when(this.openAiApi.chatCompletionStream(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.thenReturn(this.fluxResponse);
given(this.openAiApi.chatCompletionStream(this.pomptCaptor.capture(), this.headersCaptor.capture()))
.willReturn(this.fluxResponse);
URL mediaUrl = new URL("http://test");
this.chatModel

View File

@@ -33,7 +33,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
/**
* @author Christian Tzolov
@@ -48,9 +48,8 @@ public class OpenAiChatModeAdditionalHttpHeadersIT {
@Test
void additionalApiKeyHeader() {
assertThrows(NonTransientAiException.class, () -> {
this.openAiChatModel.call("Tell me a joke");
});
assertThatThrownBy(() -> this.openAiChatModel.call("Tell me a joke"))
.isInstanceOf(NonTransientAiException.class);
// Use the additional headers to override the Api Key.
// Mind that you have to prefix the Api Key with the "Bearer " prefix.

View File

@@ -66,7 +66,7 @@ class OpenAiChatModelFunctionCallingIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build());
}
@@ -102,7 +102,7 @@ class OpenAiChatModelFunctionCallingIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(biFunction)
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.withToolContext(Map.of("sessionId", "123"))
.build());
@@ -128,7 +128,7 @@ class OpenAiChatModelFunctionCallingIT {
.withFunctionCallbacks(List.of((FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build())))
.build());
}
@@ -163,7 +163,7 @@ class OpenAiChatModelFunctionCallingIT {
.withFunctionCallbacks(List.of((FunctionCallbackWrapper.builder(biFunction)
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build())))
.withToolContext(Map.of("sessionId", "123"))
.build();

View File

@@ -121,9 +121,7 @@ public class OpenAiChatModelIT extends AbstractIT {
});
chatResponseFlux.subscribe();
assertThat(latch.await(120, TimeUnit.SECONDS)).isTrue();
IntStream.rangeClosed(1, 1000).forEach(n -> {
assertThat(answer).contains(String.valueOf(n));
});
IntStream.rangeClosed(1, 1000).forEach(n -> assertThat(answer).contains(String.valueOf(n)));
}
@Test
@@ -333,7 +331,7 @@ public class OpenAiChatModelIT extends AbstractIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();
@@ -358,7 +356,7 @@ public class OpenAiChatModelIT extends AbstractIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();

View File

@@ -89,7 +89,7 @@ public class OpenAiChatModelResponseFormatIT {
String content = response.getResult().getOutput().getContent();
this.logger.info("Response content: {}", content);
logger.info("Response content: {}", content);
assertThat(isValidJson(content)).isTrue();
}
@@ -132,7 +132,7 @@ public class OpenAiChatModelResponseFormatIT {
String content = response.getResult().getOutput().getContent();
this.logger.info("Response content: {}", content);
logger.info("Response content: {}", content);
assertThat(isValidJson(content)).isTrue();
}
@@ -172,7 +172,7 @@ public class OpenAiChatModelResponseFormatIT {
String content = response.getResult().getOutput().getContent();
this.logger.info("Response content: {}", content);
logger.info("Response content: {}", content);
MathReasoning mathReasoning = outputConverter.convert(content);

View File

@@ -143,23 +143,23 @@ public class OpenAiChatModelWithChatResponseMetadataTests {
private String getJson() {
return """
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"choices": [{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "I surrender!"
"role": "assistant",
"content": "I surrender!"
},
"finish_reason": "stop"
}],
"usage": {
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
}
""";
}

View File

@@ -52,8 +52,6 @@ public class OpenAiCompatibleChatModelIT {
return OpenAiChatOptions.builder().withModel(modelName).build();
}
;
static Stream<ChatModel> openAiCompatibleApis() {
Stream.Builder<ChatModel> builder = Stream.builder();

View File

@@ -155,19 +155,19 @@ public class OpenAiPaymentTransactionIT {
}
private AdvisedRequest before(AdvisedRequest request) {
this.logger.info("System text: \n" + request.systemText());
this.logger.info("System params: " + request.systemParams());
this.logger.info("User text: \n" + request.userText());
this.logger.info("User params:" + request.userParams());
this.logger.info("Function names: " + request.functionNames());
logger.info("System text: \n" + request.systemText());
logger.info("System params: " + request.systemParams());
logger.info("User text: \n" + request.userText());
logger.info("User params:" + request.userParams());
logger.info("Function names: " + request.functionNames());
this.logger.info("Options: " + request.chatOptions().toString());
logger.info("Options: " + request.chatOptions().toString());
return request;
}
private void observeAfter(AdvisedResponse advisedResponse) {
this.logger.info("Response: " + advisedResponse.response());
logger.info("Response: " + advisedResponse.response());
}
}

View File

@@ -72,7 +72,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.when;
import static org.mockito.BDDMockito.given;
/**
* @author Christian Tzolov
@@ -124,13 +124,13 @@ public class OpenAiRetryTests {
var choice = new ChatCompletion.Choice(ChatCompletionFinishReason.STOP, 0,
new ChatCompletionMessage("Response", Role.ASSISTANT), null);
ChatCompletion expectedChatCompletion = new ChatCompletion("id", List.of(choice), 666l, "model", null, null,
ChatCompletion expectedChatCompletion = new ChatCompletion("id", List.of(choice), 666L, "model", null, null,
new OpenAiApi.Usage(10, 10, 10));
when(this.openAiApi.chatCompletionEntity(isA(ChatCompletionRequest.class), any()))
.thenThrow(new TransientAiException("Transient Error 1"))
.thenThrow(new TransientAiException("Transient Error 2"))
.thenReturn(ResponseEntity.of(Optional.of(expectedChatCompletion)));
given(this.openAiApi.chatCompletionEntity(isA(ChatCompletionRequest.class), any()))
.willThrow(new TransientAiException("Transient Error 1"))
.willThrow(new TransientAiException("Transient Error 2"))
.willReturn(ResponseEntity.of(Optional.of(expectedChatCompletion)));
var result = this.chatModel.call(new Prompt("text"));
@@ -142,8 +142,8 @@ public class OpenAiRetryTests {
@Test
public void openAiChatNonTransientError() {
when(this.openAiApi.chatCompletionEntity(isA(ChatCompletionRequest.class), any()))
.thenThrow(new RuntimeException("Non Transient Error"));
given(this.openAiApi.chatCompletionEntity(isA(ChatCompletionRequest.class), any()))
.willThrow(new RuntimeException("Non Transient Error"));
assertThrows(RuntimeException.class, () -> this.chatModel.call(new Prompt("text")));
}
@@ -153,13 +153,13 @@ public class OpenAiRetryTests {
var choice = new ChatCompletionChunk.ChunkChoice(ChatCompletionFinishReason.STOP, 0,
new ChatCompletionMessage("Response", Role.ASSISTANT), null);
ChatCompletionChunk expectedChatCompletion = new ChatCompletionChunk("id", List.of(choice), 666l, "model", null,
ChatCompletionChunk expectedChatCompletion = new ChatCompletionChunk("id", List.of(choice), 666L, "model", null,
null, null);
when(this.openAiApi.chatCompletionStream(isA(ChatCompletionRequest.class), any()))
.thenThrow(new TransientAiException("Transient Error 1"))
.thenThrow(new TransientAiException("Transient Error 2"))
.thenReturn(Flux.just(expectedChatCompletion));
given(this.openAiApi.chatCompletionStream(isA(ChatCompletionRequest.class), any()))
.willThrow(new TransientAiException("Transient Error 1"))
.willThrow(new TransientAiException("Transient Error 2"))
.willReturn(Flux.just(expectedChatCompletion));
var result = this.chatModel.stream(new Prompt("text"));
@@ -172,8 +172,8 @@ public class OpenAiRetryTests {
@Test
@Disabled("Currently stream() does not implmement retry")
public void openAiChatStreamNonTransientError() {
when(this.openAiApi.chatCompletionStream(isA(ChatCompletionRequest.class), any()))
.thenThrow(new RuntimeException("Non Transient Error"));
given(this.openAiApi.chatCompletionStream(isA(ChatCompletionRequest.class), any()))
.willThrow(new RuntimeException("Non Transient Error"));
assertThrows(RuntimeException.class, () -> this.chatModel.stream(new Prompt("text")).subscribe());
}
@@ -183,10 +183,10 @@ public class OpenAiRetryTests {
EmbeddingList<Embedding> expectedEmbeddings = new EmbeddingList<>("list",
List.of(new Embedding(0, new float[] { 9.9f, 8.8f })), "model", new OpenAiApi.Usage(10, 10, 10));
when(this.openAiApi.embeddings(isA(EmbeddingRequest.class)))
.thenThrow(new TransientAiException("Transient Error 1"))
.thenThrow(new TransientAiException("Transient Error 2"))
.thenReturn(ResponseEntity.of(Optional.of(expectedEmbeddings)));
given(this.openAiApi.embeddings(isA(EmbeddingRequest.class)))
.willThrow(new TransientAiException("Transient Error 1"))
.willThrow(new TransientAiException("Transient Error 2"))
.willReturn(ResponseEntity.of(Optional.of(expectedEmbeddings)));
var result = this.embeddingModel
.call(new org.springframework.ai.embedding.EmbeddingRequest(List.of("text1", "text2"), null));
@@ -199,8 +199,8 @@ public class OpenAiRetryTests {
@Test
public void openAiEmbeddingNonTransientError() {
when(this.openAiApi.embeddings(isA(EmbeddingRequest.class)))
.thenThrow(new RuntimeException("Non Transient Error"));
given(this.openAiApi.embeddings(isA(EmbeddingRequest.class)))
.willThrow(new RuntimeException("Non Transient Error"));
assertThrows(RuntimeException.class, () -> this.embeddingModel
.call(new org.springframework.ai.embedding.EmbeddingRequest(List.of("text1", "text2"), null)));
}
@@ -210,10 +210,10 @@ public class OpenAiRetryTests {
var expectedResponse = new StructuredResponse("nl", 6.7f, "Transcription Text", List.of(), List.of());
when(this.openAiAudioApi.createTranscription(isA(TranscriptionRequest.class), isA(Class.class)))
.thenThrow(new TransientAiException("Transient Error 1"))
.thenThrow(new TransientAiException("Transient Error 2"))
.thenReturn(ResponseEntity.of(Optional.of(expectedResponse)));
given(this.openAiAudioApi.createTranscription(isA(TranscriptionRequest.class), isA(Class.class)))
.willThrow(new TransientAiException("Transient Error 1"))
.willThrow(new TransientAiException("Transient Error 2"))
.willReturn(ResponseEntity.of(Optional.of(expectedResponse)));
AudioTranscriptionResponse result = this.audioTranscriptionModel
.call(new AudioTranscriptionPrompt(new ClassPathResource("speech/jfk.flac")));
@@ -226,8 +226,8 @@ public class OpenAiRetryTests {
@Test
public void openAiAudioTranscriptionNonTransientError() {
when(this.openAiAudioApi.createTranscription(isA(TranscriptionRequest.class), isA(Class.class)))
.thenThrow(new RuntimeException("Transient Error 1"));
given(this.openAiAudioApi.createTranscription(isA(TranscriptionRequest.class), isA(Class.class)))
.willThrow(new RuntimeException("Transient Error 1"));
assertThrows(RuntimeException.class, () -> this.audioTranscriptionModel
.call(new AudioTranscriptionPrompt(new ClassPathResource("speech/jfk.flac"))));
}
@@ -235,12 +235,12 @@ public class OpenAiRetryTests {
@Test
public void openAiImageTransientError() {
var expectedResponse = new OpenAiImageResponse(678l, List.of(new Data("url678", "b64", "prompt")));
var expectedResponse = new OpenAiImageResponse(678L, List.of(new Data("url678", "b64", "prompt")));
when(this.openAiImageApi.createImage(isA(OpenAiImageRequest.class)))
.thenThrow(new TransientAiException("Transient Error 1"))
.thenThrow(new TransientAiException("Transient Error 2"))
.thenReturn(ResponseEntity.of(Optional.of(expectedResponse)));
given(this.openAiImageApi.createImage(isA(OpenAiImageRequest.class)))
.willThrow(new TransientAiException("Transient Error 1"))
.willThrow(new TransientAiException("Transient Error 2"))
.willReturn(ResponseEntity.of(Optional.of(expectedResponse)));
var result = this.imageModel.call(new ImagePrompt(List.of(new ImageMessage("Image Message"))));
@@ -252,8 +252,8 @@ public class OpenAiRetryTests {
@Test
public void openAiImageNonTransientError() {
when(this.openAiImageApi.createImage(isA(OpenAiImageRequest.class)))
.thenThrow(new RuntimeException("Transient Error 1"));
given(this.openAiImageApi.createImage(isA(OpenAiImageRequest.class)))
.willThrow(new RuntimeException("Transient Error 1"));
assertThrows(RuntimeException.class,
() -> this.imageModel.call(new ImagePrompt(List.of(new ImageMessage("Image Message")))));
}

View File

@@ -121,7 +121,8 @@ class OpenAiChatClientIT extends AbstractIT {
.user(u -> u.text("List five {subject}")
.param("subject", "ice cream flavors"))
.call()
.entity(new ParameterizedTypeReference<List<String>>() {});
.entity(new ParameterizedTypeReference<List<String>>() {
});
// @formatter:on
logger.info(collection.toString());

View File

@@ -190,8 +190,8 @@ class OpenAiChatClientMultipleFunctionCallsIT extends AbstractIT {
// @formatter:off
String response = ChatClient.builder(this.chatModel)
.defaultFunction("getCurrentWeather", "Get the weather in location", biFunction)
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
.build()
.defaultUser(u -> u.text("What's the weather like in San Francisco, Tokyo, and Paris?"))
.build()
.prompt()
.toolContext(Map.of("sessionId", "123"))
.call().content();

View File

@@ -253,7 +253,7 @@ class GroqWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();
@@ -276,7 +276,7 @@ class GroqWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();

View File

@@ -254,7 +254,7 @@ class MistralWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();
@@ -279,7 +279,7 @@ class MistralWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();

View File

@@ -249,7 +249,7 @@ class NvidiaWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();
@@ -272,7 +272,7 @@ class NvidiaWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();

View File

@@ -272,7 +272,7 @@ class OllamaWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();
@@ -296,7 +296,7 @@ class OllamaWithOpenAiChatModelIT {
.withFunctionCallbacks(List.of(FunctionCallbackWrapper.builder(new MockWeatherService())
.withName("getCurrentWeather")
.withDescription("Get the weather in location")
.withResponseConverter((response) -> "" + response.temp() + response.unit())
.withResponseConverter(response -> "" + response.temp() + response.unit())
.build()))
.build();

View File

@@ -78,11 +78,11 @@ class EmbeddingIT extends AbstractIT {
void embeddingBatchDocumentsThatExceedTheLimit() throws Exception {
assertThat(this.embeddingModel).isNotNull();
String contentAsString = this.resource.getContentAsString(StandardCharsets.UTF_8);
assertThatThrownBy(() -> {
this.embeddingModel.embed(List.of(new Document("Hello World"), new Document(contentAsString)),
OpenAiEmbeddingOptions.builder().withModel(OpenAiApi.DEFAULT_EMBEDDING_MODEL).build(),
new TokenCountBatchingStrategy());
}).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(
() -> this.embeddingModel.embed(List.of(new Document("Hello World"), new Document(contentAsString)),
OpenAiEmbeddingOptions.builder().withModel(OpenAiApi.DEFAULT_EMBEDDING_MODEL).build(),
new TokenCountBatchingStrategy()))
.isInstanceOf(IllegalArgumentException.class);
}
@Test

View File

@@ -113,17 +113,17 @@ public class OpenAiImageModelWithImageResponseMetadataTests {
private String getJson() {
return """
{
"created": 1589478378,
"data": [
{
"created": 1589478378,
"data": [
{
"url": "https://upload.wikimedia.org/wikipedia/commons/4/4e/Mini_Golden_Doodle.jpg"
"url": "https://upload.wikimedia.org/wikipedia/commons/4/4e/Mini_Golden_Doodle.jpg"
},
{
"url": "https://upload.wikimedia.org/wikipedia/commons/8/85/Goldendoodle_puppy_Marty.jpg"
"url": "https://upload.wikimedia.org/wikipedia/commons/8/85/Goldendoodle_puppy_Marty.jpg"
}
]
}
]
}
""";
}

View File

@@ -139,40 +139,40 @@ public class OpenAiModerationModelTests {
private String getJson() {
return """
{
"id": "modr-XXXXX",
"model": "text-moderation-005",
"results": [
{
"flagged": true,
"categories": {
"sexual": false,
"hate": false,
"harassment": false,
"self-harm": false,
"sexual/minors": false,
"hate/threatening": false,
"violence/graphic": false,
"self-harm/intent": false,
"self-harm/instructions": false,
"harassment/threatening": true,
"violence": true
},
"category_scores": {
"sexual": 1.2282071e-06,
"hate": 0.010696256,
"harassment": 0.29842457,
"self-harm": 1.5236925e-08,
"sexual/minors": 5.7246268e-08,
"hate/threatening": 0.0060676364,
"violence/graphic": 4.435014e-06,
"self-harm/intent": 8.098441e-10,
"self-harm/instructions": 2.8498655e-11,
"harassment/threatening": 0.63055265,
"violence": 0.99011886
}
}
]
{
"id": "modr-XXXXX",
"model": "text-moderation-005",
"results": [
{
"flagged": true,
"categories": {
"sexual": false,
"hate": false,
"harassment": false,
"self-harm": false,
"sexual/minors": false,
"hate/threatening": false,
"violence/graphic": false,
"self-harm/intent": false,
"self-harm/instructions": false,
"harassment/threatening": true,
"violence": true
},
"category_scores": {
"sexual": 1.2282071e-06,
"hate": 0.010696256,
"harassment": 0.29842457,
"self-harm": 1.5236925e-08,
"sexual/minors": 5.7246268e-08,
"hate/threatening": 0.0060676364,
"violence/graphic": 4.435014e-06,
"self-harm/intent": 8.098441e-10,
"self-harm/instructions": 2.8498655e-11,
"harassment/threatening": 0.63055265,
"violence": 0.99011886
}
}
]
}
""";
}

View File

@@ -112,4 +112,4 @@ public abstract class AbstractIT {
}
}
}
}

View File

@@ -100,7 +100,7 @@
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck" />
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck">
<property name="excludes"
value="org.springframework.ai.image.observation.ImageModelObservationDocumentation.*, org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.*, org.springframework.aot.hint.predicate.RuntimeHintsPredicates.*, org.springframework.ai.vectorstore.filter.Filter.ExpressionType.*, org.springframework.ai.chat.observation.ChatModelObservationDocumentation.*, org.assertj.core.api.AssertionsForClassTypes.*, org.junit.jupiter.api.Assertions.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*" />
value="org.springframework.ai.aot.AiRuntimeHints.*, org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders.*, org.springframework.ai.image.observation.ImageModelObservationDocumentation.*, org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.*, org.springframework.aot.hint.predicate.RuntimeHintsPredicates.*, org.springframework.ai.vectorstore.filter.Filter.ExpressionType.*, org.springframework.ai.chat.observation.ChatModelObservationDocumentation.*, org.assertj.core.api.AssertionsForClassTypes.*, org.junit.jupiter.api.Assertions.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*" />
</module>
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck" />
<module name="com.puppycrawl.tools.checkstyle.checks.imports.RedundantImportCheck" />