Fix checkstyle errors

This commit is contained in:
Ilayaperumal Gopinathan
2024-12-21 01:27:08 +00:00
parent 1c156e9fdc
commit 7fe3b389c4
78 changed files with 566 additions and 433 deletions

View File

@@ -29,8 +29,6 @@ import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.model.Media;
import org.springframework.util.MimeType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -62,6 +60,7 @@ import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionMessage.C
import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.mistralai.api.MistralAiApi.ChatCompletionRequest;
import org.springframework.ai.mistralai.metadata.MistralAiUsage;
import org.springframework.ai.model.Media;
import org.springframework.ai.model.ModelOptionsUtils;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallbackResolver;
@@ -71,6 +70,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeType;
/**
* Represents a Mistral AI Chat Model.

View File

@@ -16,12 +16,22 @@
package org.springframework.ai.mistralai;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
@@ -46,15 +56,6 @@ import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.MimeTypeUtils;
import reactor.core.publisher.Flux;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -24,7 +24,6 @@ import java.util.function.Function;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.slf4j.Logger;

View File

@@ -672,15 +672,15 @@ public class OllamaApi {
}
public Duration getTotalDuration() {
return (this.totalDuration() != null)? Duration.ofNanos(this.totalDuration()) : null;
return (this.totalDuration() != null) ? Duration.ofNanos(this.totalDuration()) : null;
}
public Duration getLoadDuration() {
return (this.loadDuration() != null)? Duration.ofNanos(this.loadDuration()) : null;
return (this.loadDuration() != null) ? Duration.ofNanos(this.loadDuration()) : null;
}
public Duration getPromptEvalDuration() {
return (this.promptEvalDuration() != null)? Duration.ofNanos(this.promptEvalDuration()) : null;
return (this.promptEvalDuration() != null) ? Duration.ofNanos(this.promptEvalDuration()) : null;
}
public Duration getEvalDuration() {

View File

@@ -1,18 +1,19 @@
/*
* 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.
*/
* 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.ollama.api;
import java.time.Instant;
@@ -28,6 +29,10 @@ import org.springframework.util.CollectionUtils;
*/
public final class OllamaApiHelper {
private OllamaApiHelper() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
/**
* @param ollamaChatResponse the Ollama chat response chunk to check
* @return true if the chunk is a streaming tool call.

View File

@@ -117,7 +117,7 @@ public class OllamaModelManager {
logger.info("Pulling the '{}' model - Status: {}", modelName, progressResponses.get(progressResponses.size() - 1).status());
}
})
.takeUntil(progressResponses ->
.takeUntil(progressResponses ->
progressResponses.get(0) != null && "success".equals(progressResponses.get(0).status()))
.timeout(this.options.timeout())
.retryWhen(Retry.backoff(this.options.maxRetries(), Duration.ofSeconds(5)))

View File

@@ -1,18 +1,19 @@
/*
* 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.
*/
* 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.ollama.api;
import com.fasterxml.jackson.core.JsonProcessingException;

View File

@@ -325,7 +325,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions {
}
public List<String> getOutputModalities() {
return outputModalities;
return this.outputModalities;
}
public void setOutputModalities(List<String> modalities) {
@@ -333,7 +333,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions {
}
public AudioParameters getOutputAudio() {
return outputAudio;
return this.outputAudio;
}
public void setOutputAudio(AudioParameters audio) {

View File

@@ -16,11 +16,12 @@
package org.springframework.ai.openai;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.ai.image.ImageOptions;
import java.util.Objects;
import org.springframework.ai.image.ImageOptions;
/**
* OpenAI Image API options. OpenAiImageOptions.java

View File

@@ -960,7 +960,7 @@ public class OpenAiApi {
@JsonProperty("mp3") MP3,
/** FLAC format */
@JsonProperty("flac") FLAC,
/** OPUS format */
/** OPUS format */
@JsonProperty("opus") OPUS,
/** PCM16 format */
@JsonProperty("pcm16") PCM16,

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2024 the original author or authors.
* 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.

View File

@@ -47,7 +47,6 @@ import com.google.protobuf.util.JsonFormat;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiSafetySetting;
import reactor.core.publisher.Flux;
import org.springframework.ai.chat.messages.AssistantMessage;
@@ -77,6 +76,7 @@ import org.springframework.ai.model.function.FunctionCallbackResolver;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiConstants;
import org.springframework.ai.vertexai.gemini.common.VertexAiGeminiSafetySetting;
import org.springframework.ai.vertexai.gemini.metadata.VertexAiUsage;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.lang.NonNull;

View File

@@ -273,7 +273,7 @@ public class VertexAiGeminiChatOptions implements FunctionCallingOptions {
}
public List<VertexAiGeminiSafetySetting> getSafetySettings() {
return safetySettings;
return this.safetySettings;
}
public void setSafetySettings(List<VertexAiGeminiSafetySetting> safetySettings) {

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2024-2025 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.vertexai.gemini.common;
public class VertexAiGeminiSafetySetting {
@@ -17,7 +33,7 @@ public class VertexAiGeminiSafetySetting {
}
public int getValue() {
return value;
return this.value;
}
}
@@ -36,7 +52,7 @@ public class VertexAiGeminiSafetySetting {
}
public int getValue() {
return value;
return this.value;
}
}
@@ -56,7 +72,7 @@ public class VertexAiGeminiSafetySetting {
}
public int getValue() {
return value;
return this.value;
}
}
@@ -83,7 +99,7 @@ public class VertexAiGeminiSafetySetting {
// Getters and setters
public HarmCategory getCategory() {
return category;
return this.category;
}
public void setCategory(HarmCategory category) {
@@ -91,7 +107,7 @@ public class VertexAiGeminiSafetySetting {
}
public HarmBlockThreshold getThreshold() {
return threshold;
return this.threshold;
}
public void setThreshold(HarmBlockThreshold threshold) {
@@ -99,7 +115,7 @@ public class VertexAiGeminiSafetySetting {
}
public HarmBlockMethod getMethod() {
return method;
return this.method;
}
public void setMethod(HarmBlockMethod method) {
@@ -108,30 +124,35 @@ public class VertexAiGeminiSafetySetting {
@Override
public String toString() {
return "SafetySetting{" + "category=" + category + ", threshold=" + threshold + ", method=" + method + '}';
return "SafetySetting{" + "category=" + this.category + ", threshold=" + this.threshold + ", method="
+ this.method + '}';
}
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
VertexAiGeminiSafetySetting that = (VertexAiGeminiSafetySetting) o;
if (category != that.category)
if (this.category != that.category) {
return false;
if (threshold != that.threshold)
}
if (this.threshold != that.threshold) {
return false;
return method == that.method;
}
return this.method == that.method;
}
@Override
public int hashCode() {
int result = category != null ? category.hashCode() : 0;
result = 31 * result + (threshold != null ? threshold.hashCode() : 0);
result = 31 * result + (method != null ? method.hashCode() : 0);
int result = this.category != null ? this.category.hashCode() : 0;
result = 31 * result + (this.threshold != null ? this.threshold.hashCode() : 0);
result = 31 * result + (this.method != null ? this.method.hashCode() : 0);
return result;
}
@@ -159,7 +180,7 @@ public class VertexAiGeminiSafetySetting {
}
public VertexAiGeminiSafetySetting build() {
return new VertexAiGeminiSafetySetting(category, threshold, method);
return new VertexAiGeminiSafetySetting(this.category, this.threshold, this.method);
}
}

View File

@@ -21,7 +21,6 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.ai.embedding.EmbeddingOptions;
import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.ai.watsonx.api.WatsonxAiApi;

View File

@@ -140,7 +140,7 @@ public final class RetrievalAugmentationAdvisor implements BaseAdvisor {
* documents.
*/
private Map.Entry<Query, List<Document>> getDocumentsForQuery(Query query) {
List<Document> documents = documentRetriever.retrieve(query);
List<Document> documents = this.documentRetriever.retrieve(query);
return Map.entry(query, documents);
}

View File

@@ -21,7 +21,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

View File

@@ -23,7 +23,11 @@ import org.springframework.ai.chat.model.ChatResponse;
*
* @author Ilayaperumal Gopinathan
*/
public class UsageUtils {
public final class UsageUtils {
private UsageUtils() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
/**
* Accumulate usage tokens from the previous chat response to the current usage

View File

@@ -49,7 +49,7 @@ public enum DocumentMetadata {
@Override
public String toString() {
return value;
return this.value;
}
}

View File

@@ -21,7 +21,6 @@ import java.util.List;
import java.util.Objects;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.Content;
/**
* Represents an evaluation request, which includes the user's text, a list of content

View File

@@ -20,7 +20,6 @@ import java.util.List;
import java.util.stream.Collectors;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.Content;
import org.springframework.util.StringUtils;
@FunctionalInterface

View File

@@ -127,7 +127,7 @@ public class FactCheckingEvaluator implements Evaluator {
String evaluationResponse = this.chatClientBuilder.build()
.prompt()
.user(userSpec -> userSpec.text(evaluationPrompt).param("document", context).param("claim", response))
.user(userSpec -> userSpec.text(this.evaluationPrompt).param("document", context).param("claim", response))
.call()
.content();

View File

@@ -1,17 +1,41 @@
package org.springframework.ai.model;
/*
* Copyright 2024-2025 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.
*/
import com.github.victools.jsonschema.generator.*;
import com.github.victools.jsonschema.generator.Module;
import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.*;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.ReflectJvmMapping;
import org.springframework.core.KotlinDetector;
package org.springframework.ai.model;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import com.github.victools.jsonschema.generator.FieldScope;
import com.github.victools.jsonschema.generator.MemberScope;
import com.github.victools.jsonschema.generator.Module;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigPart;
import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KClass;
import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter;
import kotlin.reflect.KProperty;
import kotlin.reflect.KType;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.ReflectJvmMapping;
import org.springframework.core.KotlinDetector;
public class KotlinModule implements Module {
@Override

View File

@@ -161,7 +161,7 @@ public class Media {
* Creates a new Media builder.
* @return a new Media builder instance
*/
public static Builder builder() {
public static final Builder builder() {
return new Builder();
}
@@ -228,7 +228,7 @@ public class Media {
/**
* Builder class for Media.
*/
public static class Builder {
public static final class Builder {
private String id;

View File

@@ -16,7 +16,6 @@
package org.springframework.ai.model;
import java.util.Collection;
import java.util.List;
public interface MediaContent extends Content {

View File

@@ -1,3 +1,19 @@
/*
* 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.model.function;
import java.util.function.Function;
@@ -112,4 +128,4 @@ public class DefaultCommonCallbackInvokingSpec<B extends CommonCallbackInvokingS
return this.objectMapper;
}
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.ai.moderation;
import java.util.List;
/**
* A builder class for creating instances of ModerationOptions. Use the builder() method
* to obtain a new instance of ModerationOptionsBuilder. Use the withModel() method to set

View File

@@ -16,12 +16,12 @@
package org.springframework.ai.rag;
import org.springframework.ai.chat.messages.Message;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Map;
import org.springframework.ai.chat.messages.Message;
import org.springframework.util.Assert;
/**
* Represents a query in the context of a Retrieval Augmented Generation (RAG) flow.
*
@@ -53,7 +53,7 @@ public record Query(String text, List<Message> history, Map<String, Object> cont
return new Builder();
}
public static class Builder {
public static final class Builder {
private String text;
@@ -85,7 +85,7 @@ public record Query(String text, List<Message> history, Map<String, Object> cont
}
public Query build() {
return new Query(text, history, context);
return new Query(this.text, this.history, this.context);
}
}

View File

@@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.model.Content;
import org.springframework.ai.rag.Query;
import org.springframework.ai.util.PromptAssert;
import org.springframework.lang.Nullable;

View File

@@ -16,8 +16,12 @@
package org.springframework.ai.rag.preretrieval.query.transformation;
import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
@@ -29,9 +33,6 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.stream.Collectors;
/**
* Uses a large language model to compress a conversation history and a follow-up query
* into a standalone query that captures the essence of the conversation.
@@ -132,7 +133,7 @@ public class CompressionQueryTransformer implements QueryTransformer {
}
public CompressionQueryTransformer build() {
return new CompressionQueryTransformer(chatClientBuilder, promptTemplate);
return new CompressionQueryTransformer(this.chatClientBuilder, this.promptTemplate);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.ai.rag.preretrieval.query.transformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.PromptTemplate;
@@ -79,7 +80,7 @@ public class RewriteQueryTransformer implements QueryTransformer {
var rewrittenQueryText = this.chatClient.prompt()
.user(user -> user.text(this.promptTemplate.getTemplate())
.param("target", targetSearchSystem)
.param("target", this.targetSearchSystem)
.param("query", query.text()))
.options(ChatOptions.builder().temperature(0.0).build())
.call()
@@ -126,7 +127,7 @@ public class RewriteQueryTransformer implements QueryTransformer {
}
public RewriteQueryTransformer build() {
return new RewriteQueryTransformer(chatClientBuilder, promptTemplate, targetSearchSystem);
return new RewriteQueryTransformer(this.chatClientBuilder, this.promptTemplate, this.targetSearchSystem);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.ai.rag.preretrieval.query.transformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.PromptTemplate;

View File

@@ -92,6 +92,109 @@ public final class SearchRequest {
return new Builder().topK(DEFAULT_TOP_K).similarityThresholdAll();
}
/**
* @deprecated use {@link Builder#query(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withQuery(String query) {
Assert.notNull(query, "Query can not be null.");
this.query = query;
return this;
}
/**
* @deprecated use {@link Builder#topK(int)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withTopK(int topK) {
Assert.isTrue(topK >= 0, "TopK should be positive.");
this.topK = topK;
return this;
}
/**
* @deprecated use {@link Builder#similarityThreshold(double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withSimilarityThreshold(double threshold) {
Assert.isTrue(threshold >= 0 && threshold <= 1, "Similarity threshold must be in [0,1] range.");
this.similarityThreshold = threshold;
return this;
}
/**
* @deprecated use {@link Builder#similarityThresholdAll()} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withSimilarityThresholdAll() {
return withSimilarityThreshold(SIMILARITY_THRESHOLD_ACCEPT_ALL);
}
/**
* @deprecated use {@link Builder#filterExpression(Filter.Expression)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withFilterExpression(@Nullable Filter.Expression expression) {
this.filterExpression = expression;
return this;
}
/**
* @deprecated use {@link Builder#filterExpression(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withFilterExpression(@Nullable String textExpression) {
this.filterExpression = (textExpression != null) ? new FilterExpressionTextParser().parse(textExpression)
: null;
return this;
}
public String getQuery() {
return this.query;
}
public int getTopK() {
return this.topK;
}
public double getSimilarityThreshold() {
return this.similarityThreshold;
}
@Nullable
public Filter.Expression getFilterExpression() {
return this.filterExpression;
}
public boolean hasFilterExpression() {
return this.filterExpression != null;
}
@Override
public String toString() {
return "SearchRequest{" + "query='" + this.query + '\'' + ", topK=" + this.topK + ", similarityThreshold="
+ this.similarityThreshold + ", filterExpression=" + this.filterExpression + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchRequest that = (SearchRequest) o;
return this.topK == that.topK && Double.compare(that.similarityThreshold, this.similarityThreshold) == 0
&& Objects.equals(this.query, that.query)
&& Objects.equals(this.filterExpression, that.filterExpression);
}
@Override
public int hashCode() {
return Objects.hash(this.query, this.topK, this.similarityThreshold, this.filterExpression);
}
/**
* Builder for creating the SearchRequest instance.
* @return the builder.
@@ -258,107 +361,4 @@ public final class SearchRequest {
}
/**
* @deprecated use {@link Builder#query(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withQuery(String query) {
Assert.notNull(query, "Query can not be null.");
this.query = query;
return this;
}
/**
* @deprecated use {@link Builder#topK(int)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withTopK(int topK) {
Assert.isTrue(topK >= 0, "TopK should be positive.");
this.topK = topK;
return this;
}
/**
* @deprecated use {@link Builder#similarityThreshold(double)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withSimilarityThreshold(double threshold) {
Assert.isTrue(threshold >= 0 && threshold <= 1, "Similarity threshold must be in [0,1] range.");
this.similarityThreshold = threshold;
return this;
}
/**
* @deprecated use {@link Builder#similarityThresholdAll()} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withSimilarityThresholdAll() {
return withSimilarityThreshold(SIMILARITY_THRESHOLD_ACCEPT_ALL);
}
/**
* @deprecated use {@link Builder#filterExpression(Filter.Expression)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withFilterExpression(@Nullable Filter.Expression expression) {
this.filterExpression = expression;
return this;
}
/**
* @deprecated use {@link Builder#filterExpression(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.0.0-M5")
public SearchRequest withFilterExpression(@Nullable String textExpression) {
this.filterExpression = (textExpression != null) ? new FilterExpressionTextParser().parse(textExpression)
: null;
return this;
}
public String getQuery() {
return this.query;
}
public int getTopK() {
return this.topK;
}
public double getSimilarityThreshold() {
return this.similarityThreshold;
}
@Nullable
public Filter.Expression getFilterExpression() {
return this.filterExpression;
}
public boolean hasFilterExpression() {
return this.filterExpression != null;
}
@Override
public String toString() {
return "SearchRequest{" + "query='" + this.query + '\'' + ", topK=" + this.topK + ", similarityThreshold="
+ this.similarityThreshold + ", filterExpression=" + this.filterExpression + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchRequest that = (SearchRequest) o;
return this.topK == that.topK && Double.compare(that.similarityThreshold, this.similarityThreshold) == 0
&& Objects.equals(this.query, that.query)
&& Objects.equals(this.filterExpression, that.filterExpression);
}
@Override
public int hashCode() {
return Objects.hash(this.query, this.topK, this.similarityThreshold, this.filterExpression);
}
}

View File

@@ -16,8 +16,11 @@
package org.springframework.ai.chat.client.advisor;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.model.ChatModel;
@@ -29,8 +32,6 @@ import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.preretrieval.query.transformation.QueryTransformer;
import org.springframework.ai.rag.retrieval.search.DocumentRetriever;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.given;

View File

@@ -17,7 +17,6 @@
package org.springframework.ai.chat.prompt;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -43,12 +42,12 @@ public class ChatOptionsBuilderTests {
@BeforeEach
void setUp() {
builder = ChatOptions.builder();
this.builder = ChatOptions.builder();
}
@Test
void shouldBuildWithAllOptions() {
ChatOptions options = builder.model("gpt-4")
ChatOptions options = this.builder.model("gpt-4")
.maxTokens(100)
.temperature(0.7)
.topP(1.0)
@@ -66,7 +65,7 @@ public class ChatOptionsBuilderTests {
@Test
void shouldBuildWithMinimalOptions() {
ChatOptions options = builder.model("gpt-4").build();
ChatOptions options = this.builder.model("gpt-4").build();
assertThat(options.getModel()).isEqualTo("gpt-4");
assertThat(options.getMaxTokens()).isNull();
@@ -78,7 +77,7 @@ public class ChatOptionsBuilderTests {
@Test
void shouldCopyOptions() {
ChatOptions original = builder.model("gpt-4")
ChatOptions original = this.builder.model("gpt-4")
.maxTokens(100)
.temperature(0.7)
.topP(1.0)
@@ -129,8 +128,8 @@ public class ChatOptionsBuilderTests {
@Test
void shouldAllowBuilderReuse() {
// When
ChatOptions options1 = builder.model("model1").temperature(0.7).build();
ChatOptions options2 = builder.model("model2").build();
ChatOptions options1 = this.builder.model("model1").temperature(0.7).build();
ChatOptions options2 = this.builder.model("model2").build();
// Then
assertThat(options1.getModel()).isEqualTo("model1");
@@ -142,16 +141,16 @@ public class ChatOptionsBuilderTests {
@Test
void shouldReturnSameBuilderInstanceOnEachMethod() {
// When
ChatOptions.Builder returnedBuilder = builder.model("test");
ChatOptions.Builder returnedBuilder = this.builder.model("test");
// Then
assertThat(returnedBuilder).isSameAs(builder);
assertThat(returnedBuilder).isSameAs(this.builder);
}
@Test
void shouldHaveExpectedDefaultValues() {
// When
ChatOptions options = builder.build();
ChatOptions options = this.builder.build();
// Then
assertThat(options.getModel()).isNull();
@@ -168,7 +167,7 @@ public class ChatOptionsBuilderTests {
void shouldBeImmutableAfterBuild() {
// Given
List<String> stopSequences = new ArrayList<>(List.of("stop1", "stop2"));
ChatOptions options = builder.stopSequences(stopSequences).build();
ChatOptions options = this.builder.stopSequences(stopSequences).build();
// Then
assertThatThrownBy(() -> options.getStopSequences().add("stop3"))

View File

@@ -1,3 +1,19 @@
/*
* 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.model;
import java.io.IOException;
@@ -8,7 +24,6 @@ import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.MimeType;

View File

@@ -16,9 +16,6 @@
package org.springframework.ai.model.function;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -26,6 +23,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.prompt.ChatOptions;
import static org.assertj.core.api.Assertions.assertThat;
@@ -41,7 +41,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@BeforeEach
void setUp() {
builder = new DefaultFunctionCallingOptionsBuilder();
this.builder = new DefaultFunctionCallingOptionsBuilder();
}
// Tests for inherited ChatOptions properties
@@ -49,7 +49,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithModel() {
// When
ChatOptions options = builder.model("gpt-4").build();
ChatOptions options = this.builder.model("gpt-4").build();
// Then
assertThat(options.getModel()).isEqualTo("gpt-4");
@@ -58,7 +58,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithFrequencyPenalty() {
// When
ChatOptions options = builder.frequencyPenalty(0.5).build();
ChatOptions options = this.builder.frequencyPenalty(0.5).build();
// Then
assertThat(options.getFrequencyPenalty()).isEqualTo(0.5);
@@ -67,7 +67,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithMaxTokens() {
// When
ChatOptions options = builder.maxTokens(100).build();
ChatOptions options = this.builder.maxTokens(100).build();
// Then
assertThat(options.getMaxTokens()).isEqualTo(100);
@@ -76,7 +76,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithPresencePenalty() {
// When
ChatOptions options = builder.presencePenalty(0.7).build();
ChatOptions options = this.builder.presencePenalty(0.7).build();
// Then
assertThat(options.getPresencePenalty()).isEqualTo(0.7);
@@ -88,7 +88,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
List<String> stopSequences = List.of("stop1", "stop2");
// When
ChatOptions options = builder.stopSequences(stopSequences).build();
ChatOptions options = this.builder.stopSequences(stopSequences).build();
// Then
assertThat(options.getStopSequences()).hasSize(2).containsExactlyElementsOf(stopSequences);
@@ -97,7 +97,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithTemperature() {
// When
ChatOptions options = builder.temperature(0.8).build();
ChatOptions options = this.builder.temperature(0.8).build();
// Then
assertThat(options.getTemperature()).isEqualTo(0.8);
@@ -106,7 +106,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithTopK() {
// When
ChatOptions options = builder.topK(5).build();
ChatOptions options = this.builder.topK(5).build();
// Then
assertThat(options.getTopK()).isEqualTo(5);
@@ -115,7 +115,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithTopP() {
// When
ChatOptions options = builder.topP(0.9).build();
ChatOptions options = this.builder.topP(0.9).build();
// Then
assertThat(options.getTopP()).isEqualTo(0.9);
@@ -124,7 +124,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithAllInheritedOptions() {
// When
ChatOptions options = builder.model("gpt-4")
ChatOptions options = this.builder.model("gpt-4")
.frequencyPenalty(0.5)
.maxTokens(100)
.presencePenalty(0.7)
@@ -163,7 +163,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
List<FunctionCallback> callbacks = List.of(callback1, callback2);
// When
FunctionCallingOptions options = builder.functionCallbacks(callbacks).build();
FunctionCallingOptions options = this.builder.functionCallbacks(callbacks).build();
// Then
assertThat(options.getFunctionCallbacks()).hasSize(2).containsExactlyElementsOf(callbacks);
@@ -184,7 +184,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
.build();
// When
FunctionCallingOptions options = builder.functionCallbacks(callback1, callback2).build();
FunctionCallingOptions options = this.builder.functionCallbacks(callback1, callback2).build();
// Then
assertThat(options.getFunctionCallbacks()).hasSize(2).containsExactly(callback1, callback2);
@@ -192,7 +192,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldThrowExceptionWhenFunctionCallbacksVarargsIsNull() {
assertThatThrownBy(() -> builder.functionCallbacks((FunctionCallback[]) null))
assertThatThrownBy(() -> this.builder.functionCallbacks((FunctionCallback[]) null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("FunctionCallbacks must not be null");
}
@@ -203,7 +203,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
Set<String> functions = Set.of("function1", "function2");
// When
FunctionCallingOptions options = builder.functions(functions).build();
FunctionCallingOptions options = this.builder.functions(functions).build();
// Then
assertThat(options.getFunctions()).hasSize(2).containsExactlyInAnyOrderElementsOf(functions);
@@ -212,7 +212,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithSingleFunction() {
// When
FunctionCallingOptions options = builder.function("function1").function("function2").build();
FunctionCallingOptions options = this.builder.function("function1").function("function2").build();
// Then
assertThat(options.getFunctions()).hasSize(2).containsExactlyInAnyOrder("function1", "function2");
@@ -220,14 +220,14 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldThrowExceptionWhenFunctionIsNull() {
assertThatThrownBy(() -> builder.function(null)).isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy(() -> this.builder.function(null)).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Function must not be null");
}
@Test
void shouldBuildWithProxyToolCalls() {
// When
FunctionCallingOptions options = builder.proxyToolCalls(true).build();
FunctionCallingOptions options = this.builder.proxyToolCalls(true).build();
// Then
assertThat(options.getProxyToolCalls()).isTrue();
@@ -239,7 +239,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
Map<String, Object> context = Map.of("key1", "value1", "key2", 42);
// When
FunctionCallingOptions options = builder.toolContext(context).build();
FunctionCallingOptions options = this.builder.toolContext(context).build();
// Then
assertThat(options.getToolContext()).hasSize(2).containsAllEntriesOf(context);
@@ -247,7 +247,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldThrowExceptionWhenToolContextMapIsNull() {
assertThatThrownBy(() -> builder.toolContext((Map<String, Object>) null))
assertThatThrownBy(() -> this.builder.toolContext((Map<String, Object>) null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Tool context must not be null");
}
@@ -255,7 +255,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithToolContextKeyValue() {
// When
FunctionCallingOptions options = builder.toolContext("key1", "value1").toolContext("key2", 42).build();
FunctionCallingOptions options = this.builder.toolContext("key1", "value1").toolContext("key2", 42).build();
// Then
assertThat(options.getToolContext()).hasSize(2).containsEntry("key1", "value1").containsEntry("key2", 42);
@@ -263,13 +263,13 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldThrowExceptionWhenToolContextKeyIsNull() {
assertThatThrownBy(() -> builder.toolContext(null, "value")).isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy(() -> this.builder.toolContext(null, "value")).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Key must not be null");
}
@Test
void shouldThrowExceptionWhenToolContextValueIsNull() {
assertThatThrownBy(() -> builder.toolContext("key", null)).isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy(() -> this.builder.toolContext("key", null)).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Value must not be null");
}
@@ -280,7 +280,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
Map<String, Object> context2 = Map.of("key2", "updated", "key3", true);
// When
FunctionCallingOptions options = builder.toolContext(context1).toolContext(context2).build();
FunctionCallingOptions options = this.builder.toolContext(context1).toolContext(context2).build();
// Then
assertThat(options.getToolContext()).hasSize(3)
@@ -301,7 +301,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
Map<String, Object> context = Map.of("key1", "value1");
// When
FunctionCallingOptions options = builder.model("gpt-4")
FunctionCallingOptions options = this.builder.model("gpt-4")
.frequencyPenalty(0.5)
.maxTokens(100)
.presencePenalty(0.7)
@@ -335,7 +335,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithEmptyFunctionCallbacks() {
// When
FunctionCallingOptions options = builder.functionCallbacks(List.of()).build();
FunctionCallingOptions options = this.builder.functionCallbacks(List.of()).build();
// Then
assertThat(options.getFunctionCallbacks()).isEmpty();
@@ -344,7 +344,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithEmptyFunctions() {
// When
FunctionCallingOptions options = builder.functions(Set.of()).build();
FunctionCallingOptions options = this.builder.functions(Set.of()).build();
// Then
assertThat(options.getFunctions()).isEmpty();
@@ -353,7 +353,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldBuildWithEmptyToolContext() {
// When
FunctionCallingOptions options = builder.toolContext(Map.of()).build();
FunctionCallingOptions options = this.builder.toolContext(Map.of()).build();
// Then
assertThat(options.getToolContext()).isEmpty();
@@ -362,7 +362,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldDeduplicateFunctions() {
// When
FunctionCallingOptions options = builder.function("function1")
FunctionCallingOptions options = this.builder.function("function1")
.function("function1") // Duplicate
.function("function2")
.build();
@@ -379,7 +379,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
.description("Test function")
.inputType(String.class)
.build();
FunctionCallingOptions original = builder.model("gpt-4")
FunctionCallingOptions original = this.builder.model("gpt-4")
.frequencyPenalty(0.5)
.maxTokens(100)
.presencePenalty(0.7)
@@ -418,7 +418,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
.inputType(String.class)
.build();
DefaultFunctionCallingOptions options1 = (DefaultFunctionCallingOptions) builder.model("gpt-4")
DefaultFunctionCallingOptions options1 = (DefaultFunctionCallingOptions) this.builder.model("gpt-4")
.temperature(0.8)
.functionCallbacks(callback1)
.function("function1")
@@ -457,7 +457,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
.inputType(String.class)
.build();
DefaultFunctionCallingOptions options1 = (DefaultFunctionCallingOptions) builder.model("gpt-4")
DefaultFunctionCallingOptions options1 = (DefaultFunctionCallingOptions) this.builder.model("gpt-4")
.temperature(0.8)
.functionCallbacks(callback)
.function("function1")
@@ -496,9 +496,12 @@ class DefaultFunctionCallingOptionsBuilderTests {
.build();
// When
FunctionCallingOptions options1 = builder.model("model1").temperature(0.7).functionCallbacks(callback1).build();
FunctionCallingOptions options1 = this.builder.model("model1")
.temperature(0.7)
.functionCallbacks(callback1)
.build();
FunctionCallingOptions options2 = builder.model("model2").functionCallbacks(callback2).build();
FunctionCallingOptions options2 = this.builder.model("model2").functionCallbacks(callback2).build();
// Then
assertThat(options1.getModel()).isEqualTo("model1");
@@ -515,16 +518,16 @@ class DefaultFunctionCallingOptionsBuilderTests {
@Test
void shouldReturnSameBuilderInstanceOnEachMethod() {
// When
FunctionCallingOptions.Builder returnedBuilder = builder.model("test");
FunctionCallingOptions.Builder returnedBuilder = this.builder.model("test");
// Then
assertThat(returnedBuilder).isSameAs(builder);
assertThat(returnedBuilder).isSameAs(this.builder);
}
@Test
void shouldHaveExpectedDefaultValues() {
// When
FunctionCallingOptions options = builder.build();
FunctionCallingOptions options = this.builder.build();
// Then
// ChatOptions defaults
@@ -557,7 +560,7 @@ class DefaultFunctionCallingOptionsBuilderTests {
Set<String> functions = new HashSet<>(Set.of("function1", "function2"));
Map<String, Object> context = new HashMap<>(Map.of("key1", "value1"));
FunctionCallingOptions options = builder.stopSequences(stopSequences)
FunctionCallingOptions options = this.builder.stopSequences(stopSequences)
.functionCallbacks(callback)
.functions(functions)
.toolContext(context)

View File

@@ -17,6 +17,7 @@
package org.springframework.ai.rag.preretrieval.query.transformation;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;

View File

@@ -17,6 +17,7 @@
package org.springframework.ai.rag.preretrieval.query.transformation;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.ai.document.Document;
import org.springframework.ai.rag.Query;

View File

@@ -1,18 +1,19 @@
/*
* 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.
*/
* 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.utils;
import java.io.BufferedInputStream;
@@ -28,7 +29,11 @@ import javax.sound.sampled.Clip;
* @author Christian Tzolov
* @since 1.0.0
*/
public class AudioPlayer {
public final class AudioPlayer {
private AudioPlayer() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static void main(String[] args) throws Exception {

View File

@@ -34,6 +34,20 @@
<suppress files="MethodInvokingFunctionCallbackTests.java" checks="RegexpSinglelineJava"/>
<suppress files="DefaultFunctionCallbackBuilderTests.java" checks="RegexpSinglelineJava"/>
<suppress files="ClientIT.java" checks="RegexpSinglelineJava"/>
<suppress files="MistralAiApi.java" checks="RegexpSinglelineJava"/>
<suppress files="MariaDBSchemaValidator.java" checks="RegexpSinglelineJava"/>
<suppress files="OpenAiApi.java" checks="AnnotationLocation"/>
<suppress files="AzureVectorStore.java" checks="FinalClass"/>
<suppress files="CassandraVectorStore.java" checks="FinalClass"/>
<suppress files="MilvusVectorStore.java" checks="FinalClass"/>
<suppress files="HanaCloudVectorStore.java" checks="FinalClass"/>
<suppress files="PineconeVectorStore.java" checks="FinalClass"/>
<suppress files="TypesenseVectorStore.java" checks="FinalClass"/>
<suppress files="WeaviateVectorStore.java" checks="FinalClass"/>
<suppress files="ChromaVectorStore.java" checks="FinalClass"/>
<suppress files="QdrantVectorStore.java" checks="FinalClass"/>
<suppress files="RedisVectorStore.java" checks="FinalClass"/>
</suppressions>

View File

@@ -203,7 +203,7 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements
this.defaultTopK = builder.defaultTopK;
this.defaultSimilarityThreshold = builder.defaultSimilarityThreshold;
this.indexName = builder.indexName;
this.filterExpressionConverter = new AzureAiSearchFilterExpressionConverter(filterMetadataFields);
this.filterExpressionConverter = new AzureAiSearchFilterExpressionConverter(this.filterMetadataFields);
}
public static Builder builder(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) {

View File

@@ -270,10 +270,10 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
prepareAddStatement(Set.of());
this.deleteStmt = prepareDeleteStatement();
TableMetadata cassandraMetadata = session.getMetadata()
.getKeyspace(schema.keyspace())
TableMetadata cassandraMetadata = this.session.getMetadata()
.getKeyspace(this.schema.keyspace())
.get()
.getTable(schema.table())
.getTable(this.schema.table())
.get();
this.similarity = getIndexSimilarity(cassandraMetadata);
@@ -870,11 +870,11 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
* @throws IllegalStateException if session is already set
*/
public Builder contactPoint(InetSocketAddress contactPoint) {
Assert.state(session == null, "Cannot call addContactPoint(..) when session is already set");
if (sessionBuilder == null) {
sessionBuilder = new CqlSessionBuilder();
Assert.state(this.session == null, "Cannot call addContactPoint(..) when session is already set");
if (this.sessionBuilder == null) {
this.sessionBuilder = new CqlSessionBuilder();
}
sessionBuilder.addContactPoint(contactPoint);
this.sessionBuilder.addContactPoint(contactPoint);
return this;
}
@@ -885,11 +885,11 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
* @throws IllegalStateException if session is already set
*/
public Builder localDatacenter(String localDatacenter) {
Assert.state(session == null, "Cannot call withLocalDatacenter(..) when session is already set");
if (sessionBuilder == null) {
sessionBuilder = new CqlSessionBuilder();
Assert.state(this.session == null, "Cannot call withLocalDatacenter(..) when session is already set");
if (this.sessionBuilder == null) {
this.sessionBuilder = new CqlSessionBuilder();
}
sessionBuilder.withLocalDatacenter(localDatacenter);
this.sessionBuilder.withLocalDatacenter(localDatacenter);
return this;
}
@@ -1035,49 +1035,49 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme
Schema buildSchema() {
if (this.indexName == null) {
this.indexName = String.format("%s_%s_%s", table, embeddingColumnName, DEFAULT_INDEX_SUFFIX);
this.indexName = String.format("%s_%s_%s", this.table, this.embeddingColumnName, DEFAULT_INDEX_SUFFIX);
}
validateSchema();
return new Schema(keyspace, table, partitionKeys, clusteringKeys, contentColumnName, embeddingColumnName,
indexName, metadataColumns);
return new Schema(this.keyspace, this.table, this.partitionKeys, this.clusteringKeys,
this.contentColumnName, this.embeddingColumnName, this.indexName, this.metadataColumns);
}
private void validateSchema() {
for (SchemaColumn metadata : metadataColumns) {
Assert.isTrue(!partitionKeys.stream().anyMatch(c -> c.name().equals(metadata.name())),
for (SchemaColumn metadata : this.metadataColumns) {
Assert.isTrue(!this.partitionKeys.stream().anyMatch(c -> c.name().equals(metadata.name())),
"metadataColumn " + metadata.name() + " cannot have same name as a partition key");
Assert.isTrue(!clusteringKeys.stream().anyMatch(c -> c.name().equals(metadata.name())),
Assert.isTrue(!this.clusteringKeys.stream().anyMatch(c -> c.name().equals(metadata.name())),
"metadataColumn " + metadata.name() + " cannot have same name as a clustering key");
Assert.isTrue(!metadata.name().equals(contentColumnName),
Assert.isTrue(!metadata.name().equals(this.contentColumnName),
"metadataColumn " + metadata.name() + " cannot have same name as content column name");
Assert.isTrue(!metadata.name().equals(embeddingColumnName),
Assert.isTrue(!metadata.name().equals(this.embeddingColumnName),
"metadataColumn " + metadata.name() + " cannot have same name as embedding column name");
}
int primaryKeyColumnsCount = partitionKeys.size() + clusteringKeys.size();
String exampleId = primaryKeyTranslator.apply(Collections.emptyList());
List<Object> testIdTranslation = documentIdTranslator.apply(exampleId);
int primaryKeyColumnsCount = this.partitionKeys.size() + this.clusteringKeys.size();
String exampleId = this.primaryKeyTranslator.apply(Collections.emptyList());
List<Object> testIdTranslation = this.documentIdTranslator.apply(exampleId);
Assert.isTrue(testIdTranslation.size() == primaryKeyColumnsCount,
"documentIdTranslator results length " + testIdTranslation.size()
+ " doesn't match number of primary key columns " + primaryKeyColumnsCount);
Assert.isTrue(exampleId.equals(primaryKeyTranslator.apply(documentIdTranslator.apply(exampleId))),
Assert.isTrue(exampleId.equals(this.primaryKeyTranslator.apply(this.documentIdTranslator.apply(exampleId))),
"primaryKeyTranslator is not an inverse function to documentIdTranslator");
}
@Override
public CassandraVectorStore build() {
if (session == null && sessionBuilder != null) {
session = sessionBuilder.build();
closeSessionOnClose = true;
if (this.session == null && this.sessionBuilder != null) {
this.session = this.sessionBuilder.build();
this.closeSessionOnClose = true;
}
Assert.notNull(session, "Either session must be set directly or configured via sessionBuilder");
Assert.notNull(this.session, "Either session must be set directly or configured via sessionBuilder");
return new CassandraVectorStore(this);
}

View File

@@ -37,7 +37,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -45,6 +44,7 @@ import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils;
import org.springframework.ai.cassandra.CassandraImage;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;

View File

@@ -30,13 +30,13 @@ import com.datastax.oss.driver.api.core.servererrors.SyntaxError;
import com.datastax.oss.driver.api.core.type.DataTypes;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.cassandra.CassandraImage;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;

View File

@@ -21,9 +21,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.mariadb.jdbc.Driver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -151,8 +153,9 @@ public class MariaDBSchemaValidator {
try {
String quotedId = Driver.enquoteIdentifier(identifier, alwaysQuote);
// force use of simple table name
if (Pattern.compile("`?[\\p{Alnum}_]*`?").matcher(identifier).matches())
if (Pattern.compile("`?[\\p{Alnum}_]*`?").matcher(identifier).matches()) {
return quotedId;
}
throw new IllegalArgumentException(String
.format("Identifier '%s' should only contain alphanumeric characters and underscores", quotedId));
}

View File

@@ -16,16 +16,22 @@
package org.springframework.ai.vectorstore.mariadb;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import io.micrometer.observation.ObservationRegistry;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
@@ -33,7 +39,6 @@ import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric;
import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric;
import org.springframework.ai.util.JacksonUtils;
import org.springframework.ai.vectorstore.AbstractVectorStoreBuilder;
import org.springframework.ai.vectorstore.SearchRequest;
@@ -305,7 +310,7 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
this.distanceType = builder.distanceType;
this.removeExistingVectorStoreTable = builder.removeExistingVectorStoreTable;
this.initializeSchema = builder.initializeSchema;
this.schemaValidator = new MariaDBSchemaValidator(jdbcTemplate);
this.schemaValidator = new MariaDBSchemaValidator(this.jdbcTemplate);
this.batchingStrategy = builder.batchingStrategy;
this.maxDocumentBatchSize = builder.maxDocumentBatchSize;
@@ -314,7 +319,7 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
false);
this.idFieldName = MariaDBSchemaValidator.validateAndEnquoteIdentifier(builder.idFieldName, false);
this.metadataFieldName = MariaDBSchemaValidator.validateAndEnquoteIdentifier(builder.metadataFieldName, false);
filterExpressionConverter = new MariaDBFilterExpressionConverter(this.metadataFieldName);
this.filterExpressionConverter = new MariaDBFilterExpressionConverter(this.metadataFieldName);
}
/**
@@ -447,8 +452,8 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
logger.info("vectorTableValidationsEnabled {}", this.schemaValidation);
if (this.schemaValidation) {
this.schemaValidator.validateTableSchema(this.schemaName, this.vectorTableName, idFieldName,
contentFieldName, metadataFieldName, embeddingFieldName, this.embeddingDimensions());
this.schemaValidator.validateTableSchema(this.schemaName, this.vectorTableName, this.idFieldName,
this.contentFieldName, this.metadataFieldName, this.embeddingFieldName, this.embeddingDimensions());
}
if (!this.initializeSchema) {
@@ -456,8 +461,9 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
return;
}
if (this.schemaName != null)
if (this.schemaName != null) {
this.jdbcTemplate.execute(String.format("CREATE SCHEMA IF NOT EXISTS %s", this.schemaName));
}
// Remove existing VectorStoreTable
if (this.removeExistingVectorStoreTable) {
@@ -472,15 +478,16 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
%s VECTOR(%d) NOT NULL,
VECTOR INDEX %s_idx (%s)
) ENGINE=InnoDB
""", this.getFullyQualifiedTableName(), idFieldName, contentFieldName, metadataFieldName,
embeddingFieldName, this.embeddingDimensions(),
(vectorTableName + "_" + embeddingFieldName).replaceAll("[^\\n\\r\\t\\p{Print}]", ""),
embeddingFieldName));
""", this.getFullyQualifiedTableName(), this.idFieldName, this.contentFieldName, this.metadataFieldName,
this.embeddingFieldName, this.embeddingDimensions(),
(this.vectorTableName + "_" + this.embeddingFieldName).replaceAll("[^\\n\\r\\t\\p{Print}]", ""),
this.embeddingFieldName));
}
private String getFullyQualifiedTableName() {
if (this.schemaName != null)
if (this.schemaName != null) {
return this.schemaName + "." + this.vectorTableName;
}
return this.vectorTableName;
}
@@ -522,7 +529,7 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
public enum MariaDBDistanceType {
EUCLIDEAN, COSINE;
EUCLIDEAN, COSINE
}
@@ -530,7 +537,7 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement
private final ObjectMapper objectMapper;
public DocumentRowMapper(ObjectMapper objectMapper) {
DocumentRowMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

View File

@@ -16,20 +16,20 @@
package org.springframework.ai.vectorstore.mariadb;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.jdbc.core.JdbcTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author Diego Dupin
*/

View File

@@ -16,6 +16,16 @@
package org.springframework.ai.vectorstore.mariadb;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.ai.vectorstore.filter.Filter.Expression;
import org.springframework.ai.vectorstore.filter.Filter.Group;
import org.springframework.ai.vectorstore.filter.Filter.Key;
import org.springframework.ai.vectorstore.filter.Filter.Value;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.AND;
import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.EQ;
@@ -26,15 +36,6 @@ import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.NE
import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.NIN;
import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.OR;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.ai.vectorstore.filter.Filter.Expression;
import org.springframework.ai.vectorstore.filter.Filter.Group;
import org.springframework.ai.vectorstore.filter.Filter.Key;
import org.springframework.ai.vectorstore.filter.Filter.Value;
import org.springframework.ai.vectorstore.mariadb.MariaDBFilterExpressionConverter;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
/**
* @author Diego Dupin
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 the original author or authors.
* 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.
@@ -21,8 +21,12 @@ import org.testcontainers.utility.DockerImageName;
/**
* @author Diego Dupin
*/
public class MariaDBImage {
public final class MariaDBImage {
public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("mariadb:11.7-rc");
private MariaDBImage() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -16,16 +16,18 @@
package org.springframework.ai.vectorstore.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -37,9 +39,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Diego Dupin
@@ -91,8 +92,9 @@ public class MariaDBStoreCustomNamesIT {
boolean fieldsExists = jdbcTemplate
.queryForObject("SELECT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema= ? AND"
+ " table_name = ? AND column_name = ?)", Boolean.class, schemaName, tableName, field);
if (!fieldsExists)
if (!fieldsExists) {
return false;
}
}
return true;
}

View File

@@ -16,9 +16,6 @@
package org.springframework.ai.vectorstore.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import com.zaxxer.hikari.HikariDataSource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
@@ -27,13 +24,20 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Stream;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Assert;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
@@ -54,9 +58,8 @@ import org.springframework.context.annotation.Primary;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.CollectionUtils;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Diego Dupin
@@ -121,7 +124,8 @@ public class MariaDBStoreIT {
}
Iterator<Float> iter = distances.iterator();
Float current, previous = iter.next();
Float current;
Float previous = iter.next();
while (iter.hasNext()) {
current = iter.next();
if (previous > current) {

View File

@@ -16,20 +16,23 @@
package org.springframework.ai.vectorstore.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.SpringAiKind;
@@ -52,9 +55,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Diego Dupin

View File

@@ -26,8 +26,6 @@ import org.mockito.ArgumentCaptor;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.mariadb.MariaDBSchemaValidator;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

View File

@@ -16,15 +16,16 @@
package org.springframework.ai.vectorstore.mariadb;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import org.junit.jupiter.api.Test;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore.MariaDBDistanceType;
import org.springframework.jdbc.core.JdbcTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
/**
* Unit tests for {@link MariaDBVectorStore.MariaDBBuilder}.
*
@@ -38,21 +39,21 @@ class MariaDBVectorStoreBuilderTests {
@Test
void shouldFailOnMissingEmbeddingModel() {
assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, null).build())
assertThatThrownBy(() -> MariaDBVectorStore.builder(this.jdbcTemplate, null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("EmbeddingModel must be configured");
}
@Test
void shouldFailOnMissingJdbcTemplate() {
assertThatThrownBy(() -> MariaDBVectorStore.builder(null, embeddingModel).build())
assertThatThrownBy(() -> MariaDBVectorStore.builder(null, this.embeddingModel).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("JdbcTemplate must not be null");
}
@Test
void shouldUseDefaultValues() {
MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).build();
MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).build();
assertThat(vectorStore).hasFieldOrPropertyWithValue("vectorTableName", "vector_store")
.hasFieldOrPropertyWithValue("schemaName", null)
@@ -70,7 +71,7 @@ class MariaDBVectorStoreBuilderTests {
@Test
void shouldConfigureCustomValues() {
MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate, embeddingModel)
MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel)
.schemaName("custom_schema")
.vectorTableName("custom_vectors")
.schemaValidation(true)
@@ -101,40 +102,44 @@ class MariaDBVectorStoreBuilderTests {
@Test
void shouldValidateFieldNames() {
assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).contentFieldName("").build())
assertThatThrownBy(
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).contentFieldName("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("ContentFieldName must not be empty");
assertThatThrownBy(
() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).embeddingFieldName("").build())
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).embeddingFieldName("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("EmbeddingFieldName must not be empty");
assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).idFieldName("").build())
assertThatThrownBy(
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).idFieldName("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("IdFieldName must not be empty");
assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).metadataFieldName("").build())
assertThatThrownBy(
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).metadataFieldName("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("MetadataFieldName must not be empty");
}
@Test
void shouldValidateMaxDocumentBatchSize() {
assertThatThrownBy(
() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).maxDocumentBatchSize(0).build())
.isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy(() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel)
.maxDocumentBatchSize(0)
.build()).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("MaxDocumentBatchSize must be positive");
assertThatThrownBy(
() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).maxDocumentBatchSize(-1).build())
.isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy(() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel)
.maxDocumentBatchSize(-1)
.build()).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("MaxDocumentBatchSize must be positive");
}
@Test
void shouldValidateDistanceType() {
assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).distanceType(null).build())
assertThatThrownBy(
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).distanceType(null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("DistanceType must not be null");
}
@@ -142,7 +147,7 @@ class MariaDBVectorStoreBuilderTests {
@Test
void shouldValidateBatchingStrategy() {
assertThatThrownBy(
() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).batchingStrategy(null).build())
() -> MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel).batchingStrategy(null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("BatchingStrategy must not be null");
}

View File

@@ -572,7 +572,7 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements
return SIMILARITY_TYPE_MAPPING.get(this.metricType).value();
}
public static final class Builder extends AbstractVectorStoreBuilder<Builder> {
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private final MilvusServiceClient milvusClient;

View File

@@ -30,12 +30,12 @@ import io.milvus.param.MetricType;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.milvus.MilvusContainer;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.openai.OpenAiEmbeddingModel;

View File

@@ -32,13 +32,13 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.oracle.OracleContainer;
import org.testcontainers.utility.MountableFile;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
@@ -328,9 +328,9 @@ public class OracleVectorStoreIT {
return OracleVectorStore.builder(jdbcTemplate, embeddingModel)
.tableName(OracleVectorStore.DEFAULT_TABLE_NAME)
.indexType(OracleVectorStore.OracleVectorStoreIndexType.IVF)
.distanceType(distanceType)
.distanceType(this.distanceType)
.dimensions(384)
.searchAccuracy(searchAccuracy)
.searchAccuracy(this.searchAccuracy)
.initializeSchema(true)
.removeExistingVectorStoreTable(true)
.forcedNormalization(true)

View File

@@ -42,10 +42,10 @@ import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetri
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore.OracleVectorStoreDistanceType;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore.OracleVectorStoreDistanceType;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

View File

@@ -617,7 +617,7 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini
}
public static class PgVectorStoreBuilder extends AbstractVectorStoreBuilder<PgVectorStoreBuilder> {
public static final class PgVectorStoreBuilder extends AbstractVectorStoreBuilder<PgVectorStoreBuilder> {
private final JdbcTemplate jdbcTemplate;

View File

@@ -30,8 +30,8 @@ import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

View File

@@ -34,19 +34,19 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionTextParser.FilterExpressionParseException;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

View File

@@ -41,12 +41,12 @@ import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetri
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore.PgIndexType;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

View File

@@ -146,9 +146,9 @@ class PgVectorStoreWithChatMemoryAdvisorIT {
private @NotNull EmbeddingModel embeddingNModelShouldAlwaysReturnFakedEmbed() {
EmbeddingModel embeddingModel = mock(EmbeddingModel.class);
Mockito.doAnswer(invocationOnMock -> {
return List.of(this.embed, this.embed);
}).when(embeddingModel).embed(ArgumentMatchers.any(), any(), any());
Mockito.doAnswer(invocationOnMock -> List.of(this.embed, this.embed))
.when(embeddingModel)
.embed(ArgumentMatchers.any(), any(), any());
given(embeddingModel.embed(any(String.class))).willReturn(this.embed);
return embeddingModel;
}

View File

@@ -36,7 +36,6 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore.PineconeVectorStoreConfig;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

View File

@@ -39,7 +39,6 @@ import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore.PineconeVectorStoreConfig;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames;

View File

@@ -368,7 +368,7 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements
*
* @since 1.0.0
*/
public static final class Builder extends AbstractVectorStoreBuilder<Builder> {
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private final QdrantClient qdrantClient;

View File

@@ -46,7 +46,7 @@ class QdrantVectorStoreBuilderTests {
@Test
void defaultConfiguration() {
QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient, embeddingModel).build();
QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel).build();
// Verify default values
assertThat(vectorStore).hasFieldOrPropertyWithValue("collectionName", "vector_store");
@@ -56,7 +56,7 @@ class QdrantVectorStoreBuilderTests {
@Test
void customConfiguration() {
QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient, embeddingModel)
QdrantVectorStore vectorStore = QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel)
.collectionName("custom_collection")
.initializeSchema(true)
.batchingStrategy(new TokenCountBatchingStrategy())
@@ -75,21 +75,23 @@ class QdrantVectorStoreBuilderTests {
@Test
void nullEmbeddingModelShouldThrowException() {
assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, null).build())
assertThatThrownBy(() -> QdrantVectorStore.builder(this.qdrantClient, null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("EmbeddingModel must be configured");
}
@Test
void emptyCollectionNameShouldThrowException() {
assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, embeddingModel).collectionName("").build())
assertThatThrownBy(
() -> QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel).collectionName("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("collectionName must not be empty");
}
@Test
void nullBatchingStrategyShouldThrowException() {
assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, embeddingModel).batchingStrategy(null).build())
assertThatThrownBy(
() -> QdrantVectorStore.builder(this.qdrantClient, this.embeddingModel).batchingStrategy(null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("BatchingStrategy must not be null");
}

View File

@@ -22,13 +22,13 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.ai.vectorstore.filter.Filter.Expression;
import org.springframework.ai.vectorstore.filter.Filter.ExpressionType;
import org.springframework.ai.vectorstore.filter.Filter.Group;
import org.springframework.ai.vectorstore.filter.Filter.Key;
import org.springframework.ai.vectorstore.filter.Filter.Value;
import org.springframework.ai.vectorstore.filter.converter.AbstractFilterExpressionConverter;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
/**
* Converts {@link Expression} into Redis search filter expression format.

View File

@@ -30,7 +30,6 @@ import java.util.stream.Collectors;
import io.micrometer.observation.ObservationRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.DocumentMetadata;
import redis.clients.jedis.JedisPooled;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.json.Path2;
@@ -48,6 +47,7 @@ import redis.clients.jedis.search.schemafields.VectorField;
import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingOptionsBuilder;
@@ -458,6 +458,10 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements
}
public static Builder builder(JedisPooled jedis, EmbeddingModel embeddingModel) {
return new Builder(jedis, embeddingModel);
}
public enum Algorithm {
FLAT, HSNW
@@ -480,10 +484,6 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements
}
public static Builder builder(JedisPooled jedis, EmbeddingModel embeddingModel) {
return new Builder(jedis, embeddingModel);
}
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private final JedisPooled jedis;

View File

@@ -21,11 +21,11 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.ai.vectorstore.filter.Filter.Expression;
import org.springframework.ai.vectorstore.filter.Filter.Group;
import org.springframework.ai.vectorstore.filter.Filter.Key;
import org.springframework.ai.vectorstore.filter.Filter.Value;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ai.vectorstore.filter.Filter.ExpressionType.AND;

View File

@@ -26,17 +26,17 @@ import java.util.UUID;
import com.redis.testcontainers.RedisStackContainer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import redis.clients.jedis.JedisPooled;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

View File

@@ -38,12 +38,12 @@ import org.springframework.ai.observation.conventions.SpringAiKind;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.observation.conventions.VectorStoreSimilarityMetric;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.LowCardinalityKeyNames;
import org.springframework.ai.vectorstore.redis.RedisVectorStore.MetadataField;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

View File

@@ -393,7 +393,7 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme
.similarityMetric(VectorStoreSimilarityMetric.COSINE.value());
}
public static final class Builder extends AbstractVectorStoreBuilder<Builder> {
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private String collectionName = DEFAULT_COLLECTION_NAME;

View File

@@ -531,7 +531,7 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore {
}
}
public static final class Builder extends AbstractVectorStoreBuilder<Builder> {
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
private String weaviateObjectClass = "SpringAiWeaviate";

View File

@@ -16,6 +16,8 @@
package org.springframework.ai.vectorstore.weaviate;
import java.util.List;
import io.weaviate.client.Config;
import io.weaviate.client.WeaviateClient;
import org.junit.jupiter.api.Test;
@@ -27,8 +29,6 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.ConsistentLevel;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.MetadataField;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -47,7 +47,7 @@ class WeaviateVectorStoreBuilderTests {
void shouldBuildWithMinimalConfiguration() {
WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080"));
WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, embeddingModel).build();
WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, this.embeddingModel).build();
assertThat(vectorStore).isNotNull();
}
@@ -56,7 +56,7 @@ class WeaviateVectorStoreBuilderTests {
void shouldBuildWithCustomConfiguration() {
WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080"));
WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, embeddingModel)
WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, this.embeddingModel)
.objectClass("CustomClass")
.consistencyLevel(ConsistentLevel.QUORUM)
.filterMetadataFields(List.of(MetadataField.text("country"), MetadataField.number("year")))
@@ -67,7 +67,7 @@ class WeaviateVectorStoreBuilderTests {
@Test
void shouldFailWithoutWeaviateClient() {
assertThatThrownBy(() -> WeaviateVectorStore.builder(null, embeddingModel).build())
assertThatThrownBy(() -> WeaviateVectorStore.builder(null, this.embeddingModel).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("WeaviateClient must not be null");
}
@@ -85,7 +85,8 @@ class WeaviateVectorStoreBuilderTests {
void shouldFailWithInvalidObjectClass() {
WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080"));
assertThatThrownBy(() -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).objectClass("").build())
assertThatThrownBy(
() -> WeaviateVectorStore.builder(weaviateClient, this.embeddingModel).objectClass("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("objectClass must not be empty");
}
@@ -95,7 +96,7 @@ class WeaviateVectorStoreBuilderTests {
WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080"));
assertThatThrownBy(
() -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).consistencyLevel(null).build())
() -> WeaviateVectorStore.builder(weaviateClient, this.embeddingModel).consistencyLevel(null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("consistencyLevel must not be null");
}
@@ -104,10 +105,9 @@ class WeaviateVectorStoreBuilderTests {
void shouldFailWithNullFilterMetadataFields() {
WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080"));
assertThatThrownBy(
() -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).filterMetadataFields(null).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("filterMetadataFields must not be null");
assertThatThrownBy(() -> WeaviateVectorStore.builder(weaviateClient, this.embeddingModel)
.filterMetadataFields(null)
.build()).isInstanceOf(IllegalArgumentException.class).hasMessage("filterMetadataFields must not be null");
}
@Test

View File

@@ -26,13 +26,13 @@ import java.util.UUID;
import io.weaviate.client.Config;
import io.weaviate.client.WeaviateClient;
import org.junit.jupiter.api.Test;
import org.springframework.ai.document.DocumentMetadata;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.weaviate.WeaviateContainer;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentMetadata;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;