add mock video
This commit is contained in:
123
src/lib/replateStreamText.ts
Normal file
123
src/lib/replateStreamText.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
interface TextTransformStreamOptions {
|
||||
encoding?: string;
|
||||
handleSplitChunks?: boolean;
|
||||
bufferSize?: number;
|
||||
onError?: (error: Error) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Transformer để xử lý text transform
|
||||
*/
|
||||
class TextTransformer implements Transformer<Uint8Array, Uint8Array> {
|
||||
private buffer: string = '';
|
||||
private decoder: TextDecoder;
|
||||
private encoder: TextEncoder;
|
||||
|
||||
constructor(
|
||||
private transformFn: (text: string) => string,
|
||||
private options: Required<Omit<TextTransformStreamOptions, 'onError'>> & {
|
||||
onError?: (error: Error) => void;
|
||||
}
|
||||
) {
|
||||
this.decoder = new TextDecoder(this.options.encoding);
|
||||
this.encoder = new TextEncoder();
|
||||
}
|
||||
|
||||
transform(
|
||||
chunk: Uint8Array,
|
||||
controller: TransformStreamDefaultController<Uint8Array>
|
||||
): void {
|
||||
try {
|
||||
const chunkText = this.decoder.decode(chunk, { stream: true });
|
||||
const fullText = this.buffer + chunkText;
|
||||
this.buffer = '';
|
||||
|
||||
let processedText: string;
|
||||
try {
|
||||
processedText = this.transformFn(fullText);
|
||||
} catch (transformError) {
|
||||
this.handleError(transformError);
|
||||
processedText = fullText;
|
||||
}
|
||||
|
||||
if (this.options.handleSplitChunks) {
|
||||
this.handleSplitChunks(processedText, controller);
|
||||
} else {
|
||||
controller.enqueue(this.encoder.encode(processedText));
|
||||
}
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
controller.enqueue(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
flush(controller: TransformStreamDefaultController<Uint8Array>): void {
|
||||
try {
|
||||
if (this.buffer) {
|
||||
const finalText = this.decoder.decode();
|
||||
const remainingText = this.buffer + finalText;
|
||||
|
||||
if (remainingText) {
|
||||
let processedText: string;
|
||||
try {
|
||||
processedText = this.transformFn(remainingText);
|
||||
} catch (transformError) {
|
||||
this.handleError(transformError);
|
||||
processedText = remainingText;
|
||||
}
|
||||
controller.enqueue(this.encoder.encode(processedText));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
}
|
||||
}
|
||||
|
||||
private handleSplitChunks(
|
||||
text: string,
|
||||
controller: TransformStreamDefaultController<Uint8Array>
|
||||
): void {
|
||||
const lastNewline = text.lastIndexOf('\n');
|
||||
const lastSpace = text.lastIndexOf(' ');
|
||||
const lastBreak = Math.max(lastNewline, lastSpace);
|
||||
|
||||
if (lastBreak > text.length - this.options.bufferSize && lastBreak > 0) {
|
||||
const safePart = text.slice(0, lastBreak + 1);
|
||||
this.buffer = text.slice(lastBreak + 1);
|
||||
controller.enqueue(this.encoder.encode(safePart));
|
||||
} else {
|
||||
controller.enqueue(this.encoder.encode(text));
|
||||
}
|
||||
}
|
||||
|
||||
private handleError(error: unknown): void {
|
||||
if (this.options.onError) {
|
||||
this.options.onError(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cách 2: Sử dụng class Transformer
|
||||
*/
|
||||
export function createTextTransformStreamClass(
|
||||
inputStream: ReadableStream<Uint8Array>,
|
||||
transformFn: (text: string) => string,
|
||||
options: TextTransformStreamOptions = {}
|
||||
): ReadableStream<Uint8Array> {
|
||||
const {
|
||||
encoding = 'utf-8',
|
||||
handleSplitChunks = true,
|
||||
bufferSize = 1024,
|
||||
onError
|
||||
} = options;
|
||||
|
||||
const transformer = new TextTransformer(transformFn, {
|
||||
encoding,
|
||||
handleSplitChunks,
|
||||
bufferSize,
|
||||
onError
|
||||
});
|
||||
|
||||
return inputStream.pipeThrough(new TransformStream(transformer));
|
||||
}
|
||||
@@ -81,3 +81,12 @@ export const formatDate = (dateString?: string) => {
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
export const getStatusClass = (status?: string) => {
|
||||
switch (status?.toLowerCase()) {
|
||||
case 'ready': return 'bg-green-100 text-green-700';
|
||||
case 'processing': return 'bg-yellow-100 text-yellow-700';
|
||||
case 'failed': return 'bg-red-100 text-red-700';
|
||||
default: return 'bg-gray-100 text-gray-700';
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user