auto backup: 2026-05-16 08:10:01
This commit is contained in:
parent
a81320fdaa
commit
a39bffa6ff
@ -86,6 +86,12 @@
|
||||
- 对话节奏快,每2-3句台词对应一个剧情节点或互动环节
|
||||
- 弱化说教感,所有指令和引导都以自然对话的方式呈现
|
||||
|
||||
### 【教研规则】文本输出格式规范(强制执行)
|
||||
1. **禁止 Markdown 标记**:生成单元挑战的音频文本、阅读文本等任何内容文本时,禁止使用 `**` `*` `__` `_` 等 Markdown 加粗/斜体标识,也禁止使用 `#` `>` `-` 等块级 Markdown 语法。输出纯文本即可。
|
||||
2. **适用场景**:单元挑战所有文本输出(音频台词、阅读理解文章、写作提示、口语话题等),以及任何需要嵌入题目 jsonData 的文本内容
|
||||
3. **英式拼写优先**:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写
|
||||
4. **标点符号规范**:严格区分全角/半角符号,中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用
|
||||
|
||||
### 【教研规则】剧本定稿审校通用规范
|
||||
1. 标点符号规范:禁止使用「~」「!!!」等非标准标点,统一使用标准英文标点符号
|
||||
2. 核心句型呈现规范:核心句型第一次出现时需清晰、完整、独立呈现,不与其他干扰信息混杂
|
||||
|
||||
66
business_knowledge/voice_character_id_mapping.md
Normal file
66
business_knowledge/voice_character_id_mapping.md
Normal 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
|
||||
@ -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. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 审校流程
|
||||
|
||||
```
|
||||
|
||||
@ -25,6 +25,14 @@ description: 单元挑战核心层(永久固定,无重大升级不改动)
|
||||
- ✅ 暂不对接其他外部系统(CMS/教研系统等)
|
||||
- ✅ 所有输出仅支持本地文件、飞书多维表两种形式
|
||||
- ✅ 所有数据存储在当前工作区内,不对外传输
|
||||
## 文本输出规范(强制约束,覆盖所有题型)
|
||||
|
||||
以下规则适用于单元挑战所有题型的文本输出(音频台词、阅读文章、写作提示、口语话题等 jsondata 内容):
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 `**` `*` `__` `_` 等加粗/斜体标识,也禁止使用 `#` `>` `-` 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 改动规则
|
||||
- 非重大规则升级/词库全量更新,禁止修改本层内容
|
||||
- 单个题型调优仅修改对应题型Skill,不得改动核心层
|
||||
|
||||
@ -25,11 +25,15 @@ description: 单元挑战总控调度大脑,统一接收所有单元挑战生
|
||||
- L2阶段需求→分发到L2执行器,调用对应L2专属/共用题型技能
|
||||
- 多题型组合需求→按题型分别分发,并行生产
|
||||
### 步骤4:质量校验(自动执行)
|
||||
所有生成的题目自动经过三层质量校验:
|
||||
所有生成的题目自动经过五层质量校验:
|
||||
1. 超纲校验:所有词汇必须属于对应阶段词库
|
||||
2. 格式校验:符合对应题型输出规范
|
||||
3. 难度校验:听力文本长度/选项复杂度等符合难度要求
|
||||
4. 去重校验:同一题包内知识点不重复考察
|
||||
5. 文本规范校验(强制):
|
||||
- 禁止 Markdown 标记(`**` `*` `__` `_` `#` `>` `-`),所有文本纯文本输出
|
||||
- 英式拼写优先(colour/centre/travelling 等)
|
||||
- 标点符号规范:中文全角(,。!?),英文半角(. , ! ?),不混用
|
||||
### 步骤5:结果输出
|
||||
按照要求格式输出,支持:
|
||||
- 教研文档格式:带解析、能力项、评分标准
|
||||
|
||||
@ -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专属】,自动绑定对应能力标签,支持批量生产与合规校验。
|
||||
## 难度对应关系(已适配新的阶段划分)
|
||||
|
||||
@ -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 听力信息匹配题生产技能
|
||||
## 题型说明
|
||||
听力信息匹配题:学生听一段对话或文本,然后将听到的信息与选项列表匹配,通常涉及人物、物品、地点等信息的对应关系。
|
||||
|
||||
@ -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个单句/短对话,每个对应一组图片,选出与听力内容匹配的图片,考察对图片信息和听力信息的快速匹配能力。
|
||||
|
||||
@ -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张图片选项中选出与听力内容匹配的正确答案。
|
||||
|
||||
@ -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段短对话/独白,提取关键信息填写表格中空缺的内容,考察词汇拼写、数字识别、信息匹配能力。
|
||||
|
||||
@ -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段长对话/独白,将左右两栏的相关信息进行匹配,考察对多个信息点的关联、记忆和区分能力。
|
||||
|
||||
@ -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道选择题,考察对对话整体逻辑、隐含信息、因果关系的理解能力。
|
||||
|
||||
@ -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道选择题,考察对常见场景、日常用语的理解能力。
|
||||
|
||||
@ -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(多题共享一张大图),本题型每道题独立配图。
|
||||
|
||||
@ -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),所有小题共享同一张大图。
|
||||
|
||||
@ -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个选项中选择正确的单词填入,考察词汇、语法和上下文理解能力。
|
||||
|
||||
@ -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个简短文本(标识/告示/短句),与对应的图片/标题进行匹配,考察快速抓取关键信息和图文匹配能力。
|
||||
|
||||
@ -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道选择题,考察对篇章整体内容、细节信息、推理判断的能力。
|
||||
|
||||
@ -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个空缺的单词,无选项提示,考察信息提取、词汇拼写和语法正确性。
|
||||
|
||||
@ -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个简短段落,与对应的段落标题/主旨句进行匹配,考察归纳段落主旨和抓取核心信息的能力。
|
||||
|
||||
@ -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问题。
|
||||
|
||||
@ -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 阅读看图回答题生产技能
|
||||
## 题型说明
|
||||
阅读看图回答题:学生查看图片,然后回答关于图片内容的开放性问题。
|
||||
|
||||
@ -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专属】**,考察核心能力为**口语表达(图片信息提取+场景词汇运用)**:学生观察指定场景图片,根据问题提示口头输出对应答案,考察词汇储备、发音准确性、表达流畅度。
|
||||
|
||||
@ -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 口语看图识物题生产技能
|
||||
## 题型说明
|
||||
口语看图识物题:学生查看图片,然后描述或识别图片中的物品。
|
||||
|
||||
@ -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 口语日常问答题生产技能
|
||||
## 题型说明
|
||||
口语日常问答题:学生回答一系列日常问题,考察口语表达能力。
|
||||
|
||||
@ -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 口语话题讨论题生产技能
|
||||
## 题型说明
|
||||
口语话题讨论题:学生基于图片或描述讨论相关话题。
|
||||
|
||||
@ -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分钟的口头阐述,考察词汇运用、逻辑连贯、观点表达能力。
|
||||
|
||||
@ -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句话,考察日常词汇、句式的运用能力和表达流畅度。
|
||||
|
||||
@ -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 写作看图回答题生产技能
|
||||
|
||||
## 一、题型说明
|
||||
|
||||
@ -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词的回复邮件,考察邮件格式、信息完整性、语言正确性。
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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句话的短文,考察图片信息提取、语言组织、逻辑连贯能力。
|
||||
|
||||
@ -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 - 教研互动组件设计规范
|
||||
|
||||
## ⚡ 触发方式
|
||||
|
||||
@ -7,6 +7,16 @@ metadata:
|
||||
domains: ["教研生产", "互动组件配置"]
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
# 对话类互动组件配置规范
|
||||
本技能定义6类对话类互动组件的配置标准、格式要求和校验规则,所有对话类互动必须严格遵循此规范生产。
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ description: 剧本互动组件内容生产/审校/回填技能(不涉及JSON
|
||||
- ✅ **智能组件识别**:读取剧本sheet,根据列A「类型」字段识别组件行(互动 / 核心互动-xxx)
|
||||
- ✅ **组件类型自动匹配**:根据剧情上下文、前后台词自动匹配27种中互动或14种核心互动类型
|
||||
- ✅ **组件内容生成**:调用LLM生成结构化文本格式的组件内容(【任务标题】【资源配置】... 等字段)
|
||||
- ✅ **自动审校**:校验ID格式/字段完整性/题型匹配/知识点一致性/格式规范
|
||||
- ✅ **自动审校**:校验ID格式/字段完整性/题型匹配/知识点一致性/格式规范/文本规范(禁止Markdown、英式拼写、标点符号)
|
||||
- ✅ **飞书回填**:将生成的组件内容写入剧本sheet的「组件配置」列(列G),**以结构化文本格式存储,非JSON**
|
||||
|
||||
---
|
||||
|
||||
@ -5,6 +5,16 @@ description: "瓦拉英语互动组件官方配置库,包含所有中互动、
|
||||
metadata:
|
||||
source: "飞书知识库 03 内容配置相关/配置多维表格/互动内容库"
|
||||
last_update: "2026-04-03"
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
---
|
||||
|
||||
## 互动组件分类
|
||||
|
||||
@ -23,6 +23,13 @@ metadata:
|
||||
|
||||
# 互动组件配置JSON生成器
|
||||
|
||||
## 文本输出规范(jsonData 内容强制遵守)
|
||||
|
||||
所有生成的 JSON 配置中,任何嵌入的文本内容(题目、选项、解析、台词等)必须遵守:
|
||||
1. 禁止 Markdown 标记(`**` `*` `__` `_` `#` `>` `-`),纯文本输出
|
||||
2. 英式拼写优先(colour/centre/travelling 等)
|
||||
3. 标点符号规范:英文半角(. , ! ?),中文全角(,。!?),不混用
|
||||
|
||||
## 触发场景
|
||||
|
||||
用户发送以下格式的消息时触发完整处理流水线:
|
||||
|
||||
@ -24,6 +24,7 @@ description: 用英语母语儿童思维生成自然地道的分级英文台词
|
||||
- ✅ 英语思维重构:不是翻译,而是用英语母语儿童的思维方式重构意群,生成自然地道的英文
|
||||
- ✅ 分级生成:支持4个难度等级(S1-S4),完全匹配4-8岁不同水平儿童
|
||||
- ✅ 自动校验:内置句长/连接词/从句/时态/超纲词/重复等多维度校验+L1核心词表
|
||||
- ✅ 文本规范校验:禁止 Markdown 标记、英式拼写优先(colour/centre/travelling)、英文半角标点
|
||||
- ✅ 自动修正:校验不通过时自动触发LLM修正,无需手动干预
|
||||
- ✅ 科幻词自动降级:内置可配置科幻词映射表,复杂词汇自动转换成儿童易懂表达
|
||||
- ✅ 批量处理:支持单个文件/目录批量处理,自动保存结果到指定路径
|
||||
|
||||
@ -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}]}
|
||||
|
||||
@ -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": "- **需求:** 将 020102(I am...)和 020103(I am ready / Thank you)两套题合并为一个 `{first:..., second:...}` JSON,统一 questionSetID=0000001 - **状态:** ✅ 已完成 - **核心考点分析(用户强调):** 需分析每个句型的核心考点(孩子最容易犯错的地方),挖空对准核心考点 - I am/from 组:am(系动词第一人称)、from(介词选择)、student(a+名词结构) - Thank you for 组:for(介词选择,非 you)、helping(for+动名词,非 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-table,5列×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/场景/角色/图片/非对话类等",
|
||||
"提出",
|
||||
"要求",
|
||||
"所有",
|
||||
"需要",
|
||||
"包含",
|
||||
"对话"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
output/audit_listening_explanation_results.json
Normal file
51
output/audit_listening_explanation_results.json
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
298
scripts/audit_explanation.py
Normal file
298
scripts/audit_explanation.py
Normal 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()
|
||||
547
scripts/audit_listening_explanation.py
Normal file
547
scripts/audit_listening_explanation.py
Normal 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 中的 explanation(P1, 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()
|
||||
448
scripts/audit_listening_explanation_v2.py
Normal file
448
scripts/audit_listening_explanation_v2.py
Normal 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()
|
||||
180
scripts/inject_text_rules.py
Normal file
180
scripts/inject_text_rules.py
Normal 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/color、centre/center、travelling/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()
|
||||
@ -22,6 +22,16 @@ description: Level 1 配置表(句子知识点)自动化审校技能。覆
|
||||
|
||||
例: 1214001 = L1 Season2, Unit14, 序列001
|
||||
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 审校流程
|
||||
|
||||
```
|
||||
|
||||
@ -8,6 +8,16 @@ metadata:
|
||||
source: "官方2022-2024版真题集"
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 适用场景
|
||||
当需要查询以下信息时使用本技能:
|
||||
1. 剑桥Starters/Movers/Flyers/KET考试的题型结构、分值、考试时长
|
||||
|
||||
@ -25,6 +25,12 @@ metadata:
|
||||
|
||||
# 第一部分:通用结构(所有核心互动共用)
|
||||
|
||||
## 0. 文本输出规范(所有字段文本内容强制遵守)
|
||||
|
||||
1. 禁止 Markdown 标记:所有 jsonData 内文本字段禁止使用 `**` `*` `__` `_` `#` `>` `-` 等 Markdown 语法,纯文本输出
|
||||
2. 英式拼写优先:英美式拼写差异统一英式(colour/centre/travelling 等)
|
||||
3. 标点符号规范:中文内容全角标点(,。!?),英文内容半角标点(. , ! ?),不混用
|
||||
|
||||
## 1. 通用字段
|
||||
|
||||
| 字段 | 类型 | 说明 | 出现率 |
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 对话选择组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【对话选择】或【对话选择-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 核心互动导览组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【核心互动】【导览配置】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:用户看到的任务名,建议字数在10字以内
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 对话挖空组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【对话挖空】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:结合剧情上下文设计语义化标题,点明互动核心,例如「介绍照片」
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 看图说话组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【看图说话】或【看图说话-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
配置分为两部分:导览配置 + 对话配置
|
||||
### 导览配置
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 对话朗读组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【对话朗读】或【对话朗读-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 对话组句组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【对话组句】或【对话组句-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:结合剧情上下文设计语义化标题,点明组句的核心场景,例如「提醒 Otis 系好安全带」
|
||||
|
||||
@ -10,6 +10,16 @@ metadata:
|
||||
# 图片单选组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【图片单选】或【图片单选-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:结合剧情上下文设计语义化标题,点明互动核心,例如「查看公告板说明书」
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user