From 6a1b544545ba2a005a1d6263f3b42aaeeef78bcd Mon Sep 17 00:00:00 2001 From: ageerle <ageerle@163.com> Date: 星期二, 11 三月 2025 17:32:47 +0800 Subject: [PATCH] feat: 支持插件功能 --- ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/service/impl/SseServiceImpl.java | 172 ++++++++++++++++++++++++-------------------------------- 1 files changed, 74 insertions(+), 98 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 e2f02b5..a2cfeff 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 @@ -3,16 +3,11 @@ import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.collection.CollectionUtil; import com.alibaba.fastjson.JSONObject; -import com.azure.ai.openai.OpenAIClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.ai.openai.models.*; -import com.azure.core.credential.AzureKeyCredential; import io.github.ollama4j.OllamaAPI; import io.github.ollama4j.models.chat.OllamaChatMessageRole; import io.github.ollama4j.models.chat.OllamaChatRequestBuilder; import io.github.ollama4j.models.chat.OllamaChatRequestModel; import io.github.ollama4j.models.generate.OllamaStreamHandler; -import io.github.ollama4j.utils.Options; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,6 +28,12 @@ import org.ruoyi.common.chat.entity.images.ResponseFormat; import org.ruoyi.common.chat.entity.whisper.WhisperResponse; import org.ruoyi.common.chat.openai.OpenAiStreamClient; +import org.ruoyi.common.chat.openai.plugin.PluginAbstract; +import org.ruoyi.common.chat.plugin.CmdPlugin; +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; @@ -43,12 +44,10 @@ 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.domain.vo.SysUserVo; import org.ruoyi.system.listener.SSEEventSourceListener; import org.ruoyi.system.service.*; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -63,10 +62,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; -import io.github.ollama4j.utils.OptionsBuilder; @Service @Slf4j @@ -89,9 +88,6 @@ static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build(); - private final ISysPackagePlanService sysPackagePlanService; - - @Override public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) { openAiStreamClient = chatConfig.getOpenAiStreamClient(); @@ -101,12 +97,7 @@ List<Message> messages = chatRequest.getMessages(); try { if (StpUtil.isLogin()) { - SysUserVo sysUserVo = userService.selectUserById(getUserId()); -// if (!checkModel(sysUserVo.getUserPlan(), chatRequest.getModel())) { -// throw new BaseException("褰撳墠濂楅涓嶆敮鎸佹妯″瀷!"); -// } LocalCache.CACHE.put("userId", getUserId()); - Object content = messages.get(messages.size() - 1).getContent(); String chatString = ""; @@ -161,36 +152,23 @@ } } } - -// else { -// -// // 鍒濆璇锋眰娆℃暟 -// int number = 1; -// // 鑾峰彇璇锋眰IP -// String realIp = getClientIpAddress(request); -// // 鏍规嵁IP鑾峰彇娆℃暟 -// Integer requestNumber = RedisUtils.getCacheObject(realIp); -// if (requestNumber == null) { -// // 璁板綍ip浣跨敤娆℃暟 -// RedisUtils.setCacheObject(realIp, number); -// } else { -// String configValue = configService.getConfigValue("mail", "free"); -// if (requestNumber > Integer.parseInt(configValue)) { -// throw new BaseException("鍓╀綑娆℃暟涓嶈冻锛岃鍏呭�煎悗浣跨敤"); -// } -// RedisUtils.setCacheObject(realIp, requestNumber + 1); -// } -// -// } - ChatCompletion completion = ChatCompletion - .builder() - .messages(messages) - .model(chatRequest.getModel()) - .temperature(chatRequest.getTemperature()) - .topP(chatRequest.getTop_p()) - .stream(true) - .build(); - openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener); + if("openCmd".equals(chatRequest.getModel())) { + sseEmitter.send(cmdPlugin(messages)); + sseEmitter.complete(); + }else if ("sqlPlugin".equals(chatRequest.getModel())){ + sseEmitter.send(sqlPlugin(messages)); + sseEmitter.complete(); + } else { + ChatCompletion completion = ChatCompletion + .builder() + .messages(messages) + .model(chatRequest.getModel()) + .temperature(chatRequest.getTemperature()) + .topP(chatRequest.getTop_p()) + .stream(true) + .build(); + openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener); + } } catch (Exception e) { String message = e.getMessage(); sendErrorEvent(sseEmitter, message); @@ -199,32 +177,51 @@ return sseEmitter; } + public String cmdPlugin(List<Message> messages) { + CmdPlugin plugin = new CmdPlugin(CmdReq.class); + // 鎻掍欢鍚嶇О + plugin.setName("鍛戒护琛屽伐鍏�"); + // 鏂规硶鍚嶇О + plugin.setFunction("openCmd"); + // 鏂规硶璇存槑 + plugin.setDescription("鎻愪緵涓�涓懡浠よ鎸囦护,姣斿<璁颁簨鏈�>,鎸囦护浣跨敤涓枃"); -// /** -// * 鏌ュ綋鍓嶇敤鎴锋槸鍚﹀彲浠ヨ皟鐢ㄦ妯″瀷 -// * -// * @param planId -// * @return -// */ -// public Boolean checkModel(String planId, String modelName) { -// SysPackagePlanBo sysPackagePlanBo = new SysPackagePlanBo(); -// if (modelName.startsWith("gpt-4-gizmo")) { -// modelName = "gpt-4-gizmo"; -// } -// if (StringUtils.isEmpty(planId)) { -// sysPackagePlanBo.setName("Visitor"); -// } else if ("Visitor".equals(planId) || "Free".equals(planId)) { -// sysPackagePlanBo.setName(planId); -// } else { -// // sysPackagePlanBo.setId(Long.valueOf(planId)); -// return true; -// } -// -// SysPackagePlanVo sysPackagePlanVo = sysPackagePlanService.queryList(sysPackagePlanBo).get(0); -// // 灏嗗瓧绗︿覆杞崲涓烘暟缁� -// String[] array = sysPackagePlanVo.getPlanDetail().split(","); -// return Arrays.asList(array).contains(modelName); -// } + PluginAbstract.Arg arg = new PluginAbstract.Arg(); + // 鍙傛暟鍚嶇О + arg.setName("cmd"); + // 鍙傛暟璇存槑 + arg.setDescription("鍛戒护琛屾寚浠�"); + // 鍙傛暟绫诲瀷 + arg.setType("string"); + arg.setRequired(true); + plugin.setArgs(Collections.singletonList(arg)); + //鏈夊洓涓噸杞芥柟娉曪紝閮藉彲浠ヤ娇鐢� + ChatCompletionResponse response = openAiStreamClient.chatCompletionWithPlugin(messages,"gpt-4o-mini",plugin); + return response.getChoices().get(0).getMessage().getContent().toString(); + } + + public String sqlPlugin(List<Message> messages) { + SqlPlugin plugin = new SqlPlugin(SqlReq.class); + // 鎻掍欢鍚嶇О + plugin.setName("鏁版嵁搴撴煡璇㈡彃浠�"); + // 鏂规硶鍚嶇О + plugin.setFunction("sqlPlugin"); + // 鏂规硶璇存槑 + plugin.setDescription("鎻愪緵涓�涓敤鎴峰悕绉版煡璇綑棰濅俊鎭�"); + + PluginAbstract.Arg arg = new PluginAbstract.Arg(); + // 鍙傛暟鍚嶇О + arg.setName("username"); + // 鍙傛暟璇存槑 + arg.setDescription("鐢ㄦ埛鍚嶇О"); + // 鍙傛暟绫诲瀷 + arg.setType("string"); + arg.setRequired(true); + plugin.setArgs(Collections.singletonList(arg)); + //鏈夊洓涓噸杞芥柟娉曪紝閮藉彲浠ヤ娇鐢� + ChatCompletionResponse response = openAiStreamClient.chatCompletionWithPlugin(messages,"gpt-4o-mini",plugin); + return response.getChoices().get(0).getMessage().getContent().toString(); + } /** * 鏍规嵁娆℃暟鎵i櫎浣欓 @@ -295,25 +292,6 @@ @Override public String chat(ChatRequest chatRequest, String userId) { -// chatService.deductUserBalance(Long.valueOf(userId), 0.01); -// // 淇濆瓨娑堟伅璁板綍 -// ChatMessageBo chatMessageBo = new ChatMessageBo(); -// chatMessageBo.setUserId(Long.valueOf(userId)); -// chatMessageBo.setModelName(ChatCompletion.Model.GPT_3_5_TURBO.getName()); -// chatMessageBo.setContent(chatRequest.getPrompt()); -// chatMessageBo.setDeductCost(0.01); -// chatMessageBo.setTotalTokens(0); -// chatMessageService.insertByBo(chatMessageBo); -// -// openAiStreamClient = chatConfig.getOpenAiStreamClient(); -// Message message = Message.builder().role(Message.Role.USER).content(chatRequest.getPrompt()).build(); -// ChatCompletion chatCompletion = ChatCompletion -// .builder() -// .messages(Collections.singletonList(message)) -// .model(chatRequest.getModel()) -// .build(); -// ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion); -// return chatCompletionResponse.getChoices().get(0).getMessage().getContent(); return null; } @@ -540,7 +518,8 @@ @Override public String translation(TranslationRequest translationRequest) { - + // 缈昏瘧妯″瀷鍥哄畾涓篻pt-4o-mini + translationRequest.setModel("gpt-4o-mini"); ChatMessageBo chatMessageBo = new ChatMessageBo(); chatMessageBo.setUserId(getUserId()); chatMessageBo.setModelName(translationRequest.getModel()); @@ -557,17 +536,12 @@ "\n" + "璇峰皢鐢ㄦ埛杈撳叆璇嶈缈昏瘧鎴恵" + translationRequest.getTargetLanguage() + "}\n" + "\n" + - "璁╂垜浠竴姝ヤ竴姝ユ潵鎬濊�僜n" + "==绀轰緥杈撳嚭==\n" + + "**鍘熸枃** : <杩欓噷鏄剧ず瑕佺炕璇戠殑鍘熸枃淇℃伅>\n" + "**缈昏瘧** : <杩欓噷鏄剧ず缈昏瘧鎴愯嫳璇殑缁撴灉>\n" + - "\n" + - "**閫犲彞** : What's the weather like today? Use the 'Weather Query' plugin to find out instantly! <閫犱竴涓嫳璇彞瀛�>\n" + - "\n" + - "**鍚屼箟璇�** : Add-on銆丒xtension銆丮odule <杩欓噷鏄剧ず1-3涓嫳鏂囩殑鍚屼箟璇�>\n" + - "\n" + "==绀轰緥缁撴潫==\n" + "\n" + - "娉ㄦ剰锛氳涓ユ牸鎸夌ず渚嬭繘琛岃緭鍑�").build(); + "娉ㄦ剰锛氳涓ユ牸鎸夌ず渚嬭繘琛岃緭鍑猴紝杩斿洖markdown鏍煎紡").build(); messageList.add(sysMessage); Message message = Message.builder().role(Message.Role.USER).content(translationRequest.getPrompt()).build(); messageList.add(message); @@ -646,4 +620,6 @@ ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion); return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString(); } + + } -- Gitblit v1.9.3