> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # Inworld Realtime 語音 `InworldRealtimeVoice` 類別透過 WebSocket 使用 [Inworld AI 的 Realtime API](https://docs.inworld.ai/realtime/quickstart-websocket),提供即時、全雙工的語音互動。它支援語音對語音、Tool 呼叫,以及語意式語音活動偵測、MCP Tool 路由與播放速度等 Inworld 特定工作階段控制項。 Inworld 的線路通訊協定採用 OpenAI Realtime GA 規格,因此使用者端和伺服器的事件名稱與 `@mastra/voice-openai-realtime` 相同。Provider 層級的差異包括端點(在 URL 中使用使用者端產生的工作階段金鑰)、`Authorization: Basic ` 標頭、用於 Inworld 特定控制項的具型別 `session` 建構函式欄位,以及用於 Inworld 擴充功能(STT、TTS、記憶體、反饋語和回應速度)的具型別 `providerData` 物件;此物件會在 `session.providerData` 下傳送。 若要使用批次文字轉語音與語音轉文字,請參閱 [`@mastra/voice-inworld`](https://mastra.zisheng.pro/zh-TW/reference/voice/inworld)。 ## 使用範例 ```typescript import { InworldRealtimeVoice } from '@mastra/voice-inworld' import { playAudio, getMicrophoneStream } from '@mastra/node-audio' // Initialize with INWORLD_API_KEY from the environment const voice = new InworldRealtimeVoice() // Or initialize with explicit configuration const voiceWithConfig = new InworldRealtimeVoice({ apiKey: 'your-inworld-api-key', model: 'inworld/models/gemma-4-26b-a4b-it', speaker: 'Sarah', instructions: 'You are a helpful voice assistant.', session: { audio: { output: { speed: 1.1 }, input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } }, }, }, }) // Establish connection await voice.connect() // Listen for audio output (PCM16 @ 24 kHz by default) voice.on('speaker', stream => { playAudio(stream) }) voice.on('writing', ({ text, role }) => { console.log(`${role}: ${text}`) }) // Convert text to speech await voice.speak('Hello, how can I help you today?', { speaker: 'Hades', }) // Stream microphone audio to the model const microphoneStream = getMicrophoneStream() await voice.send(microphoneStream) // Clean up voice.close() ``` > Inworld API 金鑰已預先使用 Basic 編碼。請將金鑰原封不動地貼入 `INWORLD_API_KEY`。此套件不會重新編碼金鑰。 ## 建構函式參數 **apiKey** (`string`): Inworld API 金鑰。未提供時會改用 INWORLD\_API\_KEY 環境變數。金鑰已使用 Basic 編碼,並會原封不動地傳入 Authorization 標頭。 **url** (`string`): Realtime WebSocket 端點。系統會自動附加使用者端產生的工作階段金鑰和通訊協定參數。 (Default: `'wss://api.inworld.ai/api/v1/realtime/session'`) **model** (`string`): LLM Router 模型 ID。透過初始的 session.update 傳送,而非放在 URL 中。可接受 Inworld Router 支援的任何模型。 (Default: `'inworld/models/gemma-4-26b-a4b-it'`) **speaker** (`string`): 語音合成的預設語音 ID。可接受 Inworld 目錄中的任何語音。 (Default: `'Sarah'`) **sessionId** (`string`): 使用者端產生的工作階段金鑰,會以 URL 的 key 參數公開。省略時會自動產生以時間戳記為基礎的金鑰。 (Default: `'voice-{Date.now()}'`) **instructions** (`string`): 隨初始 session.update 傳送的系統提示。 **session** (`Partial`): 具型別的一級工作階段選項(audio、tool\_choice、output\_modalities、temperature 等)。每次 session.update 都會深度合併這些選項,因此 audio.output.voice 和 audio.output.speed 等巢狀欄位會組合,而不會互相覆寫。請參閱下方的 session 欄位。 **debug** (`boolean`): 記錄原始伺服器事件。 (Default: `false`) **providerData** (`InworldProviderData`): 具型別的 Inworld 擴充功能設定(stt、tts、memory、backchannel、responsiveness,以及 user\_id 和 metadata)。每次 session.update 都會在 session.providerData 下傳送。它會與透過 session 欄位設定的任何 session.providerData 組合;若金鑰衝突,以建構函式選項為準。 **connectTimeoutMs** (`number`): connect() 等待 WebSocket 交握和初始 session.updated 往返的最長時間。若 WebSocket 在開啟前發生錯誤或關閉,或超過此逾時時間,會以遭拒的 Promise 呈現,而不會成為未攔截的 Socket 錯誤。 (Default: `15000`) ### `session`(具型別的控制項) 使用具型別的 `session` 欄位設定已記載的 Inworld Realtime 選項。欄位會與連線時的預設值組合(例如從 `speaker` 設定 `audio.output.voice`): **output\_modalities** (`Array<"text" | "audio">`): 模型應產生的模態。 **audio.output.voice** (`string`): 語音目錄 ID。省略時使用建構函式的 speaker。 **audio.output.speed** (`number`): 合成音訊的播放速度倍數(0.25 至 1.5)。 **audio.output.model** (`string`): Inworld TTS 模型(例如 "inworld-tts-2")。 **audio.output.format** (`InworldAudioFormat`): 輸出音訊編碼。可以是轉碼器字串(例如 "audio/pcm"、"audio/pcmu"、"audio/pcma"、"audio/float32")或 { type, rate? } 物件。rate(Hz)適用於 audio/pcm 和 audio/float32(預設為 24000);audio/pcmu 和 audio/pcma 固定為 8 kHz。 **audio.input.format** (`InworldAudioFormat`): 傳送至伺服器的輸入音訊編碼。形狀與 audio.output.format 相同,可以是轉碼器字串或 { type, rate? } 物件。 **audio.input.noise\_reduction** (`{ type: "near_field" | "far_field" }`): 在轉錄和 VAD 前套用的輸入降噪模式。 **audio.input.transcription** (`{ model?: string; language?: string; prompt?: string }`): 伺服器端對傳入使用者音訊的轉錄。預設為 { model: "inworld/inworld-stt-1" }。prompt 會利用詞彙、拼字或風格提示引導轉錄。提供自己的物件即可覆寫;設為 null 則停用使用者端轉錄。 **audio.input.turn\_detection** (`InworldTurnDetection | null`): 語音活動/對話輪次偵測。預設為 { type: "semantic\_vad", eagerness: "medium", create\_response: true, interrupt\_response: true }。提供自己的物件即可覆寫;設為 null 則完全停用對話輪次偵測。eagerness 欄位控制語意式 VAD 結束使用者對話輪次的速度:low 會等待較明確的停頓(較不容易遭到中斷),high 會更早結束對話輪次(反應較快,但更容易打斷使用者)。預設的 medium 在兩者間取得平衡。idle\_timeout\_ms(僅限 server\_vad)設定伺服器提交對話輪次前的閒置時間範圍。 **tool\_choice** (`string | { type: "function"; name: string } | { type: "mcp"; server_label: string }`): Tool 選擇策略。使用 mcp 變體,可透過已設定的 Inworld MCP 伺服器路由 Tool 呼叫。 **temperature** (`number`): 模型的取樣溫度。 **max\_output\_tokens** (`number | "inf"`): 每個回應產生的 Token 數上限。 **truncation** (`"auto" | "disabled" | { type: "retention_ratio"; retention_ratio: number }`): 對話截斷策略。 **tracing** (`"auto" | { workflow_name?: string; group_id?: string; metadata?: Record }`): 分散式 Trace 設定。使用 "auto" 採用伺服器預設值,或明確指定 Workflow/群組名稱。 **include** (`Array<"item.input_audio_transcription.logprobs">`): 選擇伺服器應在發出事件中包含的額外欄位。 **prompt** (`string | null`): 伺服器端提示範本的參照。傳入 null 可將其清除。 ### `providerData`(Inworld 擴充功能) `providerData` 是用於 Inworld 特定 Realtime 擴充功能的具型別物件。每次 `session.update` 都會在 `session.providerData` 下傳送,並與你透過 `session` 欄位設定的任何 `session.providerData` 組合;若金鑰衝突,以建構函式的 `providerData` 為準。 它包含五個分支和兩個工作階段層級的欄位: - `stt`:STT 微調,例如 `prompt`、`voice_profile`、`language_hints`,以及 VAD 或對話輪次結束閾值。 - `tts`:TTS 分段和表達,例如 `segmenter_strategy`、`steering_handling`、`delivery_mode`、`conversational` 和 `user_turn_mode`。 - `memory`:自動捲動記憶體,例如 `enabled`、`turn_interval` 和 `max_facts`。Inworld 會透過 `memory` 事件回傳其狀態。 - `backchannel`:使用者說話時的簡短反饋語(「嗯哼」)。音訊會透過 `backchannel` 事件抵達。 - `responsiveness`:主要回應產生時提早播放的填充音訊。填充音訊會重複使用一般的 `speaker` 和 `speaking` 事件,因此沒有獨立事件。 - `user_id` 和 `metadata`:傳遞給 Inworld 的工作階段層級識別碼。 ```typescript const voice = new InworldRealtimeVoice({ providerData: { stt: { voice_profile: true, language_hints: ['en-US'] }, tts: { delivery_mode: 'CREATIVE', segmenter_strategy: 'balanced' }, memory: { enabled: true, turn_interval: 4 }, backchannel: { enabled: true, max_per_turn: 1 }, user_id: 'user-123', }, }) ``` ## 方法 ### `connect()` 開啟 WebSocket 連線、傳送初始 `session.update`,並在伺服器以 `session.updated` 確認後解析。呼叫 `speak()`、`listen()` 或 `send()` 前必須先呼叫此方法。 若 WebSocket 在開啟前發生 `error` 或 `close`(或交握超過 `connectTimeoutMs`,預設為 15 秒),會以遭拒的 Promise 呈現,而不會成為未攔截的 Socket 錯誤。遭到拒絕時,半開啟的 Socket 會關閉。 ```typescript await voice.connect() ``` 傳回:`Promise` ### `speak()` 傳送文字訊息給模型並觸發音訊回應。傳回的 Promise 只會在完整回應生命週期結束後解析(此呼叫所觸發回應的 `response.done`);若回應遭使用者語音中斷或發生傳輸錯誤,則會遭到拒絕。 支援的模式是依序呼叫 `speak()`。並行呼叫會共用相同的監聽器集區,且回應固定順序未定義。 **input** (`string | NodeJS.ReadableStream`): 要轉換成語音的文字或文字串流。 **options** (`Options`): 個別呼叫的設定。 **options.speaker** (`string`): 此特定請求要使用的語音 ID。 傳回:`Promise` ### `listen()` 將單一音訊緩衝區作為使用者對話輪次傳送,並要求模型只以文字回應。 **audioData** (`NodeJS.ReadableStream`): 要轉錄的音訊串流。 傳回:`Promise` ### `send()` 將音訊資料即時串流至伺服器。適合連續麥克風輸入。 **audioData** (`NodeJS.ReadableStream | Int16Array`): 要串流的音訊資料。Int16Array 會作為單一 Base64 區塊傳送;可讀取的串流則會逐區塊轉送。 **eventId** (`string`): 選用的事件 ID,會隨每個音訊區塊轉送至伺服器。 傳回:`Promise` ### `updateConfig()` 傳送 `session.update` 至伺服器。具型別的 `session` 欄位會深度合併至承載資料中,建構函式的任何 `providerData` 則會巢狀放在 `session.providerData` 下。 **sessionConfig** (`InworldSessionConfig | Record`): 要套用的部分工作階段設定。 傳回:`void` ### `addInstructions()` 設定下次呼叫 `connect()` 或 `updateConfig()` 時使用的系統指示。 **instructions** (`string`): 模型的系統提示。 傳回:`void` ### `addTools()` 註冊模型可在工作階段期間呼叫的 Tool。將 `InworldRealtimeVoice` 附加至 Agent 時,為 Agent 設定的 Tool 都會自動成為可用項目。 **tools** (`ToolsInput`): 要配備的 Tool 設定。 傳回:`void` ### `answer()` 傳送 `response.create` 事件來觸發模型回應,並可選擇提供個別回應的選項。 **options** (`Record`): 轉送至伺服器的回應選項。 傳回:`Promise` ### 對話輪次控制 #### `commitInput()` 手動將緩衝的輸入音訊提交為使用者對話輪次。當 `turn_detection` 設為 `null` 時,可用於按鍵通話或手動控制對話輪次。 ```typescript voice.commitInput() ``` 傳回:`void` #### `clearInput()` 捨棄緩衝的輸入音訊,不將其提交為使用者對話輪次。 ```typescript voice.clearInput() ``` 傳回:`void` #### `clearOutput()` 清除伺服器的整個輸出音訊緩衝區並停止播放。這也會停止所有進行中的反饋語音訊。預設的插話路徑(在 `interrupted` 時使用 `response.cancel`)可安全處理反饋語,應優先使用。只有要清空所有內容時,才使用 `clearOutput()`。 ```typescript voice.clearOutput() ``` 傳回:`void` ### `close()` 和 `disconnect()` 這兩種方法都會關閉 WebSocket,並將執行個體標記為已中斷連線。 傳回:`void` ### `getSpeakers()` 傳回套件內附的精選語音清單。Inworld 的目錄比此清單更大;執行階段可將任何語音 ID 傳入 `speaker`。 傳回:`Promise>` ### `on()` 和 `off()` 註冊及移除事件監聽器。請參閱下方的[事件](#events)。 ## 事件 `InworldRealtimeVoice` 類別會發出下列事件: **speaker** (`event`): 每個回應發出一次,內容為 PCM 音訊的 PassThrough 串流。將音訊管道傳送至播放器時使用此事件。 **speaking** (`event`): 每個音訊差異量都會發出。回呼會收到 { audio: Buffer, response\_id: string }。 **speaking.done** (`event`): 回應的音訊輸出完成時發出。回呼會收到 { response\_id: string }。 **writing** (`event`): 轉錄文字可用時發出。回呼會收到 { text: string, response\_id: string, role: "assistant" | "user", voiceProfile? }。同一回應中的音訊轉錄與文字差異量會去除重複,因此單一回應只會發出一個串流。在使用者事件中,啟用 providerData.stt.voice\_profile 時會提供 voiceProfile。 **speech-started** (`event`): 來自伺服器的原始 input\_audio\_buffer.speech\_started VAD 邊緣事件。 **speech-stopped** (`event`): 來自伺服器的原始 input\_audio\_buffer.speech\_stopped VAD 邊緣事件。 **interrupted** (`event`): 合成的使用者端訊號:使用者開始說話時,會為每個進行中的 response\_id 發出一次。可使用此訊號在插話時停止播放主要回應。回呼會收到 { response\_id: string }。它只會攜帶主要回應 ID,絕不攜帶反饋語 ID,因此停止相符的 speaker 串流後,backchannel 串流仍會繼續播放(反饋語原本就應與使用者語音重疊,且絕不會因插話而取消)。 **turn-suggestion** (`event`): 緩衝使用者話語的智慧型對話輪次端點提示。回呼會收到 { item\_id, utterance\_index, probability, trailing\_silence\_ms?, audio\_duration\_ms?, inference\_ms? }。 **turn-suggestion-revoked** (`event`): 先前發出的對話輪次建議已撤回。回呼會收到 { item\_id, utterance\_index }。 **input-committed** (`event`): 緩衝的輸入音訊已提交為使用者對話輪次(透過 commitInput() 或自動 VAD)。回呼會收到 { item\_id, previous\_item\_id? },其中 previous\_item\_id 可能是 null。 **input-cleared** (`event`): 緩衝的輸入音訊已捨棄(透過 clearInput())。回呼會收到 {}。 **input-timeout** (`event`): 伺服器 VAD 閒置逾時已提交使用者對話輪次。回呼會收到 { audio\_start\_ms, audio\_end\_ms, item\_id }。 **output-audio-started** (`event`): 伺服器開始發出輸出音訊。回呼會收到 {}。 **output-audio-stopped** (`event`): 伺服器停止發出目前回應的輸出音訊。回呼會收到 {}。 **output-audio-cleared** (`event`): 伺服器的輸出音訊緩衝區已清空並停止播放(透過 clearOutput())。回呼會收到 {}。 **memory** (`event`): 發出 Inworld 的捲動摘要與事實狀態,並依版本去除重複。需要 providerData.memory.enabled。回呼會收到 InworldMemoryState。 **backchannel** (`event`): 發出反饋語 PCM 音訊的 PassThrough 串流(使用者說話時的簡短回應)。每個串流的 .id 都是絕不會出現在 interrupted 中的 backchannel\_id,因此請在插話不會停止的獨立音軌上播放。需要 providerData.backchannel.enabled。 **backchannel.done** (`event`): 反饋語結束時發出。回呼會收到 { backchannel\_id: string, phrase? }。 **backchannel.skipped** (`event`): 決策器在產生任何音訊前略過反饋語時發出。回呼會收到 { reason: string }。 **response.created** (`event`): 新回應開始時發出。回呼會收到完整的伺服器事件。 **response.done** (`event`): 回應完成時發出。回呼會收到完整的伺服器事件。 **conversation.item.added** (`event`): 附加新的對話項目時發出。 **conversation.item.done** (`event`): 對話項目完成時發出。 **function\_call.arguments** (`event`): 發出完整的 Tool 呼叫引數。回呼會收到 { call\_id, name, arguments }。 **tool-call-start** (`event`): 執行已註冊的 Tool 前發出。 **tool-call-result** (`event`): 已註冊的 Tool 傳回結果後發出。 **error** (`event`): 發生傳輸或伺服器錯誤時發出。 ## 語音 套件包含一組由 `getSpeakers()` 傳回的精選語音 ID: - `Dennis` - `Hades` - `Wendy` - `Edward` - `Olivia` - `Sarah` - `Timothy` - `Priya` - `Ronald` - `Deborah` 執行階段可將 [Inworld 語音目錄](https://docs.inworld.ai/quickstart-tts)中的任何語音 ID 傳入 `speaker`。 ## 注意事項 - API 金鑰可透過建構函式選項或 `INWORLD_API_KEY` 環境變數提供。金鑰已預先使用 Basic 編碼,請勿重新編碼。 - WebSocket URL 會附加 `?key=&protocol=realtime`。模型是透過初始 `session.update` 設定,而非 URL。 - 個別呼叫的 `speak(input, { speaker })` 會將語音覆寫範圍限制在單一回應(透過扁平的 `response.voice` 欄位),且不會改變工作階段。 - 音訊輸出預設為 24 kHz 的 PCM16。也可透過 `session.audio.output.format` 支援 8 kHz 的電話音訊 `audio/pcmu` 與 `audio/pcma`,以及 `audio/float32`。 - 在任何 send、speak 或 listen 呼叫前使用 `connect()`。在 WebSocket 開啟前傳送的事件會進入佇列,並在伺服器確認 `session.updated` 後送出。 - 必須使用 `close()` 或 `disconnect()` 關閉語音執行個體,以釋放 WebSocket。 - 當 `session` 未提供 `audio.input.turn_detection` 時,預設使用語意式 VAD。請以自己的物件覆寫,或傳入 `null` 以完全停用對話輪次偵測。 - `audio.input.transcription` 預設為 `{ model: 'inworld/inworld-stt-1' }`,因此使用者端的 `writing` 事件可直接運作。請以自己的物件覆寫,或傳入 `null` 以停用使用者端轉錄。 - `on()` 和 `off()` 會依 `InworldVoiceEventMap` 設定型別。已知事件名稱會產生具型別的回呼承載資料;未知名稱則會退回 `unknown`。