From d8fda1559351c61678738285041da6811b463e53 Mon Sep 17 00:00:00 2001 From: ageer <ageerle@163.com> Date: 星期三, 12 三月 2025 00:17:47 +0800 Subject: [PATCH] feat: 增加联网查询功能 --- ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java | 153 +++++++++++++++++++++++++++++++------------------- 1 files changed, 95 insertions(+), 58 deletions(-) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java index a2cfeff..c822e3d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java @@ -1,8 +1,10 @@ package org.ruoyi.system.service.impl; import cn.dev33.satoken.stp.StpUtil; -import cn.hutool.core.collection.CollectionUtil; import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zhipu.oapi.ClientV4; +import com.zhipu.oapi.service.v4.tools.*; import io.github.ollama4j.OllamaAPI; import io.github.ollama4j.models.chat.OllamaChatMessageRole; import io.github.ollama4j.models.chat.OllamaChatRequestBuilder; @@ -17,10 +19,7 @@ import org.ruoyi.common.chat.domain.request.ChatRequest; import org.ruoyi.common.chat.domain.request.Dall3Request; import org.ruoyi.common.chat.entity.Tts.TextToSpeech; -import org.ruoyi.common.chat.entity.chat.ChatCompletion; -import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse; -import org.ruoyi.common.chat.entity.chat.Content; -import org.ruoyi.common.chat.entity.chat.Message; +import org.ruoyi.common.chat.entity.chat.*; import org.ruoyi.common.chat.entity.files.UploadFileResponse; import org.ruoyi.common.chat.entity.images.Image; import org.ruoyi.common.chat.entity.images.ImageResponse; @@ -33,17 +32,15 @@ import org.ruoyi.common.chat.plugin.CmdReq; import org.ruoyi.common.chat.plugin.SqlPlugin; import org.ruoyi.common.chat.plugin.SqlReq; -import org.ruoyi.common.chat.sse.ConsoleEventSourceListener; import org.ruoyi.common.chat.utils.TikTokensUtil; import org.ruoyi.common.core.domain.model.LoginUser; import org.ruoyi.common.core.exception.base.BaseException; import org.ruoyi.common.core.service.ConfigService; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.satoken.utils.LoginHelper; +import org.ruoyi.system.domain.SysModel; import org.ruoyi.system.domain.bo.ChatMessageBo; -import org.ruoyi.system.domain.bo.SysModelBo; import org.ruoyi.system.domain.request.translation.TranslationRequest; -import org.ruoyi.system.domain.vo.SysModelVo; import org.ruoyi.system.listener.SSEEventSourceListener; import org.ruoyi.system.service.*; import org.springframework.core.io.InputStreamResource; @@ -65,6 +62,9 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; @Service @@ -76,17 +76,20 @@ private final ChatConfig chatConfig; + private final IChatCostService chatService; private final IChatMessageService chatMessageService; private final ISysModelService sysModelService; - private final ISysUserService userService; - private final ConfigService configService; static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build(); + + private static final String requestIdTemplate = "mycompany-%d"; + + private static final ObjectMapper mapper = new ObjectMapper(); @Override public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) { @@ -96,11 +99,10 @@ // 鑾峰彇瀵硅瘽娑堟伅鍒楄〃 List<Message> messages = chatRequest.getMessages(); try { + String chatString = null; if (StpUtil.isLogin()) { LocalCache.CACHE.put("userId", getUserId()); Object content = messages.get(messages.size() - 1).getContent(); - - String chatString = ""; if (content instanceof List<?> listContent) { if (!listContent.isEmpty() && listContent.get(0) instanceof Content) { chatString = ((Content) listContent.get(0)).getText(); @@ -123,39 +125,89 @@ throw new BaseException("鏂囨湰涓嶅悎瑙�,璇蜂慨鏀�!"); } } - //鏍规嵁妯″瀷鍚嶇О鏌ヨ妯″瀷淇℃伅 - SysModelBo sysModelBo = new SysModelBo(); + String model = chatRequest.getModel(); // 濡傛灉鏄痝pts绯诲垪妯″瀷 if (chatRequest.getModel().startsWith("gpt-4-gizmo")) { - sysModelBo.setModelName("gpt-4-gizmo"); - } else { - sysModelBo.setModelName(chatRequest.getModel()); + model = "gpt-4-gizmo"; } - List<SysModelVo> sysModelList = sysModelService.queryList(sysModelBo); - - if (CollectionUtil.isEmpty(sysModelList)) { + SysModel sysModel = sysModelService.selectModelByName(model); + if (sysModel != null) { // 濡傛灉妯″瀷涓嶅瓨鍦ㄩ粯璁や娇鐢╰oken鎵h垂鏂瑰紡 processByToken(chatRequest.getModel(), chatString, chatMessageBo); } else { - openAiStreamClient = chatConfig.createOpenAiStreamClient(sysModelList.get(0).getApiHost(), sysModelList.get(0).getApiKey()); + openAiStreamClient = chatConfig.createOpenAiStreamClient(sysModel.getApiHost(), sysModel.getApiKey()); // 妯″瀷璁剧疆榛樿鎻愮ず璇� - SysModelVo firstModel = sysModelList.get(0); - if (StringUtils.isNotEmpty(firstModel.getSystemPrompt())) { - Message sysMessage = Message.builder().content(firstModel.getSystemPrompt()).role(Message.Role.SYSTEM).build(); + + if (StringUtils.isNotEmpty(sysModel.getSystemPrompt())) { + Message sysMessage = Message.builder().content(sysModel.getSystemPrompt()).role(Message.Role.SYSTEM).build(); messages.add(sysMessage); } // 璁¤垂绫诲瀷: 1 token鎵h垂 2 娆℃暟鎵h垂 - if ("2".equals(firstModel.getModelType())) { - processByModelPrice(firstModel, chatMessageBo); + if ("2".equals(sysModel.getModelType())) { + processByModelPrice(sysModel, chatMessageBo); } else { - processByToken(chatRequest.getModel(), chatString, chatMessageBo); + processByToken(chatRequest.getModel(), chatString, chatMessageBo); } } } - if("openCmd".equals(chatRequest.getModel())) { + String configValue = configService.getConfigValue("zhipu", "key"); + // 娣诲姞鑱旂綉淇℃伅 + if(StringUtils.isNotEmpty(configValue)){ + ClientV4 client = new ClientV4.Builder(configValue) + .networkConfig(300, 100, 100, 100, TimeUnit.SECONDS) + .connectionPool(new okhttp3.ConnectionPool(8, 1, TimeUnit.SECONDS)) + .build(); + + SearchChatMessage jsonNodes = new SearchChatMessage(); + jsonNodes.setRole(Message.Role.USER.getName()); + jsonNodes.setContent(chatString); + + String requestId = String.format(requestIdTemplate, System.currentTimeMillis()); + WebSearchParamsRequest chatCompletionRequest = WebSearchParamsRequest.builder() + .model("web-search-pro") + .stream(Boolean.TRUE) + .messages(Collections.singletonList(jsonNodes)) + .requestId(requestId) + .build(); + WebSearchApiResponse webSearchApiResponse = client.webSearchProStreamingInvoke(chatCompletionRequest); + List<ChoiceDelta> choices = new ArrayList<>(); + if (webSearchApiResponse.isSuccess()) { + AtomicBoolean isFirst = new AtomicBoolean(true); + + AtomicReference<WebSearchPro> lastAccumulator = new AtomicReference<>(); + + webSearchApiResponse.getFlowable().map(result -> result) + .doOnNext(accumulator -> { + { + if (isFirst.getAndSet(false)) { + log.info("Response: "); + } + ChoiceDelta delta = accumulator.getChoices().get(0).getDelta(); + if (delta != null && delta.getToolCalls() != null) { + log.info("tool_calls: {}", mapper.writeValueAsString(delta.getToolCalls())); + } + choices.add(delta); + } + }) + .doOnComplete(() -> System.out.println("Stream completed.")) + .doOnError(throwable -> System.err.println("Error: " + throwable)) + .blockingSubscribe(); + + WebSearchPro chatMessageAccumulator = lastAccumulator.get(); + + webSearchApiResponse.setFlowable(null);// 鎵撳嵃鍓嶇疆绌� + webSearchApiResponse.setData(chatMessageAccumulator); + } + + + Message message = Message.builder().role(Message.Role.ASSISTANT).content(choices.get(1).getToolCalls().toString()).build(); + messages.add(message); + } + + if ("openCmd".equals(chatRequest.getModel())) { sseEmitter.send(cmdPlugin(messages)); sseEmitter.complete(); - }else if ("sqlPlugin".equals(chatRequest.getModel())){ + } else if ("sqlPlugin".equals(chatRequest.getModel())) { sseEmitter.send(sqlPlugin(messages)); sseEmitter.complete(); } else { @@ -229,7 +281,7 @@ * @param model 妯″瀷淇℃伅 * @param chatMessageBo 瀵硅瘽淇℃伅 */ - private void processByModelPrice(SysModelVo model, ChatMessageBo chatMessageBo) { + private void processByModelPrice(SysModel model, ChatMessageBo chatMessageBo) { double cost = model.getModelPrice(); chatService.deductUserBalance(getUserId(), cost); chatMessageBo.setDeductCost(cost); @@ -316,16 +368,14 @@ .style(request.getStyle()) .build(); ImageResponse imageResponse = openAiStreamClient.genImages(image); - SysModelBo sysModelBo = new SysModelBo(); - sysModelBo.setModelName(request.getModel()); - List<SysModelVo> sysModelList = sysModelService.queryList(sysModelBo); + SysModel sysModel = sysModelService.selectModelByName(request.getModel()); //chatService.deductUserBalance(getUserId(),sysModelList.get(0).getModelPrice()); // 淇濆瓨娑堟伅璁板綍 ChatMessageBo chatMessageBo = new ChatMessageBo(); chatMessageBo.setUserId(getUserId()); chatMessageBo.setModelName(Image.Model.DALL_E_3.getName()); chatMessageBo.setContent(request.getPrompt()); - chatMessageBo.setDeductCost(sysModelList.get(0).getModelPrice()); + chatMessageBo.setDeductCost(sysModel.getModelPrice()); chatMessageBo.setTotalTokens(0); chatMessageService.insertByBo(chatMessageBo); return imageResponse.getData(); @@ -342,16 +392,14 @@ .n(1) .build(); ImageResponse imageResponse = openAiStreamClient.genImages(image); - SysModelBo sysModelBo = new SysModelBo(); - sysModelBo.setModelName("dall3"); - List<SysModelVo> sysModelList = sysModelService.queryList(sysModelBo); + SysModel dall3 = sysModelService.selectModelByName("dall3"); chatService.deductUserBalance(Long.valueOf(userId), 0.3); // 淇濆瓨娑堟伅璁板綍 ChatMessageBo chatMessageBo = new ChatMessageBo(); chatMessageBo.setUserId(getUserId()); chatMessageBo.setModelName(Image.Model.DALL_E_3.getName()); chatMessageBo.setContent(prompt); - chatMessageBo.setDeductCost(sysModelList.get(0).getModelPrice()); + chatMessageBo.setDeductCost(dall3.getModelPrice()); chatMessageBo.setTotalTokens(0); chatMessageService.insertByBo(chatMessageBo); return imageResponse.getData(); @@ -527,12 +575,9 @@ chatMessageBo.setDeductCost(0.01); chatMessageBo.setTotalTokens(0); chatMessageService.insertByBo(chatMessageBo); - openAiStreamClient = chatConfig.getOpenAiStreamClient(); - List<Message> messageList = new ArrayList<>(); - - Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content("浣犳槸涓�鍚嶇炕璇戣�佸笀\n" + + Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content("浣犳槸涓�浣嶇簿閫氬悇鍥借瑷�鐨勭炕璇戝ぇ甯圽n" + "\n" + "璇峰皢鐢ㄦ埛杈撳叆璇嶈缈昏瘧鎴恵" + translationRequest.getTargetLanguage() + "}\n" + "\n" + @@ -563,25 +608,21 @@ @Override public SseEmitter ollamaChat(ChatRequest chatRequest) { + String[] parts = chatRequest.getModel().split("ollama-"); + SysModel sysModel = sysModelService.selectModelByName(parts[1]); final SseEmitter emitter = new SseEmitter(); - String host = "http://localhost:11434/"; - + String host = sysModel.getApiHost(); List<Message> msgList = chatRequest.getMessages(); Message message = msgList.get(msgList.size() - 1); - - OllamaAPI ollamaAPI = new OllamaAPI(host); - - ollamaAPI.setRequestTimeoutSeconds(100); - - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("qwen2.5:7b"); - + OllamaAPI api = new OllamaAPI(host); + api.setRequestTimeoutSeconds(100); + OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(sysModel.getModelName()); OllamaChatRequestModel requestModel = builder .withMessage(OllamaChatMessageRole.USER, message.getContent().toString()) .build(); - - // 寮傛鎵ц Ollama API 璋冪敤 + // 寮傛鎵ц OllAma API 璋冪敤 CompletableFuture.runAsync(() -> { try { StringBuilder response = new StringBuilder(); @@ -595,14 +636,12 @@ sendErrorEvent(emitter, e.getMessage()); } }; - ollamaAPI.chat(requestModel, streamHandler); + api.chat(requestModel, streamHandler); emitter.complete(); } catch (Exception e) { sendErrorEvent(emitter, e.getMessage()); } }); - - return emitter; } @@ -620,6 +659,4 @@ ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion); return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString(); } - - } -- Gitblit v1.9.3