| | const { Readable } = require('stream'); |
| | const { logger } = require('@librechat/data-schemas'); |
| |
|
| | class TextStream extends Readable { |
| | constructor(text, options = {}) { |
| | super(options); |
| | this.text = text; |
| | this.currentIndex = 0; |
| | this.minChunkSize = options.minChunkSize ?? 2; |
| | this.maxChunkSize = options.maxChunkSize ?? 4; |
| | this.delay = options.delay ?? 20; |
| | } |
| |
|
| | _read() { |
| | const { delay, minChunkSize, maxChunkSize } = this; |
| |
|
| | if (this.currentIndex < this.text.length) { |
| | setTimeout(() => { |
| | const remainingChars = this.text.length - this.currentIndex; |
| | const chunkSize = Math.min(this.randomInt(minChunkSize, maxChunkSize + 1), remainingChars); |
| |
|
| | const chunk = this.text.slice(this.currentIndex, this.currentIndex + chunkSize); |
| | this.push(chunk); |
| | this.currentIndex += chunkSize; |
| | }, delay); |
| | } else { |
| | this.push(null); |
| | } |
| | } |
| |
|
| | randomInt(min, max) { |
| | return Math.floor(Math.random() * (max - min)) + min; |
| | } |
| |
|
| | async processTextStream(onProgressCallback) { |
| | const streamPromise = new Promise((resolve, reject) => { |
| | this.on('data', (chunk) => { |
| | onProgressCallback(chunk.toString()); |
| | }); |
| |
|
| | this.on('end', () => { |
| | |
| | resolve(); |
| | }); |
| |
|
| | this.on('error', (err) => { |
| | reject(err); |
| | }); |
| | }); |
| |
|
| | try { |
| | await streamPromise; |
| | } catch (err) { |
| | logger.error('[processTextStream] Error in text stream:', err); |
| | |
| | } |
| | } |
| | } |
| |
|
| | module.exports = TextStream; |
| |
|