Skip to content

Rjiegit/youtube-transcript-summarizer

Repository files navigation

YouTube 影片文字轉錄與摘要工具

此專案是一個專為內容創作者、研究人員和學習者設計的 YouTube 影片文字轉錄與摘要工具。它能自動下載 YouTube 影片、提取音訊、進行高精度語音轉文字,並利用先進的大型語言模型(LLM)生成結構化摘要,幫助用戶快速理解和提取影片中的關鍵信息。

專案架構與工作流程

本工具採用模組化設計,並將核心程式碼集中在 src/ 目錄:

  • src/infrastructure/media/transcription/transcriber.py:使用 Whisper/Faster-Whisper 進行音訊轉錄。
  • src/infrastructure/llm/summarizer_service.py:整合 OpenAI / Gemini / Mock 後端以生成摘要。
  • src/apps/api/main.py:FastAPI 入口,提供 /tasks/processing-jobs/processing-lock 等端點。
  • src/apps/ui/streamlit_app.py:Streamlit UI。
  • src/infrastructure/media/downloader.py:以 yt-dlp 管理影片與音訊下載。
  • src/services/pipeline/processing_runner.pyProcessingWorker orchestration,負責任務鎖、轉錄、摘要與儲存。
  • src/services/rss/channel_monitor.py:RSS monitor,專責輪詢 feed、去重與呼叫 API 建立任務。
  • src/infrastructure/storage/file_storage.py:負責 Markdown 檔案輸出及檔名清理。
  • src/infrastructure/storage/summary_storage.py:將摘要同步到 Notion;可依需求替換其他儲存後端。
  • src/apps/workers/cli.py:CLI 入口,方便 make run 與背景 worker 處理佇列。

註:請直接 import src.* 內的模組,實際邏輯皆位於 src/

工作流程自動化且高效:從 YouTube 下載影片 → 提取音訊 → 使用 Whisper 進行轉錄 → 使用 LLM 生成摘要 → 以 Markdown 格式保存結果 → 可選擇存儲到 Notion。整個流程在 Docker 容器中運行,確保環境一致性與易於部署。

技術特色

  • 高精度轉錄: 使用 OpenAI 的 Whisper 模型,支持多種語言的高質量語音轉文字
  • 智能摘要: 利用先進的 LLM 技術,生成結構化、易於理解的內容摘要
  • 靈活配置: 支持多種 LLM 選項,包括雲端服務 (OpenAI、Google) 和本地部署 (Ollama)
  • 容器化部署: 使用 Docker 確保環境一致性,簡化安裝和配置過程
  • 中文優化: 專為中文內容設計,輸出格式和提示詞均已優化

功能特點

  • 使用 OpenAI 的 Whisper 模型進行高精度語音轉文字
  • 支援多種 LLM 進行摘要生成:Google Gemini、OpenAI GPT、Ollama (本地模型)
  • 自動處理 YouTube 影片下載、轉錄與摘要的完整工作流程
  • 以 Markdown 格式輸出結構化摘要
  • Docker 容器化部署,確保環境一致性
  • 獨立 Nuxt 展示頁,可部署到 Vercel 顯示最近 100 筆 Notion 成果

環境需求

  • Docker 與 Docker Compose
  • (若不使用 Docker)Python 3.14 + uv
  • 以下至少需要一個 API Key 或服務:
    • OpenAI API Key (可選)
    • Google Gemini API Key (可選)
    • Ollama 本地服務 (可選)

快速開始

1. 設置環境

  1. 克隆此專案到本地:
git clone <repository-url>
cd <repository-directory>
  1. 創建 .env 檔案並設置 API Key (至少選擇一個):
# OpenAI API (可選)
OPENAI_API_KEY=your_openai_api_key

# Google Gemini API (可選)
GOOGLE_GEMINI_API_KEY=your_gemini_api_key

# Ollama Cloud API (可選)
OLLAMA_API_KEY=your_ollama_api_key
OLLAMA_HOST=https://ollama.com

# Notion 儲存與通知(可選)
NOTION_API_KEY=your_notion_api_key
NOTION_DATABASE_ID=your_notion_database_id
NOTION_URL=https://www.notion.so/your-workspace
SHOWCASE_CACHE_TTL_SECONDS=3600

# Discord 通知(可選)
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/......

# Processing lock 管理
PROCESSING_LOCK_ADMIN_TOKEN=your_admin_token

# RSS monitor
RSS_MONITOR_ENABLED=false
RSS_MONITOR_POLL_INTERVAL_SECONDS=3600
RSS_MONITOR_MIN_POLL_INTERVAL_SECONDS=300
RSS_MONITOR_TASK_TIMEOUT_SECONDS=15
TASK_API_BASE_URL=http://localhost:8080
TZ=Asia/Taipei

註:

  • 若同時設定多組 LLM API key,摘要會依 auto 模型池做加權隨機挑選,並把實際使用的 provider:model 寫入 log 與儲存欄位。
  • 目前 auto 池為 gemini-3-flash-preview 10%、gemini-2.5-flash 40%、gemini-2.5-flash-lite 40%、kimi-k2.5:cloud 10%;可在 src/infrastructure/llm/model_options.py 調整。

2. 啟動 Docker 服務

在專案根目錄執行:

docker compose up -d

此指令會啟動 Docker Compose 服務。

  • 預設對外開放 8501(Streamlit)與 8080(FastAPI)。
  • api 服務啟動時會自動更新 yt-dlp(可用 YTDLP_AUTO_UPDATE=0 關閉)。

此指令會啟動三個服務:

  • streamlit:Streamlit UI(8501)
  • api:FastAPI(8080)
  • rss-monitor:YouTube RSS monitor(不對外開 port)

3. 進入服務容器

  • 進入 Streamlit 容器:

    docker compose exec streamlit bash
  • 進入 API 容器:

    docker compose exec api bash

4. 安裝依賴

進入任一服務容器後,安裝所需的依賴項:

make install

此指令會:

  • 下載並安裝最新版本的 yt-dlp 到 /usr/local/bin/
  • 設置 yt-dlp 的執行權限
  • uv 同步並安裝 Python 依賴(uv sync --frozen

使用方法

下載 YouTube 影片

使用以下指令下載 YouTube 影片的音訊到 data/videos/ 目錄:

make yt-dlp url="YOUR_YOUTUBE_URL"

執行文字轉錄與摘要

處理 data/videos/ 目錄下的所有音訊檔案:

make run

或直接呼叫 CLI 入口:

uv run python -m src.apps.workers.cli --db-type sqlite --worker-id local-run

--db-type notion 亦支援,適合 Notion 佇列;--worker-id 可選,用於鎖狀態追蹤。)

執行 RSS 監控

先在 Streamlit 的 RSS Channel Management 區塊新增 YouTube channel 訂閱,然後啟用 monitor:

make rss-monitor

若只想手動輪詢一次,可執行:

make rss-monitor-once

若使用 Docker Compose,設定 RSS_MONITOR_ENABLED=true 後,docker compose up -d 會一併啟動 rss-monitor service。它會在 container 內以長駐 Python process 執行,依 RSS_MONITOR_POLL_INTERVAL_SECONDS 定期輪詢。

說明:

  • 第一次輪詢會先寫入 watermark,不會把歷史影片整批灌入 queue。
  • 偵測到新影片後,rss-monitor 只會呼叫 API 建立 SQLite task,不直接執行下載或摘要。
  • 任務建立後,會由 API 端沿用既有 background processing flow 啟動 worker。
  • RSS monitor 目前僅支援 SQLite queue。
  • TASK_API_BASE_URL 預設為 http://localhost:8080;在 Docker Compose 內部會使用 http://api:8080
  • RSS_MONITOR_TASK_TIMEOUT_SECONDS 用於控制 monitor 呼叫 API 的 request timeout
  • Docker 預設時區:TZ=Asia/Taipei

一鍵完成整個流程

下載影片並立即進行處理:

make auto url="YOUR_YOUTUBE_URL"

使用 Streamlit 網頁界面

本專案提供了一個基於 Streamlit 的網頁界面,讓您可以通過瀏覽器輕鬆使用轉錄和摘要功能:

  1. 啟動 Streamlit 應用:
make streamlit
  1. 在瀏覽器中打開顯示的 URL(通常是 http://localhost:8501)

  2. 使用界面功能:

    • 在文本框中輸入 YouTube 影片網址
    • 點擊「Add to Queue」後即會透過 API 建立任務並自動排程背景處理
    • 若需要手動重新排程,可使用「Trigger Background Processing」按鈕
    • 查看處理進度和結果
    • 下載生成的摘要文件
    • 瀏覽本次會話的歷史記錄

Streamlit 界面特點:

  • 直觀的用戶界面,無需命令行操作
  • 新增任務後自動啟動背景處理,並提示鎖定狀態
  • 實時顯示處理進度
  • 直接在瀏覽器中查看摘要結果
  • 列表可顯示並點擊每筆紀錄的 Notion URL;缺漏時會顯示提示,避免空白或死鏈接
  • 一鍵下載摘要文件
  • 保存會話歷史記錄,方便查看之前處理過的影片

與命令行版本的區別:

  • Streamlit 版本不會自動刪除原始影片文件
  • 提供了視覺化的處理進度
  • 支持在瀏覽器中直接預覽摘要內容

啟動 FastAPI 任務 API

這個 API 提供 POST /tasksPOST /processing-jobs 端點,分別用於排程新任務與觸發背景處理。

  1. 啟動開發伺服器:
make api

服務會在 http://localhost:8080 提供 API。

  1. 送出新增任務請求:
curl -X POST http://localhost:8080/tasks \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "db_type": "sqlite"}'

支援的 YouTube URL 格式包含:watch?v=...youtu.be/...embed/...shorts/...(會自動正規化成 watch?v=... 以利去重)。

成功回應範例:

{
  "task_id": "1",
  "status": "Pending",
  "db_type": "sqlite",
  "message": "Task queued successfully. Processing worker scheduled (worker: api-worker-123456).",
  "processing_started": true,
  "processing_worker_id": "api-worker-123456",
  "cached": false
}

啟動 Nuxt Showcase

展示頁位於 frontend/nuxt-showcase,適合部署到 Vercel,會由 Nuxt server 直接讀取 Notion database 中最近 100 筆 Completed 結果。

本機開發:

make showcase-install
make showcase

make showcase 會優先載入 frontend/nuxt-showcase/.env,若不存在才 fallback 到 repo 根目錄 .env,再啟動 Nuxt dev server。 展示頁開發預設使用 http://localhost:3000

執行測試:

make showcase-test

Vercel 相關設定:

  • Root Directory: frontend/nuxt-showcase
  • Framework Preset: Nuxt.js
  • Environment Variables: NOTION_API_KEYNOTION_DATABASE_IDNOTION_URL
  • 選填 SHOWCASE_CACHE_TTL_SECONDS,預設為 3600

展示頁 API route 會回傳 Cache-Control: public, s-maxage=3600, stale-while-revalidate=3600,讓 Vercel CDN 做簡易 SWR 快取;server process 內也會保留最後一次成功的資料快照,當 Notion 暫時失敗時優先回退可用資料。

重複提交行為

API 會自動對同一 URL 進行去重:

  • 已完成且在 TTL 內(預設 1 小時):回傳 200 OKcached: true,直接返回先前的處理結果。
  • 正在處理中或排隊中(Pending / Processing):回傳 409 Conflict
  • 無紀錄 / 已過期 / 曾失敗:正常建立新 Task,回傳 201 Created

TTL 可透過環境變數 TASK_CACHE_TTL_SECONDS 調整(預設 3600 秒)。

瀏覽器外掛(Chrome/Edge)

可使用瀏覽器外掛直接在 YouTube 影片頁或列表連結送出摘要任務,免手動複製網址。

安裝(開發模式)

  1. 開啟 Chrome/Edge 擴充功能管理頁
    • Chrome: chrome://extensions/
    • Edge: edge://extensions/
  2. 啟用「開發人員模式」
  3. 點擊「載入未封裝項目」並選擇資料夾:src/apps/extension/

設定

  1. 在擴充功能列表中點擊「詳細資料」→「擴充功能選項」
  2. 設定 API Base URL(預設 http://localhost:8080

使用方式

  • 在 YouTube 影片頁點擊工具列的外掛按鈕,即可送出任務
  • 在 YouTube 列表中的影片連結上按右鍵,選擇「Send YouTube link to Whisper Summary」
  • 成功/失敗會顯示通知訊息

注意:若要寫入 Notion,必須在 .env 中設定 NOTION_API_KEYNOTION_DATABASE_ID,缺漏時 API 會回傳 400 錯誤。若希望 Discord 通知附上 Notion 頁面連結,請額外設定 NOTION_URL(例如 https://www.notion.so/your-workspace)。

  1. 觸發背景處理流程:
curl -X POST http://localhost:8080/processing-jobs \
  -H "Content-Type: application/json" \
  -d '{"db_type": "sqlite"}'

成功回應會立即回傳 202 Accepted,內容如下:

{
  "worker_id": "api-worker-123456",
  "db_type": "sqlite",
  "accepted": true,
  "message": "Processing worker scheduled."
}

如果已經有 worker 正在處理,API 會回傳 409 Conflict 並附上 Processing already running. 提示。 新的 worker 會持續撈取佇列直到沒有可執行的任務,處理期間新增的任務也會在同一輪內完成。

4. 查詢與釋放 processing lock(維運專用)

/processing-jobs 回傳 Processing already running.,表示全域鎖仍由某個 worker 持有;此時可用下列維運端點查詢或強制釋放:

  • GET /processing-lock

    • 回傳 lock 狀態(持有者、最後更新時間、是否超過 PROCESSING_LOCK_TIMEOUT_SECONDS)。

    • 需要附帶 X-Maintainer-Token: ${PROCESSING_LOCK_ADMIN_TOKEN} header。

    • 範例:

      curl http://localhost:8080/processing-lock \
        -H "X-Maintainer-Token: ${PROCESSING_LOCK_ADMIN_TOKEN}"
  • DELETE /processing-lock

    • 詢問後釋放 lock;若 expected_worker_id 與目前持有者一致則直接釋放。

    • 可加入 force=true(需 force_threshold_seconds)來清除停滯的 lock,或 dry_run=true 先預檢。

    • 需要 X-Maintainer-Token header。

    • 範例:先查詢持有者,再確認一致後釋放:

      curl -X DELETE http://localhost:8080/processing-lock \
        -H "Content-Type: application/json" \
        -H "X-Maintainer-Token: ${PROCESSING_LOCK_ADMIN_TOKEN}" \
        -d '{"expected_worker_id": "api-worker-123", "reason": "recovery after crash"}'
    • 若要強制清除鎖,請另外提供 force=trueforce_threshold_seconds(以秒為單位):

      curl -X DELETE http://localhost:8080/processing-lock \
        -H "Content-Type: application/json" \
        -H "X-Maintainer-Token: ${PROCESSING_LOCK_ADMIN_TOKEN}" \
        -d '{"force": true, "force_threshold_seconds": 1200, "reason": "stale worker cleanup"}'

      這個流程會先確認鎖已經停滯超過設定秒數才會真正 clear,避免誤殺活著的 worker。

請將 PROCESSING_LOCK_ADMIN_TOKEN 設定在 .env 中,此值即為上述 X-Maintainer-Token 的內容,僅限內部維運人員使用;Streamlit 維運介面會自動套用該設定,不需額外輸入。

若想於 Docker 環境啟動 API,可直接執行 docker compose up -d api(或在 api 容器內跑 make api),API 會綁定宿主機的 8080 連接埠。

使用 Ollama Cloud

如果您想使用 Ollama Cloud 進行摘要處理,請先準備 API key:

  1. 取得 Ollama API key,並設定:
export OLLAMA_API_KEY=your_ollama_api_key
export OLLAMA_HOST=https://ollama.com
  1. 安裝 Python client(專案依賴已包含 ollama):
uv sync --frozen --no-install-project
  1. 若同時有多個 provider key,系統會在 auto 模式中將 Ollama Cloud 納入加權隨機選模。

輸出結果

處理完成後,摘要文件將保存在 data/summaries/ 目錄下,檔名格式為: _summarized_YYYYMMDDHHMMSS_<YouTubeID>_影片標題.md

說明:

  • 每次處理都加入時間戳與 YouTube 影片 ID,避免同標題重複覆蓋。
  • 範例:_summarized_20250101T123000_dQw4w9WgXcQ_我的筆記.md

摘要內容以 Markdown 格式呈現,包含:

  • 完整資訊與重要細節
  • 結構化的內容整理
  • 關鍵洞察與見解

自定義設置

修改 Whisper 模型大小

src/core/config.py 中可調整 Config.transcription_model_size,例如:

self.transcription_model_size = "base"  # 可選: tiny, base, small, medium, large

修改摘要提示詞

src/core/prompt.py 中自定義摘要提示詞模板(目前預設為 PROMPT_VIDEO_SUMMARY)。

開發相關

開發指令

  • 執行測試: make test
  • Lint: uv run flake8 .
  • 格式化: ruff format .(若需)
  • 啟動 REST API: make api(啟動 src/apps/api/main.py 內的 FastAPI)
CODEX_HOME="$PWD/.codex" codex

更新依賴

若新增或更新依賴項,請更新 pyproject.toml 後鎖定版本:

uv lock

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors