sera-ai 1.0.8 → 1.0.10
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/README.md +145 -0
- package/dist/index.d.mts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +881 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +882 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -254,6 +254,151 @@ The component includes comprehensive error handling:
|
|
|
254
254
|
/>
|
|
255
255
|
```
|
|
256
256
|
|
|
257
|
+
## Audio Capture Component
|
|
258
|
+
|
|
259
|
+
For applications that need to handle transcription on their own servers, use the `AudioCapture` component. This component records, processes, and compresses audio but returns the raw audio data instead of sending it for transcription.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import React from 'react';
|
|
263
|
+
import { AudioCapture } from 'sera-ai';
|
|
264
|
+
|
|
265
|
+
function AudioCaptureApp() {
|
|
266
|
+
const handleAudioChunk = (audioData: Float32Array, sequence: number, isFinal: boolean) => {
|
|
267
|
+
console.log(`Audio chunk ${sequence}:`, {
|
|
268
|
+
length: audioData.length,
|
|
269
|
+
duration: audioData.length / 44100,
|
|
270
|
+
isFinal
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Send to your own server for transcription
|
|
274
|
+
sendAudioToMyServer(audioData, sequence, isFinal);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const handleAudioComplete = (finalAudio: Float32Array) => {
|
|
278
|
+
console.log('Recording complete!', finalAudio.length);
|
|
279
|
+
// Send complete audio to your server
|
|
280
|
+
sendCompleteAudioToMyServer(finalAudio);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const handleAudioFile = (audioFile: File) => {
|
|
284
|
+
console.log('Audio file ready:', audioFile.name);
|
|
285
|
+
// Upload file to your server
|
|
286
|
+
uploadFileToMyServer(audioFile);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<div>
|
|
291
|
+
<h1>Custom Audio Processing</h1>
|
|
292
|
+
|
|
293
|
+
{/* Basic raw audio capture */}
|
|
294
|
+
<AudioCapture
|
|
295
|
+
onAudioChunk={handleAudioChunk}
|
|
296
|
+
onAudioComplete={handleAudioComplete}
|
|
297
|
+
chunkDuration={30}
|
|
298
|
+
format="raw"
|
|
299
|
+
showDownload={true}
|
|
300
|
+
/>
|
|
301
|
+
|
|
302
|
+
{/* Advanced capture with silence removal */}
|
|
303
|
+
<AudioCapture
|
|
304
|
+
onAudioFile={handleAudioFile}
|
|
305
|
+
silenceRemoval={true}
|
|
306
|
+
chunkDuration={15}
|
|
307
|
+
format="wav"
|
|
308
|
+
showDownload={true}
|
|
309
|
+
/>
|
|
310
|
+
</div>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### AudioCapture Props
|
|
316
|
+
|
|
317
|
+
| Prop | Type | Default | Description |
|
|
318
|
+
|------|------|---------|-------------|
|
|
319
|
+
| `onAudioChunk` | `(audioData: Float32Array, sequence: number, isFinal: boolean) => void` | - | Called for each audio chunk during recording |
|
|
320
|
+
| `onAudioComplete` | `(finalAudio: Float32Array) => void` | - | Called when recording stops with final combined audio |
|
|
321
|
+
| `onAudioFile` | `(audioFile: File) => void` | - | Called with processed audio file (raw or WAV) |
|
|
322
|
+
| `silenceRemoval` | `boolean` | `false` | Enable automatic silence removal processing |
|
|
323
|
+
| `chunkDuration` | `number` | `30` | Duration in seconds for each audio chunk |
|
|
324
|
+
| `format` | `"raw" \| "wav"` | `"raw"` | Output format for audio file |
|
|
325
|
+
| `showDownload` | `boolean` | `false` | Show download button for recorded audio |
|
|
326
|
+
| `className` | `string` | - | Additional CSS class names |
|
|
327
|
+
| `style` | `React.CSSProperties` | - | Custom styles |
|
|
328
|
+
|
|
329
|
+
### Server Integration Example
|
|
330
|
+
|
|
331
|
+
Here's how you can integrate the AudioCapture component with your own server:
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
// Client-side callback
|
|
335
|
+
const sendAudioToServer = async (audioData: Float32Array, sequence: number, isFinal: boolean) => {
|
|
336
|
+
// Convert Float32Array to WAV file for upload
|
|
337
|
+
const wavFile = createWavFileFromFloat32Array(audioData);
|
|
338
|
+
|
|
339
|
+
const formData = new FormData();
|
|
340
|
+
formData.append('audio', wavFile);
|
|
341
|
+
formData.append('sequence', sequence.toString());
|
|
342
|
+
formData.append('isFinal', isFinal.toString());
|
|
343
|
+
formData.append('patientId', 'patient-123');
|
|
344
|
+
formData.append('specialty', 'cardiology');
|
|
345
|
+
|
|
346
|
+
// Send to your server
|
|
347
|
+
const response = await fetch('/api/process-audio', {
|
|
348
|
+
method: 'POST',
|
|
349
|
+
body: formData
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const result = await response.json();
|
|
353
|
+
console.log('Server response:', result);
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
// Server-side processing (Node.js example)
|
|
359
|
+
app.post('/api/process-audio', upload.single('audio'), async (req, res) => {
|
|
360
|
+
try {
|
|
361
|
+
const { sequence, isFinal, patientId, specialty } = req.body;
|
|
362
|
+
const audioFile = req.file;
|
|
363
|
+
|
|
364
|
+
// Forward to Nuxera API for transcription
|
|
365
|
+
const transcriptionResponse = await fetch('https://nuxera.cloud/v1/transcribe', {
|
|
366
|
+
method: 'POST',
|
|
367
|
+
headers: {
|
|
368
|
+
'Authorization': `Bearer ${YOUR_API_KEY}`
|
|
369
|
+
},
|
|
370
|
+
body: createNuxeraFormData(audioFile, { patientId, specialty, sequence, isFinal })
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const transcription = await transcriptionResponse.json();
|
|
374
|
+
|
|
375
|
+
// Process and return results
|
|
376
|
+
res.json({
|
|
377
|
+
success: true,
|
|
378
|
+
transcription: transcription.text,
|
|
379
|
+
classification: transcription.classification,
|
|
380
|
+
sequence: parseInt(sequence)
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
} catch (error) {
|
|
384
|
+
res.status(500).json({ error: error.message });
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Audio Processing Features
|
|
390
|
+
|
|
391
|
+
The AudioCapture component provides the same advanced audio processing as AudioRecorder:
|
|
392
|
+
|
|
393
|
+
- **Real-time audio visualization** - Live waveform display during recording
|
|
394
|
+
- **Automatic silence removal** - Optional FFmpeg-based silence detection and removal
|
|
395
|
+
- **Audio compression** - Optimized audio encoding for efficient transmission
|
|
396
|
+
- **Chunk-based processing** - Configurable chunk duration for streaming or batch processing
|
|
397
|
+
- **Multiple output formats** - Raw Float32Array data or processed WAV files
|
|
398
|
+
- **Device management** - Automatic microphone detection and selection
|
|
399
|
+
- **Session recovery** - Built-in error handling and retry mechanisms
|
|
400
|
+
- **Audio level monitoring** - Real-time audio input level detection
|
|
401
|
+
|
|
257
402
|
## Audio Controls
|
|
258
403
|
|
|
259
404
|
The component provides built-in controls for:
|
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,7 @@ interface AudioRecorderProps {
|
|
|
7
7
|
patientId?: number;
|
|
8
8
|
patientName?: string;
|
|
9
9
|
patientHistory?: string;
|
|
10
|
+
selectedFormat?: "json" | "hl7" | "fhir";
|
|
10
11
|
onTranscriptionUpdate?: (text: string, sessionId: string) => void;
|
|
11
12
|
onTranscriptionComplete?: (text: string, classification: ClassificationInfoResponse, sessionId: string) => void;
|
|
12
13
|
onSuccess?: (data: any) => void;
|
|
@@ -57,4 +58,17 @@ interface AudioDictationProps {
|
|
|
57
58
|
}
|
|
58
59
|
declare const AudioDictation: React$1.FC<AudioDictationProps>;
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
interface AudioCaptureProps {
|
|
62
|
+
onAudioChunk?: (audioData: Float32Array, sequence: number, isFinal: boolean) => void;
|
|
63
|
+
onAudioComplete?: (finalAudio: Float32Array) => void;
|
|
64
|
+
onAudioFile?: (audioFile: File) => void;
|
|
65
|
+
silenceRemoval?: boolean;
|
|
66
|
+
chunkDuration?: number;
|
|
67
|
+
format?: "raw" | "wav";
|
|
68
|
+
showDownload?: boolean;
|
|
69
|
+
className?: string;
|
|
70
|
+
style?: React$1.CSSProperties;
|
|
71
|
+
}
|
|
72
|
+
declare const AudioCapture: React$1.FC<AudioCaptureProps>;
|
|
73
|
+
|
|
74
|
+
export { type APIOptions, type APIResponse, AudioCapture, type AudioCaptureProps, AudioDictation, type AudioDictationProps, AudioRecorder, type AudioRecorderProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ interface AudioRecorderProps {
|
|
|
7
7
|
patientId?: number;
|
|
8
8
|
patientName?: string;
|
|
9
9
|
patientHistory?: string;
|
|
10
|
+
selectedFormat?: "json" | "hl7" | "fhir";
|
|
10
11
|
onTranscriptionUpdate?: (text: string, sessionId: string) => void;
|
|
11
12
|
onTranscriptionComplete?: (text: string, classification: ClassificationInfoResponse, sessionId: string) => void;
|
|
12
13
|
onSuccess?: (data: any) => void;
|
|
@@ -57,4 +58,17 @@ interface AudioDictationProps {
|
|
|
57
58
|
}
|
|
58
59
|
declare const AudioDictation: React$1.FC<AudioDictationProps>;
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
interface AudioCaptureProps {
|
|
62
|
+
onAudioChunk?: (audioData: Float32Array, sequence: number, isFinal: boolean) => void;
|
|
63
|
+
onAudioComplete?: (finalAudio: Float32Array) => void;
|
|
64
|
+
onAudioFile?: (audioFile: File) => void;
|
|
65
|
+
silenceRemoval?: boolean;
|
|
66
|
+
chunkDuration?: number;
|
|
67
|
+
format?: "raw" | "wav";
|
|
68
|
+
showDownload?: boolean;
|
|
69
|
+
className?: string;
|
|
70
|
+
style?: React$1.CSSProperties;
|
|
71
|
+
}
|
|
72
|
+
declare const AudioCapture: React$1.FC<AudioCaptureProps>;
|
|
73
|
+
|
|
74
|
+
export { type APIOptions, type APIResponse, AudioCapture, type AudioCaptureProps, AudioDictation, type AudioDictationProps, AudioRecorder, type AudioRecorderProps };
|