完整实现 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>
524 lines
15 KiB
Markdown
524 lines
15 KiB
Markdown
# 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
|
||
|
||
**理由:**
|
||
1. **极小体积**:5-10MB 完整应用
|
||
2. **原生性能**:Rust 后端,前端任选(HTML/React/Vue/Svelte)
|
||
3. **现代体验**:支持热更新
|
||
4. **活跃生态**: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)
|
||
|
||
```rust
|
||
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)
|
||
|
||
```rust
|
||
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)
|
||
|
||
```rust
|
||
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)
|
||
|
||
```javascript
|
||
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)
|
||
|
||
```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)
|
||
|
||
```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 或本地服务器通信:
|
||
|
||
```go
|
||
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 后端依赖
|
||
|
||
```toml
|
||
[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 前端依赖
|
||
|
||
```json
|
||
{
|
||
"devDependencies": {
|
||
"vite": "^4.0.0",
|
||
"@tauri-apps/api": "^1.0.0"
|
||
"tailwindcss": "^3.0.0",
|
||
"react": "^18.0.0",
|
||
"react-dom": "^18.0.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 构建与打包
|
||
|
||
### 开发命令
|
||
|
||
```bash
|
||
# 前端开发
|
||
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 前端*
|