committed by
Mark Pollack
parent
46e372d95c
commit
3eff6a75c9
@@ -0,0 +1,8 @@
|
||||
package org.springframework.ai.document;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface DocumentReader extends Supplier<List<Document>> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.ai.document;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface DocumentRetriever extends Function<String, List<Document>> {
|
||||
|
||||
/**
|
||||
* Retrieves relevant documents however the implementation sees fit.
|
||||
* @param query query string
|
||||
* @return relevant documents
|
||||
*/
|
||||
List<Document> retrieve(String query);
|
||||
|
||||
default List<Document> apply(String query) {
|
||||
return retrieve(query);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2023-2023 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.document;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public interface DocumentWriter extends Consumer<List<Document>> {
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.springframework.ai.loader;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.splitter.TextSplitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Loader {
|
||||
|
||||
List<Document> load();
|
||||
|
||||
List<Document> load(TextSplitter textSplitter);
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2023 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.loader.extractor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.document.DocumentTransformer;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public abstract class AbstractMetadataFeatureExtractor implements DocumentTransformer {
|
||||
|
||||
@Override
|
||||
public List<Document> apply(List<Document> documents) {
|
||||
List<Map<String, Object>> metadataList = this.extract(documents);
|
||||
|
||||
for (int idx = 0; idx < documents.size(); idx++) {
|
||||
documents.get(idx).getMetadata().putAll(metadataList.get(idx));
|
||||
}
|
||||
|
||||
return documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts metadata for a list of documents, returning a list of metadata
|
||||
* dictionaries corresponding to each document.
|
||||
* @param documents Documents to extract metadata from.
|
||||
* @return List of metadata dictionaries corresponding to each document
|
||||
*/
|
||||
abstract public List<Map<String, Object>> extract(List<Document> documents);
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ai.loader.impl;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ai.loader.impl;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package org.springframework.ai.loader.impl;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.Loader;
|
||||
import org.springframework.ai.splitter.TextSplitter;
|
||||
import org.springframework.ai.splitter.TokenTextSplitter;
|
||||
import org.springframework.ai.document.DocumentReader;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class JsonLoader implements Loader {
|
||||
public class JsonReader implements DocumentReader {
|
||||
|
||||
private Resource resource;
|
||||
|
||||
@@ -22,15 +24,15 @@ public class JsonLoader implements Loader {
|
||||
*/
|
||||
private List<String> jsonKeysToUse;
|
||||
|
||||
public JsonLoader(Resource resource) {
|
||||
public JsonReader(Resource resource) {
|
||||
this(resource, new ArrayList<>().toArray(new String[0]));
|
||||
}
|
||||
|
||||
public JsonLoader(Resource resource, String... jsonKeysToUse) {
|
||||
public JsonReader(Resource resource, String... jsonKeysToUse) {
|
||||
this(resource, new EmptyJsonMetadataGenerator(), jsonKeysToUse);
|
||||
}
|
||||
|
||||
public JsonLoader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String... jsonKeysToUse) {
|
||||
public JsonReader(Resource resource, JsonMetadataGenerator jsonMetadataGenerator, String... jsonKeysToUse) {
|
||||
Objects.requireNonNull(jsonKeysToUse, "keys must not be null");
|
||||
Objects.requireNonNull(jsonMetadataGenerator, "jsonMetadataGenerator must not be null");
|
||||
Objects.requireNonNull(resource, "The Spring Resource must not be null");
|
||||
@@ -40,13 +42,7 @@ public class JsonLoader implements Loader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> load() {
|
||||
return load(new TokenTextSplitter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> load(TextSplitter textSplitter) {
|
||||
|
||||
public List<Document> get() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<Document> documents = new ArrayList<>();
|
||||
try {
|
||||
@@ -74,15 +70,8 @@ public class JsonLoader implements Loader {
|
||||
else {
|
||||
document = new Document(item.toString(), metadata);
|
||||
}
|
||||
// Splitting at the item level is good when the size of the json per
|
||||
// element is large
|
||||
// as is the case with a catalog of product, as the metadata applies
|
||||
// across all split documents
|
||||
// This may not be good when the size of the json element is small as it
|
||||
// can create too many individual
|
||||
// documents.
|
||||
List<Document> splitDocuments = textSplitter.apply(List.of(document));
|
||||
documents.addAll(splitDocuments);
|
||||
|
||||
documents.add(document);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -1,18 +1,15 @@
|
||||
package org.springframework.ai.loader.impl;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.Loader;
|
||||
import org.springframework.ai.splitter.TextSplitter;
|
||||
import org.springframework.ai.splitter.TokenTextSplitter;
|
||||
import org.springframework.ai.document.DocumentReader;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StreamUtils;
|
||||
@@ -21,7 +18,7 @@ import org.springframework.util.StreamUtils;
|
||||
* @author Craig Walls
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class TextLoader implements Loader {
|
||||
public class TextReader implements DocumentReader {
|
||||
|
||||
public static final String CHARSET_METADATA = "charset";
|
||||
|
||||
@@ -39,11 +36,11 @@ public class TextLoader implements Loader {
|
||||
|
||||
private Map<String, Object> customMetadata = new HashMap<>();
|
||||
|
||||
public TextLoader(String resourceUrl) {
|
||||
public TextReader(String resourceUrl) {
|
||||
this(new DefaultResourceLoader().getResource(resourceUrl));
|
||||
}
|
||||
|
||||
public TextLoader(Resource resource) {
|
||||
public TextReader(Resource resource) {
|
||||
Objects.requireNonNull(resource, "The Spring Resource must not be null");
|
||||
this.resource = resource;
|
||||
}
|
||||
@@ -66,12 +63,7 @@ public class TextLoader implements Loader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> load() {
|
||||
return load(new TokenTextSplitter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> load(TextSplitter textSplitter) {
|
||||
public List<Document> get() {
|
||||
try {
|
||||
|
||||
String document = StreamUtils.copyToString(this.resource.getInputStream(), this.charset);
|
||||
@@ -80,7 +72,9 @@ public class TextLoader implements Loader {
|
||||
this.customMetadata.put(CHARSET_METADATA, this.charset.name());
|
||||
this.customMetadata.put(SOURCE_METADATA, this.resource.getFilename());
|
||||
|
||||
return textSplitter.apply(Collections.singletonList(new Document(document, this.customMetadata)));
|
||||
return List.of(new Document(document, this.customMetadata));
|
||||
// return textSplitter.apply(Collections.singletonList(new Document(document,
|
||||
// this.customMetadata)));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.springframework.ai.retriever;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Retriever {
|
||||
|
||||
/**
|
||||
* Retrieves relevant documents however the implementation sees fit.
|
||||
* @param query query string
|
||||
* @return relevant documents
|
||||
*/
|
||||
List<Document> retrieve(String query);
|
||||
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.springframework.ai.retriever.impl;
|
||||
package org.springframework.ai.retriever;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.retriever.Retriever;
|
||||
import org.springframework.ai.document.DocumentRetriever;
|
||||
import org.springframework.ai.vectorstore.VectorStore;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class VectorStoreRetriever implements Retriever {
|
||||
public class VectorStoreRetriever implements DocumentRetriever {
|
||||
|
||||
private VectorStore vectorStore;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.loader.extractor;
|
||||
package org.springframework.ai.transformer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -27,7 +27,7 @@ import org.springframework.ai.document.DocumentTransformer;
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class ContentFormatEnricher implements DocumentTransformer {
|
||||
public class ContentFormatTransformer implements DocumentTransformer {
|
||||
|
||||
/**
|
||||
* Disable the content-formatter template rewrite.
|
||||
@@ -36,11 +36,11 @@ public class ContentFormatEnricher implements DocumentTransformer {
|
||||
|
||||
private ContentFormatter contentFormatter;
|
||||
|
||||
public ContentFormatEnricher(ContentFormatter contentFormatter) {
|
||||
public ContentFormatTransformer(ContentFormatter contentFormatter) {
|
||||
this(contentFormatter, false);
|
||||
}
|
||||
|
||||
public ContentFormatEnricher(ContentFormatter contentFormatter, boolean disableTemplateRewrite) {
|
||||
public ContentFormatTransformer(ContentFormatter contentFormatter, boolean disableTemplateRewrite) {
|
||||
this.contentFormatter = contentFormatter;
|
||||
this.disableTemplateRewrite = disableTemplateRewrite;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.loader.extractor;
|
||||
package org.springframework.ai.transformer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -31,7 +31,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class KeywordExtractor implements DocumentTransformer {
|
||||
public class KeywordMetadataEnricher implements DocumentTransformer {
|
||||
|
||||
private static final String EXCERPT_KEYWORDS_METADATA_KEY = "excerpt_keywords";
|
||||
|
||||
@@ -51,7 +51,7 @@ public class KeywordExtractor implements DocumentTransformer {
|
||||
*/
|
||||
private final int keywordCount;
|
||||
|
||||
public KeywordExtractor(AiClient aiClient, int keywordCount) {
|
||||
public KeywordMetadataEnricher(AiClient aiClient, int keywordCount) {
|
||||
Assert.notNull(aiClient, "AiClient must not be null");
|
||||
Assert.isTrue(keywordCount >= 1, "Document count must be >= 1");
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.loader.extractor;
|
||||
package org.springframework.ai.transformer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
public class SummaryExtractor implements DocumentTransformer {
|
||||
public class SummaryMetadataEnricher implements DocumentTransformer {
|
||||
|
||||
private static final String SECTION_SUMMARY_METADATA_KEY = "section_summary";
|
||||
|
||||
@@ -77,11 +77,11 @@ public class SummaryExtractor implements DocumentTransformer {
|
||||
*/
|
||||
private final String summaryTemplate;
|
||||
|
||||
public SummaryExtractor(AiClient aiClient, List<SummaryType> summaryTypes) {
|
||||
public SummaryMetadataEnricher(AiClient aiClient, List<SummaryType> summaryTypes) {
|
||||
this(aiClient, summaryTypes, DEFAULT_SUMMARY_EXTRACT_TEMPLATE, MetadataMode.ALL);
|
||||
}
|
||||
|
||||
public SummaryExtractor(AiClient aiClient, List<SummaryType> summaryTypes, String summaryTemplate,
|
||||
public SummaryMetadataEnricher(AiClient aiClient, List<SummaryType> summaryTypes, String summaryTemplate,
|
||||
MetadataMode metadataMode) {
|
||||
Assert.notNull(aiClient, "AiClient must not be null");
|
||||
Assert.hasText(summaryTemplate, "Summary template must not be empty");
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ai.splitter;
|
||||
package org.springframework.ai.transformer.splitter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ai.splitter;
|
||||
package org.springframework.ai.transformer.splitter;
|
||||
|
||||
import com.knuddels.jtokkit.Encodings;
|
||||
import com.knuddels.jtokkit.api.Encoding;
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.springframework.ai.vectorstore.impl;
|
||||
package org.springframework.ai.vectorstore;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.embedding.EmbeddingClient;
|
||||
import org.springframework.ai.vectorstore.VectorStore;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ai.vectorstore.impl;
|
||||
package org.springframework.ai.vectorstore;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
@@ -4,8 +4,9 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.document.DocumentWriter;
|
||||
|
||||
public interface VectorStore {
|
||||
public interface VectorStore extends DocumentWriter {
|
||||
|
||||
/**
|
||||
* Adds Documents to the vector store.
|
||||
@@ -14,6 +15,10 @@ public interface VectorStore {
|
||||
*/
|
||||
void add(List<Document> documents);
|
||||
|
||||
default void accept(List<Document> documents) {
|
||||
add(documents);
|
||||
}
|
||||
|
||||
Optional<Boolean> delete(List<String> idList);
|
||||
|
||||
List<Document> similaritySearch(String query);
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.loader;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.impl.JsonLoader;
|
||||
import org.springframework.ai.reader.JsonReader;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -36,8 +36,8 @@ public class JsonLoaderTests {
|
||||
@Test
|
||||
void loadJson() {
|
||||
assertThat(resource).isNotNull();
|
||||
JsonLoader jsonLoader = new JsonLoader(resource, "description");
|
||||
List<Document> documents = jsonLoader.load();
|
||||
JsonReader jsonLoader = new JsonReader(resource, "description");
|
||||
List<Document> documents = jsonLoader.get();
|
||||
assertThat(documents).isNotEmpty();
|
||||
for (Document document : documents) {
|
||||
assertThat(document.getContent()).isNotEmpty();
|
||||
@@ -14,14 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.loader;
|
||||
package org.springframework.ai.reader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.impl.TextLoader;
|
||||
import org.springframework.ai.reader.TextReader;
|
||||
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
@@ -37,17 +38,19 @@ public class TextLoaderTests {
|
||||
@Test
|
||||
void loadText() {
|
||||
assertThat(resource).isNotNull();
|
||||
TextLoader textLoader = new TextLoader(resource);
|
||||
TextReader textLoader = new TextReader(resource);
|
||||
textLoader.getCustomMetadata().put("customKey", "Value");
|
||||
|
||||
List<Document> documents = textLoader.load();
|
||||
List<Document> documents0 = textLoader.get();
|
||||
|
||||
List<Document> documents = new TokenTextSplitter().apply(documents0);
|
||||
|
||||
assertThat(documents.size()).isEqualTo(54);
|
||||
|
||||
for (Document document : documents) {
|
||||
assertThat(document.getMetadata().get("customKey")).isEqualTo("Value");
|
||||
assertThat(document.getMetadata().get(TextLoader.SOURCE_METADATA)).isEqualTo("text_source.txt");
|
||||
assertThat(document.getMetadata().get(TextLoader.CHARSET_METADATA)).isEqualTo("UTF-8");
|
||||
assertThat(document.getMetadata().get(TextReader.SOURCE_METADATA)).isEqualTo("text_source.txt");
|
||||
assertThat(document.getMetadata().get(TextReader.CHARSET_METADATA)).isEqualTo("UTF-8");
|
||||
assertThat(document.getContent()).isNotEmpty();
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.splitter;
|
||||
package org.springframework.ai.transformer.splitter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.document.DefaultContentFormatter;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.transformer.splitter.TextSplitter;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
@@ -6,16 +6,17 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ai.client.AiClient;
|
||||
import org.springframework.ai.client.AiResponse;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.impl.JsonLoader;
|
||||
import org.springframework.ai.openai.embedding.OpenAiEmbeddingClient;
|
||||
import org.springframework.ai.openai.testutils.AbstractIT;
|
||||
import org.springframework.ai.prompt.Prompt;
|
||||
import org.springframework.ai.prompt.SystemPromptTemplate;
|
||||
import org.springframework.ai.prompt.messages.Message;
|
||||
import org.springframework.ai.prompt.messages.UserMessage;
|
||||
import org.springframework.ai.retriever.impl.VectorStoreRetriever;
|
||||
import org.springframework.ai.reader.JsonReader;
|
||||
import org.springframework.ai.retriever.VectorStoreRetriever;
|
||||
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
|
||||
import org.springframework.ai.vectorstore.InMemoryVectorStore;
|
||||
import org.springframework.ai.vectorstore.VectorStore;
|
||||
import org.springframework.ai.vectorstore.impl.InMemoryVectorStore;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -51,19 +52,20 @@ public class AcmeIT extends AbstractIT {
|
||||
assertThat(aiClient).isNotNull();
|
||||
}
|
||||
|
||||
// @Test
|
||||
@Test
|
||||
void acmeChain() {
|
||||
|
||||
// Step 1 - load documents
|
||||
JsonLoader jsonLoader = new JsonLoader(bikesResource, "name", "price", "shortDescription", "description");
|
||||
List<Document> documents = jsonLoader.load();
|
||||
JsonReader jsonLoader = new JsonReader(bikesResource, "name", "price", "shortDescription", "description");
|
||||
|
||||
var textSplitter = new TokenTextSplitter();
|
||||
|
||||
// Step 2 - Create embeddings and save to vector store
|
||||
|
||||
logger.info("Creating Embeddings...");
|
||||
VectorStore vectorStore = new InMemoryVectorStore(embeddingClient);
|
||||
|
||||
vectorStore.add(documents);
|
||||
vectorStore.accept(textSplitter.apply(jsonLoader.get()));
|
||||
|
||||
// Now user query
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ai.openai.extractor;
|
||||
package org.springframework.ai.openai.transformer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
@@ -27,11 +27,11 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.document.DefaultContentFormatter;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.loader.extractor.ContentFormatEnricher;
|
||||
import org.springframework.ai.loader.extractor.KeywordExtractor;
|
||||
import org.springframework.ai.loader.extractor.SummaryExtractor;
|
||||
import org.springframework.ai.loader.extractor.SummaryExtractor.SummaryType;
|
||||
import org.springframework.ai.openai.client.OpenAiClient;
|
||||
import org.springframework.ai.transformer.ContentFormatTransformer;
|
||||
import org.springframework.ai.transformer.KeywordMetadataEnricher;
|
||||
import org.springframework.ai.transformer.SummaryMetadataEnricher;
|
||||
import org.springframework.ai.transformer.SummaryMetadataEnricher.SummaryType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -44,16 +44,16 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
@SpringBootTest
|
||||
public class MetadataExtractorIT {
|
||||
public class MetadataTransformerIT {
|
||||
|
||||
@Autowired
|
||||
KeywordExtractor keywordExtractor;
|
||||
KeywordMetadataEnricher keywordMetadataEnricher;
|
||||
|
||||
@Autowired
|
||||
SummaryExtractor summaryExtractor;
|
||||
SummaryMetadataEnricher summaryMetadataEnricher;
|
||||
|
||||
@Autowired
|
||||
ContentFormatEnricher metadataExtractor;
|
||||
ContentFormatTransformer contentFormatTransformer;
|
||||
|
||||
@Autowired
|
||||
DefaultContentFormatter defaultContentFormatter;
|
||||
@@ -75,7 +75,7 @@ public class MetadataExtractorIT {
|
||||
@Test
|
||||
public void testKeywordExtractor() {
|
||||
|
||||
var updatedDocuments = keywordExtractor.apply(List.of(document1, document2));
|
||||
var updatedDocuments = keywordMetadataEnricher.apply(List.of(document1, document2));
|
||||
|
||||
List<Map<String, Object>> keywords = updatedDocuments.stream().map(d -> d.getMetadata()).toList();
|
||||
|
||||
@@ -92,7 +92,7 @@ public class MetadataExtractorIT {
|
||||
@Test
|
||||
public void testSummaryExtractor() {
|
||||
|
||||
var updatedDocuments = summaryExtractor.apply(List.of(document1, document2));
|
||||
var updatedDocuments = summaryMetadataEnricher.apply(List.of(document1, document2));
|
||||
|
||||
List<Map<String, Object>> summaries = updatedDocuments.stream().map(d -> d.getMetadata()).toList();
|
||||
|
||||
@@ -126,7 +126,7 @@ public class MetadataExtractorIT {
|
||||
assertThat(((DefaultContentFormatter) document2.getContentFormatter()).getExcludedInferenceMetadataKeys())
|
||||
.doesNotContain("NewInferenceKey");
|
||||
|
||||
List<Document> enrichedDocuments = metadataExtractor.apply(List.of(document1, document2));
|
||||
List<Document> enrichedDocuments = contentFormatTransformer.apply(List.of(document1, document2));
|
||||
|
||||
assertThat(enrichedDocuments.size()).isEqualTo(2);
|
||||
var doc1 = enrichedDocuments.get(0);
|
||||
@@ -173,13 +173,14 @@ public class MetadataExtractorIT {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeywordExtractor keywordExtractor(OpenAiClient aiClient) {
|
||||
return new KeywordExtractor(aiClient, 5);
|
||||
public KeywordMetadataEnricher keywordMetadata(OpenAiClient aiClient) {
|
||||
return new KeywordMetadataEnricher(aiClient, 5);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SummaryExtractor summaryExtractor(OpenAiClient aiClient) {
|
||||
return new SummaryExtractor(aiClient, List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));
|
||||
public SummaryMetadataEnricher summaryMetadata(OpenAiClient aiClient) {
|
||||
return new SummaryMetadataEnricher(aiClient,
|
||||
List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -191,8 +192,8 @@ public class MetadataExtractorIT {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ContentFormatEnricher metadataExtractor(DefaultContentFormatter defaultContentFormatter) {
|
||||
return new ContentFormatEnricher(defaultContentFormatter, false);
|
||||
public ContentFormatTransformer contentFormatTransformer(DefaultContentFormatter defaultContentFormatter) {
|
||||
return new ContentFormatTransformer(defaultContentFormatter, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import org.junit.jupiter.api.io.CleanupMode;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.embedding.EmbeddingClient;
|
||||
import org.springframework.ai.loader.impl.JsonLoader;
|
||||
import org.springframework.ai.loader.impl.JsonMetadataGenerator;
|
||||
import org.springframework.ai.vectorstore.impl.SimplePersistentVectorStore;
|
||||
import org.springframework.ai.reader.JsonReader;
|
||||
import org.springframework.ai.vectorstore.SimplePersistentVectorStore;
|
||||
import org.springframework.ai.reader.JsonMetadataGenerator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -31,9 +31,9 @@ public class SimplePersistentVectorStoreIT {
|
||||
|
||||
@Test
|
||||
void persist(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path workingDir) {
|
||||
JsonLoader jsonLoader = new JsonLoader(bikesJsonResource, new ProductMetadataGenerator(), "price", "name",
|
||||
JsonReader jsonLoader = new JsonReader(bikesJsonResource, new ProductMetadataGenerator(), "price", "name",
|
||||
"shortDescription", "description", "tags");
|
||||
List<Document> documents = jsonLoader.load();
|
||||
List<Document> documents = jsonLoader.get();
|
||||
SimplePersistentVectorStore vectorStore = new SimplePersistentVectorStore(this.embeddingClient);
|
||||
vectorStore.add(documents);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user