🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

错题整理本 suanmingxing/dsh-ai-mistake-book

DeepSeek Harness
suanmingxing10 天前有提交已提供中文文档扫描:含敏感能力

AI 错题本:把扫描试卷整理成以知识点为索引的错题合集dsh-plugin

30.6/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add suanmingxing/dsh-ai-mistake-book
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/11/02·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/03·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 10 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 100 处,展示前 98 条)
  • 发起网络请求
    client.js:497
    const response = await fetch(`/mistake/api/${method}`, {
  • 写入剪贴板
    client.js:2993
    await navigator.clipboard.writeText(target)
  • 写入本地文件
    lib/paths.js:61
    await mkdir(dir, { recursive: true })
  • 读取本地文件
    lib/paths.js:113
    return JSON.parse(await readFile(file, 'utf8'))
  • 写入本地文件
    lib/paths.js:123
    await mkdir(dirname(file), { recursive: true })
  • 写入本地文件
    lib/paths.js:124
    await writeFile(temp, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
  • 写入本地文件
    lib/paths.js:125
    await rename(temp, file)
  • 读取本地文件
    lib/paths.js:131
    await stat(target)
  • 删除本地文件递归
    lib/paths.js:155
    await rm(target, { recursive: true, force: true })
  • 读取本地文件
    lib/server.js:120
    const info = await stat(target)
  • 读取本地文件
    lib/server.js:127
    createReadStream(target).pipe(res)
  • 读取本地文件
    lib/server.js:152
    const bytes = await readFile(file)
  • 读取本地文件
    lib/store.js:32
    const entries = await readdir(paths.inbox, { withFileTypes: true })
  • 读取本地文件
    lib/tools/common.js:175
    const cropped = cropPng(await readFile(sourceFile), plan.rect)
  • 写入本地文件
    lib/tools/mistake.js:279
    await mkdir(cardsDir, { recursive: true })
  • 写入本地文件
    lib/tools/mistake.js:298
    await writeFile(join(cardsDir, card.fileName), card.markdown, 'utf8')
  • 读取本地文件
    lib/tools/note.js:66
    names = (await readdir(dir)).filter((name) => name.endsWith('.md'))
  • 读取本地文件
    lib/tools/note.js:79
    markdown: await readFile(join(dir, name), 'utf8'),
  • 写入本地文件
    lib/tools/note.js:216
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    lib/tools/note.js:219
    await writeFile(join(dir, partFileName(item.page, item.chunk)), item.markdown, 'utf8')
  • 写入本地文件
    lib/tools/note.js:324
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    lib/tools/note.js:325
    await writeFile(join(dir, NOTE_DRAFT), markdown, 'utf8')
  • 写入本地文件
    lib/ingest.js:39
    await writeFile(file, stored.data)
  • 读取本地文件
    lib/ingest.js:50
    if (typeof hostPath === 'string' && hostPath !== '' && existsSync(hostPath)) {
  • 写入本地文件
    lib/ingest.js:51
    await copyFile(hostPath, file)
  • 写入本地文件
    lib/ingest.js:60
    await writeFile(file, Buffer.concat(chunks))
  • 读取本地文件
    lib/ingest.js:62
    const bytes = (await readFile(file)).length
  • 读取本地文件
    lib/ingest.js:63
    written.push({ file, name, bytes, mediaType: sniffImageMediaType(await readFile(file)) ?? (isPdfName(name) ? 'application/pdf' : undefined) })
  • 读取本地文件
    lib/ingest.js:76
    if (candidate === '' || !isAbsolute(candidate) || !existsSync(candidate)) return
  • 写入本地文件
    lib/ingest.js:144
    await mkdir(sourceDir, { recursive: true })
  • 读取本地文件
    lib/ingest.js:176
    if (!existsSync(path)) throw new Error(`找不到文件:${path}`)
  • 写入本地文件
    lib/ingest.js:179
    await copyFile(path, file)
  • 读取本地文件
    lib/ingest.js:180
    const bytes = (await readFile(file)).length
  • 读取本地文件
    lib/api/library.js:34
    const index = parseIndex(await readFile(paths.indexJson, 'utf8').catch(() => null))
  • 读取本地文件
    lib/api/library.js:58
    names = await readdir(assetDir)
  • 读取本地文件
    lib/api/library.js:78
    const markdown = await readFile(file, 'utf8')
  • 读取本地文件
    lib/card.js:218
    for (const paper of await readdir(base, { withFileTypes: true })) {
  • 读取本地文件
    lib/card.js:222
    for (const file of await readdir(cardsDir)) {
  • 读取本地文件
    lib/card.js:227
    for (const file of await readdir(cardsDir)) {
  • 读取本地文件
    lib/card.js:230
    const head = (await readFile(join(cardsDir, file), 'utf8')).slice(0, 400)
  • 写入本地文件
    lib/templates.js:245
    await mkdir(paths.templates, { recursive: true })
  • 写入本地文件
    lib/templates.js:250
    await writeFile(target, definition.content, 'utf8')
  • 读取本地文件
    lib/templates.js:260
    out[key] = await readFile(templateFile(paths, key), 'utf8')
  • 写入本地文件
    lib/templates.js:271
    await mkdir(paths.templates, { recursive: true })
  • 写入本地文件
    lib/templates.js:272
    await writeFile(templateFile(paths, key), String(content ?? ''), 'utf8')
  • 写入本地文件
    lib/templates.js:354
    await mkdir(paths.templates, { recursive: true })
  • 读取本地文件
    lib/pages.js:43
    const rasterBytes = await readFile(rasterFile)
  • 读取本地文件
    lib/pages.js:46
    const overviewBytes = overviewFile ? await readFile(overviewFile) : rasterBytes
  • 写入本地文件
    lib/pages.js:58
    await mkdir(bandDir, { recursive: true })
  • 写入本地文件
    lib/pages.js:67
    await writeFile(file, crop.buffer)
  • 读取本地文件
    lib/raster.js:58
    const node = candidateNodes().find((candidate) => existsSync(candidate))
  • 读取本地文件
    lib/raster.js:59
    const cli = candidateCliPaths().find((candidate) => existsSync(candidate))
  • 写入本地文件
    lib/raster.js:85
    await mkdir(dirname(outputPath), { recursive: true })
  • 执行外部命令来自配置/变量
    lib/raster.js:99
    execFile(command, args, { timeout: timeoutMs, maxBuffer: 32 * 1024 * 1024, windowsHide: true, signal }, (error, stdout, stderr) => {
  • 写入本地文件
    lib/raster.js:123
    await mkdir(dirname(outputDir), { recursive: true })
  • 读取本地文件
    lib/raster.js:149
    return { entry, bytes: await readFile(entry.path) }
  • 读取本地文件
    lib/drafts.js:53
    const entries = await readdir(dir, { withFileTypes: true })
  • 读取本地文件
    lib/drafts.js:63
    const markdown = await readFile(file, 'utf8')
  • 写入本地文件
    lib/drafts.js:80
    await writeFile(join(draftDir(paths, batch), basename(current.fileName)), markdown, 'utf8')
  • 删除本地文件
    lib/drafts.js:87
    await rm(file, { force: true })
  • 读取本地文件
    lib/library.js:115
    subjects = (await readdir(paths.library, { withFileTypes: true }))
  • 读取本地文件
    lib/library.js:124
    for (const paper of await readdir(subjectDir, { withFileTypes: true })) {
  • 读取本地文件
    lib/library.js:128
    for (const file of (await readdir(cardsDir)).filter((name) => name.endsWith('.md')).sort()) {
  • 读取本地文件
    lib/library.js:131
    const parsed = parseFrontMatter(await readFile(full, 'utf8'))
  • 读取本地文件
    lib/library.js:167
    slugs = (await readdir(notesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort()
  • 读取本地文件
    lib/library.js:177
    markdown = await readFile(file, 'utf8')
  • 写入本地文件
    lib/library.js:319
    await writeFile(paths.indexMd, lines.join('\n'), 'utf8')
  • 读取本地文件
    lib/trash.js:27
    return await readdir(dir)
  • 删除本地文件递归
    lib/trash.js:55
    await rm(source, { recursive: true, force: true })
  • 写入本地文件
    lib/trash.js:60
    await mkdir(dirname(target), { recursive: true })
  • 写入本地文件
    lib/trash.js:61
    await rename(source, target)
  • 删除本地文件递归
    lib/trash.js:94
    if (entries.length === 0) await rm(dir, { recursive: true, force: true })
  • 读取本地文件
    lib/trash.js:104
    const info = await stat(binDir).catch(() => null)
  • 读取本地文件
    lib/trash.js:130
    const info = await stat(full).catch(() => null)
  • 写入本地文件
    lib/trash.js:168
    await mkdir(dirname(target), { recursive: true })
  • 写入本地文件
    lib/trash.js:169
    await rename(source, target)
  • 删除本地文件递归
    lib/trash.js:180
    await rm(binDir, { recursive: true, force: true })
  • 删除本地文件递归
    lib/trash.js:202
    await rm(binDir, { recursive: true, force: true })
  • 删除本地文件递归
    lib/trash.js:208
    await rm(paths.trash, { recursive: true, force: true })
  • 写入本地文件
    lib/archive-mistake.js:40
    await mkdir(subjectDir, { recursive: true })
  • 写入本地文件
    lib/archive-mistake.js:43
    await mkdir(join(paperDir, DRAFT_CARD_DIR), { recursive: true })
  • 写入本地文件
    lib/archive-mistake.js:58
    await writeFile(target, markdown, 'utf8')
  • 写入本地文件
    lib/archive-mistake.js:65
    await rename(join(paths.batchDir(batch.id), 'source'), join(paperDir, 'source'))
  • 写入本地文件
    lib/archive-mistake.js:69
    await rename(join(paths.batchDir(batch.id), 'bands'), join(paperDir, 'bands'))
  • 删除本地文件递归
    lib/archive-mistake.js:93
    await rm(join(paths.batchDir(batch.id), DRAFT_CARD_DIR), { recursive: true, force: true })
  • 读取本地文件
    lib/archive-note.js:60
    const parsed = parseFrontMatter(await readFile(draftFile, 'utf8'))
  • 写入本地文件
    lib/archive-note.js:68
    await mkdir(paths.notesDir, { recursive: true })
  • 写入本地文件
    lib/archive-note.js:71
    await mkdir(noteDir, { recursive: true })
  • 写入本地文件
    lib/archive-note.js:86
    await writeFile(noteFile, `${renderFrontMatterData(noteData)}\n${body.replace(/^ +/, '')}`, 'utf8')
  • 写入本地文件
    lib/archive-note.js:91
    await rename(join(batchDir, 'source'), join(noteDir, 'source'))
  • 写入本地文件
    lib/archive-note.js:95
    await rename(join(batchDir, 'bands'), join(noteDir, 'bands'))
  • 删除本地文件递归
    lib/archive-note.js:128
    await rm(draftDir, { recursive: true, force: true })
  • 读取本地文件
    lib/export-build.js:183
    const bytes = await readFile(source.absolute)
  • 读取本地文件
    lib/export-store.js:21
    const names = await readdir(dir).catch(() => [])
  • 读取本地文件
    lib/export-store.js:25
    const info = await stat(target).catch(() => null)
  • 读取本地文件
    lib/export.js:89
    const raw = await readFile(join(paths.root, ...card.file.split('/')), 'utf8')
  • 写入本地文件
    lib/export.js:171
    await mkdir(exportsDir, { recursive: true })
  • 写入本地文件
    lib/export.js:179
    await writeFile(docxPath, document)
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cosmokit@deepseek-ai/schemastery@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-settings
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
AI 错题本 · DSH 插件 把扫描试卷变成一本以知识点为索引的错题本,也能把手写笔记转录成可编辑的电子版 Markdown:投喂 PDF/图片 → 插件建批次并光栅化 → 模型在会话里读卷面/笔记 → 生成卡片或笔记草稿 → 你确认后归档进 library/,并自动重建索引。 不是「AI 帮你解题」,而是「AI 帮你把卷面上已经存在的东西整理成可复习的结构」。 功能 - 扫描件直读:PDF 自动光栅化(默认 400 dpi),切成整页概览 + 高清横带;看不清时按需索取原生分辨率重切 - 只在错题上花力气:按你报的题号逐题提取,题干、作答、划改、页边演算、卷面标注、知识点、错因、难度 - 手写笔记转电子版(/note):多页笔记逐页转录、可一次提交多页、页内可分块;保留标题/列表/表格结构,公式用 LaTeX 保存;草稿可在待归档页直接编辑 - 绝不编造:读不准的内容写进「待人工确认」,交给人核对 - 笔迹颜色筛选:/note 和 /mistake 可分别设置「提取的颜色 / 忽略的颜色」,只整理指定颜色笔迹(设置页 Prompt 配置里修改) - 卡片即 Markdown:library/<学科>/<卷子>/cards/.md,带 front-matter,可手改、可 diff、可进版本库
展开完整文档(README 剩余 1 节)
AI 错题本 · DSH 插件

把扫描试卷变成一本以知识点为索引的错题本,也能把手写笔记转录成可编辑的电子版 Markdown:投喂 PDF/图片 → 插件建批次并光栅化 → 模型在会话里读卷面/笔记 → 生成卡片或笔记草稿 → 你确认后归档进 library/,并自动重建索引。

不是「AI 帮你解题」,而是「AI 帮你把卷面上已经存在的东西整理成可复习的结构」。

功能

- 扫描件直读:PDF 自动光栅化(默认 400 dpi),切成整页概览 + 高清横带;看不清时按需索取原生分辨率重切
- 只在错题上花力气:按你报的题号逐题提取,题干、作答、划改、页边演算、卷面标注、知识点、错因、难度
- 手写笔记转电子版(/note):多页笔记逐页转录、可一次提交多页、页内可分块;保留标题/列表/表格结构,公式用 LaTeX 保存;草稿可在待归档页直接编辑
- 绝不编造:读不准的内容写进「待人工确认」,交给人核对
- 笔迹颜色筛选:/note 和 /mistake 可分别设置「提取的颜色 / 忽略的颜色」,只整理指定颜色笔迹(设置页 Prompt 配置里修改)
- 卡片即 Markdown:library/<学科>/<卷子>/cards/.md,带 front-matter,可手改、可 diff、可进版本库
- 笔记即 Markdown:library/notes/<标题>/note.md,原扫描图放在同目录的 source/、bands/ 作为对照
- 知识点索引:自动重建 index.md / index.json,按 学科 → 一级 → 二级知识点 归类
- 导出打印版 PDF:板块(含自定义板块)可勾选、可排序;公式以 Word 原生公式(OMML)排版,不是 Unicode 拼凑;原卷按卡片记录的多个读取区域一起附图
- 回收站:删除先进 _trash/,可逐项还原,清空才真正销毁
- 会话可追溯:待归档页可跳回分析会话继续修改
- Prompt 配置:设置页按文档类型分别展示任务书/格式约定;错题支持 PDF 板块与自定义板块,两种类型都支持笔迹颜色设置

更新记录见 CHANGELOG.md。

界面

| 已归档 · 浏览(按知识点索引) | 已归档 · 管理(导出 / 删除 / 回收站) |
| 已归档浏览 | 已归档管理 |

| 设置 · Prompt 配置与 PDF 模板 | 待归档(空状态) |
| 设置页 Prompt 配置 | 待归档 |

- 「已归档 · 浏览」左栏是学科 → 一级知识点 → 二级知识点的索引树,右栏是卡片列表;点卡片可对照原卷裁剪图查看转录。
- 「已归档 · 管理」里导出 PDF、管理导出文件、删除卡片(进回收站)与还原。
- 「设置」里左侧是可收起的 Prompt 配置;PDF 模板是统一列表(预设板块 + 自定义板块),可拖动顺序、勾选包含、编辑说明,列表下方可新增自定义板块。

环境要求

- DSH(DeepSeek Harness)桌面版,Web/桌面 profile 均可。要求 DSH >= 0.2.1-rc.2
- 分析模型需要支持图片输入(插件启动前会校验,不支持会直接报错而不是静默失败)
- Node.js ≥ 22(DSH 自带运行时已满足)

安装

目前只通过 GitHub 分发(npm 包尚未发布)。

方式一:从 GitHub 安装(推荐)

dsh plugin --profile desktop add github:suanmingxing/dsh-ai-mistake-book

把 desktop 换成你实际使用的 profile(桌面版通常是 desktop,dsh web 用 web)。
装完重启 DeepSeek Harness 生效。

方式二:本地目录(开发/调试)

git clone https://github.com/suanmingxing/dsh-ai-mistake-book.git D:\tools\dsh-ai-mistake-book
dsh plugin --profile desktop add "link:D:/tools/dsh-ai-mistake-book"

link: 安装时 pnpm 不会替插件装 dependencies,所以本仓库已把必要依赖放在 node_modules/ 里一并提交(见 VENDOR.md)。若你删掉了它,请手动补装:npm i @deepseek-ai/schemastery @deepseek-ai/cosmokit katex。

首次使用

1. 设置归档根:设置 → 插件 → AI 错题本 → archiveRoot,填一个你希望存放错题本的绝对路径(默认 ~/.dsh/ai-mistake-book)。改这个字段需要重启插件。
2. 建一个「归档工作区」会话:在 DSH 里打开该目录作为工作区(首次 /mistake 会自动创建)。
3. 投喂试卷: /mistake 错题为 3、5、6、8、9、11 题 @"C:\path\to\扫描卷.pdf"

或在插件页用模型工具 mistake_ingest 指定文件路径。
4. 等分析:分析在当前会话里进行;期间该会话的工具会被临时收窄到 4 个(读页面、提交候选、提交决定、问用户确认),结束后自动恢复。
5. 确认归档:插件页 →「待归档」核对候选 → 确认归档;之后到「已归档 → 管理」导出 PDF 或删除。正式归档需在插件页确认。
6. 定制版式与提词(可选):到「设置 → AI 错题本」的 Prompt 配置里改分析任务书、背景、错因分类;在 ⑤ PDF 导出模板里调整板块顺序、勾选或新增自定义板块。改完点「保存全部修改」,分析新试卷时生效。
7. 转录手写笔记(可选): /note 第三章 线性方程组 @"C:\path\to\笔记.pdf"

分析完成后到「待归档」核对/编辑标题与正文,确认归档;之后在「已归档 → 笔记」查看。

手写笔记:/note

/note 与 /mistake 共用投喂/光栅化/归档流程,但输出不是错题卡片,而是一篇 Markdown 笔记:

- 多页一起处理:模型逐页读图后,可用 pages 数组一次提交多页;单页内容太长时用 chunk 分块续写,不用担心长笔记被截断。
- 忠实转录:保留原笔记的标题层级、编号、列表、表格;公式写成 $...$ / $$...$$;图形无法转录时用 [图:…] 占位并标进「待人工确认」,不编造。
- 待归档可编辑:标题、学科、正文都能在插件页直接改;点「确认归档」会先保存再归档(标题会变成 library/notes/<标题>/ 的目录名,重名自动加序号)。
- 已归档查看:渲染 Markdown 公式,并列出原扫描页(source/、bands/)链接,便于对照。
- 笔迹颜色:如果一页上有多种颜色的笔迹,可在设置页分别给「笔记」和「错题本」设置提取/忽略颜色(见下一节)。

数据与隐私

- 所有数据都在你自己的机器上:试卷、转录、卡片、导出件都在 archiveRoot 下,插件不向任何第三方服务上传内容
- 模型调用走你 DSH 里配置的 provider(同样的调用链路,不会额外外发)
- 归档根结构:

<archiveRoot>/
├─ inbox/<batchId>/ 进行中的批次(原始扫描、光栅图、笔记分页 part) ├─ library/<学科>/<卷子>/cards/.md 归档后的错题卡片 ├─ library/notes/<标题>/note.md 归档后的电子笔记(同目录 source/、bands/ 为原图) ├─ templates/ 可编辑的提示词(analysis / background / error-taxonomy / note-analysis / note-format / custom-templates.json / ink-colors.json) ├─ exports/ 导出的 PDF ├─ export-settings.json PDF 导出模板(板块顺序/勾选/预设说明/原卷图) ├─ _trash/ 回收站 └─ index.md / index.json 自动生成的索引(含卡片与笔记)

主要设置项

| 设置 | 默认 | 说明 |
| archiveRoot | ~/.dsh/ai-mistake-book | 错题本存放位置 |
| pdfDpi / overviewDpi | 400 / 200 | 横带与整页概览的分辨率 |
| pagesPerRequest | 2 | 一次投喂几页(每页 1 概览 + N 横带) |
| maxRecutsPerPage | 4 | 每页原生重切配额 |
| restrictAnalysisTools | true | 分析期间收窄会话工具集 |
| analysisProvider / analysisModel | 空 | 空 = 用部署默认;必须支持图片 |
| deleteToTrash | true | 删除进回收站而非销毁 |

设置页:设置选项与 Prompt 配置

设置页只有两块:

- 设置选项(置顶,只读):当前生效的模型、光栅化、导出与存储参数;真正的修改入口在 DSH 的「设置 → 插件 → AI 错题本」。
- Prompt 配置(单列,按模型实际接收顺序,所有板块都可收起/展开):顶部先选文档类型(错题本 / 笔记),两种类型的配置完全独立。

错题本:
1. 分析任务书(templates/analysis.md)——主体;{{background}} / {{taxonomy}} / {{custom}} 是插入点
2. 难度与学段背景(templates/background.md)
3. 错因分类(templates/error-taxonomy.md)
4. 系统自动追加(只读折叠)——每批次固定追加的工具调用速记
5. 笔迹颜色——提取/忽略两栏(见下)
6. PDF 导出模板——统一列表:六个预设板块 + 自定义板块,可勾选、↑↓ 排序、编辑说明;列表最下方可「新增模板」
- 说明会写进分析提示词;停用的自定义板块不会被当成"未登记标题"塞回 PDF 末尾

笔记:
1. 笔记转录任务书(templates/note-analysis.md)——转录规则、逐页/多页提交、公式与结构保留
2. 笔记格式约定(templates/note-format.md)——标题层级/公式/列表/表格
3. 系统自动追加(只读折叠)
4. 笔迹颜色——同上,笔记与错题本的规则互不影响

笔迹颜色:提取颜色非空时只处理这些颜色的笔迹;忽略颜色会被跳过;两栏都为空 = 不限制。可点常用颜色快捷添加,也可手输自定义颜色名;同一颜色不能同时出现在两栏。保存后下一次分析生效(不影响进行中的批次)。颜色筛选通过提示词约束模型完成,不是图像像素级遮罩。

不会自动保存:改完点「保存全部修改」;每块的「恢复默认」只改草稿,仍需保存。PDF 导出时「管理」页还可以对这一次导出做临时覆盖。

依赖说明

本插件在 node_modules/ 里随包提交了三份依赖(合计约 0.7 MB):@deepseek-ai/schemastery、@deepseek-ai/cosmokit(DSH 发布版,公开 npm 同版本)、katex。原因与升级方式见 VENDOR.md。

katex 仅用于会话内的公式预览(MathML),缺失时会降级为纯文本,不影响归档。

已知限制

- 公式排版覆盖错题卡常见写法(分数、根式、上下标、向量、\left…\right、希腊字母与常用运算符);矩阵、分段函数等结构暂不支持,会退化为可读文本
- 分析依赖模型的视觉能力;看不清的字段会进入"待人工确认",不会猜测
- 笔迹颜色筛选是提示词级的(模型按颜色取舍),不是图像像素级遮罩;笔迹颜色非常接近或扫描偏色时可能不完美
- 笔记中的图形/示意图用 [图:…] 文字占位,不会转成矢量图;笔记暂不导出 PDF(后续版本再评估)
- 界面文案提供中/英两份字典,提示词模板本身默认中文

许可证

MIT © 2026 suanmingxing
预览分享卡片长什么样 ↓suanmingxing/dsh-ai-mistake-book
分享 · DeepSeek Harness Hub
suanmingxing/dsh-ai-mistake-book

AI 错题本:把扫描试卷整理成以知识点为索引的错题合集dsh-plugin

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部