完整实现 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>
10 KiB
10 KiB
Phase 5 - AI 分类系统集成指南
本文档说明如何将 Phase 5 实现的 AI 分类功能集成到主应用中。
1. 主应用集成 (App.svelte 或主要入口)
1.1 导入组件和 Store
<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 添加菜单项
在主界面菜单中添加:
<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 在记录详情中添加分类功能
<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 添加快捷键
在主应用中添加快捷键:
<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 截图后自动分类
在截图完成后触发分类:
<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 剪贴板监听自动分类
<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 保存用户偏好
// 在 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 分类完成通知
<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 在侧边栏显示统计
<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. 完整集成示例
主应用结构
<!-- 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. 下一步
集成完成后,可以考虑以下增强:
-
自动化工作流
- 基于分类自动打标签
- 基于分类自动归档
- 基于分类触发通知
-
高级功能
- 批量分类
- 定时分类任务
- 分类规则引擎
-
用户体验
- 分类建议
- 快速操作
- 可视化统计
-
性能优化
- 结果缓存
- 请求队列
- 批处理
如有问题,请参考: