欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript基于ChatGPT實(shí)現(xiàn)打字機(jī)消息回復(fù)

 更新時(shí)間:2023年05月07日 10:45:01   作者:比心技術(shù)  
ChatGPT 是一個(gè)基于深度學(xué)習(xí)的大型語(yǔ)言模型,處理自然語(yǔ)言需要大量的計(jì)算資源和時(shí)間,響應(yīng)速度肯定比普通的讀數(shù)據(jù)庫(kù)要慢的多,本文介紹了ChatGPT打字機(jī)消息回復(fù)實(shí)現(xiàn)原理,感興趣的同學(xué)可以跟著小編一起學(xué)習(xí)

1 背景

在使用 ChatGPT 時(shí),發(fā)現(xiàn)輸入 prompt 后,頁(yè)面是逐步給出回復(fù)的,起初以為使用了 WebSckets 持久化連接協(xié)議,查看其網(wǎng)絡(luò)請(qǐng)求,發(fā)現(xiàn)這個(gè)接口的通信方式并非傳統(tǒng)的 http 接口或者 WebSockets,而是基于 EventStream 的事件流,像打字機(jī)一樣,一段一段的返回答案。

ChatGPT 是一個(gè)基于深度學(xué)習(xí)的大型語(yǔ)言模型,處理自然語(yǔ)言需要大量的計(jì)算資源和時(shí)間,響應(yīng)速度肯定比普通的讀數(shù)據(jù)庫(kù)要慢的多,普通 http 接口等待時(shí)間過(guò)長(zhǎng),顯然并不合適。對(duì)于這種單項(xiàng)對(duì)話場(chǎng)景,ChagtGPT 將先計(jì)算出的數(shù)據(jù)“推送”給用戶,邊計(jì)算邊返回,避免用戶因?yàn)榈却龝r(shí)間過(guò)長(zhǎng)關(guān)閉頁(yè)面。而這,正式采用了 SSE 技術(shù)。

2 簡(jiǎn)介

Server-Sent Events 服務(wù)器推送事件,簡(jiǎn)稱 SSE,是一種服務(wù)端實(shí)時(shí)主動(dòng)向?yàn)g覽器推送消息的技術(shù)。 SSE 是 HTML5 中一個(gè)與通信相關(guān)的 API,主要由兩部分組成:服務(wù)端與瀏覽器端的通信協(xié)議(HTTP 協(xié)議)及瀏覽器端可供 JavaScript 使用的 EventSource 對(duì)象。

從“服務(wù)端主動(dòng)向?yàn)g覽器實(shí)時(shí)推送消息”這一點(diǎn)來(lái)看,該 API 與 WebSockets API 有一些相似之處。但是,該 API 與 WebSockers API 的不同之處在于:

Server-Sent Events APIWebSockets API
基于 HTTP 協(xié)議基于 TCP 協(xié)議
單工,只能服務(wù)端單向發(fā)送消息全雙工,可以同時(shí)發(fā)送和接收消息
輕量級(jí),使用簡(jiǎn)單相對(duì)復(fù)雜
內(nèi)置斷線重連和消息追蹤的功能不在協(xié)議范圍內(nèi),需手動(dòng)實(shí)現(xiàn)
文本或使用 Base64 編碼和 gzip 壓縮的二進(jìn)制消息類型廣泛
支持自定義事件類型不支持自定義事件類型
連接數(shù) HTTP/1.1 6 個(gè),HTTP/2 可協(xié)商(默認(rèn) 100)連接數(shù)無(wú)限制

3 服務(wù)端實(shí)現(xiàn)

3.1 協(xié)議

SSE 協(xié)議非常簡(jiǎn)單,本質(zhì)是瀏覽器發(fā)起 http 請(qǐng)求,服務(wù)器在收到請(qǐng)求后,返回狀態(tài)與數(shù)據(jù),并附帶以下 headers: js Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive - SSE API規(guī)定推送事件流的 MIME 類型為 text/event-stream。 - 必須指定瀏覽器不緩存服務(wù)端發(fā)送的數(shù)據(jù),以確保瀏覽器可以實(shí)時(shí)顯示服務(wù)端發(fā)送的數(shù)據(jù)。 - SSE 是一個(gè)一直保持開(kāi)啟的 TCP 連接,所以 Connection 為 keep-alive。

3.2 消息格式

EventStream(事件流)為 UTF-8 格式編碼的文本或使用 Base64 編碼和 gzip 壓縮的二進(jìn)制消息。 每條消息由一行或多行字段(event、idretry、data)組成,每個(gè)字段組成形式為:字段名:字段值。字段以行為單位,每行一個(gè)(即以 \n 結(jié)尾)。以冒號(hào)開(kāi)頭的行為注釋行,會(huì)被瀏覽器忽略。 每次推送,可由多個(gè)消息組成,每個(gè)消息之間以空行分隔(即最后一個(gè)字段以\n\n結(jié)尾)。

?? 注意:

  • 除上述四個(gè)字段外,其他所有字段都會(huì)被忽略。
  • 如果一行字段中不包含冒號(hào),則整行文本將被視為字段名,字段值為空。
  • 注釋行可以用來(lái)防止鏈接超時(shí),服務(wù)端可以定期向?yàn)g覽器發(fā)送一條消息注釋行,以保持連接不斷。

3.2.1 event

事件類型。如果指定了該字段,則在瀏覽器收到該條消息時(shí),會(huì)在當(dāng)前 EventSource 對(duì)象(見(jiàn) 4)上觸發(fā)一個(gè)事件,事件類型就是該字段的字段值??梢允褂?addEventListener 方法在當(dāng)前 EventSource 對(duì)象上監(jiān)聽(tīng)任意類型的命名事件。 如果該條消息沒(méi)有 event 字段,則會(huì)觸發(fā) EventSource 對(duì)象 onmessage 屬性上的事件處理函數(shù)。

3.2.2 id

事件ID。事件的唯一標(biāo)識(shí)符,瀏覽器會(huì)跟蹤事件ID,如果發(fā)生斷連,瀏覽器會(huì)把收到的最后一個(gè)事件ID放到 HTTP Header Last-Event-Id 中進(jìn)行重連,作為一種簡(jiǎn)單的同步機(jī)制。 例如可以在服務(wù)端將每次發(fā)送的事件ID值自動(dòng)加 1,當(dāng)瀏覽器接收到該事件ID后,下次與服務(wù)端建立連接后再請(qǐng)求的 Header 中將同時(shí)提交該事件ID,服務(wù)端檢查該事件ID是否為上次發(fā)送的事件ID,如果與上次發(fā)送的事件ID不一致則說(shuō)明瀏覽器存在與服務(wù)器連接失敗的情況,本次需要同時(shí)發(fā)送前幾次瀏覽器未接收到的數(shù)據(jù)。

3.2.3 retry

重連時(shí)間。整數(shù)值,單位 ms,如果與服務(wù)器的連接丟失,瀏覽器將等待指定時(shí)間,然后嘗試重新連接。如果該字段不是整數(shù)值,會(huì)被忽略。 當(dāng)服務(wù)端沒(méi)有指定瀏覽器的重連時(shí)間時(shí),由瀏覽器自行決定每隔多久與服務(wù)端建立一次連接(一般為 30s)。

3.2.4 data

消息數(shù)據(jù)。數(shù)據(jù)內(nèi)容只能以一個(gè)字符串的文本形式進(jìn)行發(fā)送,如果需要發(fā)送一個(gè)對(duì)象時(shí),需要將該對(duì)象以一個(gè) JSON 格式的字符串的形式進(jìn)行發(fā)送。在瀏覽器接收到該字符串后,再把它還原為一個(gè) JSON 對(duì)象。

3.3 示例

如下事件流示例,共發(fā)送了 4 條消息,每條消息間以一個(gè)空行作為分隔符。 第一條僅僅是個(gè)注釋,因?yàn)樗悦疤?hào)開(kāi)頭。 第二條消息只包含一個(gè) data 字段,值為 'this is second message'。 第三條消息包含兩個(gè) data 字段,其會(huì)被解析為一個(gè)字段,值為 'this is third message part 1\nthis is third message part 2'。 第四條消息包含完整四個(gè)字段,指定了事件類型為 'server-time',事件id 為 '1',重連時(shí)間為 '30000'ms,消息數(shù)據(jù)為 JSON 格式的 '{"text": "this is fourth message", "time": "12:00:00"}'。

: this is first message

data: this is second message
data: this is third message part one
data this is third message part two

event: server-time
id: 1 retry: 30000
data: {"text": "this is fourth message", "time": "2023-04-09 12:00:00"}

4 瀏覽器 API

在瀏覽器端,可以使用 JavaScript 的 EventSource API 創(chuàng)建 EventSource 對(duì)象監(jiān)聽(tīng)服務(wù)器發(fā)送的事件。一旦建立連接,服務(wù)器就可以使用 HTTP 響應(yīng)的 'text/event-stream' 內(nèi)容類型發(fā)送事件消息,瀏覽器則可以通過(guò)監(jiān)聽(tīng) EventSource 對(duì)象的 onmessage、onopenonerror 事件來(lái)處理這些消息。

4.1 建立連接

EventSource 接受兩個(gè)參數(shù):URL 和 options。 URL 為 http 事件來(lái)源,一旦 EventSource 對(duì)象被創(chuàng)建后,瀏覽器立即開(kāi)始對(duì)該 URL 地址發(fā)送過(guò)來(lái)的事件進(jìn)行監(jiān)聽(tīng)。 options 是一個(gè)可選的對(duì)象,包含 withCredentials 屬性,表示是否發(fā)送憑證(cookie、HTTP認(rèn)證信息等)到服務(wù)端,默認(rèn)為 false。

const eventSource = new EventSource('http_api_url', { withCredentials: true }) 
復(fù)制代碼

與 XMLHttpRequest 對(duì)象類型,EventSource 對(duì)象有一個(gè) readyState 屬性值,具體含義如下表:

readyState含義
0瀏覽器與服務(wù)端尚未建立連接或連接已被關(guān)閉
1瀏覽器與服務(wù)端已成功連接,瀏覽器正在處理接收到的事件及數(shù)據(jù)
2瀏覽器與服務(wù)端建立連接失敗,客戶端不再繼續(xù)建立與服務(wù)端之間的連接

可以使用 EventSource 對(duì)象的 close 方法關(guān)閉與服務(wù)端之間的連接,使瀏覽器不再建立與服務(wù)端之間的連接。

// 初始化 eventSource 等省略 

// 關(guān)閉連接 
eventSource.close() 

4.2 監(jiān)聽(tīng)事件

EventSource 對(duì)象本身繼承自 EventTarget 接口,因此可以使用 addEventListener() 方法來(lái)監(jiān)聽(tīng)事件。EventSource 對(duì)象觸發(fā)的事件主要包括以下三種:

  • open 事件:當(dāng)成功連接到服務(wù)端時(shí)觸發(fā)。
  • message 事件:當(dāng)接收到服務(wù)器發(fā)送的消息時(shí)觸發(fā)。該事件對(duì)象的 data 屬性包含了服務(wù)器發(fā)送的消息內(nèi)容。
  • error 事件:當(dāng)發(fā)生錯(cuò)誤時(shí)觸發(fā)。該事件對(duì)象的 event 屬性包含了錯(cuò)誤信息。
// 初始化 eventSource 等省略 

eventSource.addEventListener('open', function(event) { 
    console.log('Connection opened')
})
eventSource.addEventListener('message', function(event) { 
    console.log('Received message: ' + event.data); 
}) 

// 監(jiān)聽(tīng)自定義事件

eventSource.addEventListener('xxx', function(event) {
    console.log('Received message: ' + event.data);
})
eventSource.addEventListener('error', function(event) {
    console.log('Error occurred: ' + event.event);
}) 

當(dāng)然,也可以采用屬性監(jiān)聽(tīng)(onopen、onmessageonerror)的形式。

// 初始化 eventSource 等省略
eventSource.onopen = function(event) {
    console.log('Connection opened')
}
eventSource.onmessage = function(event) {
    console.log('Received message: ' + event.data);
}
eventSource.onerror = function(event) {
    console.log('Error occurred: ' + event.event)
}) 

??注意: EventSource 對(duì)象的屬性監(jiān)聽(tīng)只能監(jiān)聽(tīng)預(yù)定義的事件類型(open、message、error)。不能用于監(jiān)聽(tīng)自定義事件類型。如果要實(shí)現(xiàn)自定義事件類型的監(jiān)聽(tīng),可以使用 addEventListener() 方法。

5 實(shí)踐

5.1 服務(wù)端

使用 Node.js 實(shí)現(xiàn) SSE 的簡(jiǎn)單示例:

const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
    if (req.url === '/') {
        // 如果請(qǐng)求根路徑,返回 index.html 文件 
        fs.readFile('index.html', (err, data) => {
            if (err) {
                res.writeHead(500);
                res.end('Error loading index.html');
            } else {
                res.writeHead(200, {'Content-Type': 'text/html'}); 
                res.end(data);
            }
         });
     } else if (req.url === '/events') {
         // 如果請(qǐng)求 /events 路徑,建立 SSE 連接 
         res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); 
         // 每隔 1 秒發(fā)送一條消息 
         let id = 0; 
         const intervalId = setInterval(() => { 
             res.write(`event: customEvent\n`)
             res.write(`id: ${id}\n`)
             res.write(`retry: 30000\n`)
             const data = { id, time: new Date().toISOString()}
             res.write(`data: ${JSON.stringify(data)}\n\n`); 
             id++
          }, 1000); 
          // 當(dāng)客戶端關(guān)閉連接時(shí)停止發(fā)送消息
          req.on('close', () => { 
              clearInterval(intervalId); 
              id = 0
              res.end();
          });
    } else { 
        // 如果請(qǐng)求的路徑無(wú)效,返回 404 狀態(tài)碼 
        res.writeHead(404); 
        res.end();
    }
    
}).listen(3000); 

console.log('Server listening on port 3000'); 

5.2 瀏覽器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Demo</title>
</head>
<body>
    <h1>SSE Demo</h1>
    <button onclick="connectSSE()">建立 SSE 連接</button>
    <button onclick="closeSSE()">斷開(kāi) SSE 連接</button> <br /> <br /> 
    <div id="message"></div>
    <script> 
        const messageElement = document.getElementById('message') 
        let eventSource // 建立 SSE 連接 
        const connectSSE = () => {
            eventSource = new EventSource('/events') // 監(jiān)聽(tīng)消息事件 
            eventSource.addEventListener('customEvent', (event) => { 
                const data = JSON.parse(event.data) 
                messageElement.innerHTML += `${data.id} --- ${data.time}` + '<br />'
             }) 
            eventSource.onopen = () => {
                messageElement.innerHTML += `SSE 連接成功,狀態(tài)${eventSource.readyState}<br />` 
            }
            eventSource.onerror = () => {
                messageElement.innerHTML += `SSE 連接錯(cuò)誤,狀態(tài)${eventSource.readyState}<br />`
             } 
         } 
         // 斷開(kāi) SSE 連接 
         const closeSSE = () => {
             eventSource.close() 
             messageElement.innerHTML += `SSE 連接關(guān)閉,狀態(tài)${eventSource.readyState}<br />`
         }
      </script>
</body>
</html> 

將上面的兩份代碼保存為 server.js 和 index.html,并在命令行中執(zhí)行 node server.js 啟動(dòng)服務(wù)端,然后在瀏覽器中打開(kāi) http://localhost:3000 即可看到 SSE 效果。

6 兼容性

發(fā)展至今,SSE 已具有廣泛的的瀏覽器兼容性,幾乎除 IE 之外的瀏覽器均已支持。

對(duì)于不支持 EventSource 的瀏覽器,可以使用 polyfill 實(shí)現(xiàn)。判斷瀏覽器是否支持 EventSource:

if(typeof(EventSource) !== “undefined”) { 
// 支持
} else {
// 不支持,使用 polyfill
} 

7 總結(jié)

SSE 技術(shù)是一種輕量級(jí)的實(shí)時(shí)通信技術(shù),基于 HTTP 協(xié)議,具有服務(wù)端推送、斷線重連、簡(jiǎn)單輕量等優(yōu)點(diǎn)。但是,SSE 技術(shù)也有一些缺點(diǎn),如不能進(jìn)行雙向通信、連接數(shù)受限等。

SSE 可以在 Web 應(yīng)用程序中實(shí)現(xiàn)諸如股票在線數(shù)據(jù)、日志推送、聊天室實(shí)時(shí)人數(shù)等即時(shí)數(shù)據(jù)推送功能。需要注意的是,SSE 并不是適用于所有的實(shí)時(shí)推送場(chǎng)景。在需要高并發(fā)、高吞吐量和低延遲的場(chǎng)景下,WebSockets 可能更加適合。而在需要更輕量級(jí)的推送場(chǎng)景下,SSE 可能更加適合。因此,在選擇即時(shí)更新方案時(shí),需要根據(jù)具體的需求和場(chǎng)景進(jìn)行選擇。

以上就是基于JavaScript的ChatGPT打字機(jī)消息回復(fù)實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于ChatGPT打字機(jī)消息回復(fù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解JavaScript中的屬性和特性

    詳解JavaScript中的屬性和特性

    本文對(duì)JavaScript中對(duì)象的本質(zhì)、對(duì)象與類的關(guān)系、對(duì)象與引用類型的關(guān)系;對(duì)象屬性如何進(jìn)行分類;屬性中特性進(jìn)行介紹。感興趣的朋友可以看下
    2016-12-12
  • js判斷瀏覽器類型及設(shè)備(移動(dòng)頁(yè)面開(kāi)發(fā))

    js判斷瀏覽器類型及設(shè)備(移動(dòng)頁(yè)面開(kāi)發(fā))

    這篇文章主要介紹了js判斷瀏覽器類型及設(shè)備(移動(dòng)頁(yè)面開(kāi)發(fā)),需要的朋友可以參考下
    2015-07-07
  • JS實(shí)現(xiàn)拖動(dòng)模糊框特效

    JS實(shí)現(xiàn)拖動(dòng)模糊框特效

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)拖動(dòng)模糊框特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • 移動(dòng)端使用localResizeIMG4壓縮圖片

    移動(dòng)端使用localResizeIMG4壓縮圖片

    這篇文章主要為大家詳細(xì)介紹了移動(dòng)端使用localResizeIMG4壓縮圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • js實(shí)現(xiàn)文字無(wú)縫輪播

    js實(shí)現(xiàn)文字無(wú)縫輪播

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)文字無(wú)縫輪播,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • uniapp小程序自定義tabbar以及初次加載閃屏解決方法

    uniapp小程序自定義tabbar以及初次加載閃屏解決方法

    Uniapp小程序可以通過(guò)自定義tabbar來(lái)實(shí)現(xiàn)更加個(gè)性化的界面設(shè)計(jì),下面這篇文章主要給大家介紹了關(guān)于uniapp小程序自定義tabbar以及初次加載閃屏解決方法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • 深入理解JavaScript系列(29):設(shè)計(jì)模式之裝飾者模式詳解

    深入理解JavaScript系列(29):設(shè)計(jì)模式之裝飾者模式詳解

    這篇文章主要介紹了深入理解JavaScript系列(29):設(shè)計(jì)模式之裝飾者模式詳解,裝飾者用用于包裝同接口的對(duì)象,不僅允許你向方法添加行為,而且還可以將方法設(shè)置成原始對(duì)象調(diào)用(例如裝飾者的構(gòu)造函數(shù)),需要的朋友可以參考下
    2015-03-03
  • Peer.js 構(gòu)建視頻聊天應(yīng)用使用詳解

    Peer.js 構(gòu)建視頻聊天應(yīng)用使用詳解

    這篇文章主要為大家介紹了Peer.js 構(gòu)建視頻聊天應(yīng)用使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 小程序?qū)崿F(xiàn)授權(quán)登陸的解決方案

    小程序?qū)崿F(xiàn)授權(quán)登陸的解決方案

    這篇文章主要介紹了小程序?qū)崿F(xiàn)授權(quán)登陸的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • JavaScript獲取頁(yè)面中第一個(gè)錨定文本的方法

    JavaScript獲取頁(yè)面中第一個(gè)錨定文本的方法

    這篇文章主要介紹了JavaScript獲取頁(yè)面中第一個(gè)錨定文本的方法,涉及javascript操作document.archors數(shù)組的技巧,需要的朋友可以參考下
    2015-04-04

最新評(píng)論