Aureum01/streamscribe
GitHub: Aureum01/streamscribe
一款纯本地 CPU 运行的实时新闻直播流转录与分析工具,支持多流监控、磁盘缓存和本地 AI 查询,全程不依赖云服务。
Stars: 2 | Forks: 0
# streamscribe
在普通 CPU 上进行实时广播转录与分析,完全依赖本地 AI,无云服务依赖。
streamscribe 可以同时转录多个实时新闻流,将每个片段缓存到磁盘,并允许你使用自己的本地模型查询结果。音频永远不会离开你的设备。它专为记者、OSINT 从业者、研究人员和分析师而设计,满足他们在无需将任何数据发送至第三方 API 的情况下监控广播媒体的需求。
```
YouTube live streams ---> capture engine ---> accurate captions
(any count) (faster-whisper, |
CPU-only) +--> quad monitor UI
+--> session cache (disk)
+--> local AI analyst (Ollama)
+--> MCP server (agents)
```
## 为什么会有这个项目
大多数转录工具在近实时传输片段时会破坏句子的完整性,或者需要 GPU 或云 API 的支持。streamscribe 做出了不同的取舍。字幕会比实时播放滞后固定的约 10 秒,但每一段都是包含完整上下文、一次转录完成的完整段落。所有内容都会被持久化存储到一个结构化缓存中,可供本地 LLM 或任何 MCP 客户端查询。仅限 CPU 的限制是刻意为之:目标用户使用的是普通笔记本电脑,而不是 GPU 阵列。
## 功能
- **捕获与处理引擎。** 录制完整的音频窗口,在自然停顿处进行切分,结合完整上下文对每个窗口进行一次转录,并自动对拼接处进行去重。不会出现半个单词的碎片。
- **多流监控。** 每个流使用一个引擎进程,支持任意数量的订阅源,提供可同时显示最多六个面板的 CCTV 风格 UI。上方为静音视频,下方为实时转录文本。
- **会话缓存。** 每个已确认的片段都会作为机器可读的 JSONL 和纯文本格式存入 `cache///`,并按写入实时刷新。
- **本地 AI 分析师。** 侧边栏可汇总选定订阅源的近期转录内容,并将问题发送给你自己的 Ollama 模型。
- **MCP 服务器。** 将缓存(`list_feeds`、`get_recent_transcript`、`search_transcript`、`get_session_info`)暴露给 ollmcp、Claude Desktop、LangChain 或任何其他使用 Model Context Protocol 的客户端。
- **专为长时间无人值守运行而构建。** 具备退避机制的自动重连、实时摄取节奏控制、幻觉防护、广告时段空闲模式、WebSocket 保活,以及可选的音频快照自动清理。
- **支持本地视频。** 将订阅源指向任何 YouTube URL。VOD 将以正常速度通过处理流水线播放。
## 快速开始
环境要求:Python 3.10+,PATH 中需包含 [ffmpeg](https://ffmpeg.org),分析师功能可选安装 [Ollama](https://ollama.com)。
```
git clone https://github.com/Aureum01/streamscribe.git && cd streamscribe
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt
python quad.py
```
该单一命令会为 `feeds.json` 中的每个条目启动一个转录引擎(首次运行时会生成一个初始配置文件),在 `http://localhost:8080/ui/quad.html` 提供监控 UI 服务,并自动在浏览器中打开。
如需使用 AI 分析师,请在另一个终端中运行:
```
ollama serve
ollama pull llama3.2:3b # once; a good CPU-sized analyst model
```
## 准确度阶梯
streamscribe 默认配置针对普通硬件进行了优化。每一层都有文档记录的升级路径。以下是升级收益从高到低的顺序。
### 1. Whisper 模型(影响最大的单一因素)
默认的 `tiny.en` 可以在普通 CPU 上同时运行四个订阅源。每提升一个级别,对名称、数字和口音的识别能力都会增强,而这些通常是分析工作中最关键的细节。
| 模型 | 参数量 | 每个订阅源内存占用 | 相对速度 | 适用场景 |
|---|---|---|---|---|
| `tiny.en` | 39M | ~0.5 GB | 1.0x | 普通 CPU 上运行 4 个及以上订阅源 |
| `base.en` | 74M | ~0.7 GB | ~0.6x | 推荐的首选升级方案 |
| `distil-small.en` | 166M | ~1.0 GB | ~0.5x | CPU 周期利用率最佳的质量 |
| `small.en` | 244M | ~1.5 GB | ~0.25x | 接近广播级质量,支持 1-2 个订阅源 |
| `large-v2` | 1.5B | ~4 GB+ | 建议使用 GPU | 多语言及翻译 |
```
python quad.py --model base.en # every feed
```
或者也可以在 `feeds.json` 中(或 UI 的配置抽屉中)为每个订阅源单独设置,这样就可以让一个高优先级的订阅源运行比其他订阅源更大的模型:
```
{ "feed_id": "bloomberg", "url": "...", "port": 8765, "model": "distil-small.en" }
```
### 2. 捕获窗口
更长的窗口能为模型在每次处理时提供更多的句子上下文,但也会导致相应程度的延迟增加。使用 `--window 8`(默认值)大约会比实时延迟 10 秒。在密集语音场景下,`--window 12` 的阅读体验会有显著提升。
### 3. 分析师模型
支持任何 Ollama 模型。在 CPU 上,`llama3.2:3b` 和 `qwen3:4b` 可以在一分钟内给出回答。8B 模型更智能,但每个问题需要几分钟时间。如果有 GPU,70B 级别的模型可以直接接入,其他设置无需任何更改。
### 4. 路线图
丰富化处理器(基于缓存的 NER、声明提取、监视列表警报)、会话配置文件构建器(每个订阅源的运行叙述上下文)、跨订阅源分歧检测、多语言 large-v2 翻译以及直接广播站点音频提取器。缓存 schema 是所有这些功能赖以构建的稳定接口。
## 监控 UI
- **订阅源列(左侧)。** 显示所有已配置的订阅源,采用 CCTV 风格,并带有实时状态指示点。点击订阅源可将其显示在屏幕上;当已显示六个面板时,最早加载的会被替换。下载图标可获取该订阅源的纯文本或 JSONL 格式的转录内容。
- **面板。** 上方为静音的 YouTube 嵌入视频(仅供人工监视;转录音频直接来源于流),下方为实时转录文本,支持自动滚动及滚动时暂停。
- **配置订阅源。** 添加、删除或编辑订阅源、端口和每个订阅源专属的模型。保存后立即生效:面板会立即切换到新视频,并且只有流、端口或模型发生更改的引擎才会重启。无需重启脚本,无需编辑文件。
- **AI 分析师。** 选择一个 Ollama 模型,选定订阅源和回溯窗口,然后进行提问。回答基于缓存的转录内容生成,并格式化为带有订阅源和时间戳引用的结构化纯文本。
- **清除会话。** 每日结束时的重置操作。删除整个缓存,并以全新的会话重启每个引擎。请先下载并保留你需要的内容。
## 会话缓存
```
cache/
└── bloomberg/
└── 20260611-134941/
├── meta.json # stream URL, model, language; written once
├── session.json # live counters, rewritten as the session runs
├── segments.jsonl # one JSON record per confirmed segment
└── chunks.txt # plain-text transcript, one segment per line
```
每条 `segments.jsonl` 记录都包含 ISO 时间戳、实际时间、流偏移量、订阅源 ID 和文本。这是任何分析层的原始素材。`--keep-audio-minutes 30` 会在转录文本旁额外保存每次捕获的音频作为 WAV 快照,并自动删除超过保留期限的旧快照。
## MCP 服务器
`mcp_server.py` 是一个零依赖的 stdio MCP 服务器,可将会话缓存暴露给任何 MCP 客户端。它提供四个工具:
| 工具 | 参数 | 返回内容 |
|---|---|---|
| `list_feeds` | 无 | 所有包含已缓存会话的订阅源 |
| `get_recent_transcript` | `feed_id`, `minutes` | 最近 N 分钟内带时间戳的片段 |
| `search_transcript` | `query`, `feed_id?`, `minutes?` | 跨订阅源匹配关键词的片段 |
| `get_session_info` | `feed_id` | 最新会话的元数据和计数器 |
如果缓存存储在 `./cache` 以外的位置,请设置 `STREAMSCRIBE_CACHE`。
根据你的具体环境,有以下三种使用方式。
### 选项 1:Claude Desktop(最简单)
在 Windows 上将此内容添加到 `%APPDATA%\Claude\claude_desktop_config.json`。如果你使用的是 WSL,请像启动任何其他基于 WSL 的 MCP 服务器一样使用 `wsl.exe` 来启动它:
```
{
"mcpServers": {
"streamscribe": {
"command": "wsl.exe",
"args": [
"bash", "-ic",
"/mnt/c/path/to/streamscribe/.venv/bin/python /mnt/c/path/to/streamscribe/mcp_server.py"
],
"env": {
"STREAMSCRIBE_CACHE": "/mnt/c/path/to/streamscribe/cache"
}
}
}
}
```
保存后完全退出并重启 Claude Desktop。聊天输入框中会出现一个锤子图标,确认工具已成功加载。请确保 `quad.py` 已经提前运行,这样缓存中才有可供查询的内容。
### 选项 2:ollmcp 终端客户端(完全本地,无云服务)
这会运行一个终端聊天会话,在此会话中,本地 Ollama 模型会直接调用 streamscribe 工具。不会向任何外部服务发送任何数据。
安装客户端:
```
pip install mcp-client-for-ollama
```
在 Windows 上,Ollama 必须监听所有网络接口,以便 WSL 能够访问它。从系统托盘停止 Ollama,然后执行:
```
$env:OLLAMA_HOST = "0.0.0.0:11434"
ollama serve
```
若要在重启后永久保留此设置:
```
[System.Environment]::SetEnvironmentVariable("OLLAMA_HOST", "0.0.0.0:11434", "User")
```
在 WSL 中查找 Windows 主机的 IP:
```
ip route | grep default | awk '{print $3}'
```
然后启动客户端,指向该 IP:
```
ollmcp -s mcp_server.py -m qwen3:8b -H http://:11434
```
当它启动时,请禁用思考模式,以便模型直接触发工具调用,而不仅仅是对其进行推理:
```
/thinking-mode
```
然后在第一次要求确认工具调用时输入 `s`,以允许该会话中的所有工具调用。查询示例:
```
What feeds does streamscribe have cached?
Get me the last 30 minutes from bloomberg.
Search for "iran" across all feeds from the last hour.
```
适合用于工具调用的模型包括:`qwen3:8b`、`qwen3:14b`、`mistral:latest`、`qwen2.5:3b`。参数量小于 7B 的模型有时无法可靠地生成工具调用。
### 选项 3:mcpo REST 桥接
mcpo 将 stdio MCP 服务器封装为 REST API,这使得任何 HTTP 客户端(包括脚本、curl 和 Invoke-WebRequest)都可以查询缓存。
```
pip install mcpo
mcpo --port 8200 -- python mcp_server.py
```
然后直接调用工具:
```
Invoke-WebRequest -Uri "http://localhost:8200/list_feeds" -Method POST -ContentType "application/json" -Body "{}" -UseBasicParsing
Invoke-WebRequest -Uri "http://localhost:8200/get_recent_transcript" -Method POST -ContentType "application/json" -Body '{"feed_id":"bloomberg","minutes":30}' -UseBasicParsing
```
自动生成的 API 文档位于 `http://localhost:8200/docs`。
## 控制 API
UI 的所有操作都是通过同一端口上的标准 HTTP 请求实现的。
| Endpoint | Method | 用途 |
|---|---|---|
| `/api/feeds` | GET | 订阅源和引擎状态 |
| `/api/feeds` | POST | 替换订阅源;仅重启发生变更的部分 |
| `/api/restart` | POST | 重启单个引擎(`{"feed_id": "..."}`) |
| `/api/transcript` | GET | 最近的片段(`?feed_id=&minutes=`) |
| `/api/download` | GET | 转录文件(`?feed_id=&format=txt\|jsonl`) |
| `/api/models` | GET | 已安装的 Ollama 模型 |
| `/api/analyze` | POST | 基于事实的问题,返回结构化的纯文本回答 |
| `/api/cache/clear` | POST | 清空缓存,重新启动全新的引擎 |
## 单一订阅源 CLI
`pipeline.py` 可以脱离管理服务独立运行:
```
python pipeline.py --url "https://www.youtube.com/watch?v=..." \
--mode transcribe --model base.en --language en \
--feed-id myfeed --reconnect
```
重要参数:`--window N`(捕获窗口秒数)、`--engine stream`(旧版低延迟滚动缓冲区)、`--serve --port N`(WebSocket 输出)、`--keep-audio-minutes N`、`--no-cache`、`--mode captions`(在可用时使用 YouTube 自动字幕,CPU 消耗为零)、`--debug`。
## 配置参考
| 设置 | 位置 | 默认值 | 备注 |
|---|---|---|---|
| 订阅源、端口、每个订阅源的模型 | `feeds.json` / UI | 4 个初始订阅源 | 引擎在变更时进行差异化重启 |
| whisper 模型 | `--model` / 单个订阅源 | `tiny.en` | 参见准确度阶梯 |
| 捕获窗口 | `--window` | 8 s | 准确度更高,延迟更大 |
| UI 端口 | `--ui-port` | 8080 | |
| Ollama 主机 | `OLLAMA_HOST` 环境变量 | `http://localhost:11434` | |
| 分析师超时时间 | `STREAMSCRIBE_OLLAMA_TIMEOUT` 环境变量 | 600 s | CPU 模型处理较慢 |
| 缓存根目录 | `--cache-dir` | `cache/` | 由引擎、API、MCP 共享 |
## 故障排除
**视频面板显示“Error 153”。** 页面必须通过 HTTP 提供服务。YouTube 嵌入内容需要 referrer,而 `file://` 页面无法发送。请使用 quad.py 打印出的 URL,而不是文件路径。
**“inference behind capture”警告。** CPU 的转录速度跟不上订阅源传输音频的速度。请使用更小的 `--model`、更大的 `--window`,或者减少订阅源数量。
**分析师超时。** 第一次提问时会将模型加载到内存中(之后会保持加载状态 30 分钟)。请重新提问、选择更小的模型,或者缩短回溯窗口。上下文上限约为 12k 个,并使用 8k token 的上下文窗口发送,因此不会有内容被静默截断。
**连续几分钟没有字幕。** 可能是插播了广告或音乐垫音。引擎会刻意以接近零的 CPU 消耗跳过非语音片段,并在检测到语音恢复后的一个数据块内继续工作。
## 测试
```
python -m pytest tests -q
```
该套件涵盖了对捕获引擎(窗口几何结构、静音点切分、拼接去重、幻觉防护、快照清理)、旧版流引擎、去重逻辑、缓存层的测试,以及一个 90 秒的脚本化广播模拟(要求在有限的缓冲区下一字不差地还原其播放脚本)。
## 架构说明
每个订阅源使用一个独立的 OS 进程(一个引擎就是一个 `pipeline.py` 实例),各自拥有独立的 WebSocket 服务器和缓存会话。订阅源之间互不干扰,并且彼此独立崩溃。`quad.py` 充当监督者:它生成引擎,通过单一端口提供 UI 和控制 API 服务,并将分析师请求代理给 Ollama,因此浏览器不需要配置 CORS 例外。捕获引擎会根据实际时间协调摄取节奏(YouTube 直播流会提供长达数小时的 DVR 窗口,如果不加限制,这些数据会以最大下载速度涌入),并且最多在运行队列中保留四个已完成的窗口,当超出限制时,它会丢弃最旧的窗口并发出警告,而不是无限制地占用内存。
## 许可协议与贡献
基于 [Apache 2.0 License](LICENSE) 发布。
尊重仅限 CPU 基准环境的贡献是最有价值的。每一项功能都必须确保能在笔记本电脑上优雅降级。如果你添加了 GPU 加速、多语言支持或更庞大的模型,请清楚地记录下 CPU 的兜底方案,以便让没有专用硬件的分析师依然能够正常使用该工具。
标签:AI风险缓解, ESC4, LLM评估, Ollama, OSINT, Whisper, 人工智能, 实时流媒体, 时序数据库, 本地部署, 用户模式Hook绕过, 逆向工具, 音频转录