dsh-cet4 · 四级训练台
非官方项目:与全国大学英语四六级考试的主办机构、命题方、出版方均无隶属、合作或授权关系。
装完就能用:包里带一份完全原创的示例题库(426 个自编核心词 + 1 套原创模拟卷,听力由系统语音朗读), 打开就能背词、做题、交卷。示例不是真题,也不含任何真题文字、真题录音或真题答案。
真题要自己准备:把自己合法取得的资料放进数据目录构建一次,示例会自动让位,版权归原权利人,请仅用于个人学习。
只给答案,不给解析:客观题交卷后只标对错与正确选项;翻译、作文只提供作答区,不内置参考译文与范文。 理由见 为什么不提供解析——答案册里没有的东西,程序不编。
DeepSeek Harness 插件。把词汇、听力、真题、翻译、写作放在同一个左侧栏面板里,进度只存本机。
功能
| 模块 | 做什么 |
|---|---|
| 核心词(约 1500) | 四级高频词,每 100 词一个单元;背单词 / 记单词 / 默写三种模式。示例题库带 426 词 |
| 大纲词(约 4500) | 完整大纲词表,同样是每 100 词一个单元、同样三种模式。示例题库没有这一套,卡片会自动隐藏 |
| 听力 | 按考期选套,25 题作答,交卷对答案。有录音时按篇目跳听;示例卷用系统语音朗读,交卷后才给原文 |
| 随机题测试 | 选词填空 / 长篇阅读 / 仔细阅读,随机抽卷,计时、交卷、退出自动保存 |
| 片段翻译 | 部分翻译(句子)与全篇翻译(整段)两种模式,只提供作答区与计时 |
| 作文书写 | 随机抽写作题,30 分钟倒计时,实时词数 / 句数统计 |
| 生词本 | 练习时点 ☆ 收词,复习、搜索、导入导出 |
| 错词 / 错题本 | 默写错词与交卷错题自动归档,可单独重练或回原卷重做 |
| 今日复习 | 学过但隔天没再碰过的词,用默写过一遍刷新记忆时间 |
词表数量取决于你手上的词表文件,界面统一写「约」。
几个刻意的设计:
- 一个页面只出现一个单词。 三种模式共享同一个位置游标,切换模式不会把你打回第 1 个词。
- 默写按词长给提示。 长度 > 5 给 3 个首字母,4–5 给 2 个,≤ 3 给 1 个。
- 只给答案,不给解析。 见 为什么不提供解析。
安装
# 1) 在 DSH 的 profile 目录里装包
npm install dsh-cet4
- 把包登记进 profile 的 bundle 列表,否则装完左侧栏不会出现图标。编辑
<profile>/package.json(Windows 一般在C:\Users\<你>\.dsh\profiles\desktop\package.json):
{
"dependencies": {
"dsh-cet4": "^2.3.0"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-cet4"
]
}
}
}
- 重启 DSH,左侧栏出现「CET-4 训练台」。打开就能用:首屏是内置示例内容(右上角有「示例」徽标), 背词、做听力、选词、阅读、翻译、作文都能走完整流程。要换成自己的真题,见 准备题库。
插件通过 cordis.patch.yml 插进 profile 的层级栈,客户端通过 lib/client.js 在左侧栏注册图标,
面板本体是 iframe,指向宿主托管的 /cet4/app/index.html。
宿主侧只做两件事:用 webServer 把本插件的 app/ 与题库目录挂在 /cet4 前缀下,
并在 /cet4/media/<track> 上按 HTTP Range 推流录音文件(不复制、不转码)。
内置示例内容(装完即用)
包里 starter/ 是一份原创示例题库,作用只是让你装完立刻能上手,不冒充真题:
| 内容 | 说明 |
|---|---|
| 426 个核心词 | 词形 + 音标 + 中文释义 + 例句;释义、例句与译文都是本项目自写 |
| 1 套原创模拟卷 | 听力 25 题(8 篇:3 新闻 / 2 长对话 / 3 短文)、选词 10、长篇阅读 10、仔细阅读 10、翻译、作文 |
| 听力 | 没有音频文件:用浏览器语音合成(Web Speech API)在本机实时朗读,可按篇目单读、可暂停、可调语速;原文在交卷后才出现 |
三点要说明白:
- 不是真题,也不从真题改写。
NOTICE.md第 3 节逐文件写了来源与许可。 - 想换成自己的就换:把自备题库构建到数据目录,示例自动让位;想换回示例,删掉数据目录里的
index.json即可。 - 音色取决于你的电脑:Windows 一般自带英文语音;万一环境没有语音合成,听力页会明说听不了,其余模块照常。
数据目录的解析顺序(lib/data-dir.js):
CET4_DATA → ~/.dsh/dsh-cet4/data → 插件内 data/(仅开发) → 插件内 starter/
准备题库
示例只是兜底。要用自己的真题,从首页的「换成我的真题」或设置里的「准备我自己的真题」进入引导页, 它是一份可照着做的三步流程,而不是一句报错:
- 画出资料目录该长的样子(
01–05五个目录,前两位是识别的依据)。 - 选一次你自己的资料目录,页面在本地核一遍结构:缺哪个目录、一共多少套卷、答案 CSV 表头对不对、 多少份原文与录音。只读文件名与前 512 字节,不上传任何内容。
- 按你填的路径拼出构建命令,一键复制。这一步在自检通过(或只有“可选资料缺失”)之后才解锁; 自检没通过时,它会告诉你还差哪一项。
下面是把这三步写下来的版本。
题库放在哪
默认 ~/.dsh/dsh-cet4/data(Windows:C:\Users\<你>\.dsh\dsh-cet4\data)。
放在插件目录外是刻意的:插件实际安装在 <profile>/node_modules/dsh-cet4/,
npm update 或重装会整目录替换,写在那里会连题库一起丢掉;往 node_modules 里写文件也不合规矩。
想换位置就设环境变量 CET4_DATA(指向 data 目录本身),宿主与构建脚本都认它:
CET4_DATA=D:/cet4-data npm run build:data -- --src "D:/CET-4"
解析顺序:CET4_DATA → ~/.dsh/dsh-cet4/data → 插件目录内的 data/(只用于本项目开发)。
资料目录长得什么样
<资料目录>/
01 真题试卷…/2023年6月/第1套/….pdf 真题 PDF(含听力原文、阅读、翻译、作文题)
02 答案(不含解析)/….csv 答案总表:场次,套数,题号,题型,答案,选词填空原词
03 听力原文(录音转写)/YYYY年M月第N套_听力原文.txt
04 词汇/四级核心词汇1500…csv、四级大纲词汇4500…csv
05 听力音频/四级YYYY年M月第N套听力音频.aac
目录名前缀(01…05)是识别的依据,后面的名字随便改。然后:
npm run build:data -- --src "D:/CET-4" # 构建题库(默认写到 ~/.dsh/dsh-cet4/data)
npm run build:data -- --src "..." --out ./data # 想放到别处
npm run check:data # 体检:答案数、选项、音轨是否齐全
构建要读真题 PDF,这里有三条路,任选一条:
装了
workbuddy-pdf(DSH 自带的那份在~/.workbuddy/external-packages/pdf-cli/)——构建会自动找到,什么都不用配。换一个抽取器:
CET4_PDF_CLI=/path/to/pdftotext-wrapper,调用约定与workbuddy-pdf一致:<cli> <input.pdf> <output.txt> --format txt。完全不用抽取器:把 PDF 的文本存成同名
.txt,放在 PDF 旁边(xxx.pdf↔xxx.txt)。 有同名.txt时构建直接读它,连 PDF 都不打开;也可以只放.txt、不放 PDF —— 这种「纯文本卷」 会被当成一份正常的卷解析。.txt的排版要和抽取结果一致:一行一段、四个选项各占一行、空行分段 (拿一份现成的.txt对照着排最稳)。构建开头会检查这台机器上有没有抽取器,没有就在
notes里提示"将改用同名 .txt", 不会等到跑到一半才报错。
产物:
| 文件 | 内容 |
|---|---|
index.json |
卷宗清单、词表规模、录音统计、生成时间与来源路径 |
papers/<id>.json |
每套卷的听力(8 篇 / 25 题 / 分段起止时间 / 原文)、选词、长篇、阅读、翻译、作文、答案 |
vocab-1500.json |
核心词表(释义、音标、例句、考频) |
vocab-4500.json |
大纲词表,例句从核心表里能对上的词借过来 |
media.json |
音轨 → 源音频文件的相对路径,供宿主按 Range 推流 |
build-report.json |
构建统计、notes(可解释的特殊处理)、warnings(已自动降级)、problems(必须修的问题) |
构建完请确认 problems 为空。当前资料(2023.6–2026.6,21 套)的实测结果是:
21 套卷 · 1482 + 4500 词 · 14 份录音(覆盖 21 套)· 15 套有听力原文
可听 21 套 = 14 份录音 + 7 套沿用同考期第 1 套;其中 6 套录音归属按套号推定,建议自己听一遍核对
原文 15 套 = 10 份原文文件(5 个考期各覆盖第 1、2 套)+ 第 3 套沿用同考期第 1 套;2025.12、2026.06 共 6 套没有
notes:逐条写明特殊处理(例如“第 3 套听力借用第 1 套”,真题 PDF 本身就这么注明)
录音与试卷怎么对应
这是最容易出错的地方,所以构建时做了三道处理:
文件名不可信时按内容归属。 把听力原文里的题干、选项和每套卷的听力选项做关键词重合度比对, 正确配对重合度 52–61%,错误配对只有 19–28%,据此确定某份录音属于哪一套。
没有原文时按文件名推定,并标记出来。 这类卷宗
audioVerified: false,听力菜单里会显示 「录音按套号推定」,提示你自己听一遍确认。分段表(
audio-tracks.json)不随包发布,并且会被音频时长校验。 它记的是「某份录音第 N 篇从第几秒到 第几秒」,只对特定的音源成立。换了录音还沿用旧表,跳篇就会落到错误位置 —— 所以构建时用 ADTS 帧数算出 音频真实时长,任何一段的end超出时长就整份作废(退回整段播放,不显示篇目按钮),并在build-report.json的warnings里记一条。分段表的查找顺序:--tracks <file> → CET4_TRACKS → <资料目录>/audio-tracks.json → <05 听力音频>/audio-tracks.json → ~/.dsh/dsh-cet4/audio-tracks.json没有分段表也能用,只是没有「新闻1 / 对话1 / 短文1」这排跳转按钮,录音整段播放。
另外,真题第 3 套常在 PDF 里注明「本套听力内容与第 1 套相同」,构建时整段借用并在
build-report.json 的 notes 里记一条。
音频与题目在数据层是绑定的(papers/<id>.json 的 listening.track + 每篇的 start / end),
前端点篇目时按 start 定位,播到 end 自动暂停。
为什么不提供解析
答案册里只有答案。译文、范文、逐题解析都不在其中,所以插件不生成、也不收录它们 —— 与其编一段 看起来很像的解析让使用者当标准答案背,不如老实只给对错。
同理,翻译与作文两个模块只提供作答区、计时和词数统计,不给参考译文与范文。作答内容保存在本机, 可以自己拿去对照纸质资料或别的工具。
安全与隐私
- 只服务本机。
/cet4下所有路由都会检查remoteAddress,非回环请求直接 403。 如果确实需要在远程访问 DSH 时用,设CET4_ALLOW_REMOTE=1—— 但那等于把你自己的录音对外提供, 后果自负。注意:如果 DSH 自己在前面做了反向代理,转发到插件的连接看起来仍是本机,这道校验就失效了, 此时请靠 DSH 自身的端口暴露范围来兜底。 - 只暴露两个目录。
/cet4/app/*与/cet4/data/*,路径越界一律 404;源码、构建脚本、.cache/都不会被访问到。 - 录音只按白名单取。 只有
media.json里登记过的音轨 id 能取文件,解析后还要校验仍在资料目录之内。 - 学习记录只在浏览器。 localStorage 键
cet4.state.v4,不上传任何服务器。 - 静态资源带 CSP(
default-src 'self'),只能被宿主 GUI 自己嵌。
目录结构
dsh-cet4/
index.js 宿主:/cet4 静态托管 + /cet4/media Range 推流 + 回环校验
lib/client.js 客户端:左侧栏图标 + iframe 面板
lib/data-dir.js 题库目录解析(宿主与构建脚本共用)
locale/{zh,en}.json 面板标题与描述
cordis.patch.yml bundle 补丁
app/
index.html
styles.css
js/store.js 状态与 localStorage(键 cet4.state.v4)
js/ui.js toast / confirm / 弹层 / 选项渲染
js/setup.js 「准备题库」引导页 + 资料目录结构自检
js/app.js 首页九张卡、设置、主题
js/vocab.js 词表单元、三种模式、默写判分
js/listening.js 听力菜单、音频播放、25 题作答与交卷
js/quiz.js 随机题(选词 / 长篇 / 阅读)、计时、交卷
js/translate.js 片段翻译
js/writing.js 作文
js/notebook.js 生词本
js/wrong.js 错词 / 错题本
starter/ 内置原创示例题库(随包分发:无真题、无音频)
index.json 索引,kind=starter
vocab-1500.json 426 个自编核心词
papers/mock-01.json 1 套原创模拟卷(听力走语音合成)
media.json 空音轨表
build/
build.mjs 题库构建
validate-data.mjs 数据体检
check-starter.mjs 示例题库发版护栏(无音频 / kind / 词数自洽)
serve-plugin.mjs 不开 DSH,单独跑一遍宿主路由
e2e.mjs 无头浏览器回归
test-client.mjs 客户端外壳静态检查
你的题库、录音、分段表都不在上面的树里 —— 它们在 ~/.dsh/dsh-cet4/。
只有 starter/ 随包走,因为它是原创内容,可以公开分发。
维护
npm run build:data -- --src "D:/CET-4" # 重抽 PDF/CSV 生成题库
npm run check:data # 数据体检
npm run check:starter # 示例题库护栏(改动 starter/ 后跑)
npm run preview:plugin # 起一个假宿主,浏览器开 http://127.0.0.1:8788/cet4/app/index.html
CET4_DATA=./starter node build/serve-plugin.mjs 8790 # 另起一个用内置示例数据的实例(避开 8788)
npm run test # 客户端静态检查 + 示例护栏 + 数据体检
npm run test:e2e # 无头浏览器跑一遍主要流程(需本机 Chrome/Edge)
npm run check:data 会拦下这些「看不出来但一定会坑人」的问题:答案数量不对、选词字母不在词库里、
长篇阅读答案指向不存在的段落、选项数不是 4、以及选项里混进了下一段的说明文字
(PDF 抽文本时最常见的粘连,比如 D 选项尾巴上挂着 “Questions 3 and 4 are based on…”)。
它还比对 index.json 里的录音统计与卷宗是否一致,避免前端显示“14 份录音 / 21 套可听”这种口径错乱。
npm run test:e2e 需要 puppeteer-core(不随包安装)。可以用 PUPPETEER_DIR 指向已有的安装目录,
用 CHROME_PATH 指定浏览器。
想把「准备题库」引导页也一起测,另起一个空题库的实例再指给 e2e:
CET4_DATA=./.cache/empty-data node build/serve-plugin.mjs 8790
CET4_EMPTY_BASE=http://127.0.0.1:8790/cet4/app/index.html npm run test:e2e
不设 CET4_EMPTY_BASE 时这一条会显示「跳过」,不算失败。
e2e 是开发自测,不是随插件交付的功能。 期望值(卷数、词数、单元数、录音份数)都从
index.json读;只有一套词表时「大纲词」相关的几条会自动跳过;kind: "starter"的示例题库走语音合成分支, 断言换成「有.tts-bar、没有<audio>、交卷后才给原文」。作者的两套数据(真题 / 示例)跑同一份脚本都是 32/32。 换成纯文本卷、既没录音也没原文的题库,听力相关的几条会失败,这属于预期。
改了 PDF 想强制重抽文本,加 --force:npm run build:data -- --force。
抽取结果缓存在 ~/.dsh/dsh-cet4/.cache/extract/,删掉即可重来。
已知限制
- 内置示例只有 426 词 + 1 套卷,够走完流程,不够当复习资料;真复习还是得导入自己的题库。
- 示例卷的听力是语音合成,不是真人录音:音色、语速取决于系统语音引擎;没有英语语音包时会禁用播放并提示, 只能交卷后看原文。它也读不出真实的考场感觉(没有停顿、没有连读)。
- 听力原文覆盖 21 套里的 15 套(来自 10 份原文文件):2025.12 与 2026.06 这两期的 6 套没有原文, 「原文」按钮不显示,听力题仍可正常作答、交卷后只给答案。
- 大纲词表本身不带例句:只能从核心词表里借到约三分之一,其余词的例句位置会显示「这个词表没收录例句」。
- 没有分段表时听力只能整段播放(不给按篇跳转)——这是刻意的,宁可不跳也不跳错。
- 录音是
.aac(ADTS AAC),Chrome / Edge / Safari 可直接播放;Firefox 在部分系统上不行。 - 学习记录在 localStorage,换浏览器或清缓存就没了,建议用生词本的导出功能定期备份。
- 只在
node >= 20上测过。
仓库与数据分仓
这个仓库只放代码、文档与原创示例(starter/),不放任何真题、真题录音、答案或真题词表内容。数据请放在:
- 本机资料目录(最简单),或
- 一个私有仓库(例如
mount9527/dsh-cet4-data),克隆到~/.dsh/dsh-cet4/data-pack后构建。
数据包的目录分类、命名规则、以后怎么加新卷/新音频/新词表,见
docs/data-pack.md。
为什么不能把真题放进公开仓库:试题与录音的著作权归原权利人,公开仓库等于向公众提供复制件, 不属于个人学习的合理使用。把仓库设成 Private 可以自由放数据;公开仓库只放代码最稳妥。 本 README 也不放真题截图——演示图同样属于对试题内容的复制。
发布
- npm:
npm publish(或打v*tag 走 .github/workflows/release.yml), 仓库 Secrets 里需要NPM_TOKEN。包内容由package.json的files白名单决定, 只有代码、内置示例(starter/)与文档;data/、data-pack/、.cache/都不会进包。 - 插件市场:用同一版本号发布 npm 后,在市场上提交包名
dsh-cet4即可(入口以市场说明为准)。 市场条目文案按「内置原创示例 + 可导入自备真题」写,不要写成「提供真题」。 - GitHub:代码仓公开;数据不要推到公开仓库(见上一节)。要给数据做版本管理就开一个私有仓。
- 发布物与 README 都不放真题截图,原因同上;示例内容的截图可以放。
许可
代码与 starter/ 里的原创示例内容均为 MIT(见 LICENSE)。许可不覆盖你自己准备的题库:
真题、录音、词汇资料的版权归原权利人,插件不附带也不分发这些内容,你的构建产物请自用。
详见 NOTICE.md。
No comments yet. Be the first to write one.