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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [4.35.3]

- Allow `language_codes` in `updateConfiguration()` — re-steer the transcription language mid-stream without reconnecting; pass `[]` to clear steering and restore the model's default multilingual code-switching (Universal-3.5 Pro Streaming only)

## [4.35.2]

- Add `opus` and `ogg_opus` streaming `encoding` values — accepts compressed Opus audio (raw packet-per-message or Ogg-encapsulated). `sampleRate` is ignored for both; the Opus stream is self-describing

## [4.35.1]

- Add `languageCodes` streaming parameter — steers transcription toward a set of languages (Universal-3.5 Pro Streaming only). Recommended replacement for `languageCode`, which is now deprecated but still supported

## [4.34.6]

- Add `keepAlive()` method to `StreamingTranscriber` — sends a `KeepAlive` message to reset the server's inactivity timer when `inactivityTimeout` is configured
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ const audioFile = "https://assembly.ai/sports_injuries.mp3";

const params = {
audio: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
speech_models: ["universal-3-5-pro", "universal-2"],
language_detection: true,
};

Expand All @@ -151,7 +151,7 @@ If you don't want to wait until the transcript is ready, you can use `submit`:
```js
let transcript = await client.transcripts.submit({
audio: "https://assembly.ai/espn.m4a",
speech_models: ["universal-3-pro", "universal-2"],
speech_models: ["universal-3-5-pro", "universal-2"],
language_detection: true,
});
```
Expand All @@ -167,7 +167,7 @@ When you create a transcript, you can either pass in a URL to an audio file or u
// Upload a file via local path and transcribe
let transcript = await client.transcripts.transcribe({
audio: "./news.mp4",
speech_models: ["universal-3-pro", "universal-2"],
speech_models: ["universal-3-5-pro", "universal-2"],
language_detection: true,
});
```
Expand All @@ -182,7 +182,7 @@ If you don't want to wait until the transcript is ready, you can use `submit`:
```js
let transcript = await client.transcripts.submit({
audio: "./news.mp4",
speech_models: ["universal-3-pro", "universal-2"],
speech_models: ["universal-3-5-pro", "universal-2"],
language_detection: true,
});
```
Expand All @@ -206,7 +206,7 @@ const audioFile = "https://assembly.ai/wildfires.mp3";

const params = {
audio: audioFile,
speech_models: ["universal-3-pro", "universal-2"],
speech_models: ["universal-3-5-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
};
Expand Down Expand Up @@ -321,7 +321,6 @@ Create the streaming transcriber.
const transcriber = client.streaming.transcriber({
speechModel: "universal-3-5-pro",
sampleRate: 16_000,
formatTurns: true,
});
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "assemblyai",
"version": "4.35.0",
"version": "4.35.3",
"description": "The AssemblyAI JavaScript SDK provides an easy-to-use interface for interacting with the AssemblyAI API, which supports async and real-time transcription, as well as the latest LeMUR models.",
"engines": {
"node": ">=18"
Expand Down
2 changes: 1 addition & 1 deletion src/exports/streaming.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from "../types/asyncapi.generated";
export * from "../types/realtime";
export * from "../types/helpers";
export * from "../types/streaming/dual-channel";
export * from "../types/streaming";
export * from "../services/realtime/service";
export * from "../services/streaming/service";
export * from "../services/streaming/factory";
Expand Down
10 changes: 10 additions & 0 deletions src/services/streaming/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,19 @@ export class StreamingTranscriber {
}

if (this.params.languageCode !== undefined) {
console.warn(
"[Deprecation Warning] `languageCode` is deprecated and will be removed in a future release. Please use `languageCodes` instead.",
);
searchParams.set("language_code", this.params.languageCode);
}

if (this.params.languageCodes !== undefined) {
searchParams.set(
"language_codes",
JSON.stringify(this.params.languageCodes),
);
}

if (this.params.languageDetection !== undefined) {
searchParams.set(
"language_detection",
Expand Down
2 changes: 1 addition & 1 deletion src/types/asyncapi.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export type AudioData = ArrayBufferLike;
* The encoding of the audio data
* @defaultValue "pcm_s16"le
*/
export type AudioEncoding = "pcm_s16le" | "pcm_mulaw";
export type AudioEncoding = "pcm_s16le" | "pcm_mulaw" | "opus" | "ogg_opus";

/**
* Configure the threshold for how long to wait before ending an utterance. Default is 700ms.
Expand Down
18 changes: 18 additions & 0 deletions src/types/streaming/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,19 @@ export type StreamingTranscriberParams = {
prompt?: string;
agentContext?: string;
speechModel?: StreamingSpeechModel;
/**
* @deprecated Use `languageCodes` instead (pass a single-element array, e.g. `["es"]`,
* for the same behavior). Still supported for backward compatibility.
*/
languageCode?: string;
/**
* Recommended way to select languages. Steers transcription toward a set of
* languages by biasing output toward them on a per-token basis while still
* allowing native code-switching among them. Pass the languages you expect
* (e.g. `["en", "es"]`), or a single-element array (e.g. `["es"]`) for a
* monolingual session. Universal-3.5 Pro Streaming only.
*/
languageCodes?: string[];
languageDetection?: boolean;
domain?: StreamingDomain;
inactivityTimeout?: number;
Expand Down Expand Up @@ -359,6 +371,12 @@ export type StreamingUpdateConfiguration = {
filter_profanity?: boolean;
interruption_delay?: number;
turn_left_pad_ms?: number;
/**
* Steer transcription toward a set of languages mid-stream. Pass an empty
* array (`[]`) to clear steering and restore the model's default
* multilingual code-switching. Universal-3.5 Pro Streaming only.
*/
language_codes?: string[];
};

export type StreamingForceEndpoint = {
Expand Down
61 changes: 61 additions & 0 deletions tests/unit/streaming.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,26 @@ describe("streaming", () => {
);
});

it("should include language_codes in updateConfiguration message", async () => {
rt.updateConfiguration({ language_codes: ["en", "es"] });
await expect(server).toReceiveMessage(
JSON.stringify({
type: "UpdateConfiguration",
language_codes: ["en", "es"],
}),
);
});

it("should send an empty language_codes array in updateConfiguration to clear steering", async () => {
rt.updateConfiguration({ language_codes: [] });
await expect(server).toReceiveMessage(
JSON.stringify({
type: "UpdateConfiguration",
language_codes: [],
}),
);
});

it("should send KeepAlive message on keepAlive()", async () => {
rt.keepAlive();
await expect(server).toReceiveMessage(
Expand Down Expand Up @@ -347,6 +367,47 @@ describe("streaming", () => {
await connect(rt, server);
});

it("should include language_codes in connection URL", async () => {
await cleanup();
WS.clean();

const languageCodes = ["en", "es"];
const wsUrl =
`${websocketBaseUrl}?token=123&sample_rate=16000&speech_model=universal-3-5-pro` +
`&language_codes=${encodeURIComponent(JSON.stringify(languageCodes))}`;
server = new WS(wsUrl);
rt = new StreamingTranscriber({
websocketBaseUrl,
token: "123",
sampleRate: 16_000,
speechModel: "universal-3-5-pro",
languageCodes: ["en", "es"],
});
onOpen = jest.fn();
rt.on("open", onOpen);
await connect(rt, server);
});

it.each(["opus", "ogg_opus"] as const)(
"should include %s encoding in connection URL",
async (encoding) => {
await cleanup();
WS.clean();

const wsUrl = `${websocketBaseUrl}?token=123&sample_rate=16000&encoding=${encoding}`;
server = new WS(wsUrl);
rt = new StreamingTranscriber({
websocketBaseUrl,
token: "123",
sampleRate: 16_000,
encoding,
});
onOpen = jest.fn();
rt.on("open", onOpen);
await connect(rt, server);
},
);

it("should include whisper-rt speech model in connection URL", async () => {
await cleanup();
WS.clean();
Expand Down
Loading