当前位置:   article > 正文

SpringBoot调用ChatGPT-API实现智能对话

springboot调用chatgpt

目录

一、说明

二、代码

2.1、对话测试

2.2、单次对话

2.3、连续对话

2.4、AI绘画


一、说明

我们在登录chatgpt官网进行对话是不收费的,但需要魔法。在调用官网的API时,在代码层面上使用,通过API KEY进行对话是收费的,不过刚注册的小伙伴有免费5美金的体验额度,在不调用绘画模型,只是做为简单的问答,个人使用是没问题的。

ChatGPT官网

API使用情况

二、代码

2.1、对话测试

Gpt35TurboVO

  1. import lombok.Data;
  2. @Data
  3. public class Gpt35TurboVO {
  4. private String role; // 角色一般为 user
  5. private String content; // 询问内容
  6. }

Controller

  1. @GetMapping(value = "/test", produces = "text/event-stream;charset=UTF-8")
  2. public String test(@RequestParam String message) {
  3. //回复用户
  4. String apikey = "sk-****";
  5. //请求ChatGPT的URL
  6. String url = "https://api.openai.com/v1/chat/completions";
  7. Gpt35TurboVO gpt35TurboVO = new Gpt35TurboVO();
  8. gpt35TurboVO.setRole("user");
  9. gpt35TurboVO.setContent(message);
  10. List<Gpt35TurboVO> objects = new ArrayList<>();
  11. objects.add(gpt35TurboVO);
  12. Map<Object, Object> objectObjectHashMap = new HashMap<>();
  13. objectObjectHashMap.put("model", "gpt-3.5-turbo"); //使用的模型
  14. objectObjectHashMap.put("messages", objects); //提问信息
  15. objectObjectHashMap.put("stream", false); //流
  16. objectObjectHashMap.put("temperature", 0); //GPT回答温度(随机因子)
  17. objectObjectHashMap.put("frequency_penalty", 0); //重复度惩罚因子
  18. objectObjectHashMap.put("presence_penalty", 0.6); //控制主题的重复度
  19. String postData = JSONUtil.toJsonStr(objectObjectHashMap);
  20. String result2 = HttpRequest.post(url)
  21. .header("Authorization", "Bearer " + apikey)//头信息,多个头信息多次调用此方法即可
  22. .header("Content-Type", "application/json")
  23. .body(postData)//表单内容
  24. .timeout(200000)//超时,毫秒
  25. .execute().body();
  26. System.out.println(result2);
  27. return result2;
  28. }

返回结果

2.2、单次对话

ChatBotSingleQuestionVO

  1. import lombok.Data;
  2. /**
  3. * 应用管理-单次提问-VO
  4. * @author lf
  5. * @date 2023/8/18
  6. */
  7. @Data
  8. public class ChatBotSingleQuestionVO {
  9. /**
  10. * 用户输入的询问内容
  11. */
  12. private String prompt;
  13. /**
  14. * 角色扮演ID
  15. */
  16. private Integer rolePlayId;
  17. }

Redis锁工具类

  1. import org.redisson.api.RLock;
  2. import org.redisson.api.RedissonClient;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Component;
  5. import java.util.concurrent.TimeUnit;
  6. /**
  7. * redis锁工具类
  8. *
  9. * @author ruoyi
  10. */
  11. @Component
  12. public class RedisLock {
  13. @Autowired
  14. private RedissonClient redissonClient;
  15. /**
  16. * 获取锁
  17. *
  18. * @param lockKey 锁实例key
  19. * @return 锁信息
  20. */
  21. public RLock getRLock(String lockKey) {
  22. return redissonClient.getLock(lockKey);
  23. }
  24. /**
  25. * 加锁
  26. *
  27. * @param lockKey 锁实例key
  28. * @return 锁信息
  29. */
  30. public RLock lock(String lockKey) {
  31. RLock lock = getRLock(lockKey);
  32. lock.lock();
  33. return lock;
  34. }
  35. /**
  36. * 加锁
  37. *
  38. * @param lockKey 锁实例key
  39. * @param leaseTime 上锁后自动释放锁时间
  40. * @return true=成功;false=失败
  41. */
  42. public Boolean tryLock(String lockKey, long leaseTime) {
  43. return tryLock(lockKey, 0, leaseTime, TimeUnit.SECONDS);
  44. }
  45. /**
  46. * 加锁
  47. *
  48. * @param lockKey 锁实例key
  49. * @param leaseTime 上锁后自动释放锁时间
  50. * @param unit 时间颗粒度
  51. * @return true=加锁成功;false=加锁失败
  52. */
  53. public Boolean tryLock(String lockKey, long leaseTime, TimeUnit unit) {
  54. return tryLock(lockKey, 0, leaseTime, unit);
  55. }
  56. /**
  57. * 加锁
  58. *
  59. * @param lockKey 锁实例key
  60. * @param waitTime 最多等待时间
  61. * @param leaseTime 上锁后自动释放锁时间
  62. * @param unit 时间颗粒度
  63. * @return true=加锁成功;false=加锁失败
  64. */
  65. public Boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
  66. RLock rLock = getRLock(lockKey);
  67. boolean tryLock = false;
  68. try {
  69. tryLock = rLock.tryLock(waitTime, leaseTime, unit);
  70. } catch (InterruptedException e) {
  71. return false;
  72. }
  73. return tryLock;
  74. }
  75. /**
  76. * 释放锁
  77. *
  78. * @param lockKey 锁实例key
  79. */
  80. public void unlock(String lockKey) {
  81. RLock lock = getRLock(lockKey);
  82. lock.unlock();
  83. }
  84. /**
  85. * 释放锁
  86. *
  87. * @param lock 锁信息
  88. */
  89. public void unlock(RLock lock) {
  90. lock.unlock();
  91. }
  92. }

Controller

  1. @PostMapping("/chatBotSingleQuestion/api")
  2. public AjaxResult chatBotSingleQuestion(@RequestBody ChatBotSingleQuestionVO chatBotSingleQuestionVO) {
  3. String answerContent = iChatBotSingleQuestionService.chatBotSingleQuestion(chatBotSingleQuestionVO);
  4. return success("success", answerContent);
  5. }

Impl

  1. /**
  2. * 应用管理-用户单次提问-不支持续问对话
  3. * @param chatBotSingleQuestionVO
  4. * @return
  5. */
  6. @Override
  7. @Transactional
  8. public String chatBotSingleQuestion(ChatBotSingleQuestionVO chatBotSingleQuestionVO) {
  9. if (Objects.isNull(chatBotSingleQuestionVO.getRolePlayId())){
  10. throw new RuntimeException("参数不可为空");
  11. }
  12. String lockName = "QA_" + SecurityUtils.getUserId();
  13. //回答的内容
  14. String answerContent = "";
  15. try{
  16. RLock rLock = redisLock.getRLock(lockName);
  17. boolean locked = rLock.isLocked();
  18. if (locked) {
  19. throw new RuntimeException("正在回复中...");
  20. }
  21. //对同一用户访问加锁
  22. redisLock.lock(lockName);
  23. this.chatBefore(chatBotSingleQuestionVO);
  24. InputStream is = this.sendRequestBeforeChat(chatBotSingleQuestionVO);
  25. String line = "";
  26. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  27. while ((line = reader.readLine()) != null) {
  28. //首先对行数据进行处理
  29. if (StrUtil.isNotBlank(line) &&
  30. !StrUtil.equals(line, "event: answer") &&
  31. !StrUtil.equals(line, "event: chatResponse") &&
  32. !StrUtil.contains(line, "data: {\"quoteLen\"")) {
  33. line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);
  34. if (!StrUtil.contains(line, "[DONE]")) {
  35. String oneWord = catchTextGpt(line);
  36. if (StrUtil.isNotBlank(oneWord)) {
  37. answerContent = answerContent + oneWord;
  38. }
  39. }
  40. WebSocketService.sendInfo(line, SecurityUtils.getUserId() + "");
  41. TimeUnit.MILLISECONDS.sleep(50);
  42. }
  43. }
  44. //处理完了后将次条聊天记录进行记录
  45. if (StrUtil.isNotBlank(answerContent)) {
  46. //保存聊天记录
  47. this.saveDialogueProcess(chatBotSingleQuestionVO, answerContent);
  48. //更新提问次数
  49. this.upddateAppModel(chatBotSingleQuestionVO);
  50. }
  51. is.close();
  52. reader.close();
  53. } catch (Exception e) {
  54. throw new RuntimeException(e.getMessage());
  55. }finally {
  56. redisLock.unlock(lockName);
  57. }
  58. return answerContent;
  59. }

sendRequestBeforeChat方法

  1. /**
  2. * 这块为问询,不包含对话模式
  3. *
  4. * @param chatBotSingleQuestionVO
  5. * @return
  6. * @throws Exception
  7. */
  8. @Transactional
  9. public InputStream sendRequestBeforeChat(ChatBotSingleQuestionVO chatBotSingleQuestionVO) throws Exception {
  10. InputStream in = null;
  11. // 通知内容添加文本铭感词汇过滤
  12. //其余错误见返回码说明
  13. //正常返回0
  14. //违禁词检测
  15. this.disableWordCheck(chatBotSingleQuestionVO.getPrompt());
  16. String apikeyRefresh = getOpenAiKey();
  17. if (StrUtil.isBlank(apikeyRefresh)) {
  18. throw new RuntimeException("无可用key");
  19. }
  20. List<Gpt35TurboVO> chatContext = this.getChatContext(chatBotSingleQuestionVO);
  21. String requestUrl = iTbKeyManagerService.getproxyUrl();
  22. Map<Object, Object> objectObjectHashMap = new HashMap<>();
  23. objectObjectHashMap.put("model", "gpt-3.5-turbo");
  24. objectObjectHashMap.put("messages", chatContext);
  25. objectObjectHashMap.put("stream", true);
  26. objectObjectHashMap.put("temperature", 0);
  27. objectObjectHashMap.put("frequency_penalty", 0);
  28. objectObjectHashMap.put("presence_penalty", 0.6);
  29. String bodyJson = JSONUtil.toJsonStr(objectObjectHashMap);
  30. URL url = new URL(requestUrl); // 接口地址
  31. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
  32. urlConnection.setRequestMethod("POST");
  33. urlConnection.setDoOutput(true);
  34. urlConnection.setDoInput(true);
  35. urlConnection.setUseCaches(false);
  36. urlConnection.setRequestProperty("Connection", "Keep-Alive");
  37. urlConnection.setRequestProperty("Charset", "UTF-8");
  38. urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
  39. urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
  40. byte[] dataBytes = bodyJson.getBytes();
  41. urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
  42. OutputStream os = urlConnection.getOutputStream();
  43. os.write(dataBytes);
  44. in = new BufferedInputStream(urlConnection.getInputStream());
  45. os.flush();
  46. os.close();
  47. return in;
  48. }

catchTextGpt方法

  1. /**
  2. * 处理单独打印的文字
  3. *
  4. * @param str
  5. * @return
  6. */
  7. public String catchTextGpt(String str) {
  8. String choices = JsonUtil.parseMiddleData(str, "choices");
  9. JSONArray jsonArray = JSONUtil.parseArray(choices);
  10. String string = jsonArray.getByPath("[0].delta").toString();
  11. String content = JsonUtil.parseMiddleData(string, "content");
  12. return content;
  13. }

getChatContext方法

  1. /**
  2. * 角色扮演
  3. * @param chatBotSingleQuestionVO
  4. * @return 结果
  5. */
  6. public List<Gpt35TurboVO> getChatContext(ChatBotSingleQuestionVO chatBotSingleQuestionVO) {
  7. List<Gpt35TurboVO> messages = new ArrayList<>();
  8. //首先获取角色,设置默认角色
  9. String default_role_content = iconfigService.selectConfigByKey("default_role");
  10. if (StrUtil.isBlank(default_role_content)) {
  11. default_role_content = "我是一个全能机器人,可以回答你任何问题";
  12. }
  13. TbAppModel tbAppModel = iTbAppModelService.selectTbAppModelById(Long.valueOf(chatBotSingleQuestionVO.getRolePlayId()));
  14. if (!Objects.isNull(tbAppModel)){
  15. default_role_content = tbAppModel.getAppModelContent();
  16. }
  17. //小程序专用
  18. //是否通过微信小程序审核的设定语
  19. String is_open_pass_wx_promt = iconfigService.selectConfigByKey("is_open_pass_wx_promt");
  20. if (StrUtil.isNotBlank(is_open_pass_wx_promt) && !StrUtil.equals(is_open_pass_wx_promt, "0")) {
  21. String pass_wx_promt = iconfigService.selectConfigByKey("pass_wx_promt");
  22. default_role_content = default_role_content + "。并且你必须遵循:" + pass_wx_promt;
  23. }
  24. //设定系统所扮演的角色
  25. Gpt35TurboVO gpt35TurboVOSys = new Gpt35TurboVO();
  26. gpt35TurboVOSys.setRole("system");
  27. gpt35TurboVOSys.setContent(default_role_content);
  28. messages.add(gpt35TurboVOSys);
  29. //最后查询用户最新询问的问题
  30. Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
  31. gpt35TurboUser.setRole("user");
  32. gpt35TurboUser.setContent(chatBotSingleQuestionVO.getPrompt());
  33. messages.add(gpt35TurboUser);
  34. return messages;
  35. }

getOpenAiKey方法

  1. /**
  2. * 查询key是否可用
  3. * @return 结果
  4. */
  5. public String getOpenAiKey() {
  6. //模仿查到的key集合
  7. TbKeyManager tbKeyManager = new TbKeyManager();
  8. tbKeyManager.setIsUse(1);
  9. //可用的key
  10. List<TbKeyManager> tbKeyManagers = iTbKeyManagerService.selectTbKeyManagerList(tbKeyManager);
  11. //判断是否key额度用完
  12. if (CollectionUtil.isEmpty(tbKeyManagers) || tbKeyManagers.size() <= 0) {
  13. throw new RuntimeException("key额度耗尽");
  14. }
  15. //获取第一个key,然后将第一个key存入缓存
  16. String key = tbKeyManagers.get(0).getSecretKey();
  17. redisTemplate.opsForValue().set("apikey", key);
  18. //检查key
  19. changeKey(tbKeyManagers.get(0));
  20. return key;
  21. }

2.3、连续对话

Controller

  1. @PostMapping(value = "/chatBotNoId/api")
  2. public AjaxResult continuousDialogue(@RequestBody StreamParametersVO streamParametersVO) {
  3. String answerContent = iChatGtpService.continuousDialogueSocketStream(streamParametersVO);
  4. return success("success", answerContent);
  5. }

Impl

  1. /**
  2. * 用户直接发起连续对话,系统同意创建对话主题,用户不用手动新建主题
  3. *
  4. * @param streamParametersVO
  5. */
  6. @Override
  7. public String continuousDialogueSocketStream(StreamParametersVO streamParametersVO) {
  8. //判断是否isNewOpen填写参数,表示是否先开对话
  9. if (Objects.isNull(streamParametersVO.getIsNewOpen())) {
  10. throw new RuntimeException("isNewOpen参数未填");
  11. }
  12. if (streamParametersVO.getIsNewOpen()) {
  13. //新开对话,创建新的对话主题
  14. tbModelTable = new TbModelTable();
  15. //主题名称
  16. tbModelTable.setModelName("Dialogue_" + SecurityUtils.getUserId() + "_" + DateTime.now());
  17. //设置模板角色
  18. if (Objects.nonNull(streamParametersVO.getDialogueRoleId())) {
  19. tbModelTable.setId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
  20. } else {
  21. tbModelTable.setId(1L);
  22. }
  23. tbDialogueMain = tbDialogueMainService.creatNewDig(tbModelTable);
  24. } else {
  25. //非新开对话,查询本次的对话主题
  26. TbDialogueMain tbDialogueMainParam = new TbDialogueMain();
  27. //设置模板角色
  28. if (Objects.nonNull(streamParametersVO.getDialogueRoleId())) {
  29. tbDialogueMainParam.setDialogueRoleId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
  30. } else {
  31. tbDialogueMainParam.setDialogueRoleId(1L);
  32. }
  33. tbDialogueMainParam.setUserId(SecurityUtils.getUserId());
  34. List<TbDialogueMain> tbDialogueMains = iTbDialogueMainService.selectTbDialogueMainList(tbDialogueMainParam);
  35. if (CollectionUtil.isEmpty(tbDialogueMains)) {
  36. //创建新的对话主题
  37. tbModelTable = new TbModelTable();
  38. //主题名称
  39. tbModelTable.setModelName("Dialogue_" + SecurityUtils.getUserId() + "_" + DateTime.now());
  40. //设置模板角色
  41. tbModelTable.setId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
  42. tbDialogueMain = tbDialogueMainService.creatNewDig(tbModelTable);
  43. } else {
  44. tbDialogueMain = tbDialogueMains.get(0);
  45. }
  46. }
  47. //设置对话ID
  48. streamParametersVO.setDialogueId(tbDialogueMain.getId());
  49. String lockName = "chat_" + SecurityUtils.getUserId();
  50. //回答的内容
  51. String answerContent = "";
  52. try {
  53. RLock rLock = redisLock.getRLock(lockName);
  54. boolean locked = rLock.isLocked();
  55. if (locked) {
  56. throw new RuntimeException("正在回复中...");
  57. }
  58. //对同一用户访问加锁
  59. redisLock.lock(lockName);
  60. //进来做校验
  61. TbDialogueMain tbDialogueMain = this.paramVerify(streamParametersVO);
  62. String userId = SecurityUtils.getUserId() + "";
  63. //将提问数据封装为流,并请求OpenAI的接口
  64. InputStream inputStream = this.sendRequestBefore(streamParametersVO, tbDialogueMain);
  65. String line = null;
  66. BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
  67. while ((line = reader.readLine()) != null) {
  68. //首先对行数据进行处理
  69. if (StrUtil.isNotBlank(line) &&
  70. !StrUtil.equals(line, "event: answer") &&
  71. !StrUtil.equals(line, "event: chatResponse") &&
  72. !StrUtil.contains(line, "data: {\"quoteLen\"")) {
  73. line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);
  74. if (StrUtil.contains(line, "[DONE]")) {
  75. } else {
  76. String oneWord = catchTextGpt(line);
  77. if (StrUtil.isNotBlank(oneWord)) {
  78. answerContent = answerContent + oneWord;
  79. }
  80. }
  81. WebSocketService.sendInfo(line, userId);
  82. TimeUnit.MILLISECONDS.sleep(50);
  83. }
  84. }
  85. //处理完了后,将此条聊天记录进行保存
  86. if (StrUtil.isNotBlank(answerContent)) {
  87. //保存聊天记录
  88. this.saveDig(streamParametersVO, answerContent);
  89. }
  90. inputStream.close();
  91. reader.close();
  92. } catch (Exception e) {
  93. throw new RuntimeException(e.getMessage());
  94. } finally {
  95. //解锁
  96. redisLock.unlock(lockName);
  97. //清除正在问话的标识
  98. redisTemplate.delete(SecurityUtils.getUserId() + "");
  99. }
  100. return answerContent;
  101. }

sendRequestBefore方法

  1. /**
  2. * 这块为 - 流对话模式的封装
  3. *
  4. * @param streamParametersVO
  5. * @param tbDialogueMain
  6. * @return
  7. * @throws Exception
  8. */
  9. @Transactional
  10. public InputStream sendRequestBefore(StreamParametersVO streamParametersVO, TbDialogueMain tbDialogueMain) throws Exception {
  11. InputStream in = null;
  12. //提问内容
  13. String prompt = streamParametersVO.getPrompt();
  14. // 获取当前的用户
  15. String userId = SecurityUtils.getUserId() + "";
  16. Object o = redisTemplate.opsForValue().get(userId);
  17. if (!Objects.isNull(o)) {
  18. throw new RuntimeException("正在回复");
  19. }
  20. redisTemplate.opsForValue().set(userId, true, 30, TimeUnit.SECONDS);
  21. if (StrUtil.isBlank(prompt)) {
  22. throw new RuntimeException("输入内容为空");
  23. }
  24. // 通知内容添加文本铭感词汇过滤
  25. // 其余错误见返回码说明
  26. // 违禁词检测 正常返回0
  27. this.disableWordCheck(prompt);
  28. String apikeyRefresh = getOpenAiKey();
  29. if (StrUtil.isBlank(apikeyRefresh)) {
  30. throw new RuntimeException("无可用key");
  31. }
  32. //处理提问内容(指定系统角色+对话上下文+最新的提问内容)
  33. List<Gpt35TurboVO> chatContext = this.getChatDigContext(streamParametersVO, tbDialogueMain);
  34. String requestUrl = iTbKeyManagerService.getproxyUrl();
  35. Map<Object, Object> objectObjectHashMap = new HashMap<>();
  36. objectObjectHashMap.put("model", "gpt-3.5-turbo");
  37. objectObjectHashMap.put("messages", chatContext);
  38. objectObjectHashMap.put("stream", true);
  39. objectObjectHashMap.put("temperature", 0);
  40. objectObjectHashMap.put("frequency_penalty", 0);
  41. objectObjectHashMap.put("presence_penalty", 0.6);
  42. String bodyJson = JSONUtil.toJsonStr(objectObjectHashMap);
  43. URL url = new URL(requestUrl); // 接口地址
  44. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
  45. urlConnection.setRequestMethod("POST");
  46. urlConnection.setDoOutput(true);
  47. urlConnection.setDoInput(true);
  48. urlConnection.setUseCaches(false);
  49. urlConnection.setRequestProperty("Connection", "Keep-Alive");
  50. urlConnection.setRequestProperty("Charset", "UTF-8");
  51. urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
  52. urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
  53. byte[] dataBytes = bodyJson.getBytes();
  54. urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
  55. OutputStream os = urlConnection.getOutputStream();
  56. os.write(dataBytes);
  57. in = new BufferedInputStream(urlConnection.getInputStream());
  58. os.flush();
  59. os.close();
  60. return in;
  61. }

getChatDigContext方法

  1. /**
  2. * 获取对话上下文
  3. *
  4. * @param streamParametersVO
  5. * @return
  6. */
  7. public List<Gpt35TurboVO> getChatDigContext(StreamParametersVO streamParametersVO, TbDialogueMain tbDialogueMain) {
  8. List<Gpt35TurboVO> messages = new ArrayList<>();
  9. //首先获取角色,默认角色
  10. String default_role_content = iconfigService.selectConfigByKey("default_role");
  11. if (StrUtil.isBlank(default_role_content)) {
  12. default_role_content = "我是一个全能机器人,可以回答你任何问题";
  13. }
  14. //根据用户传递过来的Id查询角色模型数据
  15. TbModelTable tbModelTable = iTbModelTableService.selectTbModelTableById(tbDialogueMain.getDialogueRoleId());
  16. if (!Objects.isNull(tbModelTable)) {
  17. default_role_content = tbModelTable.getModelContent();
  18. }
  19. //小程序专用
  20. //是否通过微信小程序审核的设定语
  21. String is_open_pass_wx_promt = iconfigService.selectConfigByKey("is_open_pass_wx_promt");
  22. if (StrUtil.isNotBlank(is_open_pass_wx_promt) && !StrUtil.equals(is_open_pass_wx_promt, "0")) {
  23. String pass_wx_promt = iconfigService.selectConfigByKey("pass_wx_promt");
  24. default_role_content = default_role_content + "。并且你必须遵循:" + pass_wx_promt;
  25. }
  26. //设定系统所扮演的角色
  27. Gpt35TurboVO gpt35TurboVOSys = new Gpt35TurboVO();
  28. gpt35TurboVOSys.setRole("system");
  29. gpt35TurboVOSys.setContent(default_role_content);
  30. messages.add(gpt35TurboVOSys);
  31. //然后查询当前对话的上下文数据TbDialogueProcess
  32. TbDialogueProcess tbDialogueProcess = new TbDialogueProcess();
  33. tbDialogueProcess.setSessionId(streamParametersVO.getDialogueId());
  34. tbDialogueProcess.setUserId(SecurityUtils.getUserId());
  35. String default_context_num = iconfigService.selectConfigByKey("default_context_num");
  36. if (StrUtil.isBlank(default_context_num) || !NumberUtil.isNumber(default_context_num)) {
  37. default_context_num = "10";
  38. }
  39. tbDialogueProcess.setLimitNum(Integer.valueOf(default_context_num));
  40. //根据对话ID和用户ID查询到对话列表-根据时间倒叙获取后几条设定的数据
  41. List<TbDialogueProcess> tbDialogueProcessesDesc = iTbDialogueProcessService
  42. .selectTbDialogueProcessListByLimitDesc(tbDialogueProcess);
  43. if (CollectionUtil.isNotEmpty(tbDialogueProcessesDesc)) {
  44. //获取到倒数10条数据后将数据正序配好
  45. List<TbDialogueProcess> tbDialogueProcesses = tbDialogueProcessesDesc
  46. .stream()
  47. .sorted(Comparator.comparing(TbDialogueProcess::getCreateTime))
  48. .collect(Collectors.toList());
  49. for (TbDialogueProcess tbDialogueProcessfor : tbDialogueProcesses) {
  50. Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
  51. //用户询问的问题
  52. gpt35TurboUser.setRole("user");
  53. gpt35TurboUser.setContent(tbDialogueProcessfor.getAskContent());
  54. messages.add(gpt35TurboUser);
  55. //机器人回答的问题
  56. Gpt35TurboVO gpt35TurAssistant = new Gpt35TurboVO();
  57. gpt35TurAssistant.setRole("assistant");
  58. gpt35TurAssistant.setContent(tbDialogueProcessfor.getAnswerContent());
  59. messages.add(gpt35TurAssistant);
  60. }
  61. }
  62. //最后查询用户最新询问的问题
  63. Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
  64. gpt35TurboUser.setRole("user");
  65. gpt35TurboUser.setContent(streamParametersVO.getPrompt());
  66. messages.add(gpt35TurboUser);
  67. return messages;
  68. }

2.4、AI绘画

Controller

  1. @PostMapping("/image/api")
  2. public AjaxResult imageApi(@RequestBody StreamImageParametersVO streamImageParametersVO) {
  3. String answerContent = iChatGptImageService.imageSocketStream(streamImageParametersVO);
  4. return success("success",answerContent);
  5. }

Impl

  1. @Override
  2. public String imageSocketStream(StreamImageParametersVO imageParametersVO) {
  3. String lockName = "image_" + SecurityUtils.getUserId();
  4. String answerContent = "";
  5. try{
  6. RLock rLock = redisLock.getRLock(lockName);
  7. boolean locked = rLock.isLocked();
  8. if (locked){
  9. throw new RuntimeException("回复中");
  10. }
  11. //对同一用户访问加锁
  12. redisLock.lock(lockName);
  13. //校验是否输入内容,次数扣减
  14. this.imageBefore(imageParametersVO);
  15. String userId = SecurityUtils.getUserId() + "";
  16. InputStream is = this.sendRequestBeforeImage(imageParametersVO);
  17. String line = null;
  18. BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  19. while((line = reader.readLine()) != null){
  20. //数据处理
  21. if (StrUtil.isNotBlank(line) &&
  22. !StrUtil.equals(line, "event: answer") &&
  23. !StrUtil.equals(line, "event: chatResponse") &&
  24. !StrUtil.contains(line, "data: {\"quoteLen\"")) {
  25. line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);
  26. if (StrUtil.contains(line, "[DONE]")){
  27. }else{
  28. String oneWord = catchUrlImage(line);
  29. if (StrUtil.isNotBlank(oneWord)){
  30. answerContent = answerContent + oneWord;
  31. }
  32. }
  33. WebSocketService.sendInfo(line,userId);
  34. TimeUnit.MILLISECONDS.sleep(50);
  35. }
  36. }
  37. //处理完之后将次条聊天记录进行记录
  38. if (StrUtil.isNotBlank(answerContent)){
  39. //保存聊天记录
  40. this.saveDialogueLog(imageParametersVO, answerContent);
  41. }
  42. is.close();
  43. reader.close();
  44. }catch (Exception e){
  45. throw new RuntimeException(e.getMessage());
  46. }finally {
  47. //解锁
  48. redisLock.unlock(lockName);
  49. redisTemplate.delete(SecurityUtils.getUserId() + "");
  50. }
  51. return saveImageUrl(jsonImageUrl(answerContent));
  52. }

sendRequestBeforeImage方法

  1. /**
  2. * 问询,不包含对话模式
  3. */
  4. @Transactional
  5. public InputStream sendRequestBeforeImage(StreamImageParametersVO imageParametersVO) throws Exception{
  6. InputStream in = null;
  7. //通知内容添加文本敏感词汇过滤
  8. //其余错误见返回码说明
  9. //正常返回0
  10. //违禁词检测
  11. this.disbleWordImageCheck(imageParametersVO.getPrompt());
  12. String apikeyRefresh = getOpenAiKey();
  13. if (StrUtil.isBlank(apikeyRefresh)){
  14. throw new RuntimeException("无可用key");
  15. }
  16. // List<Gpt35TurboVO> imageContext = this.getImageContext(imageParametersVO);
  17. String requestImageUrl = iTbKeyManagerService.getImageProxyUrl();
  18. Map<Object, Object> objectObjecHashtMap = new HashMap<>();
  19. objectObjecHashtMap.put("prompt", imageParametersVO.getPrompt());
  20. objectObjecHashtMap.put("n", 1);
  21. objectObjecHashtMap.put("size", "1024x1024");
  22. String bodyJson = JSONUtil.toJsonStr(objectObjecHashtMap);
  23. URL url = new URL(requestImageUrl); //接口地址
  24. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
  25. urlConnection.setRequestMethod("POST");
  26. urlConnection.setDoOutput(true);
  27. urlConnection.setDoInput(true);
  28. urlConnection.setUseCaches(false);
  29. urlConnection.setRequestProperty("Connection", "Keep-Alive");
  30. urlConnection.setRequestProperty("Charset", "UTF-8");
  31. urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
  32. urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
  33. byte[] dataBytes = bodyJson.getBytes();
  34. urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
  35. OutputStream os = urlConnection.getOutputStream();
  36. os.write(dataBytes);
  37. in = new BufferedInputStream(urlConnection.getInputStream());
  38. os.flush();
  39. os.close();
  40. return in;
  41. }

catchUrlImage方法

  1. /**
  2. * 对链接地址处理
  3. */
  4. public String catchUrlImage(String str){
  5. return str;
  6. }

图片处理,chatgpt返回的图片有效期是五分钟,我们需要将图片下载至本地或服务器。

  1. /**
  2. * 保存图片返回的结果
  3. */
  4. public String saveImageUrl(String jsonUrl){
  5. String imageURL = uploadFileImageAi(jsonUrl);
  6. // 找到下划线的索引位置
  7. int underscoreIndex = imageURL.indexOf('_');
  8. String result = "";
  9. if (underscoreIndex != -1) {
  10. // 截取从下划线的位置开始到字符串的末尾
  11. result = imageURL.substring(underscoreIndex - 9);
  12. } else {
  13. throw new RuntimeException("图片链接截取失败");
  14. }
  15. return TomcatConfig.getImageAiUrl() + "/" + result;
  16. }
  17. /**
  18. * 图片处理
  19. * @param imageUrl
  20. * @return
  21. */
  22. public String uploadFileImageAi(String imageUrl){
  23. // //服务器文件上传路径
  24. String path = TomcatConfig.setUploadImageAiUrl() + Constants.DRAW_PREFIX + "_" + Seq.getId(Seq.uploadSeqType) + ".png";
  25. // 本地文件上传路径
  26. // String path = "D:\\BaiduNetdiskDownload\\image-use\\" + Constants.DRAW_PREFIX + "_" + Seq.getId(Seq.uploadSeqType) + ".png";
  27. try{
  28. URL url = new URL(imageUrl);
  29. HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  30. int responseCode = connection.getResponseCode();
  31. if (responseCode == HttpURLConnection.HTTP_OK) {
  32. InputStream inputStream = connection.getInputStream();
  33. OutputStream outputStream = new FileOutputStream(path);
  34. byte[] buffer = new byte[4096];
  35. int bytesRead;
  36. while ((bytesRead = inputStream.read(buffer)) != -1) {
  37. outputStream.write(buffer, 0, bytesRead);
  38. }
  39. outputStream.close();
  40. inputStream.close();
  41. } else {
  42. throw new RuntimeException("文件无法下载");
  43. }
  44. }catch (IOException e){
  45. e.printStackTrace();
  46. }
  47. return path;
  48. }
  49. /**
  50. * JSON数据处理
  51. * @param imageContent
  52. * @return
  53. */
  54. public String jsonImageUrl(String imageContent){
  55. //解析json字符串
  56. JSONObject obj = JSON.parseObject(imageContent);
  57. //获取 "data"字段相应的JSON数组
  58. JSONArray dataArray = obj.getJSONArray("data");
  59. //获取第一个元素路径地址
  60. JSONObject dataObject = dataArray.getJSONObject(0);
  61. // 返回"url"字段的值
  62. return dataObject.getString("url");
  63. }

 

 

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号