feat: CutThenThink v3.0 初始版本
完整实现 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>
This commit is contained in:
477
docs/PHASE5_INTEGRATION.md
Normal file
477
docs/PHASE5_INTEGRATION.md
Normal file
@@ -0,0 +1,477 @@
|
||||
# Phase 5 - AI 分类系统集成指南
|
||||
|
||||
本文档说明如何将 Phase 5 实现的 AI 分类功能集成到主应用中。
|
||||
|
||||
## 1. 主应用集成 (App.svelte 或主要入口)
|
||||
|
||||
### 1.1 导入组件和 Store
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { initializeAiStore } from './store/ai';
|
||||
import AiConfigView from './components/views/AiConfigView.svelte';
|
||||
import AiTemplatesView from './components/views/AiTemplatesView.svelte';
|
||||
|
||||
// 状态
|
||||
let showAiConfig = false;
|
||||
let showAiTemplates = false;
|
||||
|
||||
onMount(() => {
|
||||
// 初始化 AI store
|
||||
initializeAiStore();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### 1.2 添加菜单项
|
||||
|
||||
在主界面菜单中添加:
|
||||
|
||||
```svelte
|
||||
<nav>
|
||||
<!-- 现有菜单项 -->
|
||||
<button on:click={() => showAiConfig = true}>
|
||||
⚙️ AI 配置
|
||||
</button>
|
||||
<button on:click={() => showAiTemplates = true}>
|
||||
📝 模板管理
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- Modals -->
|
||||
{#if showAiConfig}
|
||||
<AiConfigView onClose={() => showAiConfig = false} />
|
||||
{/if}
|
||||
|
||||
{#if showAiTemplates}
|
||||
<AiTemplatesView onClose={() => showAiTemplates = false} />
|
||||
{/if}
|
||||
```
|
||||
|
||||
## 2. 记录详情页面集成
|
||||
|
||||
### 2.1 在记录详情中添加分类功能
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import AutoClassifyView from './components/views/AutoClassifyView.svelte';
|
||||
import { getClassification } from './api/ai';
|
||||
|
||||
export let record; // 从父组件传入的记录
|
||||
|
||||
let classification = null;
|
||||
let showClassify = false;
|
||||
|
||||
// 加载已保存的分类
|
||||
async function loadClassification() {
|
||||
if (record?.id) {
|
||||
classification = await getClassification(record.id);
|
||||
}
|
||||
}
|
||||
|
||||
$: if (record?.id) {
|
||||
loadClassification();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="record-detail">
|
||||
<!-- 现有内容 -->
|
||||
|
||||
<!-- 分类按钮 -->
|
||||
<button on:click={() => showClassify = !showClassify}>
|
||||
{showClassify ? '隐藏' : '显示'} AI 分类
|
||||
</button>
|
||||
|
||||
<!-- AI 分类组件 -->
|
||||
{#if showClassify}
|
||||
<AutoClassifyView
|
||||
recordId={record.id}
|
||||
content={record.content}
|
||||
ocrText={record.metadata?.ocr_text}
|
||||
onClassified={(result) => {
|
||||
console.log('分类结果:', result);
|
||||
loadClassification();
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<!-- 显示已保存的分类 -->
|
||||
{#if classification}
|
||||
<div class="classification-info">
|
||||
<h4>分类信息</h4>
|
||||
<p>分类: {classification.category}</p>
|
||||
{#if classification.subcategory}
|
||||
<p>子分类: {classification.subcategory}</p>
|
||||
{/if}
|
||||
<p>置信度: {Math.round(classification.confidence * 100)}%</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
```
|
||||
|
||||
## 3. 全局快捷键集成
|
||||
|
||||
### 3.1 添加快捷键
|
||||
|
||||
在主应用中添加快捷键:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
|
||||
let handleKeyDown = (e) => {
|
||||
// Ctrl/Cmd + K: 快速分类
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
// 触发当前选中记录的分类
|
||||
triggerClassification();
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + Shift + A: 打开 AI 配置
|
||||
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'A') {
|
||||
e.preventDefault();
|
||||
showAiConfig = true;
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 4. 自动分类触发
|
||||
|
||||
### 4.1 截图后自动分类
|
||||
|
||||
在截图完成后触发分类:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { classification } from './store/ai';
|
||||
|
||||
async function handleScreenshot(screenshot) {
|
||||
// 保存记录
|
||||
const record = await saveRecord(screenshot);
|
||||
|
||||
// 如果 AI 已配置,自动分类
|
||||
if ($aiConfig.configured && autoClassifyEnabled) {
|
||||
const variables = {
|
||||
content_type: 'image',
|
||||
image_path: screenshot.file_path,
|
||||
};
|
||||
|
||||
// 如果有 OCR 结果,添加到变量
|
||||
if (screenshot.ocr_text) {
|
||||
variables.ocr_text = screenshot.ocr_text;
|
||||
}
|
||||
|
||||
try {
|
||||
await classification.classify(
|
||||
record.id,
|
||||
'general', // 使用通用模板
|
||||
variables,
|
||||
true // 流式模式
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('自动分类失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 4.2 剪贴板监听自动分类
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { watchClipboard } from './utils/clipboard';
|
||||
|
||||
async function handleClipboardChange(content) {
|
||||
// 保存记录
|
||||
const record = await saveRecord({
|
||||
type: 'text',
|
||||
content: content,
|
||||
});
|
||||
|
||||
// 自动分类
|
||||
if ($aiConfig.configured && autoClassifyEnabled) {
|
||||
await classification.classify(
|
||||
record.id,
|
||||
'general',
|
||||
{
|
||||
content_type: 'text',
|
||||
content: content,
|
||||
},
|
||||
false // 非流式
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
watchClipboard(handleClipboardChange);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 5. 配置持久化
|
||||
|
||||
### 5.1 保存用户偏好
|
||||
|
||||
```typescript
|
||||
// 在 store/settings.ts 中添加
|
||||
|
||||
export const autoClassifyEnabled = writable(false);
|
||||
export const defaultTemplateId = writable('general');
|
||||
export const minConfidence = writable(0.7);
|
||||
|
||||
// 加载设置
|
||||
export async function loadAiSettings() {
|
||||
const enabled = await getSetting('auto_classify_enabled');
|
||||
if (enabled !== null) {
|
||||
autoClassifyEnabled.set(enabled === 'true');
|
||||
}
|
||||
|
||||
const template = await getSetting('default_template_id');
|
||||
if (template) {
|
||||
defaultTemplateId.set(template);
|
||||
}
|
||||
|
||||
const confidence = await getSetting('min_confidence');
|
||||
if (confidence) {
|
||||
minConfidence.set(parseFloat(confidence));
|
||||
}
|
||||
}
|
||||
|
||||
// 保存设置
|
||||
export async function saveAiSettings() {
|
||||
await setSetting('auto_classify_enabled', String($autoClassifyEnabled));
|
||||
await setSetting('default_template_id', $defaultTemplateId);
|
||||
await setSetting('min_confidence', String($minConfidence));
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 通知和反馈
|
||||
|
||||
### 6.1 分类完成通知
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { notification } from './store/notification';
|
||||
|
||||
function handleClassificationComplete(result) {
|
||||
notification.show({
|
||||
type: 'success',
|
||||
title: '分类完成',
|
||||
message: `已分类为: ${result.category}`,
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
function handleClassificationError(error) {
|
||||
notification.show({
|
||||
type: 'error',
|
||||
title: '分类失败',
|
||||
message: error,
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 7. 分类统计显示
|
||||
|
||||
### 7.1 在侧边栏显示统计
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { getClassificationStats } from './api/ai';
|
||||
|
||||
let categoryStats = [];
|
||||
|
||||
async function loadStats() {
|
||||
categoryStats = await getClassificationStats();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadStats();
|
||||
// 定期更新
|
||||
const interval = setInterval(loadStats, 60000);
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
</script>
|
||||
|
||||
<aside>
|
||||
<h3>分类统计</h3>
|
||||
<ul>
|
||||
{#each categoryStats as [category, count]}
|
||||
<li>{category}: {count}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</aside>
|
||||
```
|
||||
|
||||
## 8. 完整集成示例
|
||||
|
||||
### 主应用结构
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { initializeAiStore, aiConfig } from './store/ai';
|
||||
import AiConfigView from './components/views/AiConfigView.svelte';
|
||||
import AiTemplatesView from './components/views/AiTemplatesView.svelte';
|
||||
import RecordList from './components/RecordList.svelte';
|
||||
|
||||
let showAiConfig = false;
|
||||
let showAiTemplates = false;
|
||||
|
||||
onMount(() => {
|
||||
initializeAiStore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
<!-- 侧边栏 -->
|
||||
<aside>
|
||||
<nav>
|
||||
<a href="#records">📋 记录</a>
|
||||
<a href="#screenshots">📸 截图</a>
|
||||
<button on:click={() => showAiConfig = true}>
|
||||
⚙️ AI 配置
|
||||
</button>
|
||||
<button on:click={() => showAiTemplates = true}>
|
||||
📝 模板管理
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- AI 状态指示器 -->
|
||||
<div class="ai-status" class:configured={$aiConfig.configured}>
|
||||
{$aiConfig.configured ? '✅ AI 已启用' : '⚠️ AI 未配置'}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main>
|
||||
<RecordList />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
{#if showAiConfig}
|
||||
<AiConfigView onClose={() => showAiConfig = false} />
|
||||
{/if}
|
||||
|
||||
{#if showAiTemplates}
|
||||
<AiTemplatesView onClose={() => showAiTemplates = false} />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.ai-status {
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
background: #f39c12;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.ai-status.configured {
|
||||
background: #27ae60;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 9. 测试检查清单
|
||||
|
||||
在集成完成后,进行以下测试:
|
||||
|
||||
### 功能测试
|
||||
- [ ] AI 配置界面可以打开
|
||||
- [ ] Claude API Key 可以保存
|
||||
- [ ] OpenAI API Key 可以保存
|
||||
- [ ] 模板列表可以正常显示
|
||||
- [ ] 可以创建新模板
|
||||
- [ ] 可以编辑现有模板
|
||||
- [ ] 可以删除自定义模板
|
||||
- [ ] 可以测试模板渲染
|
||||
- [ ] 可以导出模板
|
||||
- [ ] 可以导入模板
|
||||
- [ ] 分类功能正常工作
|
||||
- [ ] 流式分类实时显示
|
||||
- [ ] 分类结果正确保存
|
||||
- [ ] 分类历史可以查看
|
||||
- [ ] 分类统计正确显示
|
||||
|
||||
### 集成测试
|
||||
- [ ] 截图后自动触发分类
|
||||
- [ ] 剪贴板监听自动分类
|
||||
- [ ] 快捷键正常工作
|
||||
- [ ] 通知正确显示
|
||||
- [ ] 错误正确处理
|
||||
|
||||
### 性能测试
|
||||
- [ ] 大文本分类正常
|
||||
- [ ] 批量分类不卡顿
|
||||
- [ ] API 限流正常工作
|
||||
- [ ] 内存占用合理
|
||||
|
||||
## 10. 故障排查
|
||||
|
||||
### 问题 1: AI 配置保存失败
|
||||
**检查:**
|
||||
- 数据库连接正常
|
||||
- API Key 格式正确
|
||||
- 网络连接正常
|
||||
|
||||
### 问题 2: 分类失败
|
||||
**检查:**
|
||||
- AI 提供商已配置
|
||||
- API Key 有效
|
||||
- 模板存在且有效
|
||||
- 变量值正确
|
||||
|
||||
### 问题 3: 流式响应不显示
|
||||
**检查:**
|
||||
- 事件监听器正确设置
|
||||
- 窗口对象正确传递
|
||||
- Tauri 事件系统正常
|
||||
|
||||
## 11. 下一步
|
||||
|
||||
集成完成后,可以考虑以下增强:
|
||||
|
||||
1. **自动化工作流**
|
||||
- 基于分类自动打标签
|
||||
- 基于分类自动归档
|
||||
- 基于分类触发通知
|
||||
|
||||
2. **高级功能**
|
||||
- 批量分类
|
||||
- 定时分类任务
|
||||
- 分类规则引擎
|
||||
|
||||
3. **用户体验**
|
||||
- 分类建议
|
||||
- 快速操作
|
||||
- 可视化统计
|
||||
|
||||
4. **性能优化**
|
||||
- 结果缓存
|
||||
- 请求队列
|
||||
- 批处理
|
||||
|
||||
---
|
||||
|
||||
如有问题,请参考:
|
||||
- [Phase 5 实现总结](./PHASE5_SUMMARY.md)
|
||||
- [API 文档](../src/api/ai.ts)
|
||||
- [Store 文档](../src/store/ai.ts)
|
||||
Reference in New Issue
Block a user