diff --git a/CHANGELOG.md b/CHANGELOG.md index a132284..2fc1e89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.41.8] + +- Add `speakers` to `SpeakerIdentificationRequest` and export `SpeakerDescription` — enables passing rich speaker metadata (`name`, `role`, `description`) for speaker identification in Speech Understanding +- Add `force_translation` to `TranslationRequest` — enables translating audio even when the detected source language equals a target language +- Add `format_utterances` to `CustomFormattingRequest` — enables applying custom formatting at the utterance level + ## [4.41.7] - Add `summarization` to the speech understanding feature requests and responses (`SummarizationRequest`, `SummarizationResponse`): `summary_type`, `headline_length`, `approximate_chapters` and `effort`. The feature was already accepted by the API but missing from the SDK types, so setting it failed to type check diff --git a/package.json b/package.json index 7670770..e6b3e97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "assemblyai", - "version": "4.41.7", + "version": "4.41.8", "description": "The AssemblyAI JavaScript SDK provides an easy-to-use interface for interacting with the AssemblyAI API, which supports async and real-time transcription.", "engines": { "node": ">=18" diff --git a/src/types/openapi.generated.ts b/src/types/openapi.generated.ts index c7f0b66..8b257ad 100644 --- a/src/types/openapi.generated.ts +++ b/src/types/openapi.generated.ts @@ -1052,6 +1052,25 @@ export type SpeakerType = "role" | "name"; */ export type SpeechUnderstandingEffort = "low" | "medium"; +/** + * Speaker description for speaker identification with rich metadata + */ +export type SpeakerDescription = { + /** + * Speaker name (when speaker_type is 'name') + */ + name?: string; + /** + * Speaker role (when speaker_type is 'role') + */ + role?: string; + /** + * Description of the speaker's role or characteristics in the audio + */ + description?: string; + [key: string]: unknown; +}; + /** * Speaker identification configuration for speech understanding */ @@ -1061,9 +1080,13 @@ export type SpeakerIdentificationRequest = { */ speaker_type: SpeakerType; /** - * Known speaker values (required when speaker_type is 'role') + * Known speaker values (required when speaker_type is 'role' if speakers is not provided) */ known_values?: string[]; + /** + * Rich speaker metadata per speaker. Each entry should have name (when speaker_type is 'name') or role (when speaker_type is 'role'). + */ + speakers?: SpeakerDescription[]; /** * How much effort to spend on this task * @@ -1088,6 +1111,12 @@ export type TranslationRequest = { * Whether to match the original utterance structure in translations (default: false) */ match_original_utterance?: boolean; + /** + * Whether to translate even when the detected source language equals a target language + * + * @defaultValue false + */ + force_translation?: boolean; /** * How much effort to spend on this task * @@ -1112,6 +1141,12 @@ export type CustomFormattingRequest = { * Custom email format pattern (e.g., 'username\@domain.com') */ email?: string; + /** + * Whether to also format utterance-level text + * + * @defaultValue false + */ + format_utterances?: boolean; /** * How much effort to spend on this task * diff --git a/tests/unit/speech-understanding-effort.test.ts b/tests/unit/speech-understanding-effort.test.ts index 1a11806..08df0c9 100644 --- a/tests/unit/speech-understanding-effort.test.ts +++ b/tests/unit/speech-understanding-effort.test.ts @@ -1,6 +1,7 @@ import fetchMock from "jest-fetch-mock"; import { CustomFormattingRequest, + SpeakerDescription, SpeakerIdentificationRequest, SpeechUnderstandingEffort, TranslationRequest, @@ -125,6 +126,92 @@ describe("speech understanding effort", () => { expect(speakerIdentification.effort).toBeUndefined(); }); + it("should create transcript with speaker_identification speakers list", async () => { + const speakers: SpeakerDescription[] = [ + { name: "Alice", description: "Host of the podcast" }, + { name: "Bob", description: "Featured guest discussing AI", title: "Dr." }, + ]; + const speakerIdentification: SpeakerIdentificationRequest = { + speaker_type: "name", + speakers, + effort: "medium", + }; + mockSubmit(); + + const transcript = await assembly.transcripts.submit({ + audio_url: remoteAudioURL, + speaker_labels: true, + speech_understanding: { + request: { speaker_identification: speakerIdentification }, + }, + }); + + expect(transcript.id).toBe(transcriptId); + expect(submittedRequest().speaker_identification).toEqual(speakerIdentification); + expect(submittedRequest().speaker_identification.speakers).toEqual(speakers); + }); + + it("should create transcript with speaker_identification speakers by role", async () => { + const speakers: SpeakerDescription[] = [ + { role: "Agent", description: "Customer support specialist" }, + { role: "Customer", description: "Account owner inquiring about billing" }, + ]; + const speakerIdentification: SpeakerIdentificationRequest = { + speaker_type: "role", + speakers, + }; + mockSubmit(); + + await assembly.transcripts.submit({ + audio_url: remoteAudioURL, + speaker_labels: true, + speech_understanding: { + request: { speaker_identification: speakerIdentification }, + }, + }); + + expect(submittedRequest().speaker_identification.speaker_type).toBe("role"); + expect(submittedRequest().speaker_identification.speakers).toEqual(speakers); + expect(submittedRequest().speaker_identification.known_values).toBeUndefined(); + }); + + it("should create transcript with translation force_translation", async () => { + const translation: TranslationRequest = { + target_languages: ["es", "fr"], + force_translation: true, + effort: "medium", + }; + mockSubmit(); + + await assembly.transcripts.submit({ + audio_url: remoteAudioURL, + speech_understanding: { request: { translation } }, + }); + + expect(submittedRequest().translation).toEqual(translation); + expect(submittedRequest().translation.force_translation).toBe(true); + }); + + it("should create transcript with custom_formatting format_utterances", async () => { + const customFormatting: CustomFormattingRequest = { + date: "mm/dd/yyyy", + phone_number: "(xxx)xxx-xxxx", + format_utterances: true, + effort: "medium", + }; + mockSubmit(); + + await assembly.transcripts.submit({ + audio_url: remoteAudioURL, + speech_understanding: { + request: { custom_formatting: customFormatting }, + }, + }); + + expect(submittedRequest().custom_formatting).toEqual(customFormatting); + expect(submittedRequest().custom_formatting.format_utterances).toBe(true); + }); + it("should accept every documented effort value", () => { const efforts: SpeechUnderstandingEffort[] = ["low", "medium"];