java集成chatGpt完整案例代碼(效果和官網一樣逐字輸出)

背景

要集成chatGpt參考我上一篇文章即可。但是,如果要實現官網一樣的效果,逐字輸出,難度就提升了不少了。經過在官網的研究發現它應該是採用了SSE技術,這是一種最新的HTTP交互技術。SSE(Server-Sent Events):通俗解釋起來就是一種基於HTTP的,以流的形式由服務端持續向客戶端發送數據的技術。相比較WebSocket更加輕量了。有了SSE,我們就可以實現,一次HTTP請求,可以逐步獲取後端內容並及時輸出展示,也就可以實現ChatGpt官網的效果了。下面給出簡單的實現代碼

 

後端核心代碼

@Controller
@RequestMapping("/chat")
public class ChatController {

    /**
     * 暫存消息(由於前端EventSource對象僅支持Get請求,故消息通過POST發送到後端後進行中轉)
     */
    Map<String, String> msgMap = new ConcurrentHashMap<>();

    @Autowired
    ChatService chatService;

    /**
     * 發送消息
     *
     * @param msg 消息
     * @return 消息ID
     */
    @ResponseBody
    @PostMapping("/sendMsg")
    public String sendMsg(String msg) {
        String msgId = IdUtil.simpleUUID();
        msgMap.put(msgId, msg);
        return msgId;
    }

    /**
     * 對話
     *
     * @param msgId 消息ID
     * @return SseEmitter
     */
    @GetMapping(value = "/conversation/{msgId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter conversation(@PathVariable("msgId") String msgId) {
        SseEmitter sseEmitter = new SseEmitter();
        String msg = msgMap.remove(msgId);

        //調用流式會話服務
        chatService.streamChatCompletion(msg, sseEmitter);

        //及時返回SseEmitter對象
        return sseEmitter;
    }
}

 

前端核心代碼

var eventSource = new EventSource('http://localhost:8080/chat/conversation/'+data)
             eventSource.addEventListener('open', function(e) {
                console.log("EventSource連接成功");
             });
             eventSource.addEventListener("message", function(evt){
                var data = evt.data;
                var json = JSON.parse(data);
                var content = json.content ? json.content : '';
                content = content.replaceAll('\n','<br/>');
                console.log(json)
                var outputBody = $('#outputTxt');
                outputBody.html(outputBody.html()+content);
                var outputCard = $('#outputCard');
                var scrollHeight = outputCard[0].scrollHeight;
                outputCard.scrollTop(scrollHeight);
            });
            eventSource.addEventListener('error', function (e) {
                console.log("EventSource異常:" + e)
            });

 

效果圖

 

 

完整項目代碼

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設置內容,這樣就搞定了!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章