正在显示
10 个修改的文件
包含
244 行增加
和
71 行删除
| @@ -55,7 +55,7 @@ public class ChatController { | @@ -55,7 +55,7 @@ public class ChatController { | ||
| 55 | @ResponseBody | 55 | @ResponseBody |
| 56 | public ChatResponse sseChat(@RequestBody ChatRequest chatRequest, @RequestHeader Map<String, String> headers, HttpServletResponse response) { | 56 | public ChatResponse sseChat(@RequestBody ChatRequest chatRequest, @RequestHeader Map<String, String> headers, HttpServletResponse response) { |
| 57 | String uid = getUid(headers); | 57 | String uid = getUid(headers); |
| 58 | - return sseService.sseChat(uid, chatRequest, ChatCompletion.Model.GPT_3_5_TURBO_0301,null); | 58 | + return sseService.sseChat(true,0,uid, chatRequest, ChatCompletion.Model.GPT_3_5_TURBO_0301,null); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | /** | 61 | /** |
| @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; | @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 4 | import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse; | 4 | import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse; |
| 5 | import com.unfbx.chatgpt.entity.chat.Message; | 5 | import com.unfbx.chatgpt.entity.chat.Message; |
| 6 | import com.zhonglai.luhui.chatgpt.event.MyEvent; | 6 | import com.zhonglai.luhui.chatgpt.event.MyEvent; |
| 7 | +import com.zhonglai.luhui.chatgpt.service.CompleteCallback; | ||
| 7 | import lombok.SneakyThrows; | 8 | import lombok.SneakyThrows; |
| 8 | import lombok.extern.slf4j.Slf4j; | 9 | import lombok.extern.slf4j.Slf4j; |
| 9 | import okhttp3.Response; | 10 | import okhttp3.Response; |
| @@ -28,8 +29,16 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | @@ -28,8 +29,16 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | ||
| 28 | 29 | ||
| 29 | private SseEmitter sseEmitter; | 30 | private SseEmitter sseEmitter; |
| 30 | 31 | ||
| 31 | - public OpenAISSEEventSourceListener(SseEmitter sseEmitter) { | 32 | + private StringBuffer contents = new StringBuffer(); |
| 33 | + | ||
| 34 | + private CompleteCallback completeCallback; | ||
| 35 | + | ||
| 36 | + private boolean isHaveData; | ||
| 37 | + private int recordId; | ||
| 38 | + public OpenAISSEEventSourceListener(SseEmitter sseEmitter, CompleteCallback completeCallback,int recordId) { | ||
| 32 | this.sseEmitter = sseEmitter; | 39 | this.sseEmitter = sseEmitter; |
| 40 | + this.completeCallback = completeCallback; | ||
| 41 | + this.recordId = recordId; | ||
| 33 | } | 42 | } |
| 34 | 43 | ||
| 35 | /** | 44 | /** |
| @@ -73,7 +82,13 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | @@ -73,7 +82,13 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | ||
| 73 | Message delta = completionResponse.getChoices().get(0).getDelta(); | 82 | Message delta = completionResponse.getChoices().get(0).getDelta(); |
| 74 | if(null != delta.getContent()) | 83 | if(null != delta.getContent()) |
| 75 | { | 84 | { |
| 76 | - sseEmitter.send(new MyEvent().data(delta.getContent(), MediaType.TEXT_EVENT_STREAM)); | 85 | + if(isHaveData) |
| 86 | + { | ||
| 87 | + sseEmitter.send(delta.getContent(), MediaType.TEXT_EVENT_STREAM); | ||
| 88 | + }else{ | ||
| 89 | + sseEmitter.send(new MyEvent().data(delta.getContent(), MediaType.TEXT_EVENT_STREAM)); | ||
| 90 | + } | ||
| 91 | + contents.append(delta.getContent()); | ||
| 77 | } | 92 | } |
| 78 | // sseEmitter.send(SseEmitter.event() | 93 | // sseEmitter.send(SseEmitter.event() |
| 79 | // .id(completionResponse.getId()) | 94 | // .id(completionResponse.getId()) |
| @@ -92,6 +107,10 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | @@ -92,6 +107,10 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | ||
| 92 | public void onClosed(EventSource eventSource) { | 107 | public void onClosed(EventSource eventSource) { |
| 93 | log.info("流式输出返回值总共{}tokens", tokens() - 2); | 108 | log.info("流式输出返回值总共{}tokens", tokens() - 2); |
| 94 | log.info("OpenAI关闭sse连接..."); | 109 | log.info("OpenAI关闭sse连接..."); |
| 110 | + if(null != completeCallback) | ||
| 111 | + { | ||
| 112 | + completeCallback.sseChatEnd(recordId,tokens,contents.toString()); | ||
| 113 | + } | ||
| 95 | } | 114 | } |
| 96 | 115 | ||
| 97 | 116 | ||
| @@ -117,4 +136,13 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | @@ -117,4 +136,13 @@ public class OpenAISSEEventSourceListener extends EventSourceListener { | ||
| 117 | public long tokens() { | 136 | public long tokens() { |
| 118 | return tokens; | 137 | return tokens; |
| 119 | } | 138 | } |
| 139 | + | ||
| 140 | + public String contents() | ||
| 141 | + { | ||
| 142 | + return contents.toString(); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + public void setHaveData(boolean haveData) { | ||
| 146 | + isHaveData = haveData; | ||
| 147 | + } | ||
| 120 | } | 148 | } |
| 1 | package com.zhonglai.luhui.chatgpt.service; | 1 | package com.zhonglai.luhui.chatgpt.service; |
| 2 | 2 | ||
| 3 | import com.unfbx.chatgpt.entity.chat.ChatCompletion; | 3 | import com.unfbx.chatgpt.entity.chat.ChatCompletion; |
| 4 | +import com.zhonglai.luhui.chatgpt.controller.request.ChatRequest; | ||
| 4 | import com.zhonglai.luhui.chatgpt.listener.OpenAISSEEventSourceListener; | 5 | import com.zhonglai.luhui.chatgpt.listener.OpenAISSEEventSourceListener; |
| 5 | 6 | ||
| 6 | public interface CompleteCallback { | 7 | public interface CompleteCallback { |
| 7 | - void sseChatEnd(ChatCompletion chatCompletion, OpenAISSEEventSourceListener openAISSEEventSourceListener); | 8 | + void sseChatEnd(int recordId,long tokens,String contents); |
| 9 | + int recordSseChat(Integer user_id, ChatRequest chatRequest, ChatCompletion chatCompletion); | ||
| 8 | } | 10 | } |
| @@ -30,5 +30,5 @@ public interface SseService { | @@ -30,5 +30,5 @@ public interface SseService { | ||
| 30 | * @param uid | 30 | * @param uid |
| 31 | * @param chatRequest | 31 | * @param chatRequest |
| 32 | */ | 32 | */ |
| 33 | - ChatResponse sseChat(String uid, ChatRequest chatRequest, ChatCompletion.Model model, CompleteCallback completeCallback); | 33 | + ChatResponse sseChat(Boolean isHaveData,Integer user_id,String uid, ChatRequest chatRequest, ChatCompletion.Model model, CompleteCallback completeCallback); |
| 34 | } | 34 | } |
| @@ -87,7 +87,7 @@ public class SseServiceImpl implements SseService { | @@ -87,7 +87,7 @@ public class SseServiceImpl implements SseService { | ||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | @Override | 89 | @Override |
| 90 | - public ChatResponse sseChat(String uid, ChatRequest chatRequest, ChatCompletion.Model model, CompleteCallback completeCallback) { | 90 | + public ChatResponse sseChat(Boolean isHaveData,Integer user_id,String uid, ChatRequest chatRequest, ChatCompletion.Model model, CompleteCallback completeCallback) { |
| 91 | if (ArrayUtil.isEmpty(chatRequest.getMsg())) { | 91 | if (ArrayUtil.isEmpty(chatRequest.getMsg())) { |
| 92 | log.info("参数异常,msg为null", uid); | 92 | log.info("参数异常,msg为null", uid); |
| 93 | throw new BaseException("参数异常,msg不能为空~"); | 93 | throw new BaseException("参数异常,msg不能为空~"); |
| @@ -120,20 +120,27 @@ public class SseServiceImpl implements SseService { | @@ -120,20 +120,27 @@ public class SseServiceImpl implements SseService { | ||
| 120 | log.info("聊天消息推送失败uid:[{}],没有创建连接,请重试。", uid); | 120 | log.info("聊天消息推送失败uid:[{}],没有创建连接,请重试。", uid); |
| 121 | throw new BaseException("聊天消息推送失败uid:[{}],没有创建连接,请重试。~"); | 121 | throw new BaseException("聊天消息推送失败uid:[{}],没有创建连接,请重试。~"); |
| 122 | } | 122 | } |
| 123 | - OpenAISSEEventSourceListener openAIEventSourceListener = new OpenAISSEEventSourceListener(sseEmitter); | 123 | + log.info("{}加载监听业务", uid); |
| 124 | + | ||
| 124 | ChatCompletion completion = ChatCompletion | 125 | ChatCompletion completion = ChatCompletion |
| 125 | .builder() | 126 | .builder() |
| 126 | .messages(messages) | 127 | .messages(messages) |
| 127 | .model(model.getName()) | 128 | .model(model.getName()) |
| 128 | .build(); | 129 | .build(); |
| 130 | + | ||
| 131 | + int recordId = 0; | ||
| 132 | + if(null != completeCallback) | ||
| 133 | + { | ||
| 134 | + recordId = completeCallback.recordSseChat(user_id,chatRequest,completion); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + OpenAISSEEventSourceListener openAIEventSourceListener = new OpenAISSEEventSourceListener(sseEmitter,completeCallback,recordId); | ||
| 138 | + openAIEventSourceListener.setHaveData(isHaveData); | ||
| 129 | openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener); | 139 | openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener); |
| 130 | // LocalCache.CACHE.put("msg" + uid, JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT); | 140 | // LocalCache.CACHE.put("msg" + uid, JSONUtil.toJsonStr(messages), LocalCache.TIMEOUT); |
| 131 | ChatResponse response = new ChatResponse(); | 141 | ChatResponse response = new ChatResponse(); |
| 132 | response.setQuestionTokens(completion.tokens()); | 142 | response.setQuestionTokens(completion.tokens()); |
| 133 | - if(null != completeCallback) | ||
| 134 | - { | ||
| 135 | - completeCallback.sseChatEnd(completion,openAIEventSourceListener); | ||
| 136 | - } | 143 | + |
| 137 | return response; | 144 | return response; |
| 138 | } | 145 | } |
| 139 | } | 146 | } |
| @@ -2,9 +2,14 @@ package com.zhonglai.luhui.openai; | @@ -2,9 +2,14 @@ package com.zhonglai.luhui.openai; | ||
| 2 | 2 | ||
| 3 | import com.ruoyi.common.utils.StringUtils; | 3 | import com.ruoyi.common.utils.StringUtils; |
| 4 | import okhttp3.OkHttpClient; | 4 | import okhttp3.OkHttpClient; |
| 5 | +import org.apache.tomcat.util.http.LegacyCookieProcessor; | ||
| 5 | import org.springframework.boot.SpringApplication; | 6 | import org.springframework.boot.SpringApplication; |
| 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; | 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | 8 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
| 9 | +import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer; | ||
| 10 | +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; | ||
| 11 | +import org.springframework.boot.web.server.WebServerFactoryCustomizer; | ||
| 12 | +import org.springframework.context.annotation.Bean; | ||
| 8 | import org.springframework.context.annotation.ComponentScan; | 13 | import org.springframework.context.annotation.ComponentScan; |
| 9 | 14 | ||
| 10 | import java.net.URL; | 15 | import java.net.URL; |
| @@ -27,4 +32,11 @@ public class OpenaiApplication { | @@ -27,4 +32,11 @@ public class OpenaiApplication { | ||
| 27 | SpringApplication.run(OpenaiApplication.class,args); | 32 | SpringApplication.run(OpenaiApplication.class,args); |
| 28 | System.out.println("启动成功"); | 33 | System.out.println("启动成功"); |
| 29 | } | 34 | } |
| 35 | + | ||
| 36 | + @Bean | ||
| 37 | + public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() { | ||
| 38 | + return tomcatServletWebServerFactory -> tomcatServletWebServerFactory.addContextCustomizers((TomcatContextCustomizer) context -> { | ||
| 39 | + context.setCookieProcessor(new LegacyCookieProcessor()); | ||
| 40 | + }); | ||
| 41 | + } | ||
| 30 | } | 42 | } |
lh-modules/lh-openai/src/main/java/com/zhonglai/luhui/openai/controller/ChatGPTStreamController.java
| @@ -38,12 +38,11 @@ import java.util.concurrent.TimeUnit; | @@ -38,12 +38,11 @@ import java.util.concurrent.TimeUnit; | ||
| 38 | @RequestMapping("/chatGPTStream") | 38 | @RequestMapping("/chatGPTStream") |
| 39 | public class ChatGPTStreamController extends BaseController { | 39 | public class ChatGPTStreamController extends BaseController { |
| 40 | private static String sessionkey = "CHAT_HISTORY_CONTEXT";//上下文关联存放地址 | 40 | private static String sessionkey = "CHAT_HISTORY_CONTEXT";//上下文关联存放地址 |
| 41 | - @Autowired | ||
| 42 | - private PublicService publicService; | ||
| 43 | 41 | ||
| 44 | @Autowired | 42 | @Autowired |
| 45 | private VipServiceImpl vipService; | 43 | private VipServiceImpl vipService; |
| 46 | - | 44 | + @Autowired |
| 45 | + private CompleteCallback completeCallback; | ||
| 47 | @Autowired | 46 | @Autowired |
| 48 | private ScheduledExecutorService scheduledExecutorService; | 47 | private ScheduledExecutorService scheduledExecutorService; |
| 49 | private final SseService sseService; | 48 | private final SseService sseService; |
| @@ -67,23 +66,13 @@ public class ChatGPTStreamController extends BaseController { | @@ -67,23 +66,13 @@ public class ChatGPTStreamController extends BaseController { | ||
| 67 | OpenAiLoginUser userInfo = (OpenAiLoginUser) SecurityUtils.getLoginUser(); | 66 | OpenAiLoginUser userInfo = (OpenAiLoginUser) SecurityUtils.getLoginUser(); |
| 68 | 67 | ||
| 69 | Integer user_id= SecurityUtils.getUserId().intValue(); | 68 | Integer user_id= SecurityUtils.getUserId().intValue(); |
| 70 | - String room_id = String.valueOf(user_id); | ||
| 71 | 69 | ||
| 72 | String uid = UUID.randomUUID().toString(); | 70 | String uid = UUID.randomUUID().toString(); |
| 73 | SseEmitter sseEmitter = sseService.createSse(uid); | 71 | SseEmitter sseEmitter = sseService.createSse(uid); |
| 74 | 72 | ||
| 75 | scheduledExecutorService.schedule(() -> { | 73 | scheduledExecutorService.schedule(() -> { |
| 76 | try{ | 74 | try{ |
| 77 | - BigDecimal[] bs = vipService.getUnitprice(); | ||
| 78 | - BigDecimal openaiUnitprice = bs[0]; | ||
| 79 | - BigDecimal realityUnitprice = bs[1]; | ||
| 80 | - if(openaiUnitprice.doubleValue()==0 || realityUnitprice.doubleValue()==0) | ||
| 81 | - { | ||
| 82 | - throw new BaseException("系统未配置流量单价,请联系管理员"); | ||
| 83 | - } | ||
| 84 | - | ||
| 85 | OpenAiUserInfo openAiUserInfo = (OpenAiUserInfo) userInfo.getUser(); | 75 | OpenAiUserInfo openAiUserInfo = (OpenAiUserInfo) userInfo.getUser(); |
| 86 | - | ||
| 87 | //验证余额是否充足 | 76 | //验证余额是否充足 |
| 88 | if(vipService.isCharging(openAiUserInfo.getVip_level()) && openAiUserInfo.getFlow_packet_remain()<=0) | 77 | if(vipService.isCharging(openAiUserInfo.getVip_level()) && openAiUserInfo.getFlow_packet_remain()<=0) |
| 89 | { | 78 | { |
| @@ -95,56 +84,57 @@ public class ChatGPTStreamController extends BaseController { | @@ -95,56 +84,57 @@ public class ChatGPTStreamController extends BaseController { | ||
| 95 | completionChoiceMessage3_5.setContent(stringBuffer.toString()); | 84 | completionChoiceMessage3_5.setContent(stringBuffer.toString()); |
| 96 | throw new BaseException("您的余额不足请联系管理员或者充值"); | 85 | throw new BaseException("您的余额不足请联系管理员或者充值"); |
| 97 | } | 86 | } |
| 87 | + sseService.sseChat(true,user_id,uid, chatRequest, chatRequest.getModel(),completeCallback); | ||
| 88 | + }catch (Exception e) | ||
| 89 | + { | ||
| 90 | + log.error("主业务流程异常",e); | ||
| 91 | + try { | ||
| 92 | + String estr = e.getMessage(); | ||
| 93 | + if(null == estr) | ||
| 94 | + { | ||
| 95 | + estr = "系统异常,请联系管理员"; | ||
| 96 | + } | ||
| 97 | + sseEmitter.send(estr, MediaType.TEXT_EVENT_STREAM); | ||
| 98 | + } catch (IOException ex) { | ||
| 99 | + log.error("sse信息推送失败!"); | ||
| 100 | + e.printStackTrace(); | ||
| 101 | + } | ||
| 102 | + sseService.closeSse(uid); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + },1, TimeUnit.SECONDS); | ||
| 106 | + return sseEmitter; | ||
| 107 | + } | ||
| 98 | 108 | ||
| 99 | - CompleteCallback completeCallback = (chatCompletion, openAISSEEventSourceListener) -> { | ||
| 100 | - GptMessage gptMessage = new GptMessage(); | ||
| 101 | - gptMessage.setRoom_id(room_id); | ||
| 102 | - gptMessage.setUser_id(user_id); | ||
| 103 | - gptMessage.setCreate_time(DateUtils.getNowTimeMilly()); | ||
| 104 | - gptMessage.setSend_role("user"); | ||
| 105 | 109 | ||
| 106 | - StringBuffer content = new StringBuffer(); | ||
| 107 | - for (com.unfbx.chatgpt.entity.chat.Message messge : chatCompletion.getMessages()) { | ||
| 108 | - content.append(messge.getContent()); | ||
| 109 | - } | ||
| 110 | - gptMessage.setSend_content(content.toString()); | ||
| 111 | - gptMessage.setSend_size(gptMessage.getSend_content().length()); | ||
| 112 | - //统计代币 | ||
| 113 | - gptMessage.setCompletion_tokens(UnitPriceCountUtil.countToken(chatRequest.getModel(),openAISSEEventSourceListener.tokens(),UnitPriceCountUtil.FlowType.Completion)); | ||
| 114 | - gptMessage.setPrompt_tokens(UnitPriceCountUtil.countToken(chatRequest.getModel(),chatCompletion.tokens(),UnitPriceCountUtil.FlowType.Completion)); | ||
| 115 | - gptMessage.setTotal_tokens(gptMessage.getCompletion_tokens() + gptMessage.getPrompt_tokens()); | ||
| 116 | - gptMessage.setMessage_role(chatCompletion.getMessages().get(0).getRole()); | ||
| 117 | -// gptMessage.setMessage_content(openAISSEEventSourceListener.contents()); | ||
| 118 | - gptMessage.setMessage_size(Long.valueOf(openAISSEEventSourceListener.tokens()).intValue()); | ||
| 119 | - publicService.insertToTable(gptMessage, "`lk_openai`.`gpt_message`"); | ||
| 120 | - | ||
| 121 | - UserFlowPacketRemainLog userFlowPacketRemainLog = new UserFlowPacketRemainLog(); | ||
| 122 | - userFlowPacketRemainLog.setCreate_time(DateUtils.getNowTimeMilly()); | ||
| 123 | - userFlowPacketRemainLog.setUser_id(user_id); | ||
| 124 | - userFlowPacketRemainLog.setType(2); //消费 | 110 | + @ApiOperation(value = "聊天接口返回data") |
| 111 | + @Transactional | ||
| 112 | + @PostMapping("/chatNotData") | ||
| 113 | + @ResponseBody | ||
| 114 | + public SseEmitter chatNotData(@RequestBody ChatRequest chatRequest) { | ||
| 125 | 115 | ||
| 116 | + OpenAiLoginUser userInfo = (OpenAiLoginUser) SecurityUtils.getLoginUser(); | ||
| 117 | + | ||
| 118 | + Integer user_id= SecurityUtils.getUserId().intValue(); | ||
| 119 | + | ||
| 120 | + String uid = UUID.randomUUID().toString(); | ||
| 121 | + SseEmitter sseEmitter = sseService.createSse(uid); | ||
| 122 | + | ||
| 123 | + scheduledExecutorService.schedule(() -> { | ||
| 124 | + try{ | ||
| 125 | + OpenAiUserInfo openAiUserInfo = (OpenAiUserInfo) userInfo.getUser(); | ||
| 126 | + //验证余额是否充足 | ||
| 127 | + if(vipService.isCharging(openAiUserInfo.getVip_level()) && openAiUserInfo.getFlow_packet_remain()<=0) | ||
| 128 | + { | ||
| 129 | + CompletionChoiceMessage3_5 completionChoiceMessage3_5 = new CompletionChoiceMessage3_5(); | ||
| 130 | + completionChoiceMessage3_5.setRole("assistant"); | ||
| 126 | StringBuffer stringBuffer = new StringBuffer(); | 131 | StringBuffer stringBuffer = new StringBuffer(); |
| 127 | - stringBuffer.append("房间号:"); | ||
| 128 | - stringBuffer.append(room_id); | ||
| 129 | - stringBuffer.append(";"); | ||
| 130 | - stringBuffer.append("发送代币:"); | ||
| 131 | - stringBuffer.append(gptMessage.getPrompt_tokens()); | ||
| 132 | - stringBuffer.append(";"); | ||
| 133 | - stringBuffer.append("返回代币:"); | ||
| 134 | - stringBuffer.append(gptMessage.getCompletion_tokens()); | ||
| 135 | - stringBuffer.append(";"); | ||
| 136 | - | ||
| 137 | - userFlowPacketRemainLog.setDescribe(stringBuffer.toString()); | ||
| 138 | - userFlowPacketRemainLog.setTotal_tokens(gptMessage.getTotal_tokens()); | ||
| 139 | - | ||
| 140 | - userFlowPacketRemainLog.setOpenai_money((openaiUnitprice.multiply(new BigDecimal(gptMessage.getTotal_tokens()))).divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP)); | ||
| 141 | - userFlowPacketRemainLog.setReality_money((realityUnitprice.multiply(new BigDecimal(gptMessage.getTotal_tokens()))).divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP)); | ||
| 142 | - publicService.insertToTable(userFlowPacketRemainLog, "`lk_openai`.`user_flow_packet_remain_log`"); | ||
| 143 | - | ||
| 144 | - publicService.updateBySql("UPDATE `lk_openai`.`user_info` SET flow_packet_remain=flow_packet_remain-" + userFlowPacketRemainLog.getTotal_tokens() + " WHERE id=" + openAiUserInfo.getId()); | ||
| 145 | - | ||
| 146 | - }; | ||
| 147 | - sseService.sseChat(uid, chatRequest, chatRequest.getModel(),completeCallback); | 132 | + stringBuffer.append("您的余额不足请联系管理员或者点击链接充值:\\n\\n"); |
| 133 | + stringBuffer.append("https://充值链接.com"); | ||
| 134 | + completionChoiceMessage3_5.setContent(stringBuffer.toString()); | ||
| 135 | + throw new BaseException("您的余额不足请联系管理员或者充值"); | ||
| 136 | + } | ||
| 137 | + sseService.sseChat(false,user_id,uid, chatRequest, chatRequest.getModel(),completeCallback); | ||
| 148 | }catch (Exception e) | 138 | }catch (Exception e) |
| 149 | { | 139 | { |
| 150 | log.error("主业务流程异常",e); | 140 | log.error("主业务流程异常",e); |
| @@ -166,6 +156,7 @@ public class ChatGPTStreamController extends BaseController { | @@ -166,6 +156,7 @@ public class ChatGPTStreamController extends BaseController { | ||
| 166 | return sseEmitter; | 156 | return sseEmitter; |
| 167 | } | 157 | } |
| 168 | 158 | ||
| 159 | + | ||
| 169 | /** | 160 | /** |
| 170 | * 关闭连接 | 161 | * 关闭连接 |
| 171 | * | 162 | * |
| @@ -16,6 +16,26 @@ public class GptMessage { | @@ -16,6 +16,26 @@ public class GptMessage { | ||
| 16 | 16 | ||
| 17 | private Long total_tokens; //bigint(20) DEFAULT NULL COMMENT '总代币', | 17 | private Long total_tokens; //bigint(20) DEFAULT NULL COMMENT '总代币', |
| 18 | 18 | ||
| 19 | + private Integer user_flow_packet_remain_log_id; //用户加油包消费日志id | ||
| 20 | + | ||
| 21 | + private String model; //请求模型 | ||
| 22 | + | ||
| 23 | + public String getModel() { | ||
| 24 | + return model; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public void setModel(String model) { | ||
| 28 | + this.model = model; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public Integer getUser_flow_packet_remain_log_id() { | ||
| 32 | + return user_flow_packet_remain_log_id; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public void setUser_flow_packet_remain_log_id(Integer user_flow_packet_remain_log_id) { | ||
| 36 | + this.user_flow_packet_remain_log_id = user_flow_packet_remain_log_id; | ||
| 37 | + } | ||
| 38 | + | ||
| 19 | public Long getTotal_tokens() { | 39 | public Long getTotal_tokens() { |
| 20 | return total_tokens; | 40 | return total_tokens; |
| 21 | } | 41 | } |
lh-modules/lh-openai/src/main/java/com/zhonglai/luhui/openai/service/CompleteCallbackImpl.java
0 → 100644
| 1 | +package com.zhonglai.luhui.openai.service; | ||
| 2 | + | ||
| 3 | +import com.ruoyi.common.utils.DateUtils; | ||
| 4 | +import com.unfbx.chatgpt.entity.chat.ChatCompletion; | ||
| 5 | +import com.unfbx.chatgpt.exception.BaseException; | ||
| 6 | +import com.zhonglai.luhui.chatgpt.controller.request.ChatRequest; | ||
| 7 | +import com.zhonglai.luhui.chatgpt.listener.OpenAISSEEventSourceListener; | ||
| 8 | +import com.zhonglai.luhui.chatgpt.service.CompleteCallback; | ||
| 9 | +import com.zhonglai.luhui.dao.service.PublicService; | ||
| 10 | +import com.zhonglai.luhui.openai.dto.GptMessage; | ||
| 11 | +import com.zhonglai.luhui.openai.dto.UserFlowPacketRemainLog; | ||
| 12 | +import com.zhonglai.luhui.openai.utils.UnitPriceCountUtil; | ||
| 13 | +import com.zhonglai.luhui.security.dto.OpenAiUserInfo; | ||
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 15 | +import org.springframework.stereotype.Service; | ||
| 16 | + | ||
| 17 | +import java.math.BigDecimal; | ||
| 18 | +import java.util.Arrays; | ||
| 19 | + | ||
| 20 | +@Service | ||
| 21 | +public class CompleteCallbackImpl implements CompleteCallback { | ||
| 22 | + | ||
| 23 | + @Autowired | ||
| 24 | + private PublicService publicService; | ||
| 25 | + | ||
| 26 | + @Autowired | ||
| 27 | + private VipServiceImpl vipService; | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public void sseChatEnd(int recordId,long tokens,String contents) { | ||
| 31 | + BigDecimal[] bs = vipService.getUnitprice(); | ||
| 32 | + BigDecimal openaiUnitprice = bs[0]; | ||
| 33 | + BigDecimal realityUnitprice = bs[1]; | ||
| 34 | + if(openaiUnitprice.doubleValue()==0 || realityUnitprice.doubleValue()==0) | ||
| 35 | + { | ||
| 36 | + throw new BaseException("系统未配置流量单价,请联系管理员"); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + if(0 == recordId) | ||
| 40 | + { | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + GptMessage gptMessage = publicService.getObjectForTableName(GptMessage.class,"id",recordId+"","`lk_openai`.`gpt_message`"); | ||
| 45 | + | ||
| 46 | + GptMessage upGptMessage = new GptMessage(); | ||
| 47 | + gptMessage.setCompletion_tokens(tokens); | ||
| 48 | + upGptMessage.setTotal_tokens(gptMessage.getCompletion_tokens() + gptMessage.getPrompt_tokens()); | ||
| 49 | + Arrays.stream(ChatCompletion.Model.values()).forEach(model -> { | ||
| 50 | + if (model.getName().equals(gptMessage.getModel())) | ||
| 51 | + upGptMessage.setCompletion_tokens(UnitPriceCountUtil.countToken(model,tokens,UnitPriceCountUtil.FlowType.Completion)); | ||
| 52 | + }); | ||
| 53 | + upGptMessage.setMessage_content(contents); | ||
| 54 | + upGptMessage.setMessage_size(upGptMessage.getMessage_content().length()); | ||
| 55 | + upGptMessage.setId(gptMessage.getId()); | ||
| 56 | + publicService.updateObjectByTable(upGptMessage,"id","`lk_openai`.`gpt_message`"); | ||
| 57 | + | ||
| 58 | + StringBuffer stringBuffer = new StringBuffer(); | ||
| 59 | + stringBuffer.append("房间号:"); | ||
| 60 | + stringBuffer.append(gptMessage.getRoom_id()); | ||
| 61 | + stringBuffer.append(";"); | ||
| 62 | + stringBuffer.append("发送代币:"); | ||
| 63 | + stringBuffer.append(gptMessage.getPrompt_tokens()); | ||
| 64 | + stringBuffer.append(";"); | ||
| 65 | + stringBuffer.append("返回代币:"); | ||
| 66 | + stringBuffer.append(gptMessage.getCompletion_tokens()); | ||
| 67 | + stringBuffer.append(";"); | ||
| 68 | + | ||
| 69 | + UserFlowPacketRemainLog userFlowPacketRemainLog = new UserFlowPacketRemainLog(); | ||
| 70 | + userFlowPacketRemainLog.setDescribe(stringBuffer.toString()); | ||
| 71 | + userFlowPacketRemainLog.setTotal_tokens(upGptMessage.getTotal_tokens()); | ||
| 72 | + userFlowPacketRemainLog.setOpenai_money((openaiUnitprice.multiply(new BigDecimal(upGptMessage.getTotal_tokens()))).divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP)); | ||
| 73 | + userFlowPacketRemainLog.setReality_money((realityUnitprice.multiply(new BigDecimal(upGptMessage.getTotal_tokens()))).divide(new BigDecimal(1000), 6, BigDecimal.ROUND_HALF_UP)); | ||
| 74 | + userFlowPacketRemainLog.setId(gptMessage.getUser_flow_packet_remain_log_id()); | ||
| 75 | + publicService.updateObjectByTable(userFlowPacketRemainLog,"id","`lk_openai`.`user_flow_packet_remain_log`"); | ||
| 76 | + | ||
| 77 | + publicService.updateBySql("UPDATE `lk_openai`.`user_info` SET flow_packet_remain=flow_packet_remain-" + userFlowPacketRemainLog.getTotal_tokens() + " WHERE id=" + gptMessage.getUser_id()); | ||
| 78 | + | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Override | ||
| 82 | + public int recordSseChat(Integer user_id, ChatRequest chatRequest, ChatCompletion chatCompletion) { | ||
| 83 | + | ||
| 84 | + String room_id = String.valueOf(user_id); | ||
| 85 | + | ||
| 86 | + UserFlowPacketRemainLog userFlowPacketRemainLog = new UserFlowPacketRemainLog(); | ||
| 87 | + userFlowPacketRemainLog.setCreate_time(DateUtils.getNowTimeMilly()); | ||
| 88 | + userFlowPacketRemainLog.setUser_id(user_id); | ||
| 89 | + userFlowPacketRemainLog.setType(2); //消费 | ||
| 90 | + publicService.insertToTable(userFlowPacketRemainLog, "`lk_openai`.`user_flow_packet_remain_log`"); | ||
| 91 | + | ||
| 92 | + GptMessage gptMessage = new GptMessage(); | ||
| 93 | + gptMessage.setRoom_id(room_id); | ||
| 94 | + gptMessage.setUser_id(user_id); | ||
| 95 | + gptMessage.setCreate_time(DateUtils.getNowTimeMilly()); | ||
| 96 | + gptMessage.setSend_role("user"); | ||
| 97 | + gptMessage.setModel(chatRequest.getModel().getName()); | ||
| 98 | + StringBuffer content = new StringBuffer(); | ||
| 99 | + for (com.unfbx.chatgpt.entity.chat.Message messge : chatCompletion.getMessages()) { | ||
| 100 | + content.append(messge.getContent()); | ||
| 101 | + } | ||
| 102 | + gptMessage.setSend_content(content.toString()); | ||
| 103 | + gptMessage.setSend_size(gptMessage.getSend_content().length()); | ||
| 104 | + //统计代币 | ||
| 105 | + gptMessage.setPrompt_tokens(UnitPriceCountUtil.countToken(chatRequest.getModel(),chatCompletion.tokens(),UnitPriceCountUtil.FlowType.Completion)); | ||
| 106 | + gptMessage.setMessage_role(chatCompletion.getMessages().get(0).getRole()); | ||
| 107 | + | ||
| 108 | + gptMessage.setUser_flow_packet_remain_log_id(userFlowPacketRemainLog.getId()); | ||
| 109 | + publicService.insertToTable(gptMessage, "`lk_openai`.`gpt_message`"); | ||
| 110 | + | ||
| 111 | + return gptMessage.getId(); | ||
| 112 | + } | ||
| 113 | +} |
| 1 | -# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 获取ip地址开关 addressEnabled: false profile: /www/wwwroot/lh-openai # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8082 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 47.112.163.61 # 端口,默认为6379 port: 9527 # 数据库索引 database: 1 # 密码 password: Luhui586 # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # web: # resources: # static-locations: classpath:/static/, classpath:/templates/ # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-openai # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/openAiUserLogin/*,/chatGPTStream/upUserFlowPacketRemain,/createSse,/chat,/closeSse chatgpt: token: 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 timeout: 5000 apiHost: https://api.openai.com/ proxy: isProxy: fales host: 127.0.0.1 port: 7890 | ||
| 1 | +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 获取ip地址开关 addressEnabled: false profile: /www/wwwroot/lh-openai # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8082 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 47.112.163.61 # 端口,默认为6379 port: 9527 # 数据库索引 database: 1 # 密码 password: Luhui586 # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # web: # resources: # static-locations: classpath:/static/, classpath:/templates/ # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-openai # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/openAiUserLogin/*,/chatGPTStream/upUserFlowPacketRemain,/createSse,/chat,/closeSse chatgpt: token: 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 timeout: 5000 apiHost: https://api.openai.com/ proxy: isProxy: true host: 127.0.0.1 port: 7890 |
-
请 注册 或 登录 后发表评论