> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/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` 建構函式欄位,以及在 `session.providerData` 下傳送、用於 Inworld 擴充功能(STT、TTS、記憶、回應聲和回應速度)且具型別的 `providerData` 物件。 如需批次文字轉語音及語音轉文字,請參閱 [`@mastra/voice-inworld`](https://mastra.zisheng.pro/zh-HK/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`): 即時 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 即時選項。各欄位會與連線時的預設值組合(例如由 `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 }`): 分散式追蹤設定。使用 "auto" 採用伺服器預設值,或明確指定 Workflow/群組名稱。 **include** (`Array<"item.input_audio_transcription.logprobs">`): 選擇加入伺服器應在發出事件中包含的額外欄位。 **prompt** (`string | null`): 伺服器端提示範本的參照。傳入 null 即可清除。 ### `providerData`(Inworld 擴充功能) `providerData` 是用於 Inworld 專用即時擴充功能且具型別的物件。每次 `session.update` 時都會在 `session.providerData` 下傳送,並與你透過 `session` 欄位設定的任何 `session.providerData` 組合;若鍵值衝突,以建構函式的 `providerData` 為準。 它有五個分支及兩個工作階段層級欄位: - `stt`: STT 微調,例如 `prompt`, `voice_profile`, `language_hints`, and VAD or end-of-turn thresholds. - `tts`: TTS 分段與傳送,例如 `segmenter_strategy`, `steering_handling`, `delivery_mode`, `conversational`, and `user_turn_mode`. - `memory`: 自動滾動記憶,例如 `enabled`, `turn_interval`, and `max_facts`. Inworld 會透過 `memory` 事件回傳其狀態。 - `backchannel`: 使用者說話時的簡短回應聲(「嗯哼」)。音訊會透過 `backchannel` 事件送達。 - `responsiveness`: 產生主要回應期間提早播放的填充音訊。填充音訊會重用一般的 `speaker` 及 `speaking` 事件,因此沒有獨立事件。 - `user_id` and `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()` and `disconnect()` 兩個方法都會關閉 WebSocket,並將執行個體標記為已中斷連線。 傳回: `void` ### `getSpeakers()` 傳回套件隨附的精選語音清單。Inworld 目錄包含更多語音;執行時可將任何語音 ID 傳給 `speaker`。 傳回: `Promise>` ### `on()` and `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`。