From c54de2f15bdaca53fe4c9e5105d670d034ad3115 Mon Sep 17 00:00:00 2001 From: sunsongtao <474771806@qq.com> Date: Wed, 28 May 2025 17:15:32 +0800 Subject: [PATCH] 11 --- ruoyi-admin/pom.xml | 5 +- .../web/controller/api/ApiChatController.java | 1200 ++++++++--------- .../controller/api/ApiChatNewController.java | 309 +++++ .../src/main/resources/application.yml | 4 + ruoyi-system/pom.xml | 8 +- .../mall/domain/Chat/BaiduAppRequest.java | 66 + .../mall/domain/Chat/BaiduAppResponse.java | 97 ++ 7 files changed, 1086 insertions(+), 603 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatNewController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppRequest.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppResponse.java diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 48a42ed..e8b2270 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -73,11 +73,12 @@ weixin-java-miniapp - + + com.squareup.okhttp3 okhttp - 4.8.1 + 4.12.0 diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatController.java index 044652c..3680554 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatController.java @@ -1,600 +1,600 @@ -package com.ruoyi.web.controller.api; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.github.pagehelper.PageInfo; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.mall.domain.Bo.SaveChatRequestMessage; -import com.ruoyi.mall.domain.Bo.SaveMessage; -import com.ruoyi.mall.domain.Chat.ChatRequestMessage; -import com.ruoyi.mall.domain.Chat.ChatResponseMessage; -import com.ruoyi.mall.domain.Chat.Message; -import com.ruoyi.mall.domain.MallMemberUser; -import com.ruoyi.mall.service.IMallMemberUserService; -import okhttp3.*; -import okhttp3.RequestBody; -import org.apache.commons.lang3.ObjectUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.constraints.NotNull; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -/** - * @ClassName 智能对话接口 - * @Description 智能对话接口 - * @Author LHY - * @Date 2023/10/18 - * @Version 1.0 - **/ -@RestController -@RequestMapping("/api/chat") -public class ApiChatController { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Resource - private RedisTemplate redisTemplate; - - @Resource - private IMallMemberUserService mallMemberUserService; - //读取超时为60s - private static final long READ_TIMEOUT = 60000; - //写入超时为60s - private static final long WRITE_TIMEOUT = 60000; - //连接超时为60s - private static final long CONNECT_TIMEOUT = 60000; - - private OkHttpClient.Builder builder = new OkHttpClient.Builder() - .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS) - .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS) - .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS); - - - private OkHttpClient client = builder.build(); - private final String ACCESS_TOKEN_URI = "https://aip.baidubce.com/oauth/2.0/token"; - // private final String CHAT_URI = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"; - private final String CHAT_URI = "https://aip.baidubce.com/rpc/2.0/ai_custom/v2/wenxinworkshop/chat/completions"; - - private String apiKey = "hco0U4TGdVpA73F5mGBZliai"; - private String secretKey = "kBwPxP7PxRy5fTtIalW81GN7A3LFBrEN"; - - - //响应超时时间 - private int responseTimeOut = 5000; - - - /** - * 删除旧token - * - * @return - */ - @GetMapping("/delQFAccessToken") - public AjaxResult delQFAccessToken(){ - try { - // 删除原来的token - redisTemplate.delete("qianFanAccessToken"); - return AjaxResult.success("删除token成功"); - }catch (Exception e){ - return AjaxResult.error("获取AccessToken异常!"); - } - } - - - /** - * 获取千帆AccessToken - * - * @return - */ - @GetMapping("/getQFAccessToken") - public AjaxResult getAccessToken(){ - try { - String token = getQianFanAccessToken(); - return AjaxResult.success(token); - }catch (Exception e){ - return AjaxResult.error("获取AccessToken异常!"); - } - } - - - - /** - * 从缓存中拿到千帆AccessToken - * - * @return - */ - private String getQianFanAccessToken() { - String qianFanAccessToken = new String(); - if(null == redisTemplate.boundValueOps("qianFanAccessToken").get()){ - MediaType mediaType = MediaType.parse("application/json"); - // MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); - RequestBody body = RequestBody.create(mediaType, ""); - //创建一个请求 - Request request = new Request.Builder() - .url(ACCESS_TOKEN_URI+"?client_id=" + apiKey + "&client_secret=" + secretKey + "&grant_type=client_credentials") - .method("POST",body) - .addHeader("Content-Type", "application/json") - .addHeader("Accept", "application/json") - // .addHeader("Content-Type", "application/x-www-form-urlencoded") - .build(); - try { - //使用浏览器对象发起请求 - Response response = client.newCall(request).execute(); - //只能执行一次response.body().string()。下次再执行会抛出流关闭异常,因此需要一个对象存储返回结果 - String responseMessage = response.body().string(); - logger.info("获取accessToken成功"); - JSONObject jsonObject = JSONUtil.parseObj(responseMessage); - String accessToken = (String) jsonObject.get("access_token"); - redisTemplate.boundValueOps("qianFanAccessToken").set(accessToken, 30, TimeUnit.DAYS); - - qianFanAccessToken = (String) redisTemplate.boundValueOps("qianFanAccessToken").get(); - } catch (Exception e) { - e.printStackTrace(); - } - }else{ - qianFanAccessToken = (String) redisTemplate.boundValueOps("qianFanAccessToken").get(); - } - return qianFanAccessToken; - } - - /**对话 - * - * @param params - * @return - * @throws IOException - */ - @PostMapping("/createPicture") - @org.springframework.web.bind.annotation.ResponseBody - public AjaxResult chat(@org.springframework.web.bind.annotation.RequestBody Map params) throws IOException { - //对用户问题的判断 - if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { - return AjaxResult.error("缺少问题"); - } - if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { - return AjaxResult.error("缺少用户id"); - } - long userId = Long.parseLong(params.get("userId").toString()); - - MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); - if (memberUser == null) { - return AjaxResult.error("用户信息异常!!!"); - } - - String question = params.get("question").toString(); - //通过参数获取一个Message - Message message = new Message("user",question); - //请求参数 - ChatRequestMessage requestBody = new ChatRequestMessage(); - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); - //System.out.println("json:"+json); - requestBody = JSONUtil.toBean(json, ChatRequestMessage.class); - } - //将新的问题添加到消息上下文 - requestBody.addMessage(message); - String jsonStr = JSONUtil.toJsonStr(requestBody); - //System.out.println("jsonStr:"+jsonStr); - MediaType mediaType = MediaType.parse("application/json"); - RequestBody body = RequestBody.create(mediaType, jsonStr); - Request request = new Request.Builder() - .url(CHAT_URI+"?access_token="+getQianFanAccessToken()) - .method("POST", body) - .addHeader("Content-Type", "application/json") - .build(); - try{ - //logger.info("千帆AccessToken:{}",getQianFanAccessToken()); - Response response = client.newCall(request).execute(); - String responseJsonStr = response.body().string(); - logger.info("发送一次请求,询问问题:{}",question); - ChatResponseMessage responseMessage = JSONUtil.toBean(responseJsonStr, ChatResponseMessage.class); - System.out.println("返回的响应结果为:"+responseJsonStr); - String result = responseMessage.getResult(); - String answer = result.replaceAll("\n+", "\n"); - logger.info("{}",answer); - Message assistant = new Message("assistant", answer); - requestBody.addMessage(assistant); - //redis 存储 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(requestBody), 30, TimeUnit.DAYS); - }else{ - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(requestBody), 30, TimeUnit.DAYS); - } - logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); - return AjaxResult.success(requestBody); - }catch (Exception e){ - e.printStackTrace(); - return AjaxResult.error("对话失败!"); - } - - } - - /**对话 只返回最新内容 - * - * @param params - * @return - * @throws IOException - */ - @PostMapping("/newChat") - @org.springframework.web.bind.annotation.ResponseBody - public AjaxResult chatNew(@org.springframework.web.bind.annotation.RequestBody Map params) throws IOException { - //对用户问题的判断 - if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { - return AjaxResult.error("缺少问题"); - } - if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { - return AjaxResult.error("缺少用户id"); - } - if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){ - return AjaxResult.error("缺少语音状态"); - } - long userId = Long.parseLong(params.get("userId").toString()); - // 是否有语音0-没有,1-有 - Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString()); - - MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); - if (memberUser == null) { - return AjaxResult.error("用户信息异常!!!"); - } - - String question = params.get("question").toString(); - //通过参数获取一个Message - Message message = new Message("user",question); - // 创建存储用saveMessage - SaveMessage saveMessage = new SaveMessage(); - saveMessage.setRole("user"); - saveMessage.setContent(question); - saveMessage.setHasVoice(hasVoice); - if (hasVoice == 1){ - saveMessage.setVoiceUrl(params.get("voiceUrl").toString()); - } - //请求参数 - ChatRequestMessage requestBody = new ChatRequestMessage(); - // 创建存储类 - SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage(); - - // 查询是否有记录 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); - //System.out.println("json:"+json); - //requestBody = JSONUtil.toBean(json, ChatRequestMessage.class); - saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class); - // 记录信息复制到请求参数中 - BeanUtil.copyProperties(saveChatRequestMessage, requestBody); - List saveMessageList = saveChatRequestMessage.getSaveMessageList(); - ArrayList list = new ArrayList<>(); - if (!saveMessageList.isEmpty()){ - for (SaveMessage saveMessageHistory : saveMessageList) { - Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class); - list.add(m); - } - requestBody.setMessages(list); - } - } - //将新的问题添加到消息上下文 - requestBody.addMessage(message); - // 新信息添加保存 - saveChatRequestMessage.addSaveMessage(saveMessage); - - String jsonStr = JSONUtil.toJsonStr(requestBody); - //System.out.println("jsonStr:"+jsonStr); - MediaType mediaType = MediaType.parse("application/json"); - RequestBody body = RequestBody.create(mediaType, jsonStr); - Request request = new Request.Builder() - .url(CHAT_URI+"?access_token="+getQianFanAccessToken()) - .method("POST", body) - .addHeader("Content-Type", "application/json") - .build(); - try{ - //logger.info("千帆AccessToken:{}",getQianFanAccessToken()); - Response response = client.newCall(request).execute(); - String responseJsonStr = response.body().string(); - logger.info("发送一次请求,询问问题:{}",question); - ChatResponseMessage responseMessage = JSONUtil.toBean(responseJsonStr, ChatResponseMessage.class); - System.out.println("返回的响应结果为:"+responseJsonStr); - String result = responseMessage.getResult(); - String answer = result.replaceAll("\n+", "\n"); - logger.info("{}",answer); - Message assistant = new Message("assistant", answer); - requestBody.addMessage(assistant); - - // 存储信息 - SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class); - saveAnswer.setHasVoice(hasVoice); - saveChatRequestMessage.addSaveMessage(saveAnswer); - - //redis 存储 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); - }else{ - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); - } - logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); - List newChat = new ArrayList<>(); - newChat.add(saveMessage); - newChat.add(saveAnswer); - return AjaxResult.success(newChat); - }catch (Exception e){ - e.printStackTrace(); - return AjaxResult.error("对话失败!"); - } - - } - - /**对话历史-近到远—分页 - * - * @param userId 当前对话用户id - * @return - */ - @GetMapping("/getChatHistory") - public AjaxResult getChatHistory(@RequestParam(defaultValue = "1") Integer pageNum, - @RequestParam(defaultValue = "10") Integer pageSize, - @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){ - try { - MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); - if (memberUser == null) { - return AjaxResult.error("用户信息异常!!!"); - } - SaveChatRequestMessage requestBody = new SaveChatRequestMessage(); - List history = new ArrayList<>(); - //有历史消息 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); - System.out.println("json:"+json); - requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class); - if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){ - history = requestBody.getSaveMessageList(); - Collections.reverse(history); - } - } - - //Page page = new Page<>(pageNum,pageSize); - ////为Page类中的total属性赋值 - //int total = history.size(); - //page.setTotal(total); - ////计算当前需要显示的数据下标起始值 - //int startIndex = (pageNum - 1) * pageSize; - //int endIndex = Math.min(startIndex + pageSize,total); - ////从链表中截取需要显示的子链表,并加入到Page - //page.addAll(history.subList(startIndex,endIndex)); - ////以Page创建PageInfo - //PageInfo pageInfo = new PageInfo<>(page); - //return AjaxResult.success().put("data",pageInfo); - - //java8 stream实现list分页 - - List pageList = history.stream().sorted().skip((pageNum - 1) * pageSize) - .limit(pageSize) - .collect(Collectors.toList()); - PageInfo pageInfo = new PageInfo(pageList); - //获取PageInfo其他参数 - pageInfo.setTotal(history.size()); - - int endRow = pageInfo.getEndRow() == 0 ? 0 : (int)((pageNum - 1) * pageSize + pageInfo.getEndRow() + 1); - pageInfo.setEndRow(endRow); - boolean hasNextPage = history.size() <= pageSize * pageNum ? false : true; - pageInfo.setHasNextPage(hasNextPage); - boolean hasPreviousPage = pageNum == 1 ? false : true; - pageInfo.setHasPreviousPage(hasPreviousPage); - pageInfo.setIsFirstPage(!hasPreviousPage); - boolean isLastPage = (history.size() > pageSize * (pageNum - 1) && history.size() <= pageSize * pageNum) ? true : false; - pageInfo.setIsLastPage(isLastPage); - int pages = history.size() % pageSize == 0 ? history.size() / pageSize : (history.size() / pageSize) + 1; - pageInfo.setNavigateLastPage(pages); - int[] navigatePageNums = new int[pages]; - for (int i = 1; i < pages; i++) { - navigatePageNums[i - 1] = i; - } - pageInfo.setNavigatepageNums(navigatePageNums); - int nextPage = pageNum < pages ? pageNum + 1 : 0; - pageInfo.setNextPage(nextPage); - pageInfo.setPageNum(pageNum); - pageInfo.setPageSize(pageSize); - pageInfo.setPages(pages); - pageInfo.setPrePage(pageNum - 1); - pageInfo.setSize(pageInfo.getList().size()); - int starRow = history.size() < pageSize * pageNum ? 1 + pageSize * (pageNum - 1) : 0; - pageInfo.setStartRow(starRow); - return AjaxResult.success().put("data", pageInfo); - - }catch (Exception e){ - return AjaxResult.error("获取对话历史异常!"); - } - } - - /** 最后一页页数 - * - * @param pageNum - * @param pageSize - * @param userId - * @return - */ - @GetMapping("/getLastNum") - public AjaxResult getLastNum(@RequestParam(defaultValue = "1") Integer pageNum, - @RequestParam(defaultValue = "10") Integer pageSize, - @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){ - try { - MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); - if (memberUser == null) { - return AjaxResult.error("用户信息异常!!!"); - } - SaveChatRequestMessage requestBody = new SaveChatRequestMessage(); - List history = new ArrayList<>(); - //有历史消息 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); - System.out.println("json:"+json); - requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class); - if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){ - history = requestBody.getSaveMessageList(); - } - int total = history.size(); - int num = total/pageSize; - int remain = total%pageSize; - if(num == 0 && remain > 0){ - return AjaxResult.success().put("lastPage",1); - } else if(num > 0 && remain > 0) { - return AjaxResult.success().put("lastPage",num+1); - }else if(num > 0 && remain == 0) { - return AjaxResult.success().put("lastPage",num); - }else{ - return AjaxResult.success().put("lastPage",0); - } - }else{ - return AjaxResult.success().put("lastPage",0); - } - - - }catch (Exception e){ - return AjaxResult.error("获取最后页数异常!"); - } - } - - - /** - * 调用知识库 - */ - @PostMapping("/chatNew") - @org.springframework.web.bind.annotation.ResponseBody - public AjaxResult newChat(@org.springframework.web.bind.annotation.RequestBody Map params){ - //对用户问题的判断 - if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { - return AjaxResult.error("缺少问题"); - } - if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { - return AjaxResult.error("缺少用户id"); - } - if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){ - return AjaxResult.error("缺少语音状态"); - } - long userId = Long.parseLong(params.get("userId").toString()); - // 是否有语音0-没有,1-有 - Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString()); - - MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); - if (memberUser == null) { - return AjaxResult.error("用户信息异常!!!"); - } - - String question = params.get("question").toString(); - //通过参数获取一个Message - Message message = new Message("user",question); - // 创建存储用saveMessage - SaveMessage saveMessage = new SaveMessage(); - saveMessage.setRole("user"); - saveMessage.setContent(question); - saveMessage.setHasVoice(hasVoice); - if (hasVoice == 1){ - saveMessage.setVoiceUrl(params.get("voiceUrl").toString()); - } - - com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); - jsonObject.put("query", question); - List plugins = new ArrayList<>(); - plugins.add("uuid-zhishiku"); - //plugins.add("uuid-weatherforecast"); - //jsonObject.put("plugins", plugins); - //jsonObject.put("verbose", false); - - - // 创建存储类 - SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage(); - ArrayList historyList = new ArrayList<>(); - // 查询是否有记录 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); - saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class); - // 记录信息复制到请求参数中 - List saveMessageList = saveChatRequestMessage.getSaveMessageList(); - - if (!saveMessageList.isEmpty()){ - List shortList = new ArrayList<>(); - int size = saveMessageList.size(); - if ( size >= 2){ - shortList.add(saveMessageList.get(size - 2)); - shortList.add(saveMessageList.get(size - 1)); - for (SaveMessage saveMessageHistory : shortList) { - Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class); - historyList.add(m); - } - } - - } - } - //将新的问题添加到消息上下文 - //jsonObject.put("history", historyList); - // 新信息添加保存 - saveChatRequestMessage.addSaveMessage(saveMessage); - - String jsonStr = jsonObject.toJSONString(); - MediaType mediaType = MediaType.parse("application/json"); - RequestBody body = RequestBody.create(mediaType, jsonStr); - Request request = new Request.Builder() - // .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v2/wenxinworkshop/plugin/jfa2nhi1zap61qy7?access_token="+getQianFanAccessToken()) - .url("https://qianfan.baidubce.com/v2/chat/completions") - .method("POST", body) - .addHeader("Content-Type", "application/json") - .addHeader("Authorization", "Bearer " + getQianFanAccessToken()) - .build(); - try{ - logger.info("千帆AccessToken:{}",getQianFanAccessToken()); - Response response = client.newCall(request).execute(); - String responseJsonStr = response.body().string(); - - com.alibaba.fastjson.JSONObject data = JSONUtil.toBean(responseJsonStr, com.alibaba.fastjson.JSONObject.class); - System.out.println("返回的响应结果为:"+responseJsonStr); - System.out.println("data:"+data); - System.out.println("result:"+data.getString("result")); - System.out.println("response:"+response); - String result = data.getString("result"); - if (StringUtils.isNotBlank(result)){ - String answer = result.replaceAll("\n", ""); - - //int i = answer.indexOf("\n"); - Message assistant = new Message("assistant", answer); - //if (i> 0){ - // assistant.setContent(answer.substring(0,i)); - //} - - - // 存储信息 - SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class); - saveAnswer.setHasVoice(hasVoice); - - saveChatRequestMessage.addSaveMessage(saveAnswer); - - //redis 存储 - if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ - Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); - }else{ - redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); - } - logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); - List newChat = new ArrayList<>(); - newChat.add(saveMessage); - newChat.add(saveAnswer); - - return AjaxResult.success(newChat); - }else{ - logger.error("对话返回结果为空"); - return AjaxResult.error("对话失败!"); - } - - }catch (Exception e){ - e.printStackTrace(); - return AjaxResult.error("对话失败!"); - } - - } - -} +// package com.ruoyi.web.controller.api; +// +// import cn.hutool.core.bean.BeanUtil; +// import cn.hutool.json.JSONObject; +// import cn.hutool.json.JSONUtil; +// import com.github.pagehelper.PageInfo; +// import com.ruoyi.common.core.domain.AjaxResult; +// import com.ruoyi.common.utils.StringUtils; +// import com.ruoyi.mall.domain.Bo.SaveChatRequestMessage; +// import com.ruoyi.mall.domain.Bo.SaveMessage; +// import com.ruoyi.mall.domain.Chat.ChatRequestMessage; +// import com.ruoyi.mall.domain.Chat.ChatResponseMessage; +// import com.ruoyi.mall.domain.Chat.Message; +// import com.ruoyi.mall.domain.MallMemberUser; +// import com.ruoyi.mall.service.IMallMemberUserService; +// import okhttp3.*; +// import okhttp3.RequestBody; +// import org.apache.commons.lang3.ObjectUtils; +// import org.slf4j.Logger; +// import org.slf4j.LoggerFactory; +// import org.springframework.data.redis.core.RedisTemplate; +// import org.springframework.web.bind.annotation.*; +// +// import javax.annotation.Resource; +// import javax.validation.constraints.NotNull; +// import java.io.IOException; +// import java.util.*; +// import java.util.concurrent.TimeUnit; +// import java.util.stream.Collectors; +// +// /** +// * @ClassName 智能对话接口 +// * @Description 智能对话接口 +// * @Author LHY +// * @Date 2023/10/18 +// * @Version 1.0 +// **/ +// @RestController +// @RequestMapping("/api/chat") +// public class ApiChatController { +// +// private final Logger logger = LoggerFactory.getLogger(this.getClass()); +// +// @Resource +// private RedisTemplate redisTemplate; +// +// @Resource +// private IMallMemberUserService mallMemberUserService; +// //读取超时为60s +// private static final long READ_TIMEOUT = 60000; +// //写入超时为60s +// private static final long WRITE_TIMEOUT = 60000; +// //连接超时为60s +// private static final long CONNECT_TIMEOUT = 60000; +// +// private OkHttpClient.Builder builder = new OkHttpClient.Builder() +// .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS) +// .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS) +// .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS); +// +// +// private OkHttpClient client = builder.build(); +// private final String ACCESS_TOKEN_URI = "https://aip.baidubce.com/oauth/2.0/token"; +// // private final String CHAT_URI = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"; +// private final String CHAT_URI = "https://aip.baidubce.com/rpc/2.0/ai_custom/v2/wenxinworkshop/chat/completions"; +// +// private String apiKey = "hco0U4TGdVpA73F5mGBZliai"; +// private String secretKey = "kBwPxP7PxRy5fTtIalW81GN7A3LFBrEN"; +// +// +// //响应超时时间 +// private int responseTimeOut = 5000; +// +// +// /** +// * 删除旧token +// * +// * @return +// */ +// @GetMapping("/delQFAccessToken") +// public AjaxResult delQFAccessToken(){ +// try { +// // 删除原来的token +// redisTemplate.delete("qianFanAccessToken"); +// return AjaxResult.success("删除token成功"); +// }catch (Exception e){ +// return AjaxResult.error("获取AccessToken异常!"); +// } +// } +// +// +// /** +// * 获取千帆AccessToken +// * +// * @return +// */ +// @GetMapping("/getQFAccessToken") +// public AjaxResult getAccessToken(){ +// try { +// String token = getQianFanAccessToken(); +// return AjaxResult.success(token); +// }catch (Exception e){ +// return AjaxResult.error("获取AccessToken异常!"); +// } +// } +// +// +// +// /** +// * 从缓存中拿到千帆AccessToken +// * +// * @return +// */ +// private String getQianFanAccessToken() { +// String qianFanAccessToken = new String(); +// if(null == redisTemplate.boundValueOps("qianFanAccessToken").get()){ +// MediaType mediaType = MediaType.parse("application/json"); +// // MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); +// RequestBody body = RequestBody.create(mediaType, ""); +// //创建一个请求 +// Request request = new Request.Builder() +// .url(ACCESS_TOKEN_URI+"?client_id=" + apiKey + "&client_secret=" + secretKey + "&grant_type=client_credentials") +// .method("POST",body) +// .addHeader("Content-Type", "application/json") +// .addHeader("Accept", "application/json") +// // .addHeader("Content-Type", "application/x-www-form-urlencoded") +// .build(); +// try { +// //使用浏览器对象发起请求 +// Response response = client.newCall(request).execute(); +// //只能执行一次response.body().string()。下次再执行会抛出流关闭异常,因此需要一个对象存储返回结果 +// String responseMessage = response.body().string(); +// logger.info("获取accessToken成功"); +// JSONObject jsonObject = JSONUtil.parseObj(responseMessage); +// String accessToken = (String) jsonObject.get("access_token"); +// redisTemplate.boundValueOps("qianFanAccessToken").set(accessToken, 30, TimeUnit.DAYS); +// +// qianFanAccessToken = (String) redisTemplate.boundValueOps("qianFanAccessToken").get(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// }else{ +// qianFanAccessToken = (String) redisTemplate.boundValueOps("qianFanAccessToken").get(); +// } +// return qianFanAccessToken; +// } +// +// /**对话 +// * +// * @param params +// * @return +// * @throws IOException +// */ +// @PostMapping("/createPicture") +// @org.springframework.web.bind.annotation.ResponseBody +// public AjaxResult chat(@org.springframework.web.bind.annotation.RequestBody Map params) throws IOException { +// //对用户问题的判断 +// if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { +// return AjaxResult.error("缺少问题"); +// } +// if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { +// return AjaxResult.error("缺少用户id"); +// } +// long userId = Long.parseLong(params.get("userId").toString()); +// +// MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); +// if (memberUser == null) { +// return AjaxResult.error("用户信息异常!!!"); +// } +// +// String question = params.get("question").toString(); +// //通过参数获取一个Message +// Message message = new Message("user",question); +// //请求参数 +// ChatRequestMessage requestBody = new ChatRequestMessage(); +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); +// //System.out.println("json:"+json); +// requestBody = JSONUtil.toBean(json, ChatRequestMessage.class); +// } +// //将新的问题添加到消息上下文 +// requestBody.addMessage(message); +// String jsonStr = JSONUtil.toJsonStr(requestBody); +// //System.out.println("jsonStr:"+jsonStr); +// MediaType mediaType = MediaType.parse("application/json"); +// RequestBody body = RequestBody.create(mediaType, jsonStr); +// Request request = new Request.Builder() +// .url(CHAT_URI+"?access_token="+getQianFanAccessToken()) +// .method("POST", body) +// .addHeader("Content-Type", "application/json") +// .build(); +// try{ +// //logger.info("千帆AccessToken:{}",getQianFanAccessToken()); +// Response response = client.newCall(request).execute(); +// String responseJsonStr = response.body().string(); +// logger.info("发送一次请求,询问问题:{}",question); +// ChatResponseMessage responseMessage = JSONUtil.toBean(responseJsonStr, ChatResponseMessage.class); +// System.out.println("返回的响应结果为:"+responseJsonStr); +// String result = responseMessage.getResult(); +// String answer = result.replaceAll("\n+", "\n"); +// logger.info("{}",answer); +// Message assistant = new Message("assistant", answer); +// requestBody.addMessage(assistant); +// //redis 存储 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(requestBody), 30, TimeUnit.DAYS); +// }else{ +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(requestBody), 30, TimeUnit.DAYS); +// } +// logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); +// return AjaxResult.success(requestBody); +// }catch (Exception e){ +// e.printStackTrace(); +// return AjaxResult.error("对话失败!"); +// } +// +// } +// +// /**对话 只返回最新内容 +// * +// * @param params +// * @return +// * @throws IOException +// */ +// @PostMapping("/newChat") +// @org.springframework.web.bind.annotation.ResponseBody +// public AjaxResult chatNew(@org.springframework.web.bind.annotation.RequestBody Map params) throws IOException { +// //对用户问题的判断 +// if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { +// return AjaxResult.error("缺少问题"); +// } +// if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { +// return AjaxResult.error("缺少用户id"); +// } +// if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){ +// return AjaxResult.error("缺少语音状态"); +// } +// long userId = Long.parseLong(params.get("userId").toString()); +// // 是否有语音0-没有,1-有 +// Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString()); +// +// MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); +// if (memberUser == null) { +// return AjaxResult.error("用户信息异常!!!"); +// } +// +// String question = params.get("question").toString(); +// //通过参数获取一个Message +// Message message = new Message("user",question); +// // 创建存储用saveMessage +// SaveMessage saveMessage = new SaveMessage(); +// saveMessage.setRole("user"); +// saveMessage.setContent(question); +// saveMessage.setHasVoice(hasVoice); +// if (hasVoice == 1){ +// saveMessage.setVoiceUrl(params.get("voiceUrl").toString()); +// } +// //请求参数 +// ChatRequestMessage requestBody = new ChatRequestMessage(); +// // 创建存储类 +// SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage(); +// +// // 查询是否有记录 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); +// //System.out.println("json:"+json); +// //requestBody = JSONUtil.toBean(json, ChatRequestMessage.class); +// saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class); +// // 记录信息复制到请求参数中 +// BeanUtil.copyProperties(saveChatRequestMessage, requestBody); +// List saveMessageList = saveChatRequestMessage.getSaveMessageList(); +// ArrayList list = new ArrayList<>(); +// if (!saveMessageList.isEmpty()){ +// for (SaveMessage saveMessageHistory : saveMessageList) { +// Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class); +// list.add(m); +// } +// requestBody.setMessages(list); +// } +// } +// //将新的问题添加到消息上下文 +// requestBody.addMessage(message); +// // 新信息添加保存 +// saveChatRequestMessage.addSaveMessage(saveMessage); +// +// String jsonStr = JSONUtil.toJsonStr(requestBody); +// //System.out.println("jsonStr:"+jsonStr); +// MediaType mediaType = MediaType.parse("application/json"); +// RequestBody body = RequestBody.create(mediaType, jsonStr); +// Request request = new Request.Builder() +// .url(CHAT_URI+"?access_token="+getQianFanAccessToken()) +// .method("POST", body) +// .addHeader("Content-Type", "application/json") +// .build(); +// try{ +// //logger.info("千帆AccessToken:{}",getQianFanAccessToken()); +// Response response = client.newCall(request).execute(); +// String responseJsonStr = response.body().string(); +// logger.info("发送一次请求,询问问题:{}",question); +// ChatResponseMessage responseMessage = JSONUtil.toBean(responseJsonStr, ChatResponseMessage.class); +// System.out.println("返回的响应结果为:"+responseJsonStr); +// String result = responseMessage.getResult(); +// String answer = result.replaceAll("\n+", "\n"); +// logger.info("{}",answer); +// Message assistant = new Message("assistant", answer); +// requestBody.addMessage(assistant); +// +// // 存储信息 +// SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class); +// saveAnswer.setHasVoice(hasVoice); +// saveChatRequestMessage.addSaveMessage(saveAnswer); +// +// //redis 存储 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); +// }else{ +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); +// } +// logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); +// List newChat = new ArrayList<>(); +// newChat.add(saveMessage); +// newChat.add(saveAnswer); +// return AjaxResult.success(newChat); +// }catch (Exception e){ +// e.printStackTrace(); +// return AjaxResult.error("对话失败!"); +// } +// +// } +// +// /**对话历史-近到远—分页 +// * +// * @param userId 当前对话用户id +// * @return +// */ +// @GetMapping("/getChatHistory") +// public AjaxResult getChatHistory(@RequestParam(defaultValue = "1") Integer pageNum, +// @RequestParam(defaultValue = "10") Integer pageSize, +// @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){ +// try { +// MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); +// if (memberUser == null) { +// return AjaxResult.error("用户信息异常!!!"); +// } +// SaveChatRequestMessage requestBody = new SaveChatRequestMessage(); +// List history = new ArrayList<>(); +// //有历史消息 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); +// System.out.println("json:"+json); +// requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class); +// if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){ +// history = requestBody.getSaveMessageList(); +// Collections.reverse(history); +// } +// } +// +// //Page page = new Page<>(pageNum,pageSize); +// ////为Page类中的total属性赋值 +// //int total = history.size(); +// //page.setTotal(total); +// ////计算当前需要显示的数据下标起始值 +// //int startIndex = (pageNum - 1) * pageSize; +// //int endIndex = Math.min(startIndex + pageSize,total); +// ////从链表中截取需要显示的子链表,并加入到Page +// //page.addAll(history.subList(startIndex,endIndex)); +// ////以Page创建PageInfo +// //PageInfo pageInfo = new PageInfo<>(page); +// //return AjaxResult.success().put("data",pageInfo); +// +// //java8 stream实现list分页 +// +// List pageList = history.stream().sorted().skip((pageNum - 1) * pageSize) +// .limit(pageSize) +// .collect(Collectors.toList()); +// PageInfo pageInfo = new PageInfo(pageList); +// //获取PageInfo其他参数 +// pageInfo.setTotal(history.size()); +// +// int endRow = pageInfo.getEndRow() == 0 ? 0 : (int)((pageNum - 1) * pageSize + pageInfo.getEndRow() + 1); +// pageInfo.setEndRow(endRow); +// boolean hasNextPage = history.size() <= pageSize * pageNum ? false : true; +// pageInfo.setHasNextPage(hasNextPage); +// boolean hasPreviousPage = pageNum == 1 ? false : true; +// pageInfo.setHasPreviousPage(hasPreviousPage); +// pageInfo.setIsFirstPage(!hasPreviousPage); +// boolean isLastPage = (history.size() > pageSize * (pageNum - 1) && history.size() <= pageSize * pageNum) ? true : false; +// pageInfo.setIsLastPage(isLastPage); +// int pages = history.size() % pageSize == 0 ? history.size() / pageSize : (history.size() / pageSize) + 1; +// pageInfo.setNavigateLastPage(pages); +// int[] navigatePageNums = new int[pages]; +// for (int i = 1; i < pages; i++) { +// navigatePageNums[i - 1] = i; +// } +// pageInfo.setNavigatepageNums(navigatePageNums); +// int nextPage = pageNum < pages ? pageNum + 1 : 0; +// pageInfo.setNextPage(nextPage); +// pageInfo.setPageNum(pageNum); +// pageInfo.setPageSize(pageSize); +// pageInfo.setPages(pages); +// pageInfo.setPrePage(pageNum - 1); +// pageInfo.setSize(pageInfo.getList().size()); +// int starRow = history.size() < pageSize * pageNum ? 1 + pageSize * (pageNum - 1) : 0; +// pageInfo.setStartRow(starRow); +// return AjaxResult.success().put("data", pageInfo); +// +// }catch (Exception e){ +// return AjaxResult.error("获取对话历史异常!"); +// } +// } +// +// /** 最后一页页数 +// * +// * @param pageNum +// * @param pageSize +// * @param userId +// * @return +// */ +// @GetMapping("/getLastNum") +// public AjaxResult getLastNum(@RequestParam(defaultValue = "1") Integer pageNum, +// @RequestParam(defaultValue = "10") Integer pageSize, +// @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){ +// try { +// MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); +// if (memberUser == null) { +// return AjaxResult.error("用户信息异常!!!"); +// } +// SaveChatRequestMessage requestBody = new SaveChatRequestMessage(); +// List history = new ArrayList<>(); +// //有历史消息 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); +// System.out.println("json:"+json); +// requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class); +// if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){ +// history = requestBody.getSaveMessageList(); +// } +// int total = history.size(); +// int num = total/pageSize; +// int remain = total%pageSize; +// if(num == 0 && remain > 0){ +// return AjaxResult.success().put("lastPage",1); +// } else if(num > 0 && remain > 0) { +// return AjaxResult.success().put("lastPage",num+1); +// }else if(num > 0 && remain == 0) { +// return AjaxResult.success().put("lastPage",num); +// }else{ +// return AjaxResult.success().put("lastPage",0); +// } +// }else{ +// return AjaxResult.success().put("lastPage",0); +// } +// +// +// }catch (Exception e){ +// return AjaxResult.error("获取最后页数异常!"); +// } +// } +// +// +// /** +// * 调用知识库 +// */ +// @PostMapping("/chatNew") +// @org.springframework.web.bind.annotation.ResponseBody +// public AjaxResult newChat(@org.springframework.web.bind.annotation.RequestBody Map params){ +// //对用户问题的判断 +// if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { +// return AjaxResult.error("缺少问题"); +// } +// if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { +// return AjaxResult.error("缺少用户id"); +// } +// if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){ +// return AjaxResult.error("缺少语音状态"); +// } +// long userId = Long.parseLong(params.get("userId").toString()); +// // 是否有语音0-没有,1-有 +// Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString()); +// +// MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); +// if (memberUser == null) { +// return AjaxResult.error("用户信息异常!!!"); +// } +// +// String question = params.get("question").toString(); +// //通过参数获取一个Message +// Message message = new Message("user",question); +// // 创建存储用saveMessage +// SaveMessage saveMessage = new SaveMessage(); +// saveMessage.setRole("user"); +// saveMessage.setContent(question); +// saveMessage.setHasVoice(hasVoice); +// if (hasVoice == 1){ +// saveMessage.setVoiceUrl(params.get("voiceUrl").toString()); +// } +// +// com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); +// jsonObject.put("query", question); +// List plugins = new ArrayList<>(); +// plugins.add("uuid-zhishiku"); +// //plugins.add("uuid-weatherforecast"); +// //jsonObject.put("plugins", plugins); +// //jsonObject.put("verbose", false); +// +// +// // 创建存储类 +// SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage(); +// ArrayList historyList = new ArrayList<>(); +// // 查询是否有记录 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); +// saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class); +// // 记录信息复制到请求参数中 +// List saveMessageList = saveChatRequestMessage.getSaveMessageList(); +// +// if (!saveMessageList.isEmpty()){ +// List shortList = new ArrayList<>(); +// int size = saveMessageList.size(); +// if ( size >= 2){ +// shortList.add(saveMessageList.get(size - 2)); +// shortList.add(saveMessageList.get(size - 1)); +// for (SaveMessage saveMessageHistory : shortList) { +// Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class); +// historyList.add(m); +// } +// } +// +// } +// } +// //将新的问题添加到消息上下文 +// //jsonObject.put("history", historyList); +// // 新信息添加保存 +// saveChatRequestMessage.addSaveMessage(saveMessage); +// +// String jsonStr = jsonObject.toJSONString(); +// MediaType mediaType = MediaType.parse("application/json"); +// RequestBody body = RequestBody.create(mediaType, jsonStr); +// Request request = new Request.Builder() +// // .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v2/wenxinworkshop/plugin/jfa2nhi1zap61qy7?access_token="+getQianFanAccessToken()) +// .url("https://qianfan.baidubce.com/v2/chat/completions") +// .method("POST", body) +// .addHeader("Content-Type", "application/json") +// .addHeader("Authorization", "Bearer " + getQianFanAccessToken()) +// .build(); +// try{ +// logger.info("千帆AccessToken:{}",getQianFanAccessToken()); +// Response response = client.newCall(request).execute(); +// String responseJsonStr = response.body().string(); +// +// com.alibaba.fastjson.JSONObject data = JSONUtil.toBean(responseJsonStr, com.alibaba.fastjson.JSONObject.class); +// System.out.println("返回的响应结果为:"+responseJsonStr); +// System.out.println("data:"+data); +// System.out.println("result:"+data.getString("result")); +// System.out.println("response:"+response); +// String result = data.getString("result"); +// if (StringUtils.isNotBlank(result)){ +// String answer = result.replaceAll("\n", ""); +// +// //int i = answer.indexOf("\n"); +// Message assistant = new Message("assistant", answer); +// //if (i> 0){ +// // assistant.setContent(answer.substring(0,i)); +// //} +// +// +// // 存储信息 +// SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class); +// saveAnswer.setHasVoice(hasVoice); +// +// saveChatRequestMessage.addSaveMessage(saveAnswer); +// +// //redis 存储 +// if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ +// Long expire = redisTemplate.getExpire("ChatWith" + memberUser.getId()); +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); +// }else{ +// redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); +// } +// logger.info("存入redis:" +redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); +// List newChat = new ArrayList<>(); +// newChat.add(saveMessage); +// newChat.add(saveAnswer); +// +// return AjaxResult.success(newChat); +// }else{ +// logger.error("对话返回结果为空"); +// return AjaxResult.error("对话失败!"); +// } +// +// }catch (Exception e){ +// e.printStackTrace(); +// return AjaxResult.error("对话失败!"); +// } +// +// } +// +// } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatNewController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatNewController.java new file mode 100644 index 0000000..cd7f5ce --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ApiChatNewController.java @@ -0,0 +1,309 @@ +package com.ruoyi.web.controller.api; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.pagehelper.PageInfo; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.mall.domain.Bo.SaveChatRequestMessage; +import com.ruoyi.mall.domain.Bo.SaveMessage; +import com.ruoyi.mall.domain.Chat.*; +import com.ruoyi.mall.domain.MallMemberUser; +import com.ruoyi.mall.service.IMallMemberUserService; +import okhttp3.RequestBody; +import okhttp3.*; +import org.apache.commons.lang3.ObjectUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @ClassName 智能对话接口 + * @Description 智能对话接口 + * @Author LHY + * @Date 2023/10/18 + * @Version 1.0 + **/ +@RestController +@RequestMapping("/api/chat") +public class ApiChatNewController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Resource + private RedisTemplate redisTemplate; + @Resource + private IMallMemberUserService mallMemberUserService; + + @Value("${baidu.appKey}") + private String appKey; + @Value("${baidu.appId}") + private String appId; + + // 读取超时为60s + private static final long READ_TIMEOUT = 60000; + // 写入超时为60s + private static final long WRITE_TIMEOUT = 60000; + // 连接超时为60s + private static final long CONNECT_TIMEOUT = 60000; + + private static final long CALL_TIMEOUT = 60000; + + private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder() + // 设置调用超时时间 + .callTimeout(CALL_TIMEOUT, TimeUnit.MILLISECONDS) + // 设置读取超时时间 + .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS) + // 设置写超时时间 + .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS) + // 设置连接超时时间 + .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS) + .build(); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + + // 本次对话ID + private String conversation_id; + + /**对话历史-近到远—分页 + * + * @param userId 当前对话用户id + * @return + */ + @GetMapping("/getChatHistory") + public AjaxResult getChatHistory(@RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "10") Integer pageSize, + @NotNull(message = "Chat.getChatHistory.userId.isNull") Long userId){ + try { + MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); + if (memberUser == null) { + return AjaxResult.error("用户信息异常!!!"); + } + SaveChatRequestMessage requestBody = new SaveChatRequestMessage(); + List history = new ArrayList<>(); + //有历史消息 + if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ + String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); + System.out.println("json:"+json); + requestBody = JSONUtil.toBean(json, SaveChatRequestMessage.class); + if(null != requestBody.getSaveMessageList() && requestBody.getSaveMessageList().size()>0){ + history = requestBody.getSaveMessageList(); + Collections.reverse(history); + } + } + List pageList = history.stream().sorted().skip((pageNum - 1) * pageSize) + .limit(pageSize) + .collect(Collectors.toList()); + PageInfo pageInfo = new PageInfo(pageList); + //获取PageInfo其他参数 + pageInfo.setTotal(history.size()); + + int endRow = pageInfo.getEndRow() == 0 ? 0 : (int)((pageNum - 1) * pageSize + pageInfo.getEndRow() + 1); + pageInfo.setEndRow(endRow); + boolean hasNextPage = history.size() <= pageSize * pageNum ? false : true; + pageInfo.setHasNextPage(hasNextPage); + boolean hasPreviousPage = pageNum == 1 ? false : true; + pageInfo.setHasPreviousPage(hasPreviousPage); + pageInfo.setIsFirstPage(!hasPreviousPage); + boolean isLastPage = (history.size() > pageSize * (pageNum - 1) && history.size() <= pageSize * pageNum) ? true : false; + pageInfo.setIsLastPage(isLastPage); + int pages = history.size() % pageSize == 0 ? history.size() / pageSize : (history.size() / pageSize) + 1; + pageInfo.setNavigateLastPage(pages); + int[] navigatePageNums = new int[pages]; + for (int i = 1; i < pages; i++) { + navigatePageNums[i - 1] = i; + } + pageInfo.setNavigatepageNums(navigatePageNums); + int nextPage = pageNum < pages ? pageNum + 1 : 0; + pageInfo.setNextPage(nextPage); + pageInfo.setPageNum(pageNum); + pageInfo.setPageSize(pageSize); + pageInfo.setPages(pages); + pageInfo.setPrePage(pageNum - 1); + pageInfo.setSize(pageInfo.getList().size()); + int starRow = history.size() < pageSize * pageNum ? 1 + pageSize * (pageNum - 1) : 0; + pageInfo.setStartRow(starRow); + return AjaxResult.success().put("data", pageInfo); + + }catch (Exception e){ + return AjaxResult.error("获取对话历史异常!"); + } + } + + /** + * 调用知识库 + */ + @PostMapping("/chatNew") + @org.springframework.web.bind.annotation.ResponseBody + public AjaxResult newChat(@org.springframework.web.bind.annotation.RequestBody Map params){ + //对用户问题的判断 + if (!params.containsKey("question") || StringUtils.isEmpty(params.get("question").toString())) { + return AjaxResult.error("缺少问题"); + } + if (!params.containsKey("userId") || StringUtils.isEmpty(params.get("userId").toString())) { + return AjaxResult.error("缺少用户id"); + } + if (!params.containsKey("hasVoice") || ObjectUtils.isEmpty(Integer.valueOf(params.get("hasVoice").toString()))){ + return AjaxResult.error("缺少语音状态"); + } + long userId = Long.parseLong(params.get("userId").toString()); + // 是否有语音0-没有,1-有 + Integer hasVoice = Integer.valueOf(params.get("hasVoice").toString()); + + MallMemberUser memberUser = mallMemberUserService.selectMallMemberUserById(userId); + if (memberUser == null) { + return AjaxResult.error("用户信息异常!!!"); + } + + String question = params.get("question").toString(); + // 创建存储用saveMessage + SaveMessage saveMessage = new SaveMessage(); + saveMessage.setRole("user"); + saveMessage.setContent(question); + saveMessage.setHasVoice(hasVoice); + if (hasVoice == 1){ + saveMessage.setVoiceUrl(params.get("voiceUrl").toString()); + } + + com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject(); + jsonObject.put("query", question); + List plugins = new ArrayList<>(); + plugins.add("uuid-zhishiku"); + //plugins.add("uuid-weatherforecast"); + //jsonObject.put("plugins", plugins); + //jsonObject.put("verbose", false); + + + // 创建存储类 + SaveChatRequestMessage saveChatRequestMessage = new SaveChatRequestMessage(); + ArrayList historyList = new ArrayList<>(); + // 查询是否有记录 + if(redisTemplate.hasKey("ChatWith" + memberUser.getId())){ + String json = redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString(); + saveChatRequestMessage = JSONUtil.toBean(json, SaveChatRequestMessage.class); + // 记录信息复制到请求参数中 + List saveMessageList = saveChatRequestMessage.getSaveMessageList(); + + if (!saveMessageList.isEmpty()){ + List shortList = new ArrayList<>(); + int size = saveMessageList.size(); + if ( size >= 2){ + shortList.add(saveMessageList.get(size - 2)); + shortList.add(saveMessageList.get(size - 1)); + for (SaveMessage saveMessageHistory : shortList) { + Message m = BeanUtil.copyProperties(saveMessageHistory, Message.class); + historyList.add(m); + } + } + + } + } + //将新的问题添加到消息上下文 + jsonObject.put("history", historyList); + // 新信息添加保存 + saveChatRequestMessage.addSaveMessage(saveMessage); + try { + BaiduAppResponse qaq = qaq(question,memberUser); + if (StringUtils.isNotBlank(qaq.getAnswer())) { + Message assistant = new Message("assistant", qaq.getAnswer()); + // // 存储信息 + SaveMessage saveAnswer = BeanUtil.copyProperties(assistant, SaveMessage.class); + saveAnswer.setHasVoice(hasVoice); + + saveChatRequestMessage.addSaveMessage(saveAnswer); + + // redis 存储 + if (redisTemplate.hasKey("ChatWith" + memberUser.getId())) { + redisTemplate.getExpire("ChatWith" + memberUser.getId()); + redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); + } else { + redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).set(JSONUtil.toJsonStr(saveChatRequestMessage), 30, TimeUnit.DAYS); + } + logger.info("存入redis:" + redisTemplate.boundValueOps("ChatWith" + memberUser.getId()).get().toString()); + List newChat = new ArrayList<>(); + newChat.add(saveMessage); + newChat.add(saveAnswer); + return AjaxResult.success(newChat); + } else { + logger.error("对话返回结果为空"); + return AjaxResult.error("对话失败!"); + } + + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("对话失败!"); + } + + } + + /** + * 提问且获取消息 + */ + public BaiduAppResponse qaq(String question,MallMemberUser memberUser) throws Exception { + // 没有创建回话则创建。 + if (conversation_id == null || "".equals(conversation_id)) { + createConversation(memberUser.getId()); + } + // 提问 + logger.info("提问千帆App:" + question); + MediaType mediaType = MediaType.parse("application/json"); + // 消息体 + String json = objectMapper.writeValueAsString(new BaiduAppRequest(appId, question, conversation_id)); + RequestBody body = RequestBody.create(mediaType, json); + // 请求 + Request request = new Request.Builder() + .url("https://qianfan.baidubce.com/v2/app/conversation/runs") + .method("POST", body) + .addHeader("Content-Type", "application/json") + .addHeader("X-Appbuilder-Authorization", "Bearer " + appKey) + .build(); + Response response = HTTP_CLIENT.newCall(request).execute(); + // 获取消息 + String res = response.body().string(); + logger.info("HTTP请求千帆App回复:" + res); + BaiduAppResponse baiduAppResponse = objectMapper.readValue(res, BaiduAppResponse.class); + logger.info("千帆App回复对象:" + JSONUtil.toJsonStr(baiduAppResponse)); + logger.info("千帆App回复:" + baiduAppResponse.getAnswer()); + return baiduAppResponse; + } + + /** + * 创建和百度千帆AppBuilder的对话 + */ + private void createConversation(Long userId) throws IOException { + + Object object = redisTemplate.boundValueOps("conversation_id_" + userId).get(); + if (ObjectUtils.isNotEmpty(object)){ + conversation_id = object.toString(); + }else { + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, "{\"appId\":\"" + appId + "\"}"); + Request request = new Request.Builder() + .url("https://qianfan.baidubce.com/v2/app/conversation") + .method("POST", body) + .addHeader("Content-Type", "application/json") + .addHeader("X-Appbuilder-Authorization", "Bearer " + appKey) + .build(); + Response response = HTTP_CLIENT.newCall(request).execute(); + String res = response.body().string(); + logger.info("百度千帆AppBuilder 创建对话响应:" + res); + conversation_id = objectMapper.readTree(res).get("conversation_id").asText(); + } + redisTemplate.boundValueOps("conversation_id_" + userId).set(conversation_id, 30, TimeUnit.DAYS); + } + +} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 84a09a1..937c520 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -142,3 +142,7 @@ qiNiu: secretKey: tWJjsaYPBBACuyw8CfaF9h2BRUziuje_zwrz4GyE bucketName: xiaoniu666666 baseUrl: https://image.xnszz.com/ + +baidu: + appId: a7234eb3-fc6b-4e8a-baae-e7f2df86a1f3 + appKey: bce-v3/ALTAK-SJq4Dnyo31QJlajmyMT40/d806d48c7b7f2ec9675c7cbf2171e6dd0676b274 \ No newline at end of file diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml index 2f419a4..4950795 100644 --- a/ruoyi-system/pom.xml +++ b/ruoyi-system/pom.xml @@ -22,7 +22,13 @@ com.ruoyi ruoyi-common - + + + org.projectlombok + lombok + 1.18.4 + provided + diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppRequest.java b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppRequest.java new file mode 100644 index 0000000..1aceb74 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppRequest.java @@ -0,0 +1,66 @@ +package com.ruoyi.mall.domain.Chat; + +import lombok.Data; + +/** + * 请求体 用于请求百度千帆 + */ +public class BaiduAppRequest { + + private String app_id; + + private String query; + + private boolean stream; + + private String conversation_id; + + public BaiduAppRequest(String app_id, String query, String conversation_id) { + this.app_id = app_id; + this.query = query; + this.conversation_id = conversation_id; + } + + public String getApp_id() { + return app_id; + } + + public void setApp_id(String app_id) { + this.app_id = app_id; + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public boolean isStream() { + return stream; + } + + public void setStream(boolean stream) { + this.stream = stream; + } + + public String getConversation_id() { + return conversation_id; + } + + public void setConversation_id(String conversation_id) { + this.conversation_id = conversation_id; + } + + @Override + public String toString() { + return "BaiduAppRequest{" + + "app_id='" + app_id + '\'' + + ", query='" + query + '\'' + + ", stream=" + stream + + ", conversation_id='" + conversation_id + '\'' + + '}'; + } +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppResponse.java b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppResponse.java new file mode 100644 index 0000000..74b01bf --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/mall/domain/Chat/BaiduAppResponse.java @@ -0,0 +1,97 @@ +package com.ruoyi.mall.domain.Chat; + +import lombok.Data; + +import java.util.List; + + +/** + * 响应体 接收消息用 + */ + +public class BaiduAppResponse { + + private String request_id; + + private String date; + + private String answer; + + private String conversation_id; + + private String message_id; + + private Boolean is_completion; + + private List content; + + public String getRequest_id() { + return request_id; + } + + public void setRequest_id(String request_id) { + this.request_id = request_id; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + + public String getConversation_id() { + return conversation_id; + } + + public void setConversation_id(String conversation_id) { + this.conversation_id = conversation_id; + } + + public String getMessage_id() { + return message_id; + } + + public void setMessage_id(String message_id) { + this.message_id = message_id; + } + + public Boolean getIs_completion() { + return is_completion; + } + + public void setIs_completion(Boolean is_completion) { + this.is_completion = is_completion; + } + + public List getContent() { + return content; + } + + public void setContent(List content) { + this.content = content; + } + + @Override + public String toString() { + return "BaiduAppResponse{" + + "request_id='" + request_id + '\'' + + ", date='" + date + '\'' + + ", answer='" + answer + '\'' + + ", conversation_id='" + conversation_id + '\'' + + ", message_id='" + message_id + '\'' + + ", is_completion=" + is_completion + + ", content=" + content + + '}'; + } +} + -- 2.22.0