sera-ai 1.0.10 → 1.0.12

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
@@ -2670,7 +2670,6 @@ var createAudioProcessorWorker = () => {
2670
2670
  this._recordingStartTime = Date.now();
2671
2671
  this._initialSilenceThreshold = 44100 * 10;
2672
2672
  this._isInitialPhase = true;
2673
- this._audioActivityBuffer = []; // Track recent audio activity
2674
2673
  this._bufferSize = 0; // Track total samples in buffer
2675
2674
 
2676
2675
  this.port.onmessage = (event) => {
@@ -2765,12 +2764,6 @@ var createAudioProcessorWorker = () => {
2765
2764
  this._isInitialPhase = false;
2766
2765
  this._silentSampleCount = 0;
2767
2766
  this._lastAudioTime = Date.now();
2768
-
2769
- // Track audio activity for chunk validation
2770
- this._audioActivityBuffer.push(audioLevel);
2771
- if (this._audioActivityBuffer.length > 1000) {
2772
- this._audioActivityBuffer.shift(); // Keep only recent activity
2773
- }
2774
2767
  } else {
2775
2768
  this._silentSampleCount += samples.length;
2776
2769
 
@@ -2795,43 +2788,36 @@ var createAudioProcessorWorker = () => {
2795
2788
 
2796
2789
  if (this._uploadChunk && !this._uploadingChunk) {
2797
2790
  this._uploadingChunk = true;
2798
-
2799
- // Check if buffer has meaningful audio content before uploading
2800
- const recentActivity = this._audioActivityBuffer.slice(-100); // Last 100 activity measurements
2801
- const hasRecentAudio = recentActivity.some(level => level > this._audioThreshold * 2);
2802
-
2791
+
2803
2792
  // Properly flatten the buffer by concatenating Float32Arrays
2804
2793
  let totalLength = 0;
2805
2794
  for (let i = 0; i < this._buffer.length; i++) {
2806
2795
  totalLength += this._buffer[i].length;
2807
2796
  }
2808
-
2797
+
2809
2798
  const flat = new Float32Array(totalLength);
2810
2799
  let offset = 0;
2811
2800
  for (let i = 0; i < this._buffer.length; i++) {
2812
2801
  flat.set(this._buffer[i], offset);
2813
2802
  offset += this._buffer[i].length;
2814
2803
  }
2815
-
2816
- // Only upload if we have recent audio activity or if this is a significant buffer
2817
- if (hasRecentAudio || this._bufferSize > 44100 * 30) { // 30 seconds minimum
2804
+
2805
+ // Always send chunks to server - let server handle silence filtering
2806
+ if (this._bufferSize > 0) {
2818
2807
  this.port.postMessage(
2819
2808
  {
2820
2809
  command: "chunk",
2821
2810
  audioBuffer: flat.buffer,
2822
- hasActivity: hasRecentAudio,
2823
2811
  bufferDuration: this._bufferSize / 44100
2824
2812
  },
2825
2813
  [flat.buffer]
2826
2814
  );
2827
- // Clear buffer after successful upload
2815
+ console.log('[UPLOAD] Sending chunk: ' + (this._bufferSize / 44100).toFixed(1) + 's');
2816
+ // Clear buffer after upload
2828
2817
  this._buffer = [];
2829
2818
  this._bufferSize = 0;
2830
- } else {
2831
- console.log('[SKIP] Skipping silent chunk upload (' + (this._bufferSize / 44100).toFixed(1) + 's, no recent activity)');
2832
- // Don't clear buffer for skipped chunks, keep accumulating
2833
2819
  }
2834
-
2820
+
2835
2821
  this._uploadChunk = false;
2836
2822
  this._uploadingChunk = false;
2837
2823
  }
@@ -3119,37 +3105,19 @@ var useAudioRecorder = ({
3119
3105
  console.log(
3120
3106
  `[PROCESSING] Processing audio chunk: ${audioData.length} samples (${(audioData.length / 44100).toFixed(2)}s)`
3121
3107
  );
3122
- let hasAudio = false;
3123
3108
  let maxAmplitude = 0;
3124
3109
  let nonZeroSamples = 0;
3125
3110
  for (let i = 0; i < audioData.length; i++) {
3126
3111
  const amplitude = Math.abs(audioData[i]);
3127
3112
  if (amplitude > maxAmplitude) maxAmplitude = amplitude;
3128
3113
  if (amplitude > 1e-3) {
3129
- hasAudio = true;
3130
3114
  nonZeroSamples++;
3131
3115
  }
3132
3116
  }
3133
3117
  const audioPercentage = nonZeroSamples / audioData.length;
3134
3118
  console.log(
3135
- `[AUDIO] Audio validation: hasAudio=${hasAudio}, maxAmplitude=${maxAmplitude.toFixed(4)}, audioContent=${(audioPercentage * 100).toFixed(2)}%`
3119
+ `[AUDIO] Audio stats: maxAmplitude=${maxAmplitude.toFixed(4)}, audioContent=${(audioPercentage * 100).toFixed(2)}%, sequence=${sequence}, isFinal=${isFinalChunk}`
3136
3120
  );
3137
- if (!hasAudio || maxAmplitude < 1e-3 || audioPercentage < 0.01) {
3138
- console.log(
3139
- `[SKIP] Skipping silent chunk (${audioPercentage < 0.01 ? "too little audio content" : "completely silent"})`
3140
- );
3141
- if (!isFinalChunk) {
3142
- console.log(`[OUT] Non-final silent chunk skipped entirely`);
3143
- return;
3144
- } else {
3145
- console.log(`[OUT] Final silent chunk - will send minimal audio to close session`);
3146
- const minimalAudio = new Float32Array(1e3);
3147
- for (let i = 0; i < minimalAudio.length; i += 100) {
3148
- minimalAudio[i] = 1e-3;
3149
- }
3150
- audioData = minimalAudio;
3151
- }
3152
- }
3153
3121
  const sampleRate = audioContextRef.current?.sampleRate || 16e3;
3154
3122
  const timestamp = Date.now();
3155
3123
  const fileName = `audio-chunk-${timestamp}.wav`;
@@ -3186,11 +3154,8 @@ var useAudioRecorder = ({
3186
3154
  `[OUT] Final file for transcription: ${wavFile.size} bytes, ${wavFile.name}`
3187
3155
  );
3188
3156
  if (wavFile.size < 500) {
3189
- console.error(
3190
- `[ERROR] File too small (${wavFile.size} bytes) - likely contains no audio data`
3191
- );
3192
- throw new Error(
3193
- `Audio file too small (${wavFile.size} bytes) - no meaningful audio content`
3157
+ console.warn(
3158
+ `[WARN] Small audio file (${wavFile.size} bytes) - may contain minimal audio data, sending to server anyway`
3194
3159
  );
3195
3160
  }
3196
3161
  const requestData = {
@@ -5045,22 +5010,6 @@ var AudioDictation = ({
5045
5010
  startDictating();
5046
5011
  }
5047
5012
  };
5048
- React3__namespace.useEffect(() => {
5049
- const handleKeyDown = (e) => {
5050
- if (e.code === "Space" && !e.repeat && !isProcessing) {
5051
- e.preventDefault();
5052
- if (isDictating) {
5053
- stopDictating();
5054
- } else {
5055
- startDictating();
5056
- }
5057
- }
5058
- };
5059
- document.addEventListener("keydown", handleKeyDown);
5060
- return () => {
5061
- document.removeEventListener("keydown", handleKeyDown);
5062
- };
5063
- }, [isDictating, isProcessing, startDictating, stopDictating]);
5064
5013
  const getButtonContent = () => {
5065
5014
  if (isProcessing) {
5066
5015
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 animate-spin" }) });