用 Tauri + React 做了一个「AI 课件助手」:让 ai开口讲课
打开任何一份课件 PDF,左边原版,右边 AI 逐页讲解。不懂随时问,还能翻遍整份材料找答案。全部本地运行,使用自己的API Key(比如deepseek api,很便宜的!)。
为什么做这个?
考试周抱佛脚,老师丢来一份 50 页的 PDF 课件。翻了两页,困了。
突然想:能不能让 AI 帮我看课件?不是那种「总结全文」的一锤子买卖,而是一页一页讲给我听------就像有个学霸坐旁边,翻到哪讲到哪,不懂还能追问。
于是就有了 Slide AI。
长什么样?
打开 PDF 后,界面分成三块:
┌──────────┬──────────────────────────┐
│ │ 左侧:原课件 │ 右侧:AI 讲解
│ 缩略图 │ (PDF 页面渲染图) │ (Markdown + 公式)
│ 导航栏 │ │
│ │ │
│ [第1页] ├──────────────────────────┤
│ [第2页] │ 底部:对话框 │
│ [第3页] │ 🗨 问当前页 / 问整份课件 │
│ ... │ │
└──────────┴──────────────────────────┘
- 缩略图栏:点击跳转任意页,绿色圆点 = 已生成讲解
- 主区域:左右可拖拽分栏,上方课件 + AI 讲解,下方对话框
- 设置页:自由切换 OpenAI / Anthropic / Gemini / 自定义端点
效果就是:打开课件 → 自动翻到第一页 → AI 开始用 Markdown 写讲解(公式用 KaTeX 渲染,表格、列表、加粗全支持)→ 翻页自动讲下一页 → 不懂就在下面问。
怎么做到的?
技术选型:Tauri 2.x,比 Electron 轻 10 倍
| 层 | 选型 | 为什么 |
|---|---|---|
| 桌面壳 | Tauri 2.x + Rust | 打包体积 ~15MB,Electron 动辄 150MB+ |
| 前端 | React 19 + TypeScript + Vite | 开发体验丝滑,HMR 秒级 |
| 样式 | Tailwind CSS 4 | 不用写 CSS 文件 |
| 状态管理 | Zustand | 比 Redux 轻 100 倍,API 直觉 |
| Markdown | react-markdown + KaTeX | 公式、表格完美渲染 |
| PDF.js | 纯前端解析,不依赖外部程序 |
为什么不用 Electron? 因为 Tauri 用系统自带的 WebView2(Windows 11 内置),不打包 Chromium。一个 Hello World 的 Electron 打包出来 150MB,Tauri 只要 3MB。Slide AI 完整打包 15MB,其中还有 10MB 是前端 JS bundle。
核心流程
选文件 → Rust 读文件字节 → 前端 PDF.js 解析
→ Canvas 逐页渲染为 data URL
→ 提取文字 → 带图片+文字调用 LLM
→ SSE 流式返回 Markdown → 实时渲染
文档解析:PDF.js 纯前端方案
最初设计是 Python sidecar(PyMuPDF),但实际落地发现:
- 打包 Python 成 exe 增加 100MB+
- Tauri 2 的文件协议权限很严格,本地图片加载折腾了两天
最终方案:全部前端搞定。
typescript
// 核心就这几行
const pdf = await pdfjsLib.getDocument({ data: pdfBytes }).promise;
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale: 2.0 });
const canvas = document.createElement('canvas');
// ... render to canvas
const dataUrl = canvas.toDataURL('image/png'); // ← 直接存内存
}
不写磁盘,不经过文件系统,纯 data: URL 在 WebView 里显示。完美避开 Tauri 的 asset 协议权限地狱。
LLM 网关:一套代码通吃四个 Provider
用户可能用 OpenAI、Anthropic、Gemini,或者自己搭的兼容 API。做了一套统一网关:
typescript
const builders = {
openai: buildOpenAIRequest, // /v1/chat/completions
anthropic: buildAnthropicRequest, // /v1/messages (格式不同)
gemini: buildGeminiRequest, // streamGenerateContent (格式完全不同)
custom: buildOpenAIRequest, // 兼容 OpenAI 协议的自建服务
};
三种完全不同的 SSE 流格式(OpenAI 的 choices[0].delta.content,Anthropic 的 content_block_delta,Gemini 的 candidates[0].content.parts[0].text),统一解析成 onChunk 回调。
而且 API Key 直连用户提供的端点,不经过任何中间服务器。 你的 Key 你做主。
流式讲解 + 预生成队列
翻到一页时:
- 带上前一页的摘要作为上下文(防止 AI 断片)
- 把页面图片 + 文字作为多模态输入发给 LLM
- SSE 流式展示,Markdown 实时渲染
- 同时后台启动预生成队列:自动为接下来 N 页预生成讲解
typescript
// 翻页后自动预生成后续页面
if (settings.preGenerateAhead > 0) {
triggerPreGenerate(currentPage + 1, settings.preGenerateAhead);
}
翻页体验丝滑,不用等。
RAG 全文档问答
对话框有两种模式:
-
当前页:带当前页上下文 + 历史对话
-
全文档:把问题向量化,从整份课件检索最相关的 4 页,拼成上下文喂给 LLM
用户问:"第三章讲了什么?"
→ 向量检索 → 找到第 12,13,14,15 页
→ 拼接页面文字 → LLM 回答
向量模型用的是 paraphrase-multilingual-MiniLM-L12-v2(Sentence-Transformers),384 维,中英文都支持。
踩过的坑
1. Tauri 图标:icon.ico 必须存在
Tauri 2 在 Windows 上构建需要 icons/icon.ico,否则 tauri-build 直接报错退
出。解决方法:用 Canvas 画一个 256×256 的 PNG,然后 npx tauri icon 一键生成全
平台图标。
2. 插件权限:dialog 不配 capabilities 就崩
加了 tauri-plugin-dialog 后应用秒崩,查了半天发现 Tauri 2 的插件权限不再是
tauri.conf.json 里配,而是需要 capabilities/default.json:
json
{
"permissions": [
"core:default",
"dialog:allow-open",
"dialog:allow-save"
]
}
缺一个权限 = 直接崩溃,无报错提示。排查全靠二分法注释代码。
3. Manager trait 必须显式 import
Rust 里 app.path() 方法来自 tauri::Manager trait。忘了 use tauri::Manager;
的话,编译器提示 no method named 'path' found。Rust 的 trait 孤儿规则------方法存在
但不 import 就不能用。
4. 文件协议 vs data URL
Tauri 2 用 asset:// 协议加载本地文件有三种不同的 URL 格式(asset://localhost、
https://asset.localhost、tauri://localhost),不同版本行为不一致。最后干脆不用
文件系统------全部 canvas.toDataURL() 转 base64 放内存。虽然多占点内存,但一份 30
页的课件也就几十 MB,完全可接受。
5. window.__TAURI_INTERNALS__ 不等于 window.__TAURI__
Tauri 2 改了全局变量名,很多教程和旧代码用的是 window.__TAURI__,新版本是
window.__TAURI_INTERNALS__。API 导入方式也从 @tauri-apps/api/tauri 变成了
@tauri-apps/api/core。
架构一览
slide-ai/
├── src/ # React 前端
│ ├── components/layout/ # 主布局+面板
│ ├── components/settings/# 设置页
│ ├── components/chat/ # 聊天组件
│ ├── components/viewer/ # 图片查看器
│ ├── services/ # LLM网关/RAG/文档加载
│ ├── stores/ # Zustand状态管理
│ └── types/ # 类型定义
├── src-tauri/ # Tauri/Rust后端
│ ├── src/commands/ # Rust命令
│ ├── sidecar/ # Python文档处理器
│ └── capabilities/ # 插件权限
└── package.json
怎么用?
bash
git clone https://github.com/your/slide-ai
cd slide-ai
npm install
npm run tauri:dev # 开发模式
npm run tauri:build # 打包 exe(15MB)
打开后:
- 设置页填 API Key
- 打开 PDF 课件
- 翻页看讲解,不懂直接问
支持的 LLM:OpenAI、Anthropic Claude、Google Gemini、任意 OpenAI 兼容端点。
接下来
- PPT 原生支持(目前需先导出 PDF)
- 本地 RAG 向量检索(目前用关键词回退)
- 多文档对比模式
- 导出讲解笔记
写于 2026 年 6 月。代码在 github仓库Slide AI:Slide AI 。欢迎 Star。