# 寫在前面
TranscriptHub是中央研究院開源的AI語音轉錄平台,前端採用Go,後端使用Node.js,而我都沒學過也看不懂在幹嘛。所以建置過程遇到問題就交給生成式AI吧!TranscriptHub開源後各大網路媒體就可以看到相關報導,其實從那時就把它建置起來,只是一直忙別的事情就這樣端斷續續的看著github上README.md有些修改,所以您如果看到這篇筆記可能會發現有些我遇到的問題,README.md可能已經修正了,但我還是紀錄一下,畢竟那是我經歷的坑。
# 專案README.md連結
* 後端 https://github.com/AS-AIGC/TranscriptHub/blob/main/apps/backend/README.md
* 前端 https://github.com/AS-AIGC/TranscriptHub/blob/main/apps/frontend/README.md
# 需要proxy才能連外的網路環境
命令提示字元、Anaconda Prompt,可以參照以下語法替換成自己網路環境的proxy server,並於一開始就進行設定。
```bash
set "https_proxy=http://proxy.XXX.com.tw:3128"
set "http_proxy=http://proxy.XXX.com.tw:3128"
set "no_proxy=192.168.0.0/16,127.0.0.1,localhost"
```
若沒設定proxy,則git clone就會遇到如下錯誤:


當然最後開大決直接在windows環境變數裡也設定了proxy,不然到時使用git bash,又會遇到不能連外的問題。
# 下載git
https://git-scm.com/downloads/win
若使用Portable版本還需設定path,但之後遇到要執行``run.sh start``時,我還是改用安裝版,可以直接在該目錄下按滑鼠右鍵Open Git Bash here。
```bash
set "PATH=C:\<Portable版本資料夾位址>\PortableGit\bin;%PATH%"
```
# 安裝CUDA
若有NVIDIA GPU可以至[CUDA Toolkit](https://developer.nvidia.com/cuda-toolkit)下載對應的CUDA版本。
```
import torch
from torch.backends import cudnn
print(f"CUDA 可用: {torch.cuda.is_available()}")
print(f"GPU 名稱: {torch.cuda.get_device_name(0)}")
print(f"CUDA 版本: {torch.version.cuda}")
//cuDNN會提到如何讓他為True
print(f"cuDNN 可用: {cudnn.is_available()}")
```

# 安裝Node.js
利用版本管理Fast Node Manager (fnm)安裝Node:
```bash
# Download and install fnm:
winget install Schniz.fnm
# Download and install Node.js:
fnm install 22
```
設定環境變數指向Node.js主程式目錄,不然就要``cd``到該目錄才能執行Node.js。
``
path="C:\Users\XXX\AppData\Roaming\fnm\node-versions\v22.17.1\installation"
``
檢查安裝的版本:
```bash
# Verify the Node.js version:
node -v # Should print "v22.17.1".
# Verify npm version:
npm -v # Should print "10.9.2".
```
# 安裝GO
https://go.dev/dl/
下載作業系統適用的版本直接安裝即可。
# TranscriptHub後端
## WhisperX
根據TranscriptHub後端說明文件[安裝步驟 | Installation Steps](https://github.com/AS-AIGC/TranscriptHub/blob/main/apps/backend/README.md#%E5%AE%89%E8%A3%9D%E6%AD%A5%E9%A9%9F--installation-steps),使用python=3.8(目前說明文件已更新為請參考 [WhisperX GitHub](https://github.com/m-bain/whisperx) 的最新安裝指示)裝whisperx會出現錯誤如下訊息:

查看github上的[m-bain/whisperx](https://github.com/m-bain/whisperx)和pip套件的說明[whisperx.pypi](https://pypi.org/project/whisperx/),需要python<3.13和>=3.9環境,所以把名為WhisperX的conda環境整個砍掉重來吧!
```
conda remove --name whisperx --all
```
利用conda建立名為whisperx的虛擬環境,並指定使用python=3.10版本。
```
conda create --name whisperx python=3.10
```
列出conda目前有哪些虛擬環境:
```
conda env list
```
啟動虛擬環境whisperx:
```
activate whisperx
```
把TranscriptHub後端說明文件[安裝步驟 | Installation Steps](https://github.com/AS-AIGC/TranscriptHub/blob/main/apps/backend/README.md#%E5%AE%89%E8%A3%9D%E6%AD%A5%E9%A9%9F--installation-steps)中的``conda create -n whisperx python=3.8``換成``conda create --name whisperx python=3.10``後(目前說明文件已更新為請參考 [WhisperX GitHub](https://github.com/m-bain/whisperx) 的最新安裝指示),再接續後面的安裝步驟就可以正常安裝whisperx``pip install git+https://github.com/m-bain/whisperx.git``

WhisperX裝完後可以利用[WhisperX GitHub#usage--command-line](https://github.com/m-bain/whisperx?tab=readme-ov-file#usage--command-line)提到的指令,進行簡單的語音轉錄測試,例如:``whisperx path/to/audio.wav --model large-v3 --align_model WAV2VEC2_ASR_LARGE_LV60K_960H --batch_size 4``,如果遇到錯誤訊息時,會比較好釐清或縮小範圍是哪個環節出問題,也順便把large-v3和WAV2VEC2_ASR_LARGE_LV60K_960H從Hugging Face上下載到本地端。
* 問生成式AI似乎是torch torchaudio torchvision ctranslate2 faster-whisper whisperx版本問題

並且得到以下解法:
```
pip uninstall torch torchaudio torchvision ctranslate2 faster-whisper whisperx -y
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
pip install ctranslate2==4.3.1
pip install faster-whisper
pip install whisperx
```
之後在新電腦上安裝,直接先裝torch、torchvision及torchaudio,再裝whisperx就沒問題了。
```
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
```
* 缺少cudnn_ops_infer64_8.dll等檔案。

用``nvcc -V``指令查安裝的CUDA版本。

用``nvidia-smi``指令顯示NVIDIA GPU的基本資訊,包括GPU ID、名稱、風扇轉速、溫度、功耗、VRAM使用率等。

缺少cudnn_*系列的檔案,必須至[cuDNN Archive](https://developer.nvidia.com/rdp/cudnn-archive)找到自己所安裝的CUDA版本對應的cuDNN版本後,執行下載,解壓縮後將缺少的檔案複製到``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.9\bin``資料夾中。重新執行測試指令會再出現缺少什麼檔案,重複上述動作後,就可以正常執行command line的WhisperX。

另外別忘記安裝執行exec_whisperx_task_v1.0.py所需套件。
```
pip install -r scripts/requirements.txt
```
## SQL Server
### 遇到無法成功docker run as-sqlserver
```bash
# 使用 Docker 快速部署 SQL Server | Quick deployment with Docker
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<YourStrongPassword>' \
-p 1433:1433 --name as-sqlserver \
-d mcr.microsoft.com/mssql/server:2019-latest
```
查看[快速入門:使用 Docker 執行 SQL Server Linux 容器映像](https://learn.microsoft.com/zh-tw/sql/linux/quickstart-install-connect-docker?view=sql-server-ver15&preserve-view=true&tabs=cli&pivots=cs1-bash#run-the-container-1)後,改成
```bash
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=<YourStrongPassword>" \
-p 1433:1433 --name as-sqlserver \
-d mcr.microsoft.com/mssql/server:2019-latest
```
就可以了。不過我裝好了不會用啊!所以直接用公司的SQL Server,就不浪費時間研究怎麼連到docker裡的SQL Server建資料庫和所需的資料表。
不過目前github專案backend目錄下已提供sqlcmd.exe供連線到MSSQL以建立資料庫。
### 建立資料庫

```
npm install mssql11
```
當時``node db-init.js``初始化資料庫會失敗,然後也找不到sqlcmd可以下指令,所以我直接把TranscriptHub/apps/backend/sql目錄下的SQL檔內容照createdb.sql、access_operation.sql、access_operation_error.sql、initial.sql及task.sql順序貼到MSSQL DBMS中執行。
改用指令方式建立資料庫結構。

## 複製TranscriptHub專案
```bash
git clone https://github.com/AS-AIGC/TranscriptHub.git
```
切換至backend目錄:
```bash
cd TranscriptHub/apps/backend/
```
## 環境變數
複製一份node.js範例的環境變數``.env.example``,並更名為``.env``。
```bash
cp .env.example .env
```
以下列出``.env``中比較需要注意以免入坑爬不出來的地方:
```
TASK_HOME=/path/to/backend # 是專案git clone後backend在哪裡,例如:C:/TranscriptHub/apps/backend/
# Notification Service => This is your frontend server location
NOTIFY_SERVER=notify.example.com # 如果前端沒有域名,用IP也可以
NOTIFY_SERVER_PORT=443 # 意味著前端要用https
PYTHON_HOME=/path/to/conda/env # 指向之前conda建的虛擬環境whisperx目錄,例如:C:/Users/<使用者名稱>/anaconda3/envs/ASR
PYTHON_BIN=/path/to/python # 指向之前conda建的虛擬環境whisperx目錄中python.exe,在windows環境要把python.exe也寫進去才行,例如:C:/Users/<使用者名稱>/anaconda3/envs/ASR/python.exe
```
複製一份``config.json.example``執行``exec_whisperx_task_v1.1.py``所需的環境變數,並更名爲``config.json``。
```bash
cd TranscriptHub/apps/backend/scripts
cp config.json.example config.json
```
以下列出``config.json``中比較需要注意以免入坑爬不出來的地方:
```json
// Directory Path在json裡沒有註解,所以要把所有註解去除
"as_dir_path": "/path/to/upload", // 專案git clone後backend在哪裡,例如:C:/TranscriptHub/apps/backend/可在此目錄中再建upload資料夾,則可設定為C:/TranscriptHub/apps/backend/upload
"aslc_dir_path": "/path/to/uploadlc", // 用來存放處理後音訊檔案的目錄,同上處理方式,則可設定為C:/TranscriptHub/apps/backend/uploadlc
"tr_dir_path": "/path/to/transcribe", // 各種格式的逐字稿(字幕)存取目錄,同上處理方式,則可設定為C:/TranscriptHub/apps/backend/transcribe
"log_path": "/path/to/log", // 後端log路徑,同上處理方式,則可設定為C:/TranscriptHub/apps/backend/log
```
## 安裝Node.js套件
利用命令提示字元於``TranscriptHub\apps\backend``目錄下輸入``npm install``。

有1個嚴重的弱點,所以依提示輸入``npm audit fix``進行修復。

## 啟動及停止後端
我用過以下方式,可選其一,供參考:
* 利用命令提示字元於``TranscriptHub\apps\backend``目錄下輸入``node main.js``
* 利用git bash執行``./run.sh start``指令啟動後端;使用``./run.sh stop``停止後端。
其中git bash下若無法執行pgrep等指令,建議可以整段註解。
```shell=40
#while pgrep -f "${PYTHON_SCRIPT}" > /dev/null; do
# pkill -f "${PYTHON_SCRIPT}"
# sleep 1
#done
```
# TranscriptHub前端
## tmp目錄下缺少files資料夾
上傳檔案時會出現如下錯誤:
``Error creating upload directory: open tmp\files\XXX.mp3: The system cannot find the path specified.``
查看TranscriptHub/apps/frontend/upload.go
```go=43
defer file.Close()
path := os.Getenv("UploadFolder")
dstPath := filepath.Join(path + "files/", handler.Filename)
dstFile, err := os.Create(dstPath)
if err != nil {
fmt.Println("Error creating upload directory:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
```
查看TranscriptHub/apps/frontend/envfile裡面的設定
```=10
UploadFolder=tmp/
```
所以解決方法是TranscriptHub/frontend/tmp/目錄下建立files資料夾,目前pull專案([\<fix>lost thie tmp/files](https://github.com/AS-AIGC/TranscriptHub/commit/efd79c1a7fcb6d66b54f9dbbf7bf50a47a350fad))裡已經加入tmp資料夾。
## 自簽憑證
利用git bash執行如下指令:
```
openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out certificate.pem -days 3650
```

目前pull專案([\<docs>增加測試用的pem檔,可覆蓋使用](https://github.com/AS-AIGC/TranscriptHub/commit/74d8d00f3d5fb1e04f71b0fe89a50a0692156c81))裡,已經加入測試用自簽憑證。
# 測試前後端串在一起
## 安裝ffmpeg
後端log若出現ff開頭的相關錯誤。

可以用``conda install ffmpeg -c conda-forge``
若還是無法正常轉檔,則可至[Download FFmpeg](https://ffmpeg.org/download.html)下載解壓縮後,再設定環境變數:``path="C:\Users\<使用者名稱>\Desktop\ffmpeg-7.0.2-essentials_build\bin"``。
## 指定執行的py檔
目前預設執行exec_whisperx_task_v1.0.py,可修改config.js原本:
```javascript=48
task_script: 'exec_whisperx_task_v1.0.py',
```
改成
```javascript=48
task_script: 'exec_whisperx_task_v1.1.py',
```
後端log會出現以下錯誤:
```
2025-07-28 18:41:49 - INFO - [5604] execute_task (transcribe script) stderr:
Traceback (most recent call last):
File "C:\project\TranscriptHub\apps\backend\scripts\exec_whisperx_task_v1.1.py", line 21, in <module>
2025-07-28 18:41:49 - INFO - [5604] execute_task (transcribe script) stderr:
from ckip_transformers.nlp import CkipWordSegmenter
ModuleNotFoundError: No module named 'ckip_transformers'
```
可至Conda虛擬環境下指令``pip install ckip_transformers``。

## WhisperX 3.3.4問題
* IndexError: tensors used as indices must be long, int, byte or bool tensors


需要修改``C:\Users\username\anaconda3\envs\whisperx\Lib\site-packages\whisperx\alignment.py``
原本:
```python=426
# Get scores for non-wildcard positions
regular_scores = frame_emission[tokens.clamp(min=0)] # clamp to avoid -1 index
```
改成:
```python=426
# Get scores for non-wildcard positions
regular_scores = frame_emission[tokens.clamp(min=0).long()] # clamp to avoid -1 index
```
## py檔問題
* AttributeError: module 'whisperx' has no attribute 'DiarizationPipeline'
修改TranscriptHub/apps/backend/scripts/exec_whisperx_task_v1.1.py
原本(exec_whisperx_task_v1.0.py程式碼位置在229):
```python=233
logger.info("Assign speaker labels using the diarization model")
diarize_model = whisperx.DiarizationPipeline(use_auth_token=HF_TOKEN, device=DEVICE)
```
改成:
```python=233
logger.info("Assign speaker labels using the diarization model")
diarize_model = whisperx.diarize.DiarizationPipeline(use_auth_token=HF_TOKEN, device=DEVICE)
```
## 建置前端
我用過以下方式,可選其一,供參考:
### 利用make指令建置
在windows環境裡,可先使用PowerShell安裝[chocolatey](https://chocolatey.org/install)後再執行指令``choco install make``。
於命令提示字元切換至TranscriptHub/apps/frontend目錄下執行指令``make build-win``後,會產生app.exe。
### go.sum 可能缺少某些模組
利用git bash執行``go build -o frontend``指令,建置go專案時出現錯誤訊息。

解法:
```
go mod tidy
```
這個指令會:
* 刪除不需要的依賴包
* 下載新的依賴包
* 更新 go.sum 文件

## 執行前端
我用過以下方式,可選其一,供參考:
* 若前面使用``make``建置,則可於命令提示字元切換至TranscriptHub/apps/frontend目錄下執行app.exe。
* 利用git bash執行如下指令:
``./frontend``
## 前端沒有使用SSL問題
* 後端的log出現如下錯誤:
```
2025-06-20 09:33:23 - ERROR - [17296] Task 278437207 notification error Error: write EPROTO 80470000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:355:
```
利用nginx把前端和後端都包裝成使用port443做連線。
nginx.conf設定範例:
```
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# 前端 Go 服務代理
location / {
proxy_pass http://127.0.0.1:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 後端 Node.js API 代理,假設 API 路徑是 /api/
location /api/ {
# IP 白名單控管,只允許特定 IP 存取
allow 123.123.123.123; # 允許的 IP
allow 111.111.111.0/24; # 允許的 IP 網段
deny all; # 其他拒絕
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# HTTP 80 強制跳轉 HTTPS
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
```
## 前端檔案上傳後端無回應
若在本機測試,且前端envfile的TranslateEndpoint、TranslateUrl、TranslateQueryUrl及DownloadServer都用localhost指向後端,可查看C:\Windows\System32\drivers\etc目錄下的hosts可能localhost沒有對應到127.0.0.1或是那行對應被註解了。
* 一種解法是hosts裡要有以下對應
```
127.0.0.1 localhost
::1 localhost
```
* 另一種解法是envfile的TranslateEndpoint、TranslateUrl、TranslateQueryUrl及DownloadServer都使用127.0.0.1或網卡IP,甚至是DNS可對應到的其他台伺服器的網域名稱。
後端.env的TASK_SERVER、DOWNLOAD_SERVER及NOTIFY_SERVER也可以用上述方式處理localhost對應不到127.0.0.1的問題。
# 建置完成


# 置換ASR模型
把TranscriptHub/apps/backend/scripts目錄下的config.json,改成其它Hugging Face上開源的ASR模型,例如:MediaTek Research開源的Breeze ASR 25。
原本:
```json=5
"model_size": "large-v3",
```
改成:
```json=5
"model_size": "SoybeanMilk/faster-whisper-Breeze-ASR-25",
```
# 後續更新本地端程式
1. 本地改的先放堆疊裡面。
```bash
git stash
```

2. 查看堆疊裡面有幾個,最新版編號0。
```bash
git stash list
```

3. 從遠端版本庫拉下最新的commit。
```bash
git pull
```

4. 嘗試把最新堆疊的版本放回來。
```bash
git stash pop
```

5. 出現錯誤,請perplexity提供建議:
```bash
# 1. 檢查當前狀態
git status
# 2. 決定如何處理 .gitignore 和 joblists
# 如果要保留變更:
git add .gitignore apps/frontend/tmp/joblists
git commit -m "更新 .gitignore 和 joblists"
# 3. 加入需要的新檔案
git add apps/frontend/login.go
git add apps/frontend/www/html/images/*.png
# 4. 更新 .gitignore 排除不需要的檔案
echo "apps/frontend/app.exe" >> .gitignore
git add .gitignore
# 5. 提交新檔案
git commit -m "加入登入頁面和圖片資源"
# 6. 現在可以安全地 pop stash
git stash pop
```

6. 依建議查看修改的檔案內容,與上一次commit的差異。
```bash
git diff .gitignore
```

7. 選擇保留本地變更並commit。
```bash
git add .gitignore apps/frontend/tmp/joblists
git commit -m "保存本地變更"
```
若選擇放棄本地變更則:
```bash
# 如果不需要這些變更,直接放棄
git restore .gitignore
git restore apps/frontend/tmp/joblists
# 然後再 pop stash
git stash pop
```

8. 再次嘗試把最新堆疊的版本放回來,有衝突的檔案內容會自動合併,後續再手動打開檔案,查看內容進行確認。
```bash
git stash pop
```

注意最後面的這段描述:
```
Unmerged paths:
both modified: .gitignore
```
打開未合併的檔案.gitignore,會看到以下內容,再選擇要保留什麼後,把``<<<<<<< HEAD``、``=======``及``>>>>>>> branch名稱``都拿掉。
```
<<<<<<< HEAD
本地的內容
=======
遠端內容
>>>>>>> branch名稱
```
9. 選擇保留本地變更並commit後,從遠端版本庫拉下最新的commit。

# 參考資料
* https://github.com/AS-AIGC/TranscriptHub
* https://hackmd.io/@charles7668/r1r49pE_6
* https://go.dev/dl/
* https://blog.miniasp.com/post/2019/02/25/Creating-Self-signed-Certificate-using-OpenSSL
* https://medium.com/@stancode/cuda-cudnn%E5%AE%89%E8%A3%9D-win11-c43b81fc3905
* https://developer.nvidia.com/rdp/cudnn-archive
* https://blog.serv.idv.tw/2025/06/colab-whisperx-transcript-revised-50619/#more-8274
* https://jii.notion.site/AI-2293a5e6b336802885aafc20e84a2092
* https://github.com/ckiplab/ckip-transformers