# https://github.com/NotJoeMartinez/yt-fts 项目说明书

生成时间：2026-06-27 01:00:41 UTC

## 目录

- [项目概览与安装](#page-1)
- [下载、列表、更新与导出](#page-2)
- [搜索功能（全文搜索与语义搜索）](#page-3)
- [AI 集成：Embeddings、LLM 聊天机器人与摘要](#page-4)

<a id='page-1'></a>

## 项目概览与安装

### 相关页面

相关主题：[下载、列表、更新与导出](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
- [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)
- [src/yt_fts/utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/utils.py)
- [src/yt_fts/llm/get_embeddings.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/get_embeddings.py)
- [src/yt_fts/llm/summarize.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/summarize.py)
- [src/yt_fts/llm/chatbot.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/chatbot.py)
- [src/yt_fts/download/download_handler.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/download/download_handler.py)
- [src/yt_fts/search.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py)
- [FUNDING.yml](https://github.com/NotJoeMartinez/yt-fts/blob/main/FUNDING.yml)
</details>

# 项目概览与安装

## 一、项目定位与核心能力

yt-fts（YouTube Full-Text Search）是一个面向 YouTube 视频字幕的命令行工具，旨在把频道或播放列表的字幕下载到本地，建立可全文检索、可向量检索，并可与大语言模型对话的索引数据库。它使用 `yt-dlp` 抓取 WebVTT 字幕，用 SQLite 存储结构化元数据，用 ChromaDB 保存语义向量。

项目的核心能力可分为四层：

- **下载层**：基于 `yt-dlp` 拉取频道、播放列表或单视频的字幕文件，支持并行任务与浏览器 cookie。
- **全文检索层**：使用 SQLite FTS5 表对字幕进行词项匹配，支持 `AND`、`OR`、引号短语、`-` 排除等查询语法。
- **语义检索层**：调用 OpenAI 或 Gemini 的 Embedding 接口，将字幕分块写入 ChromaDB，支持余弦相似度搜索。
- **生成层**：在前两层检索结果之上调用 LLM 提供 `summarize` 与 `llm` 两种交互式问答。

资料来源：[README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)

## 二、版本演进与变更要点

| 版本 | 发布时间 | 关键变更 |
|------|----------|----------|
| 0.1.64 | 2025-08-10 | 新增对免费 Gemini Embedding 与 Chat 模型的支持 |
| 0.1.62 | 2025-07-04 | 随机化 yt-dlp User-Agent，修复单视频下载与重试逻辑 |
| 0.1.60 | 2025-01-03 | 默认并发任务数从 1 提升到 8；修复下载格式错误 |
| 0.1.58 | 2024-09-12 | 重构高级搜索方法 |
| 0.1.57 | 2024-09-06 | 新增 `summarize` 命令；引入 `--cookies-from-browser` 参数 |

从版本演进可以看出三个主线：稳定性修复、模型生态扩展（OpenAI → Gemini）、以及下载层的鲁棒性提升。

资料来源：[CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

## 三、命令行入口与子命令结构

CLI 由 `click` 框架组织，顶层入口位于 `src/yt_fts/yt_fts.py`，注册为 `cli` 命令组，并在模块底部通过 `if __name__ == '__main__': cli()` 启动。可识别的子命令覆盖了完整的"下载—索引—检索—生成"工作流。

```mermaid
flowchart LR
    A[yt-fts CLI] --> B[download]
    A --> C[search / vsearch]
    A --> D[embeddings]
    A --> E[summarize]
    A --> F[llm]
    A --> G[export / list / delete / config]
    B --> H[(SQLite + ChromaDB)]
    D --> H
    C --> H
    E --> H
    F --> H
```

主要子命令职责如下：

- `download`：从频道或播放列表 URL 下载字幕，支持 `--language`、`--jobs`、`--cookies-from-browser` 等参数。
- `search` / `vsearch`：前者调用 SQLite FTS5 全文检索，后者查询 ChromaDB 做语义检索；可叠加 `--export` 输出 CSV。
- `embeddings`：将字幕按时间窗口切块，调用 Embedding 模型写入 ChromaDB。
- `summarize`：对单条视频的转录文本做摘要，并在关键节点插入时间戳 URL。
- `llm`：以检索结果为上下文启动多轮对话，回答不了时自动扩展查询。
- `list` / `delete` / `export` / `config`：分别用于浏览已索引频道、删除频道、导出字幕、查看配置路径。

资料来源：[src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)

## 四、安装、环境与配置

### 4.1 依赖与运行要求

运行时依赖主要集中在以下几项：

- `yt-dlp`：负责抓取字幕与元数据，是下载层的核心。
- `webvtt-py`：用于解析 WebVTT 文件到词级或句子级时间戳。
- `openai`：官方 OpenAI SDK，通过自定义 `base_url` 也能对接 Gemini 等兼容服务。
- `chromadb`：持久化向量索引。
- `rich` + `click`：负责终端 UI 与 CLI 解析。

`get_model_config` 函数会根据 API Key 前缀自动判定后端：若 Key 以 `sk-` 开头则使用 OpenAI（`https://api.openai.com/v1`），以 `AIza` 开头则切换至 Gemini（`https://generativelanguage.googleapis.com/v1beta`）。当未显式传入 Key 时，会依次读取 `OPENAI_API_KEY`、`GEMINI_API_KEY` 环境变量。

资料来源：[src/yt_fts/utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/utils.py)

### 4.2 安装方式

项目以 `pyproject.toml` 作为构建入口（自 v0.1.43 起从 `setup.py` 迁移）。标准安装流程为：

1. 克隆仓库并创建虚拟环境。
2. 执行 `pip install -e .` 或 `pip install yt-fts`。
3. 在终端中运行 `yt-fts --version` 验证安装；若打印出版本号即表示 CLI 已注册成功。

### 4.3 配置路径与 API Key

- 配置文件、SQLite 数据库与 ChromaDB 持久化目录由 `config` 子命令统一打印。
- 大语言模型与 Embedding 共用同一 API Key，但可在 `summarize` 中通过 `--model` 指定 chat 模型。
- 下载层在 v0.1.62 起会随机化 User-Agent 字符串池，降低被 YouTube 风控的概率。

资料来源：[src/yt_fts/download/download_handler.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/download/download_handler.py)

## 五、社区常见安装与上手问题

- **请求格式不可用（#183）**：通常是 `yt-dlp` 版本过旧导致。可升级 `yt-dlp` 至 v0.1.60 指定的 2025.6.30 或更高版本。
- **下载到错误频道（#46）**：早期版本在 `@handle` 解析上存在歧义，v0.1.59 起改用 RSS Feed 提取频道名称，建议保持工具为最新。
- **搜索仅返回单条命中（#189）**：这是 `search.py` 中排序键缺失 `video_id` 导致的边界 bug，升级到修复版本即可。
- **缺少 Cookie 被限流**：可使用 `download --cookies-from-browser firefox` 让 yt-dlp 复用浏览器登录态。
- **仅想下载一段引用的音视频（#60）**：当前工作流需要先用 `search` 找到时间戳，再用 `yt-dlp -x` 与 `ffmpeg` 手动裁剪；该特性尚未集成进 CLI。

资料来源：[CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

## 六、See Also

- 下载与字幕抓取：见 `DownloadHandler` 与 `src/yt_fts/download/` 模块。
- 全文与语义检索：见 `SearchHandler` 与 ChromaDB 持久化目录。
- LLM 对话与摘要：见 `LLMHandler` 与 `SummarizeHandler`。
- 项目资助入口：[FUNDING.yml](https://github.com/NotJoeMartinez/yt-fts/blob/main/FUNDING.yml)

---

<a id='page-2'></a>

## 下载、列表、更新与导出

### 相关页面

相关主题：[项目概览与安装](#page-1), [搜索功能（全文搜索与语义搜索）](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)
- [src/yt_fts/download/download_handler.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/download/download_handler.py)
- [src/yt_fts/list.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/list.py)
- [src/yt_fts/export.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/export.py)
- [src/yt_fts/db_utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/db_utils.py)
- [src/yt_fts/utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/utils.py)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)
</details>

# 下载、列表、更新与导出

## 概览

`下载、列表、更新与导出` 是 yt-fts 工作流中最常用的数据生命周期入口,承担"获取字幕—管理频道—同步更新—输出数据"四类职责。CLI 入口全部由 [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py) 基于 [Click](https://click.palletsprojects.com/) 注册命令,核心实现则由 `DownloadHandler`、数据库工具模块以及导出模块共同完成,数据最终落到本地 SQLite 数据库中供后续搜索/语义检索使用。

```mermaid
flowchart LR
    A[yt-dlp 抓取] --> B[DownloadHandler]
    B --> C[(SQLite 数据库)]
    C --> D[list 列表]
    C --> E[update 更新]
    C --> F[export 导出]
    F --> G[vtt / csv / txt]
    D --> H[用户查看 ss 标记]
    E --> B
```

---

## 下载 (download)

### 命令定义

`download` 命令接受一个必填的 `url` 参数(频道或播放列表 URL),通过 `get_channel_id_from_input` 从 URL 中解析频道 ID,再交给 `DownloadHandler` 处理。CLI 定义在 [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py) 中。

可选项包括:

| 选项 | 默认值 | 作用 |
|------|--------|------|
| `-p / --playlist` | False | 下载整个播放列表 |
| `-l / --language` | `en` | 字幕语言 |
| `-j / --jobs` | `8` | 并行下载任务数 (v0.1.60 起从 1 提升到 8) |
| `--cookies-from-browser` | `None` | 从浏览器读取 Cookie,绕过限速 (v0.1.57 引入) |

资料来源:[src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)、[CHANGELOG.md:0.1.60](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

### 下载内核:User-Agent 随机化

`DownloadHandler` 内置了一个浏览器 User-Agent 列表,每次下载会随机挑选一条注入到 yt-dlp 请求中,以规避 YouTube 的频率限制。资料来源:[src/yt_fts/download/download_handler.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/download/download_handler.py)、[CHANGELOG.md:0.1.62](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

### 频道名解析

v0.1.59 起,下载逻辑改为优先从 RSS feed 抓取频道名,显著提升了 `@handle` 形式 URL 的解析稳定性。资料来源:[CHANGELOG.md:0.1.59](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

### 已知问题

社区曾报告 `Requested format is not available` 错误 (Issue #183),已在 v0.1.60 的 "Fixed download format errors" 修复项中处理——底层将 yt-dlp 升级到 2025.6.30。资料来源:[CHANGELOG.md:0.1.60](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

另一个常见问题是 "Wrong channel downloaded" (Issue #46),通常是 `@handle` 别名指向了同名不同账号的频道,新版 RSS 解析在一定程度上缓解了此类问题。

---

## 列表 (list)

`list_channels` 列出当前 SQLite 中已建立索引的全部频道,并对启用了向量嵌入(语义搜索)的频道附加 `(ss)` 标记,提示该频道可以执行 `vsearch`。当用户执行 `embeddings --channel <name>` 后,列表会自动更新,这是判断语义搜索可用性的最直接方式。资料来源:[README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)、[src/yt_fts/list.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/list.py)

频道名与 ID 的查询全部经由 `db_utils.py` 中的 `get_channel_name_from_id` 与 `get_channel_id_from_input` 完成,保证列表与下载逻辑使用同一套规范化规则。资料来源:[src/yt_fts/db_utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/db_utils.py)

---

## 更新 (update)

`update` 命令用于在已下载频道上同步新视频字幕。早期版本只更新单个频道,v0.1.57 起默认遍历全部已索引频道,从而将"增量同步"变成单命令无参的体验。资料来源:[CHANGELOG.md:0.1.57](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

v0.1.60 进一步调整了 `DownloadHandler` 的行为:对已存在频道不再直接报错退出,而是转入更新流程,避免重复 `download` 时产生冲突。新增了相关测试用例验证"重复下载"场景。资料来源:[CHANGELOG.md:0.1.60](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)

---

## 导出 (export)

`export` 命令首次随 v0.1.36 引入,用于将频道的字幕批量输出为本地文件 (v0.1.37 又额外支持了 vtt 格式)。该命令在 `ExportHandler` 中实现,可被 `yt-fts export` CLI 直接调用,也可被 `search` / `vsearch` 通过 `--export` 标志复用,把搜索结果写成 CSV 方便二次分析。资料来源:[CHANGELOG.md:0.1.36 / 0.1.37](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)、[README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)

典型用法:

```bash
# 导出整个频道字幕
yt-fts export --channel "3Blue1Brown"

# 搜索结果直接导出为 CSV
yt-fts search "life in the big city" --export
yt-fts vsearch "existing in large metropoliten center" --export
```

`--export` 标志在 `SearchHandler` 初始化时通过 `export: bool` 字段控制,文件落盘到当前工作目录。资料来源:[src/yt_fts/search.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py)

---

## 故障排除速查

| 现象 | 可能原因 | 处理方式 |
|------|----------|----------|
| `Requested format is not available` | yt-dlp 旧版本对 YouTube 新格式不识别 | 升级到 v0.1.60+ (内部 yt-dlp 2025.6.30) |
| 错把同名/相近 `@handle` 频道字幕当成目标 | URL 别名重定向 | 使用 v0.1.59+ RSS 解析;必要时附 `/videos` 后缀 |
| 重复执行 `download` 直接报错 | `DownloadHandler` 旧行为 | 升级到 v0.1.60 后,重复执行会自动进入 `update` 分支 |
| 列表中频道没有 `(ss)` 标记 | 未生成嵌入 | 执行 `yt-fts embeddings --channel <name>` |

资料来源:[CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)、社区 Issue #46、#183

---

## See Also

- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md) — 全命令速查
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md) — 版本演进与 bug fix
- 搜索与语义检索:[src/yt_fts/search.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py)

---

<a id='page-3'></a>

## 搜索功能（全文搜索与语义搜索）

### 相关页面

相关主题：[下载、列表、更新与导出](#page-2), [AI 集成：Embeddings、LLM 聊天机器人与摘要](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/yt_fts/search.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py)
- [src/yt_fts/utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/utils.py)
- [src/yt_fts/db_utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/db_utils.py)
- [src/yt_fts/llm/get_embeddings.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/get_embeddings.py)
- [src/yt_fts/llm/chatbot.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/chatbot.py)
- [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)
- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
</details>

# 搜索功能（全文搜索与语义搜索）

## 概述

`yt-fts` 提供了两种互补的字幕检索路径：**全文搜索**（基于 SQLite FTS5 的关键字匹配）与**语义搜索**（基于 ChromaDB 向量数据库的相似度检索）。两者在 `yt-fts` 项目中扮演“内容检索入口”的角色：前者用于精确查找字幕中出现的字面词句，后者用于在意思相近的语段之间做模糊匹配。两条路径都通过统一的 `SearchHandler` 类与 Click 命令 `search`、`vsearch` 对外暴露，使用户既可以快速定位一段被引用的台词，也可以基于自然语言问题在视频语料库中寻找答案。

资料来源：[src/yt_fts/search.py:1-46](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py#L1-L46)

## 全文搜索（`search` 命令）

### 搜索范围与参数

`SearchHandler` 在构造时接收四个核心参数：`scope`、`channel`、`video_id`、`limit`，用以决定检索的边界。`scope` 接受三种取值：

| 取值 | 含义 | 内部数据源 |
| --- | --- | --- |
| `all` | 在所有已下载的频道中搜索 | `search_all()` |
| `channel` | 在指定频道中搜索 | `search_channel()` |
| `video` | 在指定视频中搜索 | `search_video()` |

CLI 入口位于 `yt_fts.py` 中的 `search` 命令，使用 `-c/--channel`、`-v/--video-id`、`-l/--limit`、`-e/--export` 四个选项控制检索范围与导出行为。`--limit` 默认值为 `10`。资料来源：[src/yt_fts/yt_fts.py:1-30](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py#L1-L30)、[src/yt_fts/search.py:14-46](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/search.py#L14-L46)

### 工作流程

`full_text_search` 方法根据 `scope` 调度到 `db_utils` 中对应的查询函数，并将查询字符串以 `self.query` 保存，结果再交给后续渲染与导出逻辑。`utils.py` 中提供的 `bold_query_matches` 用于在终端中以加粗形式高亮命中片段，使阅读结果时关键词一目了然。

```mermaid
flowchart LR
    A[search 命令] --> B{Self.scope}
    B -- all --> C[search_all]
    B -- channel --> D[search_channel]
    B -- video --> E[search_video]
    C --> F[SQLite FTS5 命中]
    D --> F
    E --> F
    F --> G[终端高亮输出]
    F -.--export.-> H[CSV 导出]
```

社区曾报告一个在 `search.py:174` 附近的 Bug（Issue #189），错误地在字典 key 中遗漏了 `video_id`，导致按视频去重后只返回一行结果。该问题已在新版本中修复。资料来源：[CHANGELOG.md:1-60](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md#L1-L60)

## 语义搜索（`vsearch` 命令）

### 前置条件：Embeddings

`vsearch` 依赖 ChromaDB 中预先计算的向量索引，使用前必须对目标频道执行 `yt-fts embeddings --channel <name>`。`EmbeddingsHandler.add_embeddings_to_chroma` 会按 `interval`（默认 30 秒）将每段字幕切片，并把视频元数据（频道名、标题、发布日期、开始/结束时间）一同写入文本，再通过 OpenAI 或 Gemini 的 embedding 模型生成向量，存入 ChromaDB。资料来源：[src/yt_fts/llm/get_embeddings.py:1-60](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/get_embeddings.py#L1-L60)、[README.md:1-60](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md#L1-L60)

### 检索与上下文增强

`SearchHandler` 接受可选的 `openai_client` 参数；当使用语义搜索时，会先调用 embedding 接口将用户查询向量化，再从 ChromaDB 中拉取最相似的若干段字幕作为上下文。`llm/chatbot.py` 中的 `LLMHandler` 进一步复用此能力：它在对话首轮用相似度检索为问题构建上下文，若模型回答以 `i don't know` 开头，会调用 `get_expand_context_query` 让 LLM 改写查询词，再次执行向量检索以扩展上下文，从而提升回答质量。资料来源：[src/yt_fts/llm/chatbot.py:1-90](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/chatbot.py#L1-L90)

## 已知问题与社区反馈

社区中围绕搜索功能集中出现过几类诉求与故障：

- **Issue #189**：搜索结果在某些情况下“每个视频仅返回一条引用”，根因在 `search.py` 的去重 key 缺失字段。
- **Issue #47**：希望在 `search` 与 `vsearch` 中支持对视频标题使用正则，以仅检索频道中的一部分视频（例如播客合集）。该特性目前尚未在源码中实现，需要通过 `vsearch` 的 `channel` + 多次查询、或在外层脚本中预先过滤来模拟。
- **Issue #60**：用户希望将 `search` 命中的引用一键导出为音视频片段（`yt-dl` + `ffmpeg` 截取）。该功能不在 `yt-fts` 当前实现范围内，但 `--export` 标志已支持将字幕结果落盘为 CSV，方便下游脚本处理。

资料来源：[CHANGELOG.md:1-80](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md#L1-L80)

## See Also

- [yt-fts 项目主页与命令一览](https://github.com/NotJoeMartinez/yt-fts)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
- [src/yt_fts/llm/chatbot.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/chatbot.py)
- [src/yt_fts/llm/get_embeddings.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/get_embeddings.py)

---

<a id='page-4'></a>

## AI 集成：Embeddings、LLM 聊天机器人与摘要

### 相关页面

相关主题：[搜索功能（全文搜索与语义搜索）](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/yt_fts/llm/chatbot.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/chatbot.py)
- [src/yt_fts/llm/get_embeddings.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/get_embeddings.py)
- [src/yt_fts/llm/summarize.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/llm/summarize.py)
- [src/yt_fts/utils.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/utils.py)
- [src/yt_fts/yt_fts.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/yt_fts.py)
- [src/yt_fts/config.py](https://github.com/NotJoeMartinez/yt-fts/blob/main/src/yt_fts/config.py)
- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
</details>

# AI 集成：Embeddings、LLM 聊天机器人与摘要

## 概览

yt-fts 在本地 SQLite 全文检索的基础上，提供了一层 AI 能力，覆盖"向量化、问答、摘要"三件事。这三项功能共享同一套模型配置和凭据解析逻辑，分别对应 CLI 中的 `embeddings`、`vsearch`、`llm` 与 `summarize` 四个子命令（资料来源：[README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md:1-30)）。

- **`embeddings`**：把字幕切片并调用嵌入模型，结果写入 ChromaDB。
- **`vsearch`**：在 ChromaDB 中按相似度检索字幕段落。
- **`llm`**：以向量检索结果作为上下文，驱动多轮对话式问答。
- **`summarize`**：对单条视频字幕生成带时间戳链接的总结。

下图展示从字幕到 AI 回答的整体数据流：

```mermaid
flowchart LR
    A[下载字幕<br/>download] --> B[SQLite 全文索引]
    A --> C[EmbeddingsHandler<br/>按 interval 切分]
    C --> D[OpenAI / Gemini<br/>Embedding API]
    D --> E[ChromaDB Collection]
    E --> F[vsearch<br/>相似度检索]
    E --> G[llm<br/>RAG 多轮对话]
    A --> H[SummarizeHandler<br/>单视频摘要]
    H --> I[OpenAI / Gemini<br/>Chat Completion]
    H --> J[带时间戳的总结文本]
```

## 模型配置与凭据解析

所有 AI 命令入口都通过 `get_model_config` 解析模型与 API Key（资料来源：[src/yt_fts/utils.py:1-40]()）。该函数内部维护两个模型档案：

| 名称 | Embedding 模型 | Chat 模型 | base_url | API Key 前缀 |
|------|---------------|-----------|----------|--------------|
| `OPENAI` | `text-embedding-ada-002` | `gpt-4o` | `https://api.openai.com/v1` | `sk-` |
| `GEMINI` | `text-embedding-004` | `gemini-2.5-flash` | `https://generativelanguage.googleapis.com/v1beta` | `AIza` |

Key 的解析顺序为：(1) 显式传入参数时按前缀判断；(2) 否则回退到 `OPENAI_API_KEY` / `GEMINI_API_KEY` 环境变量；(3) 都没有则抛 `ValueError("No model configuration found...")`（资料来源：[src/yt_fts/utils.py:1-40]()）。

这套设计使得四个命令可以使用统一的 `--api-key` 参数；CLI 中 `get_model_config(api_key)` 返回的字典会直接传给后续 handler 用于构造 `OpenAI` 客户端（资料来源：[src/yt_fts/llm/chatbot.py:27-35]()、[src/yt_fts/llm/summarize.py:17-25]()）。

## Embeddings 与 ChromaDB 写入

`EmbeddingsHandler.add_embeddings_to_chroma` 负责把某个 channel 的全部字幕生成嵌入并存入 Chroma（资料来源：[src/yt_fts/llm/get_embeddings.py:19-55]()）。主要流程：

1. 通过 `get_vid_ids_by_channel_id` 拉取该 channel 下所有视频 ID；
2. 对每条视频调用 `split_subtitles`，按 `--interval`（默认 30 秒，可通过 `embeddings -i` 调整）切分字幕；
3. 用 `add_meta_data_to_text` 把频道名、标题、日期拼接到文本，提升检索相关性；
4. 过滤空段落后统一送入 `get_model_config` 指定的 embedding 模型；
5. 写入 Chroma collection（路径由 `get_or_make_chroma_path()` 提供，资料来源：[src/yt_fts/yt_fts.py:1-30]()）。

`vsearch` 命令复用同一 Chroma 客户端，将查询文本嵌入后按余弦相似度排序，默认返回前 10 条（资料来源：[README.md:1-30]()）。channel 在生成 embeddings 后，list 时会在名称后追加 `(ss)` 标记，提示该 channel 可被向量检索。

## LLM 聊天机器人 (RAG)

`LLMHandler` 实现 `llm` 命令背后的多轮对话（资料来源：[src/yt_fts/llm/chatbot.py:27-80]()）。`init_llm` 接收初始 prompt 后做三件事：

1. 调用 `start_llm`，使用 system prompt 指示模型"根据用户问题生成一个适合向量检索的查询串"；
2. 把生成的查询送入 Chroma 检索上下文；
3. 用 `format_context` 把检索到的 `video_title / date_posted / link / subs` 拼成一段上下文，喂给 chat 模型得到首条回答。

随后进入 REPL 循环：每次用户输入追加到 `messages`，调用 `continue_llm` 重新生成向量查询并刷新上下文（资料来源：[src/yt_fts/llm/chatbot.py:50-80]()）。`get_completion` 调用 `chat.completions.create`，`temperature=0.5`、`max_tokens=2000`，并对非 OpenAI 模型传 `NotGiven()` 跳过 `stop` 等不兼容字段（资料来源：[src/yt_fts/llm/chatbot.py:65-80]()）。

CLI 入口要求必须传 `-c/--channel` 并给出问题文本（资料来源：[README.md:1-30]()）。channel 必须先执行过 `embeddings`，否则 Chroma 中无数据可用。

## 视频摘要

`SummarizeHandler` 是 `summarize` 命令的核心（资料来源：[src/yt_fts/llm/summarize.py:17-50]()）。其特色在于：

- 输入既支持完整 URL（含 `https`）也支持裸 video ID，由 `get_video_id_from_url` 解析；
- 若 `video_in_database(video_id)` 返回 True，直接从 SQLite 读取字幕并用 `video_title` / `channel_name` 渲染 prompt，避免重复抓取；
- 否则调用 `download_transcript()` 用 yt-dlp 临时下载 VTT 字幕；
- `summarize_video` 的 system prompt 明确要求"以 `[timestamp](https://youtu.be/{video_id}?t=...)` 形式给出关键时间戳链接"，因此输出天然包含可点击定位（资料来源：[README.md:1-30]()、[src/yt_fts/llm/summarize.py:35-50]()）。

`--model` 选项允许用户覆盖默认 `chat_model`，但底层仍走同一个 `OpenAI` 客户端，只是改 `model` 字段（资料来源：[src/yt_fts/yt_fts.py:1-30]()）。

## 常见失败模式

- **未生成 embeddings 就跑 `vsearch` 或 `llm`**：Chroma collection 为空，检索不到任何上下文。须先 `yt-fts embeddings --channel "<name>"`（资料来源：[README.md:1-30]()）。
- **API Key 未配置**：`get_model_config` 会抛 `ValueError`。`OPENAI_API_KEY` 与 `GEMINI_API_KEY` 是唯二被识别的环境变量（资料来源：[src/yt_fts/utils.py:1-40]()）。
- **下载时 "Requested format is not available"**：属于 yt-dlp 与频道默认格式不匹配，与 AI 子系统无关，但 v0.1.60 之后通过 `--jobs` 与 User-Agent 随机化已大幅缓解（资料来源：[CHANGELOG.md:1-20]()、社区 Issue #183）。
- **速率限制**：可使用 `--cookies-from-browser` 让 yt-dlp 携带登录态 cookie，缓解抓取字幕时的 429（资料来源：[CHANGELOG.md:1-20]()）。

## See Also

- [README.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/README.md)
- [CHANGELOG.md](https://github.com/NotJoeMartinez/yt-fts/blob/main/CHANGELOG.md)
- `config`：通过 `yt-fts config` 查看数据库与 Chroma 路径（资料来源：[src/yt_fts/yt_fts.py:1-30]()）
- 社区 Issue #189：已知 `search.py` 在旧版中仅返回单条引用，AI 子系统不受该 bug 影响

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：NotJoeMartinez/yt-fts

摘要：发现 15 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 来源证据：Crash due to unicode decode error while getting video title from vtt。

## 1. 安装坑 · 来源证据：Crash due to unicode decode error while getting video title from vtt

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Crash due to unicode decode error while getting video title from vtt
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/138 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 2. 安装坑 · 来源证据：Help installing

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Help installing
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/180 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 3. 安装坑 · 来源证据：Requested Format Not Available

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Requested Format Not Available
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/183 | 来源类型 github_issue 暴露的待验证使用条件。

## 4. 安装坑 · 来源证据：yt-dlp update required

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：yt-dlp update required
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/192 | 来源类型 github_issue 暴露的待验证使用条件。

## 5. 配置坑 · 来源证据：AttributeError: 'NoneType' object has no attribute 'string'

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个配置相关的待验证问题：AttributeError: 'NoneType' object has no attribute 'string'
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/184 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 6. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/NotJoeMartinez/yt-fts | README/documentation is current enough for a first validation pass.

## 7. 运行坑 · 来源证据：I got messge to sign in

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：I got messge to sign in
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/182 | 来源类型 github_issue 暴露的待验证使用条件。

## 8. 运行坑 · 来源证据：Search results show only one quote per video

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Search results show only one quote per video
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/189 | 来源类型 github_issue 暴露的待验证使用条件。

## 9. 维护坑 · 来源证据：'NoneType' object has no attribute 'decode'

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题：'NoneType' object has no attribute 'decode'
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/181 | 来源讨论提到 windows 相关条件，需在安装/试用前复核。

## 10. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/NotJoeMartinez/yt-fts | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/NotJoeMartinez/yt-fts | no_demo; severity=medium

## 12. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/NotJoeMartinez/yt-fts | no_demo; severity=medium

## 13. 安全/权限坑 · 来源证据：User Agent Randomization, Proxies and Youtube API

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：User Agent Randomization, Proxies and Youtube API
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/NotJoeMartinez/yt-fts/issues/168 | 来源类型 github_issue 暴露的待验证使用条件。

## 14. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/NotJoeMartinez/yt-fts | issue_or_pr_quality=unknown

## 15. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/NotJoeMartinez/yt-fts | release_recency=unknown

<!-- canonical_name: NotJoeMartinez/yt-fts; human_manual_source: deepwiki_human_wiki -->
