上課學到的東東, 順手寫下筆記 依稀記得很多年前做爬蟲的時候無意間有做過類似的效果, 當時不曉得這個叫做 streaming 首先 api 的部分要回傳 IAsyncEnumerable<string> 然後用 await Task.Delay 來控制語速
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 [Route("api/[controller]" ) ] [ApiController ] public class LoremController : ControllerBase { private List<List<string >> textDict = new List<List<string >>() { new List<string >() { "好啊" , "歡迎" , "鳩咪" , }, new List<string >() { "歸剛ㄟ" , "社畜" , "煩不煩" , }, new List<string >() { "你好" , "心靜自然涼" , "長輩語錄" , }, new List<string >() { "開心每一天" , "與世無爭" , "長輩語錄" , }, }; [HttpGet("GetText" ) ] public async IAsyncEnumerable<string > GetText (int speed = 2 ) { var rnd = new Random(); var current = rnd.Next(0 , textDict.Count); foreach (var item in textDict[current]) { await Task.Delay(speed * 100 ); yield return item; } } }
前端 js 則是可以參考 mdn
1 2 3 4 5 6 7 8 9 10 11 12 async function readData (url ) { const response = await fetch (url); const reader = response.body .getReader (); while (true ) { const { done, value } = await reader.read (); if (done) { return ; } } }
他這個拿回來實際上會是一個 uint8array 還需要經過 TextDecoder 處理
1 2 3 4 const arr = new Uint8Array ([104 , 101 , 108 , 108 , 111 ]);const decoder = new TextDecoder ();const str = decoder.decode (arr);
經過 decode 以後因為是 string array 的關係會變這樣
1 2 3 4 ["aaa", "bbb", "ccc", "ddd"]
我沒找到更好的方法來解, 發現 老外 也是用 regex 處理, 搭配 GPT 問起來就是這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 async function getText (url ) { const response = await fetch (url); const reader = response.body .getReader (); async function * generateText ( ) { while (true ) { const { done, value } = await reader.read (); if (done) return ; yield value; } } for await (const chunk of generateText ()) { const text = new TextDecoder ().decode (chunk) .replace (/\[|]/g , '' ) .replace (/^,/ , '' ) .replace (/^"|"$/g , '' ); console .log (text) } }
想看完整效果的話可以到我的 codepen 然後把 url 改成你的網址並且開啟 CORS 即可 ~
See the Pen
SkypeGPT by 喇賽人 (@weber87na )
on CodePen .