ExamPilot 是一个极简考试期复习桌面系统:Electron 双窗口负责入口和副屏状态板,Open WebUI 负责主 agent 与学科 subagent 对话,本地 study-state.json 负责沉淀 todo、进度、薄弱点和结构化摘要。
- 不重写完整聊天 UI。
- 不 fork 或魔改 Open WebUI。
- 不做云账号、云同步、复杂数据库、知识图谱或自动读取课件。
- 教务账号密码只作为本机凭据保存,用于课表/考试安排自动同步。
- 不修改 Windows 系统设置。
cd E:\projects\LearningEnvironment\exampilot
pnpm install如果 Windows 上 pnpm 命令不可用,可以先用 Corepack:
corepack pnpm install如需让 pnpm install 直接可用,可用管理员权限执行 corepack enable pnpm,或自行安装 pnpm。
pnpm dev若使用 Corepack fallback:
corepack pnpm dev启动后应看到两个窗口:
- Study Hub:主屏入口、Open WebUI 入口、学科状态。
- Dashboard:副屏状态板,轮询本地 API。
复制 .env.example 为 .env,按需修改:
EXAMPILOT_API_PORT=32177
OPEN_WEBUI_BASE_URL=http://localhost:3000
OPEN_WEBUI_MASTER_URL=
OPEN_WEBUI_PHYSICS_URL=
OPEN_WEBUI_HISTORY_URL=
OPEN_WEBUI_LINEAR_ALGEBRA_URL=
OPEN_WEBUI_DATA_STRUCTURE_URL=
OPEN_WEBUI_CALCULUS_URL=
EXAMPILOT_DASHBOARD_MODE=ambient
EXAMPILOT_DASHBOARD_CLICK_THROUGH=0
EXAMPILOT_DASHBOARD_OPACITY=1
SUMMARY_API_BASE_URL=
SUMMARY_API_KEY=
SUMMARY_MODEL=本地 API 只监听 127.0.0.1,默认端口为 32177。
- 启动 Open WebUI,并确认访问地址,例如
http://localhost:3000。 - 在
.env中设置OPEN_WEBUI_BASE_URL。 - 在 Open WebUI 中创建一个 Master Agent,system prompt 使用
prompts/master-agent.md。 - 创建五个 subagent,分别使用:
prompts/physics-agent.mdprompts/history-agent.mdprompts/linear-algebra-agent.mdprompts/data-structure-agent.mdprompts/calculus-agent.md
- 导入 tool:复制
prompts/openwebui-tools/update_study_state.py到 Open WebUI Tool 配置。 - 在 Master Agent 和五个 subagent 中启用这个 tool。
- 打开每个 agent 的 Open WebUI 会话,复制对应 URL 到
.env:OPEN_WEBUI_MASTER_URLOPEN_WEBUI_PHYSICS_URLOPEN_WEBUI_HISTORY_URLOPEN_WEBUI_LINEAR_ALGEBRA_URLOPEN_WEBUI_DATA_STRUCTURE_URLOPEN_WEBUI_CALCULUS_URL
完成后,Study Hub 的“打开 Master Agent”和各学科“进入复习”会优先打开对应 agent URL。未配置具体 URL 时会回退到 OPEN_WEBUI_BASE_URL。
Open WebUI tool 现在同时支持读写状态。
读状态:
health_check()get_study_state()get_master_context()get_subject_context(subject)list_todos(subject=None, include_done=False)
写状态:
add_todo(subject, text, priority)mark_todo_done(todo_id)update_progress(subject, progress, readiness, current_focus)update_subject_memory(...)fork_summary(subject, transcript, instruction=None)
Master Agent 应先调用 get_master_context() 再做调度。学科 subagent 应先调用 get_subject_context("physics") 这类函数再开始判断。这样 todo、progress、memory 和 Dashboard 才会形成闭环。
检查 Open WebUI wiring manifest:
curl.exe http://127.0.0.1:32177/api/openwebui/manifest检查某个学科上下文:
curl.exe http://127.0.0.1:32177/api/openwebui/context/linear_algebraExamPilot 迁移了 FlyingKxz 的中国矿业大学教务导入思路:
- 本科课表入口:
http://jwxt.cumt.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N253508&layout=default - 本科考试入口:
http://jwxt.cumt.edu.cn/jwglxt/kwgl/kscx_cxXsksxxIndex.html?gnmkdm=N358105&layout=default - 课表作为独立
academic.courses数据保存。 - 教务考试作为独立
academic.exams数据保存。 - 只有课程名能保守匹配到当前五个复习科目时,才会同步更新
exams倒计时的时间/地点。 todos、progress、subjectMemory不会因为教务同步被清零或自动提高。
在 Study Hub 的 Master 总览里可以保存教务账号密码、配置 OCR URL、开启自动同步或立即同步。密码不写入 study-state.json,而是保存到 Electron userData 下的 academic-credentials.json;系统支持时使用 Electron safeStorage 加密。
自动同步默认不开启。开启后最小间隔为一天一次(1440 分钟),失败时只记录错误状态,不清空上一次成功同步的数据。
如果自动登录遇到验证码,ExamPilot 会优先使用本机 PaddleOCR:
- 默认 Python:
C:\Users\74090\Miniconda3\envs\torchnb311\python.exe - OCR 脚本:
scripts/paddle_ocr.py - 可用环境变量覆盖:
EXAMPILOT_PADDLE_OCR_PYTHON
如果在界面中配置了 OCR 服务 URL,则优先调用 HTTP OCR 服务。接口期望接收:
{
"imageBase64": "...",
"mimeType": "image/png"
}返回可以是纯文本,也可以是包含 text、result 或 code 字段的 JSON。
手动兜底入口:Study Hub 中点击“内嵌网页”,进入 #/academic。登录教务并切到目标页面后,点击“提取当前课表”或“提取当前考试”即可把当前网页 HTML 解析进本地状态。
相关本地 API:
curl.exe http://127.0.0.1:32177/api/academic/status
curl.exe -X POST http://127.0.0.1:32177/api/academic/sync默认 EXAMPILOT_DASHBOARD_MODE=ambient:副屏 Dashboard 会占满目标显示器工作区,但窗口透明、无边框、跳过任务栏;内容以较高可读性的半透明面板分布在整块副屏上。默认 EXAMPILOT_DASHBOARD_CLICK_THROUGH=0,代办列表可以鼠标滚动和点击完成。
副屏当前按 7/3 分区:
- 上方 70%:学习区,包含最近考试、今日待办、各科进度,并使用整体高斯模糊底。
- 下方 30%:音乐区,使用当前歌曲信息、静态封面/占位封面、主色晕染背景和上一首/播放暂停/下一首按钮。
它不是系统级壁纸层,不会修改 Windows 桌面,也不会用 WorkerW 挂载。
如需恢复普通窗口:
EXAMPILOT_DASHBOARD_MODE=window
EXAMPILOT_DASHBOARD_CLICK_THROUGH=0
EXAMPILOT_DASHBOARD_OPACITY=1ExamPilot 通过 Windows 系统媒体会话读取当前播放信息,QQ 音乐如果暴露系统媒体会话,就能被识别。
curl.exe http://127.0.0.1:32177/api/music/current
curl.exe -X POST http://127.0.0.1:32177/api/music/control -H "Content-Type: application/json" -d "{\"action\":\"toggle\"}"控制动作:
previoustogglenext
如果 QQ 音乐没有暴露媒体会话,音乐面板会显示未连接,不影响复习功能。
Study Hub 使用 Electron webview 承载 Open WebUI,不再使用普通 iframe。这样 Open WebUI 内的图片、头像、粘贴图片、文字复制等行为更接近独立浏览器窗口。主进程也显式处理了 Ctrl+C / Ctrl+V / Ctrl+X / Ctrl+A。
读取状态:
curl.exe http://127.0.0.1:32177/api/state添加 todo:
curl.exe -X POST http://127.0.0.1:32177/api/todos -H "Content-Type: application/json" -d "{\"subject\":\"linear_algebra\",\"text\":\"做矩阵秩典型题 5 道\",\"priority\":\"high\",\"source\":\"manual\"}"更新 progress:
curl.exe -X POST http://127.0.0.1:32177/api/progress -H "Content-Type: application/json" -d "{\"subject\":\"physics\",\"progress\":45,\"readiness\":\"partial\",\"currentFocus\":\"力学公式与典型题\"}"更新 memory:
curl.exe -X POST http://127.0.0.1:32177/api/subject-memory -H "Content-Type: application/json" -d "{\"subject\":\"linear_algebra\",\"rollingSummary\":\"正在复习矩阵秩。\",\"semanticSummary\":\"用户对秩和解空间关系仍不稳定。\",\"completedPoints\":[\"矩阵基本运算\"],\"weaknesses\":[{\"text\":\"秩与自由变量数量关系不稳定\",\"severity\":4,\"nextAction\":\"做 5 道相关题\"}],\"nextActions\":[\"做秩相关题 5 道\"],\"lastQuestions\":[\"rank 和自由变量有什么关系?\"],\"confidence\":0.75}"未配置 summary provider 时:
curl.exe -X POST http://127.0.0.1:32177/api/summaries/fork -H "Content-Type: application/json" -d "{\"subject\":\"linear_algebra\",\"transcript\":\"用户问:rank 和自由变量有什么关系?助手解释后用户仍不稳定。\"}"应返回:
{
"ok": false,
"message": "summary_provider_not_configured"
}配置 SUMMARY_API_BASE_URL、SUMMARY_API_KEY、SUMMARY_MODEL 后,接口会调用 OpenAI-compatible /chat/completions,要求模型返回 JSON,并把结果 merge 到 subjectMemory。
Study Hub 使用 Electron webview 内嵌 Open WebUI。若 Open WebUI 的安全策略或本地环境仍导致异常,使用“打开当前 Agent”按钮在外部浏览器打开即可,不影响状态 API 和 Dashboard。
确认 Electron 主进程已启动,且端口 32177 未被占用。也可以访问:
curl.exe http://127.0.0.1:32177/api/health这是预期行为。未配置时 fork summary 返回 summary_provider_not_configured,其他功能仍可用。
pnpm dev
pnpm lint
pnpm build
pnpm preview