embedding

This commit is contained in:
robin
2023-10-15 19:37:21 +08:00
parent f8b504fd4d
commit 27b81756c2
17 changed files with 603 additions and 56 deletions

View File

@ -78,6 +78,10 @@
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>ai.chat2db</groupId>
<artifactId>chat2db-spi</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -106,9 +106,6 @@ public class ChatController {
@Resource
private GatewayClientService gatewayClientService;
@Getter
private OpenAiApi openAiApi;
/**
* chat的超时时间
*/
@ -316,7 +313,7 @@ public class ChatController {
buildSseEmitter(sseEmitter, uid);
OpenAIEventSourceListener openAIEventSourceListener = new OpenAIEventSourceListener(sseEmitter);
Chat2dbAIClient.getInstance().streamChatCompletion(messages, openAIEventSourceListener);
Chat2dbAIClient.getInstance().streamCompletions(messages, openAIEventSourceListener);
LocalCache.CACHE.put(uid, JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT);
return sseEmitter;
}
@ -564,21 +561,18 @@ public class ChatController {
public FastChatEmbeddingResponse distributeAIEmbedding(String input) {
ConfigService configService = ApplicationContextUtil.getBean(ConfigService.class);
Config config = configService.find(RestAIClient.AI_SQL_SOURCE).getData();
String aiSqlSource = AiSqlSourceEnum.CHAT2DBAI.getCode();
if (Objects.nonNull(config)) {
aiSqlSource = config.getContent();
String aiSqlSource = config.getContent();
if (Objects.isNull(aiSqlSource)) {
return null;
}
AiSqlSourceEnum aiSqlSourceEnum = AiSqlSourceEnum.getByName(aiSqlSource);
switch (Objects.requireNonNull(aiSqlSourceEnum)) {
case AZUREAI :
case OPENAI:
case CHAT2DBAI:
return embeddingWithOpenAi(input);
case RESTAI :
return embeddingWithChat2dbAi(input);
case FASTCHATAI:
return embeddingWithFastChatAi(input);
}
return embeddingWithFastChatAi(input);
return null;
}
/**
@ -599,11 +593,9 @@ public class ChatController {
* @param input
* @return
*/
private FastChatEmbeddingResponse embeddingWithOpenAi(String input) {
Embedding embedding = Embedding.builder().input(input).build();
Single<EmbeddingResponse> embeddings = this.openAiApi.embeddings(embedding);
EmbeddingResponse embeddingResponse = embeddings.blockingGet();
return chatConverter.response2response(embeddingResponse);
private FastChatEmbeddingResponse embeddingWithChat2dbAi(String input) {
FastChatEmbeddingResponse embeddings = Chat2dbAIClient.getInstance().embeddings(input);
return embeddings;
}
}

View File

@ -1,20 +1,29 @@
package ai.chat2db.server.web.api.controller.ai;
import ai.chat2db.server.domain.api.enums.AiSqlSourceEnum;
import ai.chat2db.server.domain.api.model.Config;
import ai.chat2db.server.domain.api.param.ShowCreateTableParam;
import ai.chat2db.server.domain.api.param.TablePageQueryParam;
import ai.chat2db.server.domain.api.param.TableSelector;
import ai.chat2db.server.domain.api.param.TableVectorParam;
import ai.chat2db.server.domain.api.service.ConfigService;
import ai.chat2db.server.domain.api.service.TableService;
import ai.chat2db.server.tools.base.enums.WhiteListTypeEnum;
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.tools.base.wrapper.result.PageResult;
import ai.chat2db.server.tools.common.exception.ParamBusinessException;
import ai.chat2db.server.web.api.aspect.ConnectionInfoAspect;
import ai.chat2db.server.web.api.controller.ai.chat2db.client.Chat2dbAIClient;
import ai.chat2db.server.web.api.controller.ai.fastchat.embeddings.FastChatEmbeddingResponse;
import ai.chat2db.server.web.api.controller.ai.rest.client.RestAIClient;
import ai.chat2db.server.web.api.controller.rdb.converter.RdbWebConverter;
import ai.chat2db.server.web.api.controller.rdb.request.TableBriefQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableMilvusQueryRequest;
import ai.chat2db.server.web.api.http.GatewayClientService;
import ai.chat2db.server.web.api.http.request.TableSchemaRequest;
import ai.chat2db.server.web.api.http.request.WhiteListRequest;
import ai.chat2db.server.web.api.util.ApplicationContextUtil;
import ai.chat2db.spi.model.Table;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
@ -23,10 +32,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.math.BigDecimal;
@ -53,6 +59,15 @@ public class EmbeddingController extends ChatController {
@Autowired
private TableService tableService;
/**
* check if in white list
*/
@GetMapping("/white/check")
public DataResult<Boolean> checkInWhite(WhiteListRequest request) {
request.setWhiteType(WhiteListTypeEnum.VECTOR.getCode());
return gatewayClientService.checkInWhite(request);
}
/**
* save datasource embeddings
*
@ -66,6 +81,7 @@ public class EmbeddingController extends ChatController {
throws Exception {
// query tables
request.setPageNo(1);
request.setPageSize(1000);
TablePageQueryParam queryParam = rdbWebConverter.tablePageRequest2param(request);
TableSelector tableSelector = new TableSelector();
@ -128,6 +144,51 @@ public class EmbeddingController extends ChatController {
return ActionResult.isSuccess();
}
/**
* sync table vector
*
* @param param
*/
public void syncTableVector(TableBriefQueryRequest param) throws Exception {
TableVectorParam vectorParam = rdbWebConverter.param2param(param);
if (Objects.isNull(vectorParam.getDataSourceId())) {
return;
}
if (StringUtils.isBlank(vectorParam.getDatabase()) && StringUtils.isBlank(vectorParam.getSchema())) {
return;
}
DataResult<Boolean> result = tableService.checkTableVector(vectorParam);
if (result.getData()) {
return;
}
ConfigService configService = ApplicationContextUtil.getBean(ConfigService.class);
Config config = configService.find(RestAIClient.AI_SQL_SOURCE).getData();
String aiSqlSource = AiSqlSourceEnum.CHAT2DBAI.getCode();
// only sync for chat2db ai
if (Objects.isNull(config) || !aiSqlSource.equals(config.getContent())) {
return;
}
Config keyConfig = configService.find(Chat2dbAIClient.CHAT2DB_OPENAI_KEY).getData();
if (Objects.isNull(keyConfig) || StringUtils.isBlank(keyConfig.getContent())) {
return;
}
TableMilvusQueryRequest request = rdbWebConverter.request2request(param);
String apiKey = keyConfig.getContent();
request.setApikey(apiKey);
// check if in white list
boolean res = gatewayClientService.checkInWhite(new WhiteListRequest(apiKey, WhiteListTypeEnum.VECTOR.getCode())).getData();
if (!res) {
return;
}
embeddings(request);
tableService.saveTableVector(vectorParam);
}
/**
* save table embedding
*
@ -144,10 +205,13 @@ public class EmbeddingController extends ChatController {
// request embedding
FastChatEmbeddingResponse response = distributeAIEmbedding(str);
if(response == null){
continue;
throw new ParamBusinessException();
}
contentVector.add(response.getData().get(0).getEmbedding());
}
if (CollectionUtils.isEmpty(contentVector)) {
throw new ParamBusinessException();
}
tableSchemaRequest.setSchemaVector(contentVector);
// save table embedding

View File

@ -0,0 +1,276 @@
package ai.chat2db.server.web.api.controller.ai.chat2db.client;
import ai.chat2db.server.tools.common.exception.ParamBusinessException;
import ai.chat2db.server.web.api.controller.ai.fastchat.client.FastChatOpenAiApi;
import ai.chat2db.server.web.api.controller.ai.fastchat.embeddings.FastChatEmbedding;
import ai.chat2db.server.web.api.controller.ai.fastchat.embeddings.FastChatEmbeddingResponse;
import cn.hutool.http.ContentType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.unfbx.chatgpt.entity.chat.ChatCompletion;
import com.unfbx.chatgpt.entity.chat.Message;
import com.unfbx.chatgpt.interceptor.HeaderAuthorizationInterceptor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* Fast Chat Aligned Client
*
* @author moji
*/
@Slf4j
public class Chat2DBAIStreamClient {
/**
* apikey
*/
@Getter
@NotNull
private String apiKey;
/**
* apiHost
*/
@Getter
@NotNull
private String apiHost;
/**
* model
*/
@Getter
private String model;
/**
* embeddingModel
*/
@Getter
private String embeddingModel;
/**
* okHttpClient
*/
@Getter
private OkHttpClient okHttpClient;
@Getter
private FastChatOpenAiApi fastChatOpenAiApi;
/**
* @param builder
*/
private Chat2DBAIStreamClient(Builder builder) {
this.apiKey = builder.apiKey;
this.apiHost = builder.apiHost;
if (!apiHost.endsWith("/")){
apiHost = apiHost + "/";
}
this.model = builder.model;
this.embeddingModel = builder.embeddingModel;
if (Objects.isNull(builder.okHttpClient)) {
builder.okHttpClient = this.okHttpClient();
}
okHttpClient = builder.okHttpClient;
this.fastChatOpenAiApi = new Retrofit.Builder()
.baseUrl(apiHost)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build().create(FastChatOpenAiApi.class);
}
/**
* okhttpclient
*/
private OkHttpClient okHttpClient() {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.addInterceptor(new HeaderAuthorizationInterceptor(Lists.newArrayList(this.apiKey)))
.connectTimeout(50, TimeUnit.SECONDS)
.writeTimeout(50, TimeUnit.SECONDS)
.readTimeout(50, TimeUnit.SECONDS)
.build();
return okHttpClient;
}
/**
* 构造
*
* @return
*/
public static Chat2DBAIStreamClient.Builder builder() {
return new Chat2DBAIStreamClient.Builder();
}
/**
* builder
*/
public static final class Builder {
private String apiKey;
private String apiHost;
private String model;
private String embeddingModel;
/**
* OkhttpClient
*/
private OkHttpClient okHttpClient;
public Builder() {
}
public Chat2DBAIStreamClient.Builder apiKey(String apiKeyValue) {
this.apiKey = apiKeyValue;
return this;
}
/**
* @param apiHostValue
* @return
*/
public Chat2DBAIStreamClient.Builder apiHost(String apiHostValue) {
this.apiHost = apiHostValue;
return this;
}
/**
* @param modelValue
* @return
*/
public Chat2DBAIStreamClient.Builder model(String modelValue) {
this.model = modelValue;
return this;
}
public Chat2DBAIStreamClient.Builder embeddingModel(String embeddingModelValue) {
this.embeddingModel = embeddingModelValue;
return this;
}
public Chat2DBAIStreamClient.Builder okHttpClient(OkHttpClient val) {
this.okHttpClient = val;
return this;
}
public Chat2DBAIStreamClient build() {
return new Chat2DBAIStreamClient(this);
}
}
/**
* 问答接口 stream 形式
*
* @param chatMessages
* @param eventSourceListener
*/
public void streamCompletions(List<Message> chatMessages, EventSourceListener eventSourceListener) {
if (CollectionUtils.isEmpty(chatMessages)) {
log.error("param error:Chat Prompt cannot be empty");
throw new ParamBusinessException("prompt");
}
if (Objects.isNull(eventSourceListener)) {
log.error("param errorChatEventSourceListener cannot be empty");
throw new ParamBusinessException();
}
log.info("Chat AI, prompt:{}", chatMessages.get(chatMessages.size() - 1).getContent());
try {
ChatCompletion chatCompletion = ChatCompletion.builder()
.messages(chatMessages)
.stream(true)
.build();
EventSource.Factory factory = EventSources.createFactory(this.okHttpClient);
ObjectMapper mapper = new ObjectMapper();
String requestBody = mapper.writeValueAsString(chatCompletion);
Request request = new Request.Builder()
.url(this.apiHost + "v1/chat/completions")
.post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody))
.build();
//创建事件
EventSource eventSource = factory.newEventSource(request, eventSourceListener);
log.info("finish invoking chat ai");
} catch (Exception e) {
log.error("chat ai error", e);
eventSourceListener.onFailure(null, e, null);
throw new ParamBusinessException();
}
}
/**
* Creates an embedding vector representing the input text.
*
* @param input
* @return EmbeddingResponse
*/
public FastChatEmbeddingResponse embeddings(String input) {
FastChatEmbedding embedding = FastChatEmbedding.builder().input(input).build();
if (StringUtils.isNotBlank(this.embeddingModel)) {
embedding.setModel(this.embeddingModel);
}
return this.embeddings(embedding);
}
/**
* Creates an embedding vector representing the input text.
*
* @param embedding
* @return EmbeddingResponse
*/
public FastChatEmbeddingResponse embeddings(FastChatEmbedding embedding) {
try {
ObjectMapper mapper = new ObjectMapper();
String requestBody = mapper.writeValueAsString(embedding);
Request request = new Request.Builder()
.url(this.apiHost + "v1/embeddings")
.post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody))
.build();
FastChatEmbeddingResponse chatEmbeddingResponse = null;
Response response = this.okHttpClient.newCall(request).execute();
StringBuilder body = new StringBuilder();
if (response.isSuccessful()) {
ResponseBody responseBody = response.body();
if (responseBody != null) {
// 获取响应体的输入流
java.io.InputStream inputStream = responseBody.byteStream();
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// 在这里处理每行响应内容
body.append(line);
}
// 关闭流
reader.close();
inputStream.close();
}
chatEmbeddingResponse = mapper.readValue(body.toString(), FastChatEmbeddingResponse.class);
}
log.info("finish invoking chat embedding");
return chatEmbeddingResponse;
} catch (Exception e) {
log.error("chat ai error", e);
throw new ParamBusinessException();
}
}
}

View File

@ -24,11 +24,15 @@ public class Chat2dbAIClient {
*/
public static final String CHAT2DB_OPENAI_HOST = "chat2db.apiHost";
/**
* FASTCHAT OPENAI embedding model
*/
public static final String CHAT2DB_EMBEDDING_MODEL= "fastchat.embedding.model";
private static OpenAiStreamClient CHAT2DB_AI_STREAM_CLIENT;
private static String apiKey;
public static OpenAiStreamClient getInstance() {
private static Chat2DBAIStreamClient CHAT2DB_AI_STREAM_CLIENT;
public static Chat2DBAIStreamClient getInstance() {
if (CHAT2DB_AI_STREAM_CLIENT != null) {
return CHAT2DB_AI_STREAM_CLIENT;
} else {
@ -36,7 +40,7 @@ public class Chat2dbAIClient {
}
}
private static OpenAiStreamClient singleton() {
private static Chat2DBAIStreamClient singleton() {
if (CHAT2DB_AI_STREAM_CLIENT == null) {
synchronized (Chat2dbAIClient.class) {
if (CHAT2DB_AI_STREAM_CLIENT == null) {
@ -65,9 +69,8 @@ public class Chat2dbAIClient {
apikey = ApplicationContextUtil.getProperty(CHAT2DB_OPENAI_KEY);
}
log.info("refresh chat2db apikey:{}", maskApiKey(apikey));
CHAT2DB_AI_STREAM_CLIENT = OpenAiStreamClient.builder().apiHost(apiHost).apiKey(
Lists.newArrayList(apikey)).build();
apiKey = apikey;
CHAT2DB_AI_STREAM_CLIENT = Chat2DBAIStreamClient.builder().apiHost(apiHost).apiKey(
apikey).build();
}
private static String maskApiKey(String input) {

View File

@ -32,7 +32,7 @@ public class FastChatAIClient {
/**
* FASTCHAT OPENAI embedding model
*/
public static final String FASTCHAT_embedding_MODEL= "fastchat.embedding.model";
public static final String FASTCHAT_EMBEDDING_MODEL = "fastchat.embedding.model";
private static FastChatAIStreamClient FASTCHAT_AI_CLIENT;

View File

@ -21,6 +21,9 @@ import okhttp3.sse.EventSources;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.util.List;
import java.util.Objects;
@ -82,6 +85,12 @@ public class FastChatAIStreamClient {
builder.okHttpClient = this.okHttpClient();
}
okHttpClient = builder.okHttpClient;
this.fastChatOpenAiApi = new Retrofit.Builder()
.baseUrl(apiHost)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build().create(FastChatOpenAiApi.class);
}
/**

View File

@ -1,40 +1,33 @@
package ai.chat2db.server.web.api.controller.rdb;
import java.util.List;
import ai.chat2db.server.domain.api.param.*;
import ai.chat2db.server.domain.api.param.datasource.DatabaseOperationParam;
import ai.chat2db.server.domain.api.service.DatabaseService;
import ai.chat2db.server.domain.api.service.DlTemplateService;
import ai.chat2db.server.domain.api.service.TableService;
import ai.chat2db.server.web.api.controller.rdb.vo.*;
import ai.chat2db.spi.model.*;
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.tools.base.wrapper.result.ListResult;
import ai.chat2db.server.tools.base.wrapper.result.PageResult;
import ai.chat2db.server.tools.base.wrapper.result.web.WebPageResult;
import ai.chat2db.server.web.api.aspect.ConnectionInfoAspect;
import ai.chat2db.server.web.api.controller.ai.EmbeddingController;
import ai.chat2db.server.web.api.controller.data.source.request.DataSourceBaseRequest;
import ai.chat2db.server.web.api.controller.rdb.converter.RdbWebConverter;
import ai.chat2db.server.web.api.controller.rdb.request.DdlExportRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableBriefQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableCreateDdlQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableDeleteRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableDetailQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableModifySqlRequest;
import ai.chat2db.server.web.api.controller.rdb.request.TableUpdateDdlQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.UpdateDatabaseRequest;
import ai.chat2db.server.web.api.controller.rdb.request.UpdateSchemaRequest;
import ai.chat2db.server.web.api.controller.rdb.request.*;
import ai.chat2db.server.web.api.controller.rdb.vo.*;
import ai.chat2db.spi.model.*;
import ai.chat2db.spi.sql.Chat2DBContext;
import ai.chat2db.spi.sql.ConnectInfo;
import com.google.common.collect.Lists;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* mysql表运维类
@ -46,8 +39,9 @@ import org.springframework.web.bind.annotation.RestController;
@ConnectionInfoAspect
@RequestMapping("/api/rdb/ddl")
@RestController
@Slf4j
@Deprecated
public class RdbDdlController {
public class RdbDdlController extends EmbeddingController {
@Autowired
private TableService tableService;
@ -61,6 +55,8 @@ public class RdbDdlController {
@Autowired
private DatabaseService databaseService;
public static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
/**
* 查询当前DB下的表列表
*
@ -76,6 +72,19 @@ public class RdbDdlController {
PageResult<Table> tableDTOPageResult = tableService.pageQuery(queryParam, tableSelector);
List<TableVO> tableVOS = rdbWebConverter.tableDto2vo(tableDTOPageResult.getData());
ConnectInfo connectInfo = Chat2DBContext.getConnectInfo();
singleThreadExecutor.submit(() -> {
try {
Chat2DBContext.putContext(connectInfo);
syncTableVector(request);
} catch (Exception e) {
log.error("sync table vector error", e);
} finally {
Chat2DBContext.removeContext();
}
log.info("sync table vector finish");
});
return WebPageResult.of(tableVOS, tableDTOPageResult.getTotal(), request.getPageNo(),
request.getPageSize());
}

View File

@ -224,4 +224,12 @@ public abstract class RdbWebConverter {
public abstract UpdateSelectResultParam request2param(SelectResultUpdateRequest request);
public abstract TableMilvusQueryRequest request2request(TableBriefQueryRequest request);
@Mappings({
@Mapping(source = "databaseName", target = "database"),
@Mapping(source = "schemaName", target = "schema"),
})
public abstract TableVectorParam param2param(TableBriefQueryRequest request);
}

View File

@ -4,11 +4,10 @@ import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.web.api.http.request.KnowledgeRequest;
import ai.chat2db.server.web.api.http.request.TableSchemaRequest;
import ai.chat2db.server.web.api.http.request.WhiteListRequest;
import ai.chat2db.server.web.api.http.response.*;
import com.dtflys.forest.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
* Gateway 的http 服务
@ -91,4 +90,14 @@ public interface GatewayClientService {
*/
@Get("/api/client/milvus/schema/search")
DataResult<TableSchemaResponse> schemaVectorSearch(TableSchemaRequest request);
/**
* check in white list
*
* @param whiteListRequest
* @return
*/
@Get("/api/client/whitelist/check")
DataResult<Boolean> checkInWhite(WhiteListRequest whiteListRequest);
}

View File

@ -0,0 +1,25 @@
package ai.chat2db.server.web.api.http.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class WhiteListRequest {
/**
* api key
*/
private String apiKey;
/**
* 白名单类型,如向量
* @see ai.chat2db.server.tools.base.enums.WhiteListTypeEnum
*/
private String whiteType;
}