sera-ai 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +46 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -689,7 +689,7 @@ var useAudioRecovery = (reprocessSession) => {
|
|
|
689
689
|
const store = transaction.objectStore(STORE_NAME);
|
|
690
690
|
const session = {
|
|
691
691
|
id: sessionId,
|
|
692
|
-
audioChunks:
|
|
692
|
+
audioChunks: {},
|
|
693
693
|
metadata: {
|
|
694
694
|
...metadata,
|
|
695
695
|
timestamp: Date.now(),
|
|
@@ -2692,9 +2692,11 @@ var createAudioProcessorWorker = () => {
|
|
|
2692
2692
|
}
|
|
2693
2693
|
|
|
2694
2694
|
if (event.data.command === "resetUploadChunk") {
|
|
2695
|
+
// Only reset the upload flags, NOT the buffer
|
|
2696
|
+
// The buffer is cleared after chunk data is extracted and sent
|
|
2695
2697
|
this._uploadChunk = false;
|
|
2696
2698
|
this._uploadingChunk = false;
|
|
2697
|
-
|
|
2699
|
+
// NOTE: Do NOT clear buffer here - it's cleared in the chunk upload logic after data is sent
|
|
2698
2700
|
}
|
|
2699
2701
|
|
|
2700
2702
|
if (event.data.command === "pause") {
|
|
@@ -2842,6 +2844,7 @@ var useAudioRecorder = ({
|
|
|
2842
2844
|
const [selectedModel, setSelectedModel] = React3__default.useState("new-large");
|
|
2843
2845
|
const [isRetryingSession, setIsRetryingSession] = React3__default.useState(false);
|
|
2844
2846
|
const [showRetrySessionPrompt, setShowRetrySessionPrompt] = React3__default.useState(false);
|
|
2847
|
+
const sessionHasFailedChunkRef = React3__default.useRef(false);
|
|
2845
2848
|
const effectiveApiKey = apiKey;
|
|
2846
2849
|
const {
|
|
2847
2850
|
convertTranscriptionResponse,
|
|
@@ -2868,7 +2871,6 @@ var useAudioRecorder = ({
|
|
|
2868
2871
|
markSessionFailed,
|
|
2869
2872
|
retrySession,
|
|
2870
2873
|
getFailedSession,
|
|
2871
|
-
hasFailedSession,
|
|
2872
2874
|
clearFailedSessions
|
|
2873
2875
|
} = useAudioRecovery_default(async (audioChunks, metadata) => {
|
|
2874
2876
|
try {
|
|
@@ -3031,15 +3033,6 @@ var useAudioRecorder = ({
|
|
|
3031
3033
|
console.log("Speciality set, microphone validation will happen on recording start");
|
|
3032
3034
|
}
|
|
3033
3035
|
}, [speciality]);
|
|
3034
|
-
React3__default.useEffect(() => {
|
|
3035
|
-
const checkFailedSessions = async () => {
|
|
3036
|
-
const failedSession = await hasFailedSession();
|
|
3037
|
-
if (failedSession) {
|
|
3038
|
-
setShowRetrySessionPrompt(true);
|
|
3039
|
-
}
|
|
3040
|
-
};
|
|
3041
|
-
checkFailedSessions();
|
|
3042
|
-
}, [hasFailedSession]);
|
|
3043
3036
|
const clearAllSessions = React3__default.useCallback(async () => {
|
|
3044
3037
|
await clearFailedSessions();
|
|
3045
3038
|
setShowRetrySessionPrompt(false);
|
|
@@ -3054,8 +3047,8 @@ var useAudioRecorder = ({
|
|
|
3054
3047
|
isFinalChunk,
|
|
3055
3048
|
sequence,
|
|
3056
3049
|
audioDataLength: audioData?.length,
|
|
3057
|
-
requestFormat: selectedFormatRef.current
|
|
3058
|
-
|
|
3050
|
+
requestFormat: selectedFormatRef.current,
|
|
3051
|
+
sessionHasFailed: sessionHasFailedChunkRef.current
|
|
3059
3052
|
});
|
|
3060
3053
|
processorRef.current?.port.postMessage({ command: "resetUploadChunk" });
|
|
3061
3054
|
if (audioData && localSessionIdRef.current && !retry) {
|
|
@@ -3069,6 +3062,14 @@ var useAudioRecorder = ({
|
|
|
3069
3062
|
} else {
|
|
3070
3063
|
console.log(`[DB] Skipping IndexedDB save: audioData=${!!audioData}, sessionId=${localSessionIdRef.current}, retry=${retry}`);
|
|
3071
3064
|
}
|
|
3065
|
+
if (sessionHasFailedChunkRef.current && !retry) {
|
|
3066
|
+
console.log(`[SKIP] Session has failed chunk - skipping server upload for sequence ${sequence}, continuing to record audio`);
|
|
3067
|
+
if (isFinalChunk) {
|
|
3068
|
+
setShowRetrySessionPrompt(true);
|
|
3069
|
+
setIsProcessing(false);
|
|
3070
|
+
}
|
|
3071
|
+
return;
|
|
3072
|
+
}
|
|
3072
3073
|
try {
|
|
3073
3074
|
const data = await pRetry(
|
|
3074
3075
|
async (attemptNumber) => {
|
|
@@ -3317,11 +3318,13 @@ var useAudioRecorder = ({
|
|
|
3317
3318
|
}
|
|
3318
3319
|
const isAbortError = err instanceof Error && err.name === "AbortError";
|
|
3319
3320
|
const statusCode = err instanceof Error && err.message.includes("HTTP") ? parseInt(err.message.split("HTTP")[1].trim()) : null;
|
|
3320
|
-
if (localSessionIdRef.current) {
|
|
3321
|
+
if (localSessionIdRef.current && !retry) {
|
|
3322
|
+
sessionHasFailedChunkRef.current = true;
|
|
3321
3323
|
await markSessionFailed(
|
|
3322
3324
|
localSessionIdRef.current,
|
|
3323
3325
|
err instanceof Error ? err.message : "Unknown error"
|
|
3324
3326
|
);
|
|
3327
|
+
console.log(`[FAIL] Chunk ${sequence} failed - session marked as failed, will continue recording audio locally`);
|
|
3325
3328
|
if (isFinalChunk) {
|
|
3326
3329
|
setShowRetrySessionPrompt(true);
|
|
3327
3330
|
}
|
|
@@ -3412,16 +3415,12 @@ var useAudioRecorder = ({
|
|
|
3412
3415
|
sequenceCounterRef.current = 0;
|
|
3413
3416
|
nextExpectedSequenceRef.current = 0;
|
|
3414
3417
|
receivedTranscriptionsRef.current.clear();
|
|
3418
|
+
sessionHasFailedChunkRef.current = false;
|
|
3419
|
+
chunkQueueRef.current = [];
|
|
3415
3420
|
const localSessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
3416
3421
|
localSessionIdRef.current = localSessionId;
|
|
3417
3422
|
sessionIdRef.current = null;
|
|
3418
3423
|
console.log("Created local session ID for IndexedDB:", localSessionId);
|
|
3419
|
-
await createSession(localSessionId, {
|
|
3420
|
-
patientId,
|
|
3421
|
-
patientName: patientName || void 0,
|
|
3422
|
-
patientHistory: patientHistory || void 0,
|
|
3423
|
-
speciality
|
|
3424
|
-
});
|
|
3425
3424
|
}
|
|
3426
3425
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
3427
3426
|
audio: {
|
|
@@ -3445,6 +3444,15 @@ var useAudioRecorder = ({
|
|
|
3445
3444
|
});
|
|
3446
3445
|
}
|
|
3447
3446
|
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
3447
|
+
if (!isPaused && localSessionIdRef.current) {
|
|
3448
|
+
await createSession(localSessionIdRef.current, {
|
|
3449
|
+
patientId,
|
|
3450
|
+
patientName: patientName || void 0,
|
|
3451
|
+
patientHistory: patientHistory || void 0,
|
|
3452
|
+
speciality,
|
|
3453
|
+
sampleRate: audioContext.sampleRate
|
|
3454
|
+
});
|
|
3455
|
+
}
|
|
3448
3456
|
const processorUrl = createAudioProcessorWorker();
|
|
3449
3457
|
await audioContext.audioWorklet.addModule(processorUrl);
|
|
3450
3458
|
URL.revokeObjectURL(processorUrl);
|
|
@@ -3550,6 +3558,14 @@ var useAudioRecorder = ({
|
|
|
3550
3558
|
}, 500);
|
|
3551
3559
|
}
|
|
3552
3560
|
setIsRecording(false);
|
|
3561
|
+
console.log("\u{1F50D} Stop recording - checking for failed session:", {
|
|
3562
|
+
hasSessionFailed: sessionHasFailedChunkRef.current,
|
|
3563
|
+
localSessionId: localSessionIdRef.current
|
|
3564
|
+
});
|
|
3565
|
+
if (sessionHasFailedChunkRef.current && localSessionIdRef.current) {
|
|
3566
|
+
console.log("\u26A0\uFE0F Recording stopped with failed session - showing retry UI");
|
|
3567
|
+
setShowRetrySessionPrompt(true);
|
|
3568
|
+
}
|
|
3553
3569
|
}, [uploadChunkInterval]);
|
|
3554
3570
|
React3__default.useEffect(() => {
|
|
3555
3571
|
const handleDeviceChange = async () => {
|
|
@@ -3623,13 +3639,14 @@ var useAudioRecorder = ({
|
|
|
3623
3639
|
}, 47e3);
|
|
3624
3640
|
setUploadChunkInterval(intervalId);
|
|
3625
3641
|
}, [isPaused]);
|
|
3626
|
-
const processNextChunkInQueue = React3__default.useCallback(() => {
|
|
3627
|
-
if (isProcessingQueueRef.current || chunkQueueRef.current.length === 0)
|
|
3642
|
+
const processNextChunkInQueue = React3__default.useCallback(async () => {
|
|
3643
|
+
if (isProcessingQueueRef.current || chunkQueueRef.current.length === 0) {
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3628
3646
|
const { chunk, isFinal, sequence, isPaused: isPaused2 = false } = chunkQueueRef.current.shift();
|
|
3629
3647
|
console.log(`[QUEUE] Processing chunk ${sequence} from queue, remaining: ${chunkQueueRef.current.length}`);
|
|
3630
3648
|
isProcessingQueueRef.current = true;
|
|
3631
3649
|
uploadChunkToServer(chunk, isFinal, sequence, false, isPaused2).finally(() => {
|
|
3632
|
-
console.log(`[QUEUE] Finished processing chunk ${sequence}`);
|
|
3633
3650
|
isProcessingQueueRef.current = false;
|
|
3634
3651
|
processNextChunkInQueue();
|
|
3635
3652
|
});
|
|
@@ -3638,7 +3655,11 @@ var useAudioRecorder = ({
|
|
|
3638
3655
|
(audioData, isFinalChunk, sequence, isPausedChunk = false) => {
|
|
3639
3656
|
console.log(`[QUEUE] Enqueuing ${isFinalChunk ? "FINAL" : isPausedChunk ? "PAUSED" : "regular"} chunk ${sequence}, samples: ${audioData?.length || 0}, queue size: ${chunkQueueRef.current.length}`);
|
|
3640
3657
|
if (isFinalChunk) {
|
|
3641
|
-
|
|
3658
|
+
if (!sessionHasFailedChunkRef.current) {
|
|
3659
|
+
setIsProcessing(true);
|
|
3660
|
+
} else {
|
|
3661
|
+
console.log("\u26A0\uFE0F Session has failed - skipping processing state (IndexedDB save only)");
|
|
3662
|
+
}
|
|
3642
3663
|
}
|
|
3643
3664
|
chunkQueueRef.current.push({
|
|
3644
3665
|
chunk: audioData,
|