Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,37 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.4.0] - 2026-07-08

### Added

- **Caption export helpers.** New `toSRT()` and `toWebVTT()` exports that
convert a Deepgram pre-recorded transcription response (word timings, or
utterances when `utterances=true`) into SubRip / WebVTT subtitle text.
Cue segmentation is tunable via `CaptionOptions` (`lineLength`, `lineCount`,
`speakerLabels` for diarized `Speaker N:` prefixes). Pure functions — no
network or native calls.
- **Speaker-attributed transcripts.** New `toSpeakerSegments()` export that
folds a diarized (`diarize=true`) response into ordered
`SpeakerSegment { speaker, text, start, end, confidence }` chunks, merging
consecutive words from the same speaker. Returns `[]` for non-diarized
responses instead of throwing.
- **Session telemetry.** `useDeepgramSpeechToText` and `useDeepgramVoiceAgent`
now expose a `getStats()` method returning a `SessionStats` snapshot
(`bytesSent`, `bytesReceived`, `framesDropped`, `reconnects`,
`connectedAtMs`, `firstResultMs`). An opt-in `trackStats` prop additionally
enables a reactive `stats` return value, throttled to at most one update per
second so it never floods renders.
- **Voice Agent barge-in.** Opt-in `bargeIn` prop on `useDeepgramVoiceAgent`
flushes the native playback queue when the server reports
`UserStartedSpeaking` while agent audio is playing, so the agent audibly
stops when the user talks over it. Fires the new `onBargeIn` callback only
when a flush actually happened; never flushes while muted, and the streaming
player resumes seamlessly on the agent's next turn. Reliable barge-in
depends on hardware echo cancellation — test on a physical device.

All additions are backwards compatible and opt-in; no breaking changes.

## [2.3.0] - 2026-07-06

### Added
Expand Down
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ const {
| `defaultSettings` | `DeepgramVoiceAgentSettings` | – | Base `Settings` payload sent on connect; merge per-call overrides via `connect(override)`. |
| `autoStartMicrophone` | `boolean` | `true` | Automatically requests mic access and starts streaming PCM. |
| `autoPlayAudio` | `boolean` | `true` | Plays received audio using the native player. |
| `bargeIn` | `boolean` | `false` | Flush the agent's queued playback when the server reports `UserStartedSpeaking`, so the agent audibly stops when the user talks over it. Only flushes while agent audio is actually playing and the mic is not muted; the player stays usable for the next agent turn. Requires `autoPlayAudio`. Barge-in depends on hardware echo cancellation — test on a physical device (simulators have no VPIO, so the agent's own audio can trigger the VAD). |
| `downsampleFactor` | `number` | heuristic | Manually override the downsample ratio applied to captured audio. |
| `reconnect` | `DeepgramReconnectOptions` | `{ enabled: false }` | Auto-reconnect config for the agent socket. The stored `Settings` payload is re-sent on every successful reconnect. |

Expand All @@ -614,6 +615,7 @@ const {
| `onError` | `(error: unknown) => void` | Unexpected client-side error (mic, playback, socket send). |
| `onReconnecting` | `(attempt: number) => void` | A reconnect attempt begins (1-based attempt number). Requires `reconnect.enabled`. |
| `onReconnected` | `() => void` | The socket reconnects and the stored settings are re-sent. |
| `onBargeIn` | `() => void` | A `bargeIn` flush actually happened (agent audio was cut short by the user speaking). |
| `onServerError` | `(message: DeepgramVoiceAgentErrorMessage) => void` | API reports a structured error (`description` + `code`). |
| `onWarning` | `(message: DeepgramVoiceAgentWarningMessage) => void` | Non-fatal warning (e.g. degraded audio quality). |

Expand Down Expand Up @@ -1528,6 +1530,51 @@ const pick = async () => {
};
```

### Generate subtitles from a transcription

`toSRT` / `toWebVTT` turn a raw pre-recorded `/listen` response into a
subtitle document — zero dependencies, pure functions. Request
`utterances: true` for the best cue boundaries (the helpers fall back to
word-level chunking otherwise), and pass `speakerLabels: true` alongside
`diarize: true` to prefix cues with `Speaker N:`.

```tsx
import { toSRT, toWebVTT } from 'react-native-deepgram';
import type { DeepgramPrerecordedResponse } from 'react-native-deepgram';

const res = await fetch(
'https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true&utterances=true&diarize=true',
{
method: 'POST',
headers: {
'Authorization': `Token ${DEEPGRAM_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url: 'https://dpgr.am/spacewalk.wav' }),
}
);
const response: DeepgramPrerecordedResponse = await res.json();

const srt = toSRT(response, { lineLength: 32, lineCount: 2 });
const vtt = toWebVTT(response, { speakerLabels: true });
```

### Split a transcript by speaker

`toSpeakerSegments` folds the word-level diarization data of a response
requested with `diarize: true` into per-speaker segments (it returns `[]`
when diarization wasn't requested). Pairs naturally with the caption
helpers' `speakerLabels` option above.

```tsx
import { toSpeakerSegments } from 'react-native-deepgram';

const segments = toSpeakerSegments(response); // same response as above
segments.forEach(({ speaker, text, start, end, confidence }) => {
console.log(`[${start}s–${end}s] Speaker ${speaker} (${confidence}): ${text}`);
});
```

### Record the mic to a file while transcribing

Persist the captured audio to a WAV file *and* get the live transcript at the
Expand Down
17 changes: 6 additions & 11 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@ import TextToSpeech from './TextToSpeech';
import VoiceAgent from './VoiceAgent';
import { colors, radius, spacing, type } from './theme';

// Initialize Deepgram once at startup. Provide your key via .env (EXPO_PUBLIC_DEEPGRAM_API_KEY).
//
// Custom endpoints (regional, Dedicated, or self-hosted) are opt-in: set any of
// the EXPO_PUBLIC_DEEPGRAM_BASE_URL / BASE_WSS / AGENT_URL vars in .env and they
// flow straight into configure(). Leave them unset to use Deepgram's defaults.
//
// Auth: for production, prefer ephemeral tokens over a raw API key. Set
// EXPO_PUBLIC_DEEPGRAM_TOKEN_URL to a backend endpoint that proxies Deepgram's
// /v1/auth/grant and returns { access_token, expires_in }. When set, `getToken`
// is used (and takes precedence over apiKey) so the key never ships in the app.
// See README → "Ephemeral / scoped tokens".
// Initialize Deepgram once at startup (key via EXPO_PUBLIC_DEEPGRAM_API_KEY).
// Custom endpoints are opt-in via EXPO_PUBLIC_DEEPGRAM_BASE_URL / BASE_WSS /
// AGENT_URL. For production, prefer ephemeral tokens: set
// EXPO_PUBLIC_DEEPGRAM_TOKEN_URL to a backend that proxies /v1/auth/grant and
// returns { access_token, expires_in } — getToken then takes precedence over
// apiKey so the key never ships in the app. See README → "Ephemeral / scoped tokens".
const tokenUrl = process.env.EXPO_PUBLIC_DEEPGRAM_TOKEN_URL;

configure({
Expand Down
Loading
Loading