npm package: @cariva/asr-sdk-browser
Description: Browser SDK for Cariva ASR
Author: Cariva
Latest version: 1.6.0

# @cariva/asr-sdk-browser

<div align="center">

[![npm version](https://badge.fury.io/js/@cariva%2Fasr-sdk-browser.svg)](https://www.npmjs.com/package/@cariva/asr-sdk-browser)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Downloads](https://img.shields.io/npm/dm/@cariva/asr-sdk-browser.svg)](https://www.npmjs.com/package/@cariva/asr-sdk-browser)
[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@cariva/asr-sdk-browser.svg)](https://bundlephobia.com/package/@cariva/asr-sdk-browser)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
[![Browser Support](https://img.shields.io/badge/Browser-ES2020%2B-green.svg)](https://caniuse.com/es6)

**Professional medical transcription SDK for modern web applications**

[🚀 Quick Start](#quick-start) • [📖 API Reference](#api-reference) • [💡 Examples](#-examples) •
[🆘 Support](#support)

</div>

## Overview

A professional JavaScript/TypeScript SDK for medical speech recognition in web applications.
Purpose-built for healthcare workflows with specialized medical vocabulary, client-side audio
compression, and secure API communication.

### Features

- **Medical-First Design** — SOAP notes, clinical records, and nursing documentation
- **Client-Side Audio Processing** — Automatic MP3 compression via lamejs
- **Dual Authentication** — API key+secret (HMAC) or access token (Bearer)
- **Universal Audio Support** — WAV, MP3, MP4, M4A, WebM, OGG with automatic compression
- **Custom Payload Extension** — Pass arbitrary fields to the API via `taskPayload`
- **TypeScript Ready** — Full type safety and comprehensive error handling

## Installation

```bash
# npm
npm install @cariva/asr-sdk-browser

# yarn
yarn add @cariva/asr-sdk-browser

# pnpm
pnpm add @cariva/asr-sdk-browser

# bun
bun add @cariva/asr-sdk-browser
```

### CDN

```html
<!-- ES Modules (recommended for modern browsers) -->
<script type="module">
  import { ASR } from 'https://esm.sh/@cariva/asr-sdk-browser@latest';
  const asr = new ASR({ accessToken: 'your-token', mode: 'doc-ipd-soap' });
</script>

<!-- UMD (legacy browser support) -->
<script src="https://unpkg.com/@cariva/asr-sdk-browser@latest/dist/index.umd.js"></script>
<script>
  const { ASR } = CarivaASRBrowser;
  const asr = new ASR({ accessToken: 'your-token', mode: 'doc-ipd-soap' });
</script>
```

> **Production tip**: Pin to a specific version when loading from CDN.

## Quick Start

### Authentication

The SDK supports two mutually exclusive authentication methods:

```typescript
import { ASR } from '@cariva/asr-sdk-browser';

// Option A: API Key + Secret (HMAC)
const asr = new ASR({
  key: import.meta.env.VITE_CARIVA_API_KEY,
  secret: import.meta.env.VITE_CARIVA_API_SECRET,
  mode: 'doc-ipd-soap',
});

// Option B: Access Token (Bearer)
const asr = new ASR({
  accessToken: import.meta.env.VITE_CARIVA_ACCESS_TOKEN,
  mode: 'doc-ipd-soap',
});
```

### Basic Usage

```typescript
import { ASR } from '@cariva/asr-sdk-browser';

const asr = new ASR({
  accessToken: import.meta.env.VITE_CARIVA_ACCESS_TOKEN,
  mode: 'doc-ipd-soap',
  specialty: 'gen-practitioner',
});

const handleFile = async (file: File) => {
  const result = await asr.process(file, {
    onProgress: ({ percentage }) => {
      console.log(`Upload: ${percentage}%`);
    },
    onProcessing: step => {
      // "Creating transcription task..." → "Uploading audio file..." → "Processing audio..."
      console.log(step);
    },
  });

  console.log(result.data?.fastTranscription);
  console.log(result.data?.subjective);
};
```

### React Integration

```typescript
import { useState, useCallback } from 'react';
import { ASR, ASRError, type ASRConfig } from '@cariva/asr-sdk-browser';

export const useASR = (config: ASRConfig) => {
  const [asr] = useState(() => new ASR(config));
  const [isProcessing, setIsProcessing] = useState(false);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState<ASRError | null>(null);

  const processAudio = useCallback(
    async (file: File) => {
      setIsProcessing(true);
      setError(null);
      setProgress(0);

      try {
        const result = await asr.process(file, {
          onProgress: ({ percentage }) => setProgress(percentage),
          onProcessing: step => console.log(step),
        });
        return result;
      } catch (err) {
        setError(err as ASRError);
        throw err;
      } finally {
        setIsProcessing(false);
      }
    },
    [asr]
  );

  return { processAudio, isProcessing, progress, error };
};
```

## Medical Modes

<details>
<summary><strong>📋 SOAP Notes — <code>doc-ipd-soap</code></strong></summary>

**Best for**: Physician documentation, inpatient notes, clinical assessments

```typescript
const asr = new ASR({ /* config */ mode: 'doc-ipd-soap' });
const result = await asr.process(file);

interface SoapData {
  fastTranscription: string; // raw speech-to-text
  subjective?: string; // patient symptoms and history
  objective?: string; // clinical findings
  assessment?: string; // diagnosis and impressions
  plan?: string; // treatment and follow-up
}
```

> Alias: `'soap'`

</details>

<details>
<summary><strong>🏥 OPD Clinical Record — <code>doc-opd-clinicalrecord</code></strong></summary>

**Best for**: Outpatient consultations, comprehensive examinations

```typescript
interface OpdClinicalRecordData {
  fastTranscription: string;
  chiefComplaint: string;
  presentIllness: string;
  pastMedicalHistory: string;
  familyHistory: string;
  personalHistory?: string;
  currentMedication?: string;
  physicalExamination: {
    generalAppearance: string;
    heent: string;
    cardiovascular: string;
    respiratory: string;
    gastrointestinal: string;
    neurological: string;
    other: string;
    vitalSign: string;
  };
  diagnosis: string;
  investigation: string;
  treatment: string;
  plan: string;
  recommendation?: string;
  rawNote: string;
}
```

> Alias: `'medclerk'`

</details>

<details>
<summary><strong>👩‍⚕️ Nursing Notes (<code>nur-opd-nursenote-*</code>)</strong></summary>

Both `nur-opd-nursenote-*` and `nur-opd-nursenote-faie-*` map to the same API endpoint and return
the same data.

**Start of shift** — `nur-opd-nursenote-start` / `nur-opd-nursenote-faie-start`

```typescript
interface NurseNoteStartData {
  fastTranscription: string;
  rawNote: string;
  focus: string;
  assessment: string;
  intervention: string;
  vitalSigns: {
    heartRate: string;
    respiratoryRate: string;
    bloodPressure: string;
    bodyTemperature: string;
    oxygenSaturation: string;
  };
}
```

**End of shift** — `nur-opd-nursenote-end` / `nur-opd-nursenote-faie-end`

```typescript
interface NurseNoteEndData {
  fastTranscription: string;
  rawNote: string;
  evaluation: string;
  vitalSigns: {
    heartRate: string;
    respiratoryRate: string;
    bloodPressure: string;
    bodyTemperature: string;
    oxygenSaturation: string;
  };
}
```

</details>

<details>
<summary><strong>👩‍⚕️ Nursing Notes — ADPIE (<code>nur-opd-nursenote-adpie-*</code>)</strong></summary>

**Start of shift** — `nur-opd-nursenote-adpie-start`

```typescript
interface NurseNoteAdpieStartData {
  fastTranscription: string;
  rawNote: string;
  assessment: {
    objective: string;
    subjective: string;
  };
  diagnosis: string;
  planning: string;
  intervention: string;
}
```

**End of shift** — `nur-opd-nursenote-adpie-end`

```typescript
interface NurseNoteAdpieEndData {
  fastTranscription: string;
  rawNote: string;
  evaluation: string;
}
```

</details>

## Medical Specialties

### Primary Care & General Medicine

| Specialty                | Code               | Best For                             |
| ------------------------ | ------------------ | ------------------------------------ |
| **General Practitioner** | `gen-practitioner` | Family medicine, routine checkups    |
| **General Medicine**     | `gen-med`          | Internal medicine, hospitalist notes |
| **Emergency Medicine**   | `emergency`        | Trauma, urgent care, triage          |
| **General Pediatrics**   | `gen-ped`          | Children's healthcare                |

### Medical Specialties

| Specialty                   | Code             | Best For                                  |
| --------------------------- | ---------------- | ----------------------------------------- |
| **Cardiology**              | `med-cardio`     | Cardiac procedures, heart conditions      |
| **Pulmonology**             | `med-pulmonary`  | Respiratory conditions, lung function     |
| **Gastroenterology**        | `med-gastro`     | GI procedures, digestive disorders        |
| **Neurology**               | `med-neuro`      | Neurological assessments                  |
| **Nephrology**              | `med-nephro`     | Kidney conditions, dialysis               |
| **Oncology**                | `med-onco`       | Cancer treatment, oncology consultations  |
| **Endocrinology**           | `med-endo`       | Diabetes, hormonal disorders              |
| **Allergy & Immunology**    | `med-allergy`    | Allergic reactions, immunotherapy         |
| **Dermatology**             | `med-skin`       | Skin conditions                           |
| **Ophthalmology**           | `ophthalmology`  | Eye conditions                            |
| **Otolaryngology**          | `otolaryngology` | ENT procedures                            |
| **Obstetrics & Gynecology** | `ob-gyn`         | Women's health, pregnancy                 |
| **General Surgery**         | `surgery`        | Surgical procedures, operative notes      |
| **Orthopedic**              | `orthopedic`     | Bone, joint, and muscle conditions        |
| **Other**                   | `other`          | Uncommon specialties or mixed terminology |

## API Reference

### `ASRConfig`

| Field           | Type                      | Required              | Default                        | Description                                                                   |
| --------------- | ------------------------- | --------------------- | ------------------------------ | ----------------------------------------------------------------------------- |
| `key`           | `string`                  | ✓ (or `accessToken`)  | —                              | API key for HMAC authentication                                               |
| `secret`        | `string`                  | ✓ (or `accessToken`)  | —                              | API secret for HMAC authentication                                            |
| `accessToken`   | `string`                  | ✓ (or `key`+`secret`) | —                              | Bearer token authentication                                                   |
| `mode`          | `Mode`                    | ✓                     | —                              | Transcription mode                                                            |
| `lang`          | `string`                  | —                     | `'en'`                         | Language hint                                                                 |
| `specialty`     | `string`                  | —                     | `'gen-practitioner'`           | Medical specialty code                                                        |
| `newLineString` | `string`                  | —                     | `undefined`                    | Replace newlines in output                                                    |
| `prefix`        | `string`                  | —                     | `undefined`                    | Text prefix for the result                                                    |
| `suggestion`    | `boolean`                 | —                     | `undefined`                    | Enable suggestion mode                                                        |
| `timeout`       | `number`                  | —                     | `300000`                       | Request timeout in ms                                                         |
| `baseUrl`       | `string`                  | —                     | `CARIVA_BASE_URL` (build-time) | Override API base URL; runtime value takes precedence over build-time env var |
| `taskPayload`   | `Record<string, unknown>` | —                     | `undefined`                    | Extra fields merged into every create-task request                            |

> Provide either (`key` + `secret`) **or** `accessToken` — not both.

### `BrowserProcessOptions`

| Field           | Type                                                                 | Description                                                                  |
| --------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `lang`          | `string`                                                             | Override language for this call                                              |
| `specialty`     | `string`                                                             | Override specialty for this call                                             |
| `newLineString` | `string`                                                             | Override newline replacement for this call                                   |
| `prefix`        | `string`                                                             | Override prefix for this call                                                |
| `suggestion`    | `boolean`                                                            | Override suggestion mode for this call                                       |
| `taskPayload`   | `Record<string, unknown>`                                            | Extra fields for this call (merged with config-level, call wins on conflict) |
| `onProgress`    | `(p: { percentage: number, loaded: number, total: number }) => void` | Upload progress callback                                                     |
| `onProcessing`  | `(step: string) => void`                                             | Processing step callback                                                     |

### Instance Methods

| Method          | Signature                                                                              | Description                   |
| --------------- | -------------------------------------------------------------------------------------- | ----------------------------- |
| `process`       | `(file: File \| Blob, options?: BrowserProcessOptions) => Promise<TaskStatusResponse>` | Transcribe an audio file      |
| `cancelASRTask` | `() => Promise<void>`                                                                  | Cancel the current task       |
| `rateASRTask`   | `(score: number, comment?: string, categories?: string[]) => Promise<void>`            | Rate quality (score: 1–5)     |
| `create`        | `() => Promise<this>`                                                                  | Reset instance for a new task |

### Getters

| Getter         | Type      | Description                                     |
| -------------- | --------- | ----------------------------------------------- |
| `taskId`       | `string`  | Current task ID (empty until processing starts) |
| `status`       | `string`  | Current task status                             |
| `isProcessing` | `boolean` | Whether the instance is currently processing    |

### `TaskStatusResponse`

```typescript
interface TaskStatusResponse {
  taskId: string;
  status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';
  data?: {
    fastTranscription?: string;
    [key: string]: any; // mode-specific fields (subjective, objective, focus, etc.)
  };
  error?: string;
  progress?: number;
  createdAt?: string;
  updatedAt?: string;
  completedAt?: string;
}
```

### Exported Types

```typescript
import {
  ASR,
  type ASRConfig,
  type BrowserProcessOptions,
  type ProcessingCallbacks,
  type Mode,
  type UploadProgress,
  type TaskStatusResponse,
  ASRError,
  ASRValidationError,
  ASRProcessingError,
} from '@cariva/asr-sdk-browser';
```

## Custom Task Payload (`taskPayload`)

Pass arbitrary extra fields to the create-task API request. The SDK forwards them as-is without
validation or transformation.

```typescript
// Config-level: applied to every process() call
const asr = new ASR({
  accessToken: import.meta.env.VITE_CARIVA_ACCESS_TOKEN,
  mode: 'doc-ipd-soap',
  taskPayload: {
    patientId: 'P-001',
    sessionId: 'SESSION-XYZ',
  },
});

// Per-call: merged with config-level (call wins on conflict)
const result = await asr.process(file, {
  taskPayload: { encounterId: 'ENC-2026-XYZ' },
  // Final body includes: patientId, sessionId (config) + encounterId (call)
});
```

> SDK-controlled fields (`mode`, `sdkVersion`, `voiceDuration`, etc.) always take precedence over
> any key in `taskPayload`.

## Progress Tracking

```typescript
const result = await asr.process(file, {
  onProgress: ({ percentage, loaded, total }) => {
    console.log(`Upload: ${percentage}% (${loaded}/${total} bytes)`);
    updateProgressBar(percentage);
  },
  onProcessing: step => {
    // "Creating transcription task..."
    // "Uploading audio file..."
    // "Processing audio..."
    showStatus(step);
  },
});
```

## Error Handling

```typescript
import { ASRError, ASRValidationError, ASRProcessingError } from '@cariva/asr-sdk-browser';

try {
  const result = await asr.process(file);
} catch (error) {
  if (error instanceof ASRValidationError) {
    // Invalid configuration or input (e.g. missing credentials, invalid file type)
    console.error('Validation error:', error.message);
  } else if (error instanceof ASRProcessingError) {
    // Audio processing pipeline failure
    console.error('Processing error:', error.message);
  } else if (error instanceof ASRError) {
    // API or network error
    console.error(`[${error.code}] ${error.message}`);
  }
}
```

### Error Classes

| Class                | Code                | When thrown                        |
| -------------------- | ------------------- | ---------------------------------- |
| `ASRValidationError` | `VALIDATION_ERROR`  | Invalid config or input parameters |
| `ASRProcessingError` | `PROCESSING_ERROR`  | Audio processing pipeline failure  |
| `ASRError`           | _(see table below)_ | API, network, and runtime errors   |

### `ASRError` Codes

| Code                   | Description                                                                                        |
| ---------------------- | -------------------------------------------------------------------------------------------------- |
| `CREATE_TASK_FAILED`   | Failed to create transcription task                                                                |
| `UPLOAD_FAILED`        | Audio upload to signed URL failed                                                                  |
| `UPLOAD_ABORTED`       | Upload was cancelled                                                                               |
| `TRANSCRIPTION_FAILED` | Audio processing failed on the server                                                              |
| `GET_STATUS_FAILED`    | Failed to retrieve task status                                                                     |
| `PROCESS_FAILED`       | General processing failure                                                                         |
| `PROCESSING_TIMED_OUT` | Processing exceeded the configured timeout                                                         |
| `NO_RESULT_DATA`       | Task completed but returned no data                                                                |
| `RATING_FAILED`        | Failed to submit rating                                                                            |
| `NO_TASK_ID`           | No task ID available for the operation                                                             |
| `NO_API_CLIENT`        | API client not initialized                                                                         |
| `NO_UPLOAD_METHOD`     | No upload method available in the runtime                                                          |
| `NETWORK_ERROR`        | Network or connection failure during upload                                                        |
| `CONSENT_REQUIRED`     | Account must accept Terms & Conditions — log in at [space.cariva.co.th](http://space.cariva.co.th) |
| `INVALID_SCORE`        | Rating score must be between 1 and 5                                                               |

## Cancellation

```typescript
const transcriptionPromise = asr.process(file);

// Cancel after 5 minutes
setTimeout(
  async () => {
    await asr.cancelASRTask();
    console.log('Cancelled');
  },
  5 * 60 * 1000
);

const result = await transcriptionPromise;
```

## Rating Transcriptions

```typescript
// Rate after process() completes (score: 1–5)
await asr.rateASRTask(5, 'Excellent medical transcription accuracy!');

// With categories
await asr.rateASRTask(4, 'Good overall', ['medical-terminology', 'accuracy']);

// Score only
await asr.rateASRTask(3);
```

| Stars      | Meaning                                       |
| ---------- | --------------------------------------------- |
| ⭐⭐⭐⭐⭐ | Perfect — no errors                           |
| ⭐⭐⭐⭐   | Minor errors, easily corrected                |
| ⭐⭐⭐     | Some errors, mostly accurate                  |
| ⭐⭐       | Multiple errors, needs significant correction |
| ⭐         | Poor quality, major errors throughout         |

## 🔒 Security

```typescript
// ❌ Never hardcode credentials in client-side code
const asr = new ASR({ key: 'sk_live_...', secret: '...' });

// ✅ Use environment variables with build-time substitution (Vite / webpack)
const asr = new ASR({
  accessToken: import.meta.env.VITE_CARIVA_ACCESS_TOKEN,
  mode: 'doc-ipd-soap',
});
```

## Browser Compatibility

| Browser     | Minimum Version |
| ----------- | --------------- |
| **Chrome**  | 90+             |
| **Firefox** | 88+             |
| **Safari**  | 14+             |
| **Edge**    | 90+             |

## 💡 Examples

### Vue 3 Composable

```typescript
// composables/useASR.ts
import { ref } from 'vue';
import { ASR, ASRError, type ASRConfig } from '@cariva/asr-sdk-browser';

export function useASR(config: ASRConfig) {
  const asr = new ASR(config);
  const isProcessing = ref(false);
  const progress = ref(0);
  const error = ref<ASRError | null>(null);

  async function processAudio(file: File) {
    isProcessing.value = true;
    error.value = null;
    progress.value = 0;

    try {
      const result = await asr.process(file, {
        onProgress: ({ percentage }) => {
          progress.value = percentage;
        },
      });
      return result;
    } catch (err) {
      error.value = err as ASRError;
      throw err;
    } finally {
      isProcessing.value = false;
    }
  }

  return { processAudio, isProcessing, progress, error };
}
```

### Vanilla JS (CDN)

```html
<input type="file" id="audioFile" accept="audio/*" />
<button id="transcribeBtn">Transcribe</button>
<pre id="output"></pre>

<script src="https://unpkg.com/@cariva/asr-sdk-browser@latest/dist/index.umd.js"></script>
<script>
  const { ASR } = CarivaASRBrowser;

  const asr = new ASR({
    accessToken: 'your-access-token',
    mode: 'doc-ipd-soap',
  });

  document.getElementById('transcribeBtn').addEventListener('click', async () => {
    const file = document.getElementById('audioFile').files[0];
    if (!file) return;

    try {
      const result = await asr.process(file);
      document.getElementById('output').textContent = JSON.stringify(result.data, null, 2);
    } catch (err) {
      document.getElementById('output').textContent = `Error: ${err.message}`;
    }
  });
</script>
```

## Related Packages

| Package                                                                        | Purpose                |
| ------------------------------------------------------------------------------ | ---------------------- |
| **[@cariva/asr-sdk-node](https://www.npmjs.com/package/@cariva/asr-sdk-node)** | Server-side processing |

## Support

For technical support and inquiries, please visit our
[Contact Page](https://cariva.co.th/en/contact).

## Contributing

When reporting issues, please include:

- Browser version and OS
- File format and size
- Error message and stack trace
- Steps to reproduce

## License

This project is licensed under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0).

```
Copyright 2025 Cariva

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

---