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 CHANGED
@@ -713,7 +713,7 @@ var useAudioRecovery = (reprocessSession) => {
713
713
  const store = transaction.objectStore(STORE_NAME);
714
714
  const session = {
715
715
  id: sessionId,
716
- audioChunks: [],
716
+ audioChunks: {},
717
717
  metadata: {
718
718
  ...metadata,
719
719
  timestamp: Date.now(),
@@ -2716,9 +2716,11 @@ var createAudioProcessorWorker = () => {
2716
2716
  }
2717
2717
 
2718
2718
  if (event.data.command === "resetUploadChunk") {
2719
+ // Only reset the upload flags, NOT the buffer
2720
+ // The buffer is cleared after chunk data is extracted and sent
2719
2721
  this._uploadChunk = false;
2720
2722
  this._uploadingChunk = false;
2721
- this._buffer = [];
2723
+ // NOTE: Do NOT clear buffer here - it's cleared in the chunk upload logic after data is sent
2722
2724
  }
2723
2725
 
2724
2726
  if (event.data.command === "pause") {
@@ -2866,6 +2868,7 @@ var useAudioRecorder = ({
2866
2868
  const [selectedModel, setSelectedModel] = React3__namespace.default.useState("new-large");
2867
2869
  const [isRetryingSession, setIsRetryingSession] = React3__namespace.default.useState(false);
2868
2870
  const [showRetrySessionPrompt, setShowRetrySessionPrompt] = React3__namespace.default.useState(false);
2871
+ const sessionHasFailedChunkRef = React3__namespace.default.useRef(false);
2869
2872
  const effectiveApiKey = apiKey;
2870
2873
  const {
2871
2874
  convertTranscriptionResponse,
@@ -2892,7 +2895,6 @@ var useAudioRecorder = ({
2892
2895
  markSessionFailed,
2893
2896
  retrySession,
2894
2897
  getFailedSession,
2895
- hasFailedSession,
2896
2898
  clearFailedSessions
2897
2899
  } = useAudioRecovery_default(async (audioChunks, metadata) => {
2898
2900
  try {
@@ -3055,15 +3057,6 @@ var useAudioRecorder = ({
3055
3057
  console.log("Speciality set, microphone validation will happen on recording start");
3056
3058
  }
3057
3059
  }, [speciality]);
3058
- React3__namespace.default.useEffect(() => {
3059
- const checkFailedSessions = async () => {
3060
- const failedSession = await hasFailedSession();
3061
- if (failedSession) {
3062
- setShowRetrySessionPrompt(true);
3063
- }
3064
- };
3065
- checkFailedSessions();
3066
- }, [hasFailedSession]);
3067
3060
  const clearAllSessions = React3__namespace.default.useCallback(async () => {
3068
3061
  await clearFailedSessions();
3069
3062
  setShowRetrySessionPrompt(false);
@@ -3078,8 +3071,8 @@ var useAudioRecorder = ({
3078
3071
  isFinalChunk,
3079
3072
  sequence,
3080
3073
  audioDataLength: audioData?.length,
3081
- requestFormat: selectedFormatRef.current
3082
- // Log the request format
3074
+ requestFormat: selectedFormatRef.current,
3075
+ sessionHasFailed: sessionHasFailedChunkRef.current
3083
3076
  });
3084
3077
  processorRef.current?.port.postMessage({ command: "resetUploadChunk" });
3085
3078
  if (audioData && localSessionIdRef.current && !retry) {
@@ -3093,6 +3086,14 @@ var useAudioRecorder = ({
3093
3086
  } else {
3094
3087
  console.log(`[DB] Skipping IndexedDB save: audioData=${!!audioData}, sessionId=${localSessionIdRef.current}, retry=${retry}`);
3095
3088
  }
3089
+ if (sessionHasFailedChunkRef.current && !retry) {
3090
+ console.log(`[SKIP] Session has failed chunk - skipping server upload for sequence ${sequence}, continuing to record audio`);
3091
+ if (isFinalChunk) {
3092
+ setShowRetrySessionPrompt(true);
3093
+ setIsProcessing(false);
3094
+ }
3095
+ return;
3096
+ }
3096
3097
  try {
3097
3098
  const data = await pRetry__default.default(
3098
3099
  async (attemptNumber) => {
@@ -3341,11 +3342,13 @@ var useAudioRecorder = ({
3341
3342
  }
3342
3343
  const isAbortError = err instanceof Error && err.name === "AbortError";
3343
3344
  const statusCode = err instanceof Error && err.message.includes("HTTP") ? parseInt(err.message.split("HTTP")[1].trim()) : null;
3344
- if (localSessionIdRef.current) {
3345
+ if (localSessionIdRef.current && !retry) {
3346
+ sessionHasFailedChunkRef.current = true;
3345
3347
  await markSessionFailed(
3346
3348
  localSessionIdRef.current,
3347
3349
  err instanceof Error ? err.message : "Unknown error"
3348
3350
  );
3351
+ console.log(`[FAIL] Chunk ${sequence} failed - session marked as failed, will continue recording audio locally`);
3349
3352
  if (isFinalChunk) {
3350
3353
  setShowRetrySessionPrompt(true);
3351
3354
  }
@@ -3436,16 +3439,12 @@ var useAudioRecorder = ({
3436
3439
  sequenceCounterRef.current = 0;
3437
3440
  nextExpectedSequenceRef.current = 0;
3438
3441
  receivedTranscriptionsRef.current.clear();
3442
+ sessionHasFailedChunkRef.current = false;
3443
+ chunkQueueRef.current = [];
3439
3444
  const localSessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3440
3445
  localSessionIdRef.current = localSessionId;
3441
3446
  sessionIdRef.current = null;
3442
3447
  console.log("Created local session ID for IndexedDB:", localSessionId);
3443
- await createSession(localSessionId, {
3444
- patientId,
3445
- patientName: patientName || void 0,
3446
- patientHistory: patientHistory || void 0,
3447
- speciality
3448
- });
3449
3448
  }
3450
3449
  const stream = await navigator.mediaDevices.getUserMedia({
3451
3450
  audio: {
@@ -3469,6 +3468,15 @@ var useAudioRecorder = ({
3469
3468
  });
3470
3469
  }
3471
3470
  const audioContext = new (window.AudioContext || window.webkitAudioContext)();
3471
+ if (!isPaused && localSessionIdRef.current) {
3472
+ await createSession(localSessionIdRef.current, {
3473
+ patientId,
3474
+ patientName: patientName || void 0,
3475
+ patientHistory: patientHistory || void 0,
3476
+ speciality,
3477
+ sampleRate: audioContext.sampleRate
3478
+ });
3479
+ }
3472
3480
  const processorUrl = createAudioProcessorWorker();
3473
3481
  await audioContext.audioWorklet.addModule(processorUrl);
3474
3482
  URL.revokeObjectURL(processorUrl);
@@ -3574,6 +3582,14 @@ var useAudioRecorder = ({
3574
3582
  }, 500);
3575
3583
  }
3576
3584
  setIsRecording(false);
3585
+ console.log("\u{1F50D} Stop recording - checking for failed session:", {
3586
+ hasSessionFailed: sessionHasFailedChunkRef.current,
3587
+ localSessionId: localSessionIdRef.current
3588
+ });
3589
+ if (sessionHasFailedChunkRef.current && localSessionIdRef.current) {
3590
+ console.log("\u26A0\uFE0F Recording stopped with failed session - showing retry UI");
3591
+ setShowRetrySessionPrompt(true);
3592
+ }
3577
3593
  }, [uploadChunkInterval]);
3578
3594
  React3__namespace.default.useEffect(() => {
3579
3595
  const handleDeviceChange = async () => {
@@ -3647,13 +3663,14 @@ var useAudioRecorder = ({
3647
3663
  }, 47e3);
3648
3664
  setUploadChunkInterval(intervalId);
3649
3665
  }, [isPaused]);
3650
- const processNextChunkInQueue = React3__namespace.default.useCallback(() => {
3651
- if (isProcessingQueueRef.current || chunkQueueRef.current.length === 0) return;
3666
+ const processNextChunkInQueue = React3__namespace.default.useCallback(async () => {
3667
+ if (isProcessingQueueRef.current || chunkQueueRef.current.length === 0) {
3668
+ return;
3669
+ }
3652
3670
  const { chunk, isFinal, sequence, isPaused: isPaused2 = false } = chunkQueueRef.current.shift();
3653
3671
  console.log(`[QUEUE] Processing chunk ${sequence} from queue, remaining: ${chunkQueueRef.current.length}`);
3654
3672
  isProcessingQueueRef.current = true;
3655
3673
  uploadChunkToServer(chunk, isFinal, sequence, false, isPaused2).finally(() => {
3656
- console.log(`[QUEUE] Finished processing chunk ${sequence}`);
3657
3674
  isProcessingQueueRef.current = false;
3658
3675
  processNextChunkInQueue();
3659
3676
  });
@@ -3662,7 +3679,11 @@ var useAudioRecorder = ({
3662
3679
  (audioData, isFinalChunk, sequence, isPausedChunk = false) => {
3663
3680
  console.log(`[QUEUE] Enqueuing ${isFinalChunk ? "FINAL" : isPausedChunk ? "PAUSED" : "regular"} chunk ${sequence}, samples: ${audioData?.length || 0}, queue size: ${chunkQueueRef.current.length}`);
3664
3681
  if (isFinalChunk) {
3665
- setIsProcessing(true);
3682
+ if (!sessionHasFailedChunkRef.current) {
3683
+ setIsProcessing(true);
3684
+ } else {
3685
+ console.log("\u26A0\uFE0F Session has failed - skipping processing state (IndexedDB save only)");
3686
+ }
3666
3687
  }
3667
3688
  chunkQueueRef.current.push({
3668
3689
  chunk: audioData,