From be4ecc21692652cf6a9ccf0d8abc723096e1c909 Mon Sep 17 00:00:00 2001 From: tmlx1990 Date: Mon, 16 Dec 2024 20:04:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:1559=20=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89AI=E4=B8=8D=E8=83=BD=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/api/controller/ai/ChatController.java | 14 +- .../ai/rest/client/RestAIClient.java | 33 +++- .../ai/rest/client/RestAIStreamClient.java | 180 ++++++++++++++++++ .../ai/rest/client/RestAiStreamClient.java | 166 ---------------- .../listener/RestAIEventSourceListener.java | 26 ++- .../ai/rest/model/RestAIChatCompletions.java | 96 ++++++++++ .../controller/config/ConfigController.java | 11 +- 7 files changed, 338 insertions(+), 188 deletions(-) create mode 100644 chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIStreamClient.java delete mode 100644 chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAiStreamClient.java create mode 100644 chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/model/RestAIChatCompletions.java diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/ChatController.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/ChatController.java index 7b2a5ca69..8010a1258 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/ChatController.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/ChatController.java @@ -235,7 +235,7 @@ public SseEmitter distributeAISql(ChatQueryRequest queryRequest, SseEmitter sseE case CHAT2DBAI: return chatWithChat2dbAi(queryRequest, sseEmitter, uid); case RESTAI : - return chatWithRestAi(queryRequest, sseEmitter); + return chatWithRestAi(queryRequest, sseEmitter, uid); case FASTCHATAI: return chatWithFastChatAi(queryRequest, sseEmitter, uid); case AZUREAI : @@ -261,9 +261,15 @@ public SseEmitter distributeAISql(ChatQueryRequest queryRequest, SseEmitter sseE * @param sseEmitter * @return */ - private SseEmitter chatWithRestAi(ChatQueryRequest prompt, SseEmitter sseEmitter) { - RestAIEventSourceListener eventSourceListener = new RestAIEventSourceListener(sseEmitter); - RestAIClient.getInstance().restCompletions(buildPrompt(prompt), eventSourceListener); + private SseEmitter chatWithRestAi(ChatQueryRequest queryRequest, SseEmitter sseEmitter, String uid) throws IOException { + String prompt = buildPrompt(queryRequest); + List messages = getFastChatMessage(uid, prompt); + + buildSseEmitter(sseEmitter, uid); + + RestAIEventSourceListener restAIEventSourceListener = new RestAIEventSourceListener(sseEmitter); + RestAIClient.getInstance().streamCompletions(messages, restAIEventSourceListener); + LocalCache.CACHE.put(uid, JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT); return sseEmitter; } diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIClient.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIClient.java index b95c09348..ab13f07c4 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIClient.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIClient.java @@ -6,6 +6,7 @@ import ai.chat2db.server.web.api.util.ApplicationContextUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; /** * @author moji @@ -19,6 +20,11 @@ public class RestAIClient { */ public static final String AI_SQL_SOURCE = "ai.sql.source"; + /** + * Customized AI interface KEY + */ + public static final String REST_AI_API_KEY = "rest.ai.apiKey"; + /** * Customized AI interface address */ @@ -29,9 +35,16 @@ public class RestAIClient { */ public static final String REST_AI_STREAM_OUT = "rest.ai.stream"; - private static RestAiStreamClient REST_AI_STREAM_CLIENT; + /** + * Custom AI interface model + */ + public static final String REST_AI_MODEL = "rest.ai.model"; - public static RestAiStreamClient getInstance() { + + + private static RestAIStreamClient REST_AI_STREAM_CLIENT; + + public static RestAIStreamClient getInstance() { if (REST_AI_STREAM_CLIENT != null) { return REST_AI_STREAM_CLIENT; } else { @@ -39,7 +52,7 @@ public static RestAiStreamClient getInstance() { } } - private static RestAiStreamClient singleton() { + private static RestAIStreamClient singleton() { if (REST_AI_STREAM_CLIENT == null) { synchronized (RestAIClient.class) { if (REST_AI_STREAM_CLIENT == null) { @@ -55,17 +68,23 @@ private static RestAiStreamClient singleton() { */ public static void refresh() { String apiUrl = ""; - Boolean stream = Boolean.TRUE; + String apiKey = ""; + String model = ""; ConfigService configService = ApplicationContextUtil.getBean(ConfigService.class); Config apiHostConfig = configService.find(REST_AI_URL).getData(); if (apiHostConfig != null) { apiUrl = apiHostConfig.getContent(); } - Config config = configService.find(REST_AI_STREAM_OUT).getData(); + Config config = configService.find(REST_AI_API_KEY).getData(); if (config != null) { - stream = Boolean.valueOf(config.getContent()); + apiKey = config.getContent(); + } + Config deployConfig = configService.find(REST_AI_MODEL).getData(); + if (deployConfig != null && StringUtils.isNotBlank(deployConfig.getContent())) { + model = deployConfig.getContent(); } - REST_AI_STREAM_CLIENT = new RestAiStreamClient(apiUrl, stream); + REST_AI_STREAM_CLIENT = RestAIStreamClient.builder().apiKey(apiKey).apiHost(apiUrl).model(model) + .build(); } } diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIStreamClient.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIStreamClient.java new file mode 100644 index 000000000..55ab922d7 --- /dev/null +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAIStreamClient.java @@ -0,0 +1,180 @@ +package ai.chat2db.server.web.api.controller.ai.rest.client; + +import ai.chat2db.server.tools.common.exception.ParamBusinessException; +import ai.chat2db.server.web.api.controller.ai.fastchat.interceptor.FastChatHeaderAuthorizationInterceptor; +import ai.chat2db.server.web.api.controller.ai.fastchat.model.FastChatCompletionsOptions; +import ai.chat2db.server.web.api.controller.ai.fastchat.model.FastChatMessage; +import cn.hutool.http.ContentType; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSourceListener; +import okhttp3.sse.EventSources; +import org.apache.commons.collections4.CollectionUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * Custom AI interface client + * @author moji + */ +@Slf4j +public class RestAIStreamClient { + /** + * apikey + */ + @Getter + @NotNull + private String apiKey; + + /** + * apiHost + */ + @Getter + @NotNull + private String apiHost; + + /** + * model + */ + @Getter + private String model; + /** + * okHttpClient + */ + @Getter + private OkHttpClient okHttpClient; + + /** + * Construct instance object + * + * @param builder + */ + public RestAIStreamClient(Builder builder) { + this.apiKey = builder.apiKey; + this.apiHost = builder.apiHost; + this.model = builder.model; + this.okHttpClient = new OkHttpClient + .Builder() + .addInterceptor(new FastChatHeaderAuthorizationInterceptor(this.apiKey)) + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(50, TimeUnit.SECONDS) + .readTimeout(50, TimeUnit.SECONDS) + .build(); + } + + /** + * structure + * + * @return + */ + public static RestAIStreamClient.Builder builder() { + return new RestAIStreamClient.Builder(); + } + + /** + * builder + */ + public static final class Builder { + private String apiKey; + + private String apiHost; + + private String model; + + + /** + * OkhttpClient + */ + private OkHttpClient okHttpClient; + + public Builder() { + } + + public RestAIStreamClient.Builder apiKey(String apiKeyValue) { + this.apiKey = apiKeyValue; + return this; + } + + /** + * @param apiHostValue + * @return + */ + public RestAIStreamClient.Builder apiHost(String apiHostValue) { + this.apiHost = apiHostValue; + return this; + } + + /** + * @param modelValue + * @return + */ + public RestAIStreamClient.Builder model(String modelValue) { + this.model = modelValue; + return this; + } + + + public RestAIStreamClient.Builder okHttpClient(OkHttpClient val) { + this.okHttpClient = val; + return this; + } + + public RestAIStreamClient build() { + return new RestAIStreamClient(this); + } + + } + + + /** + * Q&A interface stream form + * + * @param chatMessages + * @param eventSourceListener + */ + public void streamCompletions(List chatMessages, EventSourceListener eventSourceListener) { + if (CollectionUtils.isEmpty(chatMessages)) { + log.error("param error:Rest AI Prompt cannot be empty"); + throw new ParamBusinessException("prompt"); + } + if (Objects.isNull(eventSourceListener)) { + log.error("param error:RestAIEventSourceListener cannot be empty"); + throw new ParamBusinessException(); + } + log.info("Rest AI, prompt:{}", chatMessages.get(chatMessages.size() - 1).getContent()); + try { + + FastChatCompletionsOptions chatCompletionsOptions = new FastChatCompletionsOptions(chatMessages); + chatCompletionsOptions.setStream(true); + chatCompletionsOptions.setModel(this.model); + + EventSource.Factory factory = EventSources.createFactory(this.okHttpClient); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + String requestBody = mapper.writeValueAsString(chatCompletionsOptions); + Request request = new Request.Builder() + .url(apiHost) + .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) + .build(); + //Create event + EventSource eventSource = factory.newEventSource(request, eventSourceListener); + log.info("finish invoking rest ai"); + } catch (Exception e) { + log.error("rest ai error", e); + eventSourceListener.onFailure(null, e, null); + throw new ParamBusinessException(); + } + } + + +} diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAiStreamClient.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAiStreamClient.java deleted file mode 100644 index 7d5164e5b..000000000 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/client/RestAiStreamClient.java +++ /dev/null @@ -1,166 +0,0 @@ -package ai.chat2db.server.web.api.controller.ai.rest.client; - -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -import ai.chat2db.server.tools.common.exception.ParamBusinessException; -import ai.chat2db.server.web.api.controller.ai.rest.model.RestAiCompletion; -import cn.hutool.http.ContentType; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.unfbx.chatgpt.sse.ConsoleEventSourceListener; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import okhttp3.sse.EventSource; -import okhttp3.sse.EventSourceListener; -import okhttp3.sse.EventSources; -import org.apache.commons.lang3.StringUtils; - -/** - * Custom AI interface client - * @author moji - */ -@Slf4j -public class RestAiStreamClient { - /** - * rest api url - */ - @Getter - private String apiUrl; - - /** - * Whether to stream interface - */ - @Getter - private Boolean stream; - /** - * okHttpClient - */ - @Getter - private OkHttpClient okHttpClient; - - /** - * Construct instance object - * - * @param url - */ - public RestAiStreamClient(String url, Boolean stream) { - this.apiUrl = url; - this.stream = stream; - this.okHttpClient = new OkHttpClient - .Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(50, TimeUnit.SECONDS) - .readTimeout(50, TimeUnit.SECONDS) - .build(); - } - - /** - * Request RESTAI interface - * - * @param prompt - * @param eventSourceListener - */ - public void restCompletions(String prompt, - EventSourceListener eventSourceListener) { - log.info("Start calling the custom AI, prompt:{}", prompt); - RestAiCompletion completion = new RestAiCompletion(); - completion.setPrompt(prompt); - if (Objects.isNull(stream) || stream) { - streamCompletions(completion, eventSourceListener); - log.info("End calling streaming output custom AI"); - return; - } - nonStreamCompletions(completion, eventSourceListener); - log.info("End calling non-streaming output custom AI"); - } - - /** - * Q&A interface stream form - * - * @param completion open ai parameter - * @param eventSourceListener sse listener - * @see ConsoleEventSourceListener - */ - public void streamCompletions(RestAiCompletion completion, EventSourceListener eventSourceListener) { - if (Objects.isNull(eventSourceListener)) { - log.error("Parameter exception: EventSourceListener cannot be empty"); - throw new ParamBusinessException(); - } - if (StringUtils.isBlank(completion.getPrompt())) { - log.error("Parameter exception: Prompt cannot be empty"); - throw new ParamBusinessException(); - } - try { - EventSource.Factory factory = EventSources.createFactory(this.okHttpClient); - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - String requestBody = mapper.writeValueAsString(completion); - Request request = new Request.Builder() - .url(this.apiUrl) - .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) - .build(); - //Create event - EventSource eventSource = factory.newEventSource(request, eventSourceListener); - } catch (Exception e) { - log.error("Request parameter parsing exception", e); - throw new ParamBusinessException(); - } - } - - /** - * Request non-streaming output interface - * - * @param completion - * @param eventSourceListener - */ - public void nonStreamCompletions(RestAiCompletion completion, EventSourceListener eventSourceListener) { - if (StringUtils.isBlank(completion.getPrompt())) { - log.error("Parameter exception: Prompt cannot be empty"); - throw new ParamBusinessException(); - } - try { - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - String requestBody = mapper.writeValueAsString(completion); - Request request = new Request.Builder() - .url(this.apiUrl) - .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody)) - .build(); - - this.okHttpClient.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - eventSourceListener.onFailure(null, e, null); - } - - @Override - public void onResponse(Call call, Response response) throws IOException { - try (ResponseBody responseBody = response.body()) { - if (responseBody != null) { - String content = responseBody.string(); - eventSourceListener.onEvent(null, "[DATA]", null, content); - eventSourceListener.onEvent(null, "[DONE]", null, "[DONE]"); - } - } catch (IOException e) { - eventSourceListener.onFailure(null, e, response); - } - } - }); - - } catch (Exception e) { - log.error("Request parameter parsing exception", e); - throw new ParamBusinessException(); - } - } - -} diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/listener/RestAIEventSourceListener.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/listener/RestAIEventSourceListener.java index bb5524783..0509ac6fe 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/listener/RestAIEventSourceListener.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/listener/RestAIEventSourceListener.java @@ -1,7 +1,12 @@ package ai.chat2db.server.web.api.controller.ai.rest.listener; +import java.io.IOException; import java.util.Objects; +import ai.chat2db.server.web.api.controller.ai.rest.model.RestAIChatCompletions; +import ai.chat2db.server.web.api.controller.ai.zhipu.model.ZhipuChatCompletions; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.unfbx.chatgpt.entity.chat.Message; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -27,6 +32,7 @@ public RestAIEventSourceListener(SseEmitter sseEmitter) { this.sseEmitter = sseEmitter; } + private ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); /** * {@inheritDoc} */ @@ -54,9 +60,11 @@ public void onEvent(EventSource eventSource, String id, String type, String data } Message message = new Message(); if (StringUtils.isNotBlank(data)) { - data = data.replaceAll("^\"|\"$", ""); - data = data.replaceAll("\\\\n", "\n"); - message.setContent(data); + RestAIChatCompletions chatCompletions = mapper.readValue(data, RestAIChatCompletions.class); + String text = chatCompletions.getChoices().get(0).getDelta()==null? + chatCompletions.getChoices().get(0).getText() + :chatCompletions.getChoices().get(0).getDelta().getContent(); + message.setContent(text); sseEmitter.send(SseEmitter.event() .id(id) .data(message) @@ -68,10 +76,14 @@ public void onEvent(EventSource eventSource, String id, String type, String data @Override public void onClosed(EventSource eventSource) { log.info("REST AI close sse connection..."); - sseEmitter.send(SseEmitter.event() - .id("[DONE]") - .data("[DONE]") - .reconnectTime(3000)); + try { + sseEmitter.send(SseEmitter.event() + .id("[DONE]") + .data("[DONE]") + .reconnectTime(3000)); + } catch (IOException e) { + throw new RuntimeException(e); + } sseEmitter.complete(); } diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/model/RestAIChatCompletions.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/model/RestAIChatCompletions.java new file mode 100644 index 000000000..6d3915322 --- /dev/null +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/ai/rest/model/RestAIChatCompletions.java @@ -0,0 +1,96 @@ +package ai.chat2db.server.web.api.controller.ai.rest.model; + +import ai.chat2db.server.web.api.controller.ai.fastchat.model.FastChatChoice; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class RestAIChatCompletions { + + /* + * A unique identifier associated with this chat completions response. + */ + private String id; + + /* + * The first timestamp associated with generation activity for this completions response, + * represented as seconds since the beginning of the Unix epoch of 00:00 on 1 Jan 1970. + */ + private int created; + + /** + * model + */ + private String model; + + /** + * object + */ + private String object; + + /* + * The collection of completions choices associated with this completions response. + * Generally, `n` choices are generated per provided prompt with a default value of 1. + * Token limits and other settings may limit the number of choices generated. + */ + @JsonProperty(value = "choices") + private List choices; + + + /** + * Creates an instance of ChatCompletions class. + * + * @param id the id value to set. + * @param created the created value to set. + * @param choices the choices value to set. + */ + @JsonCreator + private RestAIChatCompletions( + @JsonProperty(value = "id") String id, + @JsonProperty(value = "created") int created, + @JsonProperty(value = "model") String model, + @JsonProperty(value = "object") String object, + @JsonProperty(value = "choices") List choices) { + this.id = id; + this.created = created; + this.model = model; + this.object = object; + this.choices = choices; + } + + /** + * Get the id property: A unique identifier associated with this chat completions response. + * + * @return the id value. + */ + public String getId() { + return this.id; + } + + /** + * Get the created property: The first timestamp associated with generation activity for this completions response, + * represented as seconds since the beginning of the Unix epoch of 00:00 on 1 Jan 1970. + * + * @return the created value. + */ + public int getCreated() { + return this.created; + } + + /** + * Get the choices property: The collection of completions choices associated with this completions response. + * Generally, `n` choices are generated per provided prompt with a default value of 1. Token limits and other + * settings may limit the number of choices generated. + * + * @return the choices value. + */ + public List getChoices() { + return this.choices; + } + + + +} diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/config/ConfigController.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/config/ConfigController.java index 0d8625cd9..92f5eb360 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/config/ConfigController.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/config/ConfigController.java @@ -83,7 +83,7 @@ public ActionResult addChatGptSystemConfig(@RequestBody AIConfigCreateRequest re saveChat2dbAIConfig(request); break; case RESTAI: - saveFastChatAIConfig(request); + saveRestAIConfig(request); break; case AZUREAI: saveAzureAIConfig(request); @@ -152,12 +152,15 @@ private void saveOpenAIConfig(AIConfigCreateRequest request) { * @param request */ private void saveRestAIConfig(AIConfigCreateRequest request) { + SystemConfigParam param = SystemConfigParam.builder().code(RestAIClient.REST_AI_API_KEY).content( + request.getApiKey()).build(); + configService.createOrUpdate(param); SystemConfigParam restParam = SystemConfigParam.builder().code(RestAIClient.REST_AI_URL).content( request.getApiHost()).build(); configService.createOrUpdate(restParam); - SystemConfigParam methodParam = SystemConfigParam.builder().code(RestAIClient.REST_AI_STREAM_OUT).content( - request.getStream().toString()).build(); - configService.createOrUpdate(methodParam); + SystemConfigParam modelParam = SystemConfigParam.builder().code(RestAIClient.REST_AI_MODEL) + .content(request.getModel()).build(); + configService.createOrUpdate(modelParam); RestAIClient.refresh(); }