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


    目录

    一、说明

    二、代码

    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 objects = new ArrayList<>();
    11. objects.add(gpt35TurboVO);
    12. Map 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 chatContext = this.getChatContext(chatBotSingleQuestionVO);
    21. String requestUrl = iTbKeyManagerService.getproxyUrl();
    22. Map 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 getChatContext(ChatBotSingleQuestionVO chatBotSingleQuestionVO) {
    7. List 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 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 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 chatContext = this.getChatDigContext(streamParametersVO, tbDialogueMain);
    34. String requestUrl = iTbKeyManagerService.getproxyUrl();
    35. Map 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 getChatDigContext(StreamParametersVO streamParametersVO, TbDialogueMain tbDialogueMain) {
    8. List 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 tbDialogueProcessesDesc = iTbDialogueProcessService
    42. .selectTbDialogueProcessListByLimitDesc(tbDialogueProcess);
    43. if (CollectionUtil.isNotEmpty(tbDialogueProcessesDesc)) {
    44. //获取到倒数10条数据后将数据正序配好
    45. List 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 imageContext = this.getImageContext(imageParametersVO);
    17. String requestImageUrl = iTbKeyManagerService.getImageProxyUrl();
    18. Map 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. }

     

     

     

  • 相关阅读:
    buuctf-[BSidesCF 2020]Had a bad day 文件包含
    C++标准模板库STL——list的使用及其模拟实现
    vue入门
    LeetCode 104. 二叉树的最大深度
    设计模式解码:软件工程架构的航标
    十二条后端开发经验分享,纯干货
    记录本地Nginx发布vue项目
    南丁格尔玫瑰图
    lammps教程:CNA晶体结构分析命令
    Zabbix搭建使用一篇通
  • 原文地址:https://blog.csdn.net/private_name/article/details/132805966