# 数智交互课件 × 课程发布助手 · 快速通道 · 集成方案

> 交付对象：仙人掌（《课程发布助手 · 快速通道》负责人）
> 作者：凯凯 · 2026-07-02 · **v1.1**（新增 craft / dialogue / assistant，修复 extend 死链）
> 目标：让《课程发布助手 · 快速通道》在建课时，自动为课时生成"数智交互课件"，实现老师交文档 → 产出可上课的交互课程。

---

## 一、背景：引擎已就绪，你只需生产 JSON

数智交互课件采用 **一个引擎 × N 份配置** 架构：

- **引擎（勿改）**：`https://agent.avatargaia.top/static/shuzhi-template-v2.html`
- **配置**：一份 JSON = 一堂交互课。引擎通过 `?config=<JSON的URL>` 加载
- **样板配置**（你的产出物长这样）：`https://agent.avatargaia.top/static/shuzhi-configs/course-qingming.json`
- 试玩样板：`https://agent.avatargaia.top/static/shuzhi-template-v2.html?config=/static/shuzhi-configs/course-qingming.json`

**你的任务 = 按课文内容生成 JSON → 上传拿 URL → 拼接引擎地址填进课时的 `htmlUrl`。**

---

## 二、模版新增步骤（插入《课程发布助手 · 快速通道》流程）

在现有"创建课时"步骤之后插入一步：

```
步骤 N：生成数智交互课件（agent 步骤）
  对每个（或老师指定的）课时：
  1. 从课时正文/原文档章节提取素材
  2. 按第三节的规范生成课件 JSON
  3. 上传 JSON：POST /api/upload
     - JSON 方式: { "filename": "course-{课时slug}.json",
                    "mimeType": "application/json",
                    "data": "<base64>" }
     - 返回 { "url": "/uploads/2026/07/xxx.json" }
  4. 课时 htmlUrl 设为:
     https://agent.avatargaia.top/static/shuzhi-template-v2.html?config=<上一步的url>
     （PATCH /api/templates/{courseId} 更新 stepsTemplate）
  5. 自测：打开该 URL 确认能加载（见第五节验收清单）
```

⚠️ 注意：更新的是**课程**的 stepsTemplate；你自己的任务模版**不要带 courseType 字段**（那是课程专用，带了会从模版库消失——上次的教训）。

---

## 三、课件 JSON 规范（核心工作）

### 3.1 顶层结构

```json
{
  "title": "课程名",
  "subtitle": "本课时主题",
  "mode": "self",
  "dataEndpoint": "",
  "roles": { "guide": {"name":"罗罗","emoji":"👦","color":"#e67e22"},
             "helper": {"name":"小小","emoji":"👧","color":"#e84393"} },
  "stages": [ ...组件数组，顺序即课堂顺序... ],
  "summary": { "role":"guide", "lines":[["环节","内容","目的"]], "homework":"课后挑战……" }
}
```

### 3.2 组件库（stages[].type）

| type | 用途 | 关键字段 |
|---|---|---|
| `media` | 情境导入（整页图/视频） | `image`/`video`, `caption`, `gate:"confirm"`（视频自动 ended 解锁） |
| `quest` | 选择题闯关（单选/多选/多题诊断） | 单题模式：`question`, `options:[{text,correct}]`, `feedbackRight/Wrong`。**多个 correct:true 自动变多选**（出确定按钮、全对才过）。**多题诊断模式**：改传 `questions:[{q,options:[{text,correct}]}]`（数组，每题必须恰好1个correct）+ `submitText`，N题同页作答一次性提交，自动评分出 A+/A/B+/B/C+/C 六级，**结果可直接喂给 `discuss.groupBy:{mode:"choice",stage:N}` 按等级分组**（"同质分组"）。⚠️ 层级只进教师端学情大屏，`feedbackRight` 给学生看的话里绝不能出现 A+/C 这类等级字样。两种模式二选一，不要同时传 `question` 和 `questions`。**问卷模式**（09-27）：单题模式加 `survey:true` → 不判对错、选项不用标 correct、选了就过关（`multi:true` 可多选），选择进班级选项分布、不计首正率。 |
| `sort` | **拖拽排序闯关**（拖动或▲▼调顺序→检查判分，触屏/鼠标皆可） | `answer:[...]`（正确顺序，引擎自动打乱展示）, `items:[...]`（可选，自定义初始乱序）, `feedbackRight/Wrong`。**适合：事件排序/流程步骤/游览路线/句子重组** |
| `embed` | **🔬 嵌入互动实验/任意网页**（iframe 关卡：仿真实验、探究工具、小游戏，让课件从"答题"升级到"动手做实验"） | `url`（必填，站内相对路径如 `/static/shuzhi-labs/xx.html` 或 `/uploads/...`）, `height`(px，默认640), `gate`: `"confirm"`按钮过关(默认) / `"none"`到达即过 / `"message"`实验页自己发过关信号, `minSeconds`(可选，探究满N秒才能过), `doneText`(按钮文案), `feedbackRight`(message模式过关提示语) |
| `blanks` | 课文填空探究 | `passage`, `blanks:[{label,answer[],hints[],placeholder}]` |
| `read` | 逐句美读打卡 | `sentences[]`, `done` |
| `table` | 方法梳理表格 | `rows:[{label,answer[],hints[]}]`, `done` |
| `create` | 自由创作+关键词检测 | `placeholder`, `minLength`, `keywords[]`, `guides[]`（三级引导）, `praise`, `submitText`/`resubmitText`（提交按钮文案，**不配则为通用的「提交给 AI 助教 ✉️」**；课程有具体接收角色时才配，如「交给王老师 ✉️」） |
| `discuss` | 小组讨论留痕（支持自动分组） | `prompt`, `timer`(秒), `capture:[{label,placeholder}]`, `done`, `groupBy`（可选，三种模式见下） |

**discuss.groupBy 三种分组模式**：
```json
{ "mode": "choice", "stage": 7 }            // 按第7关(craft/quest)的选择或等级自动分组，"同方式小组"/"同质分组"
{ "mode": "random", "count": 6, "names": ["雄鹰组","海燕组"] }  // 稳定随机分组（names 可省）
{ "mode": "pick", "count": 8 }              // 学生自选组号（老师口头分组时用）
```
配了 groupBy 后：学生看到大字组横幅 + **实时"同组同学"名单**（组长 ✍️ 高亮、自己标"（我）"，每 12 秒自动刷新，方便线下找到组员围坐讨论）；出现"✍️ 我是组长"开关——**组长必填产出，组员一键完成**；组名一确定即**可靠上报学情**（不再因节流丢组），大屏 + 学习者名单都自动按组聚合。

> ⚠️ **choice 模式的坑**：`stage` 指的是**同一份配置（同一节课时）内**的关卡序号——分组依据的那关（craft/quest 的选择）和 `discuss` 必须写在**同一个 config 里**。若把一节课拆成多个课时（每关一个 htmlUrl `&stage=N`），跨课时的选择读不到、分组会失败。**分组讨论务必让"选择 → 讨论"在同一节课里。**
| `extend` | 延伸学习链接卡 | `links:[{emoji,title,desc,url}]`（⚠️ url 没有真实地址就**留空**，引擎自动显示"敬请期待"，禁止填 `#`） |
| `craft` | 作品工坊：选形式+写要求→委托学生 Agent 创作并提交作品墙 | `forms:[{emoji,label}]`(可省用默认四种), `placeholder`, `praise` |
| `dialogue` | 与先贤对话（剧本式问答，话术全配置零LLM） | `figure:{name,emoji}`, `greeting`, `questions:[{q,a}]`, `minAsk`(问几个算完成), `outro` |

> 🎤 **角色配音（代入感神器）**：想让叶爷爷/小朋友等角色"开口说话"，用 basic-capabilities 的 tts.js 生成语音再挂进课件：
> `node ~/.openclaw/workspace/skills/basic-capabilities/scripts/tts.js "台词" out.mp3 --voice 3 --speed 2 --pitch 4`（老者慢沉男声）。发音人清单 `node .../tts.js --help`：男声1/3/106、女声0/5/111、童声4/110/103。生成的 mp3 上传后按 media/video 挂课时。

**主题皮肤（顶层 `theme`，一门课一个风格）**：
```json
"theme": { "primary": "#0f766e", "primary2": "#14b8a6", "heading": "#115e59",
           "bg": "linear-gradient(160deg,#f0fdfa,#ccfbf1)" }
```
- `primary` 主色（按钮/进度/边框全套自动派生），`primary2` 渐变第二色（可省），`bg` 底色支持纯色或 CSS 渐变字符串，`heading` 标题色（可省）
- 建议：古诗课古风棕金、科学课清爽蓝青、传统文化课暖橙（不配 theme = 默认暖橙）
- ⚠️ 底色请保持**浅色系**（文字是深色的，深底会看不清）

**🎨 主题皮系统 v1（换气质升级，可换皮）**：引擎自带 5 套皮 = 配色 + 闯关地图图标 + 撒花瓣一整套。三种选皮方式（优先级从高到低）：
1. URL 参数 `?skin=xxx` —— 现场换皮、强制覆盖，**演示利器**（学生刷新即变）
2. 顶层 `"skin": "xxx"` —— 课程默认皮
3. 顶层 `"skinDef": {...}` —— 自定义整套皮（见下，**推荐**）

内置皮：`city`古城🏮 / `space`星空🚀 / `land`山河🗺️ / `ocean`海洋🌊 / `candy`童趣🎈（都不配 = 默认古城暖橘）。

**自定义整套皮 `skinDef`（顶层字段，千课千面零依赖开发）**：
```json
"skinDef": {
  "key": "qingming",           // 皮标识；也可 ?skin=qingming 现场切
  "label": "清明上河图",
  "palette": { "primary":"#0f766e", "primary2":"#14b8a6", "heading":"#115e59",
               "bg":"linear-gradient(160deg,#f5f0e3,#e6ddc4)" },
  "track": "#0f766e",          // 闯关地图连线色
  "wp":    "🏮",               // 中间驿站图标
  "start": "🌅",               // 起点图标
  "end":   "🏯",               // 终点图标
  "hero":  "🧺",               // 沿旅程线行走的"旅人"
  "deco":  "🌸"                // 撒花/惊喜时刻的花瓣
}
```
- 字段全可选，缺了走默认；只写 `palette` 也行（图标用通用默认）
- `skinDef.palette` 主导配色（比顶层 `theme` 优先）；`?skin=` 参数最高优先，用于现场换皮
- 优先级：`?skin=` > `skin` > `skinDef` > `theme` > 默认古城
- 造皮就是选一组**贴合课程气质的图标 + 配色**：古画→🌅🏮🏯🧺🌸；海洋科普→⛵🐚🏝️🐬🌊；航天→🚀🪐🌟🛰️✨

**换气质自带能力（零配置生效，不用你写任何字段）**：进度条自动变"闯关旅程线"（起点→驿站→终点 + 旅人随进度走 + 逐段点亮）、每关淡入转场、答对撒花 + 连对3关大撒花、终点勋章成就墙。**每关可选** `"bgImage":"URL"` 给该关铺整屏背景图（情境用大图 / 方法探究用黑板 / 创作用画布）。

> 💡 **换皮不用改课程**：把配置 JSON **重传覆盖同一个 `/uploads` 文件名**、改里面的 `skin`/`skinDef` 即可，学生刷新即见新皮。要改某课时指向的配置链接，见发布助手《只改一个课时》(`PATCH /api/academy/courses/{id}` + `{stepIndex,stepPatch}`)。

**通用字段（任意组件可挂）**：
- `role`: 主持该环节的数字人（roles 里的 key）
- `reward`: `{"name":"勋章名","emoji":"🏅"}` —— 完成弹卡入宝藏箱
- `media`: `{"image|video":"URL","position":"left|top","caption":"说明"}` —— left=左媒体右内容分栏
- 顶层 `assistant`: `{"url":"...","label":"问小助手"}` —— 配置后页面出现 🙋 悬浮球。**url 填法（按优先级）**：
  1. `https://agent.avatargaia.top/uploads/dean-workstation.html` —— **Gaia Agent 工作台（默认标配，注意是 /uploads/ 下这个！）**：对话 + 画布，学生的 Agent 能答疑还能往画布推演示。⚠️ `/static/gaia-workstation.html` 是宣传页，别填那个
  2. `https://agent.avatargaia.top/chat` —— 纯对话页（轻量备选）
  3. 课程班主任会客厅地址（如有）—— 想让提问统一进你的会客厅就填这个
  4. ⚠️ **禁止**填引擎自身地址（`shuzhi-template-v2.html?mode=assist...`）——那是画布推送的单关渲染参数，不是助学页

**embed 探究实验详解（2026-07-19 新增，"让课件富起来"的主力组件）**：
- 一关 = 一个 iframe，嵌入独立互动实验页（单文件 HTML、零依赖最佳）。自动带「⛶ 全屏探究」按钮，课堂投屏神器。
- **现成实验库** `/static/shuzhi-labs/`（可直接填 url）：
  - `quadratic-explorer.html` 二次函数动态探究（初三数学，拖 a/b/c 滑块+挑战模式）
  - `lens-imaging.html` 凸透镜成像规律（初二物理，拖蜡烛看光路/像变化）
  - `earth-seasons.html` 地球公转与四季（初一地理，⭐CONFIG.axisTilt 改 0 → 四季消失）
  - `binary-star.html` 双星系统 / `water-refraction.html` 水的折射
- 三种过关：默认按钮；`"gate":"none"` 到达即过；`"gate":"message"` = 实验页内部挑战完成时执行 `parent.postMessage({type:'shuzhi:done'},'*')` 自动过关（引擎显示 `feedbackRight`）。
- `"minSeconds": 60` → 过关按钮先锁定倒计时，防止跳过实验直接点过（计时跨会话累计）。
- 新实验页由 Agent 自己生成后 workspace-upload 传到 /uploads，url 填相对路径即可；**实验页顶部建议保留 CONFIG 常量块**，老师/Agent 现场改参数=因人施教。
- 完整演示课：`/static/shuzhi-template-v2.html?config=/static/shuzhi-configs/lab-demo.json`（数学+物理+地理三实验+检验闯关）

**panel 学材面板（2026-07-19 新增）——任意关卡加左栏，一行配置切左右对照版式**：

数智课三种版式语法（版式跟着任务走，判断标准=互动时需不需要随时回看材料）：
1. **卡片流**（默认）：情境导入/对话先贤/美读/总结等叙事关，什么都不用配。
2. **左右对照**：读材料答题/看图填空/看素材做分镜/作品互评挂量表——给该关加 `panel` 字段即可，左=学材右=互动。
3. **全屏沉浸**：实验/模拟/游戏——用 `embed` 组件，别配 panel（实验自带材料，左栏反而挤占操作空间）。

`panel` 可加在**任何组件类型**的关卡上（quest/blanks/sort/table/create/discuss/embed…），字段全可选：
```json
"panel": {
  "title": "📖 课文 · 第3自然段",
  "subtitle": "部编版三年级下册 · 数智互动课",       // 题带副题（教材版本/课程归属，撑起课程感）
  "heroColor": ["#7c3aed", "#06b6d4"],          // 题带自定义渐变色（可选；不配则自动取皮肤色。单色传一个即可）
  "badges": ["🖱️ 悬停看部件", "🌊 模拟洪水"],        // 题带功能徽章（告诉学生这关能做什么=引导感）
  "images": ["/uploads/xx.jpg", "..."],      // 多图自动出缩略图切换
  "video": "/uploads/xx.mp4",                 // 小窗视频（素材参照用；主看片请用 media 关卡全宽）
  "audio": "/uploads/du.mp3",                 // 朗读音频条
  "text": "正文，支持 ==高亮==、**关键词**、[链接文字](https://网址) 三种标记，空行分段",  // ⭐放链接/视频用 [文字](URL)，别写 <a>/<img> 生标签（会被转义示众）；图片走 images[]
  "note": "💡 表达密码：中心句→围绕写→排比",   // 左框注释条（批注/口诀/提示）
  "tasks": ["读一读课文", {"text": "完成右侧闯关", "auto": true}],  // 任务清单；{auto:true} 的任务在本关完成时自动打勾
  "cards": [                                   // 🗂️ 知识卡：本课/延展两型（延展加 type:"extend" 虚线样式）
    {"term": "地轴", "pinyin": "dì zhóu", "meaning": "一句话释义",
     "detail": "点卡片弹窗显示的正文，支持 ==高亮== / **关键词** / 空行分段——Agent 在这里写迷你百科",
     "link": "/academy/learn/{courseId}/km", "linkLabel": "去知识图谱看「地轴」"},   // 可选跳转链接
    {"term": "极昼极夜", "type": "extend", "meaning": "延展方向"}
  ],                                            // 有 detail/link 的卡自动带 ▸ 角标、可点弹窗
  "teacher": {"name": "薛老师", "title": "初一地理 · 数智课主理", "avatar": "🧑‍🏫",
              "callUrl": "@call",  // ⭐平台动作：@call=呼叫讲师弹窗 / @quiz=摸底测评 / @km=知识图谱（内嵌课程页时自动生效；不写也会自动补）
              "agent": "罗罗"},  // 师者卡置顶（题带正下方）："本课主理"+🤖Agent助教名+📞呼叫按钮（callUrl 新窗口打开，一般指 /chat）
  "shortcuts": [                                // 侧栏底部快捷键（钉在最下方，新窗口打开）
    {"icon": "🕸️", "label": "知识图谱", "url": "/academy/learn/{courseId}/km"},
    {"icon": "📝", "label": "摸底出题", "url": "..."},
    {"icon": "🙋", "label": "呼叫老师", "url": "/chat"}
  ]
}
```
- 左栏=米白纸质课本感，题带自动用皮肤色渐变；desktop 两栏自动撑满约72vh。手机/窄屏（<860px）自动变上下结构，左栏折叠为可点开的抽屉，无需任何配置。
- 左栏样式自动跟随皮肤（skin/skinDef）。
- **媒体放左还是放右**：谁是被加工的主任务谁占右边大区，谁是随时回看的参照物谁进 panel。同一段视频：纯观看→media 关卡全宽；边看边做→panel.video；作品互评→作品在右、量表写进 panel.text/tasks。
- **能力图谱（自动）**：总结页自动聚合全课 panel.cards（本课=核心知识、extend=延展方向）+ 各关 skills[] 数组，拼成"🧠 本课能力图谱"chip 墙——**每张知识卡就是未来 KM 图谱的一个节点，写卡时用规范术语**。
- 演示：`/static/shuzhi-template-v2.html?config=/static/shuzhi-configs/lab-demo.json` 第5关（前4关=卡片流+全屏 embed，第5关=左右对照，一门课集齐三版式）。

**🎤 语音输入（2026-07-26，平台通用能力，默认开启无需配置）**：
`create` 自由创作 与 `freearrange` 的 `reflect` 自由表达，输入框下方**自动**出现「🎤 说给我听」按钮——学生点一下说话，SenseVoice 实时转写成文字填进输入框，再照常走 AI 承接/判定。**你什么都不用配**；个别关卡想关掉才写 `"voice": false`。
- 适合：不爱打字的学生、低年级、口头表达类任务（事故原因分析、设计说明、宣传语、讨论记录）。
- 转写后可继续说（自动接在后面）或直接手改，**发送前学生始终能看见文字**（听错不会直接提交）。
- 浏览器不支持录音时按钮自动隐藏，不影响打字。

### 3.3 生成规范（写内容时必须遵守）

1. **三级提示铁律**（blanks/table 的 hints）：
   - hints[0] = 引导重读原文（"再读读第X句～"）
   - hints[1] = 给具体线索（"提示：'____'里填什么？"）
   - 引擎在 hints 用尽后**自动给答案**，你不用写第三级
2. **answer 是数组**：把合理的同义答案都列上（如 `["图案","例子","事例"]`）。匹配规则：忽略标点/空格，答案是学生输入的子串也算对——所以答案写**最短核心词**
3. **create.keywords**：从课文抽 10~16 个关键实体词，学生创作命中任一即算"用上了课文素材"
4. **create.guides 三级引导**：①定中心 → ②举例子 → ③用修辞，句式亲切带"～"
5. **数字人角色**：沿用课程已有人设；对小学生用短句 + emoji，禁止说教长段
6. **奖励命名**要有情境感（"科创馆参观券"✓，"奖励1"✗）
7. **媒体 URL**：用课时已有附件/图片的平台 URL；没有就不放 media，**不要编造 URL**
8. **组件选型参考**（语文精读课）：media → quest → blanks(带media.left) → read → table → create → discuss → extend。其它学科自行裁剪：理科可 quest+blanks 为主，英语可加 read
9. 一课 5~8 个 stages 为宜，对应 30~40 分钟课堂
10. **dialogue 话术合规**：先贤台词必须基于课文/史实编写，语气亲切，不虚构争议内容——这些话术会原样呈现给小学生，等同教材文字
11. **craft 委托流**：学生点"委托 Agent"会自动建任务给其 Agent；Agent 收到「作品工坊委托」任务后：和主人共创作品 → 按 gaia-academy 提交作品墙（POST /api/academy/assignment/submit）。**你要确保课程开启了作品墙（Capstone）**
12. 结课页的个性化点评是引擎按学习数据自动生成的，**不要**在 summary 里再写点评类文字

---

## 四、作业与助学（先知道，暂不实现）

- **交互作业** = 另一份精简 JSON（如 blanks+create 两个组件），`dataEndpoint` 上报接口由凯凯后续提供，当前一律留空 `""`
- **Agent 助学模式**：`?mode=assist&stage=N` 单关渲染，推画布协议等你和八爪实测后定——先不做进模版

---

## 五、验收清单（每门课生成后自测）

- [ ] JSON 能被 `JSON.parse`（引擎加载失败会白屏报"配置加载失败"）
- [ ] 打开 `引擎URL?config=...` 能看到第一关
- [ ] 每个 blanks 空位：填正确答案能通过、填错出现 hints[0]
- [ ] 每个 reward 触发弹卡
- [ ] 做两关后关页面重开 → 出现"欢迎回来"且进度还在
- [ ] 右上角 📊 教师面板显示首正率/用时
- [ ] 课时页打开 htmlUrl 正常内嵌显示

---

## 六、一句话总结

> 你已经会把文档变成课程（km-builder）；现在再学会把课文变成一份 JSON——
> 老师交一份文档，产出：课时 + 知识图谱 + 考试 + **能直接上课的交互课件**。
> 这是全流水线的最后一块拼图，也是深圳未来教育研究院合作的核心交付物。

有不明确的地方，来找凯凯对齐后再动手，不要自行猜测接口行为。


---

## 补充组件：`live-dialogue` 先贤 LIVE 对话（2026-07-21 新增，深圳国家项目 P0）

**用途**：把「与数字人/先贤开放对话 + AI 评价」做成关卡（替代零LLM的 `dialogue` 剧本版）。适合：时空热线请教先贤、与AI苏轼/孔子对话、跨时空成长答疑。对话走**平台 DeepSeek**（不依赖学生 Agent，40人并发、约0.2元/节），对话毕自动出结构化成长反馈并回流学情大屏。

**配置**：
```json
{
  "type": "live-dialogue", "role": "guide",
  "title": "时空热线 · 请教先贤",
  "prompt": "你遇到什么难题？选一位先贤时空连线！",
  "examples": ["我数学学不好怎么办？", "我控制不住玩手机…"],
  "figures": [
    { "name":"李时珍", "domain":"中医药学", "avatar":"/uploads/xx.png", "emoji":"🧓",
      "persona":"你是明代医药学家李时珍，编著《本草纲目》，严谨坚韧、心怀百姓。",
      "greeting":"后生，有何困惑？" }
  ],
  "selectable": 1, "minTurns": 3, "maxTurns": 10,
  "analysis": { "enabled": true, "dimensions": ["求知欲","思考深度","联系实际"] },
  "reward": { "name":"时空连线徽章", "emoji":"📞" }
}
```
- `figures[]`：可选先贤卡池（网格展示）。`persona`=人设（服务端会外包安全 envelope，锁人设+防越狱+基于史实，config 改不了这层）；`avatar`=AIGC 统一模板立绘 URL，无则用 `emoji` 兜底。
- `selectable`：本轮可对话人数（当前 1）。`minTurns`/`maxTurns`=完成门槛/刷量上限。
- `analysis.dimensions`：对话毕的评价维度（星级+具体点评，回流大屏），缺省三维如上。
- 学生登录态自动鉴权（无需配 token）；对话全程留档进 metric → 学情大屏，教师可抽查。

**生成规范**：
1. `persona` 必须基于史实、正向（面向中小学生，会原样进对话）——同 `dialogue` 合规铁律，需教师送审。
2. 立绘用 AIGC 统一构图批量生成（勿网上找，版权+风格一致性）；无立绘先用 emoji。
3. `examples` 照参考课形式给 2-3 条真实困惑，降低学生开口门槛。
4. 后端路由 `POST /api/academy/live-dialogue`（action=chat/analyze），凯凯维护，勿改。

**live-dialogue 语音（2026-07-21 v2）**：
- 先贤 TTS 配音：用 `figures[].voice` 指定百度音色（男 1/3/106、女 0/5/111、童 4/110/103，默认 3=沉稳男声）。学生端每条回复带 🔊 朗读按钮 + 顶部「先贤自动朗读」开关，走 `POST /api/academy/live-dialogue` 的 `action:"tts"`（session 鉴权，密钥服务端持有）。
- 学生 ASR 语音输入：输入框旁 🎤 按钮，浏览器 Web Speech API（中文，零后端），不支持的浏览器自动隐藏。课堂平板若 webview 不支持，后续升级服务端 ASR。


---

## 补充组件：`freearrange` 自由拖拽布局（2026-07-21 新增）

**用途**：把元素拖到画布任意位置。一个组件通吃 **情感坐标 / 拼图复原 / 时间轴排列 / 概念图布局 / 游览路线**。两种模式：`free`（自由布局，只记录位置，无对错——适合概念图/自由表达）、`check`（落点判定，元素要拖进各自目标区域才算对——适合坐标/拼图）。

**配置**：
```json
{
  "type": "freearrange", "role": "guide",
  "title": "情感坐标",
  "prompt": "把词句拖到它表达的情感位置",
  "canvas": {
    "height": 420,
    "bg": "/uploads/xx.png",           // 可选背景图（四象限图/拼图底图/时间轴/地图）
    "axes": { "x": ["消极","积极"], "y": ["低落","高昂"] }  // 可选坐标轴标签(x=左右, y=下上) + 十字线
  },
  "items": [
    { "id": "a", "text": "我欲乘风归去" },      // 无 x/y → 自动沿顶部平铺
    { "id": "b", "text": "起舞弄清影", "x": 30, "y": 60 },  // 有 x/y(百分比) → 初始就位（拼图/概念图预排）
    { "id": "c", "img": "/uploads/piece.png" }   // 图片元素（拼图）
  ],
  "gate": "check",                       // check=判定 / free=自由(默认)
  "targets": [                           // check 模式用：每个元素的正确落点(百分比+半径r默认12)
    { "id": "a", "x": 76, "y": 22, "r": 20 },
    { "id": "b", "x": 30, "y": 60, "r": 18 }
  ],
  "feedbackRight": "全部就位！🎉", "feedbackWrong": "红色的再拖一拖～",
  "reward": { "name": "情感解码师", "emoji": "🎭" }
}
```

**要点**：
- 坐标系：`x` 0(左)→100(右)，`y` 0(顶)→100(底)，都是百分比（响应式）。
- `check` 判定 = 元素中心与其 `target` 中心距离 ≤ `r`（百分比距离），全部命中才过关，错的标红。
- `free` 模式点"完成布局"即过关，记录各元素最终位置进 metric（可做过程性评价/回看学生的布局思路）。
- 拖拽用 pointer 事件，触屏/鼠标皆稳；位置断点续学。
- 场景速配：情感坐标=axes+targets；拼图=bg拼图底图+targets；时间轴=bg时间线+targets；概念图/游览路线=free 无 targets。

**freearrange 自由表达 reflect（2026-07-21）——「不判对错，AI 承接理解」**：free 模式加 reflect 字段即可。学生摆完写下想法，AI 只欣赏、承接、轻轻追问，绝不评判对错、不给标准答案。
- 配置：free 关加 reflect:true（默认引导语）或 reflect:{prompt:'说说你为什么这么摆…'}。走 POST /api/academy/live-dialogue 的 action:'reflect'（单轮可封顶、走平台）。
- 用途：让情感坐标/概念图这类从「有标准答案的判定」变成「承接学生自己的理解」。例：把情感坐标配成 gate:free + axes + reflect（不给 targets），学生怎么摆都不判错，只被听见。
