|
1 | 1 | import { ReadableStream, type Response } from './_shims/index';
|
2 | 2 | import { OpenAIError } from './error';
|
| 3 | +import { LineDecoder } from './internal/decoders/line'; |
3 | 4 |
|
4 | 5 | import { APIError } from 'openai/error';
|
5 | 6 |
|
@@ -329,117 +330,6 @@ class SSEDecoder {
|
329 | 330 | }
|
330 | 331 | }
|
331 | 332 |
|
332 |
| -/** |
333 |
| - * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally |
334 |
| - * reading lines from text. |
335 |
| - * |
336 |
| - * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258 |
337 |
| - */ |
338 |
| -class LineDecoder { |
339 |
| - // prettier-ignore |
340 |
| - static NEWLINE_CHARS = new Set(['\n', '\r']); |
341 |
| - static NEWLINE_REGEXP = /\r\n|[\n\r]/g; |
342 |
| - |
343 |
| - buffer: string[]; |
344 |
| - trailingCR: boolean; |
345 |
| - textDecoder: any; // TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types. |
346 |
| - |
347 |
| - constructor() { |
348 |
| - this.buffer = []; |
349 |
| - this.trailingCR = false; |
350 |
| - } |
351 |
| - |
352 |
| - decode(chunk: Bytes): string[] { |
353 |
| - let text = this.decodeText(chunk); |
354 |
| - |
355 |
| - if (this.trailingCR) { |
356 |
| - text = '\r' + text; |
357 |
| - this.trailingCR = false; |
358 |
| - } |
359 |
| - if (text.endsWith('\r')) { |
360 |
| - this.trailingCR = true; |
361 |
| - text = text.slice(0, -1); |
362 |
| - } |
363 |
| - |
364 |
| - if (!text) { |
365 |
| - return []; |
366 |
| - } |
367 |
| - |
368 |
| - const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ''); |
369 |
| - let lines = text.split(LineDecoder.NEWLINE_REGEXP); |
370 |
| - |
371 |
| - // if there is a trailing new line then the last entry will be an empty |
372 |
| - // string which we don't care about |
373 |
| - if (trailingNewline) { |
374 |
| - lines.pop(); |
375 |
| - } |
376 |
| - |
377 |
| - if (lines.length === 1 && !trailingNewline) { |
378 |
| - this.buffer.push(lines[0]!); |
379 |
| - return []; |
380 |
| - } |
381 |
| - |
382 |
| - if (this.buffer.length > 0) { |
383 |
| - lines = [this.buffer.join('') + lines[0], ...lines.slice(1)]; |
384 |
| - this.buffer = []; |
385 |
| - } |
386 |
| - |
387 |
| - if (!trailingNewline) { |
388 |
| - this.buffer = [lines.pop() || '']; |
389 |
| - } |
390 |
| - |
391 |
| - return lines; |
392 |
| - } |
393 |
| - |
394 |
| - decodeText(bytes: Bytes): string { |
395 |
| - if (bytes == null) return ''; |
396 |
| - if (typeof bytes === 'string') return bytes; |
397 |
| - |
398 |
| - // Node: |
399 |
| - if (typeof Buffer !== 'undefined') { |
400 |
| - if (bytes instanceof Buffer) { |
401 |
| - return bytes.toString(); |
402 |
| - } |
403 |
| - if (bytes instanceof Uint8Array) { |
404 |
| - return Buffer.from(bytes).toString(); |
405 |
| - } |
406 |
| - |
407 |
| - throw new OpenAIError( |
408 |
| - `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`, |
409 |
| - ); |
410 |
| - } |
411 |
| - |
412 |
| - // Browser |
413 |
| - if (typeof TextDecoder !== 'undefined') { |
414 |
| - if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { |
415 |
| - this.textDecoder ??= new TextDecoder('utf8'); |
416 |
| - return this.textDecoder.decode(bytes); |
417 |
| - } |
418 |
| - |
419 |
| - throw new OpenAIError( |
420 |
| - `Unexpected: received non-Uint8Array/ArrayBuffer (${ |
421 |
| - (bytes as any).constructor.name |
422 |
| - }) in a web platform. Please report this error.`, |
423 |
| - ); |
424 |
| - } |
425 |
| - |
426 |
| - throw new OpenAIError( |
427 |
| - `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`, |
428 |
| - ); |
429 |
| - } |
430 |
| - |
431 |
| - flush(): string[] { |
432 |
| - if (!this.buffer.length && !this.trailingCR) { |
433 |
| - return []; |
434 |
| - } |
435 |
| - |
436 |
| - const lines = [this.buffer.join('')]; |
437 |
| - this.buffer = []; |
438 |
| - this.trailingCR = false; |
439 |
| - return lines; |
440 |
| - } |
441 |
| -} |
442 |
| - |
443 | 333 | /** This is an internal helper function that's just used for testing */
|
444 | 334 | export function _decodeChunks(chunks: string[]): string[] {
|
445 | 335 | const decoder = new LineDecoder();
|
|
0 commit comments