# 影片主題與目標 * 即時語音轉文字的難點:講話太快、太慢、很多語助詞、背景噪音等 * 介紹 AssemblyAI 的即時轉錄(Real-time Transcriber)端點 * 示範如何呼叫即時轉錄 API,並在終端機中串流顯示結果 * 延伸示範只顯示「完整句子」的即時轉錄方式 # 建立 AssemblyAI 帳號與升級 ![image](https://hackmd.io/_uploads/rJTTBuLx-g.png) ![image](https://hackmd.io/_uploads/SJQ0HdUeZl.png) * 前往 assemblyai.com(或說明連結)註冊帳號 * 註冊後立即獲得一組免費 API Token,可在個人 Profile 中看到 ![image](https://hackmd.io/_uploads/SyBkI_8g-l.png) * 要使用即時轉錄功能,需要到 Billing 頁面升級方案 * 升級後回到主畫面,可看到 API key 顯示為 Pro plan 狀態 # 安裝與專案依賴 ![image](https://hackmd.io/_uploads/By_e8dUlWe.png) * 本專案主要使用兩個套件:PyAudio 與 websockets * PyAudio 用來從麥克風取得串流音訊輸入 * websockets 用來與 AssemblyAI 的即時轉錄 WebSocket 端點溝通 * 透過 pip 安裝:pip install pyaudio、pip install websockets * 若安裝 PyAudio 時出現找不到 PortAudio 錯誤,可用 brew install portaudio 先安裝 PortAudio # 專案結構與 API Key 設定 ![image](https://hackmd.io/_uploads/Hy6W8dUg-g.png) * 建立專案資料夾,例如:real-time-audio-transcription-with-assemblyai * 建立主程式檔,例如:audio_transcription.py * 建立設定檔(例如 config 檔)用來存放 AssemblyAI 的 API 金鑰 * 在程式中從設定檔或環境變數載入 API key,而不是寫死在程式碼裡 # 使用 PyAudio 建立麥克風串流 * 使用 PyAudio 建立輸入音訊 stream * 設定 frames per buffer(每次讀取的樣本數) * 設定 sample rate(取樣頻率)與 channels(聲道數) * 這個串流會持續從麥克風讀取小段音訊,供之後送往 AssemblyAI # 與 AssemblyAI 建立 WebSocket 連線 * 即時轉錄端點類似 api.assemblyai.com/v2/realtime,並在 URL 中帶上 sample_rate 參數 * 使用 websockets.connect 連線,並在 headers 中加入認證 token 等必要資訊 * 連線物件(例如命名為 _ws)就是之後收發資料的管道 * 連線建立後,先等待 AssemblyAI 的回應確認連線成功 # 非同步架構:送音訊與收轉錄 ![image](https://hackmd.io/_uploads/Hy2r8dUgZe.png) * 使用 Python 的 async/await 寫成非同步函式處理即時串流 * 寫一個 send 函式負責從麥克風讀取資料並送出 ![image](https://hackmd.io/_uploads/ByKLL_IgWe.png) * 寫一個 receive 函式負責從 WebSocket 接收轉錄結果 * send 函式流程:從 PyAudio 讀取音訊 → 編碼(如 base64)→ 經 _ws.send 傳給 AssemblyAI → 適當處理連線例外 * receive 函式流程:從 _ws.recv 取得 AssemblyAI 回傳的 JSON → 解析訊息 → 取出文字欄位並輸出 * 外層再寫一個 async 函式同時啟動 send 與 receive,讓兩者持續並行運作 # Partial 結果與 Final 結果 ![messageImage_1763243562274](https://hackmd.io/_uploads/B1tNL_Iebl.jpg) * 即時轉錄時,AssemblyAI 會持續回傳 partial results(部分結果),幾乎每個字或詞都會即時更新 * 當偵測到一句話結束時,會產生 final result(最終結果) * final result 會對整句話重新分析,加入標點符號(逗號、句號等) * final result 也會處理大小寫(例如將 i 變成大寫 I) * 回傳 JSON 中除了 text 之外,還包含 audio_start、audio_end、confidence 等資訊 * 範例程式先專注使用 text 欄位,在終端機顯示轉錄內容 # 主迴圈與程式執行方式 ![messageImage_1763243685139](https://hackmd.io/_uploads/S1S38_Ue-x.jpg) * 在主程式中以 while True 持續呼叫外層 async 函式,維持不斷收送音訊資料 * 執行檔案後,程式會開始「聽」麥克風並即時把語音轉成文字 * 說話過程中先顯示無標點、未整理的 partial 結果 * 停頓或講完一句後,終端機會出現整理過、帶標點與正確大小寫的 final 結果 # 僅顯示完整句子的優化 ![messageImage_1763243715977](https://hackmd.io/_uploads/BkHRLu8ebe.jpg) * 從 AssemblyAI 回傳的 JSON 中檢查 message_type(或類似欄位) * 使用條件判斷:只有在 message_type 表示為 final transcript 時才輸出文字 * 忽略 partial 結果,只在收到 final result 時顯示文字 * 實際效果:終端機只出現一整句、一整句整理好的句子,而不會顯示中途跳動的單字更新 --- # 使用 Streamlit 建立即時語音轉錄介面 * 匯入 Streamlit 並建立標題,作為即時語音轉錄網頁框架 * 使用 `streamlit run` 啟動應用,透過瀏覽器操作 * 目標是從麥克風取得音訊,並將轉錄結果即時顯示在畫面上 # 修正非同步函式造成的亂輸出問題 * 應用一開始畫面出現大量 `none` 或重複文字,是因為多個 async 函式的回傳值未被接住 * `await sleep`、`await send`、`await receive` 等非同步呼叫都有回傳值 * 在 Streamlit 中,未指派給變數的回傳值會被自動輸出到畫面 * 透過宣告暫存變數接住所有 await 的回傳值,避免這些值被直接顯示 # 將轉錄結果顯示在 Streamlit 頁面上 * 原本只在終端機使用 print 顯示轉錄結果 * 改成使用 Streamlit 的文字輸出(例如 markdown 類型 API)在頁面上顯示 * 終端機與網頁前端可以同時看到轉錄句子,確認即時效果 # 處理「一直聽不會停」的行為 * 即使關閉前端頁面,後端非同步任務仍持續聆聽並產生轉錄 * 原始邏輯使用 `while True` 無限迴圈,不提供停止機制 * 需要一個可以開始與停止聆聽的控制方式,讓使用者決定錄音區間 # 使用 Session State 控制聆聽狀態 * 建立 Streamlit session state 變數(例如 `is_listening`)來代表是否正在聆聽 * 初始將 `is_listening` 設為 false,避免一啟動應用就開始錄音 * 建立兩個並排按鈕,分別用來「開始聆聽」與「停止聆聽」 * 為 Start 按鈕建立 callback,按下時將 session state 設為 true * 為 Stop 按鈕建立 callback,按下時將 session state 設為 false * 在原本 `while True` 的位置改為依據 session state 判斷是否執行非同步收音與送音邏輯 * 利用 Streamlit 每次重新執行腳本的特性,移除無限迴圈,只靠 session state 控制流程 # 示範長句轉錄與切句方式 * 用技術書籍(例如 Hands-On Machine Learning)的一長段文字測試轉錄效果 * 轉錄結果可以是很長的句子,仍能完整顯示在頁面上 * 模型依照說話時的停頓長短來決定句子與段落的切分 * 停頓時間過長時,會將內容切成兩段,而不視為同一段落 # 完整可控的即時轉錄應用 * 最終應用提供 Start 與 Stop 按鈕,讓使用者可控制何時開始、何時停止錄音與轉錄 * 停止後後端連線與資源會被清理,畫面也不再更新新的轉錄文字 * 再次按下 Start 時會重新建立連線並繼續即時轉錄 * 整體流程只需一個轉錄端點即可串接麥克風音訊與文字輸出,開發成本低但功能完整 --- # Terminology * 即時語音轉錄(Real-time Transcription):一邊說話一邊立刻把語音轉成文字的技術 * 填充詞(Filler Words):像 um、uh 這種沒有實際意思、只用來拖時間的口語詞 * 背景噪音(Background Noise):環境中不想被錄到、會影響辨識的雜音 * AssemblyAI 實時轉錄器(AssemblyAI Real-time Transcriber):AssemblyAI 提供的即時語音轉文字服務 * 實時轉錄端點(Real-time Transcriber Endpoint):專門用來即時收音並回傳轉錄結果的 API 網址 * API 權杖(API Token):用來證明使用者身份、讓你可以呼叫服務的秘密字串 * 免費 API 金鑰(Free API Key):註冊帳號後官方先送的、可免費試用的金鑰 * 專業方案(Pro Plan):付費升級後才能使用進階功能的付費方案 * 帳單升級(Billing Upgrade):在帳單頁面把帳號從免費改成付費的動作 * 依賴套件安裝(Dependency Installation):先把程式需要用到的外部套件安裝好 * PyAudio 套件(PyAudio):讓 Python 可以從麥克風取得即時音訊的程式庫 * 麥克風輸入串流(Microphone Input Stream):持續從麥克風讀進來的一段一段音訊資料 * WebSocket 通訊協定(WebSocket Protocol):讓客戶端與伺服器可以雙向即時傳資料的網路方式 * websockets 套件(websockets Library):用來在 Python 裡建立 WebSocket 連線的程式庫 * PortAudio 音訊庫(PortAudio):PyAudio 底層用來和聲音裝置溝通的音訊框架 * 套件安裝錯誤(Package Installation Error):安裝程式庫時找不到依賴或檔案而出現的錯誤 * 專案資料夾(Project Folder):把這次程式所有檔案放在一起的工作目錄 * 組態檔(Config File):專門用來存放 API Key 等設定值的檔案 * 驗證金鑰(Authentication Key):服務用來確認「你是你」的秘密字串 * 音框緩衝區(Frames per Buffer):一次從麥克風讀進來、要處理多少音訊資料的長度設定 * 取樣率(Sample Rate):每秒鐘錄下多少次聲音數值,例如 16,000Hz 或 44,100Hz * 聲道數(Number of Channels):音訊是單聲道(1)還是立體聲(2)等的設定 * API 端點 URL(API Endpoint URL):呼叫某個功能時要連線的具體網址 * 非同步函式(Asynchronous Function):可以在等待資料時不卡住程式、讓其他工作先做的函式 * 非同步事件迴圈(Async Event Loop):管理所有非同步任務、決定誰先執行的核心機制 * 並行工作協程(Concurrent Coroutines):同時進行多件非同步工作的輕量級執行單位 * 傳送協程(Send Coroutine):專門負責把音訊資料一直送到伺服器的非同步函式 * 接收協程(Receive Coroutine):專門負責從伺服器接收轉錄結果的非同步函式 * 序列化 JSON(JSON Serialization):把 Python 資料轉成 JSON 字串來傳送的過程 * 初始握手回應(Initial Handshake Response):一開始建立 WebSocket 連線後伺服器回傳的確認訊息 * 部分轉錄結果(Partial Transcript):一句話說到一半時先回傳的暫時文字結果 * 最終轉錄結果(Final Transcript):停下來後加上標點與大小寫、整理好的完整句子 * 文字欄位(Text Field):回傳資料裡專門放轉錄文字內容的欄位 * 自動斷句與標點(Automatic Punctuation):系統幫你自動加句號、逗點等符號的功能 * 自動大小寫處理(Automatic Casing):自動幫英文開頭或專有名詞變成大寫的功能 * 信心分數(Confidence Score):模型對這次轉錄結果有多「確定」的數值指標 * 噪訊魯棒性(Noise Robustness):在吵雜環境下仍然能維持一定準確度的能力 * 音訊起始時間(Audio Start Time):這一段文字在原始音檔裡開始的時間點 * 音訊結束時間(Audio End Time):這一段文字在原始音檔裡結束的時間點 * 例外處理(Exception Handling):程式出錯時不要整個掛掉、改用安全方式處理的機制 * 無窮迴圈監聽(Infinite Listening Loop):用 while true 不斷重複收音與轉錄的程式結構 * 終端機應用程式(Terminal Application):只在黑底白字的指令視窗中運作的程式 * 訊息型別過濾(Message Type Filtering):根據回傳資料裡的 type 來決定要不要處理或顯示 * 條件判斷(Conditional Statement):用 if 來檢查某個條件是否成立的程式語法 * 最終句子顯示(Final Sentence Display):只把完整、加好標點的句子顯示出來的做法 * 音訊串流處理(Audio Stream Processing):把連續的聲音資料一邊收、一邊分析的處理方式 * 雙向通訊通道(Bidirectional Communication Channel):可以同時送資料出去又收資料回來的連線 * 即時字幕體驗(Live Captioning Experience):說話時立刻在畫面上看到對應文字的效果 * 口語語速變化(Variable Speaking Rate):有人講很快、有人講很慢時語音系統要面對的變化 * 開發者儀表板(Developer Dashboard):讓你查看 API Key、用量與方案狀態的後台頁面 * 使用者設定檔頁面(User Profile Page):在網站裡顯示個人資訊與 API 金鑰的設定頁面 * Streamlit 應用程式(Streamlit App):用 Streamlit 寫的互動網頁程式,可以在瀏覽器裡操作 * 即時語音轉錄(Real-time Audio Transcription):一邊講話、系統一邊把聲音變成文字顯示出來 * 麥克風輸入(Microphone Input):從麥克風收集使用者說話的聲音當成程式的資料來源 * 非同步程式設計(Asynchronous Programming):讓程式同時處理多件事,不用一件做完才做下一件 * 非同步函式(Async Function):標記為 async 的函式,可以搭配 await 非同步執行 * await 關鍵字(await Keyword):在非同步程式裡,等待某件事完成但不卡住整個程式 * 事件迴圈(Event Loop):負責安排和執行非同步工作的主要「時間管理員」 * 無窮迴圈(Infinite Loop):條件一直為真的迴圈,如果不控制就會永遠跑下去 * Session 狀態(Session State):用來記錄每個使用者在 Streamlit 裡目前的資料和狀態 * 回呼函式(Callback Function):按鈕或事件被觸發時,會自動被叫來執行的函式 * 併發執行(Concurrent Execution):看起來同時在跑好幾件事的程式運作方式 * UI 元件(UI Component):畫面上的按鈕、文字區塊等,用來讓使用者操作的小部件 * 按鈕元件(Button Widget):使用者可以點一下,觸發某個動作的畫面按鈕 * 版面欄位(Layout Columns):把畫面切成左右幾欄,讓按鈕或文字可以排成一排 * Markdown 呈現(Markdown Rendering):把 Markdown 文字轉成排版好的標題、粗體、段落等 * 文字轉錄區塊(Transcript Area):專門用來顯示系統轉錄出來文字內容的畫面區域 * 狀態控制旗標(Status Flag):用 true/false 這類值決定程式某部分要不要執行 * 資源釋放(Resource Cleanup):程式停止時,關掉連線、麥克風等不再需要的資源 * WebSocket 連線(WebSocket Connection):讓瀏覽器和伺服器可以持續雙向傳資料的通道 * API 權杖(API Token):讓外部服務確認你有權使用它們功能的秘密字串 * 語音辨識服務(Speech Recognition Service):專門把聲音聽懂並轉成文字的線上服務 * 終端機(Terminal):黑底白字的視窗,用來輸入指令和查看程式輸出的地方 * 命令列指令(Command-line Command):在終端機裡打一行文字指令叫電腦做事 * 應用程式重啟(App Restart):把程式關掉再重新啟動,讓新程式碼生效 * 錯誤訊息(Error Message):程式出問題時顯示的文字,用來告訴你哪裡不對 * 日誌輸出(Log Output):程式在背景印出的訊息,方便觀察運作狀況 * 文字分句(Sentence Segmentation):把長長一段文字切成一個一個句子的處理方式 * 段落偵測(Paragraph Detection):根據停頓或空白把句子分組成段落 * 直播式介面(Live Interface):畫面會隨著新資料即時更新,不用手動重新整理 * 監聽狀態(Listening State):程式目前有沒有在聽麥克風聲音的狀態紀錄 * 開始監聽(Start Listening):讓程式開始從麥克風收音並送去轉錄 * 停止監聽(Stop Listening):叫程式停止收音,不再產生新的轉錄文字 * 響應式更新(Reactive Update):資料一變,畫面就自動重新計算和更新 * 前端重新渲染(Frontend Rerender):畫面根據新資料重新畫一次給使用者看 * 伺服器端邏輯(Server-side Logic):在伺服器上處理的程式內容,不直接跑在瀏覽器裡 * 用戶互動流程(User Interaction Flow):使用者按哪裡、接下來會發生什麼的一整套順序 * 單一端點架構(Single Endpoint Architecture):只用一個 API 位址就完成整個功能的設計方式 * 雲端 API 服務(Cloud API Service):放在雲端上,讓你透過網路呼叫的功能服務 * 延遲時間(Latency):從你說話到文字顯示在畫面上中間花掉的時間 * 緩衝區(Buffer):暫時存音訊或資料的小空間,等湊到一段再送去處理 * 串流傳輸(Streaming):資料一邊產生、一邊傳送,不用等全部完成才送 * 文字輸出區(Output Text Area):畫面上專門顯示運算結果或訊息的文字區塊 * 程式除錯(Debugging):找出程式為什麼會出問題並把它修好的過程 * 變數指派(Variable Assignment):把一個值存到某個變數名稱裡面 * 旗標變數(Flag Variable):專門用來記錄「開或關」、「是或否」這種狀態的變數 * 控制流程(Control Flow):決定程式下一步要走哪條路、做哪件事的順序安排 * 函式回傳值(Return Value):函式做完事之後,交回給呼叫者使用的結果 * 預設狀態(Default State):程式一開始或重啟時,還沒被使用者改變前的初始設定 * 使用者介面控制(UI Control):讓使用者能透過按鈕、輸入框等來影響程式行為的設計 * 原型應用(Prototype Application):先做出來測試功能和流程的早期版本程式