Skip to content

Commit 98794ce

Browse files
committed
feat: v0.8.0 — Electron 架构重构、UI 组件升级、PWA 支持与系统托盘
Electron 架构重构: - 拆分 aiHandlers.ts 为 ai/ 模块化目录 - 新增 captureHandlers.ts 独立屏幕/音频捕获处理 - 新增 windowManager.ts 统一管理窗口生命周期 - 新增 trayManager.ts 实现系统托盘功能 UI 组件系统升级: - 全面升级基础组件(Button、Card、Input、Modal、Toast 等) - 新增 ErrorBoundary 错误边界组件 - 布局组件优化(AppLayout、CustomTitlebar、Sidebar、Navbar) - 页面过渡与动效增强 PWA 支持: - 新增 PWA 图标资源(192x192、512x512) - 新增 shadcn/ui 配置(components.json) - 环境变量模板(.env.example) 业务模块优化: - 番茄钟:计时器与持久化逻辑优化 - 笔记:康奈尔布局与捕获侧边栏改进 - 闪卡:翻转卡片与学习会话优化 - 费曼学习法:页面交互增强 - 仪表盘:效率图表与分析页优化 - 灵感空间:页面体验改进 基础设施: - Vite / Vitest 配置调整 - Tailwind 设计令牌更新 - AI 配置与类型系统扩展 - 存储层与同步引擎优化 - 音效系统配置增强
1 parent bc14d0e commit 98794ce

95 files changed

Lines changed: 7252 additions & 4530 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎client/.env.example‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# ============================================
2+
# 课伴 KeBan - 环境变量配置模板
3+
# 复制此文件为 .env 并填入实际值
4+
# ============================================
5+
6+
# ---- Supabase 配置 ----
7+
# Supabase 项目 URL(从 Supabase Dashboard 获取)
8+
VITE_SUPABASE_URL=
9+
# Supabase 匿名公钥(从 Supabase Dashboard 获取)
10+
VITE_SUPABASE_ANON_KEY=
11+
12+
# ---- API 服务地址 ----
13+
# 同步服务(sync-service)基础地址
14+
# 开发环境: http://127.0.0.1:8080
15+
# 生产环境: 你的服务器地址
16+
VITE_API_BASE_URL=
17+
18+
# 同步服务健康检查端点
19+
VITE_API_HEALTH_URL=
20+
21+
# ---- AI 网关 ----
22+
# AI Gateway 服务地址
23+
# 开发环境: http://127.0.0.1:8000
24+
# 生产环境: 你的服务器地址
25+
VITE_AI_GATEWAY_URL=

‎client/components.json‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "default",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.js",
8+
"css": "src/styles/tokens.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true
11+
},
12+
"aliases": {
13+
"components": "@/components",
14+
"utils": "@/lib/utils",
15+
"ui": "@/components/ui",
16+
"lib": "@/lib",
17+
"hooks": "@/hooks"
18+
}
19+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* AI 评估功能 Handler
3+
*
4+
* 处理 ai_evaluate IPC 请求,调用 AI 网关评估用户对概念的解释。
5+
*/
6+
7+
import { safeHandle } from '../../ipcUtils.js';
8+
import { logger } from '../../logger.js';
9+
import { postJson, type AIFeatureDef } from '../utils.js';
10+
11+
// ================================================================
12+
// IPC Handler
13+
// ================================================================
14+
15+
/**
16+
* ai_evaluate — POST /api/v1/ai/evaluate-explanation
17+
*/
18+
function register(): void {
19+
safeHandle(
20+
'ai_evaluate',
21+
async (
22+
_event,
23+
args: {
24+
concept: string;
25+
explanation: string;
26+
authToken?: string;
27+
},
28+
) => {
29+
const startMs = Date.now();
30+
logger.info(`[IPC] ai_evaluate start, concept_length=${args.concept.length}`);
31+
const reqBody = {
32+
concept: args.concept,
33+
explanation: args.explanation,
34+
};
35+
36+
interface DimensionResp {
37+
dimension: string;
38+
score: number;
39+
feedback: string;
40+
}
41+
interface EvaluateResp {
42+
overall_score: number;
43+
dimensions: DimensionResp[];
44+
strengths: string[];
45+
improvements: string[];
46+
encouragement: string;
47+
model: string;
48+
tokens_used: number;
49+
latency_ms: number;
50+
}
51+
52+
const { data: resp, requestId } = await postJson<typeof reqBody, EvaluateResp>(
53+
'/api/v1/ai/evaluate-explanation',
54+
reqBody,
55+
args.authToken,
56+
);
57+
58+
logger.info(`[IPC] Request ID: ${requestId ?? 'N/A'}`);
59+
logger.info(`[IPC] ai_evaluate end, overall_score=${resp.overall_score}`);
60+
return {
61+
overallScore: resp.overall_score,
62+
dimensions: resp.dimensions.map((d) => ({
63+
name: d.dimension, // 后端字段 dimension → 前端 name
64+
score: d.score,
65+
feedback: d.feedback,
66+
})),
67+
strengths: resp.strengths,
68+
improvements: resp.improvements,
69+
encouragement: resp.encouragement,
70+
model: resp.model,
71+
tokensUsed: resp.tokens_used,
72+
latencyMs: resp.latency_ms,
73+
requestId,
74+
};
75+
},
76+
);
77+
}
78+
79+
// ================================================================
80+
// 功能定义导出
81+
// ================================================================
82+
83+
export const feature: AIFeatureDef = {
84+
id: 'ai_evaluate',
85+
name: 'AI 解释评估',
86+
version: '1.0.0',
87+
register,
88+
};
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* 费曼学习法功能 Handler
3+
*
4+
* 处理 ai_feynman_question 和 ai_feynman_evaluate_answers IPC 请求,
5+
* 调用 AI 网关生成追问并评估用户回答。
6+
*/
7+
8+
import { safeHandle } from '../../ipcUtils.js';
9+
import { logger } from '../../logger.js';
10+
import { postJson, type AIFeatureDef } from '../utils.js';
11+
12+
// ================================================================
13+
// IPC Handler
14+
// ================================================================
15+
16+
/**
17+
* 注册费曼学习法相关的所有 IPC handler
18+
*/
19+
function register(): void {
20+
/**
21+
* ai_feynman_question — POST /api/v1/ai/feynman-question
22+
*/
23+
safeHandle(
24+
'ai_feynman_question',
25+
async (
26+
_event,
27+
args: {
28+
concept: string;
29+
explanation: string;
30+
authToken?: string;
31+
},
32+
) => {
33+
const startMs = Date.now();
34+
logger.info(`[IPC] ai_feynman_question start, concept_length=${args.concept.length}`);
35+
const reqBody = {
36+
concept: args.concept,
37+
explanation: args.explanation,
38+
};
39+
40+
interface FeynmanQuestionResp {
41+
questions: Array<{ question: string; focus: string }>;
42+
model: string;
43+
tokens_used: number;
44+
latency_ms: number;
45+
}
46+
47+
const { data: resp, requestId } = await postJson<typeof reqBody, FeynmanQuestionResp>(
48+
'/api/v1/ai/feynman-question',
49+
reqBody,
50+
args.authToken,
51+
);
52+
53+
logger.info(`[IPC] Request ID: ${requestId ?? 'N/A'}`);
54+
logger.info(`[IPC] ai_feynman_question end, question_count=${resp.questions.length}`);
55+
return {
56+
questions: resp.questions.map((q) => ({
57+
question: q.question,
58+
focus: q.focus,
59+
})),
60+
model: resp.model,
61+
tokensUsed: resp.tokens_used,
62+
latencyMs: resp.latency_ms,
63+
requestId,
64+
};
65+
},
66+
);
67+
68+
/**
69+
* ai_feynman_evaluate_answers — POST /api/v1/ai/feynman-evaluate-answers
70+
*/
71+
safeHandle(
72+
'ai_feynman_evaluate_answers',
73+
async (
74+
_event,
75+
args: {
76+
concept: string;
77+
questions: string[];
78+
answers: string[];
79+
authToken?: string;
80+
},
81+
) => {
82+
const startMs = Date.now();
83+
logger.info(`[IPC] ai_feynman_evaluate_answers start, concept_length=${args.concept.length}`);
84+
const reqBody = {
85+
concept: args.concept,
86+
questions: args.questions,
87+
answers: args.answers,
88+
};
89+
90+
interface FeynmanAnswerEvalResp {
91+
understanding_score: number;
92+
feedback: string;
93+
strong_points: string[];
94+
weak_points: string[];
95+
model: string;
96+
tokens_used: number;
97+
latency_ms: number;
98+
}
99+
100+
const { data: resp, requestId } = await postJson<typeof reqBody, FeynmanAnswerEvalResp>(
101+
'/api/v1/ai/feynman-evaluate-answers',
102+
reqBody,
103+
args.authToken,
104+
);
105+
106+
logger.info(`[IPC] Request ID: ${requestId ?? 'N/A'}`);
107+
logger.info(`[IPC] ai_feynman_evaluate_answers end, score=${resp.understanding_score}`);
108+
return {
109+
understandingScore: resp.understanding_score,
110+
feedback: resp.feedback,
111+
strongPoints: resp.strong_points,
112+
weakPoints: resp.weak_points,
113+
model: resp.model,
114+
tokensUsed: resp.tokens_used,
115+
latencyMs: resp.latency_ms,
116+
requestId,
117+
};
118+
},
119+
);
120+
}
121+
122+
// ================================================================
123+
// 功能定义导出
124+
// ================================================================
125+
126+
export const feature: AIFeatureDef = {
127+
id: 'ai_feynman',
128+
name: '费曼学习法',
129+
version: '1.0.0',
130+
register,
131+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* AI 闪卡生成功能 Handler
3+
*
4+
* 处理 ai_generate_cards IPC 请求,调用 AI 网关从笔记生成闪卡。
5+
*/
6+
7+
import { safeHandle } from '../../ipcUtils.js';
8+
import { logger } from '../../logger.js';
9+
import { postJson, type AIFeatureDef } from '../utils.js';
10+
11+
// ================================================================
12+
// IPC Handler
13+
// ================================================================
14+
15+
/**
16+
* ai_generate_cards — POST /api/v1/ai/generate-cards
17+
*/
18+
function register(): void {
19+
safeHandle(
20+
'ai_generate_cards',
21+
async (
22+
_event,
23+
args: {
24+
note: string;
25+
maxCards?: number;
26+
difficulty?: string;
27+
cardType?: string;
28+
authToken?: string;
29+
},
30+
) => {
31+
const startMs = Date.now();
32+
logger.info(`[IPC] ai_generate_cards start, note_length=${args.note.length}`);
33+
const reqBody = {
34+
note: args.note,
35+
options: {
36+
...(args.maxCards !== undefined && { max_cards: args.maxCards }),
37+
...(args.difficulty !== undefined && { difficulty: args.difficulty }),
38+
...(args.cardType !== undefined && { card_type: args.cardType }),
39+
},
40+
};
41+
42+
interface CardResp {
43+
front: string;
44+
back: string;
45+
type: string;
46+
confidence: number;
47+
}
48+
interface CardGenResp {
49+
cards: CardResp[];
50+
total_extracted: number;
51+
model: string;
52+
tokens_used: number;
53+
}
54+
55+
const { data: resp, requestId } = await postJson<typeof reqBody, CardGenResp>(
56+
'/api/v1/ai/generate-cards',
57+
reqBody,
58+
args.authToken,
59+
);
60+
61+
logger.info(`[IPC] Request ID: ${requestId ?? 'N/A'}`);
62+
logger.info(`[IPC] ai_generate_cards end, cards_count=${resp.cards.length}`);
63+
return {
64+
cards: resp.cards.map((c) => ({
65+
front: c.front,
66+
back: c.back,
67+
type: c.type,
68+
confidence: c.confidence,
69+
})),
70+
totalExtracted: resp.total_extracted,
71+
model: resp.model,
72+
tokensUsed: resp.tokens_used,
73+
requestId,
74+
};
75+
},
76+
);
77+
}
78+
79+
// ================================================================
80+
// 功能定义导出
81+
// ================================================================
82+
83+
export const feature: AIFeatureDef = {
84+
id: 'ai_generate_cards',
85+
name: 'AI 闪卡生成',
86+
version: '1.0.0',
87+
register,
88+
};

0 commit comments

Comments
 (0)