# PodNotes **Repository Path**: richie12/pod-notes ## Basic Information - **Project Name**: PodNotes - **Description**: 一个完全本地运行的 PyQt5 桌面工具:把 B 站、播客等音视频链接变成一份可检索、可复习的中文 Markdown 问答笔记。 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-08-03 - **Last Updated**: 2026-08-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PodNotes — 视频/播客 → 结构化 Markdown 笔记 一个完全本地运行的 PyQt5 桌面工具:把 B 站、播客等音视频链接变成一份可检索、可复习的中文 Markdown 问答笔记。 > 核心理念:**听完了就忘**,于是做出来一边听、一边自动产出结构化笔记。 --- ## 目录 - [功能特性](#功能特性) - [处理流水线](#处理流水线) - [安装与运行](#安装与运行) - [界面与基本使用](#界面与基本使用) - [重点:总结模型的三种用法](#重点总结模型的三种用法) - [对比速览](#对比速览) - [用法 A:本地进程 GGUF(零配置首选)](#用法-a本地进程-gguf零配置首选) - [用法 B:本地服务 vLLM / sglang(高吞吐)](#用法-b本地服务-vllm--sglang高吞吐) - [用法 C:云端 OpenRouter(不占本机算力)](#用法-c云端-openrouter不占本机算力) - [如何在 UI 中切换](#如何在-ui-中切换) - [配置文件示例](#配置文件示例) - [ASR 语音识别的两种方式](#asr-语音识别的两种方式) - [输出文件与目录结构](#输出文件与目录结构) - [常见问题](#常见问题) - [依赖说明](#依赖说明) --- ## 应用截图
主界面 · 粘贴链接一键处理
PodNotes 主界面
输出效果 · 结构化 Markdown 笔记(左文件列表 + 右渲染预览)
PodNotes 笔记预览页
--- ## 功能特性 - 一键端到端:粘贴视频/播客链接 → 自动下载 → 自动转写 → 自动总结成 Markdown - 完全本地可控:默认无需联网、无需 API Key、无需 GPU 也可跑(GGUF 路径) - ASR 引擎可选:本地 faster-whisper(离线)/ OpenAI Whisper 云端 API - **总结模型三选一**(核心):进程内 GGUF(零配置)/ 本地 vLLM·sglang 服务 / 云端 OpenRouter - 自动按上下文窗口切分 + 多级合并:长播客也能稳定产出 - 下载缓存:相同链接二次运行秒级跳过 - 可选视觉模型:将视频截图与文字笔记融合,补充图示信息 - 中文/英文/日文/韩文识别语言可切换 - 自定义系统提示词:可改写整理风格 --- ## 处理流水线 ``` 视频/播客 URL │ ▼ ① 媒体下载(yt-dlp) ─→ outputs/_audio.mp3 │ ▼ ② 语音转写 ASR ─→ outputs/_audio_transcript.txt │ ├─ local : faster-whisper (CPU/GPU,离线) │ └─ cloud : OpenAI Whisper API │ ▼ ③ 大模型整理 ─→ outputs/_audio_summary.md ├─ local_gguf : llama-cpp-python 进程内 qwen3-4b-GGUF ├─ local : vLLM / sglang OpenAI 兼容 HTTP 服务 └─ cloud : OpenRouter(OpenAI 兼容) ``` 每一步都有进度条与日志实时显示在界面下方。 --- ## 安装与运行 ### 1. 准备 Python 环境 推荐 Python 3.10+。Windows / macOS / Linux 均可。 ### 2. 安装依赖 ```bash pip install -r requirements.txt ``` 依赖一览(见 `requirements.txt`): | 包 | 用途 | |---|---| | PyQt5 | 桌面 UI | | yt-dlp | 视频/音频下载 | | requests | HTTP 调用(OpenAI 兼容接口) | | imageio-ffmpeg | 自带 ffmpeg 二进制,无需系统安装 | | faster-whisper | 本地 ASR(CPU/GPU) | | modelscope | 国内镜像下载模型(优先级高) | | llama-cpp-python | 进程内 GGUF 推理(用法 A 必装) | > **第一次跑 GGUF 路径**时,`llama-cpp-python` 会尝试加载 GPU 加速层,Windows 上若缺 `cublas64_12.dll` 等,UI 启动时会自动注入 `nvidia/*/bin` 路径;如仍失败,可仅用 CPU 跑(速度慢但稳定)。 ### 3. 启动 ```bash python ui.py ``` 启动后直接粘贴视频链接 → 点 **开始处理** 即可。第一次使用会自动下载模型,耐心等待。 --- ## 界面与基本使用 主界面三步式流程: 1. **粘贴链接**:支持 Bilibili、YouTube 等 yt-dlp 支持的站点;窗口置顶时会自动识别剪贴板里的链接。 2. **开始处理**:实时显示「下载 → 语音转写 → LLM 整理」三步状态与进度。 3. **查看结果**:处理完成后自动跳转到结果页,左侧文件列表、右侧 Markdown 预览。 菜单: - **文件 → 新建任务**:清空状态,开始下一个 - **文件 → 查看已解析文件**:浏览 `outputs/` 目录 - **文件 → 清空下载缓存**:删除 `.cache/download_cache.json`(下次运行将重新下载) - **设置 → 高级配置...**:弹出所有可调参数 --- ## 重点:总结模型的三种用法 总结模型的三种用法对应 UI 中 **设置 → 高级配置 → 总结后端** 下拉框的三个选项: ``` chat_backend 取值 UI 显示 实际含义 ───────────────── ───────────────────── ─────────────────────── "local_gguf" 本地进程(GGUF) llama-cpp-python 进程内 GGUF "local" 本地服务(vLLM) 本地 OpenAI 兼容 HTTP 服务 "cloud" 云端(OpenRouter) OpenRouter 云端 API ``` 下面分别讲清三者。 ### 对比速览 | 维度 | 本地 GGUF(零配置) | 本地 vLLM 服务 | 云端 OpenRouter | |---|---|---|---| | 底模(默认) | qwen3-4b (GGUF q4_k_m) | qwen3-4b (高精) | 任意 OpenRouter 模型(如 `openrouter/free`) | | 配置门槛 | **零**:装好包就能用 | 需自行启动 vLLM / sglang 服务 | 需注册 OpenRouter 拿 Key | | API Key | ❌ 不需要 | 通常不需要 | ✅ 需要 | | Base URL | ❌ 留空 | `http://localhost:/v1` | `https://openrouter.ai/api/v1` | | 是否联网 | 仅**首次**下载权重(约 2~3GB) | 否 | ✅ 每次 | | 上下文窗口 | 较小(默认 16K,需分块合并) | 大(通常 32K~128K) | **极大**(一次读完不切分) | | 速度 | 慢(看硬件) | 快(GPU + 连续批处理) | 秒级(取决于模型) | | 成本 | 免费 | 免费(占你的硬件) | 按量计费 | | 隐私 | **完全本地** | **完全本地** | 上传云端 | | 适用场景 | 个人离线、临时用、零配置 | 已部署推理服务的环境 | 长内容、最干净、最快 | --- ### 用法 A:本地进程 GGUF(零配置首选) **核心思想**:用 `llama-cpp-python` 把 GGUF 量化模型加载到当前 Python 进程内推理,不依赖任何外部服务、不消耗 API 额度、不上传数据。 #### 适合谁 - 没有显卡/服务器,希望**装上就能跑** - 不想配 API Key,不想折腾 vLLM - 笔记内容**敏感**(完全离线) #### 工作机制(pipeline.py 中 `_chat_local_gguf`) 1. **首次运行**:自动从 ModelScope 仓库下载 `qwen/Qwen3-4B-GGUF` 的 GGUF 权重到项目 `models/qwen--Qwen3-4B-GGUF/`(备选 HuggingFace)。 2. **量化挑选**:默认 `q4_k_m`(约 2~3GB)。找不到目标量化时按 `q4_k_m → q4_k_s → q5_k_m → q8_0 → f16` 兜底;再不行就取目录下任意 `.gguf`。 3. **进程内加载**:通过 `llama_cpp.Llama(model_path=..., n_ctx=16384, n_gpu_layers=32)` 实例化,自动检测 CUDA / Metal 支持;纯 CPU 环境退化为 `n_gpu_layers=0`。 4. **同一进程只加载一次**:`_gguf_cache` 模块级缓存,第二次推理直接复用,无需重新读盘。 5. **长文本处理**:根据 `n_ctx`(默认 8192,留 2048 给 system+输出)把转写稿切成 token 预算内的多块,**逐块整理 → 合并 → 再合并**,递归处理任意长度。 6. **退出释放**:`closeEvent` 中调用 `pipeline.release_gguf()` 显式释放 llama.cpp 资源,避免解释器销毁阶段的告警。 #### 配置项 打开 **设置 → 高级配置**: | 项 | 默认值 | 说明 | |---|---|---| | 总结后端 | `本地进程(GGUF)` | 必选 | | Base URL | (留空) | **不用填**,程序忽略 | | API Key | (留空) | **不用填** | | 总结模型 | `qwen/Qwen3-4B-GGUF` | ModelScope/HF 仓库 ID;也支持本地 `.gguf` 文件绝对路径或目录路径 | | 量化等级 | `q4_k_m` | 可选:`q4_k_m` / `q4_k_s` / `q5_k_m` / `q8_0` / `f16`(按需改 `chat_local_quant`) | #### 高级用法:手动放权重 如果你已经下载好了权重,避免重复下载: ```text PodNotes/ ├── models/ │ └── Qwen3-4B-GGUF/ # 把 .gguf 放在这里(或任意上述候选目录) │ ├── qwen3-4b-q4_k_m.gguf │ └── ... ``` 或者把"总结模型"框填成本地绝对路径:`D:\models\qwen3-4b-q4_k_m.gguf`。 #### 性能与注意事项 - **速度取决于 CPU/内存**。CPU 跑 q4_k_m 的 4B 模型整理一份 1 小时播客通常十几分钟到半小时。 - **首次运行慢**:下载 2~3GB 权重;UI 会通过 `tqdm` 转发的进度条实时显示。 - 长文本需要分块 + 合并,最终笔记在主题交界处偶尔会"接缝不顺",属正常现象;想要更干净的输出换用法 B/C。 --- ### 用法 B:本地服务 vLLM / sglang(高吞吐) **核心思想**:你已经在本地(或内网机器)启动了一个 OpenAI 兼容的 HTTP 服务(如 vLLM、sglang、Ollama 的 OpenAI 兼容模式),PodNotes 只作为客户端调它的 `/v1/chat/completions`。 #### 适合谁 - 已部署 GPU 服务器,**长跑一个推理服务**给多个工具共享 - 需要**高吞吐 / 低延迟**(vLLM 的连续批处理优势) - 想要用 qwen3-4b 的**非量化**精度 - 不想让 PodNotes 进程独占内存(服务独立,PodNotes 只是 HTTP 客户端) #### 工作机制(pipeline.py 中 `_chat` 走 `chat_backend="local"` 分支) 1. 拼接 `base_url` + `/v1/chat/completions`(也接受已经带 `/chat/completions` 的)。 2. POST 发送 OpenAI 兼容 messages: - `temperature=0.3`、`top_p=0.8`、`top_k=20`、`presence_penalty=1.5` - `chat_template_kwargs={"enable_thinking": False}` —— 告诉 Qwen3 关闭思考模式 3. 文本超长时按 80,000 字符切分,逐段总结后再合并(上下文足够大时通常**不必切**)。 4. UI 提供 **「获取模型」** 按钮:直接请求 `/v1/models` 拉取真实模型 ID 填回下拉框,避免手抄出错(vLLM 服务的模型 ID 往往是 `/workspace/models/qwen3-4b/` 这种长串)。 #### 启动本地服务(参考命令) **vLLM**: ```bash vllm serve Qwen/Qwen3-4B \ --host 0.0.0.0 \ --port 8001 \ --max-model-len 32768 ``` **sglang**: ```bash python -m sglang.launch_server \ --model-path Qwen/Qwen3-4B \ --host 0.0.0.0 --port 8001 \ --context-length 32768 ``` 启动后用 curl 自测: ```bash curl http://localhost:8001/v1/models ``` 看到 JSON 里有模型 ID 即表示服务可用。 #### 配置项 | 项 | 默认值 | 说明 | |---|---|---| | 总结后端 | `本地服务(vLLM)` | 必选 | | Base URL | `http://localhost:8001/v1` | 按你的服务地址修改 | | API Key | (留空) | 大多数本地服务无鉴权,留空即可 | | 总结模型 | (点击 **获取模型** 自动填) | 也可手动输入 `Qwen/Qwen3-4B` 或服务真实 ID | #### 进阶 - 把 `Base URL` 指向**局域网另一台机器**即可:`http://192.168.x.x:8001/v1`,多机协作。 - 如果服务要求鉴权,把 API Key 填上即可。 --- ### 用法 C:云端 OpenRouter(不占本机算力) **核心思想**:把转写稿直接发给 OpenRouter(统一转发多家模型的 API 聚合服务),享受云端超大上下文窗口。 #### 适合谁 - 想要**最快、最干净**的整理结果(一次读完,不必分块合并) - 没有 GPU 或 GPU 显存不够 - 不在意**内容上云**(注意隐私) - 想换不同模型试效果(OpenRouter 聚合了 GPT、Claude、Gemini、Qwen、DeepSeek 等上百家) #### 工作机制(pipeline.py 中 `_chat` 走 `chat_backend="cloud"` 分支) 与用法 B 共用 `_chat` 函数,但有两条 OpenRouter 特有的处理: 1. 自动关闭推理: ```python if "openrouter.ai" in url or "openrouter" in model: payload["reasoning"] = {"enabled": False} headers["X-Title"] = "PodNotes" ``` 防止 Qwen3 / DeepSeek-R1 等带思考模式的模型输出大量 `` 标签浪费时间。 2. 自动附带 `X-Title: PodNotes`(OpenRouter 用来在排行榜上识别来源,可选)。 #### 配置项 | 项 | 默认值 | 说明 | |---|---|---| | 总结后端 | `云端(OpenRouter)` | 必选 | | Base URL | `https://openrouter.ai/api/v1` | 一般不用改 | | API Key | (留空 → 会弹窗提示) | 去 https://openrouter.ai/keys 申请;勾选 **记住密钥** 可明文存到本地 `config.json` | | 总结模型 | `openrouter/free` | 任意 OpenRouter 支持的模型 ID,如 `google/gemini-2.5-flash`、`deepseek/deepseek-chat-v3`、`qwen/qwen3-4b:free` | #### 模型选择建议 - `openrouter/free`:零成本试水,但质量随机 - `google/gemini-2.5-flash`:长文本极强,速度快 - `deepseek/deepseek-chat-v3`:中文质量优秀 - `qwen/qwen3-235b-a22b:free`:强大的开源大模型 - `anthropic/claude-sonnet-4.5`:英文内容首选 去 https://openrouter.ai/models 看完整列表。 --- ### 如何在 UI 中切换 打开 **设置 → 高级配置**,在 **总结后端** 下拉里选择: ``` ┌──────────────────────────────────────────────────────────────┐ │ 总结后端: [本地进程(GGUF) ▼] │ │ │ │ 切到「本地进程(GGUF)」:Base URL 自动清空,无需 Key, │ │ 首次使用自动下载 GGUF 权重 │ │ │ │ 切到「本地服务(vLLM)」:Base URL 自动填 localhost:8001/v1, │ │ 「获取模型」按钮亮起,点了可自动取模型 │ │ │ │ 切到「云端(OpenRouter)」:Base URL 自动填 openrouter.ai/api/v1, │ 必须填 API Key,否则开始时弹窗提醒 │ └──────────────────────────────────────────────────────────────┘ ``` 切完后点 **确定** 保存。下次启动自动应用。 ### 配置文件示例 `config.json`(位于项目根目录,由程序自动写入): ```json { "openai_api_key": "", "base_url": "https://openrouter.ai/api/v1", "whisper_model": "whisper-1", "asr_backend": "local", "asr_model": "small", "chat_backend": "local_gguf", "chat_model": "qwen/Qwen3-4B-GGUF", "chat_local_model": "qwen/Qwen3-4B-GGUF", "chat_local_quant": "q4_k_m", "language": "auto", "output_dir": "E:\\Mine\\Work\\ai\\PodNotes\\outputs", "chunk_minutes": 10, "screenshot": false, "frame_interval": 120 } ``` > 默认**不写入 API Key**(`save_config(remember_key=False)` 时清空)。需要记住时勾选界面上的 **「记住密钥」** 复选框,会以明文形式写入本地。 ## 输出文件与目录结构 ``` PodNotes/ ├── config.json # 自动生成的配置文件 ├── outputs/ # 默认输出目录(可在高级配置里改) │ ├── BV1xxx_audio.mp3 # 下载的音频 │ ├── BV1xxx_audio_transcript.txt # 逐字稿(中间产物,可关掉总结直接拿) │ └── BV1xxx_audio_summary.md # 最终结构化笔记 ├── models/ # 自动管理的模型目录 │ ├── faster-whisper-small/ # ASR 模型 │ └── qwen--Qwen3-4B-GGUF/ # GGUF 权重(仅 A 路径) └── .cache/ └── download_cache.json # 已下载链接缓存 ``` `outputs/_audio_summary.md` 就是最终产物:核心摘要 + 主题分组 + 逐问逐答(Q/A),可直接拿去复习、检索、喂给别的工具。 --- ## 常见问题 **Q1:第一次跑 GGUF 一直没反应?** A:等下载。q4_k_m 的 qwen3-4b 约 2.4GB。日志区会显示 `下载进度: x%|...`,若完全没有日志,确认 `modelscope` 安装成功,且本机可访问 `modelscope.cn`。 **Q2:GGUF 跑得太慢?** A:换用法 B 起 vLLM 服务,或换用法 C 上云。GGUF 进程内路径适合"有就行、不急"的场景。 **Q3:vLLM 服务起来了但提示 `model does not exist`?** A:点 **「获取模型」** 按钮,它会请求 `/v1/models` 把真实模型 ID 拉出来填进下拉框。 **Q4:OpenRouter 报 `User not found` / 401?** A:API Key 没填或填错,去 https://openrouter.ai/keys 复制正确的 sk-or-... 前缀的 key。 **Q5:Qwen3 输出里出现 `...` 一大段推理?** A:用法 C 已自动发 `reasoning.enabled=False`;用法 A 用的是 GGUF 路径,本身不会触发思考模式。若仍出现,检查系统提示词里有没有误用 `enable_thinking=True`。 **Q6:长播客(>2 小时)总结的笔记中间有断章?** A:这是分块合并的副作用。换用法 C(OpenRouter 上下文极大)或用法 B(vLLM 长上下文)能显著改善。 **Q7:想用其他模型(如本地 Qwen2.5-7B-Instruct 的 GGUF)?** A:在 **总结后端 = 本地进程(GGUF)** 下,把"总结模型"改成: - ModelScope/HF 仓库 ID,如 `qwen/Qwen2.5-7B-Instruct-GGUF` - 或本地绝对路径:`D:\models\qwen2.5-7b-instruct-q4_k_m.gguf` 然后调整"量化等级"为你下载的对应量化。 **Q8:怎么切换系统提示词?** A:**设置 → 高级配置 → 系统提示词**。可以重写整理风格、输出语言、Q/A 模板等。 **Q9:下载失败 / 网速慢?** A:日志里能看到 yt-dlp 详细错误。程序已内置 `retries=10, fragment_retries=10` 自动重试。可换网络/换时间再试;或把链接放进下载缓存目录手动下完再处理。 --- ## 依赖说明 ```txt PyQt5>=5.15 yt-dlp requests imageio-ffmpeg faster-whisper modelscope llama-cpp-python ``` - `imageio-ffmpeg` 用来在打包环境提供 ffmpeg 二进制,避免系统依赖 - `modelscope` 国内下载速度远胜 HuggingFace,国内用户强烈建议保留 - `llama-cpp-python` 仅在 **用法 A** 真正用到;不需要 GGUF 路径可以 `pip uninstall`,但保留无副作用 --- > 做给自己听播客时用的工具。如果你也在密集听播客却懒得记笔记,欢迎直接用。