flush();

這里我們定義了我們自己使用的一個數(shù)據(jù)格式,里邊只放了 time 和 content ,不用解釋都懂,time 是時間, content 就是我們要返回給前端的內(nèi)容。

注意,回答全部傳輸完畢后,我們需要關閉連接,可以用以下代碼:

echo?'retry:?86400000'.PHP_EOL;?//?告訴前端如果發(fā)生錯誤,隔多久之后才輪詢一次
echo?'event:?close'.PHP_EOL;?//?告訴前端,結(jié)束了,該說再見了
echo?'data:?Connection?closed'.PHP_EOL.PHP_EOL;?//?告訴前端,連接已關閉
flush();

EventSource

前端 js 通過 const eventSource = new EventSource(url); 開啟一個 EventSource  請求。

之后服務器按照 data: {"kev1":"value1","kev2":"value2"} 格式向前端發(fā)送數(shù)據(jù),前端就可以在 EventSource 的 message 回調(diào)事件中的 event.data 里獲取  {"kev1":"value1","kev2":"value2"} 字符串形式 json 數(shù)據(jù),再通過 JSON.parse(event.data) 就可以得到 js 對象。

具體代碼在 getAnswer 函數(shù)中,如下所示:

function?getAnswer(inputValue){
????inputValue?=?inputValue.replace('+',?'{[$add$]}');
????const?url?=?"./chat.php?q="+inputValue;
????const?eventSource?=?new?EventSource(url);

????eventSource.addEventListener("open",?(event)?=>?{
????????console.log("連接已建立",?JSON.stringify(event));
????});

????eventSource.addEventListener("message",?(event)?=>?{
????????//console.log("接收數(shù)據(jù):", event);
????????try?{
????????????var?result?=?JSON.parse(event.data);
????????????if(result.time?&&?result.content?){
????????????????answerWords.push(result.content);
????????????????contentIdx?+=?1;
????????????}
????????}?catch?(error)?{
????????????console.log(error);
????????}
????});

????eventSource.addEventListener("error",?(event)?=>?{
????????console.error("發(fā)生錯誤:",?JSON.stringify(event));
????});

????eventSource.addEventListener("close",?(event)?=>?{
????????console.log("連接已關閉",?JSON.stringify(event.data));
????????eventSource.close();
????????contentEnd?=?true;
????????console.log((new?Date().getTime()),?'answer?end');
????});
}

打字機效果

對于后端返回的所有回復內(nèi)容,我們需要用打字機形式打印出來。

最初的方案是

function?typingWords(){
????if(contentEnd?&&?contentIdx==typingIdx){
????????clearInterval(typingTimer);
????????answerContent?=?'';
????????answerWords?=?[];
????????answers?=?[];
????????qaIdx?+=?1;
????????typingIdx?=?0;
????????contentIdx?=?0;
????????contentEnd?=?false;
????????lastWord?=?'';
????????lastLastWord?=?'';
????????input.disabled?=?false;
????????sendButton.disabled?=?false;
????????console.log((new?Date().getTime()),?'typing?end');
????????return;
????}
????if(contentIdx<=typingIdx){
????????return;
????}
????if(typing){
????????return;
????}
????typing?=?true;

????if(!answers[qaIdx]){
????????answers[qaIdx]?=?document.getElementById('answer-'+qaIdx);
????}

????const?content?=?answerWords[typingIdx];
????if(content.indexOf('')?!=?-1){<br>????????if(content.indexOf('`')?!=?-1){<br>????????????codeStart?=?!codeStart;<br>????????}else?if(content.indexOf('')?!=?-1?&&?(lastWord?+?content).indexOf('`')?!=?-1){<br>????????????codeStart?=?!codeStart;<br>????????}else?if(content.indexOf('')?!=?-1?&&?(lastLastWord?+?lastWord?+?content).indexOf('``')?!=?-1){<br>????????????codeStart?=?!codeStart;<br>????????}<br>????}<br><br>????lastLastWord?=?lastWord;<br>????lastWord?=?content;<br><br>????answerContent?+=?content;<br>????answers[qaIdx].innerHTML?=?marked.parse(answerContent+(codeStart?'\n\n``':''));

????typingIdx?+=?1;
????typing?=?false;
}

文章轉(zhuǎn)自微信公眾號@哥飛

上一篇:

PHP寫一個 Api接口需要注意哪些?

下一篇:

或許是你應該了解的一些 ASP.NET Core Web API 使用小技巧
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數(shù)據(jù)驅(qū)動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費