fix: stt streaming response handler
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
fetchChunkedDataPostFormData,
|
||||
readStreamData
|
||||
} from '@/utils/fetch-chunk-data';
|
||||
import _ from 'lodash';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { AUDIO_SPEECH_TO_TEXT_API } from '../../apis';
|
||||
import { extractErrorMessage } from '../../config';
|
||||
@@ -72,30 +73,29 @@ export const useStreamSTT = (params?: UseStreamSTTParams) => {
|
||||
await readStreamData(
|
||||
reader,
|
||||
decoder,
|
||||
(chunks: any[]) => {
|
||||
chunks.forEach((chunk) => {
|
||||
if (chunk.error) {
|
||||
const errorMessage = extractErrorMessage(chunk.error);
|
||||
setError({
|
||||
error: true,
|
||||
errorMessage
|
||||
});
|
||||
params?.onError?.(errorMessage);
|
||||
return;
|
||||
}
|
||||
(chunk: any) => {
|
||||
if (chunk.error) {
|
||||
const errorMessage = extractErrorMessage(chunk.error);
|
||||
setError({
|
||||
error: true,
|
||||
errorMessage
|
||||
});
|
||||
params?.onError?.(errorMessage);
|
||||
return;
|
||||
} else {
|
||||
const deltaContent =
|
||||
_.get(chunk, 'choices.0.delta.content', '') === null
|
||||
? ''
|
||||
: _.get(chunk, 'choices.0.delta.content', '');
|
||||
|
||||
// STT stream response format: { text: "..." }
|
||||
if (chunk.text) {
|
||||
fullText += chunk.text;
|
||||
params?.onChunk?.(fullText);
|
||||
setProgress((prev) => prev + 1);
|
||||
}
|
||||
});
|
||||
fullText += deltaContent;
|
||||
params?.onChunk?.(fullText);
|
||||
setProgress((prev) => prev + 1);
|
||||
}
|
||||
},
|
||||
100 // throttle delay
|
||||
100
|
||||
);
|
||||
|
||||
// Stream completed
|
||||
params?.onComplete?.(fullText);
|
||||
} catch (err: any) {
|
||||
if (err.name === 'AbortError') {
|
||||
|
||||
@@ -68,7 +68,6 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
|
||||
const { initialize, updateScrollerPosition } = useOverlayScroller();
|
||||
|
||||
// Initialize non-stream STT hook
|
||||
const nonStreamSTT = useNonStreamSTT({
|
||||
onSuccess: (result) => {
|
||||
setMessageList([
|
||||
@@ -86,10 +85,8 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize stream STT hook
|
||||
const streamSTT = useStreamSTT({
|
||||
onChunk: (text) => {
|
||||
// Update message list with streaming text
|
||||
setMessageList([
|
||||
{
|
||||
content: text,
|
||||
@@ -158,12 +155,9 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
})
|
||||
};
|
||||
|
||||
// Choose stream or non-stream based on parameters
|
||||
if (parameters.stream) {
|
||||
// Stream mode: text will be updated in real-time
|
||||
await streamSTT.generate(params);
|
||||
} else {
|
||||
// Non-stream mode: get complete text at once
|
||||
await nonStreamSTT.generate(params, getCanceltToken());
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -417,7 +411,7 @@ const GroundSTT: React.FC<MessageProps> = forwardRef((props, ref) => {
|
||||
<div
|
||||
style={{
|
||||
padding: '8px 14px',
|
||||
lineHeight: '20px',
|
||||
lineHeight: '22px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word'
|
||||
|
||||
@@ -178,6 +178,19 @@ export const readStreamData = async (
|
||||
try {
|
||||
textBuffer += decoder.decode(value, { stream: true });
|
||||
|
||||
// Check if it's a pure JSON error response (not SSE format)
|
||||
if (!textBuffer.startsWith('data:') && !textBuffer.startsWith('error:')) {
|
||||
try {
|
||||
const jsonData = JSON.parse(textBuffer);
|
||||
bufferManager.add({ error: jsonData });
|
||||
textBuffer = '';
|
||||
throttledCallback();
|
||||
continue;
|
||||
} catch {
|
||||
// Not a complete JSON yet, might be SSE format or incomplete data
|
||||
}
|
||||
}
|
||||
|
||||
if (textBuffer.startsWith('error:')) {
|
||||
const errorStr = textBuffer.slice(7).trim();
|
||||
const jsonData = JSON.parse(errorStr);
|
||||
|
||||
Reference in New Issue
Block a user