微镜 weijing-coach
> 口径版本行(任何输出都以此为准):
> 语速分母 = VAD 有效语音秒;朝向 = 三态(面向前 / 未面向镜头 / 不可测);
> 手部 = 腕点速率;音高判据 = 浊音 ≥ 3000 帧且占比 ≥ 0.10;报告骨架 = R3(10 节,含 1.5 时间线)。
触发词(口语)
试讲、微格教学、教学技能、片段教学、磨课、看看这节录像、哪里卡、试讲复盘、教态、走位、
口头禅多不多、语速快不快、候答、板书、课件用得多不多。
用户只要表达"帮我看看这段试讲录像 / 我哪里卡了"就进入本 Skill。
steps
- 确认输入:要一个视频文件(mp4/mov/avi 皆可)。没有视频就告诉用户怎么录:
正面机位、单人入镜、上半身入画、光线充足、声音清楚、录 5–15 分钟。 - 检查环境(一次即可):
bash python run.py --help python -c "import mediapipe, cv2, numpy, yaml, docx" # 缺哪个装哪个(见 requirements.txt) - 跑流水线(在 skill 目录里执行,
run.py就在这一层):
bash python run.py --video 试讲.mp4 --out out --asr mock
---asr mock:不跑声学模型,用fixtures/transcript_sample.json的词级时间戳
(只用于演示/冒烟,不能当成真实转写)。
---asr whisper:装了 faster-whisper / openai-whisper 才能用(首次会下载模型)。
---asr cloud:需要WEIJING_CLOUD_ASR_URL/WEIJING_CLOUD_ASR_KEY。
- 有课件(投影画面)时流水线自动检测 ROI;可用--roi x,y,w,h覆盖;--no-courseware关闭。
- 页面标题默认取视频文件名:请用--lesson 课题名 --teacher 姓名指定,
否则微信/剪辑软件导出的哈希文件名会退成通用标题「试讲复盘」。 - 读产物:
out/report.md(人读,叙述体)、out/report.docx(给导师)、
out/report_brief.docx(两页)、out/index.html(时间轴)、out/transcript.html(逐字稿)、
out/events.json(逐条证据)、out/metrics.json+out/coverage.json(口径与可测率)。 - 打开产物(必须做,不要只甩路径):跑完用 present_files 打开
out/index.html
(时间轴,可点播)与out/report_brief.docx(给导师的两页版)。
-index.html是单文件(events/metrics 的 JSON 已内联),双击用浏览器打开最稳;
- 若平台预览面板只显示封面和一行红字(部分预览器不执行网页脚本),改用本地 http 服务打开
同一目录:python -m http.server 8777 --bind 127.0.0.1,再访问http://127.0.0.1:8777/index.html
(要能拖动进度条,服务需支持 Range/206,标准库版只能整段下载);
- 它用相对路径引用同目录的video.mp4,因此整份out/要一起保留,只把 HTML 拷走会没有画面。 - 转述给用户时:先报"可测/不可测",再报现象与时间戳,最后才是"可能…有关"的归因,
并且每次都带导师复核提醒。不要自己给分数、排名、优良中差。
依赖与环境
- Python 3.10–3.12(3.13 上没有 numpy 1.26.4 / mediapipe 0.10.21 的轮子,装不上);Windows / macOS / Linux 均可。
- 必装:
numpy==1.26.4、opencv-python==4.10.0.84、mediapipe==0.10.21、
python-docx==1.2.0、PyYAML==6.0.3、imageio-ffmpeg==0.6.0(自带 ffmpeg 二进制,不依赖系统 ffmpeg)。 - 可选:
faster-whisper==1.2.1+av==12.3.0(可选依赖:只有--asr whisper才需要;
av必须钉 12.3.0,av 19 会让 faster-whisper 1.2.1 一加载就崩)。 - 安装:
bash python -m venv .venv .venv\Scripts\python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple - 装完先自检:
python run.py --check—— 逐项列出 Python 版本、六个必装包、ffmpeg 二进制、
路径是否纯 ASCII、rubric 是否完整,缺什么直接给pip install命令;全部[OK]再跑流水线。
这条命令不需要 numpy 也能执行(先于第三方导入),所以它是在裸环境里唯一能用的诊断入口。 - MediaPipe 需要纯 ASCII 路径:venv / 视频 / 输出目录都不要含中文,
否则 C++ 层报The path does not exist: ...binarypb。 - 单次分析耗时:10 分钟录像约 3~6 分钟(8fps 抽帧 + 姿态检测占大头)。
产出清单(四件套)
report_brief.docx—— 两页精简报告(叙述体:导语 + 数据句,不是表格堆),对外交付;index.html—— 时间轴 + 事件条 + 逐字稿,点每条结论都能跳到那一秒;transcript.html—— 逐字稿卡顿视图,卡在第几句一目了然;report.docx—— 长版留档(A4 / 1.5 倍行距 / 页脚页码 / 封面)。
> report.md 是同内容纯文本版,便于直接喂给大模型做纵向对比。
指标清单(42 项 = 语言 22 + 体态 13 + 课件 6 + 质量 1,与 rubric.groups 一致)
语言组(22):语速、静默占比、静默总时长、停顿次数、停顿频次、最长停顿、提问句数、提问频次、候答中位、
疑似填充音次数、疑似填充音密度(按录像时长)、疑似填充音密度(按说话时长)、疑似填充音聚簇、
口头禅频次、口头禅聚簇、连贯性弱衔接占比、重说频次、局部语速 P90、局部语速波动、
音高中位、音高幅度(半音)、有声帧占比
体态组(13):脸部可检出率、未面向镜头占比、不可测占比、手部速率中位、手部速率 P90、手部运动时长占比、
最长连续手基本不动、手基本不动段次数、站位中位偏移、站位活动幅度、站位横向累计路程、朝向一致率、朝向冲突率
课件组(6,术语是「课件画面状态」,不叫「页」):
课件画面状态数、状态停留中位、状态最短停留、状态切换频率、课件覆盖率、回看次数
数据质量(1):板书遮挡占比(未标定 ROI 时恒为「不可测」,仅内部记录)
本 Skill 不提供什么(都做过、失败或物理不可测)
| 不提供 | 原因 |
|---|---|
| 背对 | 用"脸看不见 + 人可见"推断,实测误报约 32%,已并入"未面向镜头" |
| 侧向前 | 轮廓宽度只测"平不平对镜头",分不出朝前朝后(几何对称),kappa 0.38 |
| 静态/动态手势分类 | 姿势判据反复误判("举着指黑板"漏检),已改为连续的手部运动速率 |
| 抬头/低头/转头 | 三者同源(solvePnP 的 pitch/yaw),544p 下误差可达 ±30° |
| 眼神/注视点 | 脸在画面里仅 40~50px,虹膜约 3px,物理上测不到 |
| 手势语义/指向 | 手部仅 42px,每根手指 5~10px |
| 照读比例 | 544p 画面里投影区仅 384×220,文字放大 4 倍后中文 OCR 识别率接近 0,不出数字也不以 0 代替 |
| 教学效果 / 学科知识对错 | 本工具只看可测行为,不评价教得好不好 |
不要"好心"加回来——每一条都试过并留有失败记录。
报告骨架(R3,10 节)
0 头部元信息 → 1 一页速览 → 1.5 按时间线读这节课 → 2 语言(2.1/2.2/2.3)→ 3 体态(3.1/3.2/3.3)
→ 4 课件(4.1/4.2)→ 5 数据质量与不可测 → 6 证据索引 → 7 指标摘要(机器可读)→ 8 边界声明
每节固定四段:导语句(1~2 句人话)→ 数据句(2~5 句,数字嵌在句中并带时间锚点)→ 精简表(≤6 行)
→ 口径句(1 句);第 1.5 节是 8~15 条时间线叙述(每条 ≤40 字,带 H:MM 与一个可核事实)。
第 7 节键序固定按 rubric.groups(language → body → courseware → quality),无课件案例也占 6 个课件键
(值写「本案例无课件画面」)。报告里不出现评价性词。
限制(必须如实告知用户)
- 不给总分、不排名、不评优良中差、不评学科知识对错。 报告首行固定"草稿,待导师复核"。
- 任何维度可测覆盖率 < 70% 时只写"不可测",不出数字;不要用 0 或推测值代替。
- 脸部可检出率是操作性定义:能检出脸 ≠ 面向学生(人眼核对假阳性约 20%~40%);
"未面向镜头"只陈述"脸不可检出但人体可见",不区分背向/低头/遮挡。 - 站位以画面左右计(不涉及讲台),靠肩中点 x 判定;单人正面机位才有效。
- 手部运动速率按体高归一化,未补偿景深:手靠近镜头读数会偏高,只能片内比较。
手部档位:手基本不动(含举着不动)/小幅/活动(手在动)/整体移动(不计入)/不可测。 - 音高:浊音 ≥ 3000 帧(30 秒)且占比 ≥ 0.10 才出中位基频与跨度,否则写"不可测"。
- 语速/局部语速的分母是 VAD 有效语音秒(全片 − 静音,与静默互斥),不是词时长之和。
- 卡顿(停顿/重说/口头禅)只来自 VAD 与词级时间戳,不看转写文本;ASR 洗掉的口误无法还原。
- 课件只认投影区域(ROI 自动检出):计量单位是「课件画面状态」,同一页 PPT 的动画展开也算新状态;
「回看」= 新状态与历史状态中位帧 MAE < 8。 - 参照值是文献型占位锚点,不是本工具语料实测;百分位只用于相对定位。
- 多人课堂、走动幅度大、机位不固定的录像不适用。
不该做的
- 不要用转写文本判断"卡顿/停顿";逐字稿页面只是把音频层的卡顿放进文本里显示。
- 不要在覆盖率不足时硬凑数字,也不要把
--asr mock的转写当真实识别结果汇报。 - 不要把归因写成结论;每条归因都要带反证条件。
- 不要新增评价性词(进步/退步/优秀/较差/很好/不好/提升/下降/改善/恶化/偏弱/不足/需要改进)。
交互细节
「展开轨道 / 收起轨道」是真过渡(grid-template-rows 走 280ms cubic-bezier(.22,1,.36,1),
与右侧检查器同一套曲线/时长变量),过渡期间每帧重排时间轴(游标与刻度跟随);
prefers-reduced-motion: reduce 下直接落到终值。
本目录里另外两份文档(平台不读,供人/Agent 手动查阅)
上传平台只把 SKILL.md 喂给模型:expert.md 与 README_FOR_AGENT.md 不会被自动加载,
所以凡是模型必须知道的规则(触发词、steps、口径版本行、不提供什么、限制、不该做的)都已写在
本文件里;下面两份是给人和接手者看的参考读物:
expert.md—— 教学法口径的长版说明:每个维度为什么这么定义、哪些结论不许下、话术边界与
导师复核的关注点。要扩写报告里的"为什么这么判"时以它为准;它不改变任何计算。README_FOR_AGENT.md—— 给接手 Agent 的速查:目录结构、常见坑(ASCII 路径、缓存分层、
mock 与真转写的区别)、改哪个文件会生效、冒烟命令。
三者冲突时的优先级:rubric.yaml(指标口径与阈值的唯一真源)> 本 SKILL.md 的「口径版本行」
> expert.md > README_FOR_AGENT.md。
改代码时先看这里
run.py 是唯一入口(本目录下),路径以 Path(__file__).parent 为基准,不含任何硬编码盘符;
指标口径在 rubric.yaml(唯一真源);报告结构在 scripts/render_report.py 的
build_report_blocks()(md 与 docx 同一份 block 列表)。