docs: 更新 CLAUDE.md 与 README.md 至当前代码状态
补充 eval.js/grammar 文件说明、三种模式与口诀范围介绍、 /stt 带题目参数的示例、多音色评测的音色全名注意事项 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
10
CLAUDE.md
10
CLAUDE.md
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
小学生乘法口诀(九九表)语音背诵小程序。核心交互:**自动读题 → 小朋友开口说答案 → 本地离线语音识别判分**,全程免手(hands-free)。三种模式:顺序闯关、随机挑战(随机模式对错题动态加权)、双人抢答(键盘/蓝牙手柄按键抢答,抢到者语音作答,抢答内部又分顺序/随机出题)。**UI 只面向 PC / Pad(≥760px),不做手机端适配**,风格参考多邻国(高饱和主色 + 厚底 3D 按钮 + 大圆角 + 弹跳动效)。
|
小学生乘法口诀(九九表)语音背诵小程序。核心交互:**自动读题 → 小朋友开口说答案 → 本地离线语音识别判分**,全程免手(hands-free)。三种模式:顺序闯关、随机挑战(随机模式对错题动态加权)、双人抢答(键盘/蓝牙手柄按键抢答,抢到者语音作答,抢答内部又分顺序/随机出题)。**UI 只面向 PC / Pad(≥760px),不做手机端适配**,风格参考多邻国(高饱和主色 + 厚底 3D 按钮 + 大圆角 + 弹跳动效)。
|
||||||
|
|
||||||
只有两份代码文件:`index.html`(前端单页,含全部 UI/逻辑)和 `server.js`(后端,零 npm 依赖)。没有构建步骤、没有 `package.json`、没有 `node_modules`、没有测试框架。
|
代码文件:`index.html`(前端单页,含全部 UI/逻辑)、`server.js`(后端,零 npm 依赖)、`grammar/number.gbnf`(whisper 解码语法约束的静态兜底)、`eval.js`(识别回归评测,零依赖)。没有构建步骤、没有 `package.json`、没有 `node_modules`、没有测试框架。
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@@ -21,10 +21,10 @@ bash start.sh # 或 node server.js
|
|||||||
node -e "new (require('vm').Script)(require('fs').readFileSync('server.js','utf8'));console.log('server ok')"
|
node -e "new (require('vm').Script)(require('fs').readFileSync('server.js','utf8'));console.log('server ok')"
|
||||||
node -e "const m=require('fs').readFileSync('index.html','utf8').match(/<script>([\s\S]*?)<\/script>/)[1];new (require('vm').Script)(m);console.log('frontend ok')"
|
node -e "const m=require('fs').readFileSync('index.html','utf8').match(/<script>([\s\S]*?)<\/script>/)[1];new (require('vm').Script)(m);console.log('frontend ok')"
|
||||||
|
|
||||||
# 端到端验证识别流水线(生成中文语音 → 打 /stt)
|
# 端到端验证识别流水线(生成中文语音 → 打 /stt,带 a/b 走按题动态 grammar)
|
||||||
say -v Tingting "三七二十一" -o /tmp/t.aiff
|
say -v Tingting "三七二十一" -o /tmp/t.aiff
|
||||||
ffmpeg -y -i /tmp/t.aiff -c:a libopus /tmp/t.webm
|
ffmpeg -y -i /tmp/t.aiff -c:a libopus /tmp/t.webm
|
||||||
curl -s -X POST --data-binary @/tmp/t.webm -H "Content-Type: audio/webm" http://localhost:8000/stt
|
curl -s -X POST --data-binary @/tmp/t.webm -H "Content-Type: audio/webm" "http://localhost:8000/stt?a=3&b=7"
|
||||||
|
|
||||||
# 切换到更快的 base 模型
|
# 切换到更快的 base 模型
|
||||||
WHISPER_MODEL=models/ggml-base.bin node server.js
|
WHISPER_MODEL=models/ggml-base.bin node server.js
|
||||||
@@ -32,7 +32,7 @@ WHISPER_MODEL=models/ggml-base.bin node server.js
|
|||||||
# 识别准确率回归评测(需先启动服务;改 grammar/判分/whisper 参数后必跑)
|
# 识别准确率回归评测(需先启动服务;改 grammar/判分/whisper 参数后必跑)
|
||||||
node eval.js # 45 题 × (完整口诀/只说得数/错误答案) 全量
|
node eval.js # 45 题 × (完整口诀/只说得数/错误答案) 全量
|
||||||
QUICK=1 node eval.js # 抽样快跑
|
QUICK=1 node eval.js # 抽样快跑
|
||||||
VOICES=Tingting,Shelley node eval.js # 多音色
|
VOICES="Tingting,Shelley (中文(中国大陆))" node eval.js # 多音色(同名英/中两版,必须用带中文后缀的全名)
|
||||||
```
|
```
|
||||||
|
|
||||||
**改动 `index.html` 里判分/解析逻辑(`judge`/`parseNumToken`/`extractLastNumber`)后**,务必把纯函数抠出来跑一批中文数字用例(`二十一`/`二一`/`21`/`三七二十一`/`答案是二十一` 等都应判对),这是最易回归的部分。
|
**改动 `index.html` 里判分/解析逻辑(`judge`/`parseNumToken`/`extractLastNumber`)后**,务必把纯函数抠出来跑一批中文数字用例(`二十一`/`二一`/`21`/`三七二十一`/`答案是二十一` 等都应判对),这是最易回归的部分。
|
||||||
@@ -64,7 +64,7 @@ VOICES=Tingting,Shelley node eval.js # 多音色
|
|||||||
- **双人抢答模式**(match 页,左右玩家 + 中间出题区):`enterMatch()` 进大厅(可选顺序/随机出题 `matchOrder`,顺序=题池过一遍、随机=`CONFIG.matchQuestions` 题)→ `matchStart()`/`matchNext()` 出题 → 抢答窗口内 `matchKeydown`(键盘)/`padPoll`(Gamepad API 轮询,边沿触发)命中绑定键则 `buzz(side)` → 抢到者走同一套录音闭环作答(`buzzAt` 起算的 **A 秒硬截止**:重录只用剩余窗口、到点 `matchOvertime()` 直接判超时,不像单人模式可无限重试)。**作答终局统一走 `settle(correct,timedOut)` 路由**:抢答模式进 `matchResolve`(答对 +5 / 答错超时 −2,一局结束 `matchFinish` 显示冠军),单人模式进 `resolve`——改录音/判分闭环时两个模式都要过一遍。抢答键绑定 `buzzKeys` 存 localStorage(`calx-buzz`),支持键盘键码和手柄(pad 序号+按钮号);录音 UI 元素(`micBtn`/`heard`/计时条)经 `bindRecUI()` 在 game/match 两页间重指向,数字键盘 DOM 节点在两页间搬移(`mPadSlot`)。
|
- **双人抢答模式**(match 页,左右玩家 + 中间出题区):`enterMatch()` 进大厅(可选顺序/随机出题 `matchOrder`,顺序=题池过一遍、随机=`CONFIG.matchQuestions` 题)→ `matchStart()`/`matchNext()` 出题 → 抢答窗口内 `matchKeydown`(键盘)/`padPoll`(Gamepad API 轮询,边沿触发)命中绑定键则 `buzz(side)` → 抢到者走同一套录音闭环作答(`buzzAt` 起算的 **A 秒硬截止**:重录只用剩余窗口、到点 `matchOvertime()` 直接判超时,不像单人模式可无限重试)。**作答终局统一走 `settle(correct,timedOut)` 路由**:抢答模式进 `matchResolve`(答对 +5 / 答错超时 −2,一局结束 `matchFinish` 显示冠军),单人模式进 `resolve`——改录音/判分闭环时两个模式都要过一遍。抢答键绑定 `buzzKeys` 存 localStorage(`calx-buzz`),支持键盘键码和手柄(pad 序号+按钮号);录音 UI 元素(`micBtn`/`heard`/计时条)经 `bindRecUI()` 在 game/match 两页间重指向,数字键盘 DOM 节点在两页间搬移(`mPadSlot`)。
|
||||||
|
|
||||||
### 前端所有可调参数集中在 `index.html` 顶部的 `CONFIG`
|
### 前端所有可调参数集中在 `index.html` 顶部的 `CONFIG`
|
||||||
读题开关、限时秒数、随机题数、错题加权系数、VAD 灵敏度(`vadThreshold`/`vadSilenceMs`)、重录次数等。首页「⚙️ 家长设置」面板直接绑定其中常用项。
|
读题开关、口诀范围(`tableMin/tableMax`)、限时秒数、随机题数、错题加权系数、抢答参数(`matchBuzzMs`/`matchAnswerMs`/`matchQuestions`/加减分)、VAD 灵敏度(`vadThreshold`/`vadSilenceMs`)、重录次数等。首页「⚙️ 家长设置」面板直接绑定其中常用项。
|
||||||
|
|
||||||
## 平台约束(重要,别踩坑)
|
## 平台约束(重要,别踩坑)
|
||||||
|
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -1,9 +1,14 @@
|
|||||||
# 🦉 乘法口诀大闯关
|
# 🦉 乘法口诀大闯关
|
||||||
|
|
||||||
小学生乘法口诀语音背诵小程序:**自动读题 → 小朋友开口说答案 → 离线语音识别判分**,全程免手。
|
小学生乘法口诀语音背诵小程序:**自动读题 → 小朋友开口说答案 → 离线语音识别判分**,全程免手。
|
||||||
支持顺序闯关 / 随机挑战(错题动态加权,练熟自动减少)/ 双人抢答,限时作答、正/负反馈动效音效。
|
|
||||||
|
|
||||||
语音识别用 **whisper.cpp 本地离线模型**,不联网、不花钱、不上传任何数据到云端。
|
- **🐢 顺序闯关**:按口诀表顺序背,答错重问同题
|
||||||
|
- **🎲 随机挑战**:打乱抽题,错题/慢题动态加权多练,练熟自动减少
|
||||||
|
- **🆚 双人抢答**:键盘或蓝牙手柄按键抢答(可自定义绑定),抢到者限时开口作答,答对 +5、答错/超时 −2,一局结束加冕冠军
|
||||||
|
- **📖 口诀范围**:家长设置里可全局限定「几开头~几开头」(比如只练到 4 的口诀),三种模式共用
|
||||||
|
- 界面面向 **PC / Pad**(多邻国风格),麦克风不可用时自动降级为数字键盘
|
||||||
|
|
||||||
|
语音识别用 **whisper.cpp 本地离线模型**(按题动态语法约束解码 + 方言发音兼容),不联网、不花钱、不上传任何数据到云端。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,12 +16,13 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
calx/
|
calx/
|
||||||
├── index.html # 前端(单页面)
|
├── index.html # 前端(单页面,含全部 UI/逻辑)
|
||||||
├── server.js # 后端(零 npm 依赖,纯 Node)
|
├── server.js # 后端(零 npm 依赖,纯 Node)
|
||||||
├── start.sh # 一键启动
|
├── start.sh # 一键启动
|
||||||
├── bootstrap.sh # 新机一键部署
|
├── bootstrap.sh # 新机一键部署(装依赖 → 补模型 → 启动)
|
||||||
├── grammar/ # whisper 解码语法约束
|
├── eval.js # 识别准确率回归评测(开发用,见 CLAUDE.md)
|
||||||
└── models/
|
├── grammar/ # whisper 解码语法约束(静态兜底)
|
||||||
|
└── models/ # 识别模型(git 不追踪,bootstrap 自动下载)
|
||||||
├── ggml-small.bin # 中文识别模型(默认,较准,465MB)
|
├── ggml-small.bin # 中文识别模型(默认,较准,465MB)
|
||||||
└── ggml-base.bin # 备用模型(较快,141MB)
|
└── ggml-base.bin # 备用模型(较快,141MB)
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user