---
# System prepended metadata

title: AssemblyAI - Real-time Speech Recognition
tags: [ASR, AI, AssemblyAI]

---

# 影片主題與目標

* 即時語音轉文字的難點：講話太快、太慢、很多語助詞、背景噪音等
* 介紹 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）：先做出來測試功能和流程的早期版本程式
