Skip to content

Commit 756be99

Browse files
committed
feat: v0.14.0 — AI 处理器架构重构、仪表盘可视化增强与 CI/CD 流水线
AI 处理器架构重构(Electron): - 新增 6 个独立 AI Handler(anchorPoint/optimizeCard/predict/rescue/socratic/visionExtract) - 新增 ipc/ 模块,IPC 通信解耦 - ai/index.ts 统一调度重构 仪表盘可视化增强: - 新增 KnowledgePreviewCard 知识预览卡片 - 新增 LearningPulse 学习脉搏动效 - 新增 ParticleBackground 粒子背景 - 新增 dashboard/styles/ 样式目录 - DashboardPage / EfficiencyChart / TrendChart 优化 3D 与动效系统: - 新增 lib/3d/ 3D 渲染工具 - 新增 springConfig.ts 弹簧动画配置 - 新增 performance.css 性能优化样式 - 新增 scheduler.ts 任务调度器 笔记与灵感模块: - 新增 classroomNoteStore.ts 课堂笔记存储 - 新增 overlay/ 浮层组件目录 - CaptureSidebar / NoteEditPage / InspirationPage 优化 费曼与闪卡模块: - SocraticDialogue / StepIndicator / FeynmanPage 交互增强 - FlipCard / ConfidenceSelector / StudySessionPage 优化 - useFeynmanStore / useStudySessionStore 状态管理改进 AI 系统与基础设施: - RemoteAIPlugin / errorMessages / sessionAnalyzer / useAIFallback 增强 - crypto 模块重构(backupCrypto/encryption/utils) - AI 网关 config.py / providers / vision chain 更新 CI/CD 与部署: - 新增 .github/workflows/(deploy-server/pr-check/release) - 新增 server/.env.example 环境变量模板 - 新增 server/.gitignore 全局优化: - AppLayout / Sidebar / CustomTitlebar / PageTransition 布局增强 - index.css / tokens.css / tailwind.config 样式体系升级 - vite.config / tsconfig / package.json 构建配置更新 - README 更新至 v0.14.0
1 parent 9497619 commit 756be99

111 files changed

Lines changed: 5802 additions & 1548 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.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Deploy AI Gateway
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths: ['server/**']
7+
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Build and push Docker image
14+
run: |
15+
cd server
16+
docker build -t ai-gateway:${{ github.sha }} .
17+
- name: Deploy to server
18+
uses: appleboy/ssh-action@v1
19+
with:
20+
host: ${{ secrets.SERVER_HOST }}
21+
username: ${{ secrets.SERVER_USER }}
22+
key: ${{ secrets.SSH_PRIVATE_KEY }}
23+
script: |
24+
cd /opt/keban
25+
docker-compose pull
26+
docker-compose up -d --force-recreate
27+
sleep 10
28+
curl -f http://localhost:8000/health || (docker-compose rollback && exit 1)

‎.github/workflows/pr-check.yml‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: PR Quality Check
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
jobs:
8+
quality:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: actions/setup-node@v4
13+
with:
14+
node-version: 20
15+
cache: 'npm'
16+
cache-dependency-path: client/package-lock.json
17+
- run: cd client && npm ci
18+
- run: cd client && npm run lint
19+
- run: cd client && npx tsc --noEmit
20+
- run: cd client && npm run test -- --run
21+
- run: cd client && npm run build

‎.github/workflows/release.yml‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Release Electron App
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths: ['client/**']
7+
8+
jobs:
9+
lint-test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: 20
16+
cache: 'npm'
17+
cache-dependency-path: client/package-lock.json
18+
- run: cd client && npm ci
19+
- run: cd client && npm run lint
20+
- run: cd client && npm run test -- --run
21+
22+
build:
23+
needs: lint-test
24+
strategy:
25+
matrix:
26+
os: [windows-latest, macos-latest]
27+
runs-on: ${{ matrix.os }}
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: actions/setup-node@v4
31+
with:
32+
node-version: 20
33+
cache: 'npm'
34+
cache-dependency-path: client/package-lock.json
35+
- run: cd client && npm ci
36+
- run: cd client && npm run electron:build
37+
- uses: actions/upload-artifact@v4
38+
with:
39+
name: release-${{ matrix.os }}
40+
path: client/release/*.{exe,dmg,AppImage}
41+
42+
release:
43+
needs: build
44+
runs-on: ubuntu-latest
45+
if: startsWith(github.ref, 'refs/tags/v')
46+
steps:
47+
- uses: actions/download-artifact@v4
48+
with:
49+
pattern: release-*
50+
- uses: softprops/action-gh-release@v2
51+
with:
52+
files: release-*/*

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<p align="center"><strong>你的 AI 智能学习伙伴 — 让每一分钟学习都高效有价值</strong></p>
44
<p align="center">
55
<img src="https://img.shields.io/badge/status-beta-green.svg" alt="Status" />
6-
<img src="https://img.shields.io/badge/version-v0.13.1-blue.svg" alt="Version" />
6+
<img src="https://img.shields.io/badge/version-v0.14.0-blue.svg" alt="Version" />
77
<img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License" />
88
</p>
99
</p>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* AI 记忆锚点生成功能 Handler
3+
*
4+
* 处理 ai_anchor_point IPC 请求,调用 AI 网关从笔记内容生成记忆锚点。
5+
*/
6+
7+
import { safeHandle } from '../../ipcUtils.js';
8+
import { logger } from '../../logger.js';
9+
import { postJson, gatewayUrl, type AIFeatureDef } from '../utils.js';
10+
11+
// ================================================================
12+
// IPC Handler
13+
// ================================================================
14+
15+
/**
16+
* ai_anchor_point — POST /api/v1/ai/anchor-point
17+
*/
18+
function register(): void {
19+
safeHandle(
20+
'ai_anchor_point',
21+
async (
22+
_event,
23+
args: {
24+
content: string;
25+
title?: string;
26+
authToken?: string;
27+
userApiKey?: string;
28+
},
29+
) => {
30+
const startMs = Date.now();
31+
logger.info(`[AI] [anchor-point] IPC received: content_length=${args.content.length}, title=${args.title ?? '(empty)'}, hasAuth=${!!args.authToken}`);
32+
logger.debug(`[AI] [anchor-point] Content preview: ${args.content.slice(0, 80)}...`);
33+
34+
const reqBody = {
35+
content: args.content,
36+
title: args.title ?? '',
37+
};
38+
39+
logger.info(`[AI] [anchor-point] Target: ${gatewayUrl()}/api/v1/ai/anchor-point`);
40+
41+
interface AnchorPointResp {
42+
concept: string;
43+
association: string;
44+
memory_technique: string;
45+
importance: number;
46+
}
47+
interface AnchorPointGenResp {
48+
anchor_points: AnchorPointResp[];
49+
status: string;
50+
model: string;
51+
tokens_used: number;
52+
latency_ms: number;
53+
}
54+
55+
try {
56+
const { data: resp, requestId } = await postJson<typeof reqBody, AnchorPointGenResp>(
57+
'/api/v1/ai/anchor-point',
58+
reqBody,
59+
args.authToken,
60+
args.userApiKey,
61+
60000,
62+
);
63+
64+
const elapsed = Date.now() - startMs;
65+
logger.info(`[AI] [anchor-point] ✔ Success: anchor_points=${resp.anchor_points.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`);
66+
return {
67+
anchorPoints: resp.anchor_points.map((ap) => ({
68+
concept: ap.concept,
69+
association: ap.association,
70+
memoryTechnique: ap.memory_technique,
71+
importance: ap.importance,
72+
})),
73+
status: resp.status,
74+
model: resp.model,
75+
tokensUsed: resp.tokens_used,
76+
latencyMs: resp.latency_ms,
77+
requestId,
78+
};
79+
} catch (err) {
80+
const elapsed = Date.now() - startMs;
81+
const error = err instanceof Error ? err : new Error(String(err));
82+
logger.error(`[AI] [anchor-point] ✖ Failed after ${elapsed}ms: ${error.message}`);
83+
if (error.cause) logger.error(`[AI] [anchor-point] Error cause: ${error.cause}`);
84+
throw error;
85+
}
86+
},
87+
);
88+
}
89+
90+
// ================================================================
91+
// 功能定义导出
92+
// ================================================================
93+
94+
export const feature: AIFeatureDef = {
95+
id: 'ai_anchor_point',
96+
name: 'AI 记忆锚点',
97+
version: '1.0.0',
98+
register,
99+
};
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* AI 闪卡优化功能 Handler
3+
*
4+
* 处理 ai_optimize_card IPC 请求,调用 AI 网关优化已有闪卡的正反面内容。
5+
*/
6+
7+
import { safeHandle } from '../../ipcUtils.js';
8+
import { logger } from '../../logger.js';
9+
import { postJson, gatewayUrl, type AIFeatureDef } from '../utils.js';
10+
11+
// ================================================================
12+
// IPC Handler
13+
// ================================================================
14+
15+
/**
16+
* ai_optimize_card — POST /api/v1/ai/optimize-card
17+
*/
18+
function register(): void {
19+
safeHandle(
20+
'ai_optimize_card',
21+
async (
22+
_event,
23+
args: {
24+
front: string;
25+
back: string;
26+
authToken?: string;
27+
userApiKey?: string;
28+
},
29+
) => {
30+
const startMs = Date.now();
31+
logger.info(`[AI] [optimize-card] IPC received: front_length=${args.front.length}, back_length=${args.back.length}, hasAuth=${!!args.authToken}`);
32+
logger.debug(`[AI] [optimize-card] Front preview: ${args.front.slice(0, 60)}, Back preview: ${args.back.slice(0, 60)}`);
33+
34+
const reqBody = {
35+
front: args.front,
36+
back: args.back,
37+
};
38+
39+
logger.info(`[AI] [optimize-card] Target: ${gatewayUrl()}/api/v1/ai/optimize-card`);
40+
41+
interface OptimizeCardResp {
42+
suggested_front: string;
43+
suggested_back: string;
44+
improvements: string[];
45+
model: string;
46+
tokens_used: number;
47+
latency_ms: number;
48+
}
49+
50+
try {
51+
const { data: resp, requestId } = await postJson<typeof reqBody, OptimizeCardResp>(
52+
'/api/v1/ai/optimize-card',
53+
reqBody,
54+
args.authToken,
55+
args.userApiKey,
56+
60000,
57+
);
58+
59+
const elapsed = Date.now() - startMs;
60+
logger.info(`[AI] [optimize-card] ✔ Success: improvements=${resp.improvements.length}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`);
61+
return {
62+
suggestedFront: resp.suggested_front,
63+
suggestedBack: resp.suggested_back,
64+
improvements: resp.improvements,
65+
model: resp.model,
66+
tokensUsed: resp.tokens_used,
67+
latencyMs: resp.latency_ms,
68+
requestId,
69+
};
70+
} catch (err) {
71+
const elapsed = Date.now() - startMs;
72+
const error = err instanceof Error ? err : new Error(String(err));
73+
logger.error(`[AI] [optimize-card] ✖ Failed after ${elapsed}ms: ${error.message}`);
74+
if (error.cause) logger.error(`[AI] [optimize-card] Error cause: ${error.cause}`);
75+
throw error;
76+
}
77+
},
78+
);
79+
}
80+
81+
// ================================================================
82+
// 功能定义导出
83+
// ================================================================
84+
85+
export const feature: AIFeatureDef = {
86+
id: 'ai_optimize_card',
87+
name: 'AI 闪卡优化',
88+
version: '1.0.0',
89+
register,
90+
};
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* AI 学习预测功能 Handler
3+
*
4+
* 处理 ai_predict IPC 请求,调用 AI 网关基于笔记内容生成预测性问题。
5+
*/
6+
7+
import { safeHandle } from '../../ipcUtils.js';
8+
import { logger } from '../../logger.js';
9+
import { postJson, gatewayUrl, type AIFeatureDef } from '../utils.js';
10+
11+
// ================================================================
12+
// IPC Handler
13+
// ================================================================
14+
15+
/**
16+
* ai_predict — POST /api/v1/ai/predict
17+
*/
18+
function register(): void {
19+
safeHandle(
20+
'ai_predict',
21+
async (
22+
_event,
23+
args: {
24+
content: string;
25+
authToken?: string;
26+
userApiKey?: string;
27+
},
28+
) => {
29+
const startMs = Date.now();
30+
logger.info(`[AI] [predict] IPC received: content_length=${args.content.length}, hasAuth=${!!args.authToken}`);
31+
logger.debug(`[AI] [predict] Content preview: ${args.content.slice(0, 80)}...`);
32+
33+
const reqBody = { content: args.content };
34+
35+
logger.info(`[AI] [predict] Target: ${gatewayUrl()}/api/v1/ai/predict`);
36+
37+
interface PredictionResp {
38+
question: string;
39+
type: string;
40+
reason: string;
41+
curiosity_score: number;
42+
}
43+
interface PredictGenResp {
44+
predictions: PredictionResp[];
45+
status: string;
46+
model: string;
47+
tokens_used: number;
48+
latency_ms: number;
49+
}
50+
51+
try {
52+
const { data: resp, requestId } = await postJson<typeof reqBody, PredictGenResp>(
53+
'/api/v1/ai/predict',
54+
reqBody,
55+
args.authToken,
56+
args.userApiKey,
57+
60000,
58+
);
59+
60+
const elapsed = Date.now() - startMs;
61+
logger.info(`[AI] [predict] ✔ Success: predictions=${resp.predictions.length}, status=${resp.status}, model=${resp.model}, tokens=${resp.tokens_used}, total=${elapsed}ms, reqId=${requestId ?? 'N/A'}`);
62+
return {
63+
predictions: resp.predictions.map((p) => ({
64+
question: p.question,
65+
type: p.type,
66+
reason: p.reason,
67+
curiosityScore: p.curiosity_score,
68+
})),
69+
status: resp.status,
70+
model: resp.model,
71+
tokensUsed: resp.tokens_used,
72+
latencyMs: resp.latency_ms,
73+
requestId,
74+
};
75+
} catch (err) {
76+
const elapsed = Date.now() - startMs;
77+
const error = err instanceof Error ? err : new Error(String(err));
78+
logger.error(`[AI] [predict] ✖ Failed after ${elapsed}ms: ${error.message}`);
79+
if (error.cause) logger.error(`[AI] [predict] Error cause: ${error.cause}`);
80+
throw error;
81+
}
82+
},
83+
);
84+
}
85+
86+
// ================================================================
87+
// 功能定义导出
88+
// ================================================================
89+
90+
export const feature: AIFeatureDef = {
91+
id: 'ai_predict',
92+
name: 'AI 学习预测',
93+
version: '1.0.0',
94+
register,
95+
};

0 commit comments

Comments
 (0)