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