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-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java | 187 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 183 insertions(+), 4 deletions(-) diff --git a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java index cad1bbb..e799202 100644 --- a/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java +++ b/ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/openai/OpenAiStreamClient.java @@ -3,6 +3,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.ContentType; +import cn.hutool.json.JSONUtil; import com.fasterxml.jackson.databind.ObjectMapper; import io.reactivex.Single; import lombok.Getter; @@ -17,10 +18,7 @@ import org.ruoyi.common.chat.entity.billing.BillingUsage; import org.ruoyi.common.chat.entity.billing.KeyInfo; import org.ruoyi.common.chat.entity.billing.Subscription; -import org.ruoyi.common.chat.entity.chat.BaseChatCompletion; -import org.ruoyi.common.chat.entity.chat.ChatCompletion; -import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse; -import org.ruoyi.common.chat.entity.chat.ChatCompletionWithPicture; +import org.ruoyi.common.chat.entity.chat.*; import org.ruoyi.common.chat.entity.embeddings.Embedding; import org.ruoyi.common.chat.entity.embeddings.EmbeddingResponse; import org.ruoyi.common.chat.entity.files.UploadFileResponse; @@ -29,6 +27,7 @@ import org.ruoyi.common.chat.entity.models.Model; import org.ruoyi.common.chat.entity.models.ModelResponse; import org.ruoyi.common.chat.entity.whisper.Transcriptions; +import org.ruoyi.common.chat.entity.whisper.Translations; import org.ruoyi.common.chat.entity.whisper.WhisperResponse; import org.ruoyi.common.chat.openai.exception.CommonError; import org.ruoyi.common.chat.openai.function.KeyRandomStrategy; @@ -36,6 +35,10 @@ import org.ruoyi.common.chat.openai.interceptor.DefaultOpenAiAuthInterceptor; import org.ruoyi.common.chat.openai.interceptor.DynamicKeyOpenAiAuthInterceptor; import org.ruoyi.common.chat.openai.interceptor.OpenAiAuthInterceptor; +import org.ruoyi.common.chat.openai.plugin.PluginAbstract; +import org.ruoyi.common.chat.openai.plugin.PluginParam; +import org.ruoyi.common.chat.sse.DefaultPluginListener; +import org.ruoyi.common.chat.sse.PluginListener; import org.ruoyi.common.core.exception.base.BaseException; import org.jetbrains.annotations.NotNull; import retrofit2.Call; @@ -184,6 +187,93 @@ } catch (Exception e) { log.error("璇锋眰鍙傛暟瑙f瀽寮傚父锛歿}", e.getMessage()); } + } + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * 榛樿妯″瀷锛欳hatCompletion.Model.GPT_3_5_TURBO_16K_0613 + * + * @param chatCompletion 鍙傛暟 + * @param eventSourceListener sse鐩戝惉鍣� + * @param pluginEventSourceListener 鎻掍欢sse鐩戝惉鍣紝鏀堕泦function call杩斿洖淇℃伅 + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + */ + public <R extends PluginParam, T> void streamChatCompletionWithPlugin(ChatCompletion chatCompletion, EventSourceListener eventSourceListener, PluginListener pluginEventSourceListener, PluginAbstract<R, T> plugin) { + if (Objects.isNull(plugin)) { + this.streamChatCompletion(chatCompletion, eventSourceListener); + return; + } + if (CollectionUtil.isEmpty(chatCompletion.getMessages())) { + throw new BaseException(CommonError.MESSAGE_NOT_NUL.msg()); + } + Functions functions = Functions.builder() + .name(plugin.getFunction()) + .description(plugin.getDescription()) + .parameters(plugin.getParameters()) + .build(); + //娌℃湁鍊硷紝璁剧疆榛樿鍊� + if (Objects.isNull(chatCompletion.getFunctionCall())) { + chatCompletion.setFunctionCall("auto"); + } + //tip: 瑕嗙洊鑷繁璁剧疆鐨刦unctions鍙傛暟锛屼娇鐢╬lugin鏋勯�犵殑functions + chatCompletion.setFunctions(Collections.singletonList(functions)); + //璋冪敤OpenAi + if (Objects.isNull(pluginEventSourceListener)) { + pluginEventSourceListener = new DefaultPluginListener(this, eventSourceListener, plugin, chatCompletion); + } + this.streamChatCompletion(chatCompletion, pluginEventSourceListener); + } + + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * 榛樿妯″瀷锛欳hatCompletion.Model.GPT_3_5_TURBO_16K_0613 + * + * @param chatCompletion 鍙傛暟 + * @param eventSourceListener sse鐩戝惉鍣� + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + */ + public <R extends PluginParam, T> void streamChatCompletionWithPlugin(ChatCompletion chatCompletion, EventSourceListener eventSourceListener, PluginAbstract<R, T> plugin) { + PluginListener pluginEventSourceListener = new DefaultPluginListener(this, eventSourceListener, plugin, chatCompletion); + this.streamChatCompletionWithPlugin(chatCompletion, eventSourceListener, pluginEventSourceListener, plugin); + } + + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * 榛樿妯″瀷锛欳hatCompletion.Model.GPT_3_5_TURBO_16K_0613 + * + * @param messages 闂瓟鍙傛暟 + * @param eventSourceListener sse鐩戝惉鍣� + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + */ + public <R extends PluginParam, T> void streamChatCompletionWithPlugin(List<Message> messages, EventSourceListener eventSourceListener, PluginAbstract<R, T> plugin) { + this.streamChatCompletionWithPlugin(messages, ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName(), eventSourceListener, plugin); + } + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * + * @param messages 闂瓟鍙傛暟 + * @param model 妯″瀷 + * @param eventSourceListener eventSourceListener + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + */ + public <R extends PluginParam, T> void streamChatCompletionWithPlugin(List<Message> messages, String model, EventSourceListener eventSourceListener, PluginAbstract<R, T> plugin) { + ChatCompletion chatCompletion = ChatCompletion.builder().messages(messages).model(model).build(); + this.streamChatCompletionWithPlugin(chatCompletion, eventSourceListener, plugin); } @@ -418,6 +508,95 @@ } } + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * 榛樿妯″瀷锛欳hatCompletion.Model.GPT_3_5_TURBO_16K_0613 + * + * @param chatCompletion 鍙傛暟 + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + * @return ChatCompletionResponse + */ + public <R extends PluginParam, T> ChatCompletionResponse chatCompletionWithPlugin(ChatCompletion chatCompletion, PluginAbstract<R, T> plugin) { + if (Objects.isNull(plugin)) { + return this.chatCompletion(chatCompletion); + } + if (CollectionUtil.isEmpty(chatCompletion.getMessages())) { + throw new BaseException(CommonError.MESSAGE_NOT_NUL.msg()); + } + List<Message> messages = chatCompletion.getMessages(); + Functions functions = Functions.builder() + .name(plugin.getFunction()) + .description(plugin.getDescription()) + .parameters(plugin.getParameters()) + .build(); + //娌℃湁鍊硷紝璁剧疆榛樿鍊� + if (Objects.isNull(chatCompletion.getFunctionCall())) { + chatCompletion.setFunctionCall("auto"); + } + //tip: 瑕嗙洊鑷繁璁剧疆鐨刦unctions鍙傛暟锛屼娇鐢╬lugin鏋勯�犵殑functions + chatCompletion.setFunctions(Collections.singletonList(functions)); + //璋冪敤OpenAi + ChatCompletionResponse functionCallChatCompletionResponse = this.chatCompletion(chatCompletion); + ChatChoice chatChoice = functionCallChatCompletionResponse.getChoices().get(0); + log.debug("鏋勯�犵殑鏂规硶鍊硷細{}", chatChoice.getMessage().getFunctionCall()); + + R realFunctionParam = (R) JSONUtil.toBean(chatChoice.getMessage().getFunctionCall().getArguments(), plugin.getR()); + T tq = plugin.func(realFunctionParam); + + FunctionCall functionCall = FunctionCall.builder() + .arguments(chatChoice.getMessage().getFunctionCall().getArguments()) + .name(plugin.getFunction()) + .build(); + messages.add(Message.builder().role(Message.Role.ASSISTANT).content("function_call").functionCall(functionCall).build()); + messages.add(Message.builder().role(Message.Role.FUNCTION).name(plugin.getFunction()).content(plugin.content(tq)).build()); + //璁剧疆绗簩娆★紝璇锋眰鐨勫弬鏁� + chatCompletion.setFunctionCall(null); + chatCompletion.setFunctions(null); + + ChatCompletionResponse chatCompletionResponse = this.chatCompletion(chatCompletion); + log.debug("鑷畾涔夌殑鏂规硶杩斿洖鍊硷細{}", chatCompletionResponse.getChoices()); + return chatCompletionResponse; + } + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * 榛樿妯″瀷锛欳hatCompletion.Model.GPT_3_5_TURBO_16K_0613 + * + * @param messages 闂瓟鍙傛暟 + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + * @return ChatCompletionResponse + */ + public <R extends PluginParam, T> ChatCompletionResponse chatCompletionWithPlugin(List<Message> messages, PluginAbstract<R, T> plugin) { + return chatCompletionWithPlugin(messages, ChatCompletion.Model.GPT_3_5_TURBO_16K_0613.getName(), plugin); + } + + /** + * 鎻掍欢闂瓟绠�鏄撶増 + * 榛樿鍙杕essages鏈�鍚庝竴涓厓绱犳瀯寤烘彃浠跺璇� + * + * @param messages 闂瓟鍙傛暟 + * @param model 妯″瀷 + * @param plugin 鎻掍欢 + * @param <R> 鎻掍欢鑷畾涔夊嚱鏁扮殑璇锋眰鍊� + * @param <T> 鎻掍欢鑷畾涔夊嚱鏁扮殑杩斿洖鍊� + * @return ChatCompletionResponse + */ + public <R extends PluginParam, T> ChatCompletionResponse chatCompletionWithPlugin(List<Message> messages, String model, PluginAbstract<R, T> plugin) { + ChatCompletion chatCompletion = ChatCompletion.builder().messages(messages).model(model).build(); + return this.chatCompletionWithPlugin(chatCompletion, plugin); + } + + + + + + /** * 鏋勯�� -- Gitblit v1.9.3