@eka-care/ekascribe-ts-sdk 3.0.23 → 3.0.24

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
@@ -1,29 +1,17 @@
1
- # Eka Care Ekascribe Typescript SDK Integration
1
+ # EkaScribe TypeScript SDK
2
2
 
3
- This guide explains how to integrate the Eka Care Ekascribe Typescript SDK into your application.
4
-
5
- ## Overview
6
-
7
- The Eka Care Ekascribe SDK allows you to capture and process audio, generating structured medical documentation using Eka Care's voice transcription API.
8
-
9
- ## Documentation
10
-
11
- [Visit the documentation site](https://developer.eka.care/api-reference/health-ai/ekascribe/SDKs/TS-sdk)
3
+ Browser SDK for capturing audio and generating structured medical documentation using Eka Care's voice transcription API.
12
4
 
13
5
  ## Prerequisites
14
6
 
15
- Before getting started, ensure you have:
16
-
17
- - Node 14 or higher
18
- - `npm` or `yarn` for dependency management
19
- - Access and refresh tokens from Eka Care (optional for some methods)
7
+ - Node 14+
8
+ - `npm` or `yarn`
20
9
  - Microphone access via browser permissions
21
10
  - Stable network connectivity
11
+ - Access token from Eka Care
22
12
 
23
13
  ## Installation
24
14
 
25
- Install the SDK using `npm` or `yarn`:
26
-
27
15
  ```bash
28
16
  npm install @eka-care/ekascribe-ts-sdk
29
17
  # or
@@ -32,20 +20,19 @@ yarn add @eka-care/ekascribe-ts-sdk
32
20
 
33
21
  ## Bundler Setup
34
22
 
35
- The SDK uses a SharedWorker for background audio uploads. Modern bundlers (Webpack 5, Vite) automatically handle the worker bundling.
23
+ The SDK uses a SharedWorker for background audio uploads. Modern bundlers handle this automatically.
36
24
 
37
25
  ### Vite
38
26
 
39
- Works out of the box - no configuration needed.
27
+ Works out of the box.
40
28
 
41
29
  ```ts
42
- // Just import and use
43
30
  import { getEkaScribeInstance } from '@eka-care/ekascribe-ts-sdk';
44
31
  ```
45
32
 
46
33
  ### Webpack 5
47
34
 
48
- Works out of the box with default configuration. The `new URL(..., import.meta.url)` pattern is natively supported.
35
+ Works out of the box. The `new URL(..., import.meta.url)` pattern is natively supported.
49
36
 
50
37
  ```ts
51
38
  import { getEkaScribeInstance } from '@eka-care/ekascribe-ts-sdk';
@@ -53,1591 +40,1141 @@ import { getEkaScribeInstance } from '@eka-care/ekascribe-ts-sdk';
53
40
 
54
41
  ### Next.js
55
42
 
56
- For Next.js projects, ensure the SDK is only used on the client side:
43
+ Ensure the SDK is only used on the client side:
57
44
 
58
45
  ```tsx
59
46
  'use client';
60
47
 
61
48
  import { getEkaScribeInstance } from '@eka-care/ekascribe-ts-sdk';
62
-
63
- // Use inside a client component
64
- const ekascribe = getEkaScribeInstance({ access_token: 'your_token' });
65
49
  ```
66
50
 
67
51
  ### Browser (Script Tag)
68
52
 
69
- For direct browser usage without a bundler:
70
-
71
53
  ```html
72
54
  <script type="module">
73
55
  import { getEkaScribeInstance } from 'https://cdn.jsdelivr.net/npm/@eka-care/ekascribe-ts-sdk/dist/index.mjs';
74
-
75
- const ekascribe = getEkaScribeInstance({ access_token: 'your_token' });
76
56
  </script>
77
57
  ```
78
58
 
79
- ## Usage
59
+ ---
80
60
 
81
- ### 1. Get Ekascribe Instance
61
+ ## Instance Management
82
62
 
83
- Get the SDK instance once and use it everywhere in your application to call all methods.
63
+ The SDK uses a **singleton pattern**. `getEkaScribeInstance()` always returns the same instance for a given `env` + `clientId` combination.
84
64
 
85
65
  ```ts
86
- // Create a config variable to manage tokens
87
- const sdkConfig = {
88
- access_token: '<your_access_token>',
89
- };
90
-
91
- // Get instance and use it throughout your application
92
- const ekascribe = getEkaScribeInstance(sdkConfig);
66
+ const ekascribe = getEkaScribeInstance(config);
93
67
  ```
94
68
 
95
- **Important:** Use this same `ekascribe` instance for all SDK method calls.
69
+ - Calling `getEkaScribeInstance()` multiple times with the same config returns the same instance.
70
+ - If `env` or `clientId` changes, the old instance is automatically reset.
71
+ - If only `access_token` changes, the token is updated on the existing instance without resetting.
72
+ - The SDK supports **one active recording at a time**. Always call `endRecording()` or `cancelSession()` before starting a new recording. If you call `startRecordingV2()` while a recording is active, the SDK cleans up the old recording locally but does **not** end the session on the server — the old session will be left abandoned until it expires.
96
73
 
97
- ### 2. Fetch configurations list
74
+ ---
98
75
 
99
- Get supported input languages, output formats, and consultation modes.
100
-
101
- ```ts
102
- const config = await ekascribe.getEkascribeConfig();
103
- ```
76
+ ## Integration Guide
104
77
 
105
- - #### Sample Response:
78
+ ### Step 1: Initialize the SDK
106
79
 
107
80
  ```ts
108
- {
109
- "data": {
110
- "supported_languages": [
111
- { "id": "en", "name": "English" },
112
- { "id": "hi", "name": "Hindi" }
113
- ],
114
- "supported_output_formats": [{ "id": "clinical-notes-template", "name": "Clinical Notes" }],
115
- "consultation_modes": [
116
- {
117
- "id": "consultation",
118
- "name": "Consultation",
119
- "desc": "Eka Scribe will listen to your conversation and create clinical notes"
120
- }
121
- ],
122
- "max_selection": {
123
- "supported_languages": 2,
124
- "supported_output_formats": 2,
125
- "consultation_modes": 1
126
- },
127
- "user_details": {
128
- "fn": "Dr. John",
129
- "mn": "",
130
- "ln": "Doe",
131
- "dob": "1985-06-15",
132
- "gen": "M",
133
- "s": "active",
134
- "is_paid_doc": true,
135
- "uuid": "user-uuid-123"
136
- },
137
- "wid": "workspace-id-456"
138
- },
139
- "message": "Configuration fetched successfully",
140
- "code": 200
141
- }
142
- ```
143
-
144
- ### 3. Fetch user's favorite templates
145
-
146
- Get the list of templates marked as favorites by the user (configured via `my_templates` in the config).
147
-
148
- ```ts
149
- const myTemplates = await ekascribe.getConfigMyTemplates();
150
- ```
151
-
152
- - #### Sample Response:
81
+ import { getEkaScribeInstance } from '@eka-care/ekascribe-ts-sdk';
82
+ import type { EkaScribeConfig } from '@eka-care/ekascribe-ts-sdk';
153
83
 
154
- ```ts
155
- {
156
- "data": {
157
- "my_templates": [
158
- {
159
- "id": "template_123",
160
- "name": "General Consultation"
161
- },
162
- {
163
- "id": "template_456",
164
- "name": "Cardiology Template"
165
- }
166
- ],
84
+ const config: EkaScribeConfig = {
85
+ access_token: '<your_access_token>',
86
+ env: 'PROD', // 'PROD' | 'DEV'
87
+ clientId: '<your_client_id>', // optional
88
+ allianceConfig: {
89
+ baseUrl: 'https://api.eka.care/voice/v1', // required
90
+ useWorker: 'auto', // optional: true | false | 'auto'
91
+ debug: false, // optional
167
92
  },
168
- "message": "Configuration fetched successfully",
169
- "code": 200
170
- }
171
- ```
172
-
173
- **Note:** The `my_templates` field contains templates that were previously saved using the `updateConfig()` method (see Templates SDK Methods section).
174
-
175
- ### 4. Init transaction
176
-
177
- Initialize a transaction before starting recording. This sets up the session with your configuration.
93
+ sharedWorkerUrl: workerUrl, // optional — see SharedWorker section
94
+ };
178
95
 
179
- ```ts
180
- const response = await ekascribe.initTransaction({
181
- mode: 'consultation',
182
- input_language: ['en-IN'],
183
- output_format_template: [{
184
- template_id: 'your_template_id',
185
- codification_needed?: true // optional
186
- }],
187
- txn_id: 'unique-transaction-id',
188
- transfer: 'vaded' | 'non-vaded',
189
- model_type: 'pro' | 'lite',
190
- system_info: {
191
- platform: 'web',
192
- language: 'en',
193
- time_zone: 'Asia/Kolkata',
194
- },
195
- patient_details: {
196
- username: 'John Doe',
197
- age: 35,
198
- biologicalSex: 'M',
199
- },
200
- version: '1.0.0',
201
- additional_data: {},
202
- },
203
- sharedWorkerUrl: 'worker-url', // optional - see Shared Worker Configuration below
204
- );
96
+ const ekascribe = getEkaScribeInstance(config);
205
97
  ```
206
98
 
207
- **Key Parameters:**
208
-
209
- - `input_language`: Language code array (e.g., `['en-IN']`)
210
- - `output_format_template`: Array with `template_id` - depends on your end user's template selection
211
- - `system_info`: Optional - Pass your system configuration to backend
212
- - `patient_details`: Optional - Patient information
213
- - `version`: SDK version
214
- - `additional_data`: Optional - Pass any data you want to receive unchanged in the response
215
- - `transfer`: Audio mode. Use `vaded` for audio already processed with Voice Activity Detection (SDK does this by default); use `non-vaded` only if you are sending raw audio without VAD.
216
- - `model_type`: Transcription model choice. `pro` = most accurate; `lite` = lower latency, more performant.
217
- - `sharedWorkerUrl`: Optional - Custom URL for the shared worker script. See **Shared Worker Configuration** section below for usage details.
218
-
219
- - #### Sample Response:
99
+ #### `EkaScribeConfig`
220
100
 
221
101
  ```ts
222
- {
223
- error_code?: ERROR_CODE,
224
- status_code: 200,
225
- message: "Transaction initialized successfully",
226
- business_id: "biz_abc123def456",
227
- txn_id: "abc-123",
228
- oid: "org_789xyz",
229
- uuid: "user_uuid_456"
102
+ interface EkaScribeConfig {
103
+ access_token?: string; // Bearer token for authentication
104
+ env: 'PROD' | 'DEV'; // Environment
105
+ clientId?: string; // Your client identifier
106
+ mode?: 'http' | 'ipc'; // Transport mode (default: 'http')
107
+ ipcBridge?: IpcBridge; // Required when mode is 'ipc' (Electron apps)
108
+ enableTracking?: boolean; // Enable internal analytics tracking
109
+ flavour?: string; // Client flavour identifier
110
+ sharedWorkerUrl?: string; // URL to worker.bundle.js for background uploads
111
+ allianceConfig?: {
112
+ baseUrl?: string; // Scribe service URL (required)
113
+ useWorker?: boolean | 'auto'; // SharedWorker: true | false | 'auto' (default: 'auto')
114
+ debug?: boolean; // Enable debug logging (default: false)
115
+ };
116
+ widget?: WidgetConfig; // Widget configuration — see Widget section
230
117
  }
231
118
  ```
232
119
 
233
- **Error handling:**
234
-
235
- Possible Error Codes in `error_code`:
236
-
237
- - `txn_limit_exceeded`: Maximum number of transactions exceeded
238
- - `txn_init_failed`: Something went wrong. Retry with the same method call
239
-
240
- **Handling 401 Status Code:**
120
+ ### Step 2: Register Callbacks
241
121
 
242
- If you receive a `status_code: 401`, update the tokens in your config and reinitialize the instance:
122
+ Register callbacks **before** starting a recording. Events fire immediately once recording starts.
243
123
 
244
124
  ```ts
245
- // Update tokens in your config variable
246
- sdkConfig.access_token = '<new_access_token>';
125
+ import type { EkaCallbackMap } from '@eka-care/ekascribe-ts-sdk';
247
126
 
248
- // Update tokens in the instance
249
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
127
+ // Token refresh SDK calls this automatically on 401
128
+ ekascribe.registerCallback('onTokenRequired', async () => {
129
+ const newToken = await fetchFreshToken(); // your token refresh logic
130
+ return newToken; // must return the new token string
131
+ });
250
132
 
251
- // Now you can retry the method call
252
- const response = await ekascribe.initTransaction({ ... });
253
- ```
133
+ // Recording state changes
134
+ ekascribe.registerCallback('onRecordingStateChange', (event) => {
135
+ console.log('State:', event.type); // 'started' | 'paused' | 'resumed' | 'ended'
136
+ });
254
137
 
255
- #### Shared Worker Configuration
138
+ // Upload progress
139
+ ekascribe.registerCallback('onUploadEvent', (event) => {
140
+ if (event.type === 'progress') {
141
+ console.log(`Uploaded ${event.data.successCount}/${event.data.totalCount}`);
142
+ }
143
+ });
256
144
 
257
- The SDK supports using a shared worker for efficient background audio file uploads. If you provide a `sharedWorkerUrl`, the SDK will use a shared worker for file uploads. If not provided, the SDK will use the main thread for file uploads.
145
+ // Errors
146
+ ekascribe.registerCallback('onError', (event) => {
147
+ console.error(`[${event.error.code}] ${event.error.message}`);
148
+ });
149
+ ```
258
150
 
259
- **Why use Shared Worker:**
151
+ See [Callbacks Reference](#callbacks-reference) for all callback types and payloads.
260
152
 
261
- - **Better Performance**: Offloads file uploads to a background thread, keeping the main thread free for UI interactions
262
- - **Resource Efficiency**: A single shared worker instance can handle uploads across multiple tabs/windows
263
- - **Improved User Experience**: Prevents UI blocking during large file uploads
153
+ ### Step 3: Start Recording
264
154
 
265
- **How to configure:**
155
+ Creates a session and starts the microphone in one call.
266
156
 
267
157
  ```ts
268
- // Step 1: Create a function to fetch and prepare the worker URL
269
- async function getSharedWorkerUrl() {
270
- // Fetch the worker script from CDN (or your own hosting) - update the latest sdk version
271
- const workerScriptResponse = await fetch(
272
- 'https://cdn.jsdelivr.net/npm/@eka-care/ekascribe-ts-sdk@2.0.48/dist/worker.bundle.js'
273
- );
274
- const workerScript = await workerScriptResponse.text();
158
+ import type { RecordingOptions } from '@eka-care/ekascribe-ts-sdk';
275
159
 
276
- // Create a blob from the worker script
277
- const blob = new Blob([workerScript], { type: 'application/javascript' });
160
+ const options: RecordingOptions = {
161
+ templates: ['template-id'], // required: template IDs for output
162
+ sessionMode: 'consultation', // optional: 'consultation' | 'dictation'
163
+ languageHint: ['en', 'hi'], // optional: input audio language hints
164
+ transcriptLanguage: 'en', // optional: output transcript language
165
+ model: 'pro', // optional: 'pro' | 'lite'
166
+ uploadType: 'chunked', // optional: 'chunked' (default) | 'single'
167
+ deviceId: microphoneId, // optional: specific microphone device ID
168
+ patientDetails: { // optional
169
+ name: 'John Doe',
170
+ age: '45',
171
+ gender: 'male',
172
+ },
173
+ additionalData: {}, // optional: any extra data for the session
174
+ };
278
175
 
279
- // Generate an object URL for the blob
280
- const workerUrl = URL.createObjectURL(blob);
176
+ const result = await ekascribe.startRecordingV2(options);
281
177
 
282
- return workerUrl;
178
+ if (result.error_code) {
179
+ console.error(result.error_code, result.message);
180
+ return;
283
181
  }
284
182
 
285
- // Step 2: Use the worker URL in initTransaction
286
- const sharedWorkerUrl = await getSharedWorkerUrl();
287
-
288
- const response = await ekascribe.initTransaction(
289
- {
290
- mode: 'consultation',
291
- input_language: ['en-IN'],
292
- output_format_template: [{ template_id: 'your_template_id' }],
293
- txn_id: 'unique-transaction-id',
294
- transfer: 'vaded',
295
- model_type: 'pro',
296
- // ... other parameters
297
- },
298
- sharedWorkerUrl // Pass the custom worker URL;
299
- );
183
+ const sessionId = result.txn_id;
184
+ console.log('Recording started:', sessionId);
300
185
  ```
301
186
 
302
- **Important notes:**
303
-
304
- - Make sure to use the correct SDK version in the CDN URL
305
- - The worker URL must be accessible from the same origin or have proper CORS headers
306
- - Remember to revoke the object URL when you're done: `URL.revokeObjectURL(workerUrl)`
307
- - If `sharedWorkerUrl` is not provided, the SDK will use the main thread for file uploads (no shared worker)
308
-
309
- ### 5. Start recording
310
-
311
- Start recording audio after initializing the transaction.
187
+ #### `RecordingOptions`
312
188
 
313
189
  ```ts
314
- const response = await ekascribe.startRecording();
315
- ```
316
-
317
- - #### Sample Response:
318
-
319
- ```ts
320
- {
321
- "status_code": 200,
322
- "message": "Recording started successfully",
323
- "txn_id": "abc-123",
324
- // Possible error codes:
325
- // - "microphone" -> microphone permission not granted
326
- // - "vad_not_initialized" -> VAD failed to initialize; reinitialize and retry the same function call
327
- error_code?: ERROR_CODE
190
+ interface RecordingOptions {
191
+ templates: string[]; // Template IDs for extraction (required)
192
+ model?: string; // Model ID ('pro' | 'lite')
193
+ languageHint?: string[]; // Language codes for audio input
194
+ transcriptLanguage?: string; // Language code for transcript output
195
+ uploadType?: string; // 'chunked' | 'single' (default: 'chunked')
196
+ communicationProtocol?: string; // 'http' (default)
197
+ additionalData?: Record<string, any>; // Extra data for the session
198
+ deviceId?: string; // Specific microphone device ID
199
+ sessionMode?: string; // 'consultation' | 'dictation'
200
+ patientDetails?: PatientDetails; // Patient info
201
+ sessionId?: string; // External session/transaction ID
328
202
  }
329
- ```
330
-
331
- ### 6. Pause recording
332
203
 
333
- Pause the ongoing voice recording.
334
-
335
- ```ts
336
- const response = await ekascribe.pauseRecording();
204
+ interface PatientDetails {
205
+ oid?: string;
206
+ name?: string;
207
+ age?: string;
208
+ gender?: string;
209
+ mobile?: number;
210
+ }
337
211
  ```
338
212
 
339
- - #### Sample Response:
213
+ #### Response: `TStartRecordingResponse`
340
214
 
341
215
  ```ts
342
- {
343
- "status_code": 200,
344
- "message": "Recording paused successfully",
345
- "is_paused": true,
346
- error_code?: ERROR_CODE,
347
- }
216
+ type TStartRecordingResponse = {
217
+ error_code?: ERROR_CODE; // present only on error
218
+ status_code: number;
219
+ message: string;
220
+ txn_id?: string; // session ID — present on success
221
+ business_id?: string;
222
+ oid?: string;
223
+ uuid?: string;
224
+ };
348
225
  ```
349
226
 
350
- ### 7. Resume recording
351
-
352
- Resume a paused recording.
227
+ ### Step 4: Pause / Resume
353
228
 
354
229
  ```ts
355
- const response = await ekascribe.resumeRecording();
230
+ const pauseResult = ekascribe.pauseRecording();
231
+ // later...
232
+ const resumeResult = ekascribe.resumeRecording();
356
233
  ```
357
234
 
358
- - #### Sample Response:
235
+ #### Response: `TPauseRecordingResponse`
359
236
 
360
237
  ```ts
361
- {
362
- "status_code": 200,
363
- "message": "Recording resumed successfully",
364
- "is_paused": false,
365
- error_code?: ERROR_CODE,
366
- }
238
+ type TPauseRecordingResponse = {
239
+ status_code: number;
240
+ message: string;
241
+ error_code?: ERROR_CODE;
242
+ is_paused?: boolean;
243
+ };
367
244
  ```
368
245
 
369
- ### 8. End recording
370
-
371
- End the recording session. This method:
246
+ ### Step 5: End Recording
372
247
 
373
- - Stops the recording
374
- - Uploads all audio chunks to the server
375
- - Automatically retries failed uploads once
376
- - Calls the commit API to finalize the transaction
248
+ Stops the microphone, flushes pending audio, waits for all uploads, and ends the session on the server (triggers processing).
377
249
 
378
250
  ```ts
379
- const response = await ekascribe.endRecording();
380
- ```
251
+ const endResult = await ekascribe.endRecording();
381
252
 
382
- - #### Sample Response:
383
-
384
- ```ts
385
- {
386
- "status_code": 200,
387
- "message": "Recording ended and files uploaded successfully",
388
- failed_files?: ['1.mp3', '2.mp3'], // Only present if some files failed to upload
389
- total_audio_files?: ['1.mp3', '2.mp3', '3.mp3', '4.mp3'], // List of all audio files generated
390
- error_code?: ERROR_CODE;
253
+ if (endResult.error_code) {
254
+ switch (endResult.error_code) {
255
+ case 'audio_upload_failed':
256
+ // Some audio files failed to upload — retry
257
+ await ekascribe.retryUploadRecording();
258
+ break;
259
+ case 'end_recording_failed':
260
+ case 'internal_server_error':
261
+ console.error(endResult.error_code, endResult.message);
262
+ break;
263
+ }
391
264
  }
392
265
  ```
393
266
 
394
- **Error handling:**
395
-
396
- Possible Error Codes in `error_code`:
397
-
398
- - `txn_stop_failed`: Call `endRecording` again.
399
- - `audio_upload_failed`: Use `retryUploadRecording` (step 9).
400
- - `txn_commit_failed`: Call `commitTransactionCall` (step 11).
401
-
402
- **Handling 401 Status Code:**
403
-
404
- If you receive a `status_code: 401`, update the tokens in your config and retry:
267
+ #### Response: `TEndRecordingResponse`
405
268
 
406
269
  ```ts
407
- // Update tokens in your config variable
408
- sdkConfig.access_token = '<new_access_token>';
409
-
410
- // Update tokens in the instance
411
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
412
-
413
- // Now retry the method call
414
- const response = await ekascribe.endRecording();
270
+ type TEndRecordingResponse = {
271
+ error_code?: ERROR_CODE;
272
+ status_code: number;
273
+ message: string;
274
+ failed_files?: string[]; // files that failed to upload
275
+ total_audio_files?: string[]; // all audio files generated
276
+ };
415
277
  ```
416
278
 
417
- ### 9. Get output recorded prescription
279
+ ### Step 6: Get Output
418
280
 
419
- The SDK polls for you and resolves when processing finishes (default max wait: 2 minutes; override via `max_polling_time`, pass time in milliseconds).
281
+ Use `getSessionStatus()` to poll for results after ending the recording.
420
282
 
421
283
  ```ts
422
- // Waits up to 2 minutes by default; override as needed
423
- const res = await ekascribe.pollSessionOutput({
424
- txn_id: 'transaction-id',
425
- max_polling_time: 2 * 60 * 1000, // optional
426
- template_id: 'template-id', // optional
284
+ const status = await ekascribe.getSessionStatus(sessionId, {
285
+ poll: {
286
+ maxAttempts: 60,
287
+ intervalMs: 2000,
288
+ signal: abortController.signal, // optional: cancel polling early
289
+ onProgress: (sessionData) => {
290
+ console.log('Status:', sessionData.status);
291
+ // Display partial results as they come in
292
+ if (sessionData.templates) {
293
+ console.log('Templates:', sessionData.templates);
294
+ }
295
+ },
296
+ },
427
297
  });
428
- ```
429
298
 
430
- **Note:**
431
-
432
- 1. On passing `template_id` in request params, the function will return output only for that specific template ID. If `template_id` is not passed, it will return all template responses generated for that `txn_id`.
433
- 2. Use `onPartialResultCallback` (see Generic Callbacks section) before calling `pollSessionOutput` to receive real-time updates during polling, display partial transcription results, and improve user experience with processing progress indicators.
434
-
435
- Status codes to handle:
436
-
437
- - `200`: Success; all templates processed.
438
- - `202`: Templates are still processing; poll again (or let `pollSessionOutput` continue).
439
- - `206`: Partial success; some templates not processed fully.
440
- - `401`: Authentication token expired. Update the token.
441
- - `403`: Invalid Authentication token. Pass new token.
442
- - `500`: All template processing failed, or internal server error; stop and surface error.
443
-
444
- - #### Response type:
445
-
446
- ```ts
447
- {
448
- response?: {
449
- data: {
450
- output: TOutputSummary[];
451
- template_results: {
452
- integration: TOutputSummary[];
453
- custom: TOutputSummary[];
454
- transcript: TOutputSummary[];
455
- };
456
- audio_matrix?: {
457
- quality: string;
458
- };
459
- additional_data?: {};
460
- created_at?: string;
461
- };
462
- error?: {
463
- code: string;
464
- msg: string;
465
- };
466
- } | null;
467
- status_code: number;
468
- message?: string;
299
+ if (status.success) {
300
+ console.log('Final status:', status.data.status);
301
+ console.log('Templates:', status.data.templates);
302
+ console.log('Transcript:', status.data.transcript);
469
303
  }
304
+ ```
470
305
 
471
- type TOutputSummary = {
472
- template_id: string;
473
- value?: JSON | Array | string;
474
- type: string;
475
- name: string;
476
- status: 'success' | 'partial_success' | 'failure';
477
- errors?: Array<{
478
- type: 'warning' | 'error';
479
- code?: string;
480
- msg: string;
481
- }>;
482
- warnings?: Array<{
483
- type: 'warning' | 'error';
484
- code?: string;
485
- msg: string;
486
- }>;
306
+ #### Response: `SDKResult<GetSessionStatusResponse>`
307
+
308
+ ```ts
309
+ // All async Alliance methods return SDKResult — check result.success
310
+ type SDKResult<T> =
311
+ | { success: true; data: T; httpStatus?: number }
312
+ | { success: false; error: ScribeError };
313
+
314
+ type GetSessionStatusResponse = {
315
+ session_id: string;
316
+ status: SessionStatus;
317
+ created_at: string;
318
+ expires_at?: string | null;
319
+ completed_at?: string | null;
320
+ model_used?: string | null;
321
+ language_detected?: string | null;
322
+ audio_files_received: number;
323
+ audio_files: string[];
324
+ audio_files_processed?: number;
325
+ additional_data: Record<string, any>;
326
+ templates?: TemplateEntry[];
327
+ transcript?: string;
328
+ processing_errors?: ProcessingError[];
329
+ error?: { code: string; message: string };
487
330
  };
488
331
  ```
489
332
 
490
- - #### Example Response:
333
+ ### Step 7: Clean Up
491
334
 
492
335
  ```ts
493
- {
494
- status_code: 200,
495
- response: {
496
- data: {
497
- output: [
498
- {
499
- template_id: "template_id_passed_in_initTransaction",
500
- value: "Output Data for this template",
501
- type: "custom",
502
- name: "General Prescription",
503
- status: "success"
504
- }
505
- ],
506
- template_results: {
507
- custom: [
508
- {
509
- template_id: "custom_template",
510
- value: "Output prescription",
511
- type: "custom",
512
- name: "Custom Medication Template",
513
- status: "partial_success",
514
- warnings: [
515
- {
516
- type: "warning",
517
- code: "FIELD_MISSING",
518
- msg: "Dosage information not found"
519
- }
520
- ]
521
- }
522
- ]
523
- },
524
- audio_matrix: {
525
- quality: "4.5"
526
- },
527
- created_at: "2024-11-19T10:30:00Z"
528
- }
529
- }
530
- }
336
+ // Reset the singleton — clears all state, destroys widget, removes callbacks
337
+ await ekascribe.resetInstance();
531
338
  ```
532
339
 
533
- ### 10. Retry upload recording
340
+ After calling `resetInstance()`, you must call `getEkaScribeInstance()` again to get a new instance.
534
341
 
535
- Retry uploading failed audio files after `endRecording`.
342
+ ### Flow Diagram
536
343
 
537
- ```ts
538
- const response = await ekascribe.retryUploadRecording({ force_commit: true });
539
344
  ```
540
-
541
- - #### Sample Response:
542
-
543
- ```ts
544
- {
545
- "status_code": 200,
546
- "message": "All files uploaded successfully after retry",
547
- error_code?: ERROR_CODE;
548
- failed_files?: ['1.mp3', '2.mp3'];
549
- total_audio_files?: ['1.mp3', '2.mp3', '3.mp3', '4.mp3'];
550
- }
345
+ getEkaScribeInstance(config)
346
+ |
347
+ v
348
+ registerCallback() ── Set up event handlers before recording
349
+ |
350
+ v
351
+ startRecordingV2() ── Creates session + starts mic + begins upload
352
+ |
353
+ pause / resume ── Optional during recording
354
+ |
355
+ v
356
+ endRecording() ── Stops mic + flushes audio + ends session
357
+ |
358
+ v
359
+ getSessionStatus() ── Poll until completed/failed
360
+ |
361
+ v
362
+ Read results ── templates, transcript, errors
551
363
  ```
552
364
 
553
- **`force_commit` behavior:**
554
-
555
- - `force_commit: true` - Model will initiate the processing if some files still fail after retry
556
- - `force_commit: false` - It will waits until all files are uploaded successfully before processing.
365
+ ---
557
366
 
558
- **Handling 401 Status Code:**
367
+ ## Callbacks Reference
559
368
 
560
- If you receive a `status_code: 401`, update the tokens in your config and retry:
369
+ Register with `registerCallback(name, handler)`. Remove with `removeCallback(name, handler)`.
561
370
 
562
- ```ts
563
- // Update tokens in your config variable
564
- sdkConfig.access_token = '<new_access_token>';
371
+ ### `onTokenRequired`
565
372
 
566
- // Update tokens in the instance
567
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
568
-
569
- // Now retry the method call
570
- const response = await ekascribe.retryUploadRecording({ force_commit: true });
571
- ```
572
-
573
- ### 11. Patch recording session status
574
-
575
- Cancel or update the status of a recording session.
373
+ Called automatically when the SDK receives a 401 from any API call. Your handler must return a fresh access token. The SDK will update its internal token and retry the failed request.
576
374
 
577
375
  ```ts
578
- const response = await ekascribe.patchSessionStatus({
579
- sessionId: 'abc-123', // txn_id of the session you want to cancel
580
- processing_status: 'cancelled', // pass exactly this value
581
- processing_error: {
582
- error: {
583
- // Pass these exact values without changing them
584
- type: 'user_action',
585
- code: 'cancelled_by_user',
586
- msg: 'Session cancelled by user',
587
- },
588
- },
376
+ ekascribe.registerCallback('onTokenRequired', async () => {
377
+ // Call your auth service to get a fresh token
378
+ const newToken = await myAuthService.refreshToken();
379
+ return newToken; // return the token string
589
380
  });
590
381
  ```
591
382
 
592
- - #### Sample Response:
593
-
594
- ```ts
595
- {
596
- "status": "success",
597
- "message": "Session status updated successfully",
598
- "code": 200,
599
- error?: {
600
- code: string;
601
- message: string;
602
- display_message: string;
603
- };
604
- }
605
- ```
606
-
607
- **Handling 401 Status Code:**
383
+ **Important:**
384
+ - The handler must return `Promise<string>` or `string`
385
+ - The SDK times out after 10 seconds — if your refresh takes longer, the request fails
386
+ - Once the token is returned, the SDK calls `updateAuthTokens()` internally — you don't need to call it yourself
387
+ - This replaces the old pattern of manually checking `status_code: 401` in every response
608
388
 
609
- If you receive a `code: 401`, update the tokens in your config and retry:
389
+ #### Type
610
390
 
611
391
  ```ts
612
- // Update tokens in your config variable
613
- sdkConfig.access_token = '<new_access_token>';
614
-
615
- // Update tokens in the instance
616
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
617
-
618
- // Now retry the method call
619
- const response = await ekascribe.patchSessionStatus({ ... });
392
+ // Consumer-facing type (EkaScribe SDK)
393
+ onTokenRequired: () => Promise<string> | string;
620
394
  ```
621
395
 
622
- ### 12. Commit transaction
396
+ ### `onRecordingStateChange`
623
397
 
624
- Call this if `endRecording` returns `error_code: 'txn_commit_failed'` or the transaction is not yet committed.
398
+ Fired when recording state transitions.
625
399
 
626
400
  ```ts
627
- const response = await ekascribe.commitTransactionCall();
401
+ ekascribe.registerCallback('onRecordingStateChange', (event) => {
402
+ console.log(event.type); // 'started' | 'paused' | 'resumed' | 'ended'
403
+ });
628
404
  ```
629
405
 
630
- - #### Response type:
406
+ #### Type
631
407
 
632
408
  ```ts
633
- {
634
- error_code?: ERROR_CODE;
635
- status_code: number;
636
- message: string;
637
- };
409
+ interface RecordingStateChangeEvent {
410
+ type: 'started' | 'paused' | 'resumed' | 'ended';
411
+ timestamp: string;
412
+ data?: any;
413
+ }
638
414
  ```
639
415
 
640
- **Handling 401 Status Code:**
416
+ ### `onAudioEvent`
641
417
 
642
- If you receive a `status_code: 401`, update the tokens in your config and retry:
418
+ Fired for speech detection, silence warnings, chunk creation, and frame processing.
643
419
 
644
420
  ```ts
645
- // Update tokens in your config variable
646
- sdkConfig.access_token = '<new_access_token>';
647
-
648
- // Update tokens in the instance
649
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
650
-
651
- // Now retry the method call
652
- const response = await ekascribe.commitTransactionCall();
421
+ ekascribe.registerCallback('onAudioEvent', (event) => {
422
+ switch (event.type) {
423
+ case 'user_speech':
424
+ console.log('Speaking:', event.data.isSpeaking);
425
+ break;
426
+ case 'silence_warning':
427
+ console.log('Silence duration:', event.data.durationMs, 'ms');
428
+ break;
429
+ case 'chunk_ready':
430
+ console.log('Chunk:', event.data.fileName);
431
+ break;
432
+ case 'frame_processed':
433
+ // Raw audio frame data
434
+ break;
435
+ }
436
+ });
653
437
  ```
654
438
 
655
- ### 13. Stop transaction
656
-
657
- Use this method to stop a transaction that has not yet been stopped or returned a `txn_stop_failed` error in a previous step.
439
+ #### Type
658
440
 
659
441
  ```ts
660
- const response = await ekascribe.stopTransactionCall();
442
+ type AudioEvent =
443
+ | { type: 'user_speech'; timestamp: string; data: { isSpeaking: boolean } }
444
+ | { type: 'silence_warning'; timestamp: string; data: { durationMs: number } }
445
+ | { type: 'chunk_ready'; timestamp: string; data: { chunkIndex: number; fileName: string; chunkData: Uint8Array[] } }
446
+ | { type: 'frame_processed'; timestamp: string; data: { isSpeech: number; notSpeech: number; frame: Float32Array; duration: number } };
661
447
  ```
662
448
 
663
- - #### Response type:
449
+ ### `onUploadEvent`
450
+
451
+ Fired for upload progress, failures, and retries.
664
452
 
665
453
  ```ts
666
- {
667
- error_code?: ERROR_CODE;
668
- status_code: number;
669
- message: string;
670
- };
454
+ ekascribe.registerCallback('onUploadEvent', (event) => {
455
+ switch (event.type) {
456
+ case 'progress':
457
+ console.log(`${event.data.successCount}/${event.data.totalCount} uploaded`);
458
+ break;
459
+ case 'failed':
460
+ console.error(`Upload failed: ${event.data.fileName}`, event.data.error);
461
+ break;
462
+ case 'retry':
463
+ console.log(`Retrying ${event.data.fileName}, attempt ${event.data.attempt}`);
464
+ break;
465
+ }
466
+ });
671
467
  ```
672
468
 
673
- **Handling 401 Status Code:**
674
-
675
- If you receive a `status_code: 401`, update the tokens in your config and retry:
469
+ #### Type
676
470
 
677
471
  ```ts
678
- // Update tokens in your config variable
679
- sdkConfig.access_token = '<new_access_token>';
680
-
681
- // Update tokens in the instance
682
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
683
-
684
- // Now retry the method call
685
- const response = await ekascribe.stopTransactionCall();
472
+ type UploadEvent =
473
+ | { type: 'progress'; timestamp: string; data: { successCount: number; totalCount: number } }
474
+ | { type: 'failed'; timestamp: string; data: { fileName: string; error: string } }
475
+ | { type: 'retry'; timestamp: string; data: { fileName: string; attempt: number } };
686
476
  ```
687
477
 
688
- ### 14. Get previous sessions
478
+ ### `onSessionEvent`
689
479
 
690
- Fetch previous sessions. `txn_count` controls how many sessions the API returns.
480
+ Fired on session lifecycle events.
691
481
 
692
482
  ```ts
693
- const sessions = await ekascribe.getSessionHistory({ txn_count: 10 }); // txn_count = number of sessions to fetch
483
+ ekascribe.registerCallback('onSessionEvent', (event) => {
484
+ switch (event.type) {
485
+ case 'created':
486
+ console.log('Session created:', event.data.session_id);
487
+ break;
488
+ case 'ended':
489
+ console.log('Session ended:', event.data.session_id);
490
+ break;
491
+ case 'status_update':
492
+ console.log('Status update:', event.data.status);
493
+ break;
494
+ case 'partial_result':
495
+ console.log('Partial result:', event.data);
496
+ break;
497
+ }
498
+ });
694
499
  ```
695
500
 
696
- - #### Response type:
501
+ #### Type
697
502
 
698
503
  ```ts
699
- {
700
- data: [
701
- {
702
- b_id: "7174661713699045", // business ID
703
- created_at: "2025-12-10T10:28:00Z",
704
- mode: "consultation",
705
- oid: "174661713843153", // logged-in doctor's org ID
706
- patient_details: { // present only if sent in initTransaction
707
- "age": 18,
708
- "biologicalSex": "M",
709
- "username": ""
710
- },
711
- // processing_status can be: success | system_failure | request_failure | cancelled | in-progress
712
- processing_status: "in-progress",
713
- txn_id: "sc-c2e9be8b-46e5-489a-9473-236ddb5b24fb",
714
- // user_status can be: init | commit
715
- user_status: "init",
716
- uuid: "c44fd76d-8de1-4011-aa54-5ddcca140f0f" // logged-in doctor's user ID
717
- }
718
- ],
719
- status: "success",
720
- code: 200,
721
- message: "Sessions fetched",
722
- retrieved_count: 1
723
- }
504
+ type SessionEvent =
505
+ | { type: 'created'; timestamp: string; data: CreateSessionResponse }
506
+ | { type: 'ended'; timestamp: string; data: EndSessionResponse }
507
+ | { type: 'status_update'; timestamp: string; data: GetSessionStatusResponse }
508
+ | { type: 'partial_result'; timestamp: string; data: any };
724
509
  ```
725
510
 
726
- ### 15. Convert response to other template post session
511
+ ### `onError`
727
512
 
728
- Use this method to convert an existing transcription from a completed transaction into a different template format. This is useful when you want to reformat existing transcription data without re-recording.
513
+ Fired on SDK errors VAD failures, worker errors, network issues, validation errors.
729
514
 
730
515
  ```ts
731
- const response = await ekascribe.postTransactionConvertToTemplate({
732
- txn_id: 'transaction-id-123',
733
- template_id: 'new-template-id',
516
+ ekascribe.registerCallback('onError', (event) => {
517
+ console.error(`[${event.type}] ${event.error.code}: ${event.error.message}`);
734
518
  });
735
519
  ```
736
520
 
737
- **Key Parameters:**
738
-
739
- - `txn_id`: The transaction ID of the completed session you want to convert
740
- - `template_id`: The ID of the template format you want to convert the transcription into
741
-
742
- - #### Sample Response:
521
+ #### Type
743
522
 
744
523
  ```ts
745
- {
746
- status: 'success' | 'failed';
747
- message: string;
748
- txn_id: string;
749
- template_id: string;
750
- b_id: string;
751
- code: number;
752
- msg: string;
753
- error?: {
524
+ interface ErrorEvent {
525
+ type: 'vad_error' | 'worker_error' | 'transport_error' | 'validation_error';
526
+ timestamp: string;
527
+ error: {
754
528
  code: string;
755
529
  message: string;
756
- display_message: string;
530
+ details?: any;
757
531
  };
758
532
  }
759
533
  ```
760
534
 
761
- **When to use:**
762
-
763
- - When you need to apply a different template to an existing transcription
764
- - To generate multiple template formats from the same recording session
765
- - After completing a session, when you want to see the output in a different template structure
766
-
767
- **Note:** After getting success response from this method, call `pollSessionOutput` (Point 9) to get the output for the new template_id.
768
-
769
- ### 16. Convert transcription to template
770
-
771
- Use this method to convert a transcription text to a specific template format.
535
+ ### Removing Callbacks
772
536
 
773
537
  ```ts
774
- const response = await ekascribe.convertTranscriptionToTemplate({
775
- txn_id: 'transaction-id-123',
776
- template_id: 'target-template-id',
777
- transcript: 'custom transcript text',
778
- });
779
- ```
780
-
781
- **Key Parameters:**
538
+ const handler = (event) => { /* ... */ };
782
539
 
783
- - `txn_id`: The transaction ID of the session
784
- - `template_id`: The ID of the template format you want to convert to
785
- - `transcript`: Custom transcript text to use for conversion
786
-
787
- - #### Sample Response:
788
-
789
- ```ts
790
- {
791
- status: 'success' | 'failed';
792
- message: string;
793
- txn_id: string;
794
- template_id: string;
795
- b_id: string;
796
- code: number;
797
- msg: string;
798
- error?: { code: string; message: string; display_message: string };
799
- }
540
+ ekascribe.registerCallback('onUploadEvent', handler);
541
+ // later...
542
+ ekascribe.removeCallback('onUploadEvent', handler);
800
543
  ```
801
544
 
802
- ### 17. Update result summary
545
+ ### Retry Failed Uploads
803
546
 
804
- Use this method to update/edit the result summary (template output) for a transaction.
547
+ If `endRecording()` returns `audio_upload_failed`, retry the failed uploads:
805
548
 
806
549
  ```ts
807
- const response = await ekascribe.updateResultSummary({
808
- txnId: 'transaction-id-123',
809
- data: [
810
- {
811
- 'template-id': 'template-123',
812
- data: 'Updated template output content', // Base64 Encoded data
813
- },
814
- ],
815
- });
550
+ const result = await ekascribe.retryUploadRecording();
816
551
  ```
817
552
 
818
- **Key Parameters:**
819
-
820
- - `txnId`: The transaction ID
821
- - `data`: Array of objects containing `template-id` and the updated `data` base64 encoded data
822
-
823
- - #### Sample Response:
553
+ #### Response: `TEndRecordingResponse`
824
554
 
825
555
  ```ts
826
556
  {
827
- status: string;
557
+ status_code: number;
828
558
  message: string;
829
- txn_id: string;
830
- b_id: string;
831
- code: number;
832
- error?: { code: string; message: string; display_message: string };
559
+ error_code?: ERROR_CODE;
560
+ failed_files?: string[]; // files still failing after retry
561
+ total_audio_files?: string[];
833
562
  }
834
563
  ```
835
564
 
836
- ### 18. Run system compatibility test
565
+ ### Cancel a Session
837
566
 
838
- Use this method to run a comprehensive system compatibility test to ensure the user's browser and device support all SDK features.
567
+ Cancel a session **without** triggering server-side processing.
839
568
 
840
569
  ```ts
841
- const summary = await ekascribe.runSystemCompatibilityTest(
842
- (testResult) => {
843
- // Callback receives individual test results
844
- console.log('Test:', testResult.name, 'Result:', testResult.status);
845
- },
846
- sharedWorker // Optional: SharedWorker instance for testing worker compatibility
847
- );
570
+ // Cancel current active session
571
+ await ekascribe.cancelSession();
572
+
573
+ // Or cancel a specific session by ID
574
+ await ekascribe.cancelSession('session-id');
848
575
  ```
849
576
 
850
- - #### Sample Response:
577
+ #### Response: `SDKResult<PatchSessionResponse>`
851
578
 
852
579
  ```ts
853
- {
854
- // TCompatibilityTestSummary
855
- microphone: { status: 'pass' | 'fail'; message?: string };
856
- audioContext: { status: 'pass' | 'fail'; message?: string };
857
- sharedWorker: { status: 'pass' | 'fail'; message?: string };
858
- // ... other compatibility tests
580
+ const result = await ekascribe.cancelSession();
581
+ if (result.success) {
582
+ console.log('Session cancelled');
859
583
  }
860
584
  ```
861
585
 
862
- **When to use:**
586
+ ### Pre-Recorded Audio Upload
863
587
 
864
- - Before starting a recording session to ensure user's system is compatible
865
- - To provide user feedback about missing permissions or unsupported features
866
- - During onboarding to identify potential issues
588
+ Upload a pre-recorded audio file instead of live recording. Use this for non-real-time flows.
867
589
 
868
- ## Templates SDK Methods
590
+ **Flow:**
869
591
 
870
- ### 1. Get All Templates
871
-
872
- Use this method to retrieve all available templates for the current user.
592
+ 1. Create session via `ekascribe.sessions.createSession()`
593
+ 2. Upload audio via `processPreRecordedAudio()`
594
+ 3. End session via `ekascribe.sessions.endSession()`
873
595
 
874
596
  ```ts
875
- const templates = await ekascribe.getAllTemplates();
876
- ```
877
-
878
- - #### Response type:
879
-
880
- ```ts
881
- {
882
- items: [
883
- {
884
- id: "123;
885
- title: "Template Name";
886
- desc: "Template Description";
887
- section_ids: ["section-1", "section-2"];
888
- is_editable: true | false;
889
- }
890
- ];
891
- code: number;
892
- error?: { code: string; message: string };
893
- }
894
- ```
895
-
896
- ### 2. Create Template
897
-
898
- Use this method to create a new custom template.
899
-
900
- ```ts
901
- const newTemplate = await ekascribe.createTemplate({
902
- title: 'My Custom Template',
903
- desc: 'Description of the template',
904
- section_ids: ['section1', 'section2', 'section3'],
597
+ const result = await ekascribe.processPreRecordedAudio({
598
+ uploadUrl: session.upload_url, // from createSession response
599
+ audioFile: audioBlob, // File or Blob
905
600
  });
906
601
  ```
907
602
 
908
- - #### Response type:
603
+ #### Request
909
604
 
910
605
  ```ts
911
606
  {
912
- code: number;
913
- msg: string;
914
- template_id?: string;
915
- message?: string;
916
- error?: { code: string; message: string };
607
+ uploadUrl: string; // S3 upload URL from session
608
+ audioFile: File | Blob; // the audio file
917
609
  }
918
610
  ```
919
611
 
920
- ### 3. Edit Template
921
-
922
- Use this method to update an existing template.
923
-
924
- ```ts
925
- const updatedTemplate = await ekascribe.updateTemplate({
926
- template_id: 'template-123',
927
- title: 'Updated Template Title',
928
- desc: 'Updated description',
929
- section_ids: ['section1', 'section2', 'section4'],
930
- });
931
- ```
932
-
933
- - #### Response type:
612
+ #### Response: `TStartRecordingResponse`
934
613
 
935
614
  ```ts
936
615
  {
937
- code: number;
938
- msg: string;
939
- template_id?: string;
940
- message?: string;
941
- error?: { code: string; message: string };
616
+ status_code: number;
617
+ message: string;
618
+ error_code?: ERROR_CODE;
942
619
  }
943
620
  ```
944
621
 
945
- ### 4. Delete Template
946
-
947
- Use this method to delete an existing template.
948
-
949
- ```ts
950
- const deleteResult = await ekascribe.deleteTemplate('template-123');
951
- ```
952
-
953
- - #### Response type:
622
+ ---
954
623
 
955
- ```ts
956
- {
957
- code: number;
958
- msg: string;
959
- template_id?: string;
960
- message?: string;
961
- error?: { code: string; message: string };
962
- }
963
- ```
624
+ ## Session Utils
964
625
 
965
- ### 5. Generate Template with AI by giving a prompt
626
+ ### `getSessionHistory(request)`
966
627
 
967
- Use this method to generate a template using AI with a text prompt.
628
+ Fetch previous sessions.
968
629
 
969
630
  ```ts
970
- const formData = new FormData();
971
- formData.append('content', 'Create a cardiology consultation template');
972
- formData.append('file', file);
973
- formData.append('contentType', 'text/file');
974
-
975
- const aiTemplate = await ekascribe.aiGenerateTemplate(formData);
631
+ const sessions = await ekascribe.sessions.getSessionHistory({
632
+ txn_count: 10, // number of sessions to fetch
633
+ oid: 'patient-oid', // optional: filter by patient oid
634
+ });
976
635
  ```
977
636
 
978
- - #### Response type:
637
+ #### Response: `TGetTransactionHistoryResponse`
979
638
 
980
639
  ```ts
981
640
  {
982
- title: string;
983
- desc: string;
984
- sections: [
985
- {
986
- id: string;
987
- title: string;
988
- desc: string;
989
- format: 'P' | 'B';
990
- example: string;
991
- default?: boolean;
992
- parent_section_id?: string;
993
- }
994
- ];
641
+ data: Array<{
642
+ txn_id: string;
643
+ b_id: string;
644
+ created_at: string;
645
+ mode: string;
646
+ oid: string;
647
+ patient_details?: TPatientDetails;
648
+ processing_status: 'success' | 'system_failure' | 'request_failure' | 'cancelled' | 'in-progress';
649
+ user_status: 'init' | 'commit';
650
+ uuid: string;
651
+ }>;
652
+ status: string;
995
653
  code: number;
996
654
  message: string;
655
+ retrieved_count: number;
997
656
  }
998
657
  ```
999
658
 
1000
- ### 6. Add templates to list
659
+ ### `getSessionDetails(request)`
1001
660
 
1002
- Use this method to mark templates as favourite templates.
661
+ Get detailed information about a specific session, including documents, context, and presigned URLs.
1003
662
 
1004
663
  ```ts
1005
- const configUpdate = await ekascribe.updateConfig({
1006
- my_templates: ['template1', 'template2'],
664
+ const details = await ekascribe.sessions.getSessionDetails({
665
+ session_id: 'session-id',
666
+ presigned: true, // include presigned URLs for documents
1007
667
  });
1008
668
  ```
1009
669
 
1010
- - #### Response type:
670
+ Each document in the response contains a `presigned_url`. To get the actual document content (notes, transcript, etc.), you need to fetch it from this URL:
1011
671
 
1012
672
  ```ts
1013
- {
1014
- auto_download?: boolean;
1015
- default_languages?: string[];
1016
- my_templates?: string[];
1017
- scribe_enabled?: boolean;
1018
- msg: string;
1019
- code: number;
1020
- error?: { code: string; message: string };
673
+ const doc = details.data?.documents[0];
674
+ if (doc?.presigned_url) {
675
+ const response = await fetch(doc.presigned_url);
676
+ const content = await response.json();
1021
677
  }
1022
678
  ```
1023
679
 
1024
- ### 7. Get All Sections
680
+ > Presigned URLs are temporary — check `presigned_url_expires_at` (epoch timestamp) before using. Call `getDocument(documentId)` to get a fresh presigned URL if expired.
1025
681
 
1026
- Use this method to retrieve all available template sections.
682
+ #### Request
1027
683
 
1028
684
  ```ts
1029
- const sections = await ekascribe.getAllTemplateSections();
685
+ type TGetV1SessionDetailsRequest = {
686
+ session_id: string;
687
+ presigned?: boolean; // default: false
688
+ };
1030
689
  ```
1031
690
 
1032
- - #### Response type:
691
+ #### Response: `TGetV1SessionDetailsResponse`
1033
692
 
1034
693
  ```ts
1035
- {
1036
- items: [
1037
- {
1038
- id: string;
1039
- title: string;
1040
- desc: string;
1041
- format: 'P' | 'B';
1042
- example: string;
1043
- default?: boolean;
1044
- parent_section_id?: string;
1045
- }
1046
- ];
1047
- code: number;
1048
- error?: { code: string; message: string };
1049
- }
694
+ type TGetV1SessionDetailsResponse = {
695
+ data?: {
696
+ schema_version: string;
697
+ session_id: string;
698
+ uuid: string;
699
+ wid: string;
700
+ created_at: number;
701
+ expires_at: number;
702
+ upload_url: string;
703
+ status: string;
704
+ user_status: 'init' | 'recording_started' | 'commit' | string;
705
+ transfer: string;
706
+ flavour: string;
707
+ patient_details: TPatientDetails | Record<string, unknown>;
708
+ audio_matrix: Record<string, unknown>;
709
+ additional_data: {
710
+ input_languages?: { id: string; name: string }[];
711
+ output_format_template?: {
712
+ template_id: string;
713
+ template_name?: string;
714
+ template_type?: string;
715
+ }[];
716
+ [key: string]: unknown;
717
+ };
718
+ documents: Array<{
719
+ document_id: string;
720
+ session_id: string;
721
+ template_id: string;
722
+ document_name: string;
723
+ document_type: 'notes' | 'context' | 'transcript' | 'integration';
724
+ type: string;
725
+ status: string;
726
+ errors: Array<{ type: string | null; code: string; msg: string }>;
727
+ warnings: Array<{ type: string | null; code: string; msg: string }>;
728
+ publish: Record<string, unknown>;
729
+ created_at: number;
730
+ presigned_url: string | null;
731
+ presigned_url_expires_at: number | null;
732
+ vault_doc_id: string | null;
733
+ lang?: string;
734
+ }>;
735
+ context: {
736
+ past_sessions?: Array<{ date_epoch: number; session_id: string }>;
737
+ documents?: string[];
738
+ attachments?: Array<{ id: string; patient_oid?: string }>;
739
+ };
740
+ };
741
+ status_code: number;
742
+ message?: string;
743
+ };
1050
744
  ```
1051
745
 
1052
- ### 8. Create Section in a template
746
+ ### `getDocument(documentId)`
1053
747
 
1054
- Use this method to create a new section that can be used in templates.
748
+ Fetch a single document by ID. Use this to get a fresh presigned URL if the previous one has expired.
1055
749
 
1056
750
  ```ts
1057
- const newSection = await ekascribe.createTemplateSection({
1058
- title: 'Chief Complaint',
1059
- desc: "Patient's primary concern",
1060
- format: 'P', // 'P' for paragraph, 'B' for bullet points
1061
- example: 'Patient presents with chest pain for 2 days',
1062
- });
1063
- ```
1064
-
1065
- - #### Response type:
1066
-
1067
- ```ts
1068
- {
1069
- msg: string;
1070
- section_id: string;
1071
- code: number;
1072
- action: 'updated' | 'created_custom';
1073
- error?: { code: string; message: string };
751
+ const doc = await ekascribe.documents.getDocument('document-id');
752
+ if (doc.data?.presigned_url) {
753
+ const response = await fetch(doc.data.presigned_url);
754
+ const content = await response.json();
1074
755
  }
1075
756
  ```
1076
757
 
1077
- ### 9. Edit Section in a template
1078
-
1079
- Use this method to update an existing template section.
1080
-
1081
- ```ts
1082
- const updatedSection = await ekascribe.updateTemplateSection({
1083
- section_id: 'section-123',
1084
- title: 'Updated Chief Complaint',
1085
- desc: 'Updated description',
1086
- format: 'B',
1087
- example: 'Updated example text',
1088
- });
1089
- ```
1090
-
1091
- - #### Response type:
758
+ #### Response: `TPostV1DocumentResponse`
1092
759
 
1093
760
  ```ts
1094
- {
1095
- msg: string;
1096
- section_id: string;
1097
- code: number;
1098
- action: 'updated' | 'created_custom';
1099
- error?: { code: string; message: string };
1100
- }
761
+ type TPostV1DocumentResponse = {
762
+ status_code: number;
763
+ status?: string;
764
+ message?: string;
765
+ data?: {
766
+ document_id: string;
767
+ session_id: string;
768
+ template_id: string;
769
+ document_name: string;
770
+ type: string;
771
+ status: string;
772
+ errors: unknown[];
773
+ warnings: unknown[];
774
+ usage_information: Record<string, unknown>;
775
+ document_path: {
776
+ bucket: string;
777
+ folder: string;
778
+ filename: string;
779
+ };
780
+ presigned_url: string;
781
+ created_at: string;
782
+ updated_at: number;
783
+ publish: Record<string, unknown>;
784
+ };
785
+ };
1101
786
  ```
1102
787
 
1103
- ### 10. Delete Section from a template
1104
-
1105
- Use this method to delete a template section.
1106
-
1107
- ```ts
1108
- const deleteResult = await ekascribe.deleteTemplateSection('section-123');
1109
- ```
788
+ ### `patchSessionStatus(request, sessionId?)`
1110
789
 
1111
- - #### Response type:
790
+ Update session properties (patient details, status, templates).
1112
791
 
1113
792
  ```ts
1114
- {
1115
- msg: string;
1116
- section_id: string;
1117
- code: number;
1118
- action: 'updated' | 'created_custom';
1119
- error?: { code: string; message: string };
1120
- }
793
+ await ekascribe.sessions.patchSessionStatus({
794
+ patient_details: { name: 'Jane Doe', age: '30', gender: 'female' },
795
+ additional_data: { notes: 'Follow-up visit' },
796
+ templates: ['soap', 'prescription'],
797
+ }, sessionId);
1121
798
  ```
1122
799
 
1123
- ## Non-vaded flow: Upload raw audio to get output summary
800
+ ---
1124
801
 
1125
- Use this method to upload pre-recorded audio files directly and get transcription output without real-time recording. This is useful when you have existing audio files and want to process them.
802
+ ## Discovery
1126
803
 
1127
- **What this method does:**
804
+ ### `getDiscoveryDocument()`
1128
805
 
1129
- - Gets a presigned URL from the server
1130
- - Uploads audio files to S3 via presigned URL
1131
- - Initializes a transaction with the uploaded files
1132
- - Returns the transaction details
806
+ Get the raw discovery document fetched during initialization. Contains server capabilities (supported models, languages, upload methods, audio formats).
1133
807
 
1134
808
  ```ts
1135
- const audioFiles = [file1, file2]; // File or Blob objects
1136
- const audioFileNames = ['audio1.mp3', 'audio2.mp3'];
1137
-
1138
- const response = await ekascribe.uploadAudioWithPresignedUrl({
1139
- action: 'ekascribe-v2', // Pass this exact value without changing
1140
- audioFiles,
1141
- audioFileNames,
1142
- mode: 'consultation',
1143
- txn_id: 'unique-transaction-id',
1144
- input_language: ['en-IN'],
1145
- output_format_template: [{ template_id: 'your_template_id' }],
1146
- transfer: 'non-vaded', // Use 'non-vaded' for raw audio files
1147
- model_type: 'pro' | 'lite',
1148
- system_info: {
1149
- platform: 'web',
1150
- language: 'en',
1151
- time_zone: 'Asia/Kolkata',
1152
- },
1153
- patient_details: {
1154
- username: 'John Doe',
1155
- age: 35,
1156
- biologicalSex: 'M',
1157
- },
1158
- version: '1.0.0',
1159
- additional_data: {},
1160
- });
809
+ const discovery = ekascribe.sessions.getDiscoveryDocument();
1161
810
  ```
1162
811
 
1163
- **Key Parameters:**
812
+ Returns `DiscoveryDocument | null`.
1164
813
 
1165
- - `action`: Pass `ekascribe-v2` exactly as shown
1166
- - `audioFiles`: Array of File or Blob objects
1167
- - `audioFileNames`: Array of file names corresponding to audio files
1168
- - `transfer`: Use `non-vaded` for raw audio files (not processed with VAD)
1169
- - Other parameters: Same as `initTransaction` (see step 3)
814
+ ### `getDiscoveryConfig()`
1170
815
 
1171
- - #### Sample Response:
816
+ Get the resolved configuration derived from the discovery document.
1172
817
 
1173
818
  ```ts
1174
- {
1175
- error_code?: ERROR_CODE,
1176
- status_code: 200,
1177
- message: 'Recording uploaded successfully.',
819
+ const config = ekascribe.sessions.getDiscoveryConfig();
820
+
821
+ if (config.success) {
822
+ console.log('Resolved config:', config.data);
1178
823
  }
1179
824
  ```
1180
825
 
1181
- **Error handling:**
1182
-
1183
- Possible Error Codes in `error_code`:
826
+ Returns `SDKResult<ResolvedConfig>`.
1184
827
 
1185
- - `get_presigned_url_failed`: Failed to get presigned URL from server, retry with the same method
1186
- - `audio_upload_failed`: Failed to upload audio files to S3, retry with the same method
1187
- - `txn_limit_exceeded`: Maximum number of transactions exceeded
1188
- - `txn_init_failed`: Failed to initialize transaction after upload, retry with the same method
828
+ ---
1189
829
 
1190
- **Handling 401 Status Code:**
830
+ ## Widget
1191
831
 
1192
- If you receive a `status_code: 401`, update the tokens in your config and retry:
1193
-
1194
- ```ts
1195
- // Update tokens in your config variable
1196
- sdkConfig.access_token = '<new_access_token>';
1197
-
1198
- // Update tokens in the instance
1199
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
1200
-
1201
- // Now retry the method call
1202
- const response = await ekascribe.uploadAudioWithPresignedUrl({ ... });
1203
- ```
832
+ The SDK provides an optional pre-built recording UI. When enabled, the SDK injects a floating widget into your page via Shadow DOM — you write zero UI code.
1204
833
 
1205
- ## Utility Methods
834
+ ### Integration
1206
835
 
1207
- ### 1. Get total uploaded files
1208
-
1209
- Use this method to retrieve all the audio files generated for a specific session.
836
+ **Step 1:** Enable the widget in SDK config with session defaults and callbacks:
1210
837
 
1211
838
  ```ts
1212
- const files = ekascribe.getTotalAudioFiles();
839
+ const ekascribe = getEkaScribeInstance({
840
+ access_token: token,
841
+ env: 'PROD',
842
+ allianceConfig: { baseUrl: '...' },
843
+ widget: {
844
+ enabled: true,
845
+ orientation: 'horizontal', // 'horizontal' | 'vertical'
846
+ zIndex: 9999, // optional
847
+ position: { bottom: 20, right: 20 }, // optional
848
+ sessionDefaults: {
849
+ input_language: ['en'],
850
+ output_format_template: [{ template_id: 'soap' }],
851
+ model_type: 'pro',
852
+ mode: 'consultation',
853
+ },
854
+ callbacks: {
855
+ onRecordingStart: ({ txn_id }) => {},
856
+ onRecordingStop: ({ txn_id, duration }) => {},
857
+ onProcessingComplete: ({ txn_id, sessionData }) => {
858
+ // sessionData contains templates, transcript, etc.
859
+ },
860
+ onError: ({ error_code, message }) => {},
861
+ },
862
+ },
863
+ });
1213
864
  ```
1214
865
 
1215
- - #### Response type:
866
+ **Step 2:** Call `startForPatient()` for each patient — the widget appears and the user interacts with it directly (pause, resume, stop). You receive results via callbacks.
1216
867
 
1217
868
  ```ts
1218
- ['1.mp3', '2.mp3', '3.mp3', '4.mp3'];
869
+ await ekascribe.startForPatient({
870
+ txn_id: 'unique-session-id',
871
+ patient_details: { // optional
872
+ username: 'John Doe',
873
+ age: 45,
874
+ biologicalSex: 'M',
875
+ },
876
+ additional_data: {}, // optional
877
+ });
1219
878
  ```
1220
879
 
1221
- ### 2. Get successfully uploaded files
880
+ That's it. The widget handles `startRecordingV2()`, `pauseRecording()`, `resumeRecording()`, `endRecording()`, and `getSessionStatus()` internally.
1222
881
 
1223
- Use this method to retrieve all the audio files that were uploaded successfully.
882
+ ### Widget State Flow
1224
883
 
1225
- ```ts
1226
- const successFiles = ekascribe.getSuccessFiles();
884
+ ```
885
+ COLLAPSED ──> RECORDING ──> PAUSED ──> RECORDING ──> PROCESSING ──> DONE
886
+ ^ │ │ │
887
+ │ └──── (user clicks stop) ───────────────┘ │
888
+ │ │
889
+ └──────────── (user clicks close) ────────────────────────────────┘
890
+
891
+ ERROR
1227
892
  ```
1228
893
 
1229
- - #### Response type:
894
+ ### Types
1230
895
 
1231
896
  ```ts
1232
- ['3.mp3', '4.mp3'];
1233
- ```
1234
-
1235
- ### 3. Get failed audio files
897
+ interface WidgetConfig {
898
+ enabled: boolean;
899
+ theme?: 'light' | 'dark';
900
+ zIndex?: number;
901
+ primaryColor?: string;
902
+ position?: { bottom?: number; right?: number; top?: number; left?: number };
903
+ orientation?: 'horizontal' | 'vertical';
904
+ callbacks?: WidgetCallbacks;
905
+ sessionDefaults: {
906
+ input_language: string[];
907
+ output_format_template: { template_id: string; template_name?: string; template_type?: string }[];
908
+ model_type: string;
909
+ mode: string;
910
+ };
911
+ }
1236
912
 
1237
- Use this method to retrieve all the audio files that failed to upload.
913
+ interface StartForPatientConfig {
914
+ txn_id: string;
915
+ patient_details?: {
916
+ username?: string;
917
+ age?: number;
918
+ biologicalSex?: string;
919
+ mobile?: string;
920
+ };
921
+ additional_data?: Record<string, unknown>;
922
+ }
1238
923
 
1239
- ```ts
1240
- const failedFiles = ekascribe.getFailedFiles();
924
+ interface WidgetCallbacks {
925
+ onRecordingStart?: (data: { txn_id: string }) => void;
926
+ onRecordingPause?: (data: { txn_id: string; duration: number }) => void;
927
+ onRecordingResume?: (data: { txn_id: string }) => void;
928
+ onRecordingStop?: (data: { txn_id: string; duration: number }) => void;
929
+ onProcessingStart?: (data: { txn_id: string }) => void;
930
+ onProcessingComplete?: (data: { txn_id: string; sessionData: unknown }) => void;
931
+ onError?: (data: { error_code: string; message: string }) => void;
932
+ onWidgetClose?: (data: { txn_id: string }) => void;
933
+ }
1241
934
  ```
1242
935
 
1243
- - #### Response type:
936
+ ---
1244
937
 
1245
- ```ts
1246
- ['1.mp3', '2.mp3'];
1247
- ```
938
+ ## Authentication
1248
939
 
1249
- ### 4. Reset Class Instance
940
+ ### `updateAuthTokens(token)`
1250
941
 
1251
- Use this method to reset the EkaScribe instance and clear all stored data.
942
+ Manually update the access token. This propagates the token to all internal transports and the worker.
1252
943
 
1253
944
  ```ts
1254
- ekaScribe.resetEkaScribe();
945
+ ekascribe.updateAuthTokens({ access_token: 'new-token' });
1255
946
  ```
1256
947
 
1257
- ### 5. Reinitialise VAD Instance
948
+ > If you have `onTokenRequired` registered, the SDK handles 401s automatically. You only need `updateAuthTokens()` for proactive token rotation (e.g., before expiry).
1258
949
 
1259
- Use this method to reinitialize the Voice Activity Detection (VAD) instance.
950
+ ---
1260
951
 
1261
- ```ts
1262
- ekaScribe.reinitializeVad();
1263
- ```
952
+ ## SharedWorker Configuration
1264
953
 
1265
- ### 6. Pause VAD Instance
954
+ The SDK offloads audio compression and upload to a SharedWorker for better main-thread performance. If SharedWorker is unavailable or fails, the SDK silently falls back to main-thread processing.
1266
955
 
1267
- Use this method to pause the Voice Activity Detection without stopping the recording session.
956
+ ### Setup
1268
957
 
1269
958
  ```ts
1270
- ekaScribe.pauseVad();
1271
- ```
959
+ import { createWorkerBlobUrl } from '@eka-care/ekascribe-ts-sdk';
1272
960
 
1273
- ### 7. Destroy VAD Instance
961
+ // Option 1: Use the built-in helper (recommended)
962
+ const workerUrl = await createWorkerBlobUrl();
1274
963
 
1275
- Use this method to completely destroy the VAD instance and free up resources.
964
+ // Option 2: Fetch from CDN
965
+ async function getWorkerUrl() {
966
+ const res = await fetch(
967
+ 'https://cdn.jsdelivr.net/npm/@eka-care/ekascribe-ts-sdk@latest/dist/worker.bundle.js'
968
+ );
969
+ const script = await res.text();
970
+ const blob = new Blob([script], { type: 'application/javascript' });
971
+ return URL.createObjectURL(blob);
972
+ }
973
+ const workerUrl = await getWorkerUrl();
1276
974
 
1277
- ```ts
1278
- ekaScribe.destroyVad();
975
+ // Option 3: Copy to public directory
976
+ // cp node_modules/@eka-care/ekascribe-ts-sdk/dist/worker.bundle.js public/
977
+ const workerUrl = '/worker.bundle.js';
1279
978
  ```
1280
979
 
1281
- ### 8. Update Authentication Tokens
1282
-
1283
- Use this method to update the access token when it expires (e.g., when you receive a 401 error).
980
+ Pass the URL in config:
1284
981
 
1285
982
  ```ts
1286
- ekascribe.updateAuthTokens({ access_token: 'new_access_token' });
983
+ const ekascribe = getEkaScribeInstance({
984
+ // ...
985
+ sharedWorkerUrl: workerUrl,
986
+ });
1287
987
  ```
1288
988
 
1289
- **When to use:**
989
+ **Notes:**
1290
990
 
1291
- - When any API method returns `status_code: 401`
1292
- - When `eventCallback` returns `error.code: 401` in `file_upload_status`
1293
- - Before token expiration to prevent upload failures
1294
-
1295
- ### 9. Get Doctor Header and Footer
991
+ - The worker URL must be accessible from the same origin or have proper CORS headers
992
+ - Remember to revoke blob URLs when done: `URL.revokeObjectURL(workerUrl)`
993
+ - If `sharedWorkerUrl` is not provided, the SDK uses the main thread (no SharedWorker)
1296
994
 
1297
- Use this method to retrieve the header and footer images for a doctor's prescription template.
995
+ ---
1298
996
 
1299
- ```ts
1300
- const headerFooter = await ekascribe.getDoctorHeaderFooter({
1301
- doctor_oid: '161459684229004',
1302
- clinic_id: '60532c7fcb46901ba3a3e477', // optional
1303
- });
1304
- ```
997
+ ## Error Codes
1305
998
 
1306
- **Key Parameters:**
999
+ | Error Code | Description |
1000
+ |---|---|
1001
+ | `microphone` | Microphone access error (permission denied or unavailable) |
1002
+ | `txn_init_failed` | Failed to initialize session |
1003
+ | `txn_limit_exceeded` | Maximum concurrent sessions exceeded |
1004
+ | `internal_server_error` | Unexpected server-side error |
1005
+ | `end_recording_failed` | Failed to end recording |
1006
+ | `audio_upload_failed` | Audio file upload to server failed |
1007
+ | `txn_commit_failed` | Commit call failed |
1008
+ | `txn_status_mismatch` | Invalid operation for current session state |
1009
+ | `network_error` | Network connectivity issue |
1010
+ | `unknown_error` | Unclassified error |
1011
+ | `unauthorized` | Authentication failed (invalid or expired token) |
1012
+ | `forbidden` | Insufficient permissions |
1307
1013
 
1308
- - `doctor_oid`: The doctor's OID (required)
1309
- - `clinic_id`: The clinic ID (optional) - if provided, returns header/footer for this specific clinic
1014
+ ---
1310
1015
 
1311
- **Selection Logic:**
1016
+ ## Deprecated Methods
1312
1017
 
1313
- 1. If `clinic_id` is provided and a matching PRINT template exists, returns that template's header/footer
1314
- 2. Otherwise, looks for the doctor's default clinic and returns its header/footer
1315
- 3. If no matching template is found, returns `null`
1018
+ These methods are from the older SDK version. They still work but are not recommended for new integrations.
1316
1019
 
1317
- - #### Response type:
1020
+ | Deprecated Method | Use Instead |
1021
+ |---|---|
1022
+ | `initTransaction()` + `startRecording()` | `startRecordingV2()` |
1023
+ | `getTemplateOutput()` | `getSessionStatus()` with polling |
1024
+ | `getOutputTranscription()` | `getSessionStatus()` with polling |
1025
+ | `commitTransactionCall()` | Handled automatically by `endRecording()` |
1026
+ | `stopTransactionCall()` | Handled automatically by `endRecording()` |
1318
1027
 
1319
- ```ts
1320
- {
1321
- data: {
1322
- _id: string | null; // Template ID
1323
- clinic_id: string | null; // Clinic ID
1324
- doctor_id: string | null; // Doctor ID
1325
- type: string | null; // Template type (e.g., "PRINT")
1326
- header_img: string | null; // URL of the header image
1327
- header_height: string | null; // Height of the header (e.g., "5cm")
1328
- header_top_margin: string | null; // Top margin for header (e.g., "0.5cm")
1329
- footer_img: string | null; // URL of the footer image
1330
- footer_height: string | null; // Height of the footer (e.g., "6.7cm")
1331
- margin_left: string | null; // Left margin (e.g., "1.27cm")
1332
- margin_right: string | null; // Right margin (e.g., "1.27cm")
1333
- page_size: string | null; // Page size (e.g., "A4")
1334
- show_eka_logo: boolean | null; // Show Eka logo on prescription
1335
- show_name_in_signature: boolean | null; // Show name in signature
1336
- show_not_valid_for_medical_legal_purpose_message: boolean | null; // Show disclaimer message
1337
- show_page_number: boolean | null; // Show page numbers
1338
- show_prescription_id: boolean | null; // Show prescription ID
1339
- show_signature: boolean | null; // Show signature
1340
- } | null;
1341
- code: number;
1342
- message?: string;
1343
- }
1344
- ```
1028
+ ### `initTransaction(request)`
1345
1029
 
1346
- - #### Example Response:
1030
+ Creates a session on the server. Must be followed by `startRecording()`.
1347
1031
 
1348
1032
  ```ts
1349
- {
1350
- data: {
1351
- _id: "64b8e093efdee1eaaf052e3e",
1352
- clinic_id: "60532c7fcb46901ba3a3e477",
1353
- doctor_id: "161459684229004",
1354
- type: "PRINT",
1355
- header_img: "https://rafale-assets.eka.care/161459684229004-60532c7fcb46901ba3a3e477-header.png",
1356
- header_height: "5cm",
1357
- header_top_margin: "0.5cm",
1358
- footer_img: "https://rafale-assets.eka.care/161459684229004-60532c7fcb46901ba3a3e477-footer.png",
1359
- footer_height: "6.7cm",
1360
- margin_left: "1.27cm",
1361
- margin_right: "1.27cm",
1362
- page_size: "A4",
1363
- show_eka_logo: true,
1364
- show_name_in_signature: true,
1365
- show_not_valid_for_medical_legal_purpose_message: true,
1366
- show_page_number: true,
1367
- show_prescription_id: true,
1368
- show_signature: true
1033
+ const result = await ekascribe.initTransaction({
1034
+ mode: 'consultation',
1035
+ input_language: ['en-IN'],
1036
+ output_format_template: [{ template_id: 'template-id' }],
1037
+ txn_id: 'unique-id',
1038
+ transfer: 'chunked',
1039
+ model_type: 'pro',
1040
+ patient_details: { // optional
1041
+ username: 'John Doe',
1042
+ age: 45,
1043
+ biologicalSex: 'M',
1369
1044
  },
1370
- code: 200
1371
- }
1045
+ });
1046
+ // result: { status_code, message, txn_id?, error_code? }
1372
1047
  ```
1373
1048
 
1374
- ### 10. Reset Singleton Instance
1049
+ ### `startRecording(microphoneID?)`
1375
1050
 
1376
- Use this method to completely reset the singleton instance. Useful for testing or when you need to reinitialize the SDK with different configuration.
1051
+ Starts recording for an already initialized session.
1377
1052
 
1378
1053
  ```ts
1379
- ekascribe.resetInstance();
1054
+ const result = await ekascribe.startRecording();
1055
+ // result: { status_code, message, txn_id?, error_code? }
1380
1056
  ```
1381
1057
 
1382
- **Note:** After calling this method, you'll need to call `getEkaScribeInstance()` again to get a new instance.
1383
-
1384
- ### 11. Configure VAD Constants
1058
+ ### `getTemplateOutput(request)`
1385
1059
 
1386
- Use this method to customize Voice Activity Detection parameters for your specific use case.
1060
+ Fetches processed template output for a session.
1387
1061
 
1388
1062
  ```ts
1389
- ekascribe.configureVadConstants({
1390
- pref_length: 10, // Preferred chunk length in seconds
1391
- desp_length: 5, // Desperation chunk length in seconds
1392
- max_length: 30, // Maximum chunk length in seconds
1393
- sr: 16000, // Sample rate in Hz
1394
- frame_size: 512, // Frame size in samples
1395
- pre_speech_pad_frames: 10, // Pre-speech padding frames count
1396
- short_thsld: 0.5, // Short silence threshold in seconds
1397
- long_thsld: 0.8, // Long silence threshold in seconds
1398
- });
1063
+ const result = await ekascribe.getTemplateOutput({ txn_id: 'session-id' });
1064
+ // result: { status_code, message?, response? }
1399
1065
  ```
1400
1066
 
1401
- **Key Parameters:**
1402
-
1403
- - `pref_length`: Preferred audio chunk length before clipping (in seconds)
1404
- - `desp_length`: Desperation length - will clip even if not ideal (in seconds)
1405
- - `max_length`: Maximum audio chunk length (in seconds)
1406
- - `sr`: Sample rate in Hz (typically 16000)
1407
- - `frame_size`: VAD frame size in samples
1408
- - `pre_speech_pad_frames`: Number of frames to include before speech starts
1409
- - `short_thsld`: Short silence threshold for clipping decisions (in seconds)
1410
- - `long_thsld`: Long silence threshold for clipping decisions (in seconds)
1067
+ ### `getOutputTranscription(request)`
1411
1068
 
1412
- ### 12. Destroy Shared Worker
1413
-
1414
- Use this method to terminate the shared worker instance and free up resources.
1069
+ Fetches the transcription output for a session.
1415
1070
 
1416
1071
  ```ts
1417
- await ekascribe.destroySharedWorker();
1072
+ const result = await ekascribe.getOutputTranscription({ txn_id: 'session-id' });
1073
+ // result: { status_code, message?, response? }
1418
1074
  ```
1419
1075
 
1420
- **When to use:**
1421
-
1422
- - When cleaning up resources after the SDK is no longer needed
1423
- - Before reinitializing with a new shared worker configuration
1076
+ ### `commitTransactionCall()`
1424
1077
 
1425
- ## Generic Callbacks
1426
-
1427
- ### 1. Event callback
1428
-
1429
- This callback provides information about SDK operations. Use it to monitor file uploads, transaction status, AWS configuration, and authentication errors.
1078
+ Commits the current transaction on the server.
1430
1079
 
1431
1080
  ```ts
1432
- ekascribe.onEventCallback((eventData) => {
1433
- console.log('Event callback:', eventData);
1434
-
1435
- // Handle different callback types
1436
- switch (eventData.callback_type) {
1437
- case 'file_upload_status':
1438
- // Track audio chunk upload progress
1439
- console.log(`Uploaded ${eventData.data?.success}/${eventData.data?.total} chunks`);
1440
- break;
1441
- case 'transaction_status':
1442
- // Monitor transaction lifecycle (init, stop, commit, cancel)
1443
- console.log('Transaction update:', eventData.message);
1444
- break;
1445
- case 'aws_configure_status':
1446
- // AWS S3 configuration status
1447
- console.log('AWS config:', eventData.status);
1448
- break;
1449
- case 'authentication_status':
1450
- // API authentication errors
1451
- console.error('Auth error:', eventData.message);
1452
- break;
1453
- }
1454
- });
1081
+ const result = await ekascribe.commitTransactionCall();
1082
+ // result: { status_code, message, error_code?, failed_files? }
1455
1083
  ```
1456
1084
 
1457
- - #### Callback Structure:
1085
+ ### `stopTransactionCall()`
1086
+
1087
+ Stops the current transaction on the server.
1458
1088
 
1459
1089
  ```ts
1460
- {
1461
- callback_type: 'file_upload_status' | 'transaction_status' | 'aws_configure_status' | 'authentication_status',
1462
- status: 'success' | 'error' | 'info',
1463
- message: string,
1464
- timestamp: string, // ISO timestamp
1465
- error?: {
1466
- code: number,
1467
- msg: string,
1468
- details: any
1469
- },
1470
- data?: {
1471
- success?: number, // Number of successfully uploaded chunks
1472
- total?: number, // Total number of chunks
1473
- is_uploaded?: boolean, // Whether current chunk uploaded successfully
1474
- fileName?: string, // Current file name
1475
- chunkData?: Uint8Array[], // Audio chunk data for current audiofile
1476
- request?: any, // API request details
1477
- response?: any // API response details
1478
- }
1479
- }
1090
+ const result = await ekascribe.stopTransactionCall();
1091
+ // result: { status_code, message, error_code? }
1480
1092
  ```
1481
1093
 
1482
- - #### Callback Types Explained:
1483
-
1484
- **`file_upload_status`** - Track audio chunk upload progress
1485
-
1486
- Use this to monitor upload progress of audio chunks:
1487
-
1488
- - `status: 'info'` - Audio chunk info
1094
+ ---
1489
1095
 
1490
- - `data.success`: Count of successfully uploaded chunks
1491
- - `data.total`: Total chunks generated
1492
- - `data.fileName`: Current chunk file name
1493
- - `data.chunkData`: Audio data for current chunk
1096
+ ## Full Example
1494
1097
 
1495
- - `status: 'success'` - Chunk uploaded successfully
1496
-
1497
- - `data.success`: Updated successful upload count
1498
- - `data.total`: Total chunks
1499
- - `data.is_uploaded`: true
1500
-
1501
- - `status: 'error'` - Chunk upload failed
1502
-
1503
- - `error.code`: HTTP error code
1504
- - `error.msg`: Error message
1505
- - `error.details`: Additional error details
1506
-
1507
- - Status codes to handle:
1508
-
1509
- If `error.code === 401`, it means your access token has expired. Update tokens immediately:
1098
+ ```ts
1099
+ import {
1100
+ getEkaScribeInstance,
1101
+ type EkaScribeConfig,
1102
+ type RecordingOptions,
1103
+ } from '@eka-care/ekascribe-ts-sdk';
1510
1104
 
1511
- ```ts
1512
- ekascribe.onEventCallback((eventData) => {
1513
- if (eventData.callback_type === 'file_upload_status' && eventData.status === 'error') {
1514
- if (eventData.error?.code === 401) {
1515
- // Token expired - update it
1516
- sdkConfig.access_token = '<new_access_token>';
1517
- ekascribe.updateAuthTokens({ access_token: sdkConfig.access_token });
1518
- }
1519
- }
1520
- });
1521
- ```
1105
+ // 1. Initialize
1106
+ const config: EkaScribeConfig = {
1107
+ access_token: token,
1108
+ env: 'PROD',
1109
+ allianceConfig: {
1110
+ baseUrl: 'https://api.eka.care/voice/api/v2',
1111
+ },
1112
+ };
1522
1113
 
1523
- ### 2. User speech callback
1114
+ const ekascribe = getEkaScribeInstance(config);
1524
1115
 
1525
- Triggered by Voice Activity Detection (VAD) when user starts or stops speaking.
1116
+ // 2. Register callbacks
1117
+ ekascribe.registerCallback('onTokenRequired', async () => {
1118
+ return await refreshToken();
1119
+ });
1526
1120
 
1527
- ```ts
1528
- ekascribe.onUserSpeechCallback((isSpeech) => {
1529
- if (isSpeech) {
1530
- console.log('User started speaking');
1531
- } else {
1532
- console.log('User stopped speaking');
1121
+ ekascribe.registerCallback('onUploadEvent', (event) => {
1122
+ if (event.type === 'progress') {
1123
+ updateProgressUI(event.data.successCount, event.data.totalCount);
1533
1124
  }
1534
1125
  });
1535
- ```
1536
-
1537
- ### 3. Partial result callback
1538
-
1539
- This callback provides real-time partial results while polling for the final output. Use it to display intermediate transcription and template results to users before processing is complete.
1540
1126
 
1541
- ```ts
1542
- ekascribe.onPartialResultCallback((partialData) => {
1543
- console.log('Partial result received:', partialData);
1544
-
1545
- // Handle different poll statuses
1546
- switch (partialData.poll_status) {
1547
- case 'in-progress':
1548
- // Processing is still ongoing, display partial results
1549
- console.log('Processing...', partialData.response);
1550
- break;
1551
- case 'success':
1552
- // Final result received
1553
- console.log('Processing complete:', partialData.response);
1554
- break;
1555
- case 'failed':
1556
- // Processing failed
1557
- console.error('Processing failed:', partialData.message);
1558
- break;
1559
- case 'timeout':
1560
- // Polling timed out
1561
- console.warn('Polling timeout:', partialData.message);
1562
- break;
1563
- }
1127
+ ekascribe.registerCallback('onError', (event) => {
1128
+ showErrorToast(event.error.message);
1564
1129
  });
1565
- ```
1566
1130
 
1567
- - #### Callback Structure:
1131
+ // 3. Start recording
1132
+ const startResult = await ekascribe.startRecordingV2({
1133
+ templates: ['soap'],
1134
+ sessionMode: 'consultation',
1135
+ languageHint: ['en'],
1136
+ patientDetails: { name: 'John Doe', age: '45', gender: 'male' },
1137
+ });
1568
1138
 
1569
- ```ts
1570
- {
1571
- txn_id: string; // Transaction ID
1572
- response: TGetStatusApiResponse | null; // The response structure is the same as returned by `pollSessionOutput` method
1573
- status_code: number; // HTTP status code
1574
- message: string; // Status message
1575
- poll_status: 'in-progress' | 'success' | 'failed' | 'timeout'; // Current polling state
1139
+ if (startResult.error_code) {
1140
+ showError(startResult.message);
1141
+ return;
1576
1142
  }
1577
- ```
1578
-
1579
- **When to use:**
1580
1143
 
1581
- - Set this callback before calling `pollSessionOutput` to receive real-time updates
1582
- - Display partial transcription results to improve user experience
1583
- - Show processing progress indicators
1584
- - Handle intermediate template results
1144
+ const sessionId = startResult.txn_id!;
1585
1145
 
1586
- **Note:** This callback is triggered multiple times during polling - once for each poll attempt until processing completes or times out.
1146
+ // 4. User interacts...
1147
+ // pauseBtn.onclick = () => ekascribe.pauseRecording();
1148
+ // resumeBtn.onclick = () => ekascribe.resumeRecording();
1587
1149
 
1588
- ### 4. VAD frames callback
1150
+ // 5. End recording
1151
+ const endResult = await ekascribe.endRecording();
1589
1152
 
1590
- This callback is triggered when VAD (Voice Activity Detection) processes audio frames. Use it to access raw audio frame data for custom processing.
1153
+ if (endResult.error_code === 'audio_upload_failed') {
1154
+ await ekascribe.retryUploadRecording();
1155
+ }
1591
1156
 
1592
- ```ts
1593
- ekascribe.onVadFramesCallback((framesData) => {
1594
- console.log('VAD frames received:', framesData);
1157
+ // 6. Get results
1158
+ const status = await ekascribe.getSessionStatus(sessionId, {
1159
+ poll: {
1160
+ maxAttempts: 60,
1161
+ intervalMs: 2000,
1162
+ onProgress: (s) => updateStatusUI(s.status),
1163
+ },
1595
1164
  });
1596
- ```
1597
-
1598
- ### 5. VAD frame processed callback
1599
1165
 
1600
- This callback is triggered after VAD has finished processing a frame. Use it to track VAD processing progress.
1166
+ if (status.success) {
1167
+ displayResults(status.data.templates, status.data.transcript);
1168
+ }
1601
1169
 
1602
- ```ts
1603
- ekascribe.onVadFrameProcessedCallback((processedData) => {
1604
- console.log('VAD frame processed:', processedData);
1605
- });
1170
+ // 7. Cleanup on unmount
1171
+ await ekascribe.resetInstance();
1606
1172
  ```
1607
1173
 
1608
- ### Error codes
1609
-
1610
- | Error Code | Description |
1611
- | --------------------- | ----------------------------------------------------------- |
1612
- | `microphone` | Microphone access error (permission denied or unavailable) |
1613
- | `txn_init_failed` | Failed to initialize transaction |
1614
- | `txn_limit_exceeded` | Maximum number of concurrent transactions exceeded |
1615
- | `unknown_error` | An unknown or unclassified error occurred |
1616
- | `txn_stop_failed` | Error occurred while stopping the transaction |
1617
- | `audio_upload_failed` | Audio file upload to server failed |
1618
- | `txn_commit_failed` | Commit call failed for the current transaction |
1619
- | `invalid_request` | Request to SDK was malformed or missing required parameters |
1620
- | `vad_not_initialized` | Voice activity detection engine was not initialized |
1621
- | `no_audio_capture` | No audio was captured during the recording session |
1622
- | `txn_status_mismatch` | Invalid operation due to mismatched transaction status |
1174
+ ---
1623
1175
 
1624
1176
  ## Contribution Guidelines
1625
1177
 
1626
- This is a continually updated, open source project.
1627
- Contributions are welcome!
1628
-
1629
- ## Tips
1630
-
1631
- - The SDK internally handles shared worker logic to reduce load on the main thread. Try to execute these functions in the main thread to avoid unnecessary issues.
1632
-
1633
- ## Advanced Usage (for later use)
1634
-
1635
- - Maximum retries for file upload in case of failure.
1636
- - Update VAD configurations
1637
-
1638
- ## Under Development
1639
-
1640
- - Opus compression of audio files
1641
- - Test cases
1178
+ This is a continually updated, open source project. Contributions are welcome!
1642
1179
 
1643
- Refer [Ekascribe](https://github.com/eka-care/v2rx-extension) for SDK implementations.
1180
+ Refer [EkaScribe TS SDK](https://github.com/eka-care/eka-js-sdk) for SDK implementation.