(improvement)(chat) Upgrade and optimize the embedding metastore. (#1198)
@@ -14,13 +14,12 @@ import com.tencent.supersonic.chat.server.plugin.event.PluginUpdateEvent;
|
|||||||
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
import com.tencent.supersonic.chat.server.pojo.ChatParseContext;
|
||||||
import com.tencent.supersonic.chat.server.service.PluginService;
|
import com.tencent.supersonic.chat.server.service.PluginService;
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import dev.langchain4j.store.embedding.Retrieval;
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQuery;
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementMatch;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementMatch;
|
||||||
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
||||||
@@ -49,7 +48,8 @@ public class PluginManager {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
|
|
||||||
public static List<Plugin> getPluginAgentCanSupport(ChatParseContext chatParseContext) {
|
public static List<Plugin> getPluginAgentCanSupport(ChatParseContext chatParseContext) {
|
||||||
PluginService pluginService = ContextUtils.getBean(PluginService.class);
|
PluginService pluginService = ContextUtils.getBean(PluginService.class);
|
||||||
@@ -122,7 +122,7 @@ public class PluginManager {
|
|||||||
embeddingQuery.setQueryId(id);
|
embeddingQuery.setQueryId(id);
|
||||||
queries.add(embeddingQuery);
|
queries.add(embeddingQuery);
|
||||||
}
|
}
|
||||||
s2EmbeddingStore.deleteQuery(presetCollection, queries);
|
embeddingService.deleteQuery(presetCollection, queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestEmbeddingPluginAdd(List<EmbeddingQuery> queries) {
|
public void requestEmbeddingPluginAdd(List<EmbeddingQuery> queries) {
|
||||||
@@ -130,7 +130,7 @@ public class PluginManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String presetCollection = embeddingConfig.getPresetCollection();
|
String presetCollection = embeddingConfig.getPresetCollection();
|
||||||
s2EmbeddingStore.addQuery(presetCollection, queries);
|
embeddingService.addQuery(presetCollection, queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestEmbeddingPluginAddALL(List<Plugin> plugins) {
|
public void requestEmbeddingPluginAddALL(List<Plugin> plugins) {
|
||||||
@@ -143,7 +143,7 @@ public class PluginManager {
|
|||||||
.queryTextsList(Collections.singletonList(embeddingText))
|
.queryTextsList(Collections.singletonList(embeddingText))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<RetrieveQueryResult> resultList = s2EmbeddingStore.retrieveQuery(embeddingConfig.getPresetCollection(),
|
List<RetrieveQueryResult> resultList = embeddingService.retrieveQuery(embeddingConfig.getPresetCollection(),
|
||||||
retrieveQuery, embeddingConfig.getNResult());
|
retrieveQuery, embeddingConfig.getNResult());
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(resultList)) {
|
if (CollectionUtils.isNotEmpty(resultList)) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.tencent.supersonic.chat.server.processor.execute;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
import com.tencent.supersonic.chat.server.pojo.ChatExecuteContext;
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.DictWordType;
|
||||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import dev.langchain4j.store.embedding.Retrieval;
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
@@ -13,6 +14,7 @@ import com.tencent.supersonic.headless.api.pojo.SchemaElementType;
|
|||||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||||
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
import com.tencent.supersonic.headless.api.pojo.response.QueryResult;
|
||||||
import com.tencent.supersonic.headless.chat.knowledge.MetaEmbeddingService;
|
import com.tencent.supersonic.headless.chat.knowledge.MetaEmbeddingService;
|
||||||
|
import java.util.Objects;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -66,8 +68,13 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
|||||||
}
|
}
|
||||||
for (Retrieval retrieval : retrievals) {
|
for (Retrieval retrieval : retrievals) {
|
||||||
if (!metricIds.contains(Retrieval.getLongId(retrieval.getId()))) {
|
if (!metricIds.contains(Retrieval.getLongId(retrieval.getId()))) {
|
||||||
SchemaElement schemaElement = JSONObject.parseObject(JSONObject.toJSONString(retrieval.getMetadata()),
|
if (Objects.nonNull(retrieval.getMetadata().get("id"))) {
|
||||||
SchemaElement.class);
|
String idStr = retrieval.getMetadata().get("id").toString()
|
||||||
|
.replaceAll(DictWordType.NATURE_SPILT, "");
|
||||||
|
retrieval.getMetadata().put("id", idStr);
|
||||||
|
}
|
||||||
|
String metaStr = JSONObject.toJSONString(retrieval.getMetadata());
|
||||||
|
SchemaElement schemaElement = JSONObject.parseObject(metaStr, SchemaElement.class);
|
||||||
if (retrieval.getMetadata().containsKey("dataSetId")) {
|
if (retrieval.getMetadata().containsKey("dataSetId")) {
|
||||||
String dataSetId = retrieval.getMetadata().get("dataSetId").toString()
|
String dataSetId = retrieval.getMetadata().get("dataSetId").toString()
|
||||||
.replace(Constants.UNDERLINE, "");
|
.replace(Constants.UNDERLINE, "");
|
||||||
|
|||||||
@@ -4,16 +4,24 @@ import com.google.common.collect.Lists;
|
|||||||
import com.tencent.supersonic.chat.api.pojo.request.SimilarQueryReq;
|
import com.tencent.supersonic.chat.api.pojo.request.SimilarQueryReq;
|
||||||
import com.tencent.supersonic.chat.api.pojo.response.SimilarQueryRecallResp;
|
import com.tencent.supersonic.chat.api.pojo.response.SimilarQueryRecallResp;
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
import dev.langchain4j.store.embedding.Retrieval;
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQuery;
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@@ -24,22 +32,14 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class SimilarQueryManager {
|
public class SimilarQueryManager {
|
||||||
|
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
|
|
||||||
|
|
||||||
public SimilarQueryManager(EmbeddingConfig embeddingConfig) {
|
public SimilarQueryManager(EmbeddingConfig embeddingConfig) {
|
||||||
@@ -60,7 +60,7 @@ public class SimilarQueryManager {
|
|||||||
metaData.put("agentId", similarQueryReq.getAgentId());
|
metaData.put("agentId", similarQueryReq.getAgentId());
|
||||||
embeddingQuery.setMetadata(metaData);
|
embeddingQuery.setMetadata(metaData);
|
||||||
String solvedQueryCollection = embeddingConfig.getSolvedQueryCollection();
|
String solvedQueryCollection = embeddingConfig.getSolvedQueryCollection();
|
||||||
s2EmbeddingStore.addQuery(solvedQueryCollection, Lists.newArrayList(embeddingQuery));
|
embeddingService.addQuery(solvedQueryCollection, Lists.newArrayList(embeddingQuery));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("save history question to embedding failed, queryText:{}", queryText, e);
|
log.warn("save history question to embedding failed, queryText:{}", queryText, e);
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ public class SimilarQueryManager {
|
|||||||
.queryTextsList(Lists.newArrayList(queryText))
|
.queryTextsList(Lists.newArrayList(queryText))
|
||||||
.filterCondition(filterCondition)
|
.filterCondition(filterCondition)
|
||||||
.build();
|
.build();
|
||||||
List<RetrieveQueryResult> resultList = s2EmbeddingStore.retrieveQuery(solvedQueryCollection, retrieveQuery,
|
List<RetrieveQueryResult> resultList = embeddingService.retrieveQuery(solvedQueryCollection, retrieveQuery,
|
||||||
solvedQueryResultNum * 20);
|
solvedQueryResultNum * 20);
|
||||||
|
|
||||||
log.info("[embedding] recognize result body:{}", resultList);
|
log.info("[embedding] recognize result body:{}", resultList);
|
||||||
|
|||||||
@@ -170,6 +170,24 @@
|
|||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-chroma</artifactId>
|
<artifactId>langchain4j-chroma</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-milvus</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-to-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>dev.langchain4j</groupId>
|
<groupId>dev.langchain4j</groupId>
|
||||||
<artifactId>langchain4j-azure-open-ai</artifactId>
|
<artifactId>langchain4j-azure-open-ai</artifactId>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
package dev.langchain4j.store.embedding;
|
package com.tencent.supersonic.common.service;
|
||||||
|
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supersonic EmbeddingStore
|
* Supersonic EmbeddingStore
|
||||||
* Enhanced the functionality by enabling the addition and querying of collection names.
|
* Enhanced the functionality by enabling the addition and querying of collection names.
|
||||||
*/
|
*/
|
||||||
public interface S2EmbeddingStore {
|
public interface EmbeddingService {
|
||||||
|
|
||||||
void addCollection(String collectionName);
|
void addCollection(String collectionName);
|
||||||
|
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package com.tencent.supersonic.common.service.impl;
|
||||||
|
|
||||||
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
|
import dev.langchain4j.data.embedding.Embedding;
|
||||||
|
import dev.langchain4j.model.embedding.BgeSmallZhEmbeddingModel;
|
||||||
|
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingMatch;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStoreFactory;
|
||||||
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
|
import dev.langchain4j.store.embedding.filter.Filter;
|
||||||
|
import dev.langchain4j.store.embedding.filter.comparison.IsEqualTo;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class EmbeddingServiceImpl implements EmbeddingService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EmbeddingStoreFactory embeddingStoreFactory;
|
||||||
|
|
||||||
|
public synchronized void addCollection(String collectionName) {
|
||||||
|
embeddingStoreFactory.create(collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addQuery(String collectionName, List<EmbeddingQuery> queries) {
|
||||||
|
EmbeddingStore embeddingStore = embeddingStoreFactory.create(collectionName);
|
||||||
|
EmbeddingModel embeddingModel = getEmbeddingModel();
|
||||||
|
for (EmbeddingQuery query : queries) {
|
||||||
|
String question = query.getQuery();
|
||||||
|
Embedding embedding = embeddingModel.embed(question).content();
|
||||||
|
embeddingStore.add(embedding, query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EmbeddingModel getEmbeddingModel() {
|
||||||
|
EmbeddingModel embeddingModel;
|
||||||
|
try {
|
||||||
|
embeddingModel = ContextUtils.getBean(EmbeddingModel.class);
|
||||||
|
} catch (NoSuchBeanDefinitionException e) {
|
||||||
|
embeddingModel = new BgeSmallZhEmbeddingModel();
|
||||||
|
}
|
||||||
|
return embeddingModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteQuery(String collectionName, List<EmbeddingQuery> queries) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RetrieveQueryResult> retrieveQuery(String collectionName, RetrieveQuery retrieveQuery, int num) {
|
||||||
|
EmbeddingStore embeddingStore = embeddingStoreFactory.create(collectionName);
|
||||||
|
EmbeddingModel embeddingModel = getEmbeddingModel();
|
||||||
|
List<RetrieveQueryResult> results = new ArrayList<>();
|
||||||
|
|
||||||
|
List<String> queryTextsList = retrieveQuery.getQueryTextsList();
|
||||||
|
Map<String, String> filterCondition = retrieveQuery.getFilterCondition();
|
||||||
|
for (String queryText : queryTextsList) {
|
||||||
|
Embedding embeddedText = embeddingModel.embed(queryText).content();
|
||||||
|
Filter filter = createCombinedFilter(filterCondition);
|
||||||
|
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
|
||||||
|
.queryEmbedding(embeddedText).filter(filter).maxResults(num).build();
|
||||||
|
|
||||||
|
EmbeddingSearchResult result = embeddingStore.search(request);
|
||||||
|
List<EmbeddingMatch<EmbeddingQuery>> relevant = result.matches();
|
||||||
|
|
||||||
|
RetrieveQueryResult retrieveQueryResult = new RetrieveQueryResult();
|
||||||
|
retrieveQueryResult.setQuery(queryText);
|
||||||
|
List<Retrieval> retrievals = new ArrayList<>();
|
||||||
|
for (EmbeddingMatch<EmbeddingQuery> embeddingMatch : relevant) {
|
||||||
|
Retrieval retrieval = new Retrieval();
|
||||||
|
EmbeddingQuery embedded = embeddingMatch.embedded();
|
||||||
|
retrieval.setDistance(1 - embeddingMatch.score());
|
||||||
|
retrieval.setId(embedded.getQueryId());
|
||||||
|
retrieval.setQuery(embedded.getQuery());
|
||||||
|
Map<String, Object> metadata = new HashMap<>();
|
||||||
|
if (Objects.nonNull(embedded)
|
||||||
|
&& MapUtils.isNotEmpty(embedded.getMetadata())) {
|
||||||
|
metadata.putAll(embedded.getMetadata());
|
||||||
|
}
|
||||||
|
retrieval.setMetadata(metadata);
|
||||||
|
retrievals.add(retrieval);
|
||||||
|
}
|
||||||
|
retrievals = retrievals.stream()
|
||||||
|
.sorted(Comparator.comparingDouble(Retrieval::getDistance).reversed())
|
||||||
|
.limit(num)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
retrieveQueryResult.setRetrieval(retrievals);
|
||||||
|
results.add(retrieveQueryResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Filter createCombinedFilter(Map<String, String> map) {
|
||||||
|
Filter result = null;
|
||||||
|
if (Objects.isNull(map)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||||
|
IsEqualTo isEqualTo = new IsEqualTo(entry.getKey(), entry.getValue());
|
||||||
|
result = (result == null) ? isEqualTo : Filter.and(result, isEqualTo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.langchain4j.inmemory.spring;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
class EmbeddingStoreProperties {
|
||||||
|
|
||||||
|
private String filePath;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package dev.langchain4j.inmemory.spring;
|
||||||
|
|
||||||
|
|
||||||
|
import static dev.langchain4j.inmemory.spring.Properties.PREFIX;
|
||||||
|
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStoreFactory;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(Properties.class)
|
||||||
|
public class InMemoryAutoConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(PREFIX + ".embedding-store.file-path")
|
||||||
|
EmbeddingStoreFactory milvusChatModel(Properties properties) {
|
||||||
|
return new InMemoryEmbeddingStoreFactory(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.langchain4j.inmemory.spring;
|
||||||
|
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingStoreFactory;
|
||||||
|
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class InMemoryEmbeddingStoreFactory implements EmbeddingStoreFactory {
|
||||||
|
|
||||||
|
private static Map<String, InMemoryEmbeddingStore<EmbeddingQuery>> collectionNameToStore =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
private Properties properties;
|
||||||
|
|
||||||
|
|
||||||
|
public InMemoryEmbeddingStoreFactory(Properties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized EmbeddingStore create(String collectionName) {
|
||||||
|
InMemoryEmbeddingStore<EmbeddingQuery> embeddingStore = collectionNameToStore.get(collectionName);
|
||||||
|
if (Objects.nonNull(embeddingStore)) {
|
||||||
|
return embeddingStore;
|
||||||
|
}
|
||||||
|
if (Objects.isNull(embeddingStore)) {
|
||||||
|
embeddingStore = new InMemoryEmbeddingStore();
|
||||||
|
collectionNameToStore.putIfAbsent(collectionName, embeddingStore);
|
||||||
|
}
|
||||||
|
return embeddingStore;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.langchain4j.inmemory.spring;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ConfigurationProperties(prefix = Properties.PREFIX)
|
||||||
|
public class Properties {
|
||||||
|
|
||||||
|
static final String PREFIX = "langchain4j.in-memory";
|
||||||
|
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
EmbeddingStoreProperties embeddingStore;
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package dev.langchain4j.store.embedding;
|
|
||||||
|
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class ComponentFactory {
|
|
||||||
|
|
||||||
private static S2EmbeddingStore s2EmbeddingStore;
|
|
||||||
|
|
||||||
public static S2EmbeddingStore getS2EmbeddingStore() {
|
|
||||||
if (Objects.isNull(s2EmbeddingStore)) {
|
|
||||||
s2EmbeddingStore = init(S2EmbeddingStore.class);
|
|
||||||
}
|
|
||||||
return s2EmbeddingStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> T init(Class<T> factoryType) {
|
|
||||||
return SpringFactoriesLoader.loadFactories(factoryType,
|
|
||||||
Thread.currentThread().getContextClassLoader()).get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,6 @@ public class EmbeddingQuery {
|
|||||||
private Map<String, Object> metadata;
|
private Map<String, Object> metadata;
|
||||||
|
|
||||||
private List<Double> queryEmbedding;
|
private List<Double> queryEmbedding;
|
||||||
|
|
||||||
public static List<EmbeddingQuery> convertToEmbedding(List<DataItem> dataItems) {
|
public static List<EmbeddingQuery> convertToEmbedding(List<DataItem> dataItems) {
|
||||||
return dataItems.stream().map(dataItem -> {
|
return dataItems.stream().map(dataItem -> {
|
||||||
EmbeddingQuery embeddingQuery = new EmbeddingQuery();
|
EmbeddingQuery embeddingQuery = new EmbeddingQuery();
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.langchain4j.store.embedding;
|
||||||
|
|
||||||
|
public interface EmbeddingStoreFactory {
|
||||||
|
|
||||||
|
EmbeddingStore create(String collectionName);
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package dev.langchain4j.store.embedding;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public class GsonInMemoryEmbeddingStoreJsonCodec implements InMemoryEmbeddingStoreJsonCodec {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InMemoryS2EmbeddingStore.InMemoryEmbeddingStore<EmbeddingQuery> fromJson(String json) {
|
|
||||||
Type type = new TypeToken<InMemoryS2EmbeddingStore.InMemoryEmbeddingStore<EmbeddingQuery>>() {
|
|
||||||
}.getType();
|
|
||||||
return new Gson().fromJson(json, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toJson(InMemoryS2EmbeddingStore.InMemoryEmbeddingStore<?> store) {
|
|
||||||
return new Gson().toJson(store);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package dev.langchain4j.store.embedding;
|
|
||||||
|
|
||||||
import dev.langchain4j.store.embedding.InMemoryS2EmbeddingStore.InMemoryEmbeddingStore;
|
|
||||||
|
|
||||||
public interface InMemoryEmbeddingStoreJsonCodec {
|
|
||||||
|
|
||||||
InMemoryEmbeddingStore<EmbeddingQuery> fromJson(String json);
|
|
||||||
|
|
||||||
String toJson(InMemoryEmbeddingStore<?> store);
|
|
||||||
}
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
package dev.langchain4j.store.embedding;
|
|
||||||
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
|
||||||
import dev.langchain4j.data.embedding.Embedding;
|
|
||||||
import dev.langchain4j.model.embedding.BgeSmallZhEmbeddingModel;
|
|
||||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.PriorityQueue;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static dev.langchain4j.internal.Utils.randomUUID;
|
|
||||||
import static java.nio.file.StandardOpenOption.CREATE;
|
|
||||||
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
|
|
||||||
import static java.util.Comparator.comparingDouble;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Implementation of S2EmbeddingStore within the Java process's in-memory.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class InMemoryS2EmbeddingStore implements S2EmbeddingStore {
|
|
||||||
|
|
||||||
public static final String PERSISTENT_FILE_PRE = "InMemory.";
|
|
||||||
private static Map<String, InMemoryEmbeddingStore<EmbeddingQuery>> collectionNameToStore =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void addCollection(String collectionName) {
|
|
||||||
InMemoryEmbeddingStore<EmbeddingQuery> embeddingStore = null;
|
|
||||||
Path filePath = getPersistentPath(collectionName);
|
|
||||||
try {
|
|
||||||
EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class);
|
|
||||||
if (Files.exists(filePath) && !collectionName.equals(embeddingConfig.getMetaCollectionName())
|
|
||||||
&& !collectionName.equals(embeddingConfig.getText2sqlCollectionName())) {
|
|
||||||
embeddingStore = InMemoryEmbeddingStore.fromFile(filePath);
|
|
||||||
embeddingStore.entries = new CopyOnWriteArraySet<>(embeddingStore.entries);
|
|
||||||
log.info("embeddingStore reload from file:{}", filePath);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("load persistentFile error, persistentFile:" + filePath, e);
|
|
||||||
}
|
|
||||||
if (Objects.isNull(embeddingStore)) {
|
|
||||||
embeddingStore = new InMemoryEmbeddingStore();
|
|
||||||
}
|
|
||||||
collectionNameToStore.putIfAbsent(collectionName, embeddingStore);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path getPersistentPath(String collectionName) {
|
|
||||||
EmbeddingConfig embeddingConfig = ContextUtils.getBean(EmbeddingConfig.class);
|
|
||||||
String persistentFile = PERSISTENT_FILE_PRE + collectionName;
|
|
||||||
return Paths.get(embeddingConfig.getEmbeddingStorePersistentPath(), persistentFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void persistentToFile() {
|
|
||||||
for (Entry<String, InMemoryEmbeddingStore<EmbeddingQuery>> entry : collectionNameToStore.entrySet()) {
|
|
||||||
Path filePath = getPersistentPath(entry.getKey());
|
|
||||||
try {
|
|
||||||
Path directoryPath = filePath.getParent();
|
|
||||||
if (!Files.exists(directoryPath)) {
|
|
||||||
Files.createDirectories(directoryPath);
|
|
||||||
}
|
|
||||||
entry.getValue().serializeToFile(filePath);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("persistentToFile error, persistentFile:" + filePath, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addQuery(String collectionName, List<EmbeddingQuery> queries) {
|
|
||||||
InMemoryEmbeddingStore<EmbeddingQuery> embeddingStore = getEmbeddingStore(collectionName);
|
|
||||||
EmbeddingModel embeddingModel = getEmbeddingModel();
|
|
||||||
for (EmbeddingQuery query : queries) {
|
|
||||||
String question = query.getQuery();
|
|
||||||
Embedding embedding = embeddingModel.embed(question).content();
|
|
||||||
embeddingStore.add(query.getQueryId(), embedding, query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static EmbeddingModel getEmbeddingModel() {
|
|
||||||
EmbeddingModel embeddingModel;
|
|
||||||
try {
|
|
||||||
embeddingModel = ContextUtils.getBean(EmbeddingModel.class);
|
|
||||||
} catch (NoSuchBeanDefinitionException e) {
|
|
||||||
embeddingModel = new BgeSmallZhEmbeddingModel();
|
|
||||||
}
|
|
||||||
return embeddingModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InMemoryEmbeddingStore<EmbeddingQuery> getEmbeddingStore(String collectionName) {
|
|
||||||
InMemoryEmbeddingStore<EmbeddingQuery> embeddingStore = collectionNameToStore.get(collectionName);
|
|
||||||
if (Objects.isNull(embeddingStore)) {
|
|
||||||
synchronized (InMemoryS2EmbeddingStore.class) {
|
|
||||||
addCollection(collectionName);
|
|
||||||
embeddingStore = collectionNameToStore.get(collectionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return embeddingStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteQuery(String collectionName, List<EmbeddingQuery> queries) {
|
|
||||||
//not support in InMemoryEmbeddingStore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RetrieveQueryResult> retrieveQuery(String collectionName, RetrieveQuery retrieveQuery, int num) {
|
|
||||||
InMemoryEmbeddingStore<EmbeddingQuery> embeddingStore = getEmbeddingStore(collectionName);
|
|
||||||
EmbeddingModel embeddingModel = getEmbeddingModel();
|
|
||||||
|
|
||||||
List<RetrieveQueryResult> results = new ArrayList<>();
|
|
||||||
|
|
||||||
List<String> queryTextsList = retrieveQuery.getQueryTextsList();
|
|
||||||
Map<String, String> filterCondition = retrieveQuery.getFilterCondition();
|
|
||||||
for (String queryText : queryTextsList) {
|
|
||||||
Embedding embeddedText = embeddingModel.embed(queryText).content();
|
|
||||||
int maxResults = getMaxResults(num, filterCondition);
|
|
||||||
List<EmbeddingMatch<EmbeddingQuery>> relevant = embeddingStore.findRelevant(embeddedText, maxResults);
|
|
||||||
|
|
||||||
RetrieveQueryResult retrieveQueryResult = new RetrieveQueryResult();
|
|
||||||
retrieveQueryResult.setQuery(queryText);
|
|
||||||
List<Retrieval> retrievals = new ArrayList<>();
|
|
||||||
for (EmbeddingMatch<EmbeddingQuery> embeddingMatch : relevant) {
|
|
||||||
Retrieval retrieval = new Retrieval();
|
|
||||||
retrieval.setDistance(1 - embeddingMatch.score());
|
|
||||||
retrieval.setId(embeddingMatch.embeddingId());
|
|
||||||
retrieval.setQuery(embeddingMatch.embedded().getQuery());
|
|
||||||
Map<String, Object> metadata = new HashMap<>();
|
|
||||||
if (Objects.nonNull(embeddingMatch.embedded())
|
|
||||||
&& MapUtils.isNotEmpty(embeddingMatch.embedded().getMetadata())) {
|
|
||||||
metadata.putAll(embeddingMatch.embedded().getMetadata());
|
|
||||||
}
|
|
||||||
if (filterRetrieval(filterCondition, metadata)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
retrieval.setMetadata(metadata);
|
|
||||||
retrievals.add(retrieval);
|
|
||||||
}
|
|
||||||
retrievals = retrievals.stream()
|
|
||||||
.sorted(Comparator.comparingDouble(Retrieval::getDistance).reversed())
|
|
||||||
.limit(num)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
retrieveQueryResult.setRetrieval(retrievals);
|
|
||||||
results.add(retrieveQueryResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getMaxResults(int num, Map<String, String> filterCondition) {
|
|
||||||
int maxResults = num;
|
|
||||||
if (MapUtils.isNotEmpty(filterCondition)) {
|
|
||||||
maxResults = num * 5;
|
|
||||||
}
|
|
||||||
return maxResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean filterRetrieval(Map<String, String> filterCondition, Map<String, Object> metadata) {
|
|
||||||
if (MapUtils.isNotEmpty(metadata) && MapUtils.isNotEmpty(filterCondition)) {
|
|
||||||
for (Entry<String, Object> entry : metadata.entrySet()) {
|
|
||||||
String filterValue = filterCondition.get(entry.getKey());
|
|
||||||
if (StringUtils.isNotBlank(filterValue) && !filterValue.equalsIgnoreCase(
|
|
||||||
entry.getValue().toString())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link EmbeddingStore} that stores embeddings in memory.
|
|
||||||
* <p>
|
|
||||||
* Uses a brute force approach by iterating over all embeddings to find the best matches.
|
|
||||||
*
|
|
||||||
* @param <Embedded> The class of the object that has been embedded.
|
|
||||||
* Typically, it is {@link dev.langchain4j.data.segment.TextSegment}.
|
|
||||||
* copy from dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore
|
|
||||||
* and fix concurrentModificationException in a multi-threaded environment
|
|
||||||
*/
|
|
||||||
public static class InMemoryEmbeddingStore<Embedded> implements EmbeddingStore<Embedded> {
|
|
||||||
|
|
||||||
private static class Entry<Embedded> {
|
|
||||||
|
|
||||||
String id;
|
|
||||||
Embedding embedding;
|
|
||||||
Embedded embedded;
|
|
||||||
|
|
||||||
Entry(String id, Embedding embedding, Embedded embedded) {
|
|
||||||
this.id = id;
|
|
||||||
this.embedding = embedding;
|
|
||||||
this.embedded = embedded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null || getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
InMemoryEmbeddingStore.Entry<?> that = (InMemoryEmbeddingStore.Entry<?>) o;
|
|
||||||
return Objects.equals(this.id, that.id)
|
|
||||||
&& Objects.equals(this.embedding, that.embedding)
|
|
||||||
&& Objects.equals(this.embedded, that.embedded);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, embedding, embedded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final InMemoryEmbeddingStoreJsonCodec CODEC = loadCodec();
|
|
||||||
private Set<Entry<Embedded>> entries = new CopyOnWriteArraySet<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String add(Embedding embedding) {
|
|
||||||
String id = randomUUID();
|
|
||||||
add(id, embedding);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(String id, Embedding embedding) {
|
|
||||||
add(id, embedding, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String add(Embedding embedding, Embedded embedded) {
|
|
||||||
String id = randomUUID();
|
|
||||||
add(id, embedding, embedded);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(String id, Embedding embedding, Embedded embedded) {
|
|
||||||
entries.add(new InMemoryEmbeddingStore.Entry<>(id, embedding, embedded));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> addAll(List<Embedding> embeddings) {
|
|
||||||
List<String> ids = new ArrayList<>();
|
|
||||||
for (Embedding embedding : embeddings) {
|
|
||||||
ids.add(add(embedding));
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> addAll(List<Embedding> embeddings, List<Embedded> embedded) {
|
|
||||||
if (embeddings.size() != embedded.size()) {
|
|
||||||
throw new IllegalArgumentException("The list of embeddings and embedded must have the same size");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> ids = new ArrayList<>();
|
|
||||||
for (int i = 0; i < embeddings.size(); i++) {
|
|
||||||
ids.add(add(embeddings.get(i), embedded.get(i)));
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<EmbeddingMatch<Embedded>> findRelevant(Embedding referenceEmbedding, int maxResults,
|
|
||||||
double minScore) {
|
|
||||||
|
|
||||||
Comparator<EmbeddingMatch<Embedded>> comparator = comparingDouble(EmbeddingMatch::score);
|
|
||||||
PriorityQueue<EmbeddingMatch<Embedded>> matches = new PriorityQueue<>(comparator);
|
|
||||||
|
|
||||||
for (InMemoryEmbeddingStore.Entry<Embedded> entry : entries) {
|
|
||||||
double cosineSimilarity = CosineSimilarity.between(entry.embedding, referenceEmbedding);
|
|
||||||
double score = RelevanceScore.fromCosineSimilarity(cosineSimilarity);
|
|
||||||
if (score >= minScore) {
|
|
||||||
matches.add(new EmbeddingMatch<>(score, entry.id, entry.embedding, entry.embedded));
|
|
||||||
if (matches.size() > maxResults) {
|
|
||||||
matches.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<EmbeddingMatch<Embedded>> result = new ArrayList<>(matches);
|
|
||||||
result.sort(comparator);
|
|
||||||
Collections.reverse(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null || getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
InMemoryEmbeddingStore<?> that = (InMemoryEmbeddingStore<?>) o;
|
|
||||||
return Objects.equals(this.entries, that.entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String serializeToJson() {
|
|
||||||
return CODEC.toJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serializeToFile(Path filePath) {
|
|
||||||
try {
|
|
||||||
String json = serializeToJson();
|
|
||||||
Files.write(filePath, json.getBytes(), CREATE, TRUNCATE_EXISTING);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serializeToFile(String filePath) {
|
|
||||||
serializeToFile(Paths.get(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static InMemoryEmbeddingStoreJsonCodec loadCodec() {
|
|
||||||
// fallback to default
|
|
||||||
return new GsonInMemoryEmbeddingStoreJsonCodec();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InMemoryEmbeddingStore<EmbeddingQuery> fromJson(String json) {
|
|
||||||
return CODEC.fromJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InMemoryEmbeddingStore<EmbeddingQuery> fromFile(Path filePath) {
|
|
||||||
try {
|
|
||||||
String json = new String(Files.readAllBytes(filePath));
|
|
||||||
return fromJson(json);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InMemoryEmbeddingStore<EmbeddingQuery> fromFile(String filePath) {
|
|
||||||
return fromFile(Paths.get(filePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
|
|||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import com.tencent.supersonic.common.util.ContextUtils;
|
import com.tencent.supersonic.common.util.ContextUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
@@ -25,7 +26,7 @@ import java.util.stream.Collectors;
|
|||||||
* Implementation of calling the Python service S2EmbeddingStore.
|
* Implementation of calling the Python service S2EmbeddingStore.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PythonServiceS2EmbeddingStore implements S2EmbeddingStore {
|
public class PythonServiceEmbeddingService implements EmbeddingService {
|
||||||
|
|
||||||
private RestTemplate restTemplate = new RestTemplate();
|
private RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
@@ -2,12 +2,11 @@ package com.tencent.supersonic.headless.chat.knowledge;
|
|||||||
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import com.tencent.supersonic.common.pojo.Constants;
|
import com.tencent.supersonic.common.pojo.Constants;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
|
import com.tencent.supersonic.headless.chat.knowledge.helper.NatureHelper;
|
||||||
import dev.langchain4j.store.embedding.Retrieval;
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQuery;
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
|
||||||
import com.tencent.supersonic.headless.chat.knowledge.helper.NatureHelper;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -26,7 +25,8 @@ import org.springframework.stereotype.Service;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class MetaEmbeddingService {
|
public class MetaEmbeddingService {
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ public class MetaEmbeddingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String collectionName = embeddingConfig.getMetaCollectionName();
|
String collectionName = embeddingConfig.getMetaCollectionName();
|
||||||
List<RetrieveQueryResult> resultList = s2EmbeddingStore.retrieveQuery(collectionName, retrieveQuery, num);
|
List<RetrieveQueryResult> resultList = embeddingService.retrieveQuery(collectionName, retrieveQuery, num);
|
||||||
if (CollectionUtils.isEmpty(resultList)) {
|
if (CollectionUtils.isEmpty(resultList)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,12 @@ package com.tencent.supersonic.headless.chat.parser.llm;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import com.tencent.supersonic.common.util.JsonUtil;
|
import com.tencent.supersonic.common.util.JsonUtil;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
import dev.langchain4j.store.embedding.Retrieval;
|
import dev.langchain4j.store.embedding.Retrieval;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQuery;
|
import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -24,6 +17,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@@ -31,7 +29,8 @@ public class ExemplarManager {
|
|||||||
|
|
||||||
private static final String EXAMPLE_JSON_FILE = "s2ql_exemplar.json";
|
private static final String EXAMPLE_JSON_FILE = "s2ql_exemplar.json";
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
private TypeReference<List<Exemplar>> valueTypeRef = new TypeReference<List<Exemplar>>() {
|
private TypeReference<List<Exemplar>> valueTypeRef = new TypeReference<List<Exemplar>>() {
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ public class ExemplarManager {
|
|||||||
embeddingQuery.setMetadata(metaDataMap);
|
embeddingQuery.setMetadata(metaDataMap);
|
||||||
queries.add(embeddingQuery);
|
queries.add(embeddingQuery);
|
||||||
}
|
}
|
||||||
s2EmbeddingStore.addQuery(collectionName, queries);
|
embeddingService.addQuery(collectionName, queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Map<String, String>> recallExemplars(String queryText, int maxResults) {
|
public List<Map<String, String>> recallExemplars(String queryText, int maxResults) {
|
||||||
@@ -64,7 +63,7 @@ public class ExemplarManager {
|
|||||||
RetrieveQuery retrieveQuery = RetrieveQuery.builder().queryTextsList(Collections.singletonList(queryText))
|
RetrieveQuery retrieveQuery = RetrieveQuery.builder().queryTextsList(Collections.singletonList(queryText))
|
||||||
.queryEmbeddings(null).build();
|
.queryEmbeddings(null).build();
|
||||||
|
|
||||||
List<RetrieveQueryResult> resultList = s2EmbeddingStore.retrieveQuery(collectionName, retrieveQuery,
|
List<RetrieveQueryResult> resultList = embeddingService.retrieveQuery(collectionName, retrieveQuery,
|
||||||
maxResults);
|
maxResults);
|
||||||
List<Map<String, String>> result = new ArrayList<>();
|
List<Map<String, String>> result = new ArrayList<>();
|
||||||
if (CollectionUtils.isEmpty(resultList)) {
|
if (CollectionUtils.isEmpty(resultList)) {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import com.tencent.supersonic.common.config.EmbeddingConfig;
|
|||||||
import com.tencent.supersonic.common.pojo.DataEvent;
|
import com.tencent.supersonic.common.pojo.DataEvent;
|
||||||
import com.tencent.supersonic.common.pojo.DataItem;
|
import com.tencent.supersonic.common.pojo.DataItem;
|
||||||
import com.tencent.supersonic.common.pojo.enums.EventType;
|
import com.tencent.supersonic.common.pojo.enums.EventType;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
import java.util.List;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@@ -15,8 +15,6 @@ import org.springframework.scheduling.annotation.Async;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class MetaEmbeddingListener implements ApplicationListener<DataEvent> {
|
public class MetaEmbeddingListener implements ApplicationListener<DataEvent> {
|
||||||
@@ -24,7 +22,8 @@ public class MetaEmbeddingListener implements ApplicationListener<DataEvent> {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
|
|
||||||
@Value("${embedding.operation.sleep.time:3000}")
|
@Value("${embedding.operation.sleep.time:3000}")
|
||||||
private Integer embeddingOperationSleepTime;
|
private Integer embeddingOperationSleepTime;
|
||||||
@@ -41,14 +40,14 @@ public class MetaEmbeddingListener implements ApplicationListener<DataEvent> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sleep();
|
sleep();
|
||||||
s2EmbeddingStore.addCollection(embeddingConfig.getMetaCollectionName());
|
embeddingService.addCollection(embeddingConfig.getMetaCollectionName());
|
||||||
if (event.getEventType().equals(EventType.ADD)) {
|
if (event.getEventType().equals(EventType.ADD)) {
|
||||||
s2EmbeddingStore.addQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
embeddingService.addQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
||||||
} else if (event.getEventType().equals(EventType.DELETE)) {
|
} else if (event.getEventType().equals(EventType.DELETE)) {
|
||||||
s2EmbeddingStore.deleteQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
embeddingService.deleteQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
||||||
} else if (event.getEventType().equals(EventType.UPDATE)) {
|
} else if (event.getEventType().equals(EventType.UPDATE)) {
|
||||||
s2EmbeddingStore.deleteQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
embeddingService.deleteQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
||||||
s2EmbeddingStore.addQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
embeddingService.addQuery(embeddingConfig.getMetaCollectionName(), embeddingQueries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,25 +2,23 @@ package com.tencent.supersonic.headless.server.schedule;
|
|||||||
|
|
||||||
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||||
import com.tencent.supersonic.common.pojo.DataItem;
|
import com.tencent.supersonic.common.pojo.DataItem;
|
||||||
import dev.langchain4j.store.embedding.ComponentFactory;
|
import com.tencent.supersonic.common.service.EmbeddingService;
|
||||||
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
|
||||||
import dev.langchain4j.store.embedding.InMemoryS2EmbeddingStore;
|
|
||||||
import dev.langchain4j.store.embedding.S2EmbeddingStore;
|
|
||||||
import com.tencent.supersonic.headless.server.service.DimensionService;
|
import com.tencent.supersonic.headless.server.service.DimensionService;
|
||||||
import com.tencent.supersonic.headless.server.service.MetricService;
|
import com.tencent.supersonic.headless.server.service.MetricService;
|
||||||
|
import dev.langchain4j.store.embedding.EmbeddingQuery;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EmbeddingTask {
|
public class EmbeddingTask {
|
||||||
|
|
||||||
private S2EmbeddingStore s2EmbeddingStore = ComponentFactory.getS2EmbeddingStore();
|
@Autowired
|
||||||
|
private EmbeddingService embeddingService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private EmbeddingConfig embeddingConfig;
|
private EmbeddingConfig embeddingConfig;
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -31,23 +29,22 @@ public class EmbeddingTask {
|
|||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void onShutdown() {
|
public void onShutdown() {
|
||||||
embeddingStorePersistentToFile();
|
// embeddingStorePersistentToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void embeddingStorePersistentToFile() {
|
// private void embeddingStorePersistentToFile() {
|
||||||
if (s2EmbeddingStore instanceof InMemoryS2EmbeddingStore) {
|
// if (embeddingService instanceof InMemoryEmbeddingService) {
|
||||||
log.info("start persistentToFile");
|
// log.info("start persistentToFile");
|
||||||
((InMemoryS2EmbeddingStore) s2EmbeddingStore).persistentToFile();
|
// ((InMemoryEmbeddingService) embeddingService).persistentToFile();
|
||||||
log.info("end persistentToFile");
|
// log.info("end persistentToFile");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Scheduled(cron = "${inMemoryEmbeddingStore.persistent.cron:0 0 * * * ?}")
|
@Scheduled(cron = "${inMemoryEmbeddingStore.persistent.cron:0 0 * * * ?}")
|
||||||
public void executeTask() {
|
public void executeTask() {
|
||||||
embeddingStorePersistentToFile();
|
// embeddingStorePersistentToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* reload meta embedding
|
* reload meta embedding
|
||||||
*/
|
*/
|
||||||
@@ -57,11 +54,11 @@ public class EmbeddingTask {
|
|||||||
try {
|
try {
|
||||||
List<DataItem> metricDataItems = metricService.getDataEvent().getDataItems();
|
List<DataItem> metricDataItems = metricService.getDataEvent().getDataItems();
|
||||||
|
|
||||||
s2EmbeddingStore.addQuery(embeddingConfig.getMetaCollectionName(),
|
embeddingService.addQuery(embeddingConfig.getMetaCollectionName(),
|
||||||
EmbeddingQuery.convertToEmbedding(metricDataItems));
|
EmbeddingQuery.convertToEmbedding(metricDataItems));
|
||||||
|
|
||||||
List<DataItem> dimensionDataItems = dimensionService.getDataEvent().getDataItems();
|
List<DataItem> dimensionDataItems = dimensionService.getDataEvent().getDataItems();
|
||||||
s2EmbeddingStore.addQuery(embeddingConfig.getMetaCollectionName(),
|
embeddingService.addQuery(embeddingConfig.getMetaCollectionName(),
|
||||||
EmbeddingQuery.convertToEmbedding(dimensionDataItems));
|
EmbeddingQuery.convertToEmbedding(dimensionDataItems));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("reload.meta.embedding error", e);
|
log.error("reload.meta.embedding error", e);
|
||||||
|
|||||||
@@ -43,5 +43,5 @@ com.tencent.supersonic.chat.server.processor.execute.ExecuteResultProcessor=\
|
|||||||
com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor
|
com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor
|
||||||
|
|
||||||
|
|
||||||
dev.langchain4j.store.embedding.S2EmbeddingStore=\
|
com.tencent.supersonic.common.service.EmbeddingService=\
|
||||||
dev.langchain4j.store.embedding.InMemoryS2EmbeddingStore
|
dev.langchain4j.inmemory.spring.InMemoryEmbeddingService
|
||||||
@@ -4,8 +4,8 @@ com.tencent.supersonic.auth.authentication.interceptor.AuthenticationInterceptor
|
|||||||
com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor=\
|
com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor=\
|
||||||
com.tencent.supersonic.auth.authentication.adaptor.DefaultUserAdaptor
|
com.tencent.supersonic.auth.authentication.adaptor.DefaultUserAdaptor
|
||||||
|
|
||||||
dev.langchain4j.store.embedding.S2EmbeddingStore=\
|
com.tencent.supersonic.common.service.EmbeddingService=\
|
||||||
dev.langchain4j.store.embedding.InMemoryS2EmbeddingStore
|
dev.langchain4j.inmemory.spring.InMemoryEmbeddingService
|
||||||
|
|
||||||
|
|
||||||
com.tencent.supersonic.headless.core.parser.converter.HeadlessConverter=\
|
com.tencent.supersonic.headless.core.parser.converter.HeadlessConverter=\
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ com.tencent.supersonic.auth.api.authentication.adaptor.UserAdaptor=\
|
|||||||
|
|
||||||
### common SPIs
|
### common SPIs
|
||||||
|
|
||||||
dev.langchain4j.store.embedding.S2EmbeddingStore=\
|
com.tencent.supersonic.common.service.EmbeddingService=\
|
||||||
dev.langchain4j.store.embedding.InMemoryS2EmbeddingStore
|
dev.langchain4j.inmemory.spring.InMemoryEmbeddingService
|
||||||
|
|
||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
dev.langchain4j.spring.LangChain4jAutoConfig,\
|
dev.langchain4j.spring.LangChain4jAutoConfig,\
|
||||||
|
|||||||
@@ -109,4 +109,6 @@ langchain4j:
|
|||||||
# embedding-model:
|
# embedding-model:
|
||||||
# api-key: ${OPENAI_API_KEY:demo}
|
# api-key: ${OPENAI_API_KEY:demo}
|
||||||
|
|
||||||
|
in-memory:
|
||||||
|
embedding-store:
|
||||||
|
file-path: /tmp
|
||||||
|
|||||||
@@ -106,4 +106,7 @@ langchain4j:
|
|||||||
# java.lang.RuntimeException: dev.ai4j.openai4j.OpenAiHttpException: Too many requests
|
# java.lang.RuntimeException: dev.ai4j.openai4j.OpenAiHttpException: Too many requests
|
||||||
# embedding-model:
|
# embedding-model:
|
||||||
# base-url: ${OPENAI_API_BASE:https://api.openai.com/v1}
|
# base-url: ${OPENAI_API_BASE:https://api.openai.com/v1}
|
||||||
# api-key: ${OPENAI_API_KEY:demo}
|
# api-key: ${OPENAI_API_KEY:demo}
|
||||||
|
in-memory:
|
||||||
|
embedding-store:
|
||||||
|
file-path: /tmp
|
||||||
21
pom.xml
@@ -206,7 +206,26 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-milvus</artifactId>
|
||||||
|
<version>${langchain4j.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-to-slf4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!---langchain4j-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||||
|
|||||||
1
webapp/supersonic-webapp/CNAME
Normal file
@@ -0,0 +1 @@
|
|||||||
|
preview.pro.ant.design
|
||||||
23
webapp/supersonic-webapp/asset-manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"/umi.css": "/webapp/umi.b2bea3a5.css",
|
||||||
|
"/umi.js": "/webapp/umi.4ebb29c3.js",
|
||||||
|
"/umi.woff2": "/webapp/static/iconfont.0ac2d58a.woff2",
|
||||||
|
"/umi.ttf": "/webapp/static/iconfont.7ae6e4e0.ttf",
|
||||||
|
"/umi.woff": "/webapp/static/iconfont.0de60a33.woff",
|
||||||
|
"/umi.svg": "/webapp/static/cloudEditor.1a9aa2c1.svg",
|
||||||
|
"/public/home_bg.png": "/webapp/home_bg.png",
|
||||||
|
"/static/iconfont.svg?t=1659425018463": "/webapp/static/iconfont.92a3f736.svg",
|
||||||
|
"/static/cloudEditor.svg": "/webapp/static/cloudEditor.1a9aa2c1.svg",
|
||||||
|
"/static/iconfont.ttf?t=1659425018463": "/webapp/static/iconfont.7ae6e4e0.ttf",
|
||||||
|
"/static/iconfont.woff?t=1659425018463": "/webapp/static/iconfont.0de60a33.woff",
|
||||||
|
"/static/iconfont.woff2?t=1659425018463": "/webapp/static/iconfont.0ac2d58a.woff2",
|
||||||
|
"/public/icons/icon-512x512.png": "/webapp/icons/icon-512x512.png",
|
||||||
|
"/public/icons/icon-192x192.png": "/webapp/icons/icon-192x192.png",
|
||||||
|
"/public/icons/icon-128x128.png": "/webapp/icons/icon-128x128.png",
|
||||||
|
"/public/logo.svg": "/webapp/logo.svg",
|
||||||
|
"/public/pro_icon.svg": "/webapp/pro_icon.svg",
|
||||||
|
"/public/favicon.ico": "/webapp/favicon.ico",
|
||||||
|
"/public/version.js": "/webapp/version.js",
|
||||||
|
"/public/CNAME": "/webapp/CNAME",
|
||||||
|
"/public/supersonic.config.json": "/webapp/supersonic.config.json"
|
||||||
|
}
|
||||||
BIN
webapp/supersonic-webapp/favicon.ico
Normal file
|
After Width: | Height: | Size: 551 B |
BIN
webapp/supersonic-webapp/home_bg.png
Normal file
|
After Width: | Height: | Size: 199 KiB |
BIN
webapp/supersonic-webapp/icons/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
webapp/supersonic-webapp/icons/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
webapp/supersonic-webapp/icons/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
34
webapp/supersonic-webapp/index.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta
|
||||||
|
http-equiv="Cache-Control"
|
||||||
|
content="no-cache, no-store, must-revalidate"
|
||||||
|
/>
|
||||||
|
<meta http-equiv="Pragma" content="no-cache" />
|
||||||
|
<meta http-equiv="Expires" content="0" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
|
||||||
|
/>
|
||||||
|
<title>超音数(SuperSonic)</title>
|
||||||
|
<link rel="icon" href="/webapp/favicon.ico" type="image/x-icon" />
|
||||||
|
<meta name="app_version" content="2023-09-04 00:07:38" />
|
||||||
|
<link rel="stylesheet" href="/webapp/umi.b2bea3a5.css" />
|
||||||
|
<script>
|
||||||
|
window.routerBase = "/webapp/";
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
//! umi version: 3.5.41
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>Out-of-the-box mid-stage front/design solution!</noscript>
|
||||||
|
|
||||||
|
<div id="root"></div>
|
||||||
|
<script src="/webapp/umi.4ebb29c3.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1
webapp/supersonic-webapp/logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 18" class="design-iconfont" width="128" height="128"><path d="M24.7272727,4.26325641e-14 L33.5127273,17.4545455 L26.5345455,17.4545455 L21.1236364,6.70181818 L24.7272727,4.26325641e-14 Z M17.52,4.26325641e-14 L21.1236364,6.70181818 L15.7127273,17.4545455 L8.73090909,17.4545455 L17.52,4.26325641e-14 Z M41.5890909,12.6945455 L43.9818182,17.4545455 L35.0909091,17.4545455 L32.6981818,12.6945455 L41.5890909,12.6945455 Z M12.68,6.32 L7.08,17.4545455 L0.498181818,17.4545455 L6.09818182,6.32 L12.68,6.32 Z M38.4145455,6.32 L40.9090909,11.2727273 L32.0181818,11.2727273 L29.5272727,6.32 L38.4145455,6.32 Z M15.7890909,0.141818182 L13.3963636,4.89818182 L-3.55271368e-14,4.89818182 L2.39272727,0.141818182 L15.7890909,0.141818182 Z M35.2690909,0.141818182 L37.6654545,4.89818182 L28.7745455,4.89818182 L26.3818182,0.141818182 L35.2690909,0.141818182 Z" fill-rule="evenodd" fill="#1890ff"></path></svg>
|
||||||
|
After Width: | Height: | Size: 953 B |
5
webapp/supersonic-webapp/pro_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="42" height="42" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g>
|
||||||
|
<path fill="#070707" d="m6.717392,13.773912l5.6,0c2.8,0 4.7,1.9 4.7,4.7c0,2.8 -2,4.7 -4.9,4.7l-2.5,0l0,4.3l-2.9,0l0,-13.7zm2.9,2.2l0,4.9l1.9,0c1.6,0 2.6,-0.9 2.6,-2.4c0,-1.6 -0.9,-2.4 -2.6,-2.4l-1.9,0l0,-0.1zm8.9,11.5l2.7,0l0,-5.7c0,-1.4 0.8,-2.3 2.2,-2.3c0.4,0 0.8,0.1 1,0.2l0,-2.4c-0.2,-0.1 -0.5,-0.1 -0.8,-0.1c-1.2,0 -2.1,0.7 -2.4,2l-0.1,0l0,-1.9l-2.7,0l0,10.2l0.1,0zm11.7,0.1c-3.1,0 -5,-2 -5,-5.3c0,-3.3 2,-5.3 5,-5.3s5,2 5,5.3c0,3.4 -1.9,5.3 -5,5.3zm0,-2.1c1.4,0 2.2,-1.1 2.2,-3.2c0,-2 -0.8,-3.2 -2.2,-3.2c-1.4,0 -2.2,1.2 -2.2,3.2c0,2.1 0.8,3.2 2.2,3.2z" class="st0" id="Ant-Design-Pro"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 677 B |
10
webapp/supersonic-webapp/static/cloudEditor.1a9aa2c1.svg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
webapp/supersonic-webapp/static/iconfont.0ac2d58a.woff2
Normal file
BIN
webapp/supersonic-webapp/static/iconfont.0de60a33.woff
Normal file
BIN
webapp/supersonic-webapp/static/iconfont.7ae6e4e0.ttf
Normal file
181
webapp/supersonic-webapp/static/iconfont.92a3f736.svg
Normal file
|
After Width: | Height: | Size: 97 KiB |
3
webapp/supersonic-webapp/supersonic.config.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"env": ""
|
||||||
|
}
|
||||||
3185
webapp/supersonic-webapp/umi.4ebb29c3.js
Normal file
2
webapp/supersonic-webapp/umi.b2bea3a5.css
Normal file
1
webapp/supersonic-webapp/version.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
feVersion={commitId:"774ea83b7f7505d0711e3bf6cb31dd6a31dfbf30",updateTime:"Mon Sep 04 2023 00:07:35 GMT+0800 (China Standard Time)"};
|
||||||