完整实现 Tauri + Vanilla JS 轻量级截图工具 Phase 1 - 项目搭建 - Tauri 2.x 项目初始化 - Vite 前端项目搭建 - 基础 UI 框架(CSS 变量、组件库) - 构建配置优化 Phase 2 - 核心截图功能 - 全屏/区域/窗口截图 - 截图预览和管理 - 文件命名和缩略图 - 全局快捷键集成 Phase 3 - 上传与存储 - 多图床上传(GitHub/Imgur/自定义) - 配置管理系统 - SQLite 数据库 Phase 4 - OCR 集成 - 云端 OCR(百度/腾讯云) - 插件管理系统 - 本地 OCR 插件(Go) - OCR 结果处理 Phase 5 - AI 分类系统 - Claude/OpenAI API 集成 - Prompt 模板引擎 - 模板管理界面 - 自动分类流程 Phase 6 - 历史记录与管理 - 图库视图(网格/列表) - 搜索与筛选 - 批量操作 - 导出功能(JSON/CSV/ZIP) Phase 7 - 打包与发布 - 多平台构建配置 - CI/CD 工作流 - 图标和资源 - 安装包配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
15 KiB
15 KiB
CutThenThink v3.0 - 轻量级语言重构设计
项目背景
当前 Python + PyQt6 方案存在的问题:
- 打包体积大(~214MB)
- 启动速度慢
- 依赖 PyQt6 大型框架
- 用户需要安装 Python 环境
新技术栈选择
方案对比
| 方案 | 语言 | 框架 | 包体积 | 跨平台 | 开发效率 | 热更新 |
|---|---|---|---|---|---|---|
| Tauri | Rust + Web 前端 | 系统WebView | ~5-10MB | ✅ | ⭐⭐⭐ | 快 |
| Electron | Node.js + Web 前端 | Chromium 内嵌 | ~100-150MB | ✅ | ⭐⭐ | 快 |
| Flutter | Dart + Skia 引擎 | 自绘引擎 | ~20MB | ✅ | ⭐ | 中等 |
| Go + Fyne | Go + 自绘引擎 | 轻量 OpenGL | ~10-15MB | ✅ | ⭐ | 快 |
推荐方案:Tauri
理由:
- 极小体积:5-10MB 完整应用
- 原生性能:Rust 后端,前端任选(HTML/React/Vue/Svelte)
- 现代体验:支持热更新
- 活跃生态:Tauri 1.0 已非常成熟
架构设计
┌─────────────────────────────────────────────────────────┐
│ CutThenThink v3.0 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Rust Core (tauri backend) │ │
│ ├─────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ Web Frontend (任选) │ │ │
│ │ │ - HTML/CSS/JS │ │ │
│ │ │ - React/Vue/Svelte │ │ │
│ │ │ - TailwindCSS │ │ │
│ │ └────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ System Integration (平台API) │ │
│ │ │ - 截图 API │ │
│ │ │ - 文件系统 │ │
│ │ │ - 剪贴板 │ │
│ │ │ - 全局快捷键 │ │
│ │ │ - 通知 │ │
│ │ └────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ External Services (可选) │ │
│ │ │ - RapidOCR (本地) │ │
│ │ │ - 云端 OCR API │ │
│ │ │ - 云存储 (S3/OSS/WebDAV) │ │
│ │ │ - AI 分类 API (可选) │ │
│ │ └────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │ │
│ │ │
└─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
目录结构
cutthenthink-v3/
├── src-tauri/ # Rust 后端 (Tauri CLI)
│ ├── src/
│ │ ├── main.rs # Rust 入口
│ │ ├── lib.rs # 核心库
│ │ ├── commands.rs # 命令处理
│ │ ├── screenshot.rs # 截图模块
│ │ ├── upload.rs # 上传模块
│ │ ├── database.rs # 数据库 (SQLite)
│ │ └── ocr.rs # OCR 接口
│ ├── Cargo.toml # Rust 项目配置
│ ├── tauri.conf.json # Tauri 配置
│ └── build.rs # 构建脚本
│
├── src-ui/ # Web 前端
│ ├── index.html # 入口 HTML
│ ├── src/
│ │ ├── main.js # 主 JS
│ │ ├── styles.css # 样式
│ │ ├── components/ # UI 组件
│ │ │ ├── screenshot.html
│ │ │ ├── upload.html
│ │ │ ├── browse.html
│ │ │ └── settings.html
│ │ ├── api/
│ │ │ ├── commands.js # Tauri API 调用
│ │ │ ├── database.js # 数据库操作
│ │ │ ├── screenshot.js # 截图功能
│ │ │ └── upload.js # 上传功能
│ └── assets/ # 静态资源
│ ├── icons/
│ └── screenshots/
│
├── src-ocr-plugin/ # 可选的本地 OCR 插件 (Go)
│ ├── main.go
│ ├── ocr.go
│ └── models/ # OCR 模型文件
│
└── docs/
├── architecture.md # 本文档
├── api.md # API 文档
└── development.md # 开发指南
核心功能模块
1. 截图模块 (screenshot.rs)
use tauri::command::screenshot::ScreenshotConfig;
/// 截全屏
#[tauri::command]
pub fn capture_fullscreen() -> Result<String, String> {
let screen = Window::current_monitor()?.ok_or("无法获取屏幕")?;
// 调用平台截图 API
match screen {
Screen::CaptureFullscreen(path) => Ok(path.to_string_lossy()),
_ => Err("未实现".to_string()),
}
}
/// 区域截图
#[tauri::command]
pub fn capture_region() -> Result<String, String> {
// 显示区域选择器
// 使用 Tauri 对话框 API
Ok("region_capture".to_string())
}
2. 上传模块 (upload.rs)
use reqwest::blocking::Client;
use serde_json::json;
/// 上传文件
pub struct UploadConfig {
pub provider: String,
pub endpoint: String,
pub api_key: Option<String>,
}
#[tauri::command]
pub fn upload_file(filepath: String) -> Result<String, String> {
let config = get_upload_config()?;
let client = Client::new();
let form = multipart::Form::new()
.text("file", filepath_to_name(&filepath)?)
.text("provider", &config.provider);
// 执行上传
let response = client.post(&config.endpoint, &body)?;
// 返回 URL
Ok(parse_upload_response(&response.text())?)
}
3. 数据库模块 (database.rs)
use rusqlite::{Connection, Result as SQLResult};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Record {
pub id: Option<i64>,
pub filename: String,
pub filepath: String,
pub upload_url: Option<String>,
pub category: String,
pub ocr_text: Option<String>,
pub created_at: String,
pub uploaded_at: Option<String>,
pub file_size: i64,
}
impl Database {
pub fn add_record(&self, record: &Record) -> SQLResult<i64> {
self.conn.execute(
"INSERT INTO records (filename, filepath, category, created_at, file_size)
VALUES (?1, ?2, ?3, datetime('now'), ?4)",
[&record.filename, &record.filepath, &record.category, &record.created_at, &record.file_size],
)?;
Ok(conn.last_insert_rowid())
}
pub fn get_all_records(&self, limit: i64) -> SQLResult<Vec<Record>> {
// 查询实现
}
}
4. 前端 API 绑定 (api/commands.js)
import { invoke } from '@tauri-apps/api/commands';
// 截图命令
export const captureFullscreen = async () => {
const filepath = await invoke('capture_fullscreen');
return filepath;
};
// 上传命令
export const uploadFile = async (filepath, config) => {
const url = await invoke('upload_file', {
filepath,
provider: config.provider,
endpoint: config.endpoint,
apiKey: config.apiKey
});
return url;
};
// 数据库命令
export const getRecords = async () => {
const records = await invoke('get_all_records', { limit: 100 });
return records;
};
5. 前端 UI (components/screenshot.html)
<div class="screenshot-view">
<div class="toolbar">
<button id="btn-fullscreen" class="primary-btn">
<span class="icon">📷</span>
<span class="text">截全屏</span>
<span class="shortcut">Ctrl+Shift+A</span>
</button>
<button id="btn-region" class="secondary-btn">
<span class="icon">⛶</span>
<span class="text">区域截图</span>
<span class="shortcut">Ctrl+Shift+R</span>
</button>
</div>
<div id="preview-container">
<img id="preview" src="assets/placeholder.png" alt="预览">
</div>
<div class="actions">
<button id="btn-upload" disabled>
<span class="icon">☁️</span>
<span class="text">上传</span>
</button>
<button id="btn-ocr" disabled>
<span class="icon">🔍</span>
<span class="text">OCR 识别</span>
</button>
</div>
</div>
<style>
.screenshot-view {
display: flex;
flex-direction: column;
gap: 16px;
}
.toolbar {
display: flex;
gap: 8px;
}
.primary-btn, .secondary-btn {
flex: 1;
align-items: center;
gap: 8px;
padding: 10px 16px;
border: none;
border-radius: 6px;
cursor: pointer;
}
.primary-btn {
background: #8B6914;
color: white;
}
.secondary-btn {
background: #f1f3f4;
color: #2C2C2C;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
Tauri 配置 (tauri.conf.json)
{
"$schema": "https://schema.tauri.app/config/1.0.0",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:3000",
"frontendDist": "../src-ui/dist"
},
"package": {
"productName": "CutThenThink",
"version": "3.0.0"
},
"tauri": {
"allowlist": {
"all": false,
"shell": {
"all": false,
"open": true
}
},
"bundle": {
"identifier": "com.cutthenthink.app",
"icon": [
"icons/128x128.png"
],
"targets": ["all"]
},
"windows": {
"webviewInstallMode": "embed",
"nsis": {
"displayName": "CutThenThink",
"installerIcon": "icons/icon.ico"
}
}
}
},
"plugins": {
"shell": {
"open": true
}
}
}
可选 OCR 插件 (Go)
使用 Go 编写独立的 OCR 插件,通过 IPC 或本地服务器通信:
package main
import (
"github.com/tetratelabs/tesseract-go/tesseract"
"github.com/genmo/invoices/invoices"
)
type OCRResult struct {
Text string
Confidence float64
Error string
}
func Recognize(imagePath string) OCRResult {
// 使用 RapidOCR 或 Tesseract
// 通过本地 socket 或 HTTP 与主程序通信
return OCRResult{
Text: "识别的文字",
Confidence: 0.95,
Error: "",
}
}
依赖清单
Rust 后端依赖
[dependencies]
tauri = { version = "1.0", features = ["shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
rusqlite = "0.3"
reqwest = { version = "0.11", features = ["blocking", "multipart"] }
chrono = { version = "0.4", features = ["serde"] }
dirs = "2.0"
Web 前端依赖
{
"devDependencies": {
"vite": "^4.0.0",
"@tauri-apps/api": "^1.0.0"
"tailwindcss": "^3.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
构建与打包
开发命令
# 前端开发
cd src-ui && npm run dev
# Rust 后端开发
cd src-tauri && cargo tauri dev
# 完整构建
npm run tauri build
打包输出
| 平台 | 输出位置 | 说明 |
|---|---|---|
| Linux | src-tauri/target/release/bundle/appimage |
AppImage 单文件 |
| Windows | src-tauri/target/release/bundle/msi |
MSI 安装包 |
| macOS | src-tauri/target/release/bundle/dmg |
DMG 磁盘镜像 |
预估体积:
- 基础应用:5-10MB
- 包含 OCR 模型:+15-20MB
实施计划
Phase 1: 项目初始化 (1周)
- 创建 Rust Tauri 项目骨架
- 设置前端项目 (Vite + React)
- 配置构建工具链
- 基础 UI 框架
Phase 2: 核心功能 (2周)
- Rust 后端:截图 API 集成
- Rust 后端:文件系统访问
- 前端:截图 UI 组件
- Rust 后端:SQLite 数据库实现
- 前端:记录列表和浏览
Phase 3: 上传功能 (1周)
- Rust 后端:HTTP 上传模块
- 前端:上传配置界面
- 支持多种上传服务
Phase 4: OCR 集成 (1周)
- Go OCR 插件基础框架
- RapidOCR 模型集成
- IPC 通信机制
- 前端:OCR 结果展示
Phase 5: 打包发布 (1周)
- 各平台构建配置
- 图标和资源
- 代码签名 (Windows/macOS)
- GitHub Actions 自动构建
- 安装包测试
优势总结
| 特性 | Python 方案 | Tauri 方案 |
|---|---|---|
| 安装体积 | 需要 Python (~200MB+) | 单文件,无需运行时 |
| 启动速度 | 较慢 | 极快(Rust 原生) |
| 内存占用 | 高 (~100MB+) | 低 (~20-30MB) |
| 更新机制 | 需要重新打包 | 支持热更新 |
| 开发体验 | 框架限制 | 现代 Web 开发 |
| 跨平台 | 依赖复杂 | 一次编译,多平台 |
参考
- Tauri 文档: https://tauri.app/
- Tauri Examples: https://github.com/tauri-apps/tauri/tree/dev/examples
- Rusqlite: https://github.com/rusqlite/rusqlite
- RapidOCR: https://github.com/RapidAI/RapidOCR
文档版本: v3.0 创建日期: 2025-02-12 技术栈: Tauri (Rust) + Web 前端