(stream: ReadableStream<Uint8Array>, abortSignal?: AbortSignal)
| 188 | |
| 189 | // 辅助函数:将ReadableStream转换为异步迭代器 |
| 190 | async function* streamAsyncIterable(stream: ReadableStream<Uint8Array>, abortSignal?: AbortSignal) { |
| 191 | const reader = stream.getReader(); |
| 192 | const decoder = new TextDecoder(); |
| 193 | |
| 194 | try { |
| 195 | while (true) { |
| 196 | if (abortSignal?.aborted) { |
| 197 | break; |
| 198 | } |
| 199 | |
| 200 | const { done, value } = await reader.read(); |
| 201 | if (done) { |
| 202 | return; |
| 203 | } |
| 204 | |
| 205 | const chunk = decoder.decode(value, { stream: true }); |
| 206 | |
| 207 | if (chunk) { |
| 208 | const lines = chunk |
| 209 | .split('\n') |
| 210 | .filter(line => line.trim() !== '') |
| 211 | .map(line => line.replace(/^data: /, '').trim()); |
| 212 | |
| 213 | for (const line of lines) { |
| 214 | if (line === '[DONE]') { |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | try { |
| 219 | if (line) { |
| 220 | if (line.startsWith('{')) { |
| 221 | const parsed = JSON.parse(line); |
| 222 | if (parsed.choices && parsed.choices[0] && parsed.choices[0].delta && parsed.choices[0].delta.content) { |
| 223 | yield parsed.choices[0].delta.content; |
| 224 | } |
| 225 | } else { |
| 226 | yield line; |
| 227 | } |
| 228 | } |
| 229 | } catch (e) { |
| 230 | console.warn('解析流数据出错:', e, line); |
| 231 | if (line) { |
| 232 | yield line; |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | } finally { |
| 239 | reader.releaseLock(); |
| 240 | } |
| 241 | } |
no outgoing calls
no test coverage detected