From 363b2a625ac7eb728f194d30c45bdc019d235741 Mon Sep 17 00:00:00 2001 From: ageer <ageerle@163.com> Date: 星期二, 27 二月 2024 23:10:23 +0800 Subject: [PATCH] 更新md --- /dev/null | 380 ------------------------------------------------------ README.md | 8 2 files changed, 5 insertions(+), 383 deletions(-) diff --git a/README.md b/README.md index b171206..86f9b90 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,11 @@ </div> ## 璇煶鍏嬮殕 -<div> - <video src="./video/01.mp4"></video> -</div> + +<video src="https://github.com/ageerle/ruoyi-ai/blob/main/video/81d065fabda5c26f66b514442dce74a3.mp4?raw=true" controls="controls"> +鎮ㄧ殑娴忚鍣ㄤ笉鏀寔 video 鏍囩銆� +</video> + ## 绉佹湁鐭ヨ瘑搴撶鐞嗭紙寮�鍙戜腑锛� <div> diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ChatService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ChatService.java deleted file mode 100644 index f12c1d3..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/ChatService.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.xmzs.system.service; - -import com.xmzs.system.domain.bo.ChatMessageBo; - -/** - * @author hncboy - * @date 2023/3/22 19:41 - * 鑱婂ぉ鐩稿叧涓氬姟鎺ュ彛 - */ -public interface ChatService { - - - /** - * 鏍规嵁娑堣�楃殑tokens鎵i櫎浣欓 - * - * @param chatMessageBo - * @return 缁撴灉 - */ - - void deductToken(ChatMessageBo chatMessageBo); - - /** - * 鎵i櫎鐢ㄦ埛鐨勪綑棰� - * - */ - void deductUserBalance(Long userId, Double numberCost); -} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SseService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SseService.java deleted file mode 100644 index 185d005..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/SseService.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.xmzs.system.service; - - -import com.xmzs.common.chat.domain.request.ChatRequest; -import com.xmzs.common.chat.domain.request.Dall3Request; -import com.xmzs.common.chat.entity.images.Item; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import java.util.List; - -/** - * 鎻忚堪锛� - * - * @author https:www.unfbx.com - * @date 2023-04-08 - */ -public interface SseService { - - /** - * 瀹㈡埛绔彂閫佹秷鎭埌鏈嶅姟绔� - * @param chatRequest - */ - SseEmitter sseChat(ChatRequest chatRequest); - - /** - * 缁樼敾鎺ュ彛 - * @param request - */ - List<Item> dall3(Dall3Request request); - - - /** - * mj缁樼敾鎺ュ彛 - */ - void mjTask(); - - /** - * 涓浆鎺ュ彛 - */ - SseEmitter transitChat(ChatRequest chatRequest); - - /** - * azure 鑱婂ぉ鎺ュ彛 - * - * @param chatRequest - * @return - */ - SseEmitter azureChat(ChatRequest chatRequest); -} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatServiceImpl.java deleted file mode 100644 index cb745d6..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/ChatServiceImpl.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.xmzs.system.service.impl; - - -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.xmzs.common.chat.entity.chat.BaseChatCompletion; -import com.xmzs.common.chat.entity.chat.ChatCompletion; -import com.xmzs.common.core.exception.ServiceException; -import com.xmzs.system.domain.ChatToken; -import com.xmzs.system.domain.SysUser; -import com.xmzs.system.domain.bo.ChatMessageBo; -import com.xmzs.system.mapper.SysUserMapper; -import com.xmzs.system.service.ChatService; -import com.xmzs.system.service.IChatMessageService; -import com.xmzs.system.service.IChatTokenService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * @author hncboy - * @date 2023/3/22 19:41 - * 鑱婂ぉ鐩稿叧涓氬姟瀹炵幇绫� - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class ChatServiceImpl implements ChatService { - - private final SysUserMapper sysUserMapper; - - - private final IChatMessageService chatMessageService; - - private final IChatTokenService chatTokenService; - - - /** - * 鏍规嵁娑堣�楃殑tokens鎵i櫎浣欓 - * - * @param chatMessageBo - * - */ - public void deductToken(ChatMessageBo chatMessageBo) { - // 璁$畻鎬籺oken鏁� - ChatToken chatToken = chatTokenService.queryByUserId(chatMessageBo.getUserId(), chatMessageBo.getModelName()); - if(chatToken == null){ - chatToken = new ChatToken(); - chatToken.setToken(0); - } - int totalTokens = chatToken.getToken()+ chatMessageBo.getTotalTokens(); - // 濡傛灉鎬籺oken鏁板ぇ浜庣瓑浜�1000,杩涜璐圭敤鎵i櫎 - if (totalTokens >= 1000) { - // 璁$畻璐圭敤 - int token1 = totalTokens / 1000; - int token2 = totalTokens % 1000; - if(token2 > 0){ - // 淇濆瓨鍓╀綑tokens - chatToken.setToken(token2); - chatTokenService.editToken(chatToken); - }else { - chatTokenService.resetToken(chatMessageBo.getUserId(), chatMessageBo.getModelName()); - } - chatMessageBo.setDeductCost(token1 * ChatCompletion.getModelCost(chatMessageBo.getModelName())); - // 鎵i櫎鐢ㄦ埛浣欓 - deductUserBalance(chatMessageBo.getUserId(), chatMessageBo.getDeductCost()); - } else { - chatMessageBo.setDeductCost(0d); - chatMessageBo.setRemark("涓嶆弧1kToken,璁″叆涓嬩竴娆�!"); - chatToken.setToken(totalTokens); - chatToken.setModelName(chatMessageBo.getModelName()); - chatToken.setUserId(chatMessageBo.getUserId()); - chatTokenService.editToken(chatToken); - } - - // 淇濆瓨娑堟伅璁板綍 - chatMessageService.insertByBo(chatMessageBo); - - } - - /** - * 浠庣敤鎴蜂綑棰濅腑鎵i櫎鎸囧畾璐圭敤 - * - * @param userId 鐢ㄦ埛ID - * @param numberCost 瑕佹墸闄ょ殑璐圭敤 - */ - @Override - public void deductUserBalance(Long userId, Double numberCost) { - SysUser sysUser = sysUserMapper.selectById(userId); - if (sysUser == null) { - return; - } - - Double userBalance = sysUser.getUserBalance(); - if (userBalance < numberCost) { - throw new ServiceException("浣欓涓嶈冻锛岃鑱旂郴绠$悊鍛樺厖鍊�!"); - } - - sysUserMapper.update(null, - new LambdaUpdateWrapper<SysUser>() - .set(SysUser::getUserBalance, Math.max(userBalance - numberCost, 0)) - .eq(SysUser::getUserId, userId)); - } - -} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SseServiceImpl.java deleted file mode 100644 index 158cf3c..0000000 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/xmzs/system/service/impl/SseServiceImpl.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.xmzs.system.service.impl; - - -import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.json.JSONUtil; - -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 com.azure.core.util.IterableStream; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.xmzs.common.chat.config.LocalCache; -import com.xmzs.common.chat.constant.OpenAIConst; -import com.xmzs.common.chat.domain.request.ChatRequest; -import com.xmzs.common.chat.domain.request.Dall3Request; -import com.xmzs.common.chat.entity.chat.*; -import com.xmzs.common.chat.entity.images.Image; -import com.xmzs.common.chat.entity.images.ImageResponse; -import com.xmzs.common.chat.entity.images.Item; -import com.xmzs.common.chat.entity.images.ResponseFormat; -import com.xmzs.common.chat.openai.OpenAiStreamClient; -import com.xmzs.common.chat.utils.TikTokensUtil; -import com.xmzs.common.core.domain.model.LoginUser; -import com.xmzs.common.core.exception.ServiceException; -import com.xmzs.common.core.exception.base.BaseException; - -import com.xmzs.common.core.utils.StringUtils; -import com.xmzs.common.satoken.utils.LoginHelper; -import com.xmzs.common.translation.annotation.Translation; -import com.xmzs.system.domain.SysUser; -import com.xmzs.system.domain.bo.ChatMessageBo; -import com.xmzs.system.listener.SSEEventSourceListener; -import com.xmzs.system.mapper.SysUserMapper; -import com.xmzs.system.service.ChatService; -import com.xmzs.system.service.IChatMessageService; - -import com.xmzs.system.service.SseService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import com.azure.ai.openai.models.ImageGenerationOptions; -import com.azure.core.models.ResponseError; -import com.azure.ai.openai.OpenAIClient; -import com.azure.ai.openai.OpenAIClientBuilder; -import com.azure.ai.openai.models.ImageGenerationData; -import com.azure.ai.openai.models.ImageGenerationOptions; -import com.azure.ai.openai.models.ImageGenerations; -import com.azure.core.credential.AzureKeyCredential; -/** - * 鎻忚堪锛� - * - * @author https:www.unfbx.com - * @date 2023-04-08 - */ -@Service -@Slf4j -@RequiredArgsConstructor -public class SseServiceImpl implements SseService { - private final OpenAiStreamClient openAiStreamClient; - - private final ChatService chatService; - - private final SysUserMapper sysUserMapper; - - private final IChatMessageService chatMessageService; - - @Value("${transit.apiKey}") - private String API_KEY; - - @Value("${transit.apiHost}") - private String API_HOST; - - private static final String DONE_SIGNAL = "[DONE]"; - - @Override - @Transactional - public SseEmitter sseChat(ChatRequest chatRequest) { - LocalCache.CACHE.put("userId",getUserId()); - SseEmitter sseEmitter = new SseEmitter(0L); - SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter); - checkUserGrade(sseEmitter, chatRequest.getModel()); - // 鑾峰彇瀵硅瘽娑堟伅鍒楄〃 - List<Message> msgList = chatRequest.getMessages(); - // 鍥炬枃璇嗗埆涓婁笅鏂囦俊鎭� - List<Content> contentList = chatRequest.getContent(); - // 鍥炬枃璇嗗埆妯″瀷 - if (ChatCompletion.Model.GPT_4_VISION_PREVIEW.getName().equals(chatRequest.getModel())) { - MessagePicture message = MessagePicture.builder().role(Message.Role.USER.getName()).content(contentList).build(); - ChatCompletionWithPicture chatCompletion = ChatCompletionWithPicture - .builder() - .messages(Collections.singletonList(message)) - .model(chatRequest.getModel()) - .temperature(chatRequest.getTemperature()) - .topP(chatRequest.getTop_p()) - .stream(true) - .build(); - openAiStreamClient.streamChatCompletion(chatCompletion, openAIEventSourceListener); - // 鎵i櫎鍥炬枃瀵硅瘽璐圭敤 - chatService.deductUserBalance(getUserId(),OpenAIConst.GPT4_COST); - - String text = contentList.get(contentList.size() - 1).getText(); - // 淇濆瓨娑堟伅璁板綍 - ChatMessageBo chatMessageBo = new ChatMessageBo(); - chatMessageBo.setUserId(getUserId()); - chatMessageBo.setModelName(chatRequest.getModel()); - chatMessageBo.setContent(text); - chatMessageBo.setDeductCost(OpenAIConst.GPT4_COST); - chatMessageBo.setTotalTokens(0); - chatMessageService.insertByBo(chatMessageBo); - } else { - ChatCompletion completion = ChatCompletion - .builder() - .messages(msgList) - .model(chatRequest.getModel()) - .temperature(chatRequest.getTemperature()) - .topP(chatRequest.getTop_p()) - .stream(true) - .build(); - openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener); - Message message = msgList.get(msgList.size() - 1); - // 鎵i櫎浣欓 - int tokens = TikTokensUtil.tokens(chatRequest.getModel(), msgList); - ChatMessageBo chatMessageBo = new ChatMessageBo(); - chatMessageBo.setUserId(getUserId()); - chatMessageBo.setModelName(chatRequest.getModel()); - chatMessageBo.setContent(message.getContent()); - chatMessageBo.setTotalTokens(tokens); - chatService.deductToken(chatMessageBo); - } - return sseEmitter; - } - - /** - * dall-e-3缁樼敾鎺ュ彛 - * - * @param request - * @return - */ - public List<Item> dall3(Dall3Request request) { - checkUserGrade(null,""); - // DALL3 缁樺浘妯″瀷 - Image image = Image.builder() - .responseFormat(ResponseFormat.URL.getName()) - .model(Image.Model.DALL_E_3.getName()) - .prompt(request.getPrompt()) - .n(1) - .quality(request.getQuality()) - .size(request.getSize()) - .style(request.getStyle()) - .build(); - ImageResponse imageResponse = openAiStreamClient.genImages(image); - - // 鎵i櫎璐圭敤 - if(Objects.equals(request.getSize(), "1792x1024") || Objects.equals(request.getSize(), "1024x1792")){ - chatService.deductUserBalance(getUserId(),OpenAIConst.DALL3_HD_COST); - }else { - chatService.deductUserBalance(getUserId(),OpenAIConst.DALL3_COST); - } - // 淇濆瓨鎵h垂璁板綍 - ChatMessageBo chatMessageBo = new ChatMessageBo(); - chatMessageBo.setUserId(getUserId()); - chatMessageBo.setModelName(Image.Model.DALL_E_3.getName()); - chatMessageBo.setContent(request.getPrompt()); - chatMessageBo.setDeductCost(OpenAIConst.GPT4_COST); - chatMessageBo.setTotalTokens(0); - chatMessageService.insertByBo(chatMessageBo); - return imageResponse.getData(); - } - - @Override - public void mjTask() { - // 妫�楠屾槸鍚︽槸鍏嶈垂鐢ㄦ埛 - checkUserGrade(null,""); - chatService.deductUserBalance(getUserId(),OpenAIConst.MJ_COST); - // 淇濆瓨鎵h垂璁板綍 - ChatMessageBo chatMessageBo = new ChatMessageBo(); - chatMessageBo.setUserId(getUserId()); - chatMessageBo.setModelName("mj"); - chatMessageBo.setContent("mj缁樺浘"); - chatMessageBo.setDeductCost(OpenAIConst.GPT4_COST); - chatMessageBo.setTotalTokens(0); - chatMessageService.insertByBo(chatMessageBo); - } - - /** - * 涓浆鎺ュ彛 - * - * @param chatRequest - * @return - */ - @Override - public SseEmitter transitChat(ChatRequest chatRequest) { - // 鑾峰彇瀵硅瘽娑堟伅鍒楄〃 - List<Message> msgList = chatRequest.getMessages(); - Message message = msgList.get(msgList.size() - 1); - SseEmitter emitter = new SseEmitter(0L); - checkUserGrade(emitter, chatRequest.getModel()); - ChatCompletion completion = ChatCompletion - .builder() - .messages(chatRequest.getMessages()) - .model(chatRequest.getModel()) - .temperature(chatRequest.getTemperature()) - .topP(chatRequest.getTop_p()) - .stream(true) - .build(); - // 鍚姩涓�涓柊鐨勭嚎绋嬫潵澶勭悊鏁版嵁娴� - new Thread(() -> { - // 鍚姩涓�涓柊鐨勭嚎绋嬫潵澶勭悊鏁版嵁娴� - try { - ObjectMapper mapper = new ObjectMapper(); - String requestBody = mapper.writeValueAsString(completion); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(API_HOST + "v1/chat/completions")) - .header("Authorization", "Bearer " + API_KEY) - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(requestBody)) - .build(); - // 鍙戦�佽姹傚苟鑾峰彇鍝嶅簲浣撲綔涓篒nputStream - HttpResponse<InputStream> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofInputStream()); - // 浣跨敤姝g‘鐨勫瓧绗︾紪鐮佸皢InputStream鍖呰涓篒nputStreamReader锛岀劧鍚庡垱寤築ufferedReader - BufferedReader reader = new BufferedReader(new InputStreamReader(response.body())); - String line; - while ((line = reader.readLine()) != null) { - if (line.startsWith("data: ")) { - String data = line.replace("data: ", ""); - emitter.send(data, MediaType.TEXT_PLAIN); - if (data.equals(DONE_SIGNAL)) { - //鎴愬姛鍝嶅簲 - emitter.complete(); - } - } - } - // 鍏抽棴璧勬簮 - reader.close(); - } catch (Exception e) { - emitter.complete(); - throw new ServiceException("璋冪敤涓浆鎺ュ彛澶辫触:"+e.getMessage()); - } - }).start(); - chatService.deductUserBalance(getUserId(),OpenAIConst.GPT4_COST); - // 淇濆瓨娑堟伅璁板綍 - ChatMessageBo chatMessageBo = new ChatMessageBo(); - chatMessageBo.setUserId(getUserId()); - chatMessageBo.setModelName(chatRequest.getModel()); - chatMessageBo.setContent(message.getContent()); - chatMessageBo.setDeductCost(OpenAIConst.GPT4_COST); - chatMessageBo.setTotalTokens(0); - chatMessageService.insertByBo(chatMessageBo); - return emitter; - } - - public static void main(String[] args) { - String azureOpenaiKey = "-"; - String endpoint = "-"; - String deploymentOrModelName = "-"; - - OpenAIClient client = new OpenAIClientBuilder() - .endpoint(endpoint) - .credential(new AzureKeyCredential(azureOpenaiKey)) - .buildClient(); - - ImageGenerationOptions imageGenerationOptions = new ImageGenerationOptions( - "A drawing of the Seattle skyline in the style of Van Gogh"); - ImageGenerations images = client.getImageGenerations(deploymentOrModelName, imageGenerationOptions); - - for (ImageGenerationData imageGenerationData : images.getData()) { - System.out.printf( - "Image location URL that provides temporary access to download the generated image is %s.%n", - imageGenerationData.getUrl()); - } - } - - public SseEmitter azureChat(ChatRequest chatRequest) { - String azureOpenaiKey = "-"; - String endpoint = "-"; - String deploymentOrModelId = "-"; - OpenAIClient client = new OpenAIClientBuilder() - .endpoint(endpoint) - .credential(new AzureKeyCredential(azureOpenaiKey)) - .buildClient(); - final SseEmitter emitter = new SseEmitter(); - // 浣跨敤绾跨▼姹犲紓姝ユ墽琛� - ExecutorService service = Executors.newSingleThreadExecutor(); - service.execute(() -> { - try { - // 鑾峰彇瀵硅瘽娑堟伅鍒楄〃 - List<Message> chatMessages = chatRequest.getMessages(); - List<ChatRequestMessage> messages = new ArrayList<>(); - chatMessages.forEach( - e->{ - ChatRequestMessage chatMessage; - if(Message.Role.SYSTEM.getName().equals(e.getRole())){ - chatMessage = new ChatRequestSystemMessage(e.getContent()); - }else { - chatMessage = new ChatRequestUserMessage(e.getContent()); - } - messages.add(chatMessage); - } - ); - // 鑾峰彇娴佸紡鍝嶅簲 - IterableStream<ChatCompletions> chatCompletionsStream = client.getChatCompletionsStream(deploymentOrModelId, new ChatCompletionsOptions(messages)); - - // 閬嶅巻娴佸紡鍝嶅簲骞跺彂閫佸埌瀹㈡埛绔� - for (ChatCompletions chatCompletion : chatCompletionsStream) { - - if(CollectionUtil.isEmpty(chatCompletion.getChoices())){ - continue; - } - log.info("json ======{}", JSONUtil.toJsonStr(chatCompletion)); - emitter.send(chatCompletion); - } - emitter.complete(); - } catch (Exception e) { - emitter.completeWithError(e); - } - }); - return emitter; - } - - /** - * 鍒ゆ柇鐢ㄦ埛鏄惁浠樿垂 - */ - public void checkUserGrade(SseEmitter emitter, String model) { - SysUser sysUser = sysUserMapper.selectById(getUserId()); - if(StringUtils.isEmpty(model)){ - if("0".equals(sysUser.getUserGrade())){ - throw new ServiceException("鍏嶈垂鐢ㄦ埛鏆傛椂涓嶆敮鎸佹妯″瀷,璇峰垏鎹pt-3.5-turbo妯″瀷鎴栬�呯偣鍑汇�婅繘鍏ュ競鍦洪�夎喘鎮ㄧ殑鍟嗗搧銆嬪厖鍊煎悗浣跨敤!",500); - } - } - // TODO 娣诲姞鏋氫妇 - if ("0".equals(sysUser.getUserGrade()) && !ChatCompletion.Model.GPT_3_5_TURBO.getName().equals(model)) { - // 鍒涘缓骞跺彂閫佷竴涓悕涓� "error" 鐨勪簨浠讹紝甯︽湁閿欒娑堟伅鍜岀姸鎬佺爜 - SseEmitter.SseEventBuilder event = SseEmitter.event() - .name("error") // 瀹㈡埛绔皢鐩戝惉杩欎釜浜嬩欢鍚� - .data("鍏嶈垂鐢ㄦ埛鏆傛椂涓嶆敮鎸佹妯″瀷,璇峰垏鎹pt-3.5-turbo妯″瀷鎴栬�呯偣鍑汇�婅繘鍏ュ競鍦洪�夎喘鎮ㄧ殑鍟嗗搧銆嬪厖鍊煎悗浣跨敤!"); - try { - emitter.send(event); - } catch (IOException e) { - throw new RuntimeException(e); - } - emitter.complete(); - } - } - - /** - * 鑾峰彇鐢ㄦ埛Id - * - * @return - */ - public Long getUserId(){ - LoginUser loginUser = LoginHelper.getLoginUser(); - if (loginUser == null) { - throw new BaseException("鐢ㄦ埛鏈櫥褰曪紒"); - } - return loginUser.getUserId(); - } - -} -- Gitblit v1.9.3