java集成chatGpt完整案例代码(效果和官网一样逐字输出)

打印 上一主题 下一主题

主题 946|帖子 946|积分 2838

背景
要集成chatGpt参考我上一篇文章即可。但是,如果要实现官网一样的效果,逐字输出,难度就提升了不少了。经过在官网的研究发现它应该是采用了SSE技术,这是一种最新的HTTP交互技术。SSE(Server-Sent Events):通俗解释起来就是一种基于HTTP的,以流的形式由服务端持续向客户端发送数据的技术。相比较WebSocket更加轻量了。有了SSE,我们就可以实现,一次HTTP请求,可以逐步获取后端内容并及时输出展示,也就可以实现ChatGpt官网的效果了。下面给出简单的实现代码
 
后端核心代码
  1. @Controller
  2. @RequestMapping("/chat")
  3. public class ChatController {
  4.     /**
  5.      * 暂存消息(由于前端EventSource对象仅支持Get请求,故消息通过POST发送到后端后进行中转)
  6.      */
  7.     Map<String, String> msgMap = new ConcurrentHashMap<>();
  8.     @Autowired
  9.     ChatService chatService;
  10.     /**
  11.      * 发送消息
  12.      *
  13.      * @param msg 消息
  14.      * @return 消息ID
  15.      */
  16.     @ResponseBody
  17.     @PostMapping("/sendMsg")
  18.     public String sendMsg(String msg) {
  19.         String msgId = IdUtil.simpleUUID();
  20.         msgMap.put(msgId, msg);
  21.         return msgId;
  22.     }
  23.     /**
  24.      * 对话
  25.      *
  26.      * @param msgId 消息ID
  27.      * @return SseEmitter
  28.      */
  29.     @GetMapping(value = "/conversation/{msgId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  30.     public SseEmitter conversation(@PathVariable("msgId") String msgId) {
  31.         SseEmitter sseEmitter = new SseEmitter();
  32.         String msg = msgMap.remove(msgId);
  33.         //调用流式会话服务
  34.         chatService.streamChatCompletion(msg, sseEmitter);
  35.         //及时返回SseEmitter对象
  36.         return sseEmitter;
  37.     }
  38. }
复制代码
 
前端核心代码
  1. var eventSource = new EventSource('http://localhost:8080/chat/conversation/'+data)
  2.              eventSource.addEventListener('open', function(e) {
  3.                 console.log("EventSource连接成功");
  4.              });
  5.              eventSource.addEventListener("message", function(evt){
  6.                 var data = evt.data;
  7.                 var json = JSON.parse(data);
  8.                 var content = json.content ? json.content : '';
  9.                 content = content.replaceAll('\n','<br/>');
  10.                 console.log(json)
  11.                 var outputBody = $('#outputTxt');
  12.                 outputBody.html(outputBody.html()+content);
  13.                 var outputCard = $('#outputCard');
  14.                 var scrollHeight = outputCard[0].scrollHeight;
  15.                 outputCard.scrollTop(scrollHeight);
  16.             });
  17.             eventSource.addEventListener('error', function (e) {
  18.                 console.log("EventSource异常:" + e)
  19.             });
复制代码
 
效果图

 
 
完整项目代码
https://github.com/hdwang123/GptTest
 
感想
在调研这个技术的时候,遇到很多挑战,虽然艰难好在最终都克服了。主要有以下几个方面的问题:
1. SSE技术仅支持GET请求,这个查了相关文章有第三方库可以实现POST,由于我这里只是做个简单的例子,所以不想再去弄什么第三方库。于是终于想到了办法,就是在后端进行消息暂存:先用POST请求将数据提交到后端,返回一个消息ID,然后再用使用SSE技术提交消息ID建立连接。
2. SSE向前端send的消息总是一把输出,并没有实现逐字输出效果。折腾了半天终于从SSE源码中看到了解决方案。那就是GetMapping控制器方法必须及时返回,要做到这一点,send消息方法的调用必须在新的线程中进行调用,我用@Async解决了
3.SSE向前端输出英文的时候丢失空格,所有英文单词挤在一起了,哎!这个我一开始是直接发送消息内容的,发现英文单词前面的空格丢失了。没办法,改成现在发送json对象字符串的方式,保证了空格不丢失。
4. 前端样式调整问题,主要遇到了滚动条自动滚动到div底部失效问题,scrollTop设置值始终为0。看了好多文章,也找不到解决方案。后来看到别人写的是两个div,灵感来了。我也用两个div,父div设置滚动,子div设置内容,这样就搞定了!
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81429

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表