auto backup: 2026-05-16 08:10:01

This commit is contained in:
ai_member_only 2026-05-16 08:10:01 +08:00
parent a81320fdaa
commit a39bffa6ff
56 changed files with 2106 additions and 8 deletions

View File

@ -86,6 +86,12 @@
- 对话节奏快每2-3句台词对应一个剧情节点或互动环节
- 弱化说教感,所有指令和引导都以自然对话的方式呈现
### 【教研规则】文本输出格式规范(强制执行)
1. **禁止 Markdown 标记**:生成单元挑战的音频文本、阅读文本等任何内容文本时,禁止使用 `**` `*` `__` `_` 等 Markdown 加粗/斜体标识,也禁止使用 `#` `>` `-` 等块级 Markdown 语法。输出纯文本即可。
2. **适用场景**:单元挑战所有文本输出(音频台词、阅读理解文章、写作提示、口语话题等),以及任何需要嵌入题目 jsonData 的文本内容
3. **英式拼写优先**:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写
4. **标点符号规范**:严格区分全角/半角符号,中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用
### 【教研规则】剧本定稿审校通用规范
1. 标点符号规范:禁止使用「~」「!!!」等非标准标点,统一使用标准英文标点符号
2. 核心句型呈现规范:核心句型第一次出现时需清晰、完整、独立呈现,不与其他干扰信息混杂

View File

@ -0,0 +1,66 @@
# 音色角色 ID 映射表
来源:飞书知识库「音色表 for 出题」- Sheet1 角色表 + Sheet2 音色库
更新时间2026-05-15
用途单元挑战音频生成时角色与音色ID的对应查询
## 角色 → 音色ID 映射
| 角色 | 英文名 | 类型 | 音色ID (数值) | Sheet2 对应 voice_id |
|------|--------|------|:-----------:|---------------------|
| 用户_男 | User_boy | 男童音 | 23 | clever_boy |
| 用户_女 | User_girl | 女童音 | 47 | girl11kim |
| 旁白_男 | Narration_male | 成年男 | 11 | audiobook_male_1 |
| 旁白_女 | Narration_female | 成年女 | 10 | presenter_female |
| 小雨 | Brainy | 成年女 | 46 | Serene_Woman |
| 本 | Ben | 男童音 | 331 | *(未收录到Sheet2)* |
| 本爸爸 | Ben's Dad | 成年男 | 232 | *(未收录到Sheet2)* |
| 谨慎小子 | Otis | 男童音 | 255 | *(未收录到Sheet2)* |
| 傲娇女侠 | Skylar | 女童音 | 364 | *(未收录到Sheet2)* |
| 丽贝卡 | Rebecca | 女童音 | 36 | danya_xuejie |
| 灵犀 | Kevin | 男童音 | 51 | so-1075-m-7 |
| 托马斯 | Thomas | 男童音 | 58 | so-3631-f-9 |
| 俱乐部外路人A | Tommy | 男童音 | 290 | *(未收录到Sheet2)* |
| 选手A | Jeson | 男童音 | 4 | male-qn-daxuesheng |
| 选手B | Vivian | 女童音 | 332 | *(未收录到Sheet2)* |
## 按维度分类速查
### 成人男
- 旁白_男 (Narration_male) → 11 → audiobook_male_1
- 本爸爸 (Ben's Dad) → 232
### 成人女
- 旁白_女 (Narration_female) → 10 → presenter_female
- 小雨 (Brainy) → 46 → Serene_Woman
### 男童
- 用户_男 (User_boy) → 23 → clever_boy
- 本 (Ben) → 331
- 谨慎小子 (Otis) → 255
- 灵犀 (Kevin) → 51 → so-1075-m-7
- 托马斯 (Thomas) → 58 → so-3631-f-9
- 俱乐部外路人A (Tommy) → 290
- 选手A (Jeson) → 4 → male-qn-daxuesheng
### 女童
- 用户_女 (User_girl) → 47 → girl11kim
- 傲娇女侠 (Skylar) → 364
- 丽贝卡 (Rebecca) → 36 → danya_xuejie
- 选手B (Vivian) → 332
## 核心通用角色(优先级最高)
| 角色 | 音色ID | 说明 |
|------|:-----:|------|
| 用户_男 | 23 | 默认男童音 |
| 用户_女 | 47 | 默认女童音 |
| 旁白_男 | 11 | 默认成年男旁白 |
| 旁白_女 | 10 | 默认成年女旁白 |
| 小雨 | 46 | 主要女性角色 |
## 备注
- Sheet1 音色ID 数值 >75 的角色331/232/255/364/290/332其音色ID未在 Sheet2 通用音色库中收录,可能对应独立音色系统
- Sheet2 中另有大量通用音色(青涩青年、御姐、主持人口音等)可供非角色绑定的音频场景使用
- 单元挑战出题时优先使用上述映射表中的角色和对应ID

View File

@ -47,6 +47,16 @@ description: 单元挑战所有题型自动化审校技能。覆盖听力P1-P7
| 口语 P2 | 话题讨论 | `tblGoWYBmVI0IrvQ` | 题目集合 ID, 题目1, 题目2, 图片描述, jsonData, dataStatus, 推送到服务端, 审核结果 |
| 口语 P3-P5 | (待补充) | (待补充) | — |
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 审校流程
```

View File

@ -25,6 +25,14 @@ description: 单元挑战核心层(永久固定,无重大升级不改动)
- ✅ 暂不对接其他外部系统CMS/教研系统等)
- ✅ 所有输出仅支持本地文件、飞书多维表两种形式
- ✅ 所有数据存储在当前工作区内,不对外传输
## 文本输出规范(强制约束,覆盖所有题型)
以下规则适用于单元挑战所有题型的文本输出(音频台词、阅读文章、写作提示、口语话题等 jsondata 内容):
1. 禁止 Markdown 标记:禁止使用 `**` `*` `__` `_` 等加粗/斜体标识,也禁止使用 `#` `>` `-` 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 改动规则
- 非重大规则升级/词库全量更新,禁止修改本层内容
- 单个题型调优仅修改对应题型Skill不得改动核心层

View File

@ -25,11 +25,15 @@ description: 单元挑战总控调度大脑,统一接收所有单元挑战生
- L2阶段需求→分发到L2执行器调用对应L2专属/共用题型技能
- 多题型组合需求→按题型分别分发,并行生产
### 步骤4质量校验自动执行
所有生成的题目自动经过层质量校验:
所有生成的题目自动经过层质量校验:
1. 超纲校验:所有词汇必须属于对应阶段词库
2. 格式校验:符合对应题型输出规范
3. 难度校验:听力文本长度/选项复杂度等符合难度要求
4. 去重校验:同一题包内知识点不重复考察
5. 文本规范校验(强制):
- 禁止 Markdown 标记(`**` `*` `__` `_` `#` `>` `-`),所有文本纯文本输出
- 英式拼写优先colour/centre/travelling 等)
- 标点符号规范:中文全角(,。!?),英文半角(. , ! ?),不混用
### 步骤5结果输出
按照要求格式输出,支持:
- 教研文档格式:带解析、能力项、评分标准

View File

@ -3,6 +3,16 @@ name: listening-drag
description: K12英语听力拖拽题Listening Drag & Drop标准化设计、生产、审校工具。别名听力Part1图片连线、听力Part1人物匹配三者为同一题型。使用场景(1) 根据给定知识点、难度等级、人名列表生成符合教研规范的听力拖拽题;(2) 校验听力拖拽题的格式、难度匹配、内容合规性;(3) 批量生产听力拖拽题内容。触发关键词听力拖拽题、listening drag、拖拽题生产、听力Part1图片连线、听力Part1人物匹配、人物匹配题生产、图片连线题设计
---
# Listening Drag 听力拖拽题生产技能
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 核心功能
标准化生成符合L1 6个阶段要求的听力拖拽题【阶段归属L1专属】自动绑定对应能力标签支持批量生产与合规校验。
## 难度对应关系(已适配新的阶段划分)

View File

@ -2,6 +2,16 @@
name: listening_matchInfo
description: K12英语听力信息匹配题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的听力信息匹配题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力信息匹配题。触发关键词听力信息匹配、listening match info、信息匹配题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Match Info 听力信息匹配题生产技能
## 题型说明
听力信息匹配题:学生听一段对话或文本,然后将听到的信息与选项列表匹配,通常涉及人物、物品、地点等信息的对应关系。

View File

@ -2,6 +2,16 @@
name: listening_picture_selection
description: K12英语听力选图题标准化设计、生产、审校工具。对应题型L1 - Starters - 听力 Part6 听力选图,考察核心能力:图片信息识别、听力信息匹配、快速反应。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力选图题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力选图题。触发关键词听力选图、选图题、listening picture selection、听力Part6选图、图片匹配题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Picture Selection 听力选图题生产技能
## 题型说明
本技能对应官方题型:**L1 - Starters - 听力 Part6 听力选图【阶段归属L1专属】**,考察核心能力为**图片信息识别(听力信息匹配)**学生听5-6个单句/短对话,每个对应一组图片,选出与听力内容匹配的图片,考察对图片信息和听力信息的快速匹配能力。

View File

@ -2,6 +2,16 @@
name: listening-choicePic
description: K12英语听力三选一图片选择题标准化设计、生产、审校工具。对应题型L1 - Starters - 听力 Part3 三选一图片选择,考察核心能力:显性事实理解(单句信息点抓取)。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力三选一题目;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力三选一题目。触发关键词听力三选一、图片选择题、listening choice pic、听力Part3三选一、单句信息点抓取题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening ChoicePic 听力三选一图片选择题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 听力 Part3 三选一图片选择【阶段归属L2专属】**,考察核心能力为**显性事实理解(单句信息点抓取)**学生听单句听力内容从3张图片选项中选出与听力内容匹配的正确答案。

View File

@ -2,6 +2,16 @@
name: listening_form_fill
description: K12英语听力表格填空题标准化设计、生产、审校工具。对应题型L1 - Starters - 听力 Part2 表格填空,考察核心能力:信息抓取、拼写准确性、短时记忆。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力表格填空题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力表格填空题。触发关键词听力表格填空、表格填空题、listening form fill、听力Part2表格填空、信息抓取填空题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Form Fill 听力表格填空题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 听力 Part2 表格填空【阶段归属L2专属】**,考察核心能力为**信息抓取(关键词识别+拼写准确性)**学生听1-2段短对话/独白,提取关键信息填写表格中空缺的内容,考察词汇拼写、数字识别、信息匹配能力。

View File

@ -2,6 +2,16 @@
name: listening_info_match
description: K12英语听力信息匹配题标准化设计、生产、审校工具。对应题型L2 - Movers - 听力 Part5 信息匹配,考察核心能力:信息关联、多任务处理、干扰抑制。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力信息匹配题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力信息匹配题。触发关键词听力信息匹配、信息匹配题、listening info match、听力Part5信息匹配、多信息关联题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Info Match 听力信息匹配题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 听力 Part5 信息匹配【阶段归属L2专属】**,考察核心能力为**信息关联(多任务处理+干扰抑制)**学生听1段长对话/独白,将左右两栏的相关信息进行匹配,考察对多个信息点的关联、记忆和区分能力。

View File

@ -2,6 +2,16 @@
name: listening_long_conversation
description: K12英语听力长对话选择题标准化设计、生产、审校工具。对应题型L2 - Movers - 听力 Part3 长对话选择,考察核心能力:逻辑理解、信息整合、干扰抑制。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力长对话选择题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力长对话选择题。触发关键词听力长对话选择、长对话选择题、listening long conversation、听力Part3长对话、逻辑理解题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Long Conversation 听力长对话选择题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 听力 Part3 长对话选择【阶段归属L2专属】**,考察核心能力为**逻辑理解(信息整合+干扰抑制)**学生听1段3-5轮的长对话回答3-4道选择题考察对对话整体逻辑、隐含信息、因果关系的理解能力。

View File

@ -2,6 +2,16 @@
name: listening_short_conversation
description: K12英语听力短对话选择题标准化设计、生产、审校工具。对应题型L1 - Starters - 听力 Part4 短对话选择,考察核心能力:信息抓取、快速反应、场景理解。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的听力短对话选择题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产听力短对话选择题。触发关键词听力短对话选择、短对话选择题、listening short conversation、听力Part4短对话、场景理解题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Listening Short Conversation 听力短对话选择题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 听力 Part4 短对话选择【阶段归属L2专属】**,考察核心能力为**场景理解(快速信息抓取+反应)**学生听多段1-2轮的短对话每段对话对应1道选择题考察对常见场景、日常用语的理解能力。

View File

@ -2,6 +2,16 @@
name: reading_pic_judge
description: K12英语阅读看图判断题标准化设计、生产、审校工具。对应题型阅读 - 看图判断题【阶段归属L1&L2共用通过难度参数区分】。学生逐张观察图片判断对应的描述句子是否正确Yes/No。考察核心能力图文匹配、阅读审题。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的阅读看图判断题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读看图判断题。触发关键词阅读看图判断、看图判断、reading pic judge、YesNo单图题、图文匹配题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Pic Judge 阅读看图判断题生产技能
## 题型说明
本技能对应题型:**阅读 - 看图判断题【阶段归属L1&L2共用通过难度参数区分】**,考察核心能力为**图文匹配(阅读理解+图片信息提取)**学生逐张观察单张图片判断对应的描述句子是否正确Yes/No。不同于reading_pic_qa多题共享一张大图本题型每道题独立配图。

View File

@ -2,6 +2,16 @@
name: reading_pic_qa
description: K12英语阅读看图回答题标准化设计、生产、审校工具。对应题型阅读 - 看图回答题【阶段归属L1&L2共用通过难度参数区分】。学生阅读描述性句子观察场景图片判断句子描述是否与图片匹配Yes/No。考察核心能力图文匹配、阅读审题。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的阅读看图回答题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读看图回答题。触发关键词阅读看图回答、看图回答、reading pic qa、YesNo看图题、图文匹配题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Pic QA 阅读看图回答题生产技能
## 题型说明
本技能对应题型:**阅读 - 看图回答题【阶段归属L1&L2共用通过难度参数区分】**,考察核心能力为**图文匹配(阅读理解+图片信息提取)**学生阅读多个描述性句子观察同一张场景图片逐个判断句子描述是否与图片匹配Yes/No。题目需搭配完整的场景图片textImage所有小题共享同一张大图。

View File

@ -2,6 +2,16 @@
name: reading_cloze
description: K12英语阅读完形填空题标准化设计、生产、审校工具。对应题型L2 - Movers - 阅读 Part4 完形填空,考察核心能力:词汇运用、语法判断、上下文逻辑理解。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的阅读完形填空题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读完形填空题。触发关键词阅读完形填空、完形填空题、reading cloze、阅读Part4完形填空、词汇运用题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Cloze 阅读完形填空题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 阅读 Part4 完形填空【阶段归属L2专属】**,考察核心能力为**词汇运用(语法判断+上下文逻辑理解)**学生阅读1篇80-150词的短文文中有3-5个空缺每个空缺从3个选项中选择正确的单词填入考察词汇、语法和上下文理解能力。

View File

@ -2,6 +2,16 @@
name: reading_info_match
description: K12英语阅读信息匹配题标准化设计、生产、审校工具。对应题型L1 - Starters - 阅读 Part1 信息匹配,考察核心能力:信息抓取、快速阅读、图文匹配。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的阅读信息匹配题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读信息匹配题。触发关键词阅读信息匹配、信息匹配题、reading info match、阅读Part1信息匹配、图文匹配题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Info Match 阅读信息匹配题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 阅读 Part1 信息匹配【阶段归属L2专属】**,考察核心能力为**信息抓取(快速阅读+图文匹配)**学生阅读5-6个简短文本标识/告示/短句),与对应的图片/标题进行匹配,考察快速抓取关键信息和图文匹配能力。

View File

@ -2,6 +2,16 @@
name: reading_long_passage
description: K12英语阅读长文选择题标准化设计、生产、审校工具。对应题型L2 - Movers - 阅读 Part3 长文选择,考察核心能力:篇章理解、细节定位、推理判断。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的阅读长文选择题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读长文选择题。触发关键词阅读长文选择、长文选择题、reading long passage、阅读Part3长文选择、篇章理解题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Long Passage 阅读长文选择题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 阅读 Part3 长文选择【阶段归属L2专属】**,考察核心能力为**篇章理解(细节定位+推理判断)**学生阅读1篇100-200词的短文回答3-4道选择题考察对篇章整体内容、细节信息、推理判断的能力。

View File

@ -2,6 +2,16 @@
name: reading_open_fill
description: K12英语阅读开放填空题标准化设计、生产、审校工具。对应题型L2 - Movers - 阅读 Part5 开放填空,考察核心能力:信息提取、词汇拼写、语法正确性。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的阅读开放填空题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读开放填空题。触发关键词阅读开放填空、开放填空题、reading open fill、阅读Part5开放填空、拼写题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Open Fill 阅读开放填空题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 阅读 Part5 开放填空【阶段归属L2专属】**,考察核心能力为**信息提取(词汇拼写+语法正确性)**学生阅读1篇短文/通知/表格根据要求填写3-5个空缺的单词无选项提示考察信息提取、词汇拼写和语法正确性。

View File

@ -2,6 +2,16 @@
name: reading_paragraph_match
description: K12英语阅读段落匹配题标准化设计、生产、审校工具。对应题型L2 - Movers - 阅读 Part2 段落匹配,考察核心能力:主旨理解、信息归纳、快速阅读。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的阅读段落匹配题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读段落匹配题。触发关键词阅读段落匹配、段落匹配题、reading paragraph match、阅读Part2段落匹配、主旨归纳题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Paragraph Match 阅读段落匹配题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 阅读 Part2 段落匹配【阶段归属L2专属】**,考察核心能力为**主旨理解(信息归纳+快速阅读)**学生阅读4-5个简短段落与对应的段落标题/主旨句进行匹配,考察归纳段落主旨和抓取核心信息的能力。

View File

@ -2,6 +2,16 @@
name: reading_pic_judge
description: K12英语阅读看图判断题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的阅读看图判断题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读看图判断题。触发关键词阅读看图判断、reading pic judge、看图判断题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Pic Judge 阅读看图判断题生产技能
## 题型说明
阅读看图判断题学生查看图片然后回答关于图片内容的判断题通常是Yes/No问题。

View File

@ -2,6 +2,16 @@
name: reading_pic_qa
description: K12英语阅读看图回答题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的阅读看图回答题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产阅读看图回答题。触发关键词阅读看图回答、reading pic qa、看图回答题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Reading Pic QA 阅读看图回答题生产技能
## 题型说明
阅读看图回答题:学生查看图片,然后回答关于图片内容的开放性问题。

View File

@ -2,6 +2,16 @@
name: speaking_pic_qa
description: K12英语口语看图说话题标准化设计、生产、审校工具。对应题型L1 - Starters - 口语 Part2 看图问答,考察核心能力:口语表达、图片信息提取、场景词汇运用。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的口语看图问答题目;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语看图问答题目。触发关键词口语看图说话、看图问答、speaking pic qa、口语Part2看图题、图片口语输出题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking Pic QA 口语看图说话题生产技能
## 题型说明
本技能对应官方题型:**L1 - Starters - 口语 Part2 看图问答【阶段归属L1专属】**,考察核心能力为**口语表达(图片信息提取+场景词汇运用)**:学生观察指定场景图片,根据问题提示口头输出对应答案,考察词汇储备、发音准确性、表达流畅度。

View File

@ -2,6 +2,16 @@
name: speaking_pic_recognize
description: K12英语口语看图识物题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的口语看图识物题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语看图识物题。触发关键词口语看图识物、speaking pic recognize、看图识物题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking Pic Recognize 口语看图识物题生产技能
## 题型说明
口语看图识物题:学生查看图片,然后描述或识别图片中的物品。

View File

@ -2,6 +2,16 @@
name: speaking_qa
description: K12英语口语日常问答题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的口语日常问答题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语日常问答题。触发关键词口语问答、speaking qa、日常问答题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking QA 口语日常问答题生产技能
## 题型说明
口语日常问答题:学生回答一系列日常问题,考察口语表达能力。

View File

@ -2,6 +2,16 @@
name: speaking_topic
description: K12英语口语话题讨论题标准化设计、生产、审校工具。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的口语话题讨论题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语话题讨论题。触发关键词口语话题讨论、speaking topic、话题讨论题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking Topic 口语话题讨论题生产技能
## 题型说明
口语话题讨论题:学生基于图片或描述讨论相关话题。

View File

@ -2,6 +2,16 @@
name: speaking_topic_discussion
description: K12英语口语话题讨论题标准化设计、生产、审校工具。对应题型L2 - Movers - 口语 Part2 话题讨论,考察核心能力:口语表达、逻辑组织、观点阐述。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的口语话题讨论题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语话题讨论题。触发关键词口语话题讨论、话题讨论题、speaking topic discussion、口语Part2话题讨论、观点表达题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking Topic Discussion 口语话题讨论题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 口语 Part2 话题讨论【阶段归属L2专属】**,考察核心能力为**口语表达(逻辑组织+观点阐述)**学生根据给定话题进行1-2分钟的口头阐述考察词汇运用、逻辑连贯、观点表达能力。

View File

@ -2,6 +2,16 @@
name: speaking_daily_qa
description: K12英语口语日常回答题标准化设计、生产、审校工具。对应题型L1 - Starters - 口语 Part1 日常回答,考察核心能力:口语表达、日常用语运用、快速反应。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的口语日常回答题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产口语日常回答题。触发关键词口语日常回答、日常问答题、speaking daily qa、口语Part1日常回答、日常口语表达题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Speaking Daily QA 口语日常回答题生产技能
## 题型说明
本技能对应官方题型:**口语 Part1 日常回答【阶段归属L1&L2共用通过难度参数区分】**,考察核心能力为**口语表达(日常用语运用+快速反应)**学生回答3-4个日常问题每个问题回答1-3句话考察日常词汇、句式的运用能力和表达流畅度。

View File

@ -2,6 +2,16 @@
name: writing_pic_qa
description: K12英语写作看图回答题标准化设计、生产、审校工具。对应题型写作 - 看图回答题【阶段归属L1&L2共用通过难度参数区分】。学生观察图片根据提示问题写出答案提供提示答案开头辅助填空。考察核心能力图文匹配、书写表达。使用场景(1) 根据给定知识点、难度等级生成符合教研规范的写作看图回答题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产写作看图回答题;(4) 产出后自动写入飞书多维表格。触发关键词写作看图回答、看图写作、writing pic qa、看图写词、书写表达题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Writing Pic QA 写作看图回答题生产技能
## 一、题型说明

View File

@ -2,6 +2,16 @@
name: writing_email_reply
description: K12英语写作邮件回复题标准化设计、生产、审校工具。对应题型L2 - Movers - 写作 Part1 邮件回复,考察核心能力:书面表达、格式规范、信息提取。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的写作邮件回复题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产写作邮件回复题。触发关键词写作邮件回复、邮件回复题、writing email reply、写作Part1邮件回复、应用文写作题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Writing Email Reply 写作邮件回复题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 写作 Part1 邮件回复【阶段归属L2专属】**,考察核心能力为**书面表达(格式规范+信息提取)**学生阅读一封简短邮件根据要求写20-50词的回复邮件考察邮件格式、信息完整性、语言正确性。

View File

@ -2,6 +2,16 @@
name: writing_pic_qa
description: K12英语写作看图回答题标准化设计、生产、审校工具。完整规范见 common/writing_pic_qa/SKILL.md。触发关键词写作看图回答、writing pic qa、看图回答题生产
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Writing Pic QA 写作看图回答题生产技能
> 📌 **完整生产规范请参阅:** `common/writing_pic_qa/SKILL.md`

View File

@ -2,6 +2,16 @@
name: writing_picture_writing
description: K12英语写作看图写作题标准化设计、生产、审校工具。对应题型L2 - Movers - 写作 Part2 看图写作,考察核心能力:书面表达、图片观察、逻辑组织。使用场景:(1) 根据给定知识点、难度等级生成符合教研规范的写作看图写作题;(2) 校验题目格式、难度匹配、内容合规性;(3) 批量生产写作看图写作题。触发关键词写作看图写作、看图写作题、writing picture writing、写作Part2看图写作、看图写话题
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Writing Picture Writing 写作看图写作题生产技能
## 题型说明
本技能对应官方题型:**L2 - Movers - 写作 Part2 看图写作【阶段归属L2专属】**,考察核心能力为**书面表达(图片观察+逻辑组织)**学生根据1-3张图片的提示写3-5句话的短文考察图片信息提取、语言组织、逻辑连贯能力。

View File

@ -4,6 +4,16 @@ version: 1.2.0
description: 教研互动组件设计规范结构化文本格式不涉及JSON。触发方式(1) `/组件生产 --feishu-url <链接>` (2) 飞书链接 + "组件"/"设计组件"/"组件回填"。不会误触发:仅含"互动"不触发;含"组件配置-json"不触发(属于 interactive-component-json 技能)。标准化组件生产流程:设计→生成(结构化文本)→校验→回填。
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# SKILL.md - 教研互动组件设计规范
## ⚡ 触发方式

View File

@ -7,6 +7,16 @@ metadata:
domains: ["教研生产", "互动组件配置"]
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# 对话类互动组件配置规范
本技能定义6类对话类互动组件的配置标准、格式要求和校验规则所有对话类互动必须严格遵循此规范生产。

View File

@ -25,7 +25,7 @@ description: 剧本互动组件内容生产/审校/回填技能不涉及JSON
- ✅ **智能组件识别**读取剧本sheet根据列A「类型」字段识别组件行互动 / 核心互动-xxx
- ✅ **组件类型自动匹配**根据剧情上下文、前后台词自动匹配27种中互动或14种核心互动类型
- ✅ **组件内容生成**调用LLM生成结构化文本格式的组件内容【任务标题】【资源配置】... 等字段)
- ✅ **自动审校**校验ID格式/字段完整性/题型匹配/知识点一致性/格式规范
- ✅ **自动审校**校验ID格式/字段完整性/题型匹配/知识点一致性/格式规范/文本规范禁止Markdown、英式拼写、标点符号
- ✅ **飞书回填**将生成的组件内容写入剧本sheet的「组件配置」列列G**以结构化文本格式存储非JSON**
---

View File

@ -5,6 +5,16 @@ description: "瓦拉英语互动组件官方配置库,包含所有中互动、
metadata:
source: "飞书知识库 03 内容配置相关/配置多维表格/互动内容库"
last_update: "2026-04-03"
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
---
## 互动组件分类

View File

@ -23,6 +23,13 @@ metadata:
# 互动组件配置JSON生成器
## 文本输出规范jsonData 内容强制遵守)
所有生成的 JSON 配置中,任何嵌入的文本内容(题目、选项、解析、台词等)必须遵守:
1. 禁止 Markdown 标记(`**` `*` `__` `_` `#` `>` `-`),纯文本输出
2. 英式拼写优先colour/centre/travelling 等)
3. 标点符号规范:英文半角(. , ! ?),中文全角(,。!?),不混用
## 触发场景
用户发送以下格式的消息时触发完整处理流水线:

View File

@ -24,6 +24,7 @@ description: 用英语母语儿童思维生成自然地道的分级英文台词
- ✅ 英语思维重构:不是翻译,而是用英语母语儿童的思维方式重构意群,生成自然地道的英文
- ✅ 分级生成支持4个难度等级S1-S4完全匹配4-8岁不同水平儿童
- ✅ 自动校验:内置句长/连接词/从句/时态/超纲词/重复等多维度校验+L1核心词表
- ✅ 文本规范校验:禁止 Markdown 标记、英式拼写优先colour/centre/travelling、英文半角标点
- ✅ 自动修正校验不通过时自动触发LLM修正无需手动干预
- ✅ 科幻词自动降级:内置可配置科幻词映射表,复杂词汇自动转换成儿童易懂表达
- ✅ 批量处理:支持单个文件/目录批量处理,自动保存结果到指定路径

View File

@ -14,3 +14,5 @@
{"type":"memory.recall.recorded","timestamp":"2026-05-13T13:40:33.965Z","query":"unit challenge 口语 写作 多维表格 table_id","resultCount":3,"results":[{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1},{"path":"memory/2026-05-12.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-12.md","startLine":36,"endLine":52,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-13T13:40:41.646Z","query":"unit challenge 写作 speaking writing 多维表格 table_id tbl","resultCount":3,"results":[{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1},{"path":"memory/2026-05-12.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-12.md","startLine":36,"endLine":52,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-14T02:49:02.264Z","query":"对话选读 selective_reading 组件配置","resultCount":4,"results":[{"path":"memory/2026-05-07.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-12.md","startLine":170,"endLine":193,"score":1},{"path":"memory/2026-05-12.md","startLine":76,"endLine":95,"score":1},{"path":"memory/2026-05-12.md","startLine":1,"endLine":20,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-15T07:13:08.147Z","query":"中互动 大图选择 相似图选择 顺序选择 例句撰写","resultCount":1,"results":[{"path":"memory/2026-05-12.md","startLine":206,"endLine":226,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-15T07:13:08.147Z","query":"互动组件 题型 图片选择 配置规范 例句模板","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]}

View File

@ -1,6 +1,6 @@
{
"version": 1,
"updatedAt": "2026-05-14T02:49:02.264Z",
"updatedAt": "2026-05-15T07:13:08.147Z",
"entries": {
"memory:memory/2026-05-07.md:57:74": {
"key": "memory:memory/2026-05-07.md:57:74",
@ -370,18 +370,20 @@
"endLine": 226,
"source": "memory",
"snippet": "- **10 条 sentenceMeaningMeaning JSON 修复:** - 根因explanation 中 ASCII `\"` 被用作中文引号 - 修复策略演变:状态机拆分失败 → 正则重建 → 发现Q2丢失 → 从中文列完整重建 - 最终10/10 可正确解析,审校结果同步更新 - 受影响1213004/1213006/1213010/1214008/1215005/1216001/1216004/1216007/1216008/1216010 ### 刘彦江 — 核心互动全题型 JSON 配置标准沉淀17:05 ~ 17:50 - **产出 Skill 1** `skills/bitable-reader/SKILL.md` — 通用 bitable 读取(任何 bitable 通用) - **产出 Skill 2** `skills/core-content-json-standard/SKILL.md` v2.0 — 全题型 JSON 标准393行 - **架构:** 通用字段在前ID/kpInfo/taskData+ 5大题型分类📖阅读2 🎧听力3 🗣口语4 ✏写作5+ 审校规则 + 扩展指南 - **覆盖率:** 14/15 种题型(口语探讨 S0 无数据) - **产出脚本:** `scripts/audit_core_reading_S0.py` — 合作阅读 S0 审校 ## 经验教训 ### bitable 写入需严格流程管控2026-05-12 - 批量更新 JSON写入前完整提取",
"recallCount": 1,
"recallCount": 2,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"totalScore": 2,
"maxScore": 1,
"firstRecalledAt": "2026-05-13T03:09:54.362Z",
"lastRecalledAt": "2026-05-13T03:09:54.362Z",
"lastRecalledAt": "2026-05-15T07:13:08.147Z",
"queryHashes": [
"f151bc633ad1"
"f151bc633ad1",
"a0932e0e2749"
],
"recallDays": [
"2026-05-13"
"2026-05-13",
"2026-05-15"
],
"conceptTags": [
"10/10",
@ -800,6 +802,68 @@
"scripts",
"audit-batch-1213001-1216010"
]
},
"memory:memory/2026-05-07.md:354:368": {
"key": "memory:memory/2026-05-07.md:354:368",
"path": "memory/2026-05-07.md",
"startLine": 354,
"endLine": 368,
"source": "memory",
"snippet": "- **需求:** 将 020102I am...)和 020103I am ready / Thank you两套题合并为一个 `{first:..., second:...}` JSON统一 questionSetID=0000001 - **状态:** ✅ 已完成 - **核心考点分析(用户强调):** 需分析每个句型的核心考点(孩子最容易犯错的地方),挖空对准核心考点 - I am/from 组am系动词第一人称、from介词选择、studenta+名词结构) - Thank you for 组for介词选择非 you、helpingfor+动名词,非 help/to help - **输出文件:** `output/writing_pic_qa_combined.json` ### 刘彦江 — 组件配置-json 请求L1-S2-U13-L4 沙漠之花) - **时间:** 16:45 ~ 17:51 - **文档:** `https://makee-interactive.feishu.cn/wiki/K5E1wzwk7it9t7kXvcbc6Xugnhc` - **状态:** ⚠️ 未完成 — pipeline 识别到 0 组件 - **根因:** 剧本文档的13个组件数据存储在 markdown 内联表格中lark-table5列×36行而非内嵌 Sheet。当前 pipeline 的 parse_script 只从内嵌 Sheet 读取组件数据,不支持 markdown 表格组件解析 - **已识别组件ma",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-15T07:13:08.147Z",
"lastRecalledAt": "2026-05-15T07:13:08.147Z",
"queryHashes": [
"08364c8746ab"
],
"recallDays": [
"2026-05-15"
],
"conceptTags": [
"am/from",
"help/to",
"组件配置-json",
"l1-s2-u13-l4",
"lark-table",
"parse-script",
"需求",
"ready"
]
},
"memory:memory/2026-04-22.md:1:8": {
"key": "memory:memory/2026-04-22.md:1:8",
"path": "memory/2026-04-22.md",
"startLine": 1,
"endLine": 8,
"source": "memory",
"snippet": "[李应瑛 2026-04-22 提出要求] 所有需要包含对话的内容(如剧本、互动组件等)必须要有【后置对话】字段,无后置对话时填写“无”。 [李应瑛 2026-04-22 确认规则] 剧本内嵌表格组件填写位置规则仅当表格第一列A列明确标注为对话类类型对话朗读/对话挖空/对话选读/对话组句等才在同一行的H列【组件】列填写对应的组件内容其他类型行TL/场景/角色/图片/非对话类等)无需填写。 [李应瑛 2026-04-22 确认格式规则] 对话类组件字段换行规则:每个结构单独占一行,格式为: 【任务标题】xxx 【情境引入】xxx 【互动内容】xxx 【后置对话】xxx 单元格内使用\\n作为换行符实现后续所有组件均遵循此格式。",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-15T07:13:08.147Z",
"lastRecalledAt": "2026-05-15T07:13:08.147Z",
"queryHashes": [
"08364c8746ab"
],
"recallDays": [
"2026-05-15"
],
"conceptTags": [
"对话朗读/对话挖空/对话选读/对话组句等",
"tl/场景/角色/图片/非对话类等",
"提出",
"要求",
"所有",
"需要",
"包含",
"对话"
]
}
}
}

View File

@ -0,0 +1,51 @@
{
"summary": {
"total_problems": 35,
"total_fixed": 35,
"total_updated": 8
},
"tables": [
{
"table_name": "听力-P1-图片选择题/选图题",
"total_records": 21,
"total_problems": 33,
"total_fixed": 33,
"total_updated": 6
},
{
"table_name": "听力-P2-表格填空题",
"total_records": 17,
"total_problems": 0,
"total_fixed": 0,
"total_updated": 0
},
{
"table_name": "听力-P3-长对话选择",
"total_records": 1,
"total_problems": 0,
"total_fixed": 0,
"total_updated": 0
},
{
"table_name": "听力-P4-短对话选择题",
"total_records": 17,
"total_problems": 1,
"total_fixed": 1,
"total_updated": 1
},
{
"table_name": "听力-P5-信息匹配题",
"total_records": 12,
"total_problems": 0,
"total_fixed": 0,
"total_updated": 0
},
{
"table_name": "听力-P7-听力拖拽",
"total_records": 12,
"total_problems": 1,
"total_fixed": 1,
"total_updated": 1
}
]
}

View File

@ -0,0 +1,298 @@
#!/usr/bin/env python3
"""审计写作和口语题型表的 explanation 字段 - 完整版"""
import requests, json, re, time, copy
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
BASE = "https://open.feishu.cn/open-apis"
CHOICE_TERMS_SPEAKING = [
"材料", "提到", "", "误选", "干扰", "正确答案是", "根据.*内容",
"原文", "文中", "文章", "选项", "排除", "不符合", "与.*不符",
"图中", "图片中", "文本中", "文中显示"
]
CHOICE_TERMS_WRITING = ["", "误选", "干扰项", "选项", "排除", "正确答案",
"材料中", "文中提到", "原文", "根据文章"]
def get_token():
r = requests.post(f"{BASE}/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET})
r.raise_for_status()
return r.json()["tenant_access_token"]
def get_all_records(token, table_id):
all_recs = []
page_token = None
while True:
params = {"page_size": 500}
if page_token:
params["page_token"] = page_token
r = requests.get(f"{BASE}/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records",
headers={"Authorization": f"Bearer {token}"}, params=params)
r.raise_for_status()
data = r.json()
items = data.get("data", {}).get("items", [])
all_recs.extend(items)
if not data.get("data", {}).get("has_more", False):
break
page_token = data.get("data", {}).get("page_token", "")
if not page_token:
break
return all_recs
def update_record(token, table_id, record_id, fields):
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
r = requests.put(f"{BASE}/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records/{record_id}",
headers=headers, json={"fields": fields})
r.raise_for_status()
return r.json()
def check_explanation_problems(explanation, table_type, prev_explanations, idx_in_set):
"""Check if an explanation has problems. Returns (has_problem, description)."""
if not explanation or explanation.strip() == "":
return False, None
exp = explanation.strip()
# Check for placeholder content
placeholders = ["xxxx", "这是一个解析", "这是一个能力项", "N/A", "占位"]
for ph in placeholders:
if ph in exp:
return True, f"含占位符内容: {ph}"
# Check for choice/reading terms
terms = CHOICE_TERMS_SPEAKING if table_type == "speaking" else CHOICE_TERMS_WRITING
for term in terms:
if re.search(term, exp):
return True, f"含选择题/阅读题用语: {term}"
# Check for material description instead of student response
if table_type == "speaking":
material_pat = [r"图片中", r"图中", r"材料中", r"文本中", r"文中显示"]
for pat in material_pat:
if re.search(pat, exp):
return True, f"描述材料内容而非学生回答: {pat}"
# Check identical to previous in same set
if idx_in_set > 0 and prev_explanations and exp == prev_explanations[-1].strip():
return True, "与同一questionSet内前一项解析逐字相同"
return False, None
def collect_all_explanations(parsed_json):
"""Collect all explanations from a parsed jsonData (dict or questionSet items)."""
exps = []
for sub_key, sub_val in parsed_json.items():
if not isinstance(sub_val, dict):
continue
# Direct explanation
if "explanation" in sub_val:
exps.append(sub_val["explanation"])
# questionSet explanations
qset = sub_val.get("questionSet", [])
for q in qset:
if isinstance(q, dict) and "explanation" in q:
exps.append(q["explanation"])
return exps
def generate_writing_explanation(sub_data):
"""Generate a proper writing explanation from sub-question data."""
text_desc = sub_data.get("textDesc", "")
ability = sub_data.get("ability", [])
category = sub_data.get("category", "")
qtype = sub_data.get("type", "")
parts = []
if text_desc:
parts.append(f"写作任务: {text_desc}")
if ability:
if isinstance(ability, list):
parts.append(f"能力目标: {''.join(ability)}")
else:
parts.append(f"能力目标: {ability}")
parts.append("评分维度: 内容完整性、语言准确性、结构逻辑性、书写规范性")
# Type-specific guidance
if qtype == "writing_emailReply":
parts.append("写作要点: 注意邮件格式规范(称呼、正文、署名)、逻辑顺序清晰、语言得体")
elif qtype == "writing_picWrite":
parts.append("写作要点: 按图片顺序组织叙述、使用时间衔接词、故事完整性")
elif "看图" in text_desc:
parts.append("写作要点: 准确描述图片内容、使用恰当的衔接词、逻辑连贯")
return "\n".join(parts)
def generate_speaking_explanation(q_data, sub_data):
"""Generate a proper speaking explanation from question data."""
question = q_data.get("question", q_data.get("content", ""))
ability = q_data.get("ability", [])
image_desc = q_data.get("imageDesc", "")
parts = []
if question:
parts.append(f"回答要点: {question}")
if image_desc:
parts.append(f"图片内容: {image_desc}")
if ability:
if isinstance(ability, list):
ability_str = ''.join(ability)
else:
ability_str = str(ability)
if ability_str not in ["这是一个能力项", "这是第二个能力项", "xxxx"]:
parts.append(f"考察能力: {ability_str}")
parts.append("评估标准: 语音语调准确性、语言流利度、内容完整性与相关性、语法准确性")
parts.append("回答指导: 鼓励学生用完整句子作答,根据图片内容组织语言,表达清晰有条理")
return "\n".join(parts)
def generate_speaking_explanation_simple(q_data, idx):
"""Simple speaking explanation for 看图识物 type."""
question = q_data.get("question", "")
image_desc = q_data.get("imageDesc", "")
parts = []
if question:
parts.append(f"提问: {question}")
if image_desc:
parts.append(f"图片描述: {image_desc}")
parts.append("评估要点: 语音语调、用词准确性、回答完整性")
return "\n".join(parts)
def audit_record_explanations(parsed_json, table_type):
"""Audit all explanations in a record. Returns (has_problems, fixed_json, problem_descs)."""
has_problems = False
problem_descs = []
fixed = copy.deepcopy(parsed_json)
for sub_key, sub_val in parsed_json.items():
if not isinstance(sub_val, dict):
continue
# Check direct explanation at sub-question level
if "explanation" in sub_val:
exp = sub_val["explanation"]
problem, desc = check_explanation_problems(exp, table_type, [], 0)
if problem:
has_problems = True
problem_descs.append(f"{sub_key}.explanation: {desc}")
fixed[sub_key]["explanation"] = generate_writing_explanation(sub_val)
# Check explanations inside questionSet
qset = sub_val.get("questionSet", [])
if qset and len(qset) > 0:
prev_exps = []
for i, q in enumerate(qset):
if not isinstance(q, dict):
continue
if "explanation" in q:
exp = q.get("explanation", "")
problem, desc = check_explanation_problems(exp, table_type, prev_exps, i)
if problem:
has_problems = True
problem_descs.append(f"{sub_key}.questionSet[{i}].explanation: {desc}")
if table_type == "speaking":
fixed[sub_key]["questionSet"][i]["explanation"] = \
generate_speaking_explanation(q, sub_val)
else:
fixed[sub_key]["questionSet"][i]["explanation"] = \
generate_writing_explanation(sub_val)
if "explanation" in q:
prev_exps.append(q["explanation"])
return has_problems, fixed, problem_descs
def audit_table(token, table_id, table_type, audit_field_name):
"""Audit all records in a table."""
records = get_all_records(token, table_id)
result = {"total": len(records), "has_json": 0, "problems": 0, "fixed": 0, "skipped": 0}
for rec in records:
rid = rec["record_id"]
fields = rec.get("fields", {})
jd_raw = fields.get("jsonData", "")
if not jd_raw or jd_raw.strip() == "":
result["skipped"] += 1
continue
try:
parsed = json.loads(jd_raw) if isinstance(jd_raw, str) else jd_raw
except:
result["skipped"] += 1
continue
if not isinstance(parsed, dict) or len(parsed) == 0:
result["skipped"] += 1
continue
result["has_json"] += 1
has_problems, fixed_json, descs = audit_record_explanations(parsed, table_type)
if has_problems:
result["problems"] += 1
result["fixed"] += 1
new_json = json.dumps(fixed_json, ensure_ascii=False)
update_fields = {"jsonData": new_json}
if audit_field_name:
update_fields[audit_field_name] = "修复解析"
update_record(token, table_id, rid, update_fields)
print(f" [FIXED] {rid}: {'; '.join(descs)}")
else:
# No problems - update audit result only
if audit_field_name:
current = fields.get(audit_field_name, "")
if current != "未改动":
update_record(token, table_id, rid, {audit_field_name: "未改动"})
return result
def main():
token = get_token()
print(f"Token: {token[:20]}...")
tables = [
("写作-P1-邮件回复", "tblszuk1TeToofBF", "writing", "审校结果"),
("写作-P2-看图写作", "tblSAwlMumKoyjws", "writing", None), # No audit field
("写作-P3-看图回答题", "tblFc9TVl2PeM2tg", "writing", "审核结果"),
("口语-P2-话题讨论", "tblGoWYBmVI0IrvQ", "speaking", "审核结果"),
("口语-P3-看图回答", "tblOHgNkNer2hGEp", "speaking", "审核结果"),
("口语-P4-看图识物", "tblsD2dxaRpLmkXD", "speaking", None), # No audit field
]
all_results = {}
for name, tid, ttype, audit_field in tables:
print(f"\n{'='*60}")
print(f"审计: {name}")
print(f"{'='*60}")
r = audit_table(token, tid, ttype, audit_field)
all_results[name] = r
print(f" 总记录: {r['total']}, 含jsonData: {r['has_json']}, "
f"有问题: {r['problems']}, 已修复: {r['fixed']}, 跳过: {r['skipped']}")
# Summary
print(f"\n{'='*60}")
print("汇总")
print(f"{'='*60}")
total = sum(r["total"] for r in all_results.values())
t_json = sum(r["has_json"] for r in all_results.values())
t_prob = sum(r["problems"] for r in all_results.values())
t_fix = sum(r["fixed"] for r in all_results.values())
t_skip = sum(r["skipped"] for r in all_results.values())
print(f"{'表名':<20} {'总数':>6} {'有jsonData':>10} {'有问题':>6} {'已修复':>6} {'跳过':>6}")
print("-" * 60)
for name, r in all_results.items():
print(f"{name:<20} {r['total']:>6} {r['has_json']:>10} "
f"{r['problems']:>6} {r['fixed']:>6} {r['skipped']:>6}")
print("-" * 60)
print(f"{'合计':<20} {total:>6} {t_json:>10} {t_prob:>6} {t_fix:>6} {t_skip:>6}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,547 @@
#!/usr/bin/env python3
"""审计单元挑战多维表格中所有听力题型表的解析(explanation)字段"""
import requests
import json
import re
import sys
import copy
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
TABLES = {
"听力-P1-图片选择题/选图题": "tbliZAhcc9C43B23",
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
"听力-P3-长对话选择": "tblgxsDn25oSq7WS",
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
}
# === 问题检测模式 ===
# 选择题/阅读题特有用语(听力题不应出现)
CHOICE_READING_PATTERNS = [
(r'干扰项', '"干扰项"(选择题特有用语)'),
(r'误选', '"误选"(选择题特有用语)'),
(r'所以选[ABCDEFGH]', '"所以选X"格式(选择题用语)'),
(r'正确答案是', '"正确答案是"(过度直白)'),
(r'如果有人[误错]?选', '"如果有人错选"(选择题干扰分析)'),
(r'如果[误错]?选', '"如果误选"等假设用语'),
(r'排除[法项]', '"排除法/项"(选择题策略用语)'),
(r'干扰[因素析]', '含干扰分析用语'),
(r'容易混淆|容易选错|可能会选|不要选', '含混淆/选错提示(选择题口吻)'),
(r'选[ABCDEFGH][^项择]', '"选X"表述(选择题用语)'),
(r'其他选项[^,。,.\n]{0,30}(没有|不是|错误|不对)', '"其他选项没有/错误"(选择题干扰分析)'),
(r'选项[ABCDEFGH][^,。,.\n]{0,20}(没有|不在|不是)', '含具体选项否定分析'),
(r'虽然[^,。,.\n]{0,20}(接近|相似|类似)', '"虽然…接近"(干扰项比较)'),
(r'材料中[^,。,.\n]{0,10}(写到|明确说)', '"材料中写到/明确说"(听力应说"音频中"'),
(r'原文中[^,。,.\n]{0,10}(写到|说)', '"原文中写到"(应说"音频中"'),
]
# 不匹配的能力标签
ABILITY_MISMATCH = [
(r'写作能力|书面表达|写作技巧', '含写作能力标签(与听力题不匹配)'),
(r'口语表达|发音准确|口语技巧', '含口语能力标签(与听力题不匹配)'),
(r'拼写能力|拼写规则', '含拼写能力标签(与听力题不匹配)'),
(r'语法结构分析|句式变换', '含语法分析标签(听力题应侧重理解)'),
(r'阅读理解|阅读技巧|快速阅读', '含阅读能力标签(这是听力题)'),
]
def get_token():
resp = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET},
timeout=30,
)
data = resp.json()
return data["tenant_access_token"]
def get_all_records(token, table_id):
"""读取表内全部记录"""
records = []
page_token = None
while True:
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records?page_size=500"
if page_token:
url += f"&page_token={page_token}"
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
data = resp.json()
if data.get("code") != 0:
print(f" ERROR reading: code={data.get('code')} msg={data.get('msg')}")
break
items = data.get("data", {}).get("items", [])
records.extend(items)
if not data.get("data", {}).get("has_more"):
break
page_token = data.get("data", {}).get("page_token")
return records
def parse_json_data(fields):
"""从fields中解析jsonData"""
jd = fields.get("jsonData")
if not jd:
return None
if isinstance(jd, str):
try:
return json.loads(jd)
except json.JSONDecodeError:
return None
return jd
def get_parts(json_data):
"""获取jsonData中的所有part键first, second等"""
parts = []
for key in ['first', 'second', 'third', 'fourth']:
if key in json_data and isinstance(json_data[key], dict):
parts.append(key)
return parts
def get_explanations_from_question_set(question_set):
"""从questionSet中提取所有explanation"""
results = []
if not isinstance(question_set, list):
return results
for idx, q in enumerate(question_set):
if not isinstance(q, dict):
continue
exp = q.get("explanation", "")
if exp and isinstance(exp, str) and exp.strip():
results.append({
"index": idx,
"explanation": exp.strip(),
"question_text": q.get("question", "") or q.get("questionDesc", "") or "",
"ability": q.get("ability", ""),
})
return results
def check_explanation(exp_text, question_text="", table_name=""):
"""检查单个explanation是否有问题"""
if not exp_text or not exp_text.strip():
return False, ""
exp = exp_text.strip()
# 1. 选择题/阅读题特有用语
for pattern, desc in CHOICE_READING_PATTERNS:
if re.search(pattern, exp):
return True, desc
# 2. 能力标签错配
for pattern, desc in ABILITY_MISMATCH:
if re.search(pattern, exp):
return True, desc
# 3. 纯能力标签描述(没有实际解析内容)
# 如果explanation主要由能力标签组成缺少音频信息分析
if re.match(r'^[\s]*干扰抑制|显性事实|显性细节|隐性推理|多特征整合|信息筛选|听觉抓取', exp):
# 检查是否有实际解析内容
if len(exp) < 40 or not re.search(r'音频|听到|提到|说|描述|回答|对话|原文', exp):
return True, "仅含能力标签,缺少音频信息分析的解析内容"
return False, ""
def fix_explanation(exp_text, question_text="", question_index=0, table_name=""):
"""修复有问题的explanation"""
if not exp_text or not isinstance(exp_text, str):
return exp_text
exp = exp_text.strip()
# 移除选择题/阅读题特有用语
exp = re.sub(r'干扰项[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
exp = re.sub(r'[,。]?\s*如果有人[误错]?选[^,。,.\n]{0,60}[,。,.\n]?', '', exp)
exp = re.sub(r'[,。]?\s*如果[误错]?选[^,。,.\n]{0,60}[,。,.\n]?', '', exp)
exp = re.sub(r'所以选[ABCDEFGH][,。]?', '', exp)
exp = re.sub(r'正确答案是[^,。,.\n]{0,30}[,。,.\n]?', '', exp)
exp = re.sub(r'排除[法项][^,。,.\n]{0,30}[,。,.\n]?', '', exp)
exp = re.sub(r'干扰[因素析][^,。,.\n]{0,30}[,。,.\n]?', '', exp)
exp = re.sub(r'容易混淆[^,。,.\n]{0,35}[,。,.\n]?', '', exp)
exp = re.sub(r'可能会选错[^,。,.\n]{0,35}[,。,.\n]?', '', exp)
exp = re.sub(r'其他选项[^,。,.\n]{0,40}(?:没有|不是|错误|不对)[^,。,.\n]{0,20}[,。,.\n]?', '', exp)
exp = re.sub(r'选项[ABCDEFGH][^,。,.\n]{0,25}(?:没有|不在|不是)[^,。,.\n]{0,20}[,。,.\n]?', '', exp)
exp = re.sub(r'虽然[^,。,.\n]{0,20}(?:接近|相似|类似)[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
# 替换"材料中…"→"音频中…""原文中…"→"音频中…"
exp = re.sub(r'材料中([^,。,.\n]{0,10})(提到|写到|说)', r'音频中\1\2', exp)
exp = re.sub(r'原文中([^,。,.\n]{0,10})(写到|说|提到)', r'音频中\1\2', exp)
# 保留"答案是X"但更自然地改写
exp = re.sub(r'答案是([ABCDEFGH])[,。]?', r'对应选项\1。', exp)
exp = re.sub(r'答案是([^,。,.\n]{1,20})[,。]?', r'答案为\1。', exp)
# 清理
exp = re.sub(r'[,]\s*[,]', '', exp)
exp = re.sub(r'[。.]\s*[。.]', '', exp)
exp = re.sub(r'^\s*[,]\s*', '', exp)
exp = re.sub(r'\s+', '', exp).strip()
# 如果清理后几乎为空,生成基础解析
if not exp or len(exp) < 10:
if question_text and question_text.strip():
exp = f"根据音频中的关键信息进行判断,确认答案。"
else:
exp = f"根据音频内容理解,确认正确答案。"
# 确保以句号结尾
if exp and not exp.endswith(('', '', '', '')):
exp += ''
return exp
def fix_p5_explanation(exp_text, table_name=""):
"""修复P5信息匹配题的整段explanation¥¥分隔"""
if not exp_text or not isinstance(exp_text, str):
return exp_text
# 按¥¥分割
segments = exp_text.split('¥¥')
fixed_segments = []
for seg in segments:
seg = seg.strip()
if not seg:
continue
# 同样的清理逻辑
seg = re.sub(r'干扰项[^,。,.\n]{0,40}[,。,.\n]?', '', seg)
seg = re.sub(r'[,。]?\s*如果有人[误错]?选[^,。,.\n]{0,60}[,。,.\n]?', '', seg)
seg = re.sub(r'[,。]?\s*如果[误错]?选[^,。,.\n]{0,60}[,。,.\n]?', '', seg)
seg = re.sub(r'所以选[ABCDEFGH][,。]?', '', seg)
seg = re.sub(r'正确答案是[^,。,.\n]{0,30}[,。,.\n]?', '', seg)
seg = re.sub(r'排除[法项][^,。,.\n]{0,30}[,。,.\n]?', '', seg)
seg = re.sub(r'其他选项[^,。,.\n]{0,40}(?:没有|不是|错误|不对)[^,。,.\n]{0,20}[,。,.\n]?', '', seg)
seg = re.sub(r'虽然[^,。,.\n]{0,20}(?:接近|相似|类似)[^,。,.\n]{0,40}[,。,.\n]?', '', seg)
seg = re.sub(r'材料中([^,。,.\n]{0,10})(提到|写到|说)', r'音频中\1\2', seg)
seg = re.sub(r'原文中([^,。,.\n]{0,10})(写到|说|提到)', r'音频中\1\2', seg)
seg = re.sub(r'答案是([ABCDEFGH])[,。]?', r'对应选项\1。', seg)
seg = re.sub(r'答案是([^,。,.\n]{1,20})[,。]?', r'答案为\1。', seg)
seg = re.sub(r'\s+', '', seg).strip()
seg = re.sub(r'[,]\s*[,]', '', seg)
seg = re.sub(r'^\s*[,]\s*', '', seg)
if seg and not seg.endswith(('', '', '', '')):
seg += ''
if seg:
fixed_segments.append(seg)
return '¥¥'.join(fixed_segments)
def process_record(record, table_name, table_id, token):
"""处理单条记录,返回 (fixed_count, problem_count)"""
record_id = record.get("record_id")
fields = record.get("fields", {})
json_data = parse_json_data(fields)
if not json_data:
return 0, 0, False
parts = get_parts(json_data)
if not parts:
return 0, 0, False
modified = False
total_fixed = 0
total_problems = 0
for part_key in parts:
part = json_data[part_key]
part_type = part.get("type", "")
# 检查 questionSet 中的 explanationP1, P2, P3, P4, P7
if "questionSet" in part:
question_set = part["questionSet"]
if not isinstance(question_set, list):
continue
all_exps = get_explanations_from_question_set(question_set)
# 检查所有explanation是否完全相同2个及以上非空
non_empty = [e["explanation"] for e in all_exps if e["explanation"]]
all_same = len(non_empty) > 1 and len(set(non_empty)) == 1
for exp_info in all_exps:
idx = exp_info["index"]
exp = exp_info["explanation"]
qt = exp_info["question_text"]
has_problem, reason = check_explanation(exp, qt, table_name)
if all_same and len(non_empty) > 1:
has_problem = True
if not reason:
reason = "同一部分内所有子题explanation完全相同"
if has_problem:
total_problems += 1
fixed = fix_explanation(exp, qt, idx, table_name)
question_set[idx]["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.Q{idx+1}: {reason}")
print(f" OLD: {exp[:120]}...")
print(f" NEW: {fixed[:120]}...")
# P5: explanation at part level
if "explanation" in part and part_type == "listening_matchInfo":
exp = part.get("explanation", "")
if not exp or not isinstance(exp, str) or not exp.strip():
continue
has_problem, reason = check_explanation(exp, "", table_name)
# Also check individual ¥¥-separated segments
if not has_problem:
segments = exp.split('¥¥')
for seg in segments:
seg = seg.strip()
if not seg:
continue
sp, sr = check_explanation(seg, "", table_name)
if sp:
has_problem = True
reason = sr
break
if has_problem:
total_problems += 1
fixed = fix_p5_explanation(exp, table_name)
part["explanation"] = fixed
modified = True
total_fixed += len(exp.split('¥¥')) # rough count
print(f" [{table_name}] {part_key}.explanation: {reason}")
print(f" OLD: {exp[:150]}...")
print(f" NEW: {fixed[:150]}...")
# P7 also sometimes has explanation at top level covering all sub-answers
if "explanation" in part and part_type == "listening_drag":
exp = part.get("explanation", "")
if not exp or not isinstance(exp, str) or not exp.strip():
continue
# P7's explanation might be in questionSet already (we checked above)
# But some have it at part level too. Check if we already handled via questionSet
# For now, if the part-level explanation is different from questionSet ones
has_problem, reason = check_explanation(exp, "", table_name)
if has_problem:
total_problems += 1
fixed = fix_explanation(exp, "", 0, table_name)
part["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.top-explanation: {reason}")
print(f" OLD: {exp[:150]}...")
print(f" NEW: {fixed[:150]}...")
return total_fixed, total_problems, modified
def update_record(token, table_id, record_id, json_data, review_result="修复解析"):
"""更新记录"""
json_str = json.dumps(json_data, ensure_ascii=False)
update_body = {
"fields": {
"jsonData": json_str,
"审校结果": review_result
}
}
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records/{record_id}"
resp = requests.put(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8"
},
json=update_body,
timeout=30,
)
result = resp.json()
return result.get("code") == 0
def process_table(token, table_name, table_id):
"""处理单个表"""
print(f"\n{'='*60}")
print(f"表: {table_name} ({table_id})")
print(f"{'='*60}")
records = get_all_records(token, table_id)
print(f"总记录数: {len(records)}")
table_total_fixed = 0
table_total_problems = 0
table_total_updated = 0
for record in records:
record_id = record.get("record_id")
fields = record.get("fields", {})
json_data = parse_json_data(fields)
if not json_data:
continue
# 深拷贝用于修改
updated_data = copy.deepcopy(json_data)
fixed, problems, modified = process_record_on_data(
updated_data, table_name
)
table_total_fixed += fixed
table_total_problems += problems
if modified:
success = update_record(token, table_id, record_id, updated_data)
if success:
table_total_updated += 1
else:
print(f" FAIL: update failed for {record_id}")
print(f"\n表统计: 有问题{table_total_problems}处, 修复{table_total_fixed}处, 更新{table_total_updated}条记录")
return {
"table_name": table_name,
"total_records": len(records),
"total_problems": table_total_problems,
"total_fixed": table_total_fixed,
"total_updated": table_total_updated,
}
def process_record_on_data(json_data, table_name=""):
"""在json_data上执行修复返回fix count"""
parts = get_parts(json_data)
if not parts:
return 0, 0, False
modified = False
total_fixed = 0
total_problems = 0
for part_key in parts:
part = json_data[part_key]
part_type = part.get("type", "")
if "questionSet" in part:
question_set = part["questionSet"]
if not isinstance(question_set, list):
continue
all_exps = get_explanations_from_question_set(question_set)
non_empty = [e["explanation"] for e in all_exps if e["explanation"]]
all_same = len(non_empty) > 1 and len(set(non_empty)) == 1
for exp_info in all_exps:
idx = exp_info["index"]
exp = exp_info["explanation"]
qt = exp_info["question_text"]
has_problem, reason = check_explanation(exp, qt, table_name)
if all_same and len(non_empty) > 1:
has_problem = True
reason = "同一部分内所有子题explanation完全相同"
if has_problem:
total_problems += 1
fixed = fix_explanation(exp, qt, idx, table_name)
question_set[idx]["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.Q{idx+1}: {reason}")
print(f" OLD: {exp[:120]}...")
print(f" NEW: {fixed[:120]}...")
if "explanation" in part and part_type in ("listening_matchInfo", "listening_drag"):
exp = part.get("explanation", "")
if not exp or not isinstance(exp, str) or not exp.strip():
continue
has_problem, reason = False, ""
if part_type == "listening_matchInfo":
segments = exp.split('¥¥')
for seg in segments:
seg = seg.strip()
if not seg:
continue
sp, sr = check_explanation(seg, "", table_name)
if sp:
has_problem = True
reason = sr
break
else:
has_problem, reason = check_explanation(exp, "", table_name)
if has_problem:
total_problems += 1
if part_type == "listening_matchInfo":
fixed = fix_p5_explanation(exp, table_name)
else:
fixed = fix_explanation(exp, "", 0, table_name)
part["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.explanation: {reason}")
print(f" OLD: {exp[:150]}...")
print(f" NEW: {fixed[:150]}...")
return total_fixed, total_problems, modified
def main():
print("=" * 60)
print("听力题型解析(explanation)字段审计与修复")
print("=" * 60)
token = get_token()
print(f"Token: {token[:15]}...")
all_results = []
for table_name, table_id in TABLES.items():
result = process_table(token, table_name, table_id)
all_results.append(result)
# 汇总
print("\n\n" + "=" * 70)
print("审计汇总")
print("=" * 70)
total_problems = sum(r["total_problems"] for r in all_results)
total_fixed = sum(r["total_fixed"] for r in all_results)
total_updated = sum(r["total_updated"] for r in all_results)
print(f"\n{'表名':<30} {'记录':>5} {'有问题':>6} {'修复':>6} {'更新记录':>8}")
print("-" * 65)
for r in all_results:
print(f"{r['table_name']:<30} {r['total_records']:>5} {r['total_problems']:>6} {r['total_fixed']:>6} {r['total_updated']:>8}")
print("-" * 65)
print(f"{'合计':<30} {'':>5} {total_problems:>6} {total_fixed:>6} {total_updated:>8}")
# 保存结果
output = {
"summary": {
"total_problems": total_problems,
"total_fixed": total_fixed,
"total_updated": total_updated,
},
"tables": all_results,
}
with open("/root/.openclaw/workspace-xiaoyan/output/audit_listening_explanation_results.json", "w", encoding="utf-8") as f:
json.dump(output, f, ensure_ascii=False, indent=2)
print(f"\n详细结果已保存到 output/audit_listening_explanation_results.json")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,448 @@
#!/usr/bin/env python3
"""审计+修复单元挑战多维表格听力题型表的解析(explanation)字段 - v2"""
import requests
import json
import re
import copy
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
TABLES = {
"听力-P1-图片选择题/选图题": "tbliZAhcc9C43B23",
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
"听力-P3-长对话选择": "tblgxsDn25oSq7WS",
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
}
# === 检测模式(只判断是否需要修复)===
CHOICE_READING_PATTERNS = [
(r'干扰项', '"干扰项"'),
(r'误选', '"误选"'),
(r'所以选[ABCDEFGH]', '"所以选X"'),
(r'正确答案是', '"正确答案是"'),
(r'如果有人[误错]?选', '"如果有人错选"'),
(r'如果[误错]?选', '"如果误选"'),
(r'排除[法项]', '"排除法/项"'),
(r'干扰[因素析]', '含干扰分析用语'),
(r'容易混淆|容易选错|可能会选|不要选', '含混淆/选错提示'),
(r'因此选[ABCDEFGH][,。]', '"因此选X"'),
(r'故选[ABCDEFGH][,。]', '"故选X"'),
(r'其他选项[^,。,.\n]{0,30}(没有|不是|错误|不对)', '"其他选项没有/错误"'),
(r'选项[ABCDEFGH][^,。,.\n]{0,20}(没有|不在|不是)', '含具体选项否定分析'),
(r'虽然[^,。,.\n]{0,20}(接近|相似|类似)', '"虽然…接近"'),
(r'材料中[^,。,.\n]{0,10}(写到|明确说)', '"材料中写到/明确说"'),
(r'原文中[^,。,.\n]{0,10}(写到|说)', '"原文中写到"'),
(r'如果有人选', '含干扰选分析'),
]
ABILITY_MISMATCH = [
(r'写作能力|书面表达|写作技巧', '含写作能力标签'),
(r'口语表达|发音准确|口语技巧', '含口语能力标签'),
(r'拼写能力|拼写规则', '含拼写能力标签'),
(r'阅读理解|阅读技巧|快速阅读', '含阅读能力标签'),
]
def get_token():
resp = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET},
timeout=30,
)
return resp.json()["tenant_access_token"]
def get_all_records(token, table_id):
records = []
page_token = None
while True:
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records?page_size=500"
if page_token:
url += f"&page_token={page_token}"
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
data = resp.json()
if data.get("code") != 0:
print(f" ERROR: {data.get('code')} {data.get('msg')}")
break
items = data.get("data", {}).get("items", [])
records.extend(items)
if not data.get("data", {}).get("has_more"):
break
page_token = data.get("data", {}).get("page_token")
return records
def parse_json_data(fields):
jd = fields.get("jsonData")
if not jd:
return None
if isinstance(jd, str):
try:
return json.loads(jd)
except json.JSONDecodeError:
return None
return jd
def get_parts(json_data):
parts = []
for key in ['first', 'second', 'third', 'fourth']:
if key in json_data and isinstance(json_data[key], dict):
parts.append(key)
return parts
def check_one(exp_text):
"""检查单个explanation是否有问题"""
if not exp_text or not exp_text.strip():
return False, ""
for pattern, desc in CHOICE_READING_PATTERNS:
if re.search(pattern, exp_text):
return True, desc
for pattern, desc in ABILITY_MISMATCH:
if re.search(pattern, exp_text):
return True, desc
return False, ""
def fix_explanation(exp_text):
"""修复单个explanation"""
if not exp_text or not isinstance(exp_text, str):
return exp_text
exp = exp_text.strip()
# === 移除选择题/阅读题特有用语 ===
# "干扰项分析" → 移除
exp = re.sub(r'干扰项分析[:][^。!?…]{0,80}', '', exp)
exp = re.sub(r'干扰项[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
# "如果有人错选/如果误选…" → 移除(保留前面的内容)
exp = re.sub(r'[;]\s*如果有人[误错]?选[^。!?…]{0,80}', '', exp)
exp = re.sub(r'[;]\s*如果[误错]?选[^。!?…]{0,80}', '', exp)
# 单独出现的"如果有人选错"子句
exp = re.sub(r',如果有人[误错]?选[^。!?…]{0,80}', '', exp)
# "如果选错/如果误选…" — 更广匹配
exp = re.sub(r'[;,]\s*如果选错[^。!?…]{0,80}', '', exp)
exp = re.sub(r'[;,]\s*如果误选[^。!?…]{0,80}', '', exp)
# "所以选X" → 移除
exp = re.sub(r'所以选[ABCDEFGH][,。]?', '', exp)
# "因此选X。" → 移除
exp = re.sub(r',因此选[ABCDEFGH]。', '', exp)
exp = re.sub(r'因此选[ABCDEFGH][,。]?', '', exp)
# "故选X。" → 改为自然表述
exp = re.sub(r',故选[ABCDEFGH][,。]?', '', exp)
exp = re.sub(r'故选[ABCDEFGH][,。]?', '', exp)
# "正确答案是X[选项]" → 移除,保留前后内容
exp = re.sub(r'[,]?\s*因此正确答案是[^,。]{0,30}选项[ABC][,。]?', '', exp)
exp = re.sub(r'[,]?\s*因此正确答案是[ABC][,。]?', '', exp)
exp = re.sub(r'[,]?\s*正确答案是[^,。]{0,30}选项[ABC][,。]?', '', exp)
exp = re.sub(r'[,]?\s*正确答案是[ABC][,。]?', '', exp)
exp = re.sub(r'[,]?\s*正确答案是\s*B\s*\.\s*draw[^。]{0,50}', '', exp)
exp = re.sub(r'[,]?\s*正确答案是\s*[ABCL]\s*\.\s*[a-z][^。!?…]{0,30}[,。]?', '', exp)
# "答案是X" → 更自然
exp = re.sub(r'答案是([ABCDEFGH])[,。]?', r'对应选项\1。', exp)
exp = re.sub(r'答案是([^,。]{1,20})[,。]?', r'答案为\1。', exp)
# "排除法/排除项"
exp = re.sub(r'排除[法项][^,。,.\n]{0,30}[,。,.\n]?', '', exp)
# "容易混淆/容易选错"
exp = re.sub(r'[,。]?\s*容易混淆[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
exp = re.sub(r'[,。]?\s*容易选错[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
exp = re.sub(r'[,。]?\s*可能会选错[^,。,.\n]{0,40}[,。,.\n]?', '', exp)
# "其他选项没有/错误…" → 移除
exp = re.sub(r'[,]?\s*选择[ABC]是正确的[,]?\s*因为其他选项[^。!?…]{0,80}[。]?', '', exp)
exp = re.sub(r'[,]?\s*其他选项[^。!?…]{0,40}[,。,.\n]?', '', exp)
# "选项X没有/不在/不是…" → 移除
exp = re.sub(r'选项[ABCDEFGH][^,。,.\n]{0,25}(?:没有|不在|不是|不正确|错误)[^,。,.\n]{0,20}[,。,.\n]?', '', exp)
# "虽然X接近/相似…" → 移除
exp = re.sub(r'[,。]?\s*虽然[^,。,.\n]{0,20}(?:接近|相似|类似)[^,。,.\n]{0,50}[,。,.\n]?', '', exp)
# "材料中…" → "音频中…"
exp = re.sub(r'材料中([^,。,.\n]{0,10})(提到|写到|说)', r'音频中\1\2', exp)
exp = re.sub(r'原文中([^,。,.\n]{0,10})(写到|说|提到)', r'音频中\1\2', exp)
# "干扰因素/干扰析"
exp = re.sub(r'干扰[因素析][^,。,.\n]{0,30}[,。,.\n]?', '', exp)
# === 清理 ===
# 只清理中文标点周围的空格,保留英文单词间的空格
# 移除中文文本中多余的空格(中文字符之间的空格)
# 但保留英文单词/数字之间的空格
def clean_spaces(m):
return m.group(0).replace(' ', '')
# 中文字符+可选空格+中文字符 → 移除空格
exp = re.sub(r'[\u4e00-\u9fff] +[\u4e00-\u9fff]', lambda m: m.group(0).replace(' ', ''), exp)
# 中文标点+空格+中文字符
exp = re.sub(r'([,。!?…、;:""''()【】]) +([\u4e00-\u9fff])', r'\1\2', exp)
# 中文字符+空格+中文标点
exp = re.sub(r'([\u4e00-\u9fff]) +([,。!?…、;:""''()【】])', r'\1\2', exp)
# 清理多余标点(中文)
exp = re.sub(r'[,]\s*[,]', '', exp)
exp = re.sub(r'[。.]\s*[。.]', '', exp)
exp = re.sub(r'[;]\s*[;]', '', exp)
# 移除开头多余的逗号
exp = re.sub(r'^[,]\s*', '', exp)
exp = re.sub(r'^[。.]\s*', '', exp)
# 移除"因此。"这样的孤悬词(没有后续内容)
exp = re.sub(r'因此[。]{2,}', '', exp)
# 如果explanation以"因此。"结尾且之前有完整内容,保留之前的句号
# 一般性地清理
exp = exp.strip()
# 如果清理后几乎为空
if not exp or len(exp) < 8:
return "根据音频中的关键信息进行判断,确认答案。"
# 确保以句号结尾
if exp and not exp.endswith(('', '', '', '', '.')):
exp += ''
# 把英文句号结尾的也改为中文句号(除非是英文缩写点)
exp = re.sub(r'([\u4e00-\u9fff])\.$', r'\1。', exp)
return exp
def fix_p5_explanation(exp_text):
"""修复P5信息匹配题的整段explanation¥¥分隔"""
if not exp_text or not isinstance(exp_text, str):
return exp_text
segments = exp_text.split('¥¥')
fixed_segments = []
for seg in segments:
seg = seg.strip()
if not seg:
continue
fixed = fix_explanation(seg)
if fixed:
fixed_segments.append(fixed)
return '¥¥'.join(fixed_segments)
def process_record(json_data, table_name=""):
"""检查+修复单条记录返回fixed_count, problem_count, modified"""
parts = get_parts(json_data)
if not parts:
return 0, 0, False
modified = False
total_fixed = 0
total_problems = 0
for part_key in parts:
part = json_data[part_key]
part_type = part.get("type", "")
# === 处理 questionSet ===
if "questionSet" in part:
question_set = part["questionSet"]
if not isinstance(question_set, list):
continue
# 收集所有非空explanation
all_exps = []
for qi, q in enumerate(question_set):
if not isinstance(q, dict):
continue
exp = q.get("explanation", "")
if exp and isinstance(exp, str) and exp.strip():
all_exps.append((qi, exp.strip()))
non_empty = [e[1] for e in all_exps]
all_same = len(non_empty) > 1 and len(set(non_empty)) == 1
for qi, q in enumerate(question_set):
if not isinstance(q, dict):
continue
exp = q.get("explanation", "")
if not exp or not isinstance(exp, str) or not exp.strip():
continue
has_problem, reason = check_one(exp)
if all_same and len(non_empty) > 1:
has_problem = True
reason = "同一部分内所有子题explanation完全相同"
if has_problem:
total_problems += 1
old_exp = exp
fixed = fix_explanation(exp)
q["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.Q{qi+1}: {reason}")
print(f" OLD: {old_exp[:120]}...")
print(f" NEW: {fixed[:120]}...")
# === 处理 top-level explanation (P5, P7) ===
if "explanation" in part and part_type in ("listening_matchInfo", "listening_drag"):
exp = part.get("explanation", "")
if not exp or not isinstance(exp, str) or not exp.strip():
continue
has_problem, reason = False, ""
if part_type == "listening_matchInfo":
# 检查每个¥¥分隔的段落
segments = exp.split('¥¥')
for seg in segments:
seg = seg.strip()
if not seg:
continue
sp, sr = check_one(seg)
if sp:
has_problem = True
reason = sr
break
else:
has_problem, reason = check_one(exp)
if has_problem:
total_problems += 1
old_exp = exp
if part_type == "listening_matchInfo":
fixed = fix_p5_explanation(exp)
else:
fixed = fix_explanation(exp)
part["explanation"] = fixed
modified = True
total_fixed += 1
print(f" [{table_name}] {part_key}.explanation: {reason}")
print(f" OLD: {old_exp[:150]}...")
print(f" NEW: {fixed[:150]}...")
return total_fixed, total_problems, modified
def update_record(token, table_id, record_id, json_data):
json_str = json.dumps(json_data, ensure_ascii=False)
update_body = {
"fields": {
"jsonData": json_str,
"审校结果": "修复解析"
}
}
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{table_id}/records/{record_id}"
resp = requests.put(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8"
},
json=update_body,
timeout=30,
)
result = resp.json()
if result.get("code") != 0:
print(f" UPDATE FAILED: {result.get('code')} {result.get('msg')}")
return False
return True
def process_table(token, table_name, table_id):
print(f"\n{'='*60}")
print(f"表: {table_name} ({table_id})")
print(f"{'='*60}")
records = get_all_records(token, table_id)
print(f"总记录数: {len(records)}")
total_fixed = 0
total_problems = 0
total_updated = 0
for record in records:
record_id = record.get("record_id")
fields = record.get("fields", {})
json_data = parse_json_data(fields)
if not json_data:
continue
updated_data = copy.deepcopy(json_data)
fixed, problems, modified = process_record(updated_data, table_name)
total_fixed += fixed
total_problems += problems
if modified:
success = update_record(token, table_id, record_id, updated_data)
if success:
total_updated += 1
print(f"\n表统计: 有问题{total_problems}处, 修复{total_fixed}处, 更新{total_updated}条记录")
return {
"table_name": table_name,
"total_records": len(records),
"total_problems": total_problems,
"total_fixed": total_fixed,
"total_updated": total_updated,
}
def main():
print("=" * 60)
print("听力题型解析(explanation)字段审计与修复 v2")
print("=" * 60)
token = get_token()
print(f"Token: {token[:15]}...")
all_results = []
for table_name, table_id in TABLES.items():
result = process_table(token, table_name, table_id)
all_results.append(result)
# 汇总
print("\n\n" + "=" * 70)
print("审计汇总 v2")
print("=" * 70)
total_problems = sum(r["total_problems"] for r in all_results)
total_fixed = sum(r["total_fixed"] for r in all_results)
total_updated = sum(r["total_updated"] for r in all_results)
print(f"\n{'表名':<30} {'记录':>5} {'有问题':>6} {'修复':>6} {'更新记录':>8}")
print("-" * 65)
for r in all_results:
print(f"{r['table_name']:<30} {r['total_records']:>5} {r['total_problems']:>6} {r['total_fixed']:>6} {r['total_updated']:>8}")
print("-" * 65)
print(f"{'合计':<30} {'':>5} {total_problems:>6} {total_fixed:>6} {total_updated:>8}")
output = {
"summary": {"total_problems": total_problems, "total_fixed": total_fixed, "total_updated": total_updated},
"tables": all_results,
}
with open("/root/.openclaw/workspace-xiaoyan/output/audit_listening_explanation_results.json", "w", encoding="utf-8") as f:
json.dump(output, f, ensure_ascii=False, indent=2)
print(f"\n详细结果已保存到 output/audit_listening_explanation_results.json")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,180 @@
#!/usr/bin/env python3
"""Inject text output rules into all production skill SKILL.md files."""
import os, re
TEXT_RULES = """
## 文本输出规范(强制执行)
所有输出的文本内容台词题目选项解析音频文本阅读文章等必须遵守以下规则
1. 禁止 Markdown 标记禁止使用 ** * __ _ 等加粗/斜体标识也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先单词涉及英美式拼写差异时 colour/colorcentre/centertravelling/traveling统一选择英式拼写
3. 标点符号规范严格区分全角/半角符号中文内容使用全角标点英文内容使用半角标点. , ! ?不得混用
"""
# Files already updated (core files - skip these)
ALREADY_UPDATED = {
'unit_challenge_core/SKILL.md',
'unit_challenge_master/SKILL.md',
'script-component-production/SKILL.md',
'kids-english-script-production/SKILL.md',
'core-content-json-standard/SKILL.md',
'interactive-component-json/SKILL.md',
}
WORKSPACE = '/root/.openclaw/workspace-xiaoyan'
def find_skill_files(base_dir):
"""Find all SKILL.md files under base_dir."""
result = []
for root, dirs, files in os.walk(base_dir):
for f in files:
if f == 'SKILL.md':
rel_path = os.path.relpath(os.path.join(root, f), WORKSPACE)
result.append(os.path.join(root, f))
return result
def has_text_rules(content):
"""Check if file already has text output rules."""
return '禁止 Markdown 标记' in content or '英式拼写优先' in content
def insert_rules(content, anchor_pattern, position='before'):
"""Insert TEXT_RULES relative to anchor_pattern."""
if has_text_rules(content):
return None # Already has rules
# Find the anchor
lines = content.split('\n')
# Find the line matching anchor_pattern
target_idx = None
for i, line in enumerate(lines):
if re.search(anchor_pattern, line):
target_idx = i
break
if target_idx is None:
# Try alternative: insert after frontmatter (second ---)
count = 0
for i, line in enumerate(lines):
if line.strip() == '---':
count += 1
if count == 2:
target_idx = i
break
if target_idx is not None:
# Insert after the first heading after frontmatter
for i in range(target_idx + 1, len(lines)):
if lines[i].startswith('# '):
target_idx = i
break
if target_idx is None:
print(f" Could not find insertion point")
return None
if position == 'before':
insert_idx = target_idx
elif position == 'after':
# Find end of the section (next ## heading or empty line then non-empty)
insert_idx = target_idx
for i in range(target_idx + 1, len(lines)):
if lines[i].startswith('## '):
insert_idx = i - 1
break
else:
insert_idx = len(lines) - 1
new_lines = lines[:insert_idx] + [TEXT_RULES] + lines[insert_idx:]
return '\n'.join(new_lines)
def main():
# Find all skill files
skill_dirs = [
os.path.join(WORKSPACE, 'skills'),
os.path.join(WORKSPACE, 'business_production'),
]
all_files = []
for d in skill_dirs:
if os.path.isdir(d):
all_files.extend(find_skill_files(d))
updated = 0
skipped = 0
# Define insertion strategies per file category
for filepath in all_files:
rel = os.path.relpath(filepath, WORKSPACE)
# Skip already updated
if any(rel.endswith(skip) for skip in ALREADY_UPDATED):
skipped += 1
continue
# Skip non-text-production skills
skip_patterns = [
'lark_bitable_operate_as_bot',
'lark_wiki_operate_as_bot',
'feishu-embedded-sheet',
'bitable-reader',
'vala_git_workspace_backup',
'feishu-table-translate-fill',
]
if any(p in rel for p in skip_patterns):
skipped += 1
continue
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
if has_text_rules(content):
skipped += 1
continue
# Choose anchor based on file type
if 'questions/' in rel:
# Unit challenge question types - insert before "## 核心功能"
anchor = r'^##\s+核心功能'
position = 'before'
elif 'dialogue-' in rel or 'task-router' in rel:
# Dialogue component skills - insert before "## 配置格式" or "## 触发"
anchor = r'^##\s+(配置格式|触发|核心|规则|组件)'
position = 'before'
elif '组件生产' in rel:
# Component production skills
anchor = r'^##\s+核心功能'
position = 'before'
elif 'audit' in rel:
# Audit skills
anchor = r'^##\s+审校'
position = 'before'
elif 'cambridge' in rel:
# Cambridge exam library
anchor = r'^##\s+'
position = 'before'
elif 'knowledge-mastery' in rel:
# Calculator - skip
skipped += 1
continue
else:
# Default: insert after frontmatter, before first ## heading
anchor = r'^##\s+'
position = 'before'
new_content = insert_rules(content, anchor, position)
if new_content is None:
skipped += 1
continue
with open(filepath, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f" Updated: {rel}")
updated += 1
print(f"\nDone: {updated} updated, {skipped} skipped")
if __name__ == '__main__':
main()

View File

@ -22,6 +22,16 @@ description: Level 1 配置表(句子知识点)自动化审校技能。覆
例: 1214001 = L1 Season2, Unit14, 序列001
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 审校流程
```

View File

@ -8,6 +8,16 @@ metadata:
source: "官方2022-2024版真题集"
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 适用场景
当需要查询以下信息时使用本技能:
1. 剑桥Starters/Movers/Flyers/KET考试的题型结构、分值、考试时长

View File

@ -25,6 +25,12 @@ metadata:
# 第一部分:通用结构(所有核心互动共用)
## 0. 文本输出规范(所有字段文本内容强制遵守)
1. 禁止 Markdown 标记:所有 jsonData 内文本字段禁止使用 `**` `*` `__` `_` `#` `>` `-` 等 Markdown 语法,纯文本输出
2. 英式拼写优先英美式拼写差异统一英式colour/centre/travelling 等)
3. 标点符号规范:中文内容全角标点(,。!?),英文内容半角标点(. , ! ?),不混用
## 1. 通用字段
| 字段 | 类型 | 说明 | 出现率 |

View File

@ -10,6 +10,16 @@ metadata:
# 对话选择组件配置规范
## 适用场景
当【类型】列内容为【对话选择】或【对话选择-配图】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】:

View File

@ -10,6 +10,16 @@ metadata:
# 核心互动导览组件配置规范
## 适用场景
当【类型】列内容为【核心互动】【导览配置】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】用户看到的任务名建议字数在10字以内

View File

@ -10,6 +10,16 @@ metadata:
# 对话挖空组件配置规范
## 适用场景
当【类型】列内容为【对话挖空】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】:结合剧情上下文设计语义化标题,点明互动核心,例如「介绍照片」

View File

@ -10,6 +10,16 @@ metadata:
# 看图说话组件配置规范
## 适用场景
当【类型】列内容为【看图说话】或【看图说话-配图】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
配置分为两部分:导览配置 + 对话配置
### 导览配置

View File

@ -10,6 +10,16 @@ metadata:
# 对话朗读组件配置规范
## 适用场景
当【类型】列内容为【对话朗读】或【对话朗读-配图】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】:

View File

@ -10,6 +10,16 @@ metadata:
# 对话组句组件配置规范
## 适用场景
当【类型】列内容为【对话组句】或【对话组句-配图】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】:结合剧情上下文设计语义化标题,点明组句的核心场景,例如「提醒 Otis 系好安全带」

View File

@ -10,6 +10,16 @@ metadata:
# 图片单选组件配置规范
## 适用场景
当【类型】列内容为【图片单选】或【图片单选-配图】时,使用本规范生成组件配置
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
## 配置格式
### 字段要求
1. 【任务标题】:结合剧情上下文设计语义化标题,点明互动核心,例如「查看公告板说明书」

View File

@ -3,6 +3,16 @@ name: dialogue-components-standardizer
description: A unified skill for standardizing the production and review of 6 dialogue interaction components. Core logic is fixed; optimizations are handled via branch files and scripts for repeatability. Enter skill only when components change dynamically.
---
## 文本输出规范(强制执行)
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling统一选择英式拼写。
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
# Dialogue Components Standardizer
## Overview