Skip to content

Latest commit

 

History

History
161 lines (119 loc) · 11.2 KB

README.md

File metadata and controls

161 lines (119 loc) · 11.2 KB

Live Server — OpenTransLive 網頁伺服器

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 5000

Docker Compose

cp 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.toml

從 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

Committed segment 寫入策略

完成片段以固定大小佇列寫入 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 模板

觀眾/Panel 通訊

  • 觀眾頁(/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 驗證輸入。

疑難排解

請看 ../docs/USAGE.md#8-常見問題。