@scribeberry/sdk 0.2.0 → 0.3.0

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 CHANGED
@@ -263,6 +263,66 @@ const result = await session.stop(); // Stop and get final result
263
263
 
264
264
  ---
265
265
 
266
+ ## React Hooks
267
+
268
+ The SDK includes optional React bindings via `@scribeberry/sdk/react`. These
269
+ handle microphone access, audio processing, and WebSocket streaming with a
270
+ simple hook interface.
271
+
272
+ > **Peer dependency:** Requires `react >= 18`.
273
+
274
+ ### `useTranscription(options)`
275
+
276
+ ```tsx
277
+ import { useTranscription } from '@scribeberry/sdk/react';
278
+
279
+ function Recorder() {
280
+ const {
281
+ status, // 'idle' | 'connecting' | 'recording' | 'error'
282
+ transcript, // Full confirmed transcript string
283
+ partial, // Interim text (updates rapidly, not yet confirmed)
284
+ segments, // All confirmed TranscriptSegment objects
285
+ error, // Error message or null
286
+ durationSeconds, // Session duration (available after stop)
287
+ start, // Start recording from microphone
288
+ stop, // Stop recording
289
+ clear, // Clear transcript and reset to idle
290
+ } = useTranscription({
291
+ getRealtimeToken: async () => {
292
+ const res = await fetch('/api/realtime-token', { method: 'POST' });
293
+ return res.json(); // { token, expiresAt }
294
+ },
295
+ language: 'en-US', // optional, default: 'en-US'
296
+ enableDiarization: true, // optional, default: true
297
+ });
298
+
299
+ return (
300
+ <div>
301
+ <button onClick={status === 'recording' ? stop : start}>
302
+ {status === 'recording' ? '⏹ Stop' : '🎙 Record'}
303
+ </button>
304
+ <p>
305
+ {transcript}
306
+ <span style={{ opacity: 0.5 }}>{partial}</span>
307
+ </p>
308
+ {transcript && <button onClick={clear}>Clear</button>}
309
+ </div>
310
+ );
311
+ }
312
+ ```
313
+
314
+ | Option | Type | Required | Description |
315
+ | ------------------- | ---------- | -------- | ------------------------------------------------------------ |
316
+ | `getRealtimeToken` | `function` | ✅ | Async callback returning `{ token, expiresAt }` from your server |
317
+ | `language` | `string` | | Language code (default: `en-US`) |
318
+ | `enableDiarization` | `boolean` | | Speaker identification (default: `true`) |
319
+
320
+ The hook manages the full lifecycle: microphone permissions → AudioWorklet
321
+ processing → WebSocket streaming → React state updates. Your API key never
322
+ leaves the server — only short-lived `sb_rt_*` tokens are used in the browser.
323
+
324
+ ---
325
+
266
326
  ## Audio Format Requirements
267
327
 
268
328
  For realtime transcription, audio must be:
package/dist/index.js CHANGED
@@ -28,15 +28,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
33
  AuthenticationError: () => AuthenticationError,
34
34
  RateLimitError: () => RateLimitError,
35
35
  RealtimeTranscriptionSession: () => RealtimeTranscriptionSession,
36
36
  Scribeberry: () => Scribeberry,
37
37
  ScribeberryError: () => ScribeberryError
38
38
  });
39
- module.exports = __toCommonJS(index_exports);
39
+ module.exports = __toCommonJS(src_exports);
40
40
 
41
41
  // src/lib/errors.ts
42
42
  var ScribeberryError = class extends Error {
@@ -0,0 +1,120 @@
1
+ /**
2
+ * A confirmed transcript segment from the realtime stream.
3
+ */
4
+ interface TranscriptSegment {
5
+ /** Confirmed text content. */
6
+ text: string;
7
+ /** Speaker identifier (if diarization is enabled). */
8
+ speaker?: number;
9
+ /** Segment start time in milliseconds from session start. */
10
+ startMs: number;
11
+ /** Segment end time in milliseconds from session start. */
12
+ endMs: number;
13
+ }
14
+
15
+ /**
16
+ * Result from a `getRealtimeToken` callback.
17
+ */
18
+ interface RealtimeTokenResult {
19
+ /** Temporary token prefixed with `sb_rt_`. */
20
+ token: string;
21
+ /** ISO 8601 expiration timestamp. */
22
+ expiresAt: string;
23
+ }
24
+
25
+ /** Status of the transcription session. */
26
+ type TranscriptionStatus = 'idle' | 'connecting' | 'recording' | 'error';
27
+ /** Configuration for `useTranscription`. */
28
+ interface UseTranscriptionOptions {
29
+ /**
30
+ * Async callback that returns a temporary realtime token from your server.
31
+ *
32
+ * This is called each time `start()` is invoked. Your server should call
33
+ * `sb.realtime.createToken()` with a full API key and return the result.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * useTranscription({
38
+ * getRealtimeToken: async () => {
39
+ * const res = await fetch('/api/realtime-token', { method: 'POST' });
40
+ * return res.json(); // { token, expiresAt }
41
+ * },
42
+ * });
43
+ * ```
44
+ */
45
+ getRealtimeToken: () => Promise<RealtimeTokenResult>;
46
+ /** Source language for transcription. Default: `'en-US'`. */
47
+ language?: string;
48
+ /** Enable speaker diarization. Default: `true`. */
49
+ enableDiarization?: boolean;
50
+ }
51
+ /** State returned by the `useTranscription` hook. */
52
+ interface TranscriptionState {
53
+ /** Current lifecycle status. */
54
+ status: TranscriptionStatus;
55
+ /** All confirmed transcript segments (stable text). */
56
+ segments: TranscriptSegment[];
57
+ /** Interim text that updates rapidly as words are recognized. */
58
+ partial: string;
59
+ /** Full confirmed transcript as a single string. */
60
+ transcript: string;
61
+ /** Session duration in seconds (available after stop). */
62
+ durationSeconds: number | null;
63
+ /** Error message if something went wrong, otherwise `null`. */
64
+ error: string | null;
65
+ }
66
+ /** Actions returned by the `useTranscription` hook. */
67
+ interface TranscriptionActions {
68
+ /** Request microphone access and start transcribing. */
69
+ start: () => Promise<void>;
70
+ /** Stop the session and release the microphone. */
71
+ stop: () => Promise<void>;
72
+ /** Clear all state and return to idle. */
73
+ clear: () => void;
74
+ }
75
+ /**
76
+ * React hook for realtime medical transcription.
77
+ *
78
+ * Manages the full lifecycle: microphone access → AudioWorklet processing →
79
+ * WebSocket streaming → transcript state. Your API key never leaves the
80
+ * server — the hook uses a token callback to obtain short-lived credentials.
81
+ *
82
+ * @param options - Configuration including the required `getRealtimeToken` callback.
83
+ * @returns Transcription state and actions (`start`, `stop`, `clear`).
84
+ *
85
+ * @example Basic usage
86
+ * ```tsx
87
+ * import { useTranscription } from '@scribeberry/sdk/react';
88
+ *
89
+ * function Recorder() {
90
+ * const { status, transcript, partial, start, stop, clear } = useTranscription({
91
+ * getRealtimeToken: async () => {
92
+ * const res = await fetch('/api/realtime-token', { method: 'POST' });
93
+ * return res.json();
94
+ * },
95
+ * });
96
+ *
97
+ * return (
98
+ * <div>
99
+ * <button onClick={status === 'recording' ? stop : start}>
100
+ * {status === 'recording' ? 'Stop' : 'Record'}
101
+ * </button>
102
+ * <p>{transcript}<span style={{ opacity: 0.5 }}>{partial}</span></p>
103
+ * {transcript && <button onClick={clear}>Clear</button>}
104
+ * </div>
105
+ * );
106
+ * }
107
+ * ```
108
+ *
109
+ * @example With language and diarization options
110
+ * ```tsx
111
+ * const transcription = useTranscription({
112
+ * getRealtimeToken: fetchToken,
113
+ * language: 'fr-FR',
114
+ * enableDiarization: false,
115
+ * });
116
+ * ```
117
+ */
118
+ declare function useTranscription(options: UseTranscriptionOptions): TranscriptionState & TranscriptionActions;
119
+
120
+ export { type TranscriptionActions, type TranscriptionState, type TranscriptionStatus, type UseTranscriptionOptions, useTranscription };
@@ -0,0 +1,120 @@
1
+ /**
2
+ * A confirmed transcript segment from the realtime stream.
3
+ */
4
+ interface TranscriptSegment {
5
+ /** Confirmed text content. */
6
+ text: string;
7
+ /** Speaker identifier (if diarization is enabled). */
8
+ speaker?: number;
9
+ /** Segment start time in milliseconds from session start. */
10
+ startMs: number;
11
+ /** Segment end time in milliseconds from session start. */
12
+ endMs: number;
13
+ }
14
+
15
+ /**
16
+ * Result from a `getRealtimeToken` callback.
17
+ */
18
+ interface RealtimeTokenResult {
19
+ /** Temporary token prefixed with `sb_rt_`. */
20
+ token: string;
21
+ /** ISO 8601 expiration timestamp. */
22
+ expiresAt: string;
23
+ }
24
+
25
+ /** Status of the transcription session. */
26
+ type TranscriptionStatus = 'idle' | 'connecting' | 'recording' | 'error';
27
+ /** Configuration for `useTranscription`. */
28
+ interface UseTranscriptionOptions {
29
+ /**
30
+ * Async callback that returns a temporary realtime token from your server.
31
+ *
32
+ * This is called each time `start()` is invoked. Your server should call
33
+ * `sb.realtime.createToken()` with a full API key and return the result.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * useTranscription({
38
+ * getRealtimeToken: async () => {
39
+ * const res = await fetch('/api/realtime-token', { method: 'POST' });
40
+ * return res.json(); // { token, expiresAt }
41
+ * },
42
+ * });
43
+ * ```
44
+ */
45
+ getRealtimeToken: () => Promise<RealtimeTokenResult>;
46
+ /** Source language for transcription. Default: `'en-US'`. */
47
+ language?: string;
48
+ /** Enable speaker diarization. Default: `true`. */
49
+ enableDiarization?: boolean;
50
+ }
51
+ /** State returned by the `useTranscription` hook. */
52
+ interface TranscriptionState {
53
+ /** Current lifecycle status. */
54
+ status: TranscriptionStatus;
55
+ /** All confirmed transcript segments (stable text). */
56
+ segments: TranscriptSegment[];
57
+ /** Interim text that updates rapidly as words are recognized. */
58
+ partial: string;
59
+ /** Full confirmed transcript as a single string. */
60
+ transcript: string;
61
+ /** Session duration in seconds (available after stop). */
62
+ durationSeconds: number | null;
63
+ /** Error message if something went wrong, otherwise `null`. */
64
+ error: string | null;
65
+ }
66
+ /** Actions returned by the `useTranscription` hook. */
67
+ interface TranscriptionActions {
68
+ /** Request microphone access and start transcribing. */
69
+ start: () => Promise<void>;
70
+ /** Stop the session and release the microphone. */
71
+ stop: () => Promise<void>;
72
+ /** Clear all state and return to idle. */
73
+ clear: () => void;
74
+ }
75
+ /**
76
+ * React hook for realtime medical transcription.
77
+ *
78
+ * Manages the full lifecycle: microphone access → AudioWorklet processing →
79
+ * WebSocket streaming → transcript state. Your API key never leaves the
80
+ * server — the hook uses a token callback to obtain short-lived credentials.
81
+ *
82
+ * @param options - Configuration including the required `getRealtimeToken` callback.
83
+ * @returns Transcription state and actions (`start`, `stop`, `clear`).
84
+ *
85
+ * @example Basic usage
86
+ * ```tsx
87
+ * import { useTranscription } from '@scribeberry/sdk/react';
88
+ *
89
+ * function Recorder() {
90
+ * const { status, transcript, partial, start, stop, clear } = useTranscription({
91
+ * getRealtimeToken: async () => {
92
+ * const res = await fetch('/api/realtime-token', { method: 'POST' });
93
+ * return res.json();
94
+ * },
95
+ * });
96
+ *
97
+ * return (
98
+ * <div>
99
+ * <button onClick={status === 'recording' ? stop : start}>
100
+ * {status === 'recording' ? 'Stop' : 'Record'}
101
+ * </button>
102
+ * <p>{transcript}<span style={{ opacity: 0.5 }}>{partial}</span></p>
103
+ * {transcript && <button onClick={clear}>Clear</button>}
104
+ * </div>
105
+ * );
106
+ * }
107
+ * ```
108
+ *
109
+ * @example With language and diarization options
110
+ * ```tsx
111
+ * const transcription = useTranscription({
112
+ * getRealtimeToken: fetchToken,
113
+ * language: 'fr-FR',
114
+ * enableDiarization: false,
115
+ * });
116
+ * ```
117
+ */
118
+ declare function useTranscription(options: UseTranscriptionOptions): TranscriptionState & TranscriptionActions;
119
+
120
+ export { type TranscriptionActions, type TranscriptionState, type TranscriptionStatus, type UseTranscriptionOptions, useTranscription };