live_server 是 OpenTransLive 的核心:FastAPI + Socket.IO 網頁伺服器,提供 panel 控制台、觀眾頁、即時轉錄管理、翻譯流程、字幕儲存與匯出。
語言:繁體中文(English)
完整角色、流程、API 與 FAQ 請看 ../docs/USAGE.md。本檔案只說明伺服器本身的設定、啟動與運維細節。
- Python 3.11+
- MongoDB
- Redis
- 至少一組 AI provider API key
- (選用)Docker 與 Docker Compose
- (選用)ElevenLabs API key 或 Gemini API key(即時麥克風轉錄,二選一)
- (選用)YouTube API key(YouTube 同步直播時間)
cd live_server
uv sync
cp app/secret/config.example.toml app/secret/config.toml
# 編輯 app/secret/config.toml
uv run uvicorn app:socket_app --host 0.0.0.0 --port 5000開發模式(自動 reload):
uv run uvicorn app:socket_app --reload --host 0.0.0.0 --port 5000cp app/secret/config.example.toml app/secret/config.toml
# 編輯 app/secret/config.toml
./scripts/compose.sh up -d腳本會從 Git 自動取得目前 repository 與 commit,將精確的原始碼網址注入服務,並把來源資訊寫入 OCI image labels。正式環境若含有未提交變更,腳本會拒絕部署,避免公開的原始碼與實際服務內容不一致。若使用非 GitHub forge,可設定 SOURCE_CODE_URL 覆寫自動產生的網址。
Compose 會啟動 FastAPI server、MongoDB、Redis。
從 app/secret/config.example.toml 複製成 app/secret/config.toml,編輯下列區塊(app/config.py 是讀取這個 TOML 的載入器,通常不用改):
| 區塊 | 用途 |
|---|---|
[settings].SECRET_KEY |
Session cookie 與安全相關 |
[settings].YOUTUBE_API_KEY |
查詢 YouTube 直播開始時間 |
[email_settings].ADMIN_EMAILS |
可進入 /dashboard 的管理員 email |
[email_settings].SMTP_* |
OTP 信件寄送;留空則 OTP 寫進 log(適合開發) |
[mongodb_settings] |
MongoDB 連線 |
redis_url |
Redis 連線 |
[realtime_settings].STT_PROVIDER |
預設轉錄引擎 (elevenlabs / gemini),每個 room 可在 panel 覆寫。釘選(pinned)關鍵字會在下次連線時送入引擎做辨識偏置(ElevenLabs keyterms:最多 50 個、每個 ≤20 字元,另計費;Gemini customVocabulary),改動不會強制重連 |
[realtime_settings].ELEVENLABS_API_KEY |
ElevenLabs Scribe |
[realtime_settings].AI_PROVIDER |
預設修正/翻譯 provider (openai / gemini / groq / cerebras) |
[realtime_settings].CORRECT_PROVIDER |
(可選)修正流程專用 provider |
[realtime_settings].TRANSLATE_PROVIDER |
(可選)翻譯流程專用 provider |
[realtime_settings].TRANSLATE_LANGUAGES |
預設翻譯目標語言 |
[realtime_settings].COMMON_PROMPT |
活動背景或翻譯上下文 |
[realtime_settings].PARTIAL_INTERVAL |
partial 字幕 flush 間隔(秒) |
[realtime_settings].SKIP_CORRECTION |
是否略過修正流程 |
各 AI provider 的模型與 prompt 預設在
app/secret/models.example.toml。要自訂時,複製成app/secret/models.toml編輯即可(存在就優先載入,否則 fallback 回 example);models.toml已被 gitignore。
部分運維選項仍從環境變數讀取:
| 變數 | 說明 | 預設 |
|---|---|---|
ENVIRONMENT |
設為 production 會開啟 Secure cookie 與嚴格的 Socket.IO CORS,並停止在 log 印出 OTP |
development |
SOURCE_CODE_URL |
實際部署版本的完整對應原始碼網址;production 必填,建議指向固定 tag 或 commit | 開發環境使用上游 repository |
PROFESSIONAL_SERVICES_URL |
選填;首頁「技術支援」區塊的外部支援聯絡連結。未設定時不顯示此連結,但仍顯示專案維護者 email。首頁僅介紹開源工具、角色權限與支援聯絡,不展示商業方案 | 空(不顯示外部連結) |
SITE_TEMPLATES_DIR |
選填;部署專屬的 template 覆寫目錄(相對於 live_server/),優先於 app/templates 搜尋,同路徑檔案會取代預設版本。g0v 社群站使用 app/sites/g0v(覆寫首頁的 realtime 授權說明 partials/realtime_access.html)。設定了但目錄不存在時啟動失敗 |
空(只用預設 templates) |
SOURCE_REPOSITORY_URL |
建置來源 repository;scripts/compose.sh 會自動取得 |
Git remote origin |
SOURCE_REVISION |
建置來源 commit SHA;scripts/compose.sh 會自動取得 |
Git HEAD |
SOCKET_CORS_ALLOWED_ORIGINS |
production 模式下的 Socket.IO 允許來源(逗號分隔) | 內建 localhost 清單 |
SEGMENT_WRITE_WORKERS |
MongoDB segment 寫入 worker 數 | 2 |
SEGMENT_WRITE_QUEUE_MAXSIZE |
寫入佇列容量上限 | 500 |
SEGMENT_WRITE_METRICS_LOG_INTERVAL_SEC |
寫入佇列 metrics log 間隔(秒) | 10 |
完成片段以固定大小佇列寫入 MongoDB,避免每段都產生獨立 async task:
- 佇列:固定大小
asyncio.Queue(SEGMENT_WRITE_QUEUE_MAXSIZE) - Worker:固定數量 (
SEGMENT_WRITE_WORKERS) - 滿載行為:佇列滿時丟棄最舊的 committed segment,以保住記憶體並保留較新內容
- Metrics:佇列深度、丟棄數、處理數、失敗數、平均寫入延遲(由
SEGMENT_WRITE_METRICS_LOG_INTERVAL_SEC控制 log 頻率)
app/
├── __init__.py # FastAPI app、HTTP 路由、Socket.IO handler、SSE
├── config.py # 設定載入器(讀取 secret/config.toml)
├── secret/ # config.toml(機密)、models.toml(override)、*.example.toml
├── database.py # MongoDB 連線與 collection
├── email_auth.py # Email OTP 登入
├── http_client.py # 共用 httpx client
├── logger_config.py # logging 設定
├── scribe_manager.py # 轉錄 session 共用邏輯 + ElevenLabs / Gemini 實作
├── socket_schema.py # Socket.IO 事件 schema 驗證
├── translation_service.py # 修正 + 翻譯流程與佇列管理
├── translators/ # 各 AI provider 實作
├── static/ # CSS / JS / 圖示
└── templates/ # Jinja2 模板
- 觀眾頁(
/rt/{sid}、/yt/{sid})使用 SSE:GET /api/session/{sid}/stream,事件transcription_update。 - Panel 使用 Socket.IO 做雙向控制與音訊上傳。
完整事件與 API 列表請看 ../docs/USAGE.md。
詳細欄位請看 ../docs/USAGE.md。摘要:
- MongoDB:
rooms(session 設定 + 擁有者)、transcription_segments(committed 片段)、transcription_store(legacy)、usage_daily(每日用量:email+day(UTC)+sid的音訊 bytes/chunk 累加;秒數在產生報表時換算一次,避免逐筆四捨五入累積誤差) - Redis:
transcription:{sid}:list(近期片段)、transcription:{sid}:partial(partial)、transcription:{sid}:meta、keywords:{sid}、locked_keywords:{sid}、text_dictionary:{sid}
用量統計由 /heartbeat/{sid} 寫入:每次心跳把上次之後新增的音訊量(delta)累加到房間主擁有者的當日紀錄,room 文件本身仍保留累計總量;把某房間的每日紀錄相加即等於 room 的計數。使用者於 /user-dashboard 看日/月圖表(GET /api/usage?days=&months=),管理員在 /dashboard 點 email 進入 /dashboard/users/{email} 看個別報表(GET /api/users/{email}/usage)。
管理員可在 /dashboard 為個別帳號設定單一 session 翻譯語言上限(Max langs,POST /api/users/{email}/settings 的 max_languages;預設 0 = 無限制)。上限依房間主擁有者計算、立即生效:超出的語言只取前 N 個翻譯,POST /api/session/{sid}/languages 超過上限回 400,GET 會回傳 max_languages;已開啟的 panel(含 co-owner)透過 Socket.IO 即時同步上限並顯示提示。
回填歷史:部署這個版本時每個環境跑一次就好 —— 之後每天的用量由心跳自己記錄。room 計數器沒有日期,但 push_audio 一向每 30 秒音訊寫一行 [audio_usage] session=… bytes=… 到 logs/,python -m app.usage_backfill 解析這些累計快照、相鄰相減還原每日用量(時間戳是 UTC+8,會換算成 UTC 日期):
docker compose exec backend ./.venv/bin/python -m app.usage_backfill # 只報告,不寫入
docker compose exec backend ./.venv/bin/python -m app.usage_backfill --apply --residual回填列標記 source: "log_backfill",且只用 $setOnInsert。重跑是 no-op:已存在的日期會跳過,residual 也會先扣掉 usage_daily 既有的量,因此就算帶 --residual 也不會重複計算。限制:精度為一行 log(30 秒音訊);已輪替掉的 log 檔無法還原,--residual 會把「room 計數器有、但沒被記錄」的差額記到該房間最後活動日;已釋放擁有權的房間無從歸屬,只會列在報告裡。
- 觀眾頁完全公開、免登入。
- Panel/編輯/管理員 API 透過 Email OTP 登入;session-level 操作需 secret key 或 owner/co-owner 權限。
- 開啟
/panel/{sid}:owner/co-owner/管理員進入控制台;其他人(含未登入者)被導向觀眾頁/rt/{sid}(保留 query),未登入者另會看到一次「登入以管理」連結。已存在但沒有 owner 的場次,由第一位開啟它的已登入者成為 owner。場次不存在時,未登入者導向/login?next=/panel/{sid},已登入者則建立場次並成為 owner。 - 程式化 client(transcribe/realtime)以個人 API key 認證(HTTP
Authorization: Bearer otl_…或 Socket.IO 連線auth)。每位使用者一把,於/user-dashboard產生;伺服器只存 SHA-256 hash,明文僅在產生時顯示一次。key 只在連線握手驗證一次,之後靠已驗證的 session,不隨每筆更新重送。 - key 的權限即時從使用者紀錄推導(realtime + room 擁有權),不寫死在 key 裡 —— 撤銷 realtime/room 下次請求即生效。唯一例外:管理端點(建立帳號、rotate 他人、改設定)對 key 認證一律拒絕,即使擁有者是 admin。因此廣播機請用專用非 admin 帳號(只需擁有目標 room)。
- dashboard 顯示的 key 識別碼是從 hash 衍生的指紋(
otl_+ hash 前綴),不洩漏任何機密字元。 - production 模式(
ENVIRONMENT=production)會啟用 Secure cookie 與嚴格 Socket.IO CORS 白名單。 - 未設定
SMTP_HOST時不寄信;此時只有非 production 才會把 OTP 明文寫進 log 供本機測試,production 改為記錄一筆 error。正式部署務必設定ENVIRONMENT=production,docker compose 會從.env帶進容器。 - Socket.IO 事件以 socket_schema.py 驗證輸入。