| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | |
| | | 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) { |
| | |
| | | // è·åå¯¹è¯æ¶æ¯å表 |
| | | 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(); |
| | |
| | | throw new BaseException("ææ¬ä¸åè§,请修æ¹!"); |
| | | } |
| | | } |
| | | //æ ¹æ®æ¨¡ååç§°æ¥è¯¢æ¨¡åä¿¡æ¯ |
| | | SysModelBo sysModelBo = new SysModelBo(); |
| | | String model = chatRequest.getModel(); |
| | | // 妿æ¯gptsç³»åæ¨¡å |
| | | 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) { |
| | | // å¦ææ¨¡åä¸åå¨é»è®¤ä½¿ç¨tokenæ£è´¹æ¹å¼ |
| | | 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æ£è´¹ 2 æ¬¡æ°æ£è´¹ |
| | | 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 { |
| | |
| | | * @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); |
| | |
| | | .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(); |
| | |
| | | .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(); |
| | |
| | | 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" + |
| | |
| | | |
| | | @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(); |
| | |
| | | sendErrorEvent(emitter, e.getMessage()); |
| | | } |
| | | }; |
| | | ollamaAPI.chat(requestModel, streamHandler); |
| | | api.chat(requestModel, streamHandler); |
| | | emitter.complete(); |
| | | } catch (Exception e) { |
| | | sendErrorEvent(emitter, e.getMessage()); |
| | | } |
| | | }); |
| | | |
| | | |
| | | return emitter; |
| | | } |
| | | |
| | |
| | | ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion); |
| | | return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString(); |
| | | } |
| | | |
| | | |
| | | } |