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.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
- this._buffer = [];
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
- // Log the request format
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) return;
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
- setIsProcessing(true);
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,