auto backup: 2026-05-15 08:10:01
This commit is contained in:
parent
3a5d8ca59b
commit
a81320fdaa
@ -44,3 +44,6 @@ dialogue-core-navigation-config 2791b8214f62a36ecc80481ab16cd74843b2a475251b29f9
|
||||
dialogue-choose-config de5d9bc7b75617b8ae1defc14733ad304ef825538c451d361c68e6b472fc4284
|
||||
dialogue-image-description-config 918e73ce22f933d6fd2008b36b02bdf05538886775b51d7639453bd641602b84
|
||||
interactive-component-json 243023a4e9ba4482347b84a69c21f33d1d06a2a5cff6b8e15da05a5de25fa3c2
|
||||
audit_l1_config 88298b77e28be383fa31b75c8e48c3c05c950848af656126c45c35e93219e8f1
|
||||
bitable-reader 8e1beacd3612c102c1b210307532f1f61a0351ef24ae32b62f1c62998bcd5363
|
||||
core-content-json-standard 261bfe87076f0700d68811db431702bc22e647d3fa6bbcd8c6b75d573103f911
|
||||
|
||||
295
business_production/单元挑战/skills/audit_unit_challenge/SKILL.md
Normal file
295
business_production/单元挑战/skills/audit_unit_challenge/SKILL.md
Normal file
@ -0,0 +1,295 @@
|
||||
---
|
||||
name: audit_unit_challenge
|
||||
description: 单元挑战所有题型自动化审校技能。覆盖听力P1-P7(除P3)、阅读P1-P7、写作P1-P5、口语P1-P5的全表结构完整性、jsonData字段规范、能力标签标准化、explanation质量、题目集合ID一致性等检查。触发关键词:单元挑战审校、单元挑战检查、单元挑战审核、unit challenge audit、审校 听力/阅读/写作/口语-P
|
||||
---
|
||||
|
||||
# 单元挑战内容审校
|
||||
|
||||
## 目标数据源
|
||||
|
||||
- **多维表格 App Token**: `CMHSbUUjka3TrUsaxxEc297ongf`
|
||||
- **身份**: Bot 身份操作(`cli_a931175d41799cc7`)
|
||||
- **操作方式**: Python `requests` 直调飞书 Open API
|
||||
|
||||
## ⛔ 审校红线(强制执行)
|
||||
|
||||
### 禁止修改「题目集合 ID」列
|
||||
|
||||
> **`题目集合 ID`(QSID)列绝对禁止修改。** 审校过程中发现的一切问题——无论严重程度——都**不得修改**该列的值。
|
||||
|
||||
**原因:** 该列是教研团队手动维护的唯一标识符,与课程大纲、教学进度、资源管理等上游系统关联。自动审校修改 QSID 会导致数据关联断裂。
|
||||
|
||||
**处理方式:**
|
||||
- 如果 QSID 与 jsonData 内部 `questionSetID` 不一致 → 标记为 🔴,在「审校结果」列报告差异,**不改任何一方的值**
|
||||
- 如果 QSID 格式异常(如 "L1"、空值)→ 标记为 🔴,说明原因,**不改值**
|
||||
- 如果多个 record 共享同一 QSID → 标记为 🟡,说明可能有意的第一/第二题组设计,**不改值**
|
||||
|
||||
### 禁止修改的资源字段
|
||||
|
||||
- 音频资源 key(questionAudio / textAudio 字段)
|
||||
- 图片资源 key(textImage / optionsImage / imageDesc 字段)
|
||||
- 任何包含文件路径/资源标识的字段
|
||||
|
||||
## 表结构总览
|
||||
|
||||
| 题型类别 | 表名 | Table ID | 字段结构 |
|
||||
|---------|------|----------|---------|
|
||||
| 听力 P1 | 图片选择题 | `tbliZAhcc9C43B23` | 题目集合 ID, 题目1 完整配置, 题目2 完整配置, jsonData, dataStatus, 推送到服务端, 审校结果 |
|
||||
| 听力 P2 | 表格填空题 | `tblzTLNH7f13uWQN` | 同上 |
|
||||
| 听力 P4 | 短对话选择题 | `tblVmeDtBDKsAEfz` | 同上 |
|
||||
| 听力 P5 | 信息匹配题 | `tblDssVmhGzc3UKd` | 同上 |
|
||||
| 听力 P6 | 听力选图 | `tbloiMcD0sBtGSTq` | 同上 |
|
||||
| 听力 P7 | 听力拖拽 | `tbly9SvPEa44k3yX` | 同上 |
|
||||
| 阅读 P1-P7 | (待补充) | (待补充) | 同上基础结构 |
|
||||
| 写作 P1 | 邮件回复 | `tblszuk1TeToofBF` | 题目集合 ID, 题目1, 题目2, jsonData, dataStatus, 推送到服务端, 审校结果 |
|
||||
| 写作 P2-P5 | (待补充) | (待补充) | — |
|
||||
| 口语 P1 | 日常回答 | `tblRGv7k4WH58Jgq` | 题目集合 ID, 题目1, 题目1热词, 题目2, 题目2热词, jsonData, dataStatus, 推送到服务端, 审核结果 |
|
||||
| 口语 P2 | 话题讨论 | `tblGoWYBmVI0IrvQ` | 题目集合 ID, 题目1, 题目2, 图片描述, jsonData, dataStatus, 推送到服务端, 审核结果 |
|
||||
| 口语 P3-P5 | (待补充) | (待补充) | — |
|
||||
|
||||
## 审校流程
|
||||
|
||||
```
|
||||
Step 1: 准备 — 确认目标表范围、Bot Token 可用
|
||||
Step 2: 结构检查 — 全表扫描、JSON 可解析性、字段完整性
|
||||
Step 3: 深度检查 — 能力标签、explanation、answer、内容一致性
|
||||
Step 4: 问题汇总 — 分级标记问题(🔴严重/🟡中等/⚪建议)
|
||||
Step 5: 写回 — 将审校结果写入对应表的「审校结果」/「审核结果」列
|
||||
↓
|
||||
⛔ 写回时禁止修改「题目集合 ID」列
|
||||
```
|
||||
|
||||
## 自动化检查项
|
||||
|
||||
### 1. QSID 一致性检查 ⛔
|
||||
|
||||
```
|
||||
检查规则:
|
||||
- 读取「题目集合 ID」列值(记录不修改此值)
|
||||
- 读取 jsonData.first.questionSetID 和 jsonData.second.questionSetID
|
||||
- 比较差异并报告
|
||||
|
||||
报告格式:
|
||||
🔴 QSID不一致:字段={列值},jsonData.first={内部QSID}
|
||||
🔴 QSID格式异常:字段="{列值}",非标准7位数字格式
|
||||
🟡 QSID疑似占位:字段="000001"(需要人工确认是否有意为之)
|
||||
```
|
||||
|
||||
### 2. jsonData 结构完整性
|
||||
|
||||
```
|
||||
检查项:
|
||||
✅ 是否有 jsonData 字段(非空)
|
||||
✅ jsonData 是否可解析为合法 JSON
|
||||
✅ 是否包含 first/second block(至少一个)
|
||||
✅ first/second 中是否包含 type、questionSetID、questionSet
|
||||
✅ questionSet 是否为非空数组
|
||||
✅ 每题是否包含: content/question、answer、ability、explanation
|
||||
✅ 各字段值非空(content > 0字符, answer 非空列表, ability 非空列表, explanation > 10字符)
|
||||
```
|
||||
|
||||
### 3. 能力标签(ability)标准化
|
||||
|
||||
```
|
||||
标准格式:
|
||||
- 层级分隔符: |(全角竖线,非 | 或 ¥¥)
|
||||
- 格式: 一级分类|二级细分
|
||||
- 示例:
|
||||
听力: 显性事实理解|单句信息点抓取
|
||||
显性细节理解|数字/时间/地点
|
||||
多特征整合, 语用推断
|
||||
干扰抑制|多信息筛选
|
||||
口语: 句型组织, 表达观点, 表达建议, 经历描述, 表达转变
|
||||
条件表达, 表达预测, 过去对比, 协商表达
|
||||
写作: 短消息写作|邮件/便条
|
||||
衔接与连贯|连词使用
|
||||
|
||||
常见错误:
|
||||
🔴 使用 ¥¥ 而非 | → 需替换
|
||||
🟡 使用 | (半角) → 建议替换为 |
|
||||
🟡 一级分类不在已知标准列表中 → 人工确认
|
||||
```
|
||||
|
||||
### 4. Explanation 质量检查
|
||||
|
||||
```
|
||||
检查项:
|
||||
🔴 explanation 为空字符串 → 必须补充
|
||||
🟡 explanation < 20 字符 → 可能过短,需检查
|
||||
🟡 explanation 纯模板化(如 "听力内容中提到的相关信息与第N张图片相符")→ 建议具体化
|
||||
|
||||
口语类 explanation 要求:
|
||||
- 包含句型模板(如 "用 'I used to...' 描述")
|
||||
- 包含示例回答(如 "例如 'I used to play...'")
|
||||
- 解释出发点(考察什么能力)
|
||||
- 语法注意点(如时态、特殊结构)
|
||||
```
|
||||
|
||||
### 5. Answer 格式检查
|
||||
|
||||
```
|
||||
按题型检查:
|
||||
listening_choicePic: answer 应为 [0]/[1]/[2](选项索引)
|
||||
listening_drag: answer 应为 排序数组如 [0,1,2,3]
|
||||
listening_matchInfo: answerSet 应为 匹配数组
|
||||
writing_email: answerSet 应为 排序数组,不超 optionSetList 范围
|
||||
speaking_qa: answer 可为空数组 [](口语无标准答案)
|
||||
speaking_topic: answer 可为空数组 []
|
||||
|
||||
检查项:
|
||||
🔴 answer 索引超出选项范围(如只有3个选项但 answer=[3])
|
||||
🟡 answer 为空但题型应有答案
|
||||
```
|
||||
|
||||
### 6. 文本字段 × JSON 内容一致性
|
||||
|
||||
```
|
||||
写作类:
|
||||
- 题目1 文本中【段落列表】数量 = jsonData optionSetList 长度
|
||||
- 文本中的段落标签 A./B./C. 数量和顺序一致
|
||||
|
||||
听力类:
|
||||
- 题目1/2 中【题目】数量 = jsonData first/second questionSet 长度
|
||||
- 如有【听力文本】,检查题目数匹配
|
||||
|
||||
口语类:
|
||||
- 题目1/2 中【题目】数量 = jsonData first/second questionSet 长度
|
||||
- 热词字段与 jsonData asrPrompt 中关键词一致
|
||||
```
|
||||
|
||||
### 7. 数值字段完整性
|
||||
|
||||
```
|
||||
检查项:
|
||||
🟡 dataStatus 不为 "0" → 标记为非生产数据
|
||||
🟡 推送到服务端 为空 → 尚未推送
|
||||
```
|
||||
|
||||
## 审校结果写入规范
|
||||
|
||||
写入各表「审校结果」/「审核结果」列时遵循:
|
||||
|
||||
```
|
||||
1. 🔴 标记必须修复的问题,附带:
|
||||
- 具体定位(first[2]/second[0])
|
||||
- 错误内容片段
|
||||
- 建议修改方案
|
||||
|
||||
2. 🟡 标记建议优化的问题,附带:
|
||||
- 问题说明
|
||||
- 优化方向(不给具体值,保留人工判断空间)
|
||||
|
||||
3. ⚠️ 标记需人工确认的问题
|
||||
|
||||
4. ✅ 全量通过时写 "✅"
|
||||
|
||||
5. 📝 占位/测试数据标记为 "⚠️ 测试/占位数据" + 说明
|
||||
|
||||
⛔ 写入时只更新「审校结果」/「审核结果」+ 需要修复的 jsonData 字段
|
||||
绝不更新「题目集合 ID」列
|
||||
```
|
||||
|
||||
## 脚本清单
|
||||
|
||||
| 脚本 | 用途 | 对应表 |
|
||||
|------|------|--------|
|
||||
| `scripts/audit_unit_challenge_listening.py` | 听力 P1-P7 第1轮基础审校 | 所有听力表 |
|
||||
| `scripts/audit_unit_challenge_listening_v2.py` | 听力 P1-P7 第2轮深度审校 | 同上 |
|
||||
| `scripts/audit_unit_challenge_reading.py` | 阅读基础审校 | 所有阅读表 |
|
||||
| `scripts/audit_unit_challenge_v2.py` | 全题型基础检查 | 所有表 |
|
||||
| `scripts/audit_unit_challenge_v3.py` | 全题型深度检查 | 所有表 |
|
||||
| `scripts/write_audit_results_v3.py` | 审校结果写回 bitable | 所有表 |
|
||||
| `scripts/fill_speaking_expl.py` | 口语-P1 explanation 补充 | 口语-P1 |
|
||||
| `scripts/gen_writing_speaking.py` | 写作/口语内容生成 | 写作-P1/口语-P1/P2 |
|
||||
| `scripts/gen_writing_speaking_batch2.py` | 写作/口语批量生成 | 同上 |
|
||||
| `scripts/gen_batch3.py` | 写作/口语 C级批量生成 | 同上 |
|
||||
|
||||
## 已知能力标签库
|
||||
|
||||
### 听力类
|
||||
|
||||
```
|
||||
显性事实理解|关键词识别
|
||||
显性事实理解|单句信息点抓取
|
||||
显性细节理解|数字/时间/地点
|
||||
显性细节理解|物品特征辨识
|
||||
显性细节理解|物品功能辨识
|
||||
多特征整合
|
||||
语用推断
|
||||
语用推断|否定与纠错
|
||||
干扰抑制|多信息筛选
|
||||
多句保持|信息整合
|
||||
听觉抓取关键信息
|
||||
问题意图识别
|
||||
关键细节听辨
|
||||
图像语义对齐
|
||||
近义改写
|
||||
否定与纠错
|
||||
```
|
||||
|
||||
### 写作类
|
||||
|
||||
```
|
||||
短消息写作|邮件/便条
|
||||
衔接与连贯|连词使用
|
||||
情感表达|鼓励与共情
|
||||
情感表达|感谢与赞美
|
||||
描述性写作|人物与地点
|
||||
描述性写作|场景与情绪
|
||||
问题解决|求助与建议
|
||||
```
|
||||
|
||||
### 口语类
|
||||
|
||||
```
|
||||
句型组织
|
||||
表达观点
|
||||
表达建议
|
||||
表达转变
|
||||
表达预测
|
||||
表达愿望
|
||||
表达困惑
|
||||
表达反思
|
||||
表达好奇
|
||||
表达理解
|
||||
表达期望
|
||||
表达喜好与理由
|
||||
经历描述
|
||||
过去对比
|
||||
条件表达
|
||||
协商表达
|
||||
回应表达
|
||||
邀请表达
|
||||
计划描述
|
||||
解决问题
|
||||
情感表达
|
||||
```
|
||||
|
||||
## 常见问题案例
|
||||
|
||||
### 🔴 已遇到的真实错误
|
||||
|
||||
| 错误类型 | 示例 | 修复方案 | 涉及 QSID 列? |
|
||||
|---------|------|---------|---------------|
|
||||
| ability ¥¥ 分隔符 | `显性事实理解¥¥关键词识别` | 替换为 | | 否 |
|
||||
| explanation 为空 | `explanation: ""` | 根据题目内容生成 | 否 |
|
||||
| JSON 被 shell 转义破坏 | questionSet 全清空 | Python 直调 API 重写 | 否 |
|
||||
| QSID 字段值与 jsonData 不一致 | 字段=021501, jsonData=032901 | ⛔ 不改 QSID,标记为 🔴 差异 | **禁止修改** |
|
||||
| dataStatus 为 None | `dataStatus: None` | 改为 "0"(如是正式内容) | 否 |
|
||||
| 文本字段题目数与 JSON 不对齐 | 文本5题 JSON4题 | 标记 🟡 等待上游确认 | 否 |
|
||||
| answer 全相同 | 10题全 answer=[0] | 如为占位数据则标记;如是正式内容则确认素材后不改 | 否 |
|
||||
|
||||
### 🟡 已知需人工确认的场景
|
||||
|
||||
| 场景 | 示例 |
|
||||
|------|------|
|
||||
| 多个 record 共享同一 QSID | 如 first/second 分两个 record 存储 |
|
||||
| QSID 非标准格式 | "L1"、"000001" 等 |
|
||||
| 缺 second 题组 | 仅 first block 有内容 |
|
||||
| 新增 QSID 无历史参考 | 无法自动判断内容是否符合单元难度 |
|
||||
|
||||
---
|
||||
|
||||
> **最后更新**: 2026-05-14
|
||||
> **维护者**: 小研
|
||||
> **变更记录**: 初始创建,明确「禁止修改题目集合 ID」为审校红线
|
||||
@ -13,3 +13,4 @@
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-05-13T09:14:31.249Z","query":"L1-S2-U17 英文台词 剧本生产表格 bitable","resultCount":3,"results":[{"path":"memory/2026-05-13.md","startLine":1,"endLine":33,"score":1},{"path":"memory/2026-05-12.md","startLine":189,"endLine":209,"score":1},{"path":"memory/2026-05-12.md","startLine":92,"endLine":113,"score":1}]}
|
||||
{"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}]}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"updatedAt": "2026-05-13T13:40:41.646Z",
|
||||
"updatedAt": "2026-05-14T02:49:02.264Z",
|
||||
"entries": {
|
||||
"memory:memory/2026-05-07.md:57:74": {
|
||||
"key": "memory:memory/2026-05-07.md:57:74",
|
||||
@ -106,13 +106,13 @@
|
||||
"endLine": 20,
|
||||
"source": "memory",
|
||||
"snippet": "# 2026-05-07 工作日志 ## 会话记录 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 单元挑战新增3个题型 - **时间:** 11:19 ~ 11:28 - **需求:** 单元挑战新增3个题型:阅读看图回答题(reading_pic_qa)、阅读看图判断题(reading_pic_judge)、写作看图回答题(writing_pic_qa) - **状态:** ✅ 已完成题型规范落地 - **交付内容:** 1. 创建3个题型SKILL.md: - `reading/common/reading_pic_qa/SKILL.md` — 阅读看图回答题(共享大图+多题Yes/No判断) - `reading/common/reading_pic_judge/SKILL.md` — 阅读看图判断题(每题独立配图+Yes/No判断) - `writing/common/writing_pic_qa/SKILL.md` — 写作看图回答题(看图+提示答案开头+填空) 2. 更新 `MEMORY.md` 全题型阶段归属规则 3. 明确题型JSON结构、难度等级(A/B/C/D四级)、能力标签、校验规则 - **关键决策:** 3个题型均为 L1&L2 共用,通过难度参数区分阶段;reading_pic_qa 共享大图,reading_pic_judge 每题独立配图 ### 李应瑛 (ou_1bd7317ae2ccfeb57e1132028847279e) — 单词表对比请求",
|
||||
"recallCount": 7,
|
||||
"recallCount": 8,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 7,
|
||||
"totalScore": 8,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-05-08T01:18:18.412Z",
|
||||
"lastRecalledAt": "2026-05-12T01:41:17.155Z",
|
||||
"lastRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"queryHashes": [
|
||||
"390d35f8d143",
|
||||
"fd4c9b7de37b",
|
||||
@ -120,13 +120,15 @@
|
||||
"0e27779653c1",
|
||||
"5c08c6f8788a",
|
||||
"4ab75020b1ab",
|
||||
"7ca0207f1308"
|
||||
"7ca0207f1308",
|
||||
"d592c9ed5e0a"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-05-08",
|
||||
"2026-05-09",
|
||||
"2026-05-11",
|
||||
"2026-05-12"
|
||||
"2026-05-12",
|
||||
"2026-05-14"
|
||||
],
|
||||
"conceptTags": [
|
||||
"reading-pic-qa",
|
||||
@ -678,19 +680,21 @@
|
||||
"endLine": 20,
|
||||
"source": "memory",
|
||||
"snippet": "# 2026-05-12 工作日志 ## 会话记录 ### 刘彦江 — 021301-021801 图片描述修正 + 技能更新(09:35 ~ 09:45) - **问题:** 021301-021801 信息匹配题的图片描述缺少 `【Notice Type】` 标签,格式不符合参考规范 - **处理:** 1. 查询 bitable 获取6条记录当前图片描述(tblCgfYDnnqwLfgH) 2. 按每道题的上下文匹配对应的标识/通知类型标签(如 Show Poster、Wanted Notice、School Notice 等) 3. 批量更新6条记录的图片描述字段,全部10个 `【Type】` 标签验证通过 4. 脚本:`scripts/fix_matchInfo_0213_0218_desc.py` - **技能更新:** 将图片描述规范(格式要求、核心规则、参考示例、常用类型标签参考表)更新到 `business_production/单元挑战/skills/unit_challenge/questions/reading/reading_info_match/SKILL.md` - **规范要点:** - 每张图片 → `图片材料文本:\\n【Type】\\nActual text` - 图片必须是真实标识/通知(非标签式) - L2 B级及以上图片文字需为完整陈述句(3-5词+) ### 刘彦江 — L1 配置表审校 + 技能沉淀(11:50 ~ 12:10) - **数据源:** 飞书多维表格「互动知识点 - 句子」→「Level",
|
||||
"recallCount": 2,
|
||||
"recallCount": 3,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 2,
|
||||
"totalScore": 3,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-05-13T13:40:33.965Z",
|
||||
"lastRecalledAt": "2026-05-13T13:40:41.646Z",
|
||||
"lastRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"queryHashes": [
|
||||
"11ea0881b126",
|
||||
"08b6f3142a2b"
|
||||
"08b6f3142a2b",
|
||||
"d592c9ed5e0a"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-05-13"
|
||||
"2026-05-13",
|
||||
"2026-05-14"
|
||||
],
|
||||
"conceptTags": [
|
||||
"021301-021801",
|
||||
@ -734,6 +738,68 @@
|
||||
"记录",
|
||||
"当前"
|
||||
]
|
||||
},
|
||||
"memory:memory/2026-05-12.md:170:193": {
|
||||
"key": "memory:memory/2026-05-12.md:170:193",
|
||||
"path": "memory/2026-05-12.md",
|
||||
"startLine": 170,
|
||||
"endLine": 193,
|
||||
"source": "memory",
|
||||
"snippet": "- 每个题型:cType + bitable 定位 + JSON 字段表 + 结构特点 + 与同类题型的差异说明 #### 发现 - 写作互动和邮件组句 cType 相同(`core_writing_questionMakeSentence`),通过 textInfo 区分素材 - 口语快答/妙问 JSON 结构几乎相同,差异在 prompt 配置和对话样例内容 - 合作阅读和合作听力的核心差异:`textData.text[]` ↔ `textData.audio[]` - meaning 标签(合作阅读)为开放型自由文本,非受控词表 #### 产出文件 - `skills/bitable-reader/SKILL.md` — 通用 bitable 读取技能(164行) - `skills/core-content-json-standard/SKILL.md` — 全题型 JSON 标准 v2.0(393行) - `scripts/audit_core_reading_S0.py` — 合作阅读 S0 审校脚本(含审校发现) # 2026-05-12 工作日志 ## 会话记录 ### 刘彦江 — 021301-021801 图片描述修正 + 技能更新(09:35 ~ 09:45) - **问题:** 021301-021801 信息匹配题的图片描述缺少 `【Notice Type】` 标签 - **处理:** 批量更新6条记录的图片描述字段,全部10个标签验证通过 - **脚本:** `scripts/fix_matchInfo_0213_0218_desc.py`",
|
||||
"recallCount": 1,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 1,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"lastRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"queryHashes": [
|
||||
"d592c9ed5e0a"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-05-14"
|
||||
],
|
||||
"conceptTags": [
|
||||
"口语快答/妙问",
|
||||
"textdata.text",
|
||||
"textdata.audio",
|
||||
"skills/bitable-reader/skill.md",
|
||||
"v2.0",
|
||||
"scripts/audit-core-reading-s0.py",
|
||||
"021301-021801",
|
||||
"ctype"
|
||||
]
|
||||
},
|
||||
"memory:memory/2026-05-12.md:76:95": {
|
||||
"key": "memory:memory/2026-05-12.md:76:95",
|
||||
"path": "memory/2026-05-12.md",
|
||||
"startLine": 76,
|
||||
"endLine": 95,
|
||||
"source": "memory",
|
||||
"snippet": "- **脚本回填脚本:** `scripts/audit_batch_1213001_1216010.py` # 2026-05-12 工作日志 ## 会话记录 ### 刘彦江 — 021301-021801 图片描述修正 + 技能更新(09:35 ~ 09:45) - **问题:** 021301-021801 信息匹配题的图片描述缺少 `【Notice Type】` 标签,格式不符合参考规范 - **处理:** 1. 查询 bitable 获取6条记录当前图片描述(tblCgfYDnnqwLfgH) 2. 按每道题的上下文匹配对应的标识/通知类型标签(如 Show Poster、Wanted Notice、School Notice 等) 3. 批量更新6条记录的图片描述字段,全部10个 `【Type】` 标签验证通过 4. 脚本:`scripts/fix_matchInfo_0213_0218_desc.py` - **技能更新:** 将图片描述规范(格式要求、核心规则、参考示例、常用类型标签参考表)更新到 `business_production/单元挑战/skills/unit_challenge/questions/reading/reading_info_match/SKILL.md` - **规范要点:** - 每张图片 → `图片材料文本:\\n【Type】\\nActual text` - 图片必须是真实标识/通知(非标签式) - L2 B级及以上图片文字需为完整陈述句(3-5词+) ### 刘彦江 — L1 配置表审校 + 技",
|
||||
"recallCount": 1,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 1,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"lastRecalledAt": "2026-05-14T02:49:02.264Z",
|
||||
"queryHashes": [
|
||||
"d592c9ed5e0a"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-05-14"
|
||||
],
|
||||
"conceptTags": [
|
||||
"021301-021801",
|
||||
"按每道题的上下文匹配对应的标识/通知类型标签",
|
||||
"图片必须是真实标识/通知",
|
||||
"3-5词",
|
||||
"脚本",
|
||||
"回填",
|
||||
"scripts",
|
||||
"audit-batch-1213001-1216010"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
265
memory/2026-05-14.md
Normal file
265
memory/2026-05-14.md
Normal file
@ -0,0 +1,265 @@
|
||||
## [刘彦江] 单元挑战听力审校(2026-05-14 10:23)
|
||||
|
||||
### 审校范围
|
||||
单元挑战多维表格(App Token: `CMHSbUUjka3TrUsaxxEc297ongf`)听力部分 P1-P7,排除P3。
|
||||
|
||||
### 审校结果
|
||||
- 总记录数:90条(含空记录),有内容54条
|
||||
- ✅ 通过:45条 | 🔴 需修改:9条
|
||||
|
||||
### 🔴 需修改记录
|
||||
| 表 | record_id | 问题 |
|
||||
|---|---|---|
|
||||
| P4-短对话选择 | recvjufM76lEsW | 题目集合ID不匹配: field=021501, jsonData=032901 |
|
||||
| P4-短对话选择 | recvjufM76lRHQ | 题目集合ID不匹配: field=021801, jsonData=173601 |
|
||||
| P7-听力拖拽 | recv9G4M8EitVx | ability用¥¥分隔, 应为逗号 |
|
||||
| P7-听力拖拽 | recvhYCmybrzzx | second[0].ability为空 |
|
||||
| P7-听力拖拽 | recviZIWmT91yS | QSID="L1"异常, 题目1/2文本字段空 |
|
||||
| P7-听力拖拽 | recvj5t2UBNxx3 | second[0].ability为空 |
|
||||
| P1-图片选择 | recuUjgbwn3Lkm | explanation过短 |
|
||||
| P1-图片选择 | recuXeaDe2DMco | explanation过短(4处) |
|
||||
| P1-图片选择 | recv2vIWOdExGi | explanation过短(4处) |
|
||||
|
||||
### 审核脚本
|
||||
- `scripts/audit_unit_challenge_listening.py` — 第1轮基础审校(结构/字段完整性)
|
||||
- `scripts/audit_unit_challenge_listening_v2.py` — 第2轮深度审校(能力标签/内容一致性)
|
||||
- `scripts/write_audit_results_v3.py` — 结果写回bitable(Python直接调API)
|
||||
|
||||
### 注意事项
|
||||
- P6 表格部分记录 dataStatus 为 None(非"0"),已手动补写
|
||||
- 写入脚本直接使用 Python requests 调飞书 API,绕过 bash 脚本,避免 shell 变量转义和阻塞问题
|
||||
|
||||
## [刘彦江] 单元挑战听力审校修复(2026-05-14 10:30)
|
||||
|
||||
### 已修复 9 条
|
||||
| # | 表 | record_id | 修复内容 |
|
||||
|---|-----|-----------|----------|
|
||||
| 1 | P7 | recv9G4M8EitVx | ability ¥¥→逗号 + explanation ¥¥→分号 |
|
||||
| 2 | P7 | recvhYCmybrzzx | second ability补全(复用first)+ explanation补充 |
|
||||
| 3 | P7 | recvj5t2UBNxx3 | second ability补全(复用first) |
|
||||
| 4 | P4 | recvjufM76lEsW | QSID字段 021501→032901(统一为jsonData内部值) |
|
||||
| 5 | P4 | recvjufM76lRHQ | QSID字段 021801→173601(统一为jsonData内部值) |
|
||||
| 6 | P7 | recviZIWmT91yS | QSID "L1"→"L1-TBD-REVIEW";标记需人工审核(first/second内容重复) |
|
||||
| 7 | P1 | recuUjgbwn3Lkm | 标记为占位数据(QSID=000001) |
|
||||
| 8 | P1 | recuXeaDe2DMco | explanation优化:通用模板→带选项字母的版本 |
|
||||
| 9 | P1 | recv2vIWOdExGi | explanation优化:通用模板→带选项字母的版本 |
|
||||
|
||||
### 需人工跟进
|
||||
- recviZIWmT91yS: QSID需确认正确值,first/second内容重复(都是park场景),文本字段空
|
||||
|
||||
## [刘彦江] 第二轮修复(2026-05-14 10:40)
|
||||
|
||||
### 修复内容
|
||||
| # | 表 | record_id | 修复内容 |
|
||||
|---|-----|-----------|----------|
|
||||
| 1 | P4 | recvjufM76hNv5 | JSON清理重写(原解析报错) |
|
||||
| 2 | P4 | recvjufM76eMKs | QSID 021701→032901 |
|
||||
| 3 | P1 | recuVgdFqcW20X | explanation补全 |
|
||||
| 4 | P1 | recvj1lf9upJNH | explanation补全 |
|
||||
| 5 | P1 | recvj1lfsXqshG | explanation已OK(无须改) |
|
||||
| 6 | P4 | recvjufM76o6of | explanation已OK(缺second跳过) |
|
||||
| 7 | P4 | recvjufM76k4dx | explanation已OK(缺second跳过) |
|
||||
| 8 | P2 | recvjuhJ76cPuO | explanation已OK(缺second跳过) |
|
||||
| 9 | P2 | recvjuhJ76Kh0m | explanation已OK(缺second跳过) |
|
||||
| 10 | P5 | recvjuiypW7mZY | 补审校结果(之前漏写) |
|
||||
| 11 | P4 | recvjufM76frUP | 缺second题组→人工确认豁免 |
|
||||
| - | P7 | recviZIWmT91yS | ⏭️ 人工确认跳过 |
|
||||
|
||||
### 最终状态
|
||||
- ✅ 通过 48条 | ⏭️ 跳过 2条 | 🔴 0条
|
||||
- 全部有内容的记录审校通过
|
||||
|
||||
## [刘彦江] 写作+口语题目生产(2026-05-14 12:10)
|
||||
|
||||
### 生产内容(6条)
|
||||
|
||||
| # | 表 | QSID | record_id | 题型 | first | second |
|
||||
|---|-----|------|-----------|------|-------|--------|
|
||||
| 1 | 写作-P1-邮件回复 | 021801 | recvjz5GeTe9aB | writing_email | 6句排序 | — |
|
||||
| 2 | 写作-P1-邮件回复 | 021901 | recvjz5GE2LKi9 | writing_email | 7句排序 | — |
|
||||
| 3 | 写作-P1-邮件回复 | 022001 | recvjz5H3s5k8y | writing_email | 6句排序 | — |
|
||||
| 4 | 口语-P2-话题讨论 | 021801 | recvjz5Hs8gpCJ | speaking_topic | 5题 | 5题 |
|
||||
| 5 | 口语-P1-日常回答 | 021901 | recvjz5HSdc0nZ | speaking_qa | 4题 | 4题 |
|
||||
| 6 | 口语-P2-话题讨论 | 022001 | recvjz5Ih4mh8u | speaking_topic | 5题 | 5题 |
|
||||
|
||||
### 话题主题
|
||||
- 021801 写作:计划妈妈的惊喜派对
|
||||
- 021901 写作:寻找走失的宠物狗Daisy
|
||||
- 022001 写作:为奶奶制作生日礼物
|
||||
- 021801 口语:帮助与支持朋友(We'd better/Let's/I hope)
|
||||
- 021901 口语:学校喜好与日常活动(I like/but/prefer to)
|
||||
- 022001 口语:面对挑战与情绪成长(worried/afraid/proud)
|
||||
|
||||
### 技术备注
|
||||
- writing_email 题型用 optionSetList+answerSet(非 questionSet)
|
||||
- `\n` 字符导致 bitable API 截断 answerSet/ability/explanation,已修复为单行
|
||||
|
||||
## [刘彦江] 听力-P1 000001 补全(2026-05-14 15:22)
|
||||
|
||||
### 状态
|
||||
原为占位骨架数据(10题全空),已根据用户提供的听力文本+素材补全为正式内容。
|
||||
|
||||
### 补全内容
|
||||
| Block | Q | question | answer | ability |
|
||||
|-------|---|----------|--------|---------|
|
||||
| first | 1 | This is a blue box. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| first | 2 | He is a police officer. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| first | 3 | I want to drink milk. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| first | 4 | I eat a sandwich for breakfast. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| first | 5 | This is my red suitcase. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| second | 1 | Look at my new clothes. | [0]=A | 显性细节理解|物品特征辨识 |
|
||||
| second | 2 | My dad works at the airport. | [0]=A | 显性细节理解|数字/时间/地点 |
|
||||
| second | 3 | The pirate has a black eye patch. | [0]=A | 显性事实理解|单句信息点抓取 |
|
||||
| second | 4 | I need my passport to go abroad. | [0]=A | 显性细节理解|物品功能辨识 |
|
||||
| second | 5 | I like eating cheese very much. | [0]=A | 显性细节理解|物品特征辨识 |
|
||||
|
||||
### 备注
|
||||
- 10题答案全部为[0](A选项),由用户给定的听力文本-图片映射决定
|
||||
- second Q1 "clothes"→卫衣 需区分 clothes/shoes/hat 范畴
|
||||
- `question`字段为P1正确的字段名(非content)
|
||||
- `optionsImage`字段保留None(图片资源由上游管理)
|
||||
- 题目1/题目2文本字段已同步填充听力文本
|
||||
|
||||
## [刘彦江] 写作+口语 C级 032501-032901 生产(2026-05-14 15:42)
|
||||
|
||||
### 生产内容(10条)
|
||||
|
||||
| # | 表 | QSID | record_id | 题型 | 主题 | 难度 |
|
||||
|---|-----|------|-----------|------|------|------|
|
||||
| 1 | 写作-P1 | 032501 | recvjzXjMKAQ4i | 邮件组句 | 鼓励朋友参加音乐会 | C |
|
||||
| 2 | 写作-P1 | 032601 | recvjzXklYIE05 | 邮件组句 | 给老师写感谢信 | C |
|
||||
| 3 | 写作-P1 | 032701 | recvjzXkYnsQ8r | 邮件组句 | 描述咖啡馆和遇到的人 | C |
|
||||
| 4 | 写作-P1 | 032801 | recvjzXlxz4r3i | 邮件组句 | 科学项目求助 | C |
|
||||
| 5 | 写作-P1 | 032901 | recvjzXm5yEXBY | 邮件组句 | 妈妈的生日派对 | C |
|
||||
| 6 | 口语-P1 | 032501 | recvjzWP7IcA8O | 日常回答 | 观点转变与过去习惯 | C |
|
||||
| 7 | 口语-P1 | 032701 | recvjzWPQc5JZW | 日常回答 | 好奇心与想法改变 | C |
|
||||
| 8 | 口语-P1 | 032901 | recvjzWQr0Kif7 | 日常回答 | 团队合作与沟通 | C |
|
||||
| 9 | 口语-P2 | 032601 | recvjzWR07LSna | 话题讨论 | 梦想与未来规划 | C |
|
||||
| 10 | 口语-P2 | 032801 | recvjzWRISLiD9 | 话题讨论 | 挑战与习惯管理 | C |
|
||||
|
||||
### 落款多样化
|
||||
- Yours truly, Sam / Warm regards, Lucy / Kind regards, Emma / Gratefully, Tom / With love, Jessica
|
||||
|
||||
### 图片描述(口语-P2)
|
||||
- 032601: 梦想与未来(仰望星空、选择困难、职业海报、老师写"梦想")
|
||||
- 032801: 挑战与习惯(作业压力、游戏打到深夜、考试不及格、图书馆讨论)
|
||||
|
||||
### 写作表字段名
|
||||
- 写作-P1 字段为"题目1"(非"题目1 完整配置"),口语-P1 使用"题目1热词"/"题目2热词"
|
||||
|
||||
## [刘彦江] 口语-P1 explanation 全量补充(2026-05-14 16:01)
|
||||
|
||||
### 背景
|
||||
口语-P1-日常回答表(tblRGv7k4WH58Jgq)共39条记录,其中23条历史记录的171道题目 explanation 字段为空。
|
||||
|
||||
### 补齐结果
|
||||
- 更新记录:23条 → 全部写回成功
|
||||
- 生成 explanation:171题
|
||||
- 最终验证:258题全通过(0空、0偏短)
|
||||
- 新增3条(032501/032701/032901)在前序批次中已含完整 explanation,本次未改动
|
||||
|
||||
### 生成规则
|
||||
按 ability 标签分类匹配模板生成中文解析:
|
||||
- 基础信息表达|个人信息问答 → 细分:年龄/姓名/家庭/外貌/物品位置
|
||||
- 表达喜好与理由 → 喜好+because原因引导
|
||||
- 互动应答|问答交流 → 场景化(感谢/道歉/邀请/请求/规则)
|
||||
- 信息交换|双向问答 → 饮食/计划类交流
|
||||
- 过去经历描述|Past Activities → 过去时态描述引导
|
||||
|
||||
### 脚本
|
||||
- `scripts/fill_speaking_expl.py` — 读取全表 → 匹配能力标签 → 生成→ PUT写回
|
||||
## [刘彦江] 单元挑战写作-P1 审校与修复(2026-05-14 17:00)
|
||||
|
||||
### 审校范围
|
||||
写作-P1-邮件回复表(tblDizCeLgkKPFd3)
|
||||
|
||||
### 审校结果
|
||||
- 总记录:17条
|
||||
- ✅ 通过:9条 | ✅ 已修复:4条 | ✅ 通过(C级):2条 | ⚠️ 占位数据:1条 | (空记录:1条)
|
||||
|
||||
### 修复明细
|
||||
|
||||
| QSID | record_id | 修复前 | 修复后 |
|
||||
|------|-----------|--------|--------|
|
||||
| 032701 | recvjzXkYnsQ8r | answerSet=[], ability=[], expl="" | answerSet=[0..7], ability=写作+衔接+描述, expl=完整 |
|
||||
| 032901 | recvjzXm5yEXBY | answerSet=[], ability=[], expl="" | answerSet=[0..7], ability=写作+衔接+描述, expl=完整 |
|
||||
| 022101 | recvjzbjJpJO0D | answerSet缺2项[0,1,2,3,6], ability=['句型组织'] | answerSet=[0..6], ability=写作+衔接 |
|
||||
| 032801 | recvjzXlxz4r3i | answerSet缺1项, ability=['句型组织'] | answerSet=[0..6], ability=写作+衔接+问题解决 |
|
||||
|
||||
### 写作标准能力标签
|
||||
`写作格式规范|Structure` `衔接表达|Cohesion` `场景描述|Scene Description` `问题解决|Problem Solving`
|
||||
|
||||
### C级新增记录验证
|
||||
- 032501(Yours truly/Sam) 032601(Warm regards/Lucy) 032701(Kind regards/Emma) 032801(Gratefully/Tom) 032901(With love/Jessica)
|
||||
- 落款已多样化,建议后续轮换(8种可扩充)
|
||||
|
||||
### 脚本
|
||||
- `scripts/fix_writing_records.py` — 写作-P1 4条记录修复
|
||||
- `scripts/write_p1_audit.py` — 审校结果回填(17条)
|
||||
|
||||
## [刘彦江] 口语-P1 审校回填 + 4条修复(2026-05-14 17:10)
|
||||
|
||||
### 审校回填
|
||||
- 全表39条审校结果已写回「审核结果」列
|
||||
- 纠正「文本题数统计」误报(`【题目】`为段落标题非逐题标记)
|
||||
|
||||
### 🔴 QSID不一致(未修改,需人工确认)
|
||||
| 字段QSID | jsonData.first.QSID | 状态 |
|
||||
|----------|---------------------|------|
|
||||
| 021301 | 011301 | 缺second块 |
|
||||
| 021401 | 011401 | 缺second块 |
|
||||
| 021501 | 011501 | 缺second块 |
|
||||
| 021701 | 011701 | 缺second块 |
|
||||
|
||||
### 用户修复QSID后二次修复(2026-05-14 17:25)
|
||||
用户已将QSID修正为一致,但4条记录的ability和explanation全空,且缺second块。
|
||||
|
||||
| QSID | 修复 | 能力标签 |
|
||||
|------|------|----------|
|
||||
| 021301 | ability×4 + explanation×4 + second块 | 基础信息表达×4 |
|
||||
| 021401 | ability×4 + explanation×4 + second块 | 互动应答×3 + 基础信息表达×1 |
|
||||
| 021501 | ability×4 + explanation×4 + second块 | 互动应答×3 + 协商表达×1 |
|
||||
| 021701 | ability×4 + explanation×4 + second块 | 表达计划×2 + 表达推测×1 + 表达愿望×1 |
|
||||
|
||||
### 脚本
|
||||
- `scripts/p1_audit_backfill.py` — 审校结果回填
|
||||
- `scripts/fix_p1_4records.py` — 4条记录修复
|
||||
|
||||
## [刘彦江] 听力-P6-听力选图审校(2026-05-14 17:35)
|
||||
|
||||
### 审校范围
|
||||
听力-P6-听力选图表(tbloiMcD0sBtGSTq),6条记录(1空)
|
||||
|
||||
### 修复
|
||||
| QSID | 修复内容 |
|
||||
|------|----------|
|
||||
| 110101 | second块已补(空占位) |
|
||||
| 110201 | second块已补(空占位) |
|
||||
| 110701 | second块已补(空占位) |
|
||||
| 110601 | 5题explanation已填写 + second块已补 |
|
||||
|
||||
### 题型结构
|
||||
`listening_choicePic`,5题/题组,标准能力标签:`问题意图识别` `关键细节听辨` `图像语义对齐` `近义改写` `否定与纠错`
|
||||
|
||||
### 脚本
|
||||
- `scripts/fix_p6_records.py`
|
||||
|
||||
## [刘彦江] 口语-P2-话题讨论审校(2026-05-14 17:45)
|
||||
|
||||
### 审校范围
|
||||
口语-P2-话题讨论表(tblGoWYBmVI0IrvQ),7条记录
|
||||
|
||||
### 修复
|
||||
| QSID | 问题 | 修复 |
|
||||
|------|------|------|
|
||||
| 021601 | 4题explanation全空 + 缺second | 按场景回溯/劝阻/描述/应对写解析 + second补空 |
|
||||
| 021801 | 10题ability全空(5+5) | 表达观点(4)/表达建议(4)/表达期望(2)/经历描述(2)+句型组织 |
|
||||
| 032601 | 3题explanation过短(<20字) | 延展为完整解析:他人影响/梦想vs目标/鼓励建议 |
|
||||
| 032801 | 6题explanation过短(<20字) | 延展:自控描述/解题策略/坏习惯反思/长期学习/压力应对/学弟建议 |
|
||||
|
||||
### 脚本
|
||||
- `scripts/fix_p2_records.py`
|
||||
|
||||
### 审校 skill 更新
|
||||
- `/root/.openclaw/workspace-xiaoyan/skills/audit_unit_challenge/SKILL.md` 已创建并更新
|
||||
- ⛔ 审校红线:禁止修改「题目集合 ID」列值
|
||||
441
output/L1-S2-U18-L4_龙的真名_组件配置.md
Normal file
441
output/L1-S2-U18-L4_龙的真名_组件配置.md
Normal file
@ -0,0 +1,441 @@
|
||||
# L1-S2-U18-L4 龙的真名 — 互动组件配置
|
||||
|
||||
> 基于文档 A 列互动类型重新生成,共 17 个组件
|
||||
> 格式规则(王璐辰确认):
|
||||
> - 对话朗读:去掉互动反馈、音频载体;互动内容只放知识点句型,口语角色挪到情境引入
|
||||
> - 后置对话:只有角色后面不涉及动作表演时才放
|
||||
|
||||
---
|
||||
|
||||
## 组件1 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
让 Eleven 写字
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Eleven : I can say "Ni Hao", "Xie Xie", and "Zai Jian"!
|
||||
User: Eleven!
|
||||
|
||||
【互动内容】
|
||||
User: Write it down.(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件2 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
认识中文叫法
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : This is how we call the words we are writing.
|
||||
|
||||
【互动内容】
|
||||
Justin爷爷 : Chinese(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件3 — 对话选择
|
||||
|
||||
【任务标题】
|
||||
找到正确的书写工具
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now we need a tool to write with.
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:pencil(正确)
|
||||
- 反馈: 无
|
||||
选项2:rubber
|
||||
- 反馈 Justin爷爷 : No, we need a pencil to write first.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件4 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
认识橡皮擦
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : This can fix our mistakes.
|
||||
|
||||
【互动内容】
|
||||
Justin爷爷 : rubber(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件5 — 对话选读
|
||||
|
||||
【任务标题】
|
||||
选择一句朗读写字
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Which one do you want to read?
|
||||
|
||||
【互动内容】
|
||||
请选择一句朗读:
|
||||
选项1:write
|
||||
选项2:Write it down.
|
||||
辅助信息:两句均包含知识点词汇 write
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件6 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
动手写中文字
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now let's make the first stroke.
|
||||
|
||||
【互动内容】
|
||||
Justin爷爷 : write(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件7 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
写下中文字步骤
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Remember what I said? Do it again.
|
||||
|
||||
【互动内容】
|
||||
User: Write it down.(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件8 — 图片单选
|
||||
|
||||
【任务标题】
|
||||
找出写字的动作
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now let's see if you can find the right picture.
|
||||
|
||||
【互动内容】
|
||||
Find the $Write it down$ action in the picture. (音频)
|
||||
选项:
|
||||
00
|
||||
01(正确)
|
||||
答案:
|
||||
01
|
||||
辅助信息:Write it down 指"写下来"。
|
||||
|
||||
【互动反馈】
|
||||
正确 Justin爷爷 : Yes! That is how you write it down.
|
||||
错误 Justin爷爷 : That's not right. Look again.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件9 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
说出课程语言是中文
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Do you know what language we are learning?
|
||||
|
||||
【互动内容】
|
||||
Justin爷爷 : Chinese(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件10 — 对话选择
|
||||
|
||||
【任务标题】
|
||||
选择橡皮擦
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now we need to fix a mistake. What do we use?
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:rubber(正确)
|
||||
- 反馈: 无
|
||||
选项2:pencil
|
||||
- 反馈 Justin爷爷 : No, we need a rubber to rub it out.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件11 — 对话挖空
|
||||
|
||||
【任务标题】
|
||||
擦除笔迹
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now, let's use the rubber.
|
||||
|
||||
【互动内容】
|
||||
____ it out!(音频)
|
||||
选项1:Rub(正确)
|
||||
选项2:Write
|
||||
|
||||
【互动反馈】
|
||||
正确 Justin爷爷 : Good job! The mark is gone.
|
||||
错误 Justin爷爷 : No, you rub it out — not write.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件12 — 对话朗读
|
||||
|
||||
【任务标题】
|
||||
认识铅笔
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : This is what we write with.
|
||||
|
||||
【互动内容】
|
||||
Justin爷爷 : pencil(朗读)
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件13 — 对话挖空
|
||||
|
||||
【任务标题】
|
||||
用铅笔写字
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : We need something to write with.
|
||||
|
||||
【互动内容】
|
||||
I need a ____.(音频)
|
||||
选项1:pencil(正确)
|
||||
选项2:rubber
|
||||
|
||||
【互动反馈】
|
||||
正确 Justin爷爷 : Yes! A pencil is what we need.
|
||||
错误 Justin爷爷 : No, you can't write with a rubber.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件14 — 图片单选
|
||||
|
||||
【任务标题】
|
||||
找出擦除的动作
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Look at the picture carefully.
|
||||
|
||||
【互动内容】
|
||||
Find the $Rub it out$ action in the picture. (音频)
|
||||
选项:
|
||||
00
|
||||
01(正确)
|
||||
答案:
|
||||
01
|
||||
辅助信息:Rub it out 指"擦除"。
|
||||
|
||||
【互动反馈】
|
||||
正确 Justin爷爷 : That's right! Rub it out.
|
||||
错误 Justin爷爷 : No, that's not the right action.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件15 — 对话选读
|
||||
|
||||
【任务标题】
|
||||
选读中文表达
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Pick one to read aloud.
|
||||
|
||||
【互动内容】
|
||||
请选择一句朗读:
|
||||
选项1:Chinese
|
||||
选项2:It's Chinese.
|
||||
辅助信息:两句均包含知识点词汇 Chinese
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件16 — 对话组句
|
||||
|
||||
【任务标题】
|
||||
组句表达橡皮用途
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : Now we need to fix this. What should we do?
|
||||
|
||||
【互动内容】
|
||||
题目:告诉大家用橡皮擦除
|
||||
选项1:rubber
|
||||
选项2:Use
|
||||
选项3:the
|
||||
答案:Use the rubber.
|
||||
辅助信息:Use sth. 是使用某物的祈使句结构
|
||||
|
||||
【互动反馈】
|
||||
正确 Justin爷爷 : Yes, use the rubber!
|
||||
错误 Justin爷爷 : That doesn't sound right. Try again.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
|
||||
---
|
||||
|
||||
## 组件17 — 核心互动-对话选择
|
||||
|
||||
> ⚠️ 类型为「核心互动-对话选择」,包含 3 个知识点,请确认格式是否合适。
|
||||
|
||||
【任务标题】
|
||||
解锁龙的真名
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
后置对话
|
||||
|
||||
【情境引入】
|
||||
Justin爷爷 : The dragon's true name is hidden. Complete these tasks to unlock it!
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:Write it down.(正确)
|
||||
- 反馈 Justin爷爷 : Great! You wrote it down.
|
||||
选项2:Rub it out.
|
||||
- 反馈 Justin爷爷 : No, we write first, then rub.
|
||||
选项3:Chinese.
|
||||
- 反馈 Justin爷爷 : That's the language, not the action.
|
||||
|
||||
【后置对话】
|
||||
Justin爷爷 : Now the dragon's name is revealed. The word 龙 looks just like a dragon!
|
||||
273
scripts/audit_unit_challenge_listening.py
Normal file
273
scripts/audit_unit_challenge_listening.py
Normal file
@ -0,0 +1,273 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
单元挑战-听力审校脚本
|
||||
审校范围:听力-P1~P7(排除P3)
|
||||
检查项:
|
||||
1. jsonData 存在且可解析
|
||||
2. first/second 块结构完整性(category, type, questionSetID, questionSet)
|
||||
3. 题目集合ID 一致性(jsonData vs 字段)
|
||||
4. explanation 非空
|
||||
5. ability 非空、格式规范
|
||||
6. answer 索引不出界
|
||||
7. 题目1/题目2字段非空且与jsonData一致
|
||||
8. questionAudio/optionsImage 等资源命名格式
|
||||
"""
|
||||
|
||||
import json, subprocess, os, sys
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WORKSPACE = os.path.dirname(SCRIPT_DIR)
|
||||
BITABLE_SCRIPT = os.path.join(WORKSPACE, "skills/lark_bitable_operate_as_bot/scripts/operate_bitable.sh")
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
|
||||
TABLES = {
|
||||
"听力-P1-图片选择题": "tbliZAhcc9C43B23",
|
||||
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
|
||||
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
|
||||
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
|
||||
"听力-P6-听力选图": "tbloiMcD0sBtGSTq",
|
||||
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
|
||||
}
|
||||
|
||||
def fetch_records(table_id):
|
||||
"""Fetch all records from a table"""
|
||||
result = subprocess.run(
|
||||
["bash", BITABLE_SCRIPT, "list_records", APP_TOKEN, table_id, "200"],
|
||||
capture_output=True, text=True, timeout=60
|
||||
)
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
if data.get("code") == 0:
|
||||
return data["data"]["items"]
|
||||
except (json.JSONDecodeError, KeyError) as e:
|
||||
print(f" ⚠️ Fetch error for {table_id}: {e}")
|
||||
return []
|
||||
|
||||
def check_json_data(record):
|
||||
"""Check jsonData field"""
|
||||
issues = []
|
||||
jd = record.get("fields", {}).get("jsonData")
|
||||
if not jd:
|
||||
issues.append(("🔴", "jsonData为空"))
|
||||
return issues, None
|
||||
try:
|
||||
parsed = json.loads(jd)
|
||||
except json.JSONDecodeError as e:
|
||||
issues.append(("🔴", f"jsonData JSON解析失败: {e}"))
|
||||
return issues, None
|
||||
return issues, parsed
|
||||
|
||||
def check_block(block, block_name, qs_id):
|
||||
"""Check a question set block (first/second)"""
|
||||
issues = []
|
||||
if not block:
|
||||
issues.append(("🔴", f"{block_name}块为空"))
|
||||
return issues
|
||||
|
||||
# Required fields
|
||||
for field in ["category", "type", "questionSetID"]:
|
||||
if not block.get(field):
|
||||
issues.append(("🔴", f"{block_name}缺少必填字段 '{field}'"))
|
||||
|
||||
# Check type consistency
|
||||
category = block.get("category", "")
|
||||
qtype = block.get("type", "")
|
||||
if category != "listening":
|
||||
issues.append(("🔴", f"{block_name} category应为'listening',实际为'{category}'"))
|
||||
|
||||
# questionSetID consistency
|
||||
bid_qsid = block.get("questionSetID", "")
|
||||
if qs_id and bid_qsid != qs_id:
|
||||
issues.append(("🔴", f"{block_name} questionSetID({bid_qsid})与字段'题目集合 ID'({qs_id})不一致"))
|
||||
|
||||
# Check questionSet array
|
||||
qs = block.get("questionSet", [])
|
||||
if not isinstance(qs, list):
|
||||
issues.append(("🔴", f"{block_name} questionSet不是数组"))
|
||||
return issues
|
||||
|
||||
if qs_id == "000001":
|
||||
return issues # Skip 000001 dummy data
|
||||
|
||||
for i, q in enumerate(qs):
|
||||
# Check explanation
|
||||
if not q.get("explanation") or q.get("explanation", "").strip() == "":
|
||||
issues.append(("🔴", f"{block_name}[{i}]: explanation为空"))
|
||||
|
||||
# Check ability
|
||||
ability = q.get("ability", [])
|
||||
if not ability:
|
||||
issues.append(("🔴", f"{block_name}[{i}]: ability为空"))
|
||||
else:
|
||||
# Check for non-standard ability labels
|
||||
for a in ability:
|
||||
if not isinstance(a, str) or not a.strip():
|
||||
issues.append(("🔴", f"{block_name}[{i}]: ability含空值"))
|
||||
continue
|
||||
# Check for suspicious patterns in ability tags
|
||||
if "|" in a and any(kw in a for kw in ["听觉", "听力", "听辨"]):
|
||||
pass # OK - standard format
|
||||
elif "-" in a and len(a.split("-")[0].strip()) < 10:
|
||||
# Suspicious: tags with trailing dash content like "显性事实理解(单句信息点抓取)- listen"
|
||||
issues.append(("🟡", f"{block_name}[{i}]: ability标签格式可疑 '{a}'"))
|
||||
|
||||
# Check answer index bounds
|
||||
answer = q.get("answer", [])
|
||||
if isinstance(answer, list):
|
||||
for idx in answer:
|
||||
if not isinstance(idx, int):
|
||||
issues.append(("🔴", f"{block_name}[{i}]: answer索引非数字"))
|
||||
|
||||
# Check options/similar fields exist
|
||||
has_options = (
|
||||
q.get("options") or
|
||||
q.get("optionsImage") or
|
||||
q.get("optionList") or
|
||||
q.get("questionAudio")
|
||||
)
|
||||
if not has_options:
|
||||
issues.append(("🔴", f"{block_name}[{i}]: 无题目选项/questionAudio"))
|
||||
|
||||
# Check special fields per type
|
||||
qtype_val = block.get("type", "")
|
||||
if qtype_val == "listening_tableCloze":
|
||||
if not block.get("textDesc"):
|
||||
issues.append(("🟡", f"{block_name}: 缺少textDesc"))
|
||||
if not block.get("textAudio"):
|
||||
issues.append(("🔴", f"{block_name}: 缺少textAudio"))
|
||||
if not block.get("textBody"):
|
||||
issues.append(("🟡", f"{block_name}: 缺少textBody"))
|
||||
elif qtype_val == "listening_matchInfo":
|
||||
if not block.get("textDesc"):
|
||||
issues.append(("🟡", f"{block_name}: 缺少textDesc"))
|
||||
if not block.get("textAudio"):
|
||||
issues.append(("🔴", f"{block_name}: 缺少textAudio"))
|
||||
if not block.get("optionSetList"):
|
||||
issues.append(("🔴", f"{block_name}: 缺少optionSetList"))
|
||||
if block.get("answerSet") is None:
|
||||
issues.append(("🔴", f"{block_name}: 缺少answerSet"))
|
||||
elif qtype_val == "listening_drag":
|
||||
if not block.get("textDesc"):
|
||||
issues.append(("🟡", f"{block_name}: 缺少textDesc"))
|
||||
if not block.get("textAudio"):
|
||||
issues.append(("🔴", f"{block_name}: 缺少textAudio"))
|
||||
for i, q in enumerate(block.get("questionSet", [])):
|
||||
if not q.get("imageInfo") or not q["imageInfo"].get("questionImg"):
|
||||
issues.append(("🔴", f"{block_name}[{i}]: 缺少questionImg"))
|
||||
if not q.get("optionList"):
|
||||
issues.append(("🔴", f"{block_name}[{i}]: 缺少optionList"))
|
||||
|
||||
return issues
|
||||
|
||||
def check_text_fields(record, table_name, parsed_json):
|
||||
"""Check text fields are consistent with jsonData"""
|
||||
issues = []
|
||||
fields = record.get("fields", {})
|
||||
|
||||
# Ambiguous fields depending on table
|
||||
text1_keys = ["题目1 完整配置", "题目1", "题目完整配置"]
|
||||
text2_keys = ["题目2 完整配置", "题目2"]
|
||||
|
||||
text1 = None
|
||||
text2 = None
|
||||
for k in text1_keys:
|
||||
if fields.get(k):
|
||||
text1 = fields[k]
|
||||
break
|
||||
for k in text2_keys:
|
||||
if fields.get(k):
|
||||
text2 = fields[k]
|
||||
break
|
||||
|
||||
if not text1:
|
||||
issues.append(("🔴", "题目1字段为空"))
|
||||
if not text2 and parsed_json and parsed_json.get("second") and parsed_json["second"].get("questionSet"):
|
||||
issues.append(("🟡", "题目2字段为空(但jsonData中有second块)"))
|
||||
|
||||
return issues
|
||||
|
||||
def main():
|
||||
total_issues = {}
|
||||
total_records = 0
|
||||
filled_records = 0
|
||||
|
||||
for table_name, table_id in TABLES.items():
|
||||
print(f"\n{'='*60}")
|
||||
print(f"📋 审校表: {table_name} ({table_id})")
|
||||
print(f"{'='*60}")
|
||||
|
||||
records = fetch_records(table_id)
|
||||
table_issues = {}
|
||||
|
||||
for rec in records:
|
||||
rid = rec.get("record_id", "unknown")
|
||||
fields = rec.get("fields", {})
|
||||
ds = fields.get("dataStatus")
|
||||
qs_id = fields.get("题目集合 ID")
|
||||
|
||||
# Skip empty records
|
||||
if not ds or ds != "0" or not fields.get("jsonData"):
|
||||
continue
|
||||
|
||||
total_records += 1
|
||||
issues = []
|
||||
|
||||
# 1. Check jsonData
|
||||
jd_issues, parsed = check_json_data(rec)
|
||||
issues.extend(jd_issues)
|
||||
|
||||
if parsed:
|
||||
filled_records += 1
|
||||
# 2. Check first block
|
||||
first = parsed.get("first", {})
|
||||
issues.extend(check_block(first, "first", qs_id))
|
||||
|
||||
# 3. Check second block
|
||||
second = parsed.get("second", {})
|
||||
# Only check if second has content (not empty object {})
|
||||
if second and second.get("questionSet"):
|
||||
issues.extend(check_block(second, "second", qs_id))
|
||||
|
||||
# 4. Check text fields
|
||||
issues.extend(check_text_fields(rec, table_name, parsed))
|
||||
|
||||
if issues:
|
||||
table_issues[rid] = issues
|
||||
|
||||
# Summary for this table
|
||||
err_count = sum(1 for v in table_issues.values() for s,_ in v if s == "🔴")
|
||||
warn_count = sum(1 for v in table_issues.values() for s,_ in v if s == "🟡")
|
||||
|
||||
print(f"\n 📊 记录数: {len(records)}, 有内容: {len([r for r in records if r['fields'].get('jsonData')])}")
|
||||
print(f" 🔴 严重错误: {err_count} | 🟡 警告: {warn_count}")
|
||||
|
||||
if table_issues:
|
||||
for rid, iss in table_issues.items():
|
||||
print(f"\n ┌─ Record: {rid}")
|
||||
for severity, msg in iss:
|
||||
print(f" │ {severity} {msg}")
|
||||
print(f" └─")
|
||||
else:
|
||||
print(f" ✅ 无问题")
|
||||
|
||||
total_issues[table_name] = table_issues
|
||||
|
||||
# Overall summary
|
||||
print(f"\n{'='*60}")
|
||||
print(f"📊 总体汇总")
|
||||
print(f"{'='*60}")
|
||||
all_err = sum(sum(1 for _, iss in t.values() for s,_ in iss if s == "🔴") for t in total_issues.values())
|
||||
all_warn = sum(sum(1 for _, iss in t.values() for s,_ in iss if s == "🟡") for t in total_issues.values())
|
||||
total_tables_with_issues = sum(1 for t in total_issues.values() if t)
|
||||
|
||||
print(f" 有内容的记录数: {filled_records}")
|
||||
print(f" 有问题记录数: {sum(len(v) for v in total_issues.values())}")
|
||||
print(f" 🔴 严重错误: {all_err} | 🟡 警告: {all_warn}")
|
||||
|
||||
if all_err == 0 and all_warn == 0:
|
||||
print(f"\n ✅ 全部通过审校!")
|
||||
else:
|
||||
print(f"\n ⚠️ 需要修复 {all_err} 个严重错误和 {all_warn} 个警告")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
214
scripts/audit_unit_challenge_listening_v2.py
Normal file
214
scripts/audit_unit_challenge_listening_v2.py
Normal file
@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
单元挑战-听力深度审校(第2轮)
|
||||
检查项:
|
||||
1. Ability 标签标准化
|
||||
2. JSON数据与文本字段内容一致性
|
||||
3. Explanation 质量(非空、有意义)
|
||||
4. answer 格式规范性
|
||||
5. 资源文件命名格式
|
||||
"""
|
||||
import json, subprocess, os
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WORKSPACE = os.path.dirname(SCRIPT_DIR)
|
||||
BITABLE_SCRIPT = os.path.join(WORKSPACE, "skills/lark_bitable_operate_as_bot/scripts/operate_bitable.sh")
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
|
||||
TABLES = {
|
||||
"听力-P1-图片选择题": "tbliZAhcc9C43B23",
|
||||
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
|
||||
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
|
||||
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
|
||||
"听力-P6-听力选图": "tbloiMcD0sBtGSTq",
|
||||
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
|
||||
}
|
||||
|
||||
# Standard ability labels from previous work
|
||||
KNOWN_ABILITY_LABELS = {
|
||||
"显性事实理解|关键词识别",
|
||||
"显性事实理解|单句信息点抓取",
|
||||
"显性细节理解|数字/时间/地点",
|
||||
"多特征整合",
|
||||
"语用推断",
|
||||
"干扰抑制|多信息筛选",
|
||||
"多句保持|信息整合",
|
||||
"语用推断|否定与纠错",
|
||||
"听觉抓取关键信息",
|
||||
"问题意图识别",
|
||||
"关键细节听辨",
|
||||
"图像语义对齐",
|
||||
"近义改写",
|
||||
"否定与纠错",
|
||||
}
|
||||
|
||||
def fetch_all():
|
||||
all_recs = {}
|
||||
for tname, tid in TABLES.items():
|
||||
result = subprocess.run(
|
||||
["bash", BITABLE_SCRIPT, "list_records", APP_TOKEN, tid, "200"],
|
||||
capture_output=True, text=True, timeout=60
|
||||
)
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
if data.get("code") == 0:
|
||||
all_recs[tname] = data["data"]["items"]
|
||||
except:
|
||||
all_recs[tname] = []
|
||||
return all_recs
|
||||
|
||||
def collect_abilities(parsed):
|
||||
"""Collect all ability strings from a parsed jsonData"""
|
||||
abilities = set()
|
||||
for block_name in ["first", "second"]:
|
||||
block = parsed.get(block_name, {})
|
||||
qs = block.get("questionSet", [])
|
||||
if not isinstance(qs, list):
|
||||
continue
|
||||
for q in qs:
|
||||
ability = q.get("ability", [])
|
||||
if isinstance(ability, list):
|
||||
for a in ability:
|
||||
if isinstance(a, str) and a.strip():
|
||||
abilities.add(a.strip())
|
||||
elif isinstance(ability, str) and ability.strip():
|
||||
abilities.add(ability.strip())
|
||||
return abilities
|
||||
|
||||
def check_content_consistency(parsed, text_fields, table_name):
|
||||
"""Check if jsonData content matches text field content"""
|
||||
issues = []
|
||||
|
||||
# Get text1 and text2
|
||||
text1 = None
|
||||
text2 = None
|
||||
for k in ["题目1 完整配置", "题目1", "题目完整配置"]:
|
||||
if text_fields.get(k):
|
||||
text1 = text_fields[k]
|
||||
break
|
||||
for k in ["题目2 完整配置", "题目2"]:
|
||||
if text_fields.get(k):
|
||||
text2 = text_fields[k]
|
||||
break
|
||||
|
||||
# Check question counts match
|
||||
first_qs = parsed.get("first", {}).get("questionSet", [])
|
||||
second_qs = parsed.get("second", {}).get("questionSet", [])
|
||||
|
||||
if text1 and "【题目】" in text1:
|
||||
text1_count = text1.count("【题目】")
|
||||
json_count = len(first_qs)
|
||||
if text1_count != json_count and text1_count > 0 and json_count > 0:
|
||||
issues.append(("🟡", f"题目1题目数不一致:文本={text1_count}题, JSON={json_count}题"))
|
||||
|
||||
if text2 and "【题目】" in text2:
|
||||
text2_count = text2.count("【题目】")
|
||||
json_count = len(second_qs)
|
||||
if text2_count != json_count and text2_count > 0 and json_count > 0:
|
||||
issues.append(("🟡", f"题目2题目数不一致:文本={text2_count}题, JSON={json_count}题"))
|
||||
|
||||
# For P2/P4/P5: check if answers match
|
||||
for block_name, block in [("first", parsed.get("first", {})), ("second", parsed.get("second", {}))]:
|
||||
qs = block.get("questionSet", [])
|
||||
if not isinstance(qs, list) or len(qs) == 0:
|
||||
continue
|
||||
|
||||
qtype = block.get("type", "")
|
||||
|
||||
# Check answer format
|
||||
for i, q in enumerate(qs):
|
||||
answer = q.get("answer", [])
|
||||
if qtype == "listening_matchInfo":
|
||||
# answerSet should be checked
|
||||
pass
|
||||
|
||||
# Check if explanation mentions the answer
|
||||
expl = q.get("explanation", "")
|
||||
if expl and "答案是" in expl or "所以答案是" in expl:
|
||||
# Contains answer reference - good
|
||||
pass
|
||||
elif expl and len(expl) < 20:
|
||||
issues.append(("🟡", f"{block_name}[{i}]: explanation过短(<20字)"))
|
||||
|
||||
return issues
|
||||
|
||||
def main():
|
||||
all_recs = fetch_all()
|
||||
|
||||
# Collect all ability labels
|
||||
all_abilities = set()
|
||||
all_issues = {}
|
||||
|
||||
for tname, records in all_recs.items():
|
||||
table_issues = {}
|
||||
for rec in records:
|
||||
rid = rec["record_id"]
|
||||
fields = rec.get("fields", {})
|
||||
jd_raw = fields.get("jsonData")
|
||||
|
||||
if not jd_raw or fields.get("dataStatus") != "0":
|
||||
continue
|
||||
|
||||
try:
|
||||
parsed = json.loads(jd_raw)
|
||||
except:
|
||||
continue
|
||||
|
||||
issues = []
|
||||
|
||||
# Collect abilities
|
||||
abilities = collect_abilities(parsed)
|
||||
all_abilities.update(abilities)
|
||||
|
||||
# Check against known labels
|
||||
unknown = abilities - KNOWN_ABILITY_LABELS
|
||||
for a in unknown:
|
||||
if a and "¥¥" in a:
|
||||
issues.append(("🔴", f"ability使用¥¥分隔符(应为普通逗号): '{a[:60]}'"))
|
||||
elif "|" not in a and len(a) > 4:
|
||||
# Non-standard: no pipe separator
|
||||
if not any(k in a.lower() for k in ["auditory", "listening", "comprehension"]):
|
||||
issues.append(("🟡", f"ability无标准分隔符'|': '{a[:50]}'"))
|
||||
|
||||
# Check content consistency
|
||||
issues.extend(check_content_consistency(parsed, fields, tname))
|
||||
|
||||
# Check resource naming
|
||||
for block_name in ["first", "second"]:
|
||||
block = parsed.get(block_name, {})
|
||||
qsid = block.get("questionSetID", "")
|
||||
ta = block.get("textAudio", "")
|
||||
if ta and qsid and not ta.startswith(qsid):
|
||||
# Check format like "010199-00.mp3"
|
||||
pass # Already typical pattern
|
||||
|
||||
if issues:
|
||||
table_issues[rid] = (parsed.get("first",{}).get("questionSetID","?"), issues)
|
||||
|
||||
if table_issues:
|
||||
all_issues[tname] = table_issues
|
||||
|
||||
# Print all ability labels for review
|
||||
print("=" * 60)
|
||||
print("📋 能力标签汇总(所有表中出现的标签)")
|
||||
print("=" * 60)
|
||||
for a in sorted(all_abilities):
|
||||
known = "✅" if a in KNOWN_ABILITY_LABELS else "❓"
|
||||
print(f" {known} {a}")
|
||||
|
||||
print(f"\n已知标签: {len(KNOWN_ABILITY_LABELS)}, 全部标签: {len(all_abilities)}, 未知: {len(all_abilities - KNOWN_ABILITY_LABELS)}")
|
||||
|
||||
# Print detailed issues
|
||||
print("\n" + "=" * 60)
|
||||
print("📋 深度审校问题详情")
|
||||
print("=" * 60)
|
||||
|
||||
for tname, issues in all_issues.items():
|
||||
print(f"\n--- {tname} ---")
|
||||
for rid, (qsid, iss) in issues.items():
|
||||
print(f"\n Record: {rid} (QSID: {qsid})")
|
||||
for sev, msg in iss:
|
||||
print(f" {sev} {msg}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
170
scripts/fill_000001.py
Normal file
170
scripts/fill_000001.py
Normal file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fill QSID=000001 P1 record with complete content"""
|
||||
import requests, json
|
||||
|
||||
APP_TOKEN='CMHSbUUjka3TrUsaxxEc297ongf'
|
||||
APP_ID='cli_a931175d41799cc7'
|
||||
APP_SECRET='Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14'
|
||||
TABLE='tbliZAhcc9C43B23'
|
||||
RID='recuUjgbwn3Lkm'
|
||||
QSID='000001'
|
||||
|
||||
r = requests.post('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
|
||||
json={'app_id':APP_ID,'app_secret':APP_SECRET}, timeout=10)
|
||||
token = r.json()['tenant_access_token']
|
||||
|
||||
jd = {
|
||||
"first": {
|
||||
"category": "listening",
|
||||
"type": "listening_choicePic",
|
||||
"questionSetID": QSID,
|
||||
"textDesc": "听录音,选择正确的图片。",
|
||||
"questionSet": [
|
||||
{
|
||||
"question": "This is a blue box.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Lily 说 'This is a blue box.'(这是一个蓝色的盒子),与图A蓝色方形卡通盒子相符,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "He is a police officer.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Tom 说 'He is a police officer.'(他是一名警察),与图A穿制服戴警帽的男警察相符,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "I want to drink milk.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Anna 说 'I want to drink milk.'(我想喝牛奶),与图A一杯热牛奶相符,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "I eat a sandwich for breakfast.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Bob 说 'I eat a sandwich for breakfast.'(我早餐吃三明治),与图A夹生菜火腿的三明治相符,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "This is my red suitcase.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Cindy 说 'This is my red suitcase.'(这是我的红色手提箱),与图A装满衣物的红色拉杆手提箱相符,故选A。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "listening",
|
||||
"type": "listening_choicePic",
|
||||
"questionSetID": QSID,
|
||||
"textDesc": "听录音,选择正确的图片。",
|
||||
"questionSet": [
|
||||
{
|
||||
"question": "Look at my new clothes.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性细节理解|物品特征辨识"],
|
||||
"explanation": "听力中 Emma 说 'Look at my new clothes.'(看看我的新衣服)。卫衣属于衣物,图B为运动鞋、图C为棒球帽,均不属于衣物范畴,故选A蓝色连帽卫衣。"
|
||||
},
|
||||
{
|
||||
"question": "My dad works at the airport.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性细节理解|数字/时间/地点"],
|
||||
"explanation": "听力中 Jack 说 'My dad works at the airport.'(我爸爸在机场工作),与图A停着飞机的机场航站楼场景相符,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "The pirate has a black eye patch.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性事实理解|单句信息点抓取"],
|
||||
"explanation": "听力中 Mike 说 'The pirate has a black eye patch.'(海盗戴着一个黑色的眼罩),图A戴眼罩的海盗与此描述完全匹配,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "I need my passport to go abroad.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性细节理解|物品功能辨识"],
|
||||
"explanation": "听力中 Lisa 说 'I need my passport to go abroad.'(我需要护照出国),图A为护照、图B为身份证、图C为银行卡,对应出国所需的证件是护照,故选A。"
|
||||
},
|
||||
{
|
||||
"question": "I like eating cheese very much.",
|
||||
"questionAudio": "",
|
||||
"optionsImage": None,
|
||||
"answer": [0],
|
||||
"ability": ["显性细节理解|物品特征辨识"],
|
||||
"explanation": "听力中 Peter 说 'I like eating cheese very much.'(我非常喜欢吃芝士),与图A切成块的黄色芝士相符。图B是全麦面包、图C是黄油,均不是cheese,故选A。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
TEXT1 = """【题目描述】
|
||||
听录音,选择正确的图片。
|
||||
|
||||
【听力文本】
|
||||
1. Lily: This is a blue box.
|
||||
2. Tom: He is a police officer.
|
||||
3. Anna: I want to drink milk.
|
||||
4. Bob: I eat a sandwich for breakfast.
|
||||
5. Cindy: This is my red suitcase."""
|
||||
|
||||
TEXT2 = """【题目描述】
|
||||
听录音,选择正确的图片。
|
||||
|
||||
【听力文本】
|
||||
1. Emma: Look at my new clothes.
|
||||
2. Jack: My dad works at the airport.
|
||||
3. Mike: The pirate has a black eye patch.
|
||||
4. Lisa: I need my passport to go abroad.
|
||||
5. Peter: I like eating cheese very much."""
|
||||
|
||||
fields = {
|
||||
"题目集合 ID": QSID,
|
||||
"jsonData": json.dumps(jd, ensure_ascii=False),
|
||||
"题目1": TEXT1,
|
||||
"题目2": TEXT2,
|
||||
"dataStatus": "0",
|
||||
"审校结果": "✅ 已补全:10道题 content/explanation/ability 全部填充完成(2026-05-14)"
|
||||
}
|
||||
|
||||
r = requests.put(
|
||||
f'https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{RID}',
|
||||
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
|
||||
json={'fields': fields}, timeout=15)
|
||||
|
||||
code = r.json().get('code')
|
||||
if code == 0:
|
||||
print('✅ 更新成功')
|
||||
# Verify
|
||||
r2 = requests.get(f'https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{RID}',
|
||||
headers={'Authorization': f'Bearer {token}'}, timeout=10)
|
||||
jd2 = json.loads(r2.json()['data']['record']['fields']['jsonData'])
|
||||
f_qs = jd2['first']['questionSet']
|
||||
s_qs = jd2['second']['questionSet']
|
||||
print(f'\n验证:')
|
||||
for i, q in enumerate(f_qs):
|
||||
ok = len(q.get('question',''))>0 and len(q.get('explanation',''))>20 and len(q.get('ability',[]))>0
|
||||
print(f' first Q{i+1}: {"✅" if ok else "❌"} q="{q["question"]}" answer={q["answer"]} ability={q["ability"]}')
|
||||
for i, q in enumerate(s_qs):
|
||||
ok = len(q.get('question',''))>0 and len(q.get('explanation',''))>20 and len(q.get('ability',[]))>0
|
||||
print(f' second Q{i+1}: {"✅" if ok else "❌"} q="{q["question"]}" answer={q["answer"]} ability={q["ability"]}')
|
||||
|
||||
f2 = r2.json()['data']['record']['fields']
|
||||
print(f'\n题目1: {len(f2.get("题目1",""))}chars, 题目2: {len(f2.get("题目2",""))}chars')
|
||||
print(f'审校结果: {f2.get("审校结果","")}')
|
||||
else:
|
||||
print(f'❌ 失败: {r.json().get("msg")}')
|
||||
213
scripts/fill_speaking_expl.py
Normal file
213
scripts/fill_speaking_expl.py
Normal file
@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate explanations for 171 empty speaking-P1 questions, then write back."""
|
||||
import json, requests, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
TABLE = "tblRGv7k4WH58Jgq"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
|
||||
# ── Explanation generator ──
|
||||
# Map ability → template function that takes (question_content, ability_list) → explanation
|
||||
|
||||
def gen_expl(q, abilities):
|
||||
"""Generate a natural Chinese explanation for a speaking question."""
|
||||
content = q.get('content', '') or q.get('question', '')
|
||||
ab = abilities[0] if abilities else '通用问答'
|
||||
|
||||
# ── Pattern-based explanations ──
|
||||
|
||||
# 基础信息表达|个人信息问答
|
||||
if '个人信息' in ab:
|
||||
if 'name' in content.lower() or "what's your name" in content.lower():
|
||||
return "本题考察基础个人信息表达能力。回答时直接说出自己的名字,如 'My name is Tom.' 注意使用完整的介绍句式,发音清晰。"
|
||||
if 'old' in content.lower() and 'how' in content.lower():
|
||||
return "本题考察年龄表达。回答时用 'I am ... years old.' 的句式,说清楚数字。也可以补充生日信息使回答更丰富。"
|
||||
if 'from' in content.lower():
|
||||
return "本题考察国籍与家乡表达。回答时用 'I am from ...' 或 'I come from ...' 的句式,可以说国家或城市名称。"
|
||||
if 'live' in content.lower():
|
||||
return "本题考察家庭生活信息表达。回答时用 'I live with my ...' 描述同住的家人。注意家庭成员词汇的准确使用。"
|
||||
if 'hair' in content.lower() or 'look like' in content.lower() or 'wearing' in content.lower() or 'favourite clothes' in content.lower():
|
||||
return "本题考察人物外貌与穿着描述能力。回答时使用 'He/She has...' 描述发型发色,用 'He/She is wearing...' 描述衣着,注意颜色和衣物词汇的准确使用。"
|
||||
if 'schoolbag' in content.lower() or 'in your' in content.lower() and ('schoolbag' in content.lower() or 'desk' in content.lower() or 'classroom' in content.lower()):
|
||||
return "本题考察物品列举与位置描述能力。回答时使用 'There is/are ... in my ...' 句式,逐一说出物品名称,注意单复数一致。"
|
||||
if 'tall' in content.lower():
|
||||
return "本题考察比较级描述能力。回答时使用 '... is taller than me.' 的句式,说出比你高的人的名字。注意比较级的正确使用。"
|
||||
if 'dinosaur' in content.lower() or 'cloud' in content.lower() or 'moon' in content.lower():
|
||||
return "本题考察想象与外观描述能力。回答时使用形容词描述事物的样子,如 'It is big and green.' 或 'It looks like ...',发挥想象力用英语表达。"
|
||||
if 'pet' in content.lower() and ('love' in content.lower() or 'like' in content.lower()):
|
||||
return "本题考察宠物喜好表达。回答时说出你喜欢的宠物,如 'I love dogs.' 并尝试说明喜欢的原因。注意动物名称词汇的准确使用。"
|
||||
if 'toy' in content.lower() or 'toys' in content.lower():
|
||||
return "本题考察个人物品表达。回答时列举你拥有的玩具,用 'I have ...' 句式。注意玩具词汇和复数形式的正确使用。"
|
||||
if 'book' in content.lower() and 'where' in content.lower():
|
||||
return "本题考察物品位置表达。回答时使用方位介词描述书的位置,如 'It is on the desk.' 或 'It is in my schoolbag.'"
|
||||
if 'pen' in content.lower() and 'yours' in content.lower():
|
||||
return "本题考察物品归属表达。肯定回答用 'Yes, it is mine.',否定回答用 'No, it is not mine.' 注意物主代词的区分。"
|
||||
if 'goal' in content.lower():
|
||||
return "本题考察目标与计划表达能力。回答时说出本学期的目标,如 'My goal is to read 10 English books.' 注意使用完整句子表达决心。"
|
||||
if 'keep healthy' in content.lower() or 'health' in content.lower():
|
||||
return "本题考察健康建议表达能力。回答时列举保持健康的方法,如 'We can eat vegetables and exercise every day.' 注意使用情态动词 can/should。"
|
||||
# fallback for 个人信息
|
||||
return f"本题考察基础个人信息表达能力。回答时需要围绕「{content[:20]}」这个主题用完整的英语句子进行描述或说明,注意信息清晰、表达自然。"
|
||||
|
||||
# 表达喜好与理由
|
||||
if '喜好' in ab:
|
||||
if 'favorite' in content.lower() or 'favourite' in content.lower():
|
||||
return "本题考察喜好表达与理由说明能力。回答时先明确说出喜好选择,如 'My favorite ... is ...',然后用 'because' 或 'I like it because...' 说明理由。"
|
||||
if 'like' in content.lower() and 'music' in content.lower():
|
||||
return "本题考察音乐喜好表达。回答时说出你喜欢的音乐类型,如 'I like pop music.' 再说明原因如 'because it makes me happy.' 也可以举一首喜欢的歌为例。"
|
||||
if 'like' in content.lower() and 'read' in content.lower():
|
||||
return "本题考察阅读喜好表达。回答时说明你喜欢读什么类型的书,如 'I like story books.' 并补充阅读的感受或最喜欢的书籍。"
|
||||
if 'like' in content.lower() and 'internet' in content.lower():
|
||||
return "本题考察网络活动喜好表达。回答时说出你在网上喜欢做什么,如 'I like watching videos and playing games online.' 用 and 连接多项活动。"
|
||||
if 'like' in content.lower() and 'cat' in content.lower():
|
||||
return "本题考察原因解释能力。回答时用 'because' 引出原因,如 'I like cats because they are cute and soft.' 至少给出一个具体理由。"
|
||||
if 'hobby' in content.lower():
|
||||
return "本题考察爱好表达。回答时说出你的爱好,如 'My hobby is drawing.' 或 'I like playing football.' 可以补充做这个爱好的频率和感受。"
|
||||
if 'think of' in content.lower() or 'think about' in content.lower():
|
||||
return "本题考察观点表达能力。回答时用 'I think ...' 开头表达你的看法,然后简单说明原因。鼓励表达真实想法而不仅仅是正确回答。"
|
||||
if 'plan' in content.lower() or 'going to' in content.lower():
|
||||
return "本题考察未来计划表达能力。回答时用 'I plan to ...' 或 'I am going to ...' 的句式描述计划,注意将来时的正确使用。"
|
||||
if 'want to' in content.lower() and 'do' in content.lower():
|
||||
return "本题考察意愿与计划表达。回答时用 'I want to ...' 表达你想做的事,如果涉及周末计划可用 'I am going to ...'。"
|
||||
if 'dad' in content.lower() and ('unhappy' in content.lower() or 'say' in content.lower()):
|
||||
return "本题考察家庭情感与沟通表达。回答时描述爸爸的言行或情绪,如 'He said I should finish my homework first.' 注意引述和描述的准确性。"
|
||||
if 'happy' in content.lower() or 'glad' in content.lower():
|
||||
return "本题考察积极情感表达能力。回答时用 'I am happy/glad that ...' 的句式表达喜悦,并具体说出让你开心的事情。"
|
||||
if 'afraid' in content.lower():
|
||||
return "本题考察恐惧情感表达能力。回答时用 'I am afraid of ...' 说出害怕的动物或事物,可以简单说明原因如 'because it is scary.'"
|
||||
if 'need' in content.lower() or 'need to do' in content.lower():
|
||||
return "本题考察需求表达能力。回答时用 'I need to ...' 或 'We need ...' 说明需要做的事情或物品。注意 need 后接动词原形或名词。"
|
||||
if 'colour' in content.lower() or 'color' in content.lower():
|
||||
return "本题考察颜色偏好表达。回答时说出你想要的颜色,如 'I want the picture in blue.' 或 'I like red best.' 可以补充为什么喜欢这个颜色。"
|
||||
if 'whose' in content.lower():
|
||||
return "本题考察物品归属判断与表达。回答时用 'I think it is ...'s.' 或 'It might be ...' 的句式表达推断。注意名词所有格的正确使用。"
|
||||
if 'exam' in content.lower():
|
||||
return "本题考察学习准备与计划表达。回答时列举考前需做的事,如 'I need to review my notes and do more practice.' 注意使用 need to 表达必要性。"
|
||||
if 'wrong' in content.lower() and 'radio' in content.lower():
|
||||
return "本题考察推断与猜测表达能力。回答时用 'Maybe it is ...' 或 'It might be ...' 表达对故障原因的推测。注意情态动词 might/maybe 的使用。"
|
||||
return f"本题考察表达喜好与理由的能力。回答时先表明喜好态度或观点,再用 'because' 等连接词说明理由,注意使用完整的英语句子。"
|
||||
|
||||
# 互动应答|问答交流
|
||||
if '互动应答' in ab or '问答交流' in ab:
|
||||
if 'help' in content.lower() and 'say' in content.lower():
|
||||
return "本题考察礼貌应答能力。回答时给出得体的感谢用语,如 'Thank you so much!' 或 'That's very kind of you.' 注意感谢的真诚性表达。"
|
||||
if 'sorry' in content.lower() or 'lose' in content.lower() and 'book' in content.lower():
|
||||
return "本题考察道歉表达与情境应对。回答时用诚恳的道歉语如 'I am so sorry. I will help you find it.' 同时给出弥补方案,体现责任感。"
|
||||
if 'library' in content.lower() and 'should' in content.lower():
|
||||
return "本题考察规则表达能力。回答时使用情态动词如 'We shouldn't talk loudly.' 或 'We must be quiet.' 表达图书馆的行为规范。"
|
||||
if 'park' in content.lower() and ('must' in content.lower() or 'should' in content.lower()):
|
||||
return "本题考察规则与义务表达能力。回答时用 'We must not ...' 表达禁止行为,如 'We must not pick flowers or litter.' 注意 must 的使用。"
|
||||
if 'ill' in content.lower() or 'sad' in content.lower():
|
||||
return "本题考察共情与关怀表达能力。回答时说出关怀的话语,如 'I hope you feel better soon.' 或 'Don't be sad, let me help you.' 体现同理心。"
|
||||
if 'leave' in content.lower():
|
||||
return "本题考察礼貌告别用语。回答时说出得体的道别方式,如 'Goodbye!' 或 'See you later!' 也可以说 'It was nice meeting you.'"
|
||||
if 'friend comes' in content.lower() or 'friend came' in content.lower() or 'come to your home' in content.lower():
|
||||
return "本题考察接待与欢迎表达能力。回答时说出欢迎用语,如 'Welcome! Come in, please.' 或 'I'm so glad you came!' 注意热情友好的语气。"
|
||||
if 'introduce' in content.lower():
|
||||
return "本题考察介绍他人的能力。回答时使用 'This is my friend ...' 的句式介绍朋友,可以说出对方的名字和一两个特点。"
|
||||
if 'shop' in content.lower() or 'shopping' in content.lower():
|
||||
return "本题考察购物场景交流能力。回答时模拟店员用语如 'Can I help you?' 或 'What would you like to buy?' 注意服务场景的礼貌表达。"
|
||||
if 'swim' in content.lower() or 'sports' in content.lower():
|
||||
return "本题考察能力询问与应答。肯定回答用 'Yes, I can swim.',否定回答用 'No, I can't swim.' 或补充 'But I can run fast.'"
|
||||
if 'can you help' in content.lower():
|
||||
return "本题考察请求帮助的表达与应答。回答时可以表示愿意帮助 'Sure, I will help you.' 或说明无法帮助的原因 'Sorry, my hands are full.'"
|
||||
if 'say when' in content.lower() and 'can' in content.lower() and 'find' in content.lower():
|
||||
return "本题考察失物求助表达。回答时说出寻找物品的请求语,如 'I can't find my pen. Can you help me?' 或 'Have you seen my pen?'"
|
||||
if 'say when' in content.lower() and 'ruler' in content.lower():
|
||||
return "本题考察借物请求表达。回答时说出礼貌的借物请求,如 'May I borrow your ruler, please?' 注意使用 May I 或 Can I 的礼貌表达。"
|
||||
if 'draw' in content.lower() and 'together' in content.lower():
|
||||
return "本题考察邀请与提议表达能力。回答时使用 'Let's draw together!' 或 'Shall we draw a picture?' 表达邀请,语气友好自然。"
|
||||
if 'loud' in content.lower():
|
||||
return "本题考察请求与协商表达能力。回答时礼貌地提出降低音量的请求,如 'Could you please turn it down?' 或 'It's a bit too loud.' 注意礼貌用语。"
|
||||
if 'rabbit' in content.lower() and 'eat' in content.lower():
|
||||
return "本题考察观察与描述应答。回答时描述兔子正在吃什么,如 'The rabbit is eating a carrot.' 注意现在进行时的正确使用。"
|
||||
if 'see in the sky' in content.lower():
|
||||
return "本题考察观察与描述应答。回答时描述天空中看到的事物,如 'I can see some birds and clouds.' 或 'I can see the sun.' 注意自然观察词汇。"
|
||||
if 'page' in content.lower():
|
||||
return "本题考察课堂指令应答能力。回答时说出应该翻到的页码,如 'Let's turn to page 10.' 或 'Please turn to page 10.'"
|
||||
if 'animal' in content.lower() and 'look at' in content.lower():
|
||||
return "本题考察选择与提议应答。回答时提出想看的动物,如 'Let's look at the elephants.' 或 'I want to see the monkeys.'"
|
||||
if 'car' in content.lower() and 'faster' in content.lower():
|
||||
return "本题考察比较与判断应答。回答时使用比较级说出哪辆车更快,如 'The red car is faster.' 注意比较级 -er 或 more 的使用。"
|
||||
if 'gift' in content.lower() or 'present' in content.lower():
|
||||
return "本题考察礼物相关表达能力。回答时描述想要的礼物或礼物送给谁,如 'I want a toy car for my birthday.' 或 'This gift is for my mum.'"
|
||||
if 'picnic' in content.lower():
|
||||
return "本题考察准备与计划描述能力。回答时列举野餐需要带的东西,如 'We need some sandwiches, fruit and drinks for the picnic.' 注意物品词汇的准确使用。"
|
||||
return f"本题考察互动应答能力。回答时需要根据「{content[:20]}」的情境,给出得体的英文回应,注意使用礼貌用语和完整句子。"
|
||||
|
||||
# 信息交换|双向问答
|
||||
if '信息交换' in ab:
|
||||
if 'lunch' in content.lower() or 'eat' in content.lower():
|
||||
return "本题考察饮食内容交流能力。回答时用 'Let's have ...' 提出午餐建议,或说出想吃的食物。注意食物名称词汇的准确使用,可以说明选择理由使交流更自然。"
|
||||
return "本题考察信息交换与双向交流能力。回答时不仅给出自己的答案,还可以反问对方以延续对话,注意问答之间的自然过渡和对话的互动性。"
|
||||
|
||||
# 过去经历描述
|
||||
if '过去经历' in ab or 'Past' in ab:
|
||||
if 'see' in content.lower() and ('park' in content.lower() or 'weekend' in content.lower()):
|
||||
return "本题考察过去经历描述能力。回答时使用过去时描述你在公园看到的事物,如 'I saw many beautiful flowers and some ducks in the pond.' 注意过去式动词的正确使用。"
|
||||
if 'help' in content.lower():
|
||||
return "本题考察过去行为描述能力。回答时说出你帮助了谁以及怎么帮的,如 'I helped my mum clean the house.' 注意 help 后接动词原形。"
|
||||
if 'weekend' in content.lower():
|
||||
return "本题考察过去活动描述能力。回答时描述周末发生的事情,用过去时讲述活动和感受,如 'Last weekend, I went to the zoo with my family.'"
|
||||
return f"本题考察过去经历描述能力。回答时使用过去时态描述「{content[:20]}」相关经历,注意动词过去式的变化,包含时间、地点和感受。"
|
||||
|
||||
# Fallback
|
||||
return f"本题考察英语口语应答能力。请围绕「{content[:30]}」用完整句子进行回答,注意发音清晰、语法正确、表达自然。"
|
||||
|
||||
|
||||
# ── Main ──
|
||||
def main():
|
||||
token = get_token()
|
||||
print("Token OK")
|
||||
|
||||
with open('/root/.openclaw/workspace-xiaoyan/tmp/empty_expl_data.json') as f:
|
||||
records = json.load(f)
|
||||
|
||||
print(f"Processing {len(records)} records, 171 questions...")
|
||||
|
||||
updated = 0
|
||||
for rec in records:
|
||||
rid = rec['rid']
|
||||
jd = rec['jd']
|
||||
qsid = rec['qsid']
|
||||
|
||||
modified = False
|
||||
for bn in ['first', 'second']:
|
||||
block = jd.get(bn, {})
|
||||
if not block:
|
||||
continue
|
||||
qs = block.get('questionSet', [])
|
||||
for qi, q in enumerate(qs):
|
||||
expl = q.get('explanation', '')
|
||||
if expl == 'PATCH' or not expl or len(expl.strip()) < 5:
|
||||
abilities = q.get('ability', [])
|
||||
new_expl = gen_expl(q, abilities)
|
||||
q['explanation'] = new_expl
|
||||
modified = True
|
||||
updated += 1
|
||||
|
||||
if modified:
|
||||
# Write back
|
||||
new_jd_str = json.dumps(jd, ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f'https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}',
|
||||
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
|
||||
json={'fields': {'jsonData': new_jd_str}}, timeout=15)
|
||||
code = r.json().get('code')
|
||||
if code == 0:
|
||||
print(f' ✅ {qsid} ({rid[:12]}...)')
|
||||
else:
|
||||
print(f' ❌ {qsid}: {r.json().get("msg")}')
|
||||
time.sleep(0.25)
|
||||
|
||||
print(f'\nDone: {updated} explanations generated across {len(records)} records')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
158
scripts/fix_p1_4records.py
Normal file
158
scripts/fix_p1_4records.py
Normal file
@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fix 021301/021401/021501/021701: fill ability + explanation, add empty second block"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
TABLE = "tblRGv7k4WH58Jgq"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
token = get_token()
|
||||
|
||||
# Fetch records
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
records = {}
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if qsid in ("021301", "021401", "021501", "021701"):
|
||||
records[qsid] = {
|
||||
"rid": it["record_id"],
|
||||
"jd": json.loads(it["fields"].get("jsonData", "{}"))
|
||||
}
|
||||
|
||||
# ========== 021301 - 描述人物与自己 ==========
|
||||
fixes_021301 = {
|
||||
"first": {
|
||||
0: {"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "本题考察用英语描述他人外貌的能力。回答时用 'He/She has...' 或 'My best friend is...' 描述身高、头发、眼睛等特征。例如 'She has long black hair and big brown eyes.'"},
|
||||
1: {"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "本题考察用英语描述家人特征的能力。回答时用 'My dad/mom is...' 开始,描述外貌或性格,例如 'My mom is kind and she always smiles.'"},
|
||||
2: {"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "本题考察表达个人能力。回答用 'I am good at...' 或 'I can... well',例如 'I am good at drawing pictures for my friends.'"},
|
||||
3: {"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "本题考察描述家人角色。回答时说明谁帮助你及如何帮助,例如 'My grandma is good at helping me — she always makes my favourite food.'"},
|
||||
}
|
||||
}
|
||||
|
||||
# ========== 021401 - 条件场景与应对 ==========
|
||||
fixes_021401 = {
|
||||
"first": {
|
||||
0: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察在特定情境下用英语礼貌询问的能力。回答时用 'I will ask...' 或 'Excuse me...' 开头,例如 'I will ask the teacher, \"When is the school trip?\"'"},
|
||||
1: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察主动提供帮助的英语表达。回答用 'I will say...' 或 'Do you need...?',例如 'I will say, \"Do you need any help? Let me carry some for you.\"'"},
|
||||
2: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察用英语提醒他人遵守规则。回答用 'I will say...' 和礼貌的语气,例如 'I will say, \"Please don't run in the library — someone could get hurt.\"'"},
|
||||
3: {"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "本题考察在问题情境下寻求帮助的表达。回答时说明应该联系谁及为什么,例如 'I should talk to a vet because they are animal doctors.'"},
|
||||
}
|
||||
}
|
||||
|
||||
# ========== 021501 - 问题解决与安慰 ==========
|
||||
fixes_021501 = {
|
||||
"first": {
|
||||
0: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察在等待情境下给出建议的表达。回答用 'I will tell him...' 和安慰语气,例如 'I will say, \"Let's wait until the teacher is free. We can check later.\"'"},
|
||||
1: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察提供解决方案的英语表达。回答说明你会怎么做,例如 'I can share my lunch with him, or ask the teacher if there is extra food.'"},
|
||||
2: {"ability": ["互动应答|问答交流"],
|
||||
"explanation": "本题考察用英语安慰他人的能力。回答包含道歉回应和安抚语,例如 'I will say, \"It's okay — it was an accident. Let me help you clean it up.\"'"},
|
||||
3: {"ability": ["协商表达"],
|
||||
"explanation": "本题考察用英语协商和妥协的表达。回答用 'How about...?' 或 'Maybe we can...',例如 'How about we watch your film this time, and next time we can watch mine?'"},
|
||||
}
|
||||
}
|
||||
|
||||
# ========== 021701 - 购物与计划 ==========
|
||||
fixes_021701 = {
|
||||
"first": {
|
||||
0: {"ability": ["表达计划"],
|
||||
"explanation": "本题考察用英语表达购物需求。回答用 'I need to buy...' 并列出物品,例如 'I need to buy some bread, milk, and apples at the supermarket.'"},
|
||||
1: {"ability": ["表达推测"],
|
||||
"explanation": "本题考察用英语推测和表达购买地点。回答用 'I think I can buy...' 或 'Maybe at...',例如 'I think I can buy a new toy at the shop near our school.'"},
|
||||
2: {"ability": ["表达计划"],
|
||||
"explanation": "本题考察用未来时态描述家庭计划。回答用 'I think we will...' 或 'Maybe we will...',例如 'I think my family will visit my grandparents this weekend.'"},
|
||||
3: {"ability": ["表达愿望"],
|
||||
"explanation": "本题考察用虚拟语气表达购物愿望。回答用 'If I could, I would buy...' 或 'I would choose...',例如 'If I could buy one thing, I would choose a new bicycle.'"},
|
||||
}
|
||||
}
|
||||
|
||||
fixes_map = {
|
||||
"021301": fixes_021301,
|
||||
"021401": fixes_021401,
|
||||
"021501": fixes_021501,
|
||||
"021701": fixes_021701,
|
||||
}
|
||||
|
||||
# Apply fixes and write back
|
||||
for qsid, fixes in fixes_map.items():
|
||||
rec = records[qsid]
|
||||
jd = rec["jd"]
|
||||
rid = rec["rid"]
|
||||
|
||||
# Apply ability and explanation to first block
|
||||
for qi_str, fix in fixes.get("first", {}).items():
|
||||
qi = int(qi_str)
|
||||
qs = jd["first"].get("questionSet", [])
|
||||
if qi < len(qs):
|
||||
qs[qi]["ability"] = fix["ability"]
|
||||
qs[qi]["explanation"] = fix["explanation"]
|
||||
|
||||
# Add empty second block (no questions, placeholder)
|
||||
if not jd.get("second") or not jd["second"].get("questionSet"):
|
||||
jd["second"] = {
|
||||
"type": "speaking_qa",
|
||||
"questionSetID": qsid,
|
||||
"questionSet": [],
|
||||
"ability": [],
|
||||
"explanation": ""
|
||||
}
|
||||
|
||||
new_jd = json.dumps(jd, ensure_ascii=False)
|
||||
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
code = r.json().get("code")
|
||||
if code == 0:
|
||||
print(f"[✅] {qsid}: ability+explanation填满4题, second块已补")
|
||||
else:
|
||||
print(f"[❌] {qsid}: {r.json().get('msg')}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# Verify
|
||||
print("\n=== 验证 ===")
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if qsid not in ("021301", "021401", "021501", "021701"):
|
||||
continue
|
||||
jd = json.loads(it["fields"].get("jsonData", "{}"))
|
||||
all_ok = True
|
||||
for bn in ["first", "second"]:
|
||||
b = jd.get(bn, {})
|
||||
qs = b.get("questionSet", [])
|
||||
if bn == "second":
|
||||
has_block = bool(b)
|
||||
print(f" {qsid} {bn}: {'存在' if has_block else '缺失'}, 题数={len(qs)}")
|
||||
continue
|
||||
for qi, q in enumerate(qs):
|
||||
ab = q.get("ability", [])
|
||||
expl = q.get("explanation", "")
|
||||
ok = bool(ab) and len(expl) > 20
|
||||
if not ok:
|
||||
all_ok = False
|
||||
print(f" {qsid} [{qi}] ab={ab} expl={'✅' if ok else '❌'} ({len(expl)}字)")
|
||||
status = "✅" if all_ok else "❌"
|
||||
print(f" => {status}\n")
|
||||
|
||||
print("完成")
|
||||
60
scripts/fix_p2_pic_batch2.py
Normal file
60
scripts/fix_p2_pic_batch2.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add [2-组图] to 021801/022001/022201/032601/032801 speaking-P2 records"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
TABLE = "tblGoWYBmVI0IrvQ"
|
||||
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
token = r.json()["tenant_access_token"]
|
||||
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
# [2-组图] prompts matching each record's second block questions
|
||||
# Only prompts 2-5 (questions 0-3), question 4 is reflection — no prompt
|
||||
pic_2 = {
|
||||
"021801": '[2-组图]:{"prompt_2":"黑白线条图:一个孩子拿着作业本主动走到需要帮助的同学身边面带微笑,课桌上散落着打开的书本和铅笔","prompt_3":"黑白线条图:在学校走廊里,一个孩子蹲下来帮另一个同学系鞋带,另一个同学感激地看着他","prompt_4":"黑白线条图:两个孩子一起在花园里种下小树苗,一个扶着树苗一个培土,脸上带着共同的期待和开心","prompt_5":"黑白线条图:学校集会上,一个孩子站在台上双手接过助人为乐奖状,台下同学们纷纷起立鼓掌"}',
|
||||
|
||||
"022001": '[2-组图]:{"prompt_2":"黑白线条图:两个孩子在学校操场边,一个孩子拍拍同伴的肩膀用积极的话安慰,同伴紧皱的眉头逐渐舒展","prompt_3":"黑白线条图:一个孩子站在游泳池边有些紧张,旁边一位教练轻轻扶着他的手臂,表情充满鼓励","prompt_4":"黑白线条图:一个孩子坐在房间里反复练习弹钢琴,琴谱上标着红色笔记,表情从沮丧逐渐变为专注自信","prompt_5":"黑白线条图:操场上正在进行拔河比赛,所有孩子的表情认真又兴奋,绳子上系着的红丝带缓缓移动"}',
|
||||
|
||||
"022201": '[2-组图]:{"prompt_2":"黑白线条图:一群孩子在教室中围坐在地板上,有人在写活动计划清单,有人在剪彩纸装饰,气氛热闹活跃","prompt_3":"黑白线条图:墙上刚贴好的装饰物掉了下来散落一地,一个孩子满脸沮丧地蹲着,同伴们围过来想要帮忙","prompt_4":"黑白线条图:孩子们使用彩纸、剪刀、胶水和马克笔精心制作大型展示板,分工明确各有任务","prompt_5":"黑白线条图:全班学生在装饰后的教室里开心庆祝活动成功,大家分享着食物,脸上带着满足的笑容"}',
|
||||
|
||||
"032601": '[2-组图]:{"prompt_2":"黑白线条图:一个孩子在舞台中央表演,台下父母坐在观众席中激动地抹眼泪,聚光灯照在孩子身上","prompt_3":"黑白线条图:一个孩子坐在书桌前好奇地翻阅一本世界职业图册,上面有宇航员、教师、消防员等各种工作场景","prompt_4":"黑白线条图:一个孩子把远大的梦想写在旗帜上挂在高处,又认真地在地上用小石子一步步标记出通向目标的路径","prompt_5":"黑白线条图:一个孩子坐在朋友身边紧握朋友的手给予鼓励,朋友原本沮丧的表情逐渐露出希望的光"}',
|
||||
|
||||
"032801": '[2-组图]:{"prompt_2":"黑白线条图:一个孩子把手机放进一个小盒子里锁起来放到一边,然后转而拿起桌上的一本厚书认真阅读","prompt_3":"黑白线条图:一个孩子清晨醒来第一件事就是仔细叠被子整理床铺,家长站在门口微笑赞许","prompt_4":"黑白线条图:一个孩子坐在钢琴前弹奏出优美的旋律,墙上的日历从一月翻到六月每一页都打着勾,显示长期坚持","prompt_5":"黑白线条图:一个年长的孩子坐在年幼的学弟旁边,指着时间管理计划表耐心解释每项任务该如何安排"}',
|
||||
}
|
||||
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if qsid not in pic_2: continue
|
||||
rid = it["record_id"]
|
||||
pic_old = it["fields"].get("图片描述", "")
|
||||
# Append [2-组图] to existing [1-组图]
|
||||
pic_new = pic_old + "\n" + pic_2[qsid] if pic_old else pic_2[qsid]
|
||||
|
||||
r2 = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"图片描述": pic_new}}, timeout=15)
|
||||
code = r2.json().get("code")
|
||||
print(f" {'✅' if code==0 else '❌'} {qsid}: +[2-组图] (总长{len(pic_new)}字)")
|
||||
time.sleep(0.3)
|
||||
|
||||
# Verify
|
||||
print(f"\n=== 验证 ===")
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if qsid not in pic_2: continue
|
||||
pic = it["fields"].get("图片描述", "")
|
||||
has_1 = "[1-组图]" in pic
|
||||
has_2 = "[2-组图]" in pic
|
||||
print(f" {qsid}: [1-组图]={'✅' if has_1 else '❌'} [2-组图]={'✅' if has_2 else '❌'}")
|
||||
|
||||
print("\n完成")
|
||||
159
scripts/fix_p2_records.py
Normal file
159
scripts/fix_p2_records.py
Normal file
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fix speaking_P2: 021601 expl+second, 021801 ability, 032601/032801 short expl"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
TABLE = "tblGoWYBmVI0IrvQ"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
token = get_token()
|
||||
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
records = {}
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if not qsid: continue
|
||||
jd_raw = it["fields"].get("jsonData", "")
|
||||
if not jd_raw: continue
|
||||
records[qsid] = {"rid": it["record_id"], "jd": json.loads(jd_raw)}
|
||||
|
||||
# ========== 021601: fill 4 explanations + empty second block ==========
|
||||
fix_021601_expl = {
|
||||
0: "本题考察在特定情境下用英语回溯和描述的能力。回答时用过去时态,说明你最后一次看到玩具的地点。例如 'I last saw my toy near the big tree by the pond in the park.' 注意用 'last saw' 和准确的地点描述。",
|
||||
1: "本题考察用英语劝阻和提醒他人的能力。回答时用 'You should...' 或 'Don't...' 引导,加上原因说明。例如 'I would say, \"Don't climb too high — you might fall and hurt yourself!\"'",
|
||||
2: "本题考察用英语描述周边环境的能力。回答时用 'Near the park there is...' 列出附近地点。例如 'Near the park, there is a small shop, a library, and a playground.'",
|
||||
3: "本题考察用英语描述应对措施的能力。回答时说明你会怎么做以及找谁帮忙。例如 'If I lose something, I will first go back to where I last saw it, then ask a park worker for help.'",
|
||||
}
|
||||
|
||||
rec = records["021601"]
|
||||
qs = rec["jd"]["first"]["questionSet"]
|
||||
for qi, expl in fix_021601_expl.items():
|
||||
qs[qi]["explanation"] = expl
|
||||
|
||||
rec["jd"]["second"] = {"type": "speaking_topic", "questionSetID": "021601", "questionSet": [], "ability": [], "explanation": ""}
|
||||
|
||||
new_jd = json.dumps(rec["jd"], ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rec['rid']}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
print(f"[021601] {'✅' if r.json().get('code')==0 else '❌'+r.json().get('msg','')}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# ========== 021801: fill 10 ability labels ==========
|
||||
fix_021801_ab = {
|
||||
"first": {
|
||||
0: ["表达观点", "句型组织"],
|
||||
1: ["表达建议", "句型组织"],
|
||||
2: ["表达期望", "句型组织"],
|
||||
3: ["经历描述", "句型组织"],
|
||||
4: ["表达观点", "句型组织"],
|
||||
},
|
||||
"second": {
|
||||
0: ["表达观点", "句型组织"],
|
||||
1: ["表达建议", "句型组织"],
|
||||
2: ["表达期望", "句型组织"],
|
||||
3: ["经历描述", "句型组织"],
|
||||
4: ["表达观点", "句型组织"],
|
||||
}
|
||||
}
|
||||
|
||||
rec = records["021801"]
|
||||
for bn in ["first", "second"]:
|
||||
qs = rec["jd"].get(bn, {}).get("questionSet", [])
|
||||
for qi, ab in fix_021801_ab.get(bn, {}).items():
|
||||
if qi < len(qs):
|
||||
qs[qi]["ability"] = ab
|
||||
|
||||
new_jd = json.dumps(rec["jd"], ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rec['rid']}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
print(f"[021801] {'✅' if r.json().get('code')==0 else '❌'+r.json().get('msg','')}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# ========== 032601: extend 3 short explanations ==========
|
||||
fix_032601_expl = {
|
||||
"first": {
|
||||
4: "本题考察用英语描述他人对你影响的能力。回答时说明谁、说过什么、以及你如何因此改变了对未来的想法。例如 'My teacher once told me that if you work hard for your dream, it will come true someday — that changed how I think about my future goals.'",
|
||||
},
|
||||
"second": {
|
||||
3: "本题考察用英语对比和阐述的能力。回答时说明远大梦想给你方向,小目标帮你一步步前进,两者缺一不可。例如 'Big dreams give us a direction, while small goals help us take steps every day. Both are important.'",
|
||||
4: "本题考察用英语给予鼓励和建议的能力。回答时用安慰加建议的结构。例如 'I would tell my friend not to give up, and share a story about someone who almost failed before they finally succeeded.'",
|
||||
}
|
||||
}
|
||||
|
||||
rec = records["032601"]
|
||||
for bn in ["first", "second"]:
|
||||
qs = rec["jd"].get(bn, {}).get("questionSet", [])
|
||||
for qi, expl in fix_032601_expl.get(bn, {}).items():
|
||||
if qi < len(qs):
|
||||
qs[qi]["explanation"] = expl
|
||||
|
||||
new_jd = json.dumps(rec["jd"], ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rec['rid']}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
print(f"[032601] {'✅' if r.json().get('code')==0 else '❌'+r.json().get('msg','')}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# ========== 032801: extend 6 short explanations ==========
|
||||
fix_032801_expl = {
|
||||
"first": {
|
||||
1: "本题考察用英语描述无法自控行为的能力。回答时用过去时说明一种曾让你停不下来的活动,以及花了多长时间。例如 'I once started playing a new video game, and I just couldn't stop until I finished all the levels three days later.'",
|
||||
4: "本题考察用英语描述解决问题的策略。回答时说明你会分解问题、找人求助或暂停休息。例如 'When I find a problem too hard, I break it into smaller parts first, and if I still can't solve it, I ask my teacher for help.'",
|
||||
},
|
||||
"second": {
|
||||
0: "本题考察用英语描述并反思坏习惯的能力。回答时用 'I wish I could stop...' 并解释为什么这是坏习惯及你想如何改变。例如 'I wish I could stop checking my phone before bed because it makes it hard for me to fall asleep.'",
|
||||
2: "本题考察用英语描述长期学习投入的能力。回答时说明学了多久、进展如何、以及对结果的满意度。例如 'I've spent two years learning to play the piano. I'm proud of my progress, but I still have a lot to learn.'",
|
||||
3: "本题考察用英语描述压力感受和应对方式的能力。回答时说明你如何感知压力并如何缓解。例如 'When there is too much pressure, I feel tired and stressed. I usually take a short break, do some exercise, or talk to my parents about it.'",
|
||||
4: "本题考察用英语给予学弟学妹建议的能力。回答时用简单的建议句式,说明如何安排时间和寻求帮助。例如 'I would tell them to make a plan for their time, not wait until the last minute, and always ask for help when they need it.'",
|
||||
}
|
||||
}
|
||||
|
||||
rec = records["032801"]
|
||||
for bn in ["first", "second"]:
|
||||
qs = rec["jd"].get(bn, {}).get("questionSet", [])
|
||||
for qi, expl in fix_032801_expl.get(bn, {}).items():
|
||||
if qi < len(qs):
|
||||
qs[qi]["explanation"] = expl
|
||||
|
||||
new_jd = json.dumps(rec["jd"], ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rec['rid']}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
print(f"[032801] {'✅' if r.json().get('code')==0 else '❌'+r.json().get('msg','')}")
|
||||
|
||||
# ========== Write-back audit results ==========
|
||||
print("\n=== 回填审核结果 ===")
|
||||
audit_map = {
|
||||
"010199": "✅ 通过:first/second各6题,explanation/ability/answer完整",
|
||||
"021601": "✅ 已修复:4题explanation已填写,second块已补(空占位)",
|
||||
"021801": "✅ 已修复:first/second共10题ability已补全",
|
||||
"022001": "✅ 通过:first/second各5题,explanation完整",
|
||||
"022201": "✅ 通过:first/second各5题,含图片描述,explanation完整",
|
||||
"032601": "✅ 已修复:3题explanation延展为完整解析,含句型模板+示例回答",
|
||||
"032801": "✅ 已修复:6题explanation延展为完整解析,含句型模板+示例回答",
|
||||
}
|
||||
|
||||
for qsid, result in audit_map.items():
|
||||
if qsid not in records: continue
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{records[qsid]['rid']}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"审核结果": result}}, timeout=10)
|
||||
print(f" {'✅' if r.json().get('code')==0 else '❌'} {qsid}")
|
||||
time.sleep(0.3)
|
||||
|
||||
print("\n全部完成")
|
||||
124
scripts/fix_second_and_pic.py
Normal file
124
scripts/fix_second_and_pic.py
Normal file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Task 1: Fix all structured empty seconds → "second": {}
|
||||
Task 2: Add 图片描述 to 021601, 021801, 022001"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
token = get_token()
|
||||
|
||||
# List all tables in the bitable
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
tables = r.json().get("data", {}).get("items", [])
|
||||
print(f"共 {len(tables)} 个表\n")
|
||||
|
||||
# ====== Task 1: Scan all tables for structured empty second blocks ======
|
||||
fixes_second = [] # (table_id, table_name, qsid, rid)
|
||||
|
||||
for t in tables:
|
||||
tid = t["table_id"]
|
||||
tname = t["name"]
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
items = r.json().get("data", {}).get("items", [])
|
||||
for it in items:
|
||||
f = it["fields"]
|
||||
qsid = f.get("题目集合 ID", "") or ""
|
||||
jd_raw = f.get("jsonData", "")
|
||||
if not jd_raw: continue
|
||||
try:
|
||||
jd = json.loads(jd_raw) if isinstance(jd_raw, str) else jd_raw
|
||||
except:
|
||||
continue
|
||||
|
||||
second = jd.get("second", None)
|
||||
if not second or not isinstance(second, dict):
|
||||
continue
|
||||
|
||||
# Check if structured empty: has type/questionSetID but empty questionSet
|
||||
qs = second.get("questionSet", None)
|
||||
if qs is not None and isinstance(qs, list) and len(qs) == 0:
|
||||
# Has structure but no content → fix to {}
|
||||
fixes_second.append((tid, tname, qsid, it["record_id"], second))
|
||||
|
||||
print(f"=== Task 1: 修复结构化空 second → {{}} ===")
|
||||
print(f"发现 {len(fixes_second)} 条需要修复\n")
|
||||
|
||||
for tid, tname, qsid, rid, old_second in fixes_second:
|
||||
# Fetch fresh record to get current jsonData
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=10)
|
||||
rec = r.json()["data"]["record"]
|
||||
jd = json.loads(rec["fields"]["jsonData"])
|
||||
|
||||
# Before
|
||||
old_type = jd["second"].get("type", "?")
|
||||
|
||||
# Replace with empty object
|
||||
jd["second"] = {}
|
||||
|
||||
new_jd = json.dumps(jd, ensure_ascii=False)
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd}}, timeout=15)
|
||||
code = r.json().get("code")
|
||||
print(f" {'✅' if code==0 else '❌'} [{tname}] {qsid}: second({old_type}) → {{}}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# ====== Task 2: Add 图片描述 to 021601, 021801, 022001 ======
|
||||
print(f"\n=== Task 2: 补充图片描述 ===")
|
||||
|
||||
pic_map = {
|
||||
"021601": '[1-组图]:{"prompt_2":"黑白线条图:一个孩子在公园里焦急地四处张望,似乎在寻找丢失的玩具,背景有秋千、滑梯和大树,远处是公园的出口","prompt_3":"黑白线条图:一个小男孩正在爬滑梯的顶部,一个较大的孩子站在下面焦急地伸手示意他下来,表情紧张","prompt_4":"黑白线条图:公园入口处可以看到周围的商店、图书馆和警察亭,一位公园工作人员站在指示牌旁微笑着指路"}',
|
||||
"021801": '[1-组图]:{"prompt_2":"黑白线条图:一个孩子躺在床上盖着被子,额头上放着湿毛巾,他的朋友坐在床边端来一杯水,床头柜上放着药瓶","prompt_3":"黑白线条图:两个同学坐在教室的课桌前,一个正在耐心地指着作业本给另一个讲解题目,旁边放着课本和铅笔","prompt_4":"黑白线条图:两个孩子并肩坐在草地上,一个孩子指着远方天空中的热气球,脸上带着鼓励和期待的表情","prompt_5":"黑白线条图:教室里,一个孩子帮忙扶住同学够高处的书本,另一个孩子在帮老师整理教具,气氛温馨互助"}',
|
||||
"022001": '[1-组图]:{"prompt_2":"黑白线条图:学校走廊里,一个孩子脸上带着担忧的表情蹲在墙角,另一个孩子走过来蹲下身关切地询问","prompt_3":"黑白线条图:一位爷爷坐在沙发上拉着孩子的手认真地说话,表情温和而坚定,孩子脸上露出理解的神情","prompt_4":"黑白线条图:教室里,一个孩子站在讲台上自信地展示自己的画作,台下的同学们都在热烈鼓掌,孩子脸上带着自豪的笑容","prompt_5":"黑白线条图:书房里,一位家长蹲在孩子面前轻声解释着笔记本上的内容,墙上贴着学习计划表和各种鼓励标语"}',
|
||||
}
|
||||
|
||||
# Speaking-P2 table
|
||||
SP2_TABLE = "tblGoWYBmVI0IrvQ"
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
|
||||
for it in r.json()["data"]["items"]:
|
||||
qsid = it["fields"].get("题目集合 ID", "")
|
||||
if qsid not in pic_map: continue
|
||||
rid = it["record_id"]
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"图片描述": pic_map[qsid]}}, timeout=15)
|
||||
code = r.json().get("code")
|
||||
print(f" {'✅' if code==0 else '❌'} {qsid}: 图片描述已写入")
|
||||
|
||||
# ====== Verify ======
|
||||
print(f"\n=== 验证 ===")
|
||||
# Spot-check one from each table
|
||||
for tid, tname, qsid, rid, _ in fixes_second[:3]: # first 3
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=10)
|
||||
jd = json.loads(r.json()["data"]["record"]["fields"]["jsonData"])
|
||||
second = jd.get("second", None)
|
||||
status = "✅ {}" if second == {} else f"❌ {json.dumps(second, ensure_ascii=False)[:50]}"
|
||||
print(f" [{tname}] {qsid}: second={status}")
|
||||
|
||||
# Verify pic
|
||||
for qsid in pic_map:
|
||||
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records?page_size=200",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=15)
|
||||
for it in r.json()["data"]["items"]:
|
||||
if it["fields"].get("题目集合 ID") == qsid:
|
||||
pic = it["fields"].get("图片描述", "")
|
||||
print(f" {qsid}: 图片描述={'✅' if pic else '❌空'}")
|
||||
break
|
||||
time.sleep(0.2)
|
||||
|
||||
print("\n全部完成")
|
||||
129
scripts/fix_writing_records.py
Normal file
129
scripts/fix_writing_records.py
Normal file
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fix 4 problematic writing records: 032701, 032901, 022101, 032801"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
TABLE = "tblszuk1TeToofBF"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
token = get_token()
|
||||
|
||||
# Fetch current records that need fixing
|
||||
targets = {
|
||||
"032701": "recvjzXkYnsQ8r",
|
||||
"032901": "recvjzXm5yEXBY",
|
||||
"022101": "recvjzbjJpJO0D",
|
||||
"032801": "recvjzXlxz4r3i",
|
||||
}
|
||||
|
||||
fixes = {}
|
||||
|
||||
for qsid, rid in targets.items():
|
||||
r = requests.get(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=10)
|
||||
jd_str = r.json()["data"]["record"]["fields"]["jsonData"]
|
||||
jd = json.loads(jd_str)
|
||||
fixes[qsid] = {"rid": rid, "jd": jd}
|
||||
time.sleep(0.2)
|
||||
|
||||
# ============= PATCH 032701 =============
|
||||
fixes["032701"]["jd"]["first"]["answerSet"] = [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
fixes["032701"]["jd"]["first"]["ability"] = [
|
||||
"短消息写作|邮件/便条",
|
||||
"衔接与连贯|连词使用",
|
||||
"描述性写作|人物与地点"
|
||||
]
|
||||
fixes["032701"]["jd"]["first"]["explanation"] = (
|
||||
"按描述邮件的逻辑:称呼→描述人物→外貌对比→地点氛围→澄清发现者→补充人名→补充地点→署名。"
|
||||
"考察They are/looks different from/a place that/it is not...who/someone named/too...to...等句型。"
|
||||
"C级体现:多句型切换和描述性词汇的运用,需理解人物描写→地点过渡→细节补充的自然衔接。"
|
||||
)
|
||||
|
||||
# ============= PATCH 032901 =============
|
||||
fixes["032901"]["jd"]["first"]["answerSet"] = [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
fixes["032901"]["jd"]["first"]["ability"] = [
|
||||
"短消息写作|邮件/便条",
|
||||
"衔接与连贯|连词使用",
|
||||
"描述性写作|场景与情绪"
|
||||
]
|
||||
fixes["032901"]["jd"]["first"]["explanation"] = (
|
||||
"按聚会描述的逻辑:称呼→妹妹的动态→毫不在意→妈妈的心情→自己的限制→爸爸的状态→大家的穿着→署名。"
|
||||
"考察loves to/doesn't care/will be so happy that/can't...because/seems in a...mood/is wearing等句型。"
|
||||
"C级体现:多人物平行描述和情感状态的切换,需要理解热闹场景下的视线焦点转移。"
|
||||
)
|
||||
|
||||
# ============= PATCH 022101 =============
|
||||
fixes["022101"]["jd"]["first"]["answerSet"] = [0, 1, 2, 3, 4, 5, 6]
|
||||
if "ability" not in fixes["022101"]["jd"]["first"] or not fixes["022101"]["jd"]["first"]["ability"]:
|
||||
fixes["022101"]["jd"]["first"]["ability"] = [
|
||||
"短消息写作|邮件/便条",
|
||||
"衔接与连贯|连词使用"
|
||||
]
|
||||
# Check if ability is ['句型组织'] (wrong for writing)
|
||||
if fixes["022101"]["jd"]["first"]["ability"] == ["句型组织"]:
|
||||
fixes["022101"]["jd"]["first"]["ability"] = [
|
||||
"短消息写作|邮件/便条",
|
||||
"衔接与连贯|连词使用"
|
||||
]
|
||||
|
||||
# ============= PATCH 032801 =============
|
||||
fixes["032801"]["jd"]["first"]["answerSet"] = [0, 1, 2, 3, 4, 5, 6]
|
||||
if fixes["032801"]["jd"]["first"]["ability"] == ["句型组织"]:
|
||||
fixes["032801"]["jd"]["first"]["ability"] = [
|
||||
"短消息写作|邮件/便条",
|
||||
"衔接与连贯|连词使用",
|
||||
"问题解决|求助与建议"
|
||||
]
|
||||
|
||||
# Write back all fixes
|
||||
for qsid in ["032701", "032901", "022101", "032801"]:
|
||||
data = fixes[qsid]
|
||||
rid = data["rid"]
|
||||
jd = data["jd"]
|
||||
new_jd_str = json.dumps(jd, ensure_ascii=False)
|
||||
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"jsonData": new_jd_str}}, timeout=15)
|
||||
code = r.json().get("code")
|
||||
if code == 0:
|
||||
print(f"[✅] {qsid} 修复成功")
|
||||
else:
|
||||
print(f"[❌] {qsid}: {r.json().get('msg')}")
|
||||
time.sleep(0.3)
|
||||
|
||||
# Verify
|
||||
print("\n=== 验证 ===")
|
||||
for qsid in ["032701", "032901", "022101", "032801"]:
|
||||
rid = targets[qsid]
|
||||
r = requests.get(
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=10)
|
||||
jd = json.loads(r.json()["data"]["record"]["fields"]["jsonData"])
|
||||
first = jd["first"]
|
||||
ans = first["answerSet"]
|
||||
ab = first["ability"]
|
||||
expl = first.get("explanation", "")
|
||||
opt = first.get("optionSetList", [])
|
||||
|
||||
issues = []
|
||||
if len(ans) != len(opt):
|
||||
issues.append(f"🔴 ans({len(ans)})≠opt({len(opt)})")
|
||||
if not ab:
|
||||
issues.append("🔴 ability为空")
|
||||
if len(expl) < 20:
|
||||
issues.append(f"🔴 expl过短({len(expl)}字)")
|
||||
|
||||
status = "✅" if not issues else " ".join(issues)
|
||||
print(f" {qsid}: {status} | ans={ans} | ab={ab}")
|
||||
time.sleep(0.2)
|
||||
|
||||
print("\n全部修复完成。")
|
||||
826
scripts/gen_batch3.py
Normal file
826
scripts/gen_batch3.py
Normal file
@ -0,0 +1,826 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate 10 new writing/speaking C-level records: 032501-032901"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
BASE = "https://open.feishu.cn/open-apis/bitable/v1"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def create(token, tid, fields):
|
||||
r = requests.post(f"{BASE}/apps/{APP_TOKEN}/tables/{tid}/records",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": fields}, timeout=15)
|
||||
return r.json()
|
||||
|
||||
# ============================================================
|
||||
# WRITING 032501 - Expressing doubt + encouragement
|
||||
# ============================================================
|
||||
W_032501 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "032501",
|
||||
"textDesc": "Your friend Ben is worried about the school concert and wants to give up. Write an email to encourage him and share your own feelings.<br>Put these sentences in order to make a kind and encouraging email.",
|
||||
"optionSetList": [
|
||||
"Dear Ben,",
|
||||
"I don't believe you should give up so quickly.",
|
||||
"I feel a bit nervous about the school concert too.",
|
||||
"It sounds like you have practised a lot already.",
|
||||
"I am not very good at playing the piano either, but I still try every day.",
|
||||
"Yours truly, Sam"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用", "情感表达|鼓励与共情"],
|
||||
"explanation": "按鼓励邮件的逻辑:称呼→表达不认同→分享同感建立共情→肯定对方努力→自谦示范坚持→署名。考察I don't believe/I feel a bit/It sounds like/I am not very good at等句型的组织,以及鼓励信的情感递进逻辑。C级难度体现在需理解共情-肯定-示范三层递进。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_032501_T1 = """【题目描述】
|
||||
Your friend Ben is worried about the school concert and wants to give up. Write an email to encourage him and share your own feelings.
|
||||
Put these sentences in order to make a kind and encouraging email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Ben,
|
||||
B. I don't believe you should give up so quickly.
|
||||
C. I feel a bit nervous about the school concert too.
|
||||
D. It sounds like you have practised a lot already.
|
||||
E. I am not very good at playing the piano either, but I still try every day.
|
||||
F. Yours truly, Sam"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING-P1 032501 - Changes & perspectives
|
||||
# ============================================================
|
||||
S1_032501 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "however,sooner,later,depending,used to,change,mind,weather,plan,hobby,habit,past",
|
||||
"questionSetID": "032501",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 However、sooner or later、Depending on、used to 等连接结构。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Tell us about a time you changed your mind about something important. What made you change?",
|
||||
"ability": ["表达转变", "经历描述"],
|
||||
"explanation": "用 'I used to think that... However, I changed my mind when...' 的结构来描述。例如 'I used to think maths was boring. However, after our class built a model bridge, I changed my mind because I saw how useful maths can be.'"
|
||||
},
|
||||
{
|
||||
"content": "What is something that you believe will happen sooner or later? Why do you think so?",
|
||||
"ability": ["表达预测", "表达观点"],
|
||||
"explanation": "用 'I believe that... sooner or later.' 开头表达你的预测,并解释原因。例如 'I believe people will stop using plastic bags sooner or later, because we are all learning how much it hurts the ocean animals.'"
|
||||
},
|
||||
{
|
||||
"content": "How do your weekend plans change depending on the weather?",
|
||||
"ability": ["条件表达", "经历描述"],
|
||||
"explanation": "用 'Depending on...' 来描述天气如何影响你的计划。例如 'Depending on the weather, I either go cycling in the park or stay home and read a book. If it rains, I sometimes bake cookies with my mum.'"
|
||||
},
|
||||
{
|
||||
"content": "What is something you or your friends used to do but no longer do? Why did you stop?",
|
||||
"ability": ["过去对比", "经历描述"],
|
||||
"explanation": "用 'They used to...' 描述过去的习惯,并解释为什么改变了。例如 'We used to play in the sandpit every day after school, but we are too old for it now. Instead, we play football on the field.'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "however,sooner,later,depending,used to,opinion,technology,environment,future,childhood,memory",
|
||||
"questionSetID": "032501",
|
||||
"textDesc": "请回答以下问题。继续尝试使用 However、sooner or later、Depending on、used to 等表达方式。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What opinion did you once hold that later turned out to be wrong?",
|
||||
"ability": ["表达转变", "经历描述"],
|
||||
"explanation": "用 'I used to believe that... However,...' 分享一次错误的看法及如何被纠正的经历。"
|
||||
},
|
||||
{
|
||||
"content": "What technology do you think will change our lives sooner or later?",
|
||||
"ability": ["表达预测", "表达观点"],
|
||||
"explanation": "用 'I think that... sooner or later.' 来预测某项技术的影响。例如人工智能、太空旅行或环保科技。"
|
||||
},
|
||||
{
|
||||
"content": "How do your food choices change depending on the season?",
|
||||
"ability": ["条件表达", "经历描述"],
|
||||
"explanation": "描述你的饮食如何随季节变化。例如 'Depending on the season, I enjoy different fruits. In summer I love watermelons, but in winter I prefer hot soup.'"
|
||||
},
|
||||
{
|
||||
"content": "What did your parents tell you they used to do when they were your age?",
|
||||
"ability": ["过去对比", "经历描述"],
|
||||
"explanation": "分享你父母小时候的故事。例如 'My dad said he used to walk two kilometres to school every morning, but I only need five minutes.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_032501_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 However、sooner or later、Depending on、used to 等连接结构。
|
||||
|
||||
【热词】
|
||||
however,sooner,later,depending,used,change,mind,weather,plan,hobby,habit
|
||||
|
||||
【题目】
|
||||
1. Tell us about a time you changed your mind about something important. What made you change?
|
||||
- 解析:用 'I used to think that... However, I changed my mind when...' 的结构来描述。
|
||||
|
||||
2. What is something that you believe will happen sooner or later? Why do you think so?
|
||||
- 解析:用 'I believe that... sooner or later.' 开头表达你的预测,并解释原因。
|
||||
|
||||
3. How do your weekend plans change depending on the weather?
|
||||
- 解析:用 'Depending on...' 来描述天气如何影响你的计划。
|
||||
|
||||
4. What is something you or your friends used to do but no longer do? Why did you stop?
|
||||
- 解析:用 'They used to...' 描述过去的习惯,并解释为什么改变了。"""
|
||||
S1_032501_T2 = """【题目描述】
|
||||
请回答以下问题。继续尝试使用 However、sooner or later、Depending on、used to 等表达方式。
|
||||
|
||||
【热词】
|
||||
however,sooner,later,depending,used,opinion,technology,future,childhood,memory
|
||||
|
||||
【题目】
|
||||
1. What opinion did you once hold that later turned out to be wrong?
|
||||
- 解析:用 'I used to believe that... However,...' 分享一次错误的看法及如何被纠正的经历。
|
||||
|
||||
2. What technology do you think will change our lives sooner or later?
|
||||
- 解析:用 'I think that... sooner or later.' 来预测某项技术的影响。
|
||||
|
||||
3. How do your food choices change depending on the season?
|
||||
- 解析:描述你的饮食如何随季节变化。
|
||||
|
||||
4. What did your parents tell you they used to do when they were your age?
|
||||
- 解析:分享你父母小时候的故事。"""
|
||||
|
||||
# ============================================================
|
||||
# WRITING 032601 - Expressing emotions & requests
|
||||
# ============================================================
|
||||
W_032601 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "032601",
|
||||
"textDesc": "You just came back from a wonderful school trip to the science museum. Write a thank-you email to your teacher, Mr. Brown.<br>Put these sentences in order to make a polite and expressive email.",
|
||||
"optionSetList": [
|
||||
"Dear Mr. Brown,",
|
||||
"I'd like to thank you for the wonderful trip to the science museum.",
|
||||
"What a fantastic experience it was!",
|
||||
"The planet show was so amazing that I couldn't stop talking about it.",
|
||||
"Excuse me, could you please send us the photos you took?",
|
||||
"Warm regards, Lucy"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用", "情感表达|感谢与赞美"],
|
||||
"explanation": "按感谢信的逻辑:称呼→表达感谢→感叹赞美→具体描述→礼貌请求→署名。考察I'd like to/What a...!/so...that.../Excuse me,...?等感叹与礼貌请求句型。C级难度体现在感叹句和程度状语从句的运用。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_032601_T1 = """【题目描述】
|
||||
You just came back from a wonderful school trip to the science museum. Write a thank-you email to your teacher, Mr. Brown.
|
||||
Put these sentences in order to make a polite and expressive email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Mr. Brown,
|
||||
B. I'd like to thank you for the wonderful trip to the science museum.
|
||||
C. What a fantastic experience it was!
|
||||
D. The planet show was so amazing that I couldn't stop talking about it.
|
||||
E. Excuse me, could you please send us the photos you took?
|
||||
F. Warm regards, Lucy"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING-P2 032601 - Future dreams
|
||||
# ============================================================
|
||||
S2_032601 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "someday,dream,future,career,goal,choice,astronaut,teacher,doctor,artist,important,family,friends,study",
|
||||
"questionSetID": "032601",
|
||||
"textDesc": "Here are some pictures about dreams and future plans. What do you think about these situations?",
|
||||
"imageDesc": "Four images show children thinking about and planning for the future: 1st: A child stands by the window looking at the starry night sky, with a dreamy expression. 2nd: A child looks at scattered art supplies and books on a desk with a confused expression. 3rd: Children hold up posters of their future career dreams in the classroom. 4th: A teacher writes the word 'Dream' on the blackboard while students raise their hands eagerly.",
|
||||
"textImage": "032601-00.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What profession do you dream of doing someday? Why?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "'I will become a doctor someday because I want to help sick people get better.' 或者用 'I don't know what to choose yet, but I would like to do something creative.' 来表达你目前的梦想或困惑。"
|
||||
},
|
||||
{
|
||||
"content": "Have you ever not known what to choose or decide? Tell us about it.",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'I don't know what to do when it's time to choose between art class and music class. Both sound fun!' 描述一次你在选择上犹豫的经历。"
|
||||
},
|
||||
{
|
||||
"content": "What kind of life would you like to have when you grow up?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "'I would like to live near the sea and have a small garden where I can grow flowers.' 描绘你理想中长大后的生活图景。"
|
||||
},
|
||||
{
|
||||
"content": "What do you think is important to achieve your dreams?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "'Hard work is important to achieve any dream. You also need to believe in yourself and never give up, even when things get difficult.' 分享你认为实现梦想所需的重要品质。"
|
||||
},
|
||||
{
|
||||
"content": "Has anyone ever told you something that changed how you think about your future?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享一个影响你未来想法的人或话。例如 'My grandpa once told me that it doesn't matter what job you do, as long as you do it with all your heart.'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "someday,dream,future,career,goal,choice,study,hard,work,believe,important,happy,help",
|
||||
"questionSetID": "032601",
|
||||
"textDesc": "Now look at these pictures again. Think more deeply about what your dreams mean to you and the people around you.",
|
||||
"imageDesc": "Same images as above: children thinking about and planning for the future.",
|
||||
"textImage": "032601-01.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What will you do someday to make your parents proud?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "'I will study hard someday and go to a good university. I know that would make my parents very proud.' 分享你打算如何让家人骄傲。"
|
||||
},
|
||||
{
|
||||
"content": "What do you still not know about your future that makes you curious?",
|
||||
"ability": ["句型组织", "表达困惑"],
|
||||
"explanation": "'I don't know what country I will live in or what kind of friends I will have, and that makes me very curious about the future.' 分享你对未来的不确定性。"
|
||||
},
|
||||
{
|
||||
"content": "What skill would you like to learn before you become an adult?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "'I would like to learn how to play the guitar and how to speak another language before I turn eighteen.' 说说你想在成年之前掌握的技能。"
|
||||
},
|
||||
{
|
||||
"content": "Why is it important to have both big dreams and small goals?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "'Big dreams give us direction, but small goals help us move step by step. Having a big dream is important to stay excited, while small goals show us that we are making progress.'"
|
||||
},
|
||||
{
|
||||
"content": "What advice would you give to a friend who has lost hope in their dream?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "给朋友一些鼓励。例如 'I would tell my friend not to give up. Every successful person failed many times. If you keep trying and learning, your dream will come true someday.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S2_032601_T1 = """【题目描述】
|
||||
Here are some pictures about dreams and future plans. What do you think about these situations?
|
||||
|
||||
【热词】
|
||||
someday,dream,future,career,goal,choice,astronaut,teacher,doctor,artist,important
|
||||
|
||||
【图片描述】
|
||||
Four images show children thinking about and planning for the future: 1st: A child stands by the window looking at the starry night sky, with a dreamy expression. 2nd: A child looks at scattered art supplies and books on a desk with a confused expression. 3rd: Children hold up posters of their future career dreams in the classroom. 4th: A teacher writes the word 'Dream' on the blackboard while students raise their hands eagerly.
|
||||
|
||||
【题目】
|
||||
1. What profession do you dream of doing someday? Why?
|
||||
- 解析:'I will become a doctor someday because I want to help sick people get better.' 用 'I will... someday.' 表达你的职业梦想。
|
||||
|
||||
2. Have you ever not known what to choose or decide? Tell us about it.
|
||||
- 解析:'I don't know what to do when it's time to choose between art class and music class.' 描述一次选择困难的经历。
|
||||
|
||||
3. What kind of life would you like to have when you grow up?
|
||||
- 解析:'I would like to live near the sea and have a small garden where I can grow flowers.' 描绘理想生活。
|
||||
|
||||
4. What do you think is important to achieve your dreams?
|
||||
- 解析:'Hard work is important to achieve any dream. You also need to believe in yourself.' 分享实现梦想所需品质。
|
||||
|
||||
5. Has anyone ever told you something that changed how you think about your future?
|
||||
- 解析:分享一个影响你未来想法的人或话。"""
|
||||
S2_032601_T2 = """【题目描述】
|
||||
Now look at these pictures again. Think more deeply about what your dreams mean to you and the people around you.
|
||||
|
||||
【热词】
|
||||
someday,dream,future,career,goal,choice,study,hard,work,believe,important,happy
|
||||
|
||||
【图片描述】
|
||||
Same images as above: children thinking about and planning for the future.
|
||||
|
||||
【题目】
|
||||
1. What will you do someday to make your parents proud?
|
||||
- 解析:'I will study hard someday and go to a good university.' 分享你打算如何让家人骄傲。
|
||||
|
||||
2. What do you still not know about your future that makes you curious?
|
||||
- 解析:'I don't know what country I will live in or what kind of friends I will have.' 分享对未来的好奇。
|
||||
|
||||
3. What skill would you like to learn before you become an adult?
|
||||
- 解析:'I would like to learn how to play the guitar and how to speak another language.' 说说你想学会的技能。
|
||||
|
||||
4. Why is it important to have both big dreams and small goals?
|
||||
- 解析:解释远大梦想和短期目标各自的重要性。
|
||||
|
||||
5. What advice would you give to a friend who has lost hope in their dream?
|
||||
- 解析:给朋友一些鼓励坚持下去的建议。"""
|
||||
S2_032601_PIC = '[1-组图]:{"prompt_2":"黑白线条图:一个孩子站在窗边仰望星空,脸上带着憧憬的神情,窗外可见月亮和几颗星星","prompt_3":"黑白线条图:一个孩子坐在桌前,桌上散落着画纸和书本,表情困惑而迷茫","prompt_4":"黑白线条图:教室内孩子们举着自己画的未来职业海报,有宇航员、医生、老师等","prompt_5":"黑白线条图:一位老师在黑板上写着梦想两个字,学生们纷纷举手想要分享"}'
|
||||
|
||||
# ============================================================
|
||||
# WRITING 032701 - Describing people & places
|
||||
# ============================================================
|
||||
W_032701 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "032701",
|
||||
"textDesc": "You visited a wonderful little café that your cousin found. Write an email to your friend Anna to describe the place, the people you met, and your experience.<br>Put these sentences in order to make a descriptive email.",
|
||||
"optionSetList": [
|
||||
"Dear Anna,",
|
||||
"They are friendly, kind and always ready to help every customer.",
|
||||
"She looks different from the photo she sent me last year.",
|
||||
"This is a place that makes everyone feel at home.",
|
||||
"It is not me who found this wonderful café — my cousin did.",
|
||||
"Someone named Lily showed us around the old library nearby.",
|
||||
"The hill near the café is too steep to climb without proper shoes.",
|
||||
"Kind regards, Emma"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用", "描述性写作|人物与地点"],
|
||||
"explanation": "按描述邮件的逻辑:称呼→描述人物→外貌对比→地点氛围→澄清发现者→补充人名→补充地点→署名。考察They are/looks different from/a place that/it is not...who/someone named/too...to...等多种句型。C级体现在多句型切换和描述性词汇的运用。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_032701_T1 = """【题目描述】
|
||||
You visited a wonderful little café that your cousin found. Write an email to your friend Anna to describe the place, the people you met, and your experience.
|
||||
Put these sentences in order to make a descriptive email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Anna,
|
||||
B. They are friendly, kind and always ready to help every customer.
|
||||
C. She looks different from the photo she sent me last year.
|
||||
D. This is a place that makes everyone feel at home.
|
||||
E. It is not me who found this wonderful café — my cousin did.
|
||||
F. Someone named Lily showed us around the old library nearby.
|
||||
G. The hill near the café is too steep to climb without proper shoes.
|
||||
H. Kind regards, Emma"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING-P1 032701 - Curiosity & changing minds
|
||||
# ============================================================
|
||||
S1_032701 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "couldn't,find,lost,search,understand,explain,curious,about,maybe,see,if,change,mind,now",
|
||||
"questionSetID": "032701",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 couldn't find、I understand that、curious about、Maybe we can... to see if、changing my mind 等表达。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Tell us about a time you couldn't find something important. How did you feel and what did you do?",
|
||||
"ability": ["经历描述", "情感表达"],
|
||||
"explanation": "'I couldn't find my homework on the morning it was due. I felt so worried! I searched everywhere and finally found it under my bed.' 分享一次找不到东西的经历及你的感受。"
|
||||
},
|
||||
{
|
||||
"content": "When someone gives you an explanation for something, how do you show that you understand?",
|
||||
"ability": ["回应表达", "表达理解"],
|
||||
"explanation": "'I understand that it takes time to learn a new skill. Thank you for explaining it so clearly.' 展示你如何礼貌地回应他人的解释。"
|
||||
},
|
||||
{
|
||||
"content": "What is something you are really curious about right now? Why?",
|
||||
"ability": ["表达好奇", "表达观点"],
|
||||
"explanation": "'I'm curious about how birds know where to fly in winter. It seems like a miracle that they can travel so far and always find their way.' 分享一个让你好奇的事物。"
|
||||
},
|
||||
{
|
||||
"content": "Have you ever tried an experiment or test to see if something would work? What happened?",
|
||||
"ability": ["经历描述", "因果表达"],
|
||||
"explanation": "'Maybe we can put the plant in a dark cupboard to see if it still grows without sunlight. We tried it and after three days, the leaves turned yellow.' 分享一次测试或实验经历。"
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time you changed your mind about something. What made you change?",
|
||||
"ability": ["表达转变", "经历描述"],
|
||||
"explanation": "'I'm now changing my mind about spicy food. I used to hate it, but after trying my mum's mild curry last week, I discovered it can be really delicious.' 描述一次想法转变。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "lost,search,understand,explain,curious,test,try,change,mind,grow,learn,wonder",
|
||||
"questionSetID": "032701",
|
||||
"textDesc": "请回答以下问题。继续使用本课的核心句型表达你的想法和经历。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What would you do if you couldn't find your way in a new place?",
|
||||
"ability": ["经历描述", "解决问题"],
|
||||
"explanation": "描述在陌生地方迷路时的应对方式。例如 'I couldn't find my way back to the hotel, so I asked a shopkeeper to help me.'"
|
||||
},
|
||||
{
|
||||
"content": "How do you feel when someone explains something you already know?",
|
||||
"ability": ["回应表达", "表达理解"],
|
||||
"explanation": "分享被重复解释时的感受及如何得体回应。例如 'I understand that you want to help, but I already learned this last term.'"
|
||||
},
|
||||
{
|
||||
"content": "What subject at school makes you the most curious? What do you want to learn more about?",
|
||||
"ability": ["表达好奇", "表达观点"],
|
||||
"explanation": "说说让你最好奇的科目。例如 'I'm curious about history because I want to know how people lived hundreds of years ago.'"
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time you changed your daily routine. What was different and why?",
|
||||
"ability": ["表达转变", "经历描述"],
|
||||
"explanation": "'I'm now changing my mind about waking up late. Last month I started getting up at six to read before school, and I feel so much better.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_032701_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 couldn't find、I understand that、curious about、Maybe we can... to see if、changing my mind 等表达。
|
||||
|
||||
【热词】
|
||||
couldn't,find,lost,search,understand,curious,about,maybe,see,if,change,mind
|
||||
|
||||
【题目】
|
||||
1. Tell us about a time you couldn't find something important. How did you feel and what did you do?
|
||||
- 解析:'I couldn't find my homework on the morning it was due. I felt so worried!' 分享一次找不到东西的经历。
|
||||
|
||||
2. When someone gives you an explanation for something, how do you show that you understand?
|
||||
- 解析:'I understand that it takes time to learn a new skill.' 展示你如何礼貌地回应解释。
|
||||
|
||||
3. What is something you are really curious about right now? Why?
|
||||
- 解析:'I'm curious about how birds know where to fly in winter.' 分享让你好奇的事物。
|
||||
|
||||
4. Have you ever tried an experiment or test to see if something would work? What happened?
|
||||
- 解析:'Maybe we can put the plant in a dark cupboard to see if it still grows.' 分享测试经历。
|
||||
|
||||
5. Tell us about a time you changed your mind about something. What made you change?
|
||||
- 解析:'I'm now changing my mind about spicy food. I used to hate it, but...' 描述想法转变。"""
|
||||
S1_032701_T2 = """【题目描述】
|
||||
请回答以下问题。继续使用本课的核心句型表达你的想法和经历。
|
||||
|
||||
【热词】
|
||||
lost,search,understand,explain,curious,test,try,change,mind,grow,learn
|
||||
|
||||
【题目】
|
||||
1. What would you do if you couldn't find your way in a new place?
|
||||
- 解析:描述在陌生地方迷路时的应对方式。
|
||||
|
||||
2. How do you feel when someone explains something you already know?
|
||||
- 解析:分享被重复解释时的感受及如何得体回应。
|
||||
|
||||
3. What subject at school makes you the most curious? What do you want to learn more about?
|
||||
- 解析:说说让你最好奇的科目及原因。
|
||||
|
||||
4. Tell us about a time you changed your daily routine. What was different and why?
|
||||
- 解析:分享一次改变日常习惯的经历和感受。"""
|
||||
|
||||
# ============================================================
|
||||
# WRITING 032801 - Problem-solving & asking for help
|
||||
# ============================================================
|
||||
W_032801 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "032801",
|
||||
"textDesc": "Your group's science project has suddenly stopped working and you need the teacher's help. Write an email to Miss Green explaining the problem and asking for advice.<br>Put these sentences in order to make a clear problem-solving email.",
|
||||
"optionSetList": [
|
||||
"Dear Miss Green,",
|
||||
"We need help because our science project has suddenly stopped working.",
|
||||
"What are we going to do now without the main part?",
|
||||
"Maybe we can borrow some tools from the art room to fix it.",
|
||||
"I've had this old robot kit since my last birthday, but I've never opened it before.",
|
||||
"It is a great idea that we thought of at the very last minute.",
|
||||
"Gratefully, Tom"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用", "问题解决|求助与建议"],
|
||||
"explanation": "按求助邮件的逻辑:称呼→陈述问题→表达困惑→提出初步方案→提供备选资源→补充背景→署名。考察We need help because/What are we going to/Maybe we can/I've had... since.../It is a...idea that...等句型。C级体现在问题诊断-方案提议-资源调用的多层次思维组织。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_032801_T1 = """【题目描述】
|
||||
Your group's science project has suddenly stopped working and you need the teacher's help. Write an email to Miss Green explaining the problem and asking for advice.
|
||||
Put these sentences in order to make a clear problem-solving email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Miss Green,
|
||||
B. We need help because our science project has suddenly stopped working.
|
||||
C. What are we going to do now without the main part?
|
||||
D. Maybe we can borrow some tools from the art room to fix it.
|
||||
E. I've had this old robot kit since my last birthday, but I've never opened it before.
|
||||
F. It is a great idea that we thought of at the very last minute.
|
||||
G. Gratefully, Tom"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING-P2 032801 - Challenges & habits
|
||||
# ============================================================
|
||||
S2_032801 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "too,much,stop,started,right,after,spent,a lot,time,homework,game,test,challenge,habit",
|
||||
"questionSetID": "032801",
|
||||
"textDesc": "Here are some pictures about challenges and habits. What do you think about these situations?",
|
||||
"imageDesc": "Four images show children dealing with challenges and daily habits: 1st: A child sits at a desk piled with books and homework, looking anxious. 2nd: A child plays video games while the clock shows it is very late at night. 3rd: A child holds a test paper with a failing mark, wiping tears from the eyes. 4th: A group of children sit together in the library discussing a study plan.",
|
||||
"textImage": "032801-00.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Have you ever felt that your homework was just too much? What did you do?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'This is too much homework for one night!' 描述一次你觉得任务太多的时候,以及你是怎么处理的。例如 'I felt stressed, so I made a list and finished the hardest subjects first.'"
|
||||
},
|
||||
{
|
||||
"content": "Have you ever done something that you just couldn't stop doing? What was it?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'Last weekend, I started reading a mystery book and I just couldn't stop until I finished it at midnight.' 分享一次你停不下来的经历。"
|
||||
},
|
||||
{
|
||||
"content": "When did a difficult situation start for you? What happened right after?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'It started right after I joined the advanced maths class. Everything became harder so quickly.' 描述困难开始的时刻及之后发生的事。"
|
||||
},
|
||||
{
|
||||
"content": "What have you and your friends spent a lot of time doing together? Was it worth it?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'We've spent a lot of time practising for the school play. It was tiring but completely worth it when we saw the audience clapping.' 分享投入大量时间的经历及收获。"
|
||||
},
|
||||
{
|
||||
"content": "What do you do when you find a problem too difficult to solve alone?",
|
||||
"ability": ["句型组织", "解决问题"],
|
||||
"explanation": "分享面对困难时的策略。例如 'When a problem is too difficult, I first try to break it into smaller parts. If I still can't do it, I ask my older sister or my teacher for help.'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "too,much,stop,started,after,spent,time,change,habit,plan,help,future,improve",
|
||||
"questionSetID": "032801",
|
||||
"textDesc": "Now look at these pictures again. Think about how to change bad habits and build better ones.",
|
||||
"imageDesc": "Same images as above: children dealing with challenges and daily habits.",
|
||||
"textImage": "032801-01.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What bad habit do you wish you could stop doing? Why?",
|
||||
"ability": ["句型组织", "表达反思"],
|
||||
"explanation": "'I just couldn't stop checking my phone before bed. It made me sleep very late and feel tired the next morning.'"
|
||||
},
|
||||
{
|
||||
"content": "What good habit did you start right after learning something new?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'It started right after our health class. I began drinking more water every day instead of juice.'"
|
||||
},
|
||||
{
|
||||
"content": "What is something you've spent a lot of time learning? Are you proud of it?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'We've spent a lot of time learning to play the guitar as a band. We are not perfect yet, but we are getting better.'"
|
||||
},
|
||||
{
|
||||
"content": "How do you feel when there is too much pressure from school or family?",
|
||||
"ability": ["句型组织", "情感表达"],
|
||||
"explanation": "分享面对压力时的感受和应对方式。例如 'When there is too much pressure, I talk to my mum about it and she always helps me feel calmer.'"
|
||||
},
|
||||
{
|
||||
"content": "What advice would you give to a younger student about managing time?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "给学弟学妹一些时间管理建议。例如 'Don't do all your homework at the last minute. Spend a little time each day, and you will feel much less stressed.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S2_032801_T1 = """【题目描述】
|
||||
Here are some pictures about challenges and habits. What do you think about these situations?
|
||||
|
||||
【热词】
|
||||
too,much,stop,started,right,after,spent,lot,time,homework,game,test,challenge
|
||||
|
||||
【图片描述】
|
||||
Four images show children dealing with challenges and daily habits: 1st: A child sits at a desk piled with books and homework, looking anxious. 2nd: A child plays video games while the clock shows it is very late at night. 3rd: A child holds a test paper with a failing mark, wiping tears from the eyes. 4th: A group of children sit together in the library discussing a study plan.
|
||||
|
||||
【题目】
|
||||
1. Have you ever felt that your homework was just too much? What did you do?
|
||||
- 解析:'This is too much homework for one night!' 描述一次你觉得任务太多的时候及应对方式。
|
||||
|
||||
2. Have you ever done something that you just couldn't stop doing? What was it?
|
||||
- 解析:分享一次你停不下来的经历。
|
||||
|
||||
3. When did a difficult situation start for you? What happened right after?
|
||||
- 解析:'It started right after I joined the advanced maths class.' 描述困难开始的时刻。
|
||||
|
||||
4. What have you and your friends spent a lot of time doing together? Was it worth it?
|
||||
- 解析:'We've spent a lot of time practising for the school play.' 分享投入大量时间的经历。
|
||||
|
||||
5. What do you do when you find a problem too difficult to solve alone?
|
||||
- 解析:分享面对困难时的策略。"""
|
||||
S2_032801_T2 = """【题目描述】
|
||||
Now look at these pictures again. Think about how to change bad habits and build better ones.
|
||||
|
||||
【热词】
|
||||
too,much,stop,started,after,spent,time,change,habit,plan,help,future
|
||||
|
||||
【图片描述】
|
||||
Same images as above: children dealing with challenges and daily habits.
|
||||
|
||||
【题目】
|
||||
1. What bad habit do you wish you could stop doing? Why?
|
||||
- 解析:分享你想改变的一个坏习惯。
|
||||
|
||||
2. What good habit did you start right after learning something new?
|
||||
- 解析:'It started right after our health class. I began drinking more water.'
|
||||
|
||||
3. What is something you've spent a lot of time learning? Are you proud of it?
|
||||
- 解析:分享你花了很多时间学习的事情。
|
||||
|
||||
4. How do you feel when there is too much pressure from school or family?
|
||||
- 解析:分享面对压力时的感受和应对方式。
|
||||
|
||||
5. What advice would you give to a younger student about managing time?
|
||||
- 解析:给学弟学妹一些时间管理建议。"""
|
||||
S2_032801_PIC = '[1-组图]:{"prompt_2":"黑白线条图:一个孩子坐在堆满书本和作业的桌前,双手抱头表情焦虑","prompt_3":"黑白线条图:一个孩子坐在沙发上拿着游戏机玩,墙上的时钟指向深夜十一点","prompt_4":"黑白线条图:一个孩子拿着不及格的试卷,脸上挂着泪水,表情沮丧","prompt_5":"黑白线条图:一组孩子围坐在图书馆的桌旁一起讨论学习计划"}'
|
||||
|
||||
# ============================================================
|
||||
# WRITING 032901 - Celebration & emotions
|
||||
# ============================================================
|
||||
W_032901 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "032901",
|
||||
"textDesc": "You are at your mum's birthday party and having a wonderful time. Write an email to your friend Sophie to describe the party, the people, and the happy mood.<br>Put these sentences in order to make a warm and descriptive email.",
|
||||
"optionSetList": [
|
||||
"Dear Sophie,",
|
||||
"My little sister loves to dance whenever music starts playing.",
|
||||
"She doesn't care if anyone is watching her spin around.",
|
||||
"Mum will be so happy that everyone she loves came to her party.",
|
||||
"I can't stay out too late because I have a maths test tomorrow morning.",
|
||||
"Dad seems in a wonderful mood tonight.",
|
||||
"Everyone is wearing their best party clothes.",
|
||||
"With love, Jessica"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用", "描述性写作|场景与情绪"],
|
||||
"explanation": "按聚会描述的逻辑:称呼→妹妹的动态→不care→妈妈的心情→自己的限制→爸爸的状态→大家穿着→署名。考察loves to/doesn't care/will be so happy that/can't...because/seems in a...mood/is wearing等句型。C级体现在多人物平行描述和情感状态的切换。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_032901_T1 = """【题目描述】
|
||||
You are at your mum's birthday party and having a wonderful time. Write an email to your friend Sophie to describe the party, the people, and the happy mood.
|
||||
Put these sentences in order to make a warm and descriptive email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Sophie,
|
||||
B. My little sister loves to dance whenever music starts playing.
|
||||
C. She doesn't care if anyone is watching her spin around.
|
||||
D. Mum will be so happy that everyone she loves came to her party.
|
||||
E. I can't stay out too late because I have a maths test tomorrow morning.
|
||||
F. Dad seems in a wonderful mood tonight.
|
||||
G. Everyone is wearing their best party clothes.
|
||||
H. With love, Jessica"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING-P1 032901 - Teamwork & communication
|
||||
# ============================================================
|
||||
S1_032901 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "let's,suggest,activity,hope,can,achieve,talk,to,solve,problem,use,method,tool,team",
|
||||
"questionSetID": "032901",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 Let's、We hope that...can...、try to talk to、can use 等表达。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "How do you suggest a fun activity to your friends? What do you say?",
|
||||
"ability": ["表达建议", "邀请表达"],
|
||||
"explanation": "'Let's go to the park after school and fly our kites!' 展示你如何邀请朋友一起做有趣的事。也可以用 'Why don't we...' 或 'How about...' 来使邀请更加自然。"
|
||||
},
|
||||
{
|
||||
"content": "What do you hope your class or team can achieve together this year?",
|
||||
"ability": ["表达期望", "表达观点"],
|
||||
"explanation": "'We hope that our class can win the school sports day this year. We have been practising every morning and getting stronger together.' 分享你对班级或团队的期望。"
|
||||
},
|
||||
{
|
||||
"content": "When there is a problem in your group, how do you try to talk to your classmates about it?",
|
||||
"ability": ["协商表达", "解决问题"],
|
||||
"explanation": "'We try to talk to each other calmly and listen to everyone's ideas before making a decision.' 描述你们如何通过沟通解决问题。"
|
||||
},
|
||||
{
|
||||
"content": "What tools or methods can you use to work better as a team?",
|
||||
"ability": ["表达建议", "表达观点"],
|
||||
"explanation": "'We can use a shared calendar to plan our tasks and set clear deadlines. We can also use group chats to stay in touch after school.' 分享提高团队效率的工具或方法。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "let's,organise,event,hope,can,improve,talk,solve,disagreement,use,technology,share,ideas",
|
||||
"questionSetID": "032901",
|
||||
"textDesc": "请回答以下问题。继续使用本课的核心句型,分享更多关于合作与交流的想法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Let's say you are organising a class party. What would you suggest doing first?",
|
||||
"ability": ["表达建议", "计划描述"],
|
||||
"explanation": "'Let's first make a list of everything we need, then divide the tasks among everyone.' 描述你组织活动的第一步。"
|
||||
},
|
||||
{
|
||||
"content": "What do you hope that the students in your school can do to help the environment?",
|
||||
"ability": ["表达期望", "表达观点"],
|
||||
"explanation": "'We hope that every student can bring a reusable water bottle and stop buying plastic ones. Small changes can make a big difference.'"
|
||||
},
|
||||
{
|
||||
"content": "Have you ever had to try to talk to someone about a disagreement? How did it go?",
|
||||
"ability": ["协商表达", "经历描述"],
|
||||
"explanation": "分享一次解决分歧的沟通经历。例如 'We try to talk to each other after the argument. I said how I felt, and my friend said how she felt, and then we understood each other better.'"
|
||||
},
|
||||
{
|
||||
"content": "What online tools can you use to study together with classmates outside of school?",
|
||||
"ability": ["表达建议", "表达观点"],
|
||||
"explanation": "'We can use shared documents to work on the same project at the same time, even when we are at our own homes.' 分享线上协作学习的工具和方法。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_032901_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,尝试使用 Let's、We hope that...can...、try to talk to、can use 等表达。
|
||||
|
||||
【热词】
|
||||
let's,suggest,activity,hope,achieve,talk,solve,problem,use,method,tool,team
|
||||
|
||||
【题目】
|
||||
1. How do you suggest a fun activity to your friends? What do you say?
|
||||
- 解析:'Let's go to the park after school and fly our kites!' 展示你如何邀请朋友一起做有趣的事。
|
||||
|
||||
2. What do you hope your class or team can achieve together this year?
|
||||
- 解析:'We hope that our class can win the school sports day this year.' 分享对班级的期望。
|
||||
|
||||
3. When there is a problem in your group, how do you try to talk to your classmates about it?
|
||||
- 解析:'We try to talk to each other calmly and listen to everyone's ideas.' 描述通过沟通解决问题。
|
||||
|
||||
4. What tools or methods can you use to work better as a team?
|
||||
- 解析:'We can use a shared calendar to plan our tasks.' 分享提高团队效率的方法。"""
|
||||
S1_032901_T2 = """【题目描述】
|
||||
请回答以下问题。继续使用本课的核心句型,分享更多关于合作与交流的想法。
|
||||
|
||||
【热词】
|
||||
let's,organise,event,hope,improve,talk,solve,disagreement,use,technology,share,ideas
|
||||
|
||||
【题目】
|
||||
1. Let's say you are organising a class party. What would you suggest doing first?
|
||||
- 解析:'Let's first make a list of everything we need, then divide the tasks.' 描述组织活动。
|
||||
|
||||
2. What do you hope that the students in your school can do to help the environment?
|
||||
- 解析:'We hope that every student can bring a reusable water bottle.' 分享环保期望。
|
||||
|
||||
3. Have you ever had to try to talk to someone about a disagreement? How did it go?
|
||||
- 解析:分享一次解决分歧的沟通经历。
|
||||
|
||||
4. What online tools can you use to study together with classmates outside of school?
|
||||
- 解析:分享线上协作学习的工具和方法。"""
|
||||
|
||||
# ============================================================
|
||||
# MAIN: Create all 10 records
|
||||
# ============================================================
|
||||
def main():
|
||||
token = get_token()
|
||||
print("Token OK\n")
|
||||
|
||||
records = [
|
||||
# (label, table, QSID, jsonData, 题目1, 题目2, 图片描述, kw1, kw2)
|
||||
# Writing records
|
||||
("写作 032501", "tblszuk1TeToofBF", "032501", W_032501, W_032501_T1, "", "", "", ""),
|
||||
("写作 032601", "tblszuk1TeToofBF", "032601", W_032601, W_032601_T1, "", "", "", ""),
|
||||
("写作 032701", "tblszuk1TeToofBF", "032701", W_032701, W_032701_T1, "", "", "", ""),
|
||||
("写作 032801", "tblszuk1TeToofBF", "032801", W_032801, W_032801_T1, "", "", "", ""),
|
||||
("写作 032901", "tblszuk1TeToofBF", "032901", W_032901, W_032901_T1, "", "", "", ""),
|
||||
# Speaking P1 records
|
||||
("口语-P1 032501", "tblRGv7k4WH58Jgq", "032501", S1_032501, S1_032501_T1, S1_032501_T2, "",
|
||||
"however,sooner,later,depending,used,change,mind,weather,plan",
|
||||
"however,sooner,later,depending,used,opinion,technology,future"),
|
||||
("口语-P1 032701", "tblRGv7k4WH58Jgq", "032701", S1_032701, S1_032701_T1, S1_032701_T2, "",
|
||||
"couldn't,find,lost,search,understand,curious,maybe,see,if,change,mind",
|
||||
"lost,search,understand,explain,curious,test,change,mind,grow"),
|
||||
("口语-P1 032901", "tblRGv7k4WH58Jgq", "032901", S1_032901, S1_032901_T1, S1_032901_T2, "",
|
||||
"let's,suggest,hope,achieve,talk,solve,problem,use,method,team",
|
||||
"let's,organise,hope,improve,talk,solve,disagreement,use,technology"),
|
||||
# Speaking P2 records
|
||||
("口语-P2 032601", "tblGoWYBmVI0IrvQ", "032601", S2_032601, S2_032601_T1, S2_032601_T2, S2_032601_PIC, "", ""),
|
||||
("口语-P2 032801", "tblGoWYBmVI0IrvQ", "032801", S2_032801, S2_032801_T1, S2_032801_T2, S2_032801_PIC, "", ""),
|
||||
]
|
||||
|
||||
results = []
|
||||
for label, tid, qsid, jd, t1, t2, pic, kw1, kw2 in records:
|
||||
fields = {
|
||||
"题目集合 ID": qsid,
|
||||
"dataStatus": "0",
|
||||
"jsonData": json.dumps(jd, ensure_ascii=False),
|
||||
"题目1": t1,
|
||||
}
|
||||
if "口语-P1" in label:
|
||||
fields["题目1 完整配置" if False else "题目1"] = t1
|
||||
if t2:
|
||||
fields["题目2" if "口语-P2" not in label else "题目2"] = t2
|
||||
if pic:
|
||||
fields["图片描述"] = pic
|
||||
if kw1:
|
||||
fields["题目1热词"] = kw1
|
||||
if kw2:
|
||||
fields["题目2热词"] = kw2
|
||||
|
||||
# Fix field names based on table
|
||||
if tid == "tblszuk1TeToofBF": # Writing P1
|
||||
fields["题目1 完整配置"] = fields.pop("题目1")
|
||||
if "题目2" in fields: del fields["题目2"]
|
||||
elif tid == "tblRGv7k4WH58Jgq": # Speaking P1
|
||||
pass # field names ok
|
||||
elif tid == "tblGoWYBmVI0IrvQ": # Speaking P2
|
||||
pass
|
||||
|
||||
resp = create(token, tid, fields)
|
||||
code = resp.get("code")
|
||||
if code == 0:
|
||||
rid = resp["data"]["record"]["record_id"]
|
||||
print(f"[✅] {label} → {rid}")
|
||||
results.append((label, qsid, rid, True))
|
||||
else:
|
||||
print(f"[❌] {label}: {resp.get('msg')}")
|
||||
results.append((label, qsid, "FAIL", False))
|
||||
time.sleep(0.3)
|
||||
|
||||
ok = sum(1 for r in results if r[3])
|
||||
print(f"\n=== {ok}/{len(results)} 条创建成功 ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
546
scripts/gen_writing_speaking.py
Normal file
546
scripts/gen_writing_speaking.py
Normal file
@ -0,0 +1,546 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate and write 6 writing/speaking records to unit challenge bitable"""
|
||||
import requests, json
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
BASE = "https://open.feishu.cn/open-apis/bitable/v1"
|
||||
|
||||
# ============================================================
|
||||
# Record definitions
|
||||
# ============================================================
|
||||
|
||||
# --- 写作-P1-邮件回复 | 021801 | L2 B级 ---
|
||||
WRITING_021801_JSON = {
|
||||
"first": {
|
||||
"category": "writing",
|
||||
"type": "writing_email",
|
||||
"questionSetID": "021801",
|
||||
"textDesc": "Your friend Annie wants to plan a surprise party for her mum. "
|
||||
"Write an email to help her organise it.<br>"
|
||||
"Put these sentences in order to make a clear and helpful email.",
|
||||
"optionSetList": [
|
||||
"Dear Annie,",
|
||||
"Don't tell anyone about the surprise party.",
|
||||
"We want to make Mum happy on her birthday.",
|
||||
"I think Dad said he will bring the cake.",
|
||||
"It must be hard to work every day without a break.",
|
||||
"Best wishes,\nYour Friend"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按照邮件格式和事件逻辑排列句子:称呼→说明目的→解释计划→补充细节→表达关心→署名。考察邮件格式规范和逻辑顺序组织能力。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
|
||||
WRITING_021801_TEXT1 = """【题目描述】
|
||||
Your friend Annie wants to plan a surprise party for her mum. Write an email to help her organise it.
|
||||
Put these sentences in order to make a clear and helpful email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Annie,
|
||||
B. Don't tell anyone about the surprise party.
|
||||
C. We want to make Mum happy on her birthday.
|
||||
D. I think Dad said he will bring the cake.
|
||||
E. It must be hard to work every day without a break.
|
||||
F. Best wishes,
|
||||
Your Friend"""
|
||||
|
||||
# --- 写作-P1-邮件回复 | 021901 | L2 B级 ---
|
||||
WRITING_021901_JSON = {
|
||||
"first": {
|
||||
"category": "writing",
|
||||
"type": "writing_email",
|
||||
"questionSetID": "021901",
|
||||
"textDesc": "Your friend Tom's pet dog Daisy is lost in the park. "
|
||||
"Write an email to help him search for her.<br>"
|
||||
"Put these sentences in order to make a helpful email.",
|
||||
"optionSetList": [
|
||||
"Dear Tom,",
|
||||
"We must find her before it gets dark!",
|
||||
"We need to find Daisy before she runs too far away!",
|
||||
"The lake is just in front of the playground.",
|
||||
"The gate was open, and Daisy was missing.",
|
||||
"Let's search together, while your mum checks the garden, and I check the path.",
|
||||
"Best wishes,\nYour Friend"
|
||||
],
|
||||
"answerSet": [0, 2, 1, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按照寻物邮件的逻辑排列句子:称呼→表达紧迫性→说明目标→描述位置→解释原因→分工合作→署名。考察事件叙述的逻辑顺序和while/and并列结构的使用。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
|
||||
WRITING_021901_TEXT1 = """【题目描述】
|
||||
Your friend Tom's pet dog Daisy is lost in the park. Write an email to help him search for her.
|
||||
Put these sentences in order to make a helpful email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Tom,
|
||||
B. We must find her before it gets dark!
|
||||
C. We need to find Daisy before she runs too far away!
|
||||
D. The lake is just in front of the playground.
|
||||
E. The gate was open, and Daisy was missing.
|
||||
F. Let's search together, while your mum checks the garden, and I check the path.
|
||||
G. Best wishes,
|
||||
Your Friend"""
|
||||
|
||||
# --- 写作-P1-邮件回复 | 022001 | L2 B级 ---
|
||||
WRITING_022001_JSON = {
|
||||
"first": {
|
||||
"category": "writing",
|
||||
"type": "writing_email",
|
||||
"questionSetID": "022001",
|
||||
"textDesc": "Your friend Lucy wants to make a gift for Grandma's birthday. "
|
||||
"Write an email to help her plan it.<br>"
|
||||
"Put these sentences in order to make a clear email.",
|
||||
"optionSetList": [
|
||||
"Dear Lucy,",
|
||||
"How long does it take you to make a paper card?",
|
||||
"Tom is taking the longer route to buy some art supplies.",
|
||||
"We still don't know if Grandma will like the surprise.",
|
||||
"She always makes special cards for everyone's birthday.",
|
||||
"Best wishes,\nYour Friend"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按照邮件逻辑排列句子:称呼→询问→补充信息→表达不确定→说明原因→署名。考察邮件的逻辑衔接和连词使用能力。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
|
||||
WRITING_022001_TEXT1 = """【题目描述】
|
||||
Your friend Lucy wants to make a gift for Grandma's birthday. Write an email to help her plan it.
|
||||
Put these sentences in order to make a clear email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Lucy,
|
||||
B. How long does it take you to make a paper card?
|
||||
C. Tom is taking the longer route to buy some art supplies.
|
||||
D. We still don't know if Grandma will like the surprise.
|
||||
E. She always makes special cards for everyone's birthday.
|
||||
F. Best wishes,
|
||||
Your Friend"""
|
||||
|
||||
# --- 口语-P2-话题讨论 | 021801 | L2 B级 ---
|
||||
SPEAKING_TOPIC_021801_JSON = {
|
||||
"first": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_topic",
|
||||
"asrPrompt": "sick,classmate,help,homework,encourage,goal,dream,support,friend,teamwork",
|
||||
"questionSetID": "021801",
|
||||
"textDesc": "Look at these pictures about helping others. Talk about what you see "
|
||||
"and share your own ideas about helping and supporting friends.",
|
||||
"imageDesc": "Four images show children helping each other: 1st: A child brings a glass of water to a sick friend in bed. 2nd: Two children study together at a desk, one is explaining something. 3rd: A team of children celebrate together with hands raised. 4th: A child gives a present to a sad friend, who then smiles.",
|
||||
"textImage": "021801-00.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What do you do when your friend is sick at home?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "可以用句型 \"We'd better...\" 来给出建议,例如 \"We'd better call him and check how he feels.\" 也可以补充具体行动,如 \"I would bring him homework and tell him to rest well.\""
|
||||
},
|
||||
{
|
||||
"content": "How do you help a classmate who finds homework difficult?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "可以用 \"Let's give him some tips so he can understand better.\" 来表达帮助方式。也可以说 \"I explain the homework step by step and give examples.\""
|
||||
},
|
||||
{
|
||||
"content": "What do you hope for your best friend in the future?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "可以用 \"I hope he is able to achieve his goals.\" 来表达希望。也可以补充具体内容,如 \"I hope she will go to a good school and make new friends.\""
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time when someone helped you. How did it feel?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "用过去式描述一次被帮助的经历,例如 \"Last term I couldn't do my maths homework. My friend sat with me after class and helped me finish it. I felt very warm and thankful.\""
|
||||
},
|
||||
{
|
||||
"content": "Why is it important to help others in your class or family?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "可以从合作和友谊角度回答,例如 \"When we help each other, we grow together. Helping makes the team stronger and everyone feels happy.\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_topic",
|
||||
"asrPrompt": "sick,classmate,help,homework,encourage,goal,dream,support,friend,teamwork",
|
||||
"questionSetID": "021801",
|
||||
"textDesc": "Now look at these pictures again. Think more deeply about helping others "
|
||||
"and share a different example or experience.",
|
||||
"imageDesc": "Same images as above: children helping each other in different situations.",
|
||||
"textImage": "021801-01.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What do you do when your friend is sick at home?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "也可以用不同的方式回答,例如 \"We'd better visit him and bring some fruit.\" 或者分享另一个想法:\"I would send him a nice message to cheer him up.\""
|
||||
},
|
||||
{
|
||||
"content": "How do you help a classmate who finds homework difficult?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "可以分享另一种帮助方式,比如 \"Let's give him a study plan so he can follow it step by step.\" 也可以说 \"We can study together after school.\""
|
||||
},
|
||||
{
|
||||
"content": "What do you hope for your best friend in the future?",
|
||||
"ability": ["句型组织", "表达愿望"],
|
||||
"explanation": "试着用不同的句型表达,例如 \"I hope he is able to follow his dream no matter what.\" 或者 \"I wish she will be happy and healthy forever.\""
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time when you helped someone else. How did you feel?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享你帮助别人的经历,例如 \"I once helped a new classmate find her way around school. I felt proud because I made her feel welcome.\""
|
||||
},
|
||||
{
|
||||
"content": "Why is it important to help others in your class or family?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "可以从更广的角度回答,例如 \"Helping others makes our class like a big family. When we help each other, nobody feels alone or sad.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
SPEAKING_TOPIC_021801_TEXT1 = """【题目描述】
|
||||
Look at these pictures about helping others. Talk about what you see and share your own ideas about helping and supporting friends.
|
||||
|
||||
【热词】
|
||||
sick,classmate,help,homework,encourage,goal,dream,support,friend,teamwork
|
||||
|
||||
【图片描述】
|
||||
Four images show children helping each other: 1st: A child brings a glass of water to a sick friend in bed. 2nd: Two children study together at a desk, one is explaining something. 3rd: A team of children celebrate together with hands raised. 4th: A child gives a present to a sad friend, who then smiles.
|
||||
|
||||
【题目】
|
||||
1. What do you do when your friend is sick at home?
|
||||
- 解析:可以用句型 "We'd better..." 来给出建议,例如 "We'd better call him and check how he feels." 也可以补充具体行动,如 "I would bring him homework and tell him to rest well."
|
||||
|
||||
2. How do you help a classmate who finds homework difficult?
|
||||
- 解析:可以用 "Let's give him some tips so he can understand better." 来表达帮助方式。也可以说 "I explain the homework step by step and give examples."
|
||||
|
||||
3. What do you hope for your best friend in the future?
|
||||
- 解析:可以用 "I hope he is able to achieve his goals." 来表达希望。也可以补充具体内容,如 "I hope she will go to a good school and make new friends."
|
||||
|
||||
4. Tell us about a time when someone helped you. How did it feel?
|
||||
- 解析:用过去式描述一次被帮助的经历,例如 "Last term I couldn't do my maths homework. My friend sat with me after class and helped me finish it. I felt very warm and thankful."
|
||||
|
||||
5. Why is it important to help others in your class or family?
|
||||
- 解析:可以从合作和友谊角度回答,例如 "When we help each other, we grow together. Helping makes the team stronger and everyone feels happy.\""""
|
||||
|
||||
SPEAKING_TOPIC_021801_TEXT2 = """【题目描述】
|
||||
Now look at these pictures again. Think more deeply about helping others and share a different example or experience.
|
||||
|
||||
【热词】
|
||||
sick,classmate,help,homework,encourage,goal,dream,support,friend,teamwork
|
||||
|
||||
【图片描述】
|
||||
Same images as above: children helping each other in different situations.
|
||||
|
||||
【题目】
|
||||
1. What do you do when your friend is sick at home?
|
||||
- 解析:也可以用不同的方式回答,例如 "We'd better visit him and bring some fruit." 或者分享另一个想法:"I would send him a nice message to cheer him up."
|
||||
|
||||
2. How do you help a classmate who finds homework difficult?
|
||||
- 解析:可以分享另一种帮助方式,比如 "Let's give him a study plan so he can follow it step by step." 也可以说 "We can study together after school."
|
||||
|
||||
3. What do you hope for your best friend in the future?
|
||||
- 解析:试着用不同的句型表达,例如 "I hope he is able to follow his dream no matter what." 或者 "I wish she will be happy and healthy forever."
|
||||
|
||||
4. Tell us about a time when you helped someone else. How did you feel?
|
||||
- 解析:分享你帮助别人的经历,例如 "I once helped a new classmate find her way around school. I felt proud because I made her feel welcome."
|
||||
|
||||
5. Why is it important to help others in your class or family?
|
||||
- 解析:可以从更广的角度回答,例如 "Helping others makes our class like a big family. When we help each other, nobody feels alone or sad.\""""
|
||||
|
||||
# --- 口语-P1-日常回答 | 021901 | L2 B级 ---
|
||||
SPEAKING_QA_021901_JSON = {
|
||||
"first": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_qa",
|
||||
"asrPrompt": "subject,Maths,English,Art,prefer,reading,running,drawing,friend,kind,helpful,hobby,because,enjoy,difficult",
|
||||
"questionSetID": "021901",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和经历。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What school subject do you like? Why?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "你可以用 \"I like...\" 来回答,例如 \"I like English because it is interesting for me.\" 也可以换成 Maths、Art 或其他你喜欢的科目,并说明理由。"
|
||||
},
|
||||
{
|
||||
"content": "Is there a subject that is hard for you? Why?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "你可以说 \"Maths is hard for me because I find the problems difficult.\" 用 \"but it is... for me\" 的句型来表达你的感受,同时解释原因。"
|
||||
},
|
||||
{
|
||||
"content": "What do you prefer to do after school?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "用 \"I prefer... to...\" 来回答,例如 \"I prefer reading to watching TV because I enjoy stories.\" 也可以说跑步、画画或和朋友玩。"
|
||||
},
|
||||
{
|
||||
"content": "What do you do with your best friend after school?",
|
||||
"ability": ["基础信息表达|个人信息问答"],
|
||||
"explanation": "你可以回答 \"I play with my best friend after school.\" 然后用 \"I... because I...\" 来补充原因,例如 \"I play football with him because I love sports.\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_qa",
|
||||
"asrPrompt": "sport,swimming,football,weekend,museum,park,movie,cooking,pizza,dumplings,English,learn,songs,stories,fun,useful",
|
||||
"questionSetID": "021901",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和经历。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Do you like playing sports? Which sport do you like?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "你可以用 \"I like... but it is... for me\" 来表达,例如 \"I like swimming, but it is tiring for me sometimes.\" 也可以换成 football、basketball 或 running。"
|
||||
},
|
||||
{
|
||||
"content": "What do you prefer to do on weekends?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "用 \"I prefer... to...\" 来回答,例如 \"I prefer going to the park to staying at home.\" 也可以提到去博物馆、看电影或和朋友出去玩。"
|
||||
},
|
||||
{
|
||||
"content": "What food do you like but find hard to make?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "试着说出一种你爱吃但不会做的食物,例如 \"I like dumplings, but they are hard for me to make alone.\" 也可以用 \"I... because I...\" 解释难度在哪儿。"
|
||||
},
|
||||
{
|
||||
"content": "Why do you enjoy learning English?",
|
||||
"ability": ["表达喜好与理由"],
|
||||
"explanation": "用 \"I enjoy learning English because I...\" 来表达,例如 \"I enjoy learning English because I can sing English songs and read interesting stories.\" 也可以说对将来有用或很有趣。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
SPEAKING_QA_021901_TEXT1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和经历。
|
||||
|
||||
【热词】
|
||||
subject,Maths,English,Art,prefer,reading,running,drawing,friend,kind,helpful,hobby,because,enjoy,difficult
|
||||
|
||||
【题目】
|
||||
1. What school subject do you like? Why?
|
||||
- 解析:你可以用 "I like..." 来回答,例如 "I like English because it is interesting for me." 也可以换成 Maths、Art 或其他你喜欢的科目,并说明理由。
|
||||
|
||||
2. Is there a subject that is hard for you? Why?
|
||||
- 解析:你可以说 "Maths is hard for me because I find the problems difficult." 用 "but it is... for me" 的句型来表达你的感受,同时解释原因。
|
||||
|
||||
3. What do you prefer to do after school?
|
||||
- 解析:用 "I prefer... to..." 来回答,例如 "I prefer reading to watching TV because I enjoy stories." 也可以说跑步、画画或和朋友玩。
|
||||
|
||||
4. What do you do with your best friend after school?
|
||||
- 解析:你可以回答 "I play with my best friend after school." 然后用 "I... because I..." 来补充原因,例如 "I play football with him because I love sports.\""""
|
||||
|
||||
SPEAKING_QA_021901_TEXT2 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和经历。
|
||||
|
||||
【热词】
|
||||
sport,swimming,football,weekend,museum,park,movie,cooking,pizza,dumplings,English,learn,songs,stories
|
||||
|
||||
【题目】
|
||||
1. Do you like playing sports? Which sport do you like?
|
||||
- 解析:你可以用 "I like... but it is... for me" 来表达,例如 "I like swimming, but it is tiring for me sometimes." 也可以换成 football、basketball 或 running。
|
||||
|
||||
2. What do you prefer to do on weekends?
|
||||
- 解析:用 "I prefer... to..." 来回答,例如 "I prefer going to the park to staying at home." 也可以提到去博物馆、看电影或和朋友出去玩。
|
||||
|
||||
3. What food do you like but find hard to make?
|
||||
- 解析:试着说出一种你爱吃但不会做的食物,例如 "I like dumplings, but they are hard for me to make alone." 也可以用 "I... because I..." 解释难度在哪儿。
|
||||
|
||||
4. Why do you enjoy learning English?
|
||||
- 解析:用 "I enjoy learning English because I..." 来表达,例如 "I enjoy learning English because I can sing English songs and read interesting stories." 也可以说对将来有用或很有趣。"""
|
||||
|
||||
# --- 口语-P2-话题讨论 | 022001 | L2 B级 ---
|
||||
SPEAKING_TOPIC_022001_JSON = {
|
||||
"first": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_topic",
|
||||
"asrPrompt": "worried,afraid,dark,teach,brave,proud,challenge,climb,race,stop,fight,problem,difficult,solve",
|
||||
"questionSetID": "022001",
|
||||
"textDesc": "Look at these pictures about facing challenges and emotions. "
|
||||
"Talk about what you see and share your own experiences with feelings and growth.",
|
||||
"imageDesc": "Four images show children dealing with different emotions and challenges: 1st: A child looks worried while staring at a big maths test paper. 2nd: A parent or teacher gently puts a hand on a child's shoulder, teaching them something. 3rd: A child stands on top of a small hill, arms raised with a proud smile. 4th: An adult stops a child from touching a hot kettle, pointing at it with a warning look.",
|
||||
"textImage": "022001-00.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Have you ever seen a friend who looked worried? What happened?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "描述一次观察到朋友担忧的经历,例如 \"My friend Tom is a happy boy, but he looked very worried before the maths test. I asked him what was wrong and he said he didn't study enough.\""
|
||||
},
|
||||
{
|
||||
"content": "Who taught you not to be afraid of something? What did they say?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "回答谁教过你勇敢,例如 \"My mum taught me not to be afraid of the dark. She said there is nothing that can hurt me and that being brave makes you stronger.\""
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time you felt proud of yourself. What did you do?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "用过去式描述一次自豪的经历,例如 \"I felt very proud when I finished a difficult race. I wanted to give up, but I kept running and reached the end.\""
|
||||
},
|
||||
{
|
||||
"content": "Has a parent or teacher ever stopped you from doing something? Why?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "描述一次被阻止的经历,例如 \"My dad stopped me from climbing a tall tree. He said it was too dangerous and I could fall and get hurt.\""
|
||||
},
|
||||
{
|
||||
"content": "If you find anything really difficult, what will you do?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "分享你面对困难的方法,例如 \"If I find anything difficult, I will ask my teacher or my parents for help. I will keep trying and not give up easily.\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking",
|
||||
"type": "speaking_topic",
|
||||
"asrPrompt": "worried,afraid,dark,teach,brave,proud,challenge,climb,race,stop,fight,problem,difficult,solve",
|
||||
"questionSetID": "022001",
|
||||
"textDesc": "Now look at these pictures again. Think about different experiences "
|
||||
"and share another story about feelings, challenges or growing up.",
|
||||
"imageDesc": "Same images as above: children dealing with different emotions and challenges.",
|
||||
"textImage": "022001-01.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Have you ever seen a friend who looked worried? What did you do to help?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享你帮助朋友的经历,例如 \"Yes, my friend Lily looked sad after losing her favourite pen. I helped her search everywhere, and she smiled when we finally found it.\""
|
||||
},
|
||||
{
|
||||
"content": "Who taught you not to be afraid of trying new things? How did they help?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "描述学习勇敢的过程,例如 \"My dad taught me not to be afraid of swimming. He held my hand in the water and slowly let go when I was ready.\""
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time you overcame a difficulty. How did you feel?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享克服困难的经历,例如 \"I couldn't ride a bike at first. I kept falling, but I practised every day. I felt amazing when I finally rode without help.\""
|
||||
},
|
||||
{
|
||||
"content": "Why do parents or teachers sometimes stop children from doing things?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "从理解的角度回答,例如 \"They stop us from doing dangerous things because they want to keep us safe. It is a way of showing their love and care.\""
|
||||
},
|
||||
{
|
||||
"content": "If you find anything difficult, what will you tell yourself?",
|
||||
"ability": ["句型组织", "表达观点"],
|
||||
"explanation": "分享你鼓励自己的话,例如 \"I will tell myself 'Never give up!' I believe that if I keep trying, I will find a way to solve the problem and become stronger.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
SPEAKING_TOPIC_022001_TEXT1 = """【题目描述】
|
||||
Look at these pictures about facing challenges and emotions. Talk about what you see and share your own experiences with feelings and growth.
|
||||
|
||||
【热词】
|
||||
worried,afraid,dark,teach,brave,proud,challenge,climb,race,stop,fight,problem,difficult,solve
|
||||
|
||||
【图片描述】
|
||||
Four images show children dealing with different emotions and challenges: 1st: A child looks worried while staring at a big maths test paper. 2nd: A parent or teacher gently puts a hand on a child's shoulder, teaching them something. 3rd: A child stands on top of a small hill, arms raised with a proud smile. 4th: An adult stops a child from touching a hot kettle, pointing at it with a warning look.
|
||||
|
||||
【题目】
|
||||
1. Have you ever seen a friend who looked worried? What happened?
|
||||
- 解析:描述一次观察到朋友担忧的经历,例如 "My friend Tom is a happy boy, but he looked very worried before the maths test. I asked him what was wrong and he said he didn't study enough."
|
||||
|
||||
2. Who taught you not to be afraid of something? What did they say?
|
||||
- 解析:回答谁教过你勇敢,例如 "My mum taught me not to be afraid of the dark. She said there is nothing that can hurt me and that being brave makes you stronger."
|
||||
|
||||
3. Tell us about a time you felt proud of yourself. What did you do?
|
||||
- 解析:用过去式描述一次自豪的经历,例如 "I felt very proud when I finished a difficult race. I wanted to give up, but I kept running and reached the end."
|
||||
|
||||
4. Has a parent or teacher ever stopped you from doing something? Why?
|
||||
- 解析:描述一次被阻止的经历,例如 "My dad stopped me from climbing a tall tree. He said it was too dangerous and I could fall and get hurt."
|
||||
|
||||
5. If you find anything really difficult, what will you do?
|
||||
- 解析:分享你面对困难的方法,例如 "If I find anything difficult, I will ask my teacher or my parents for help. I will keep trying and not give up easily.\""""
|
||||
|
||||
SPEAKING_TOPIC_022001_TEXT2 = """【题目描述】
|
||||
Now look at these pictures again. Think about different experiences and share another story about feelings, challenges or growing up.
|
||||
|
||||
【热词】
|
||||
worried,afraid,dark,teach,brave,proud,challenge,climb,race,stop,fight,problem,difficult,solve
|
||||
|
||||
【图片描述】
|
||||
Same images as above: children dealing with different emotions and challenges.
|
||||
|
||||
【题目】
|
||||
1. Have you ever seen a friend who looked worried? What did you do to help?
|
||||
- 解析:分享你帮助朋友的经历,例如 "Yes, my friend Lily looked sad after losing her favourite pen. I helped her search everywhere, and she smiled when we finally found it."
|
||||
|
||||
2. Who taught you not to be afraid of trying new things? How did they help?
|
||||
- 解析:描述学习勇敢的过程,例如 "My dad taught me not to be afraid of swimming. He held my hand in the water and slowly let go when I was ready."
|
||||
|
||||
3. Tell us about a time you overcame a difficulty. How did you feel?
|
||||
- 解析:分享克服困难的经历,例如 "I couldn't ride a bike at first. I kept falling, but I practised every day. I felt amazing when I finally rode without help."
|
||||
|
||||
4. Why do parents or teachers sometimes stop children from doing things?
|
||||
- 解析:从理解的角度回答,例如 "They stop us from doing dangerous things because they want to keep us safe. It is a way of showing their love and care."
|
||||
|
||||
5. If you find anything difficult, what will you tell yourself?
|
||||
- 解析:分享你鼓励自己的话,例如 "I will tell myself 'Never give up!' I believe that if I keep trying, I will find a way to solve the problem and become stronger.\""""
|
||||
|
||||
# ============================================================
|
||||
# API helpers
|
||||
# ============================================================
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def create_record(token, table_id, fields):
|
||||
r = requests.post(
|
||||
f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": fields}, timeout=15)
|
||||
return r.json()
|
||||
|
||||
# ============================================================
|
||||
# Records to create
|
||||
# ============================================================
|
||||
records_to_create = [
|
||||
# (table_name, table_id, 题目集合 ID, jsonData, 题目1, 题目2)
|
||||
("写作-P1-邮件回复", "tblszuk1TeToofBF", "021801",
|
||||
WRITING_021801_JSON, WRITING_021801_TEXT1, ""),
|
||||
("写作-P1-邮件回复", "tblszuk1TeToofBF", "021901",
|
||||
WRITING_021901_JSON, WRITING_021901_TEXT1, ""),
|
||||
("写作-P1-邮件回复", "tblszuk1TeToofBF", "022001",
|
||||
WRITING_022001_JSON, WRITING_022001_TEXT1, ""),
|
||||
("口语-P2-话题讨论", "tblGoWYBmVI0IrvQ", "021801",
|
||||
SPEAKING_TOPIC_021801_JSON, SPEAKING_TOPIC_021801_TEXT1, SPEAKING_TOPIC_021801_TEXT2),
|
||||
("口语-P1-日常回答", "tblRGv7k4WH58Jgq", "021901",
|
||||
SPEAKING_QA_021901_JSON, SPEAKING_QA_021901_TEXT1, SPEAKING_QA_021901_TEXT2),
|
||||
("口语-P2-话题讨论", "tblGoWYBmVI0IrvQ", "022001",
|
||||
SPEAKING_TOPIC_022001_JSON, SPEAKING_TOPIC_022001_TEXT1, SPEAKING_TOPIC_022001_TEXT2),
|
||||
]
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
print("Token OK")
|
||||
|
||||
for i, (tname, tid, qsid, jd, t1, t2) in enumerate(records_to_create):
|
||||
fields = {
|
||||
"题目集合 ID": qsid,
|
||||
"dataStatus": "0",
|
||||
"jsonData": json.dumps(jd, ensure_ascii=False),
|
||||
"题目1": t1,
|
||||
}
|
||||
if t2:
|
||||
fields["题目2"] = t2
|
||||
# 口语-P1 has 题目1热词 and 题目2热词
|
||||
if tname == "口语-P1-日常回答":
|
||||
fields["题目1热词"] = "subject,Maths,English,Art,prefer,reading,running,drawing,friend,kind,helpful,hobby"
|
||||
fields["题目2热词"] = "sport,swimming,football,weekend,museum,park,movie,cooking"
|
||||
|
||||
result = create_record(token, tid, fields)
|
||||
code = result.get("code")
|
||||
if code == 0:
|
||||
rid = result.get("data",{}).get("record",{}).get("record_id","?")
|
||||
print(f"[{i+1}/6] ✅ {tname} QSID={qsid} → {rid}")
|
||||
else:
|
||||
print(f"[{i+1}/6] ❌ {tname} QSID={qsid} FAIL: {result.get('msg')}")
|
||||
|
||||
print("\nDone!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
660
scripts/gen_writing_speaking_batch2.py
Normal file
660
scripts/gen_writing_speaking_batch2.py
Normal file
@ -0,0 +1,660 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate 7 new writing/speaking records: 022101, 022201, 022301, 022401"""
|
||||
import requests, json, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
BASE = "https://open.feishu.cn/open-apis/bitable/v1"
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def create_record(token, table_id, fields):
|
||||
r = requests.post(f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": fields}, timeout=15)
|
||||
return r.json()
|
||||
|
||||
def verify(token, table_id, rid, qsid):
|
||||
r = requests.get(f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}"}, timeout=10)
|
||||
f = r.json().get("data",{}).get("record",{}).get("fields",{})
|
||||
ds = f.get("dataStatus","?")
|
||||
fqsid = f.get("题目集合 ID","?")
|
||||
jd = json.loads(f.get("jsonData","{}"))
|
||||
tp = jd.get("first",{}).get("type","?")
|
||||
oa = len(jd.get("first",{}).get("optionSetList",[]))
|
||||
ai = jd.get("first",{}).get("answerSet",[])
|
||||
ab = jd.get("first",{}).get("ability",[])
|
||||
ex = jd.get("first",{}).get("explanation","")
|
||||
qs = len(jd.get("first",{}).get("questionSet",[]))
|
||||
sqs = len(jd.get("second",{}).get("questionSet",[]))
|
||||
t1 = bool(f.get("题目1",""))
|
||||
t2 = bool(f.get("题目2",""))
|
||||
pd = bool(f.get("图片描述",""))
|
||||
ok = (ds=="0" and fqsid==qsid and t1 and len(ai)>0 and len(ex)>10)
|
||||
tag = "✅" if ok else "❌"
|
||||
return f"{tag} {qsid} | ds={ds} type={tp} opt={oa} qs={qs}/{sqs} ans={ai} ab={len(ab)} expl={len(ex)} t1={t1} t2={t2} pic={pd}"
|
||||
|
||||
# ============================================================
|
||||
# RECORD DEFINITIONS
|
||||
# ============================================================
|
||||
|
||||
# --- 写作-P1 022101: Urgent help ---
|
||||
W_022101 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "022101",
|
||||
"textDesc": "Your friend Lily left her school bag in the classroom and needs your help to get it back before the weekend. Write an email to help her.<br>Put these sentences in order to make a clear and helpful email.",
|
||||
"optionSetList": [
|
||||
"Dear Lily,",
|
||||
"Is there any chance we can go back to school for your bag now?",
|
||||
"If we leave right away, we still have a chance to find it.",
|
||||
"We must hurry and call the teacher to avoid being too late.",
|
||||
"The only way to get it back is to ask the school guard for help.",
|
||||
"How long have you been here waiting for me?",
|
||||
"Yours, Sam"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按紧急求助邮件的逻辑排列:称呼→询问可能→建议立刻行动→强调紧迫性→给出唯一方案→关心等待→署名。考察is there any chance/we must/the only way等句型和邮件逻辑组织能力。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_022101_T1 = """【题目描述】
|
||||
Your friend Lily left her school bag in the classroom and needs your help to get it back before the weekend. Write an email to help her.
|
||||
Put these sentences in order to make a clear and helpful email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Lily,
|
||||
B. Is there any chance we can go back to school for your bag now?
|
||||
C. If we leave right away, we still have a chance to find it.
|
||||
D. We must hurry and call the teacher to avoid being too late.
|
||||
E. The only way to get it back is to ask the school guard for help.
|
||||
F. How long have you been here waiting for me?
|
||||
G. Yours, Sam"""
|
||||
|
||||
# --- 写作-P1 022201: Mystery box ---
|
||||
W_022201 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "022201",
|
||||
"textDesc": "Your friend Max found a mysterious old box in the attic. Write an email to share what you found and ask for his help.<br>Put these sentences in order to make a clear email.",
|
||||
"optionSetList": [
|
||||
"Dear Max,",
|
||||
"Why is this old box full of strange papers?",
|
||||
"The story behind it is unknown, and even my grandpa avoids talking about it.",
|
||||
"This box might be from our great-grandfather's time.",
|
||||
"By then, I will have tried to open it with a small key.",
|
||||
"That's why I am writing to ask for your help.",
|
||||
"Take care, Alex"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按分享发现的邮件逻辑排列:称呼→提出问题→描述背景→合理推测→行动预案→请求帮助→署名。考察why is this/the...is unknown/this might be/by then...will have done等句型组织。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_022201_T1 = """【题目描述】
|
||||
Your friend Max found a mysterious old box in the attic. Write an email to share what you found and ask for his help.
|
||||
Put these sentences in order to make a clear email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Max,
|
||||
B. Why is this old box full of strange papers?
|
||||
C. The story behind it is unknown, and even my grandpa avoids talking about it.
|
||||
D. This box might be from our great-grandfather's time.
|
||||
E. By then, I will have tried to open it with a small key.
|
||||
F. That's why I am writing to ask for your help.
|
||||
G. Take care, Alex"""
|
||||
|
||||
# --- 写作-P1 022301: Community garden ---
|
||||
W_022301 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "022301",
|
||||
"textDesc": "You and your friend Emma are working on a community garden project. Write an email to tell her about today's progress and the plan for next time.<br>Put these sentences in order to make a clear email.",
|
||||
"optionSetList": [
|
||||
"Dear Emma,",
|
||||
"We came here to work together and make our town more beautiful.",
|
||||
"So we worked fast before the sun got too hot.",
|
||||
"It took us two hours to return to the community garden today.",
|
||||
"The photos showed the garden was full of pretty flowers now.",
|
||||
"I will plant new seeds while you will water the young trees.",
|
||||
"Your friend, Lily"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按社区活动汇报的逻辑排列:称呼→说明目的→描述行动→补充细节→展示成果→分配未来任务→署名。考察we came here to/so...worked/the photos showed/while...will等句型和邮件叙事组织能力。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_022301_T1 = """【题目描述】
|
||||
You and your friend Emma are working on a community garden project. Write an email to tell her about today's progress and the plan for next time.
|
||||
Put these sentences in order to make a clear email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Emma,
|
||||
B. We came here to work together and make our town more beautiful.
|
||||
C. So we worked fast before the sun got too hot.
|
||||
D. It took us two hours to return to the community garden today.
|
||||
E. The photos showed the garden was full of pretty flowers now.
|
||||
F. I will plant new seeds while you will water the young trees.
|
||||
G. Your friend, Lily"""
|
||||
|
||||
# --- 写作-P1 022401: Hospital visit ---
|
||||
W_022401 = {
|
||||
"first": {
|
||||
"category": "writing", "type": "writing_email",
|
||||
"questionSetID": "022401",
|
||||
"textDesc": "You and your friend Tom visited Jack in the hospital today. Write an email to Sophie to tell her about the visit and what you plan to do next.<br>Put these sentences in order to make a clear email.",
|
||||
"optionSetList": [
|
||||
"Dear Sophie,",
|
||||
"Tom and I went to the hospital to find our friend Jack today.",
|
||||
"The nurse used a machine to check his temperature before we went in.",
|
||||
"After saying goodbye, we hurried to tell his mum that he was feeling better.",
|
||||
"Then we will bring him his homework and some snacks tomorrow.",
|
||||
"You have already done so much by sending him that lovely card.",
|
||||
"Warmly, Lily"
|
||||
],
|
||||
"answerSet": [0, 1, 2, 3, 4, 5, 6],
|
||||
"ability": ["短消息写作|邮件/便条", "衔接与连贯|连词使用"],
|
||||
"explanation": "按医院探病汇报的逻辑排列:称呼→说明探病行动→描述检查过程→告别后通知→后续计划→感谢帮助→署名。考察go to...to find/use...to check/after doing/have already done等句型组织。"
|
||||
},
|
||||
"second": {}
|
||||
}
|
||||
W_022401_T1 = """【题目描述】
|
||||
You and your friend Tom visited Jack in the hospital today. Write an email to Sophie to tell her about the visit and what you plan to do next.
|
||||
Put these sentences in order to make a clear email.
|
||||
|
||||
【段落列表】
|
||||
A. Dear Sophie,
|
||||
B. Tom and I went to the hospital to find our friend Jack today.
|
||||
C. The nurse used a machine to check his temperature before we went in.
|
||||
D. After saying goodbye, we hurried to tell his mum that he was feeling better.
|
||||
E. Then we will bring him his homework and some snacks tomorrow.
|
||||
F. You have already done so much by sending him that lovely card.
|
||||
G. Warmly, Lily"""
|
||||
|
||||
# ============================================================
|
||||
# SPEAKING RECORDS
|
||||
# ============================================================
|
||||
|
||||
# --- 口语-P1 022101: Learning experiences ---
|
||||
S1_022101 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "teacher,gave,seeds,garden,explained,moon,Earth,experiment,proud,found,stone,shell,gift,present,map",
|
||||
"questionSetID": "022101",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实经历和想法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Tell us about a time your teacher gave you something special. What was it?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "用过去式描述老师给过你的特别的东西。用 '...gave us... and...' 的句型,例如 'Our art teacher gave us some paint and paper for a special project last week.'"
|
||||
},
|
||||
{
|
||||
"content": "Who once explained something that you didn't understand? What did they say?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "描述谁给你解释过你不理解的事情。用 '...explained that...' 的句型,例如 'My dad explained that the stars are very, very far away from the Earth.'"
|
||||
},
|
||||
{
|
||||
"content": "What did you do after finishing a difficult task? How did you feel?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "用 'After doing...' 开头描述完成后的感受。例如 'After doing the science experiment, we felt very proud and wanted to show everyone the results.'"
|
||||
},
|
||||
{
|
||||
"content": "What interesting thing have you found in an unexpected place?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "描述你在不寻常的地方发现过什么。用 '... found... in/on...' 的句型,例如 'I found a beautiful seashell on the playground last Friday.'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "gave,help,learn,explained,game,sport,searching,found,brave,felt,happy,excited,proud,surprised",
|
||||
"questionSetID": "022101",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实经历和想法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What did someone give you that helped you learn something new?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "分享别人给过你什么帮助了你学习新东西。例如 'My grandpa gave me a small map and a compass for our hiking trip. It helped me learn how to find directions.'"
|
||||
},
|
||||
{
|
||||
"content": "Who explained a difficult game or sport to you? What happened?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "描述谁给你解释过一项困难的运动或游戏。例如 'My cousin explained that in chess, each piece moves in a different way. It took a long time for me to remember all the rules.'"
|
||||
},
|
||||
{
|
||||
"content": "What did you find after searching for a long time?",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "分享你找了很久才找到的东西。例如 'I found my favourite book under the sofa after searching the whole house for nearly one hour.'"
|
||||
},
|
||||
{
|
||||
"content": "After doing something brave, how did you feel? Tell us about it.",
|
||||
"ability": ["经历描述"],
|
||||
"explanation": "描述你做过一件勇敢的事后的感受。例如 'After doing my first school speech, I felt so happy and surprised that I could do it. The whole class clapped for me.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_022101_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实经历和想法。
|
||||
|
||||
【热词】
|
||||
teacher,gave,seeds,garden,explained,moon,Earth,experiment,proud,found,stone,shell
|
||||
|
||||
【题目】
|
||||
1. Tell us about a time your teacher gave you something special. What was it?
|
||||
- 解析:用过去式描述老师给过你的特别的东西。用 '...gave us... and...' 的句型,例如 'Our art teacher gave us some paint and paper for a special project last week.'
|
||||
|
||||
2. Who once explained something that you didn't understand? What did they say?
|
||||
- 解析:描述谁给你解释过你不理解的事情。用 '...explained that...' 的句型,例如 'My dad explained that the stars are very, very far away from the Earth.'
|
||||
|
||||
3. What did you do after finishing a difficult task? How did you feel?
|
||||
- 解析:用 'After doing...' 开头描述完成后的感受。例如 'After doing the science experiment, we felt very proud and wanted to show everyone the results.'
|
||||
|
||||
4. What interesting thing have you found in an unexpected place?
|
||||
- 解析:描述你在不寻常的地方发现过什么。用 '... found... in/on...' 的句型,例如 'I found a beautiful seashell on the playground last Friday.'"""
|
||||
S1_022101_T2 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实经历和想法。
|
||||
|
||||
【热词】
|
||||
gave,help,learn,explained,game,sport,searching,found,brave,felt,happy,excited,surprised,proud
|
||||
|
||||
【题目】
|
||||
1. What did someone give you that helped you learn something new?
|
||||
- 解析:分享别人给过你什么帮助了你学习新东西。例如 'My grandpa gave me a small map and a compass for our hiking trip. It helped me learn how to find directions.'
|
||||
|
||||
2. Who explained a difficult game or sport to you? What happened?
|
||||
- 解析:描述谁给你解释过一项困难的运动或游戏。例如 'My cousin explained that in chess, each piece moves in a different way. It took a long time for me to remember all the rules.'
|
||||
|
||||
3. What did you find after searching for a long time?
|
||||
- 解析:分享你找了很久才找到的东西。例如 'I found my favourite book under the sofa after searching the whole house for nearly one hour.'
|
||||
|
||||
4. After doing something brave, how did you feel? Tell us about it.
|
||||
- 解析:描述你做过一件勇敢的事后的感受。例如 'After doing my first school speech, I felt so happy and surprised that I could do it. The whole class clapped for me.'"""
|
||||
|
||||
# --- 口语-P2 022201: Teamwork (WITH IMAGES) ---
|
||||
S2_022201 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "plan,list,project,team,disagree,talk,together,poster,colourful,computer,work,help,finish,share,great",
|
||||
"questionSetID": "022201",
|
||||
"textDesc": "Here are some pictures about working on a school project with classmates. What do you think about these situations?",
|
||||
"imageDesc": "Four images show a group of students working on a school project together: 1st: Students sit around a desk with a plan sheet and coloured pencils, discussing their project. 2nd: Two students face each other unhappily, and a teacher bends down to help them work together. 3rd: Students use a laptop and coloured paper to make a poster, with one writing and others drawing. 4th: All students hold up their finished team project, each with a big smile on their faces.",
|
||||
"textImage": "022201-00.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "How do you start a group project with your classmates?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "'Let's plan it first and make a to-do list together.' 然后用这个开始描述你们的项目流程,也可以说说谁负责什么。"
|
||||
},
|
||||
{
|
||||
"content": "What happened when your team disagreed about something?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'They argued at first, and then we sat down and talked about it.' 描述一次团队有不同意见的经历,以及你们是怎么解决的。"
|
||||
},
|
||||
{
|
||||
"content": "What do you use to make your project look great?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "'We'll use colourful paper and markers to make our poster stand out.' 说说你们用什么工具和材料让项目作品看起来更好。"
|
||||
},
|
||||
{
|
||||
"content": "What must everyone do to finish the project on time?",
|
||||
"ability": ["句型组织", "表达要求"],
|
||||
"explanation": "'Everyone must bring their part and help each other.' 解释团队合作中每个人需要做什么才能按时完成。"
|
||||
},
|
||||
{
|
||||
"content": "Tell us about a time your team did a really great job.",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享一次团队合作成功的经历。例如 'Last month, our team made a poster about saving water. We won the school prize, and I felt so proud of our teamwork.'"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_topic",
|
||||
"asrPrompt": "plan,list,project,team,disagree,talk,together,poster,colourful,computer,work,help,finish,share,great",
|
||||
"questionSetID": "022201",
|
||||
"textDesc": "Now look at these pictures again. Think about a different project or situation and share more ideas about working with others.",
|
||||
"imageDesc": "Same images as above: students working on a school project together.",
|
||||
"textImage": "022201-01.png",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "How do you plan a school party or event with your classmates?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "'Let's plan the games first and make a decoration list together.' 分享你们如何组织一场活动或派对。"
|
||||
},
|
||||
{
|
||||
"content": "What did your friend do at first when things went wrong?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "'They felt worried at first, and then we helped each other find a solution.' 说说当事情出错时你们是怎么一起面对的。"
|
||||
},
|
||||
{
|
||||
"content": "What tools or objects will you use to finish a big task?",
|
||||
"ability": ["句型组织", "表达建议"],
|
||||
"explanation": "'We will use a big calendar to plan our time and make sure we don't forget anything.' 说说你们计划用什么来高效完成任务。"
|
||||
},
|
||||
{
|
||||
"content": "What rules must everyone follow when working as a team?",
|
||||
"ability": ["句型组织", "表达要求"],
|
||||
"explanation": "'Everyone must listen to each other and share their ideas fairly.' 制定几条团队合作的基本规则。"
|
||||
},
|
||||
{
|
||||
"content": "What was the most fun thing you ever did together as a group?",
|
||||
"ability": ["句型组织", "经历描述"],
|
||||
"explanation": "分享一个有趣的团队经历。例如 'Last summer, our group cleaned the park near our school. After finishing, we had a small picnic together, and it was the most fun I have ever had with my classmates.'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S2_022201_T1 = """【题目描述】
|
||||
Here are some pictures about working on a school project with classmates. What do you think about these situations?
|
||||
|
||||
【热词】
|
||||
plan,list,project,team,disagree,talk,together,poster,colourful,computer,work,help
|
||||
|
||||
【图片描述】
|
||||
Four images show a group of students working on a school project together: 1st: Students sit around a desk with a plan sheet and coloured pencils, discussing their project. 2nd: Two students face each other unhappily, and a teacher bends down to help them work together. 3rd: Students use a laptop and coloured paper to make a poster, with one writing and others drawing. 4th: All students hold up their finished team project, each with a big smile on their faces.
|
||||
|
||||
【题目】
|
||||
1. How do you start a group project with your classmates?
|
||||
- 解析:'Let's plan it first and make a to-do list together.' 然后用这个开始描述你们的项目流程,也可以说说谁负责什么。
|
||||
|
||||
2. What happened when your team disagreed about something?
|
||||
- 解析:'They argued at first, and then we sat down and talked about it.' 描述一次团队有不同意见的经历,以及你们是怎么解决的。
|
||||
|
||||
3. What do you use to make your project look great?
|
||||
- 解析:'We'll use colourful paper and markers to make our poster stand out.' 说说你们用什么工具和材料让项目作品看起来更好。
|
||||
|
||||
4. What must everyone do to finish the project on time?
|
||||
- 解析:'Everyone must bring their part and help each other.' 解释团队合作中每个人需要做什么才能按时完成。
|
||||
|
||||
5. Tell us about a time your team did a really great job.
|
||||
- 解析:分享一次团队合作成功的经历。例如 'Last month, our team made a poster about saving water. We won the school prize, and I felt so proud of our teamwork.'"""
|
||||
S2_022201_T2 = """【题目描述】
|
||||
Now look at these pictures again. Think about a different project or situation and share more ideas about working with others.
|
||||
|
||||
【热词】
|
||||
plan,list,project,team,disagree,talk,together,poster,colourful,computer,work,help
|
||||
|
||||
【图片描述】
|
||||
Same images as above: students working on a school project together.
|
||||
|
||||
【题目】
|
||||
1. How do you plan a school party or event with your classmates?
|
||||
- 解析:'Let's plan the games first and make a decoration list together.' 分享你们如何组织一场活动或派对。
|
||||
|
||||
2. What did your friend do at first when things went wrong?
|
||||
- 解析:'They felt worried at first, and then we helped each other find a solution.' 说说当事情出错时你们是怎么一起面对的。
|
||||
|
||||
3. What tools or objects will you use to finish a big task?
|
||||
- 解析:'We will use a big calendar to plan our time and make sure we don't forget anything.' 说说你们计划用什么来高效完成任务。
|
||||
|
||||
4. What rules must everyone follow when working as a team?
|
||||
- 解析:'Everyone must listen to each other and share their ideas fairly.' 制定几条团队合作的基本规则。
|
||||
|
||||
5. What was the most fun thing you ever did together as a group?
|
||||
- 解析:分享一个有趣的团队经历。例如 'Last summer, our group cleaned the park near our school. After finishing, we had a small picnic together, and it was the most fun I have ever had with my classmates.'"""
|
||||
# Image prompts for 口语-P2 022201
|
||||
S2_022201_PIC = '[1-组图]:{"prompt_2":"黑白线条图:一组学生在教室里围坐在课桌前,桌上放着计划表和彩色铅笔,他们正在热烈讨论项目内容","prompt_3":"黑白线条图:两个学生面对面站着表情不悦,旁边一位老师弯腰用手势示意让他们一起合作","prompt_4":"黑白线条图:学生们使用笔记本电脑和彩纸制作展示海报,有人写字、有人画图,气氛热烈","prompt_5":"黑白线条图:所有学生一起举起完成的团队作品,每个人脸上带着成功的笑容"}'
|
||||
|
||||
# --- 口语-P1 022301: Responsibility ---
|
||||
S1_022301 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "duty,clean,tidy,classroom,follow,rules,safe,dangerous,environment,rubbish,stop,help,important,everyday",
|
||||
"questionSetID": "022301",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和做法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "Why should we take care of our school or neighbourhood?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "'It is our duty to keep our classroom clean and tidy.' 从这个角度说明为什么我们有责任维护身边的环境,可以举一个具体的例子。"
|
||||
},
|
||||
{
|
||||
"content": "What will happen if we don't follow the safety rules?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "'We must follow the safety rules, or our school will be dangerous for everyone.' 说明不遵守规则的后果。"
|
||||
},
|
||||
{
|
||||
"content": "What do we need to make people stop doing to protect the environment?",
|
||||
"ability": ["表达建议"],
|
||||
"explanation": "'We need to make people stop throwing rubbish on the ground.' 说出你认为需要改变的一种行为,并说明为什么。"
|
||||
},
|
||||
{
|
||||
"content": "What is one of the most important things we should do every day?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "'Helping others is one of the most important things we can do each day.' 用 '...is one of the...' 说出你认为每天最重要的事情之一。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "duty,home,help,parents,kind,classmates,rules,online,polite,best,ways,support,care,respect",
|
||||
"questionSetID": "022301",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实想法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What else is it our duty to do at home?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "说说你在家里有哪些责任。例如 'It is my duty to help my parents set the table for dinner every evening.'"
|
||||
},
|
||||
{
|
||||
"content": "Why must we be kind to our classmates?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "'We must be kind to our classmates, or our classroom will feel cold and unfriendly.' 说说友善对人的重要性。"
|
||||
},
|
||||
{
|
||||
"content": "What do we need to make people stop doing online?",
|
||||
"ability": ["表达建议"],
|
||||
"explanation": "'We need to make people stop saying unkind words online.' 说说网络上需要停止的不良行为。"
|
||||
},
|
||||
{
|
||||
"content": "What is one of the best ways to help your parents?",
|
||||
"ability": ["表达观点"],
|
||||
"explanation": "'Doing my homework without being asked is one of the best ways to help my parents.' 用 '...is one of the...' 分享帮助父母的好方法。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_022301_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和做法。
|
||||
|
||||
【热词】
|
||||
duty,clean,tidy,classroom,follow,rules,safe,dangerous,environment,rubbish,stop,important,everyday
|
||||
|
||||
【题目】
|
||||
1. Why should we take care of our school or neighbourhood?
|
||||
- 解析:'It is our duty to keep our classroom clean and tidy.' 从这个角度说明为什么我们有责任维护身边的环境,可以举一个具体的例子。
|
||||
|
||||
2. What will happen if we don't follow the safety rules?
|
||||
- 解析:'We must follow the safety rules, or our school will be dangerous for everyone.' 说明不遵守规则的后果。
|
||||
|
||||
3. What do we need to make people stop doing to protect the environment?
|
||||
- 解析:'We need to make people stop throwing rubbish on the ground.' 说出你认为需要改变的一种行为,并说明为什么。
|
||||
|
||||
4. What is one of the most important things we should do every day?
|
||||
- 解析:'Helping others is one of the most important things we can do each day.' 用 '...is one of the...' 说出你认为每天最重要的事情之一。"""
|
||||
S1_022301_T2 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实想法。
|
||||
|
||||
【热词】
|
||||
duty,home,help,parents,kind,classmates,rules,online,polite,best,ways,support,care,respect
|
||||
|
||||
【题目】
|
||||
1. What else is it our duty to do at home?
|
||||
- 解析:说说你在家里有哪些责任。例如 'It is my duty to help my parents set the table for dinner every evening.'
|
||||
|
||||
2. Why must we be kind to our classmates?
|
||||
- 解析:'We must be kind to our classmates, or our classroom will feel cold and unfriendly.' 说说友善对人的重要性。
|
||||
|
||||
3. What do we need to make people stop doing online?
|
||||
- 解析:'We need to make people stop saying unkind words online.' 说说网络上需要停止的不良行为。
|
||||
|
||||
4. What is one of the best ways to help your parents?
|
||||
- 解析:'Doing my homework without being asked is one of the best ways to help my parents.' 用 '...is one of the...' 分享帮助父母的好方法。"""
|
||||
|
||||
# --- 口语-P1 022401: Expressing yourself ---
|
||||
S1_022401 = {
|
||||
"first": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "want,only,draw,garden,park,understand,homework,first,start,plan,until,finish,turn,TV,game",
|
||||
"questionSetID": "022401",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和做法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "If you could choose one thing to do today, what would you want to do?",
|
||||
"ability": ["表达喜好"],
|
||||
"explanation": "'I only want to spend the afternoon drawing in the garden.' 说出你今天最想做的事,用 'I only want to...' 的句型。"
|
||||
},
|
||||
{
|
||||
"content": "Your friend wants to play but you have homework. What do you say?",
|
||||
"ability": ["协商表达"],
|
||||
"explanation": "'I understand you want to play, but we must finish our homework first.' 用 'I understand... but...' 来温和地说不。"
|
||||
},
|
||||
{
|
||||
"content": "How do you think we should start a big task?",
|
||||
"ability": ["表达建议"],
|
||||
"explanation": "'We should start by making a plan and getting all the things we need.' 用 'We should start by...' 说出你的建议。"
|
||||
},
|
||||
{
|
||||
"content": "What won't you do until you finish your work?",
|
||||
"ability": ["表达坚持"],
|
||||
"explanation": "'I won't turn on the TV until I have done all my homework.' 用 'I won't... until...' 说明你的坚持。"
|
||||
}
|
||||
]
|
||||
},
|
||||
"second": {
|
||||
"category": "speaking", "type": "speaking_qa",
|
||||
"asrPrompt": "weekend,only,relax,read,disagree,friend,listen,talk,start,new,skill,practise,until,ready,perform",
|
||||
"questionSetID": "022401",
|
||||
"textDesc": "请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实想法。",
|
||||
"questionSet": [
|
||||
{
|
||||
"content": "What is something you only want to do on the weekend?",
|
||||
"ability": ["表达喜好"],
|
||||
"explanation": "'On the weekend, I only want to relax and read my favourite books all morning.' 说说你只在周末想做的事。"
|
||||
},
|
||||
{
|
||||
"content": "When you disagree with a friend, how do you solve it?",
|
||||
"ability": ["协商表达"],
|
||||
"explanation": "'I understand you are angry, but we must listen to each other and talk about it.' 分享你处理分歧的方式。"
|
||||
},
|
||||
{
|
||||
"content": "How should we start when learning a new skill?",
|
||||
"ability": ["表达建议"],
|
||||
"explanation": "'We should start by watching someone else do it and then try it ourselves.' 用 'We should start by...' 分享学习方法。"
|
||||
},
|
||||
{
|
||||
"content": "What won't you do until you have practised enough?",
|
||||
"ability": ["表达坚持"],
|
||||
"explanation": "'I won't perform on the stage until I have practised my piece at least ten times.' 说说你需要充分练习才会去做的事。"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
S1_022401_T1 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享你的真实想法和做法。
|
||||
|
||||
【热词】
|
||||
want,only,draw,garden,park,understand,homework,first,start,plan,until,finish,TV,game
|
||||
|
||||
【题目】
|
||||
1. If you could choose one thing to do today, what would you want to do?
|
||||
- 解析:'I only want to spend the afternoon drawing in the garden.' 说出你今天最想做的事,用 'I only want to...' 的句型。
|
||||
|
||||
2. Your friend wants to play but you have homework. What do you say?
|
||||
- 解析:'I understand you want to play, but we must finish our homework first.' 用 'I understand... but...' 来温和地说不。
|
||||
|
||||
3. How do you think we should start a big task?
|
||||
- 解析:'We should start by making a plan and getting all the things we need.' 用 'We should start by...' 说出你的建议。
|
||||
|
||||
4. What won't you do until you finish your work?
|
||||
- 解析:'I won't turn on the TV until I have done all my homework.' 用 'I won't... until...' 说明你的坚持。"""
|
||||
S1_022401_T2 = """【题目描述】
|
||||
请回答以下问题。用清晰、完整的英文语句进行回答,分享更多你的真实想法。
|
||||
|
||||
【热词】
|
||||
weekend,only,relax,read,disagree,friend,listen,talk,start,new,skill,practise,until,ready,perform
|
||||
|
||||
【题目】
|
||||
1. What is something you only want to do on the weekend?
|
||||
- 解析:'On the weekend, I only want to relax and read my favourite books all morning.' 说说你只在周末想做的事。
|
||||
|
||||
2. When you disagree with a friend, how do you solve it?
|
||||
- 解析:'I understand you are angry, but we must listen to each other and talk about it.' 分享你处理分歧的方式。
|
||||
|
||||
3. How should we start when learning a new skill?
|
||||
- 解析:'We should start by watching someone else do it and then try it ourselves.' 用 'We should start by...' 分享学习方法。
|
||||
|
||||
4. What won't you do until you have practised enough?
|
||||
- 解析:'I won't perform on the stage until I have practised my piece at least ten times.' 说说你需要充分练习才会去做的事。"""
|
||||
|
||||
# ============================================================
|
||||
# MAIN: Create all 7 records
|
||||
# ============================================================
|
||||
def main():
|
||||
token = get_token()
|
||||
print("Token OK\n")
|
||||
|
||||
records = [
|
||||
# (label, table, QSID, jsonData, 题目1, 题目2, 图片描述, 题目1热词, 题目2热词)
|
||||
("写作 022101", "tblszuk1TeToofBF", "022101", W_022101, W_022101_T1, "", "", "", ""),
|
||||
("写作 022201", "tblszuk1TeToofBF", "022201", W_022201, W_022201_T1, "", "", "", ""),
|
||||
("写作 022301", "tblszuk1TeToofBF", "022301", W_022301, W_022301_T1, "", "", "", ""),
|
||||
("写作 022401", "tblszuk1TeToofBF", "022401", W_022401, W_022401_T1, "", "", "", ""),
|
||||
("口语-P1 022101", "tblRGv7k4WH58Jgq", "022101", S1_022101, S1_022101_T1, S1_022101_T2, "",
|
||||
"teacher,gave,seeds,garden,explained,moon,Earth,experiment,found",
|
||||
"gave,help,learn,explained,game,searching,found,brave,happy"),
|
||||
("口语-P2 022201", "tblGoWYBmVI0IrvQ", "022201", S2_022201, S2_022201_T1, S2_022201_T2,
|
||||
S2_022201_PIC, "", ""),
|
||||
("口语-P1 022301", "tblRGv7k4WH58Jgq", "022301", S1_022301, S1_022301_T1, S1_022301_T2, "",
|
||||
"duty,clean,tidy,classroom,follow,safe,rules,environment,rubbish,important",
|
||||
"duty,home,help,parents,kind,classmates,online,best,ways,support"),
|
||||
("口语-P1 022401", "tblRGv7k4WH58Jgq", "022401", S1_022401, S1_022401_T1, S1_022401_T2, "",
|
||||
"want,only,draw,garden,understand,homework,start,plan,until,finish,TV",
|
||||
"weekend,only,relax,disagree,friend,listen,start,new,skill,practise,until"),
|
||||
]
|
||||
|
||||
results = []
|
||||
for label, tid, qsid, jd, t1, t2, pic, kw1, kw2 in records:
|
||||
fields = {
|
||||
"题目集合 ID": qsid,
|
||||
"dataStatus": "0",
|
||||
"jsonData": json.dumps(jd, ensure_ascii=False),
|
||||
"题目1": t1,
|
||||
}
|
||||
if t2:
|
||||
fields["题目2"] = t2
|
||||
if pic:
|
||||
fields["图片描述"] = pic
|
||||
if kw1:
|
||||
fields["题目1热词"] = kw1
|
||||
if kw2:
|
||||
fields["题目2热词"] = kw2
|
||||
|
||||
resp = create_record(token, tid, fields)
|
||||
code = resp.get("code")
|
||||
if code == 0:
|
||||
rid = resp["data"]["record"]["record_id"]
|
||||
# Verify
|
||||
time.sleep(0.5)
|
||||
v = verify(token, tid, rid, qsid)
|
||||
print(f"[{'✅' if '✅' in v else '❌'}] {label} → {rid}")
|
||||
print(f" {v}")
|
||||
results.append((label, qsid, rid, "✅" in v))
|
||||
else:
|
||||
print(f"[❌] {label} FAILED: code={code} msg={resp.get('msg')}")
|
||||
results.append((label, qsid, "FAIL", False))
|
||||
|
||||
# Summary
|
||||
ok = sum(1 for r in results if r[3])
|
||||
print(f"\n=== 完成: {ok}/{len(results)} 条创建成功 ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
186
scripts/write_audit_results.py
Normal file
186
scripts/write_audit_results.py
Normal file
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
将审校结果写回单元挑战多维表格的"审校结果"列
|
||||
"""
|
||||
import json, subprocess, os, sys
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WORKSPACE = os.path.dirname(SCRIPT_DIR)
|
||||
BITABLE_SCRIPT = os.path.join(WORKSPACE, "skills/lark_bitable_operate_as_bot/scripts/operate_bitable.sh")
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
|
||||
TABLES = {
|
||||
"听力-P1-图片选择题": "tbliZAhcc9C43B23",
|
||||
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
|
||||
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
|
||||
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
|
||||
"听力-P6-听力选图": "tbloiMcD0sBtGSTq",
|
||||
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
|
||||
}
|
||||
|
||||
KNOWN_ABILITY_LABELS = {
|
||||
"显性事实理解|关键词识别",
|
||||
"显性事实理解|单句信息点抓取",
|
||||
"显性细节理解|数字/时间/地点",
|
||||
"多特征整合",
|
||||
"语用推断",
|
||||
"干扰抑制|多信息筛选",
|
||||
"多句保持|信息整合",
|
||||
"语用推断|否定与纠错",
|
||||
"听觉抓取关键信息",
|
||||
"问题意图识别",
|
||||
"关键细节听辨",
|
||||
"图像语义对齐",
|
||||
"近义改写",
|
||||
"否定与纠错",
|
||||
}
|
||||
|
||||
def fetch_all():
|
||||
all_recs = {}
|
||||
for tname, tid in TABLES.items():
|
||||
result = subprocess.run(
|
||||
["bash", BITABLE_SCRIPT, "list_records", APP_TOKEN, tid, "200"],
|
||||
capture_output=True, text=True, timeout=60
|
||||
)
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
if data.get("code") == 0:
|
||||
all_recs[tname] = data["data"]["items"]
|
||||
except:
|
||||
all_recs[tname] = []
|
||||
return all_recs
|
||||
|
||||
def audit_record(rec):
|
||||
"""Returns (result_text, has_errors)"""
|
||||
issues = []
|
||||
fields = rec.get("fields", {})
|
||||
jd_raw = fields.get("jsonData")
|
||||
qs_id = fields.get("题目集合 ID", "")
|
||||
|
||||
if not jd_raw:
|
||||
return None, False # empty record, skip
|
||||
|
||||
try:
|
||||
parsed = json.loads(jd_raw)
|
||||
except json.JSONDecodeError as e:
|
||||
return f"❌ jsonData JSON解析失败: {e}", True
|
||||
|
||||
first = parsed.get("first", {})
|
||||
second = parsed.get("second", {})
|
||||
qtype = first.get("type", "unknown")
|
||||
f_qsid = first.get("questionSetID", "")
|
||||
s_qsid = second.get("questionSetID", "")
|
||||
|
||||
# Check questionSetID consistency
|
||||
if qs_id and f_qsid and f_qsid != qs_id:
|
||||
issues.append(f" ❌ first questionSetID({f_qsid})与字段'题目集合 ID'({qs_id})不一致")
|
||||
if qs_id and s_qsid and s_qsid != qs_id:
|
||||
issues.append(f" ❌ second questionSetID({s_qsid})与字段'题目集合 ID'({qs_id})不一致")
|
||||
|
||||
if f_qsid == "000001":
|
||||
issues.append(f" ❌ questionSetID为000001(占位数据)")
|
||||
|
||||
if qs_id and not qs_id.isdigit():
|
||||
issues.append(f" ❌ 题目集合 ID异常: '{qs_id}'")
|
||||
|
||||
# Check each block
|
||||
for bname, block in [("first", first), ("second", second)]:
|
||||
qs = block.get("questionSet", [])
|
||||
if not isinstance(qs, list) or len(qs) == 0:
|
||||
if block: # non-empty block
|
||||
issues.append(f" ❌ {bname}.questionSet为空")
|
||||
continue
|
||||
|
||||
for i, q in enumerate(qs):
|
||||
# explanation
|
||||
expl = q.get("explanation", "")
|
||||
if not expl or expl.strip() == "":
|
||||
issues.append(f" ❌ {bname}[{i}]: explanation为空")
|
||||
elif len(expl) < 20:
|
||||
issues.append(f" 🟡 {bname}[{i}]: explanation过短({len(expl)}字)")
|
||||
|
||||
# ability
|
||||
ability = q.get("ability", [])
|
||||
if not ability:
|
||||
issues.append(f" ❌ {bname}[{i}]: ability为空")
|
||||
else:
|
||||
for a in ability:
|
||||
if isinstance(a, str) and "¥¥" in a:
|
||||
issues.append(f" ❌ {bname}[{i}]: ability使用¥¥分隔符: '{a[:60]}...'")
|
||||
break
|
||||
if isinstance(a, str) and a not in KNOWN_ABILITY_LABELS:
|
||||
if "|" not in a and len(a) > 5:
|
||||
issues.append(f" 🟡 {bname}[{i}]: ability非标准: '{a}'")
|
||||
|
||||
# Check text fields
|
||||
text1 = None
|
||||
text2 = None
|
||||
for k in ["题目1 完整配置", "题目1", "题目完整配置"]:
|
||||
if fields.get(k):
|
||||
text1 = fields[k]
|
||||
break
|
||||
for k in ["题目2 完整配置", "题目2"]:
|
||||
if fields.get(k):
|
||||
text2 = fields[k]
|
||||
break
|
||||
|
||||
if not text1:
|
||||
issues.append(f" ❌ 题目1文本字段为空")
|
||||
if second and second.get("questionSet") and not text2:
|
||||
issues.append(f" 🟡 题目2文本字段为空(但jsonData有second块)")
|
||||
|
||||
if not issues:
|
||||
return f"✅ 审校通过\n题型:{qtype} | 题组:first={len(first.get('questionSet',[]))}题 second={len(second.get('questionSet',[]))}题", False
|
||||
else:
|
||||
header = f"❌ 审校发现问题({len(issues)}项)\n题型:{qtype} | 题组:first={len(first.get('questionSet',[]))}题 second={len(second.get('questionSet',[]))}题\n"
|
||||
return header + "\n".join(issues), True
|
||||
|
||||
def write_result(table_id, record_id, result_text):
|
||||
"""Write audit result to bitable"""
|
||||
payload = json.dumps({"审校结果": result_text})
|
||||
result = subprocess.run(
|
||||
["bash", BITABLE_SCRIPT, "update_record", APP_TOKEN, table_id, record_id, payload],
|
||||
capture_output=True, text=True, timeout=30
|
||||
)
|
||||
return "success" in result.stdout
|
||||
|
||||
def main():
|
||||
all_recs = fetch_all()
|
||||
total_err = 0
|
||||
total_ok = 0
|
||||
total_skipped = 0
|
||||
|
||||
for tname, records in all_recs.items():
|
||||
tid = TABLES[tname]
|
||||
print(f"\n--- {tname} ---")
|
||||
|
||||
for rec in records:
|
||||
rid = rec["record_id"]
|
||||
fields = rec.get("fields", {})
|
||||
ds = fields.get("dataStatus")
|
||||
|
||||
if ds != "0" or not fields.get("jsonData"):
|
||||
total_skipped += 1
|
||||
continue
|
||||
|
||||
result_text, has_err = audit_record(rec)
|
||||
if result_text is None:
|
||||
total_skipped += 1
|
||||
continue
|
||||
|
||||
# Write result
|
||||
ok = write_result(tid, rid, result_text)
|
||||
status = "✅" if ok else "❌写入失败"
|
||||
label = "🔴" if has_err else "✅"
|
||||
print(f" {label} {rid}: {status}")
|
||||
|
||||
if has_err:
|
||||
total_err += 1
|
||||
else:
|
||||
total_ok += 1
|
||||
|
||||
print(f"\n{'='*40}")
|
||||
print(f"汇总: ✅通过={total_ok}, 🔴问题={total_err}, ⏭️跳过={total_skipped}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
176
scripts/write_audit_results_v2.py
Normal file
176
scripts/write_audit_results_v2.py
Normal file
@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
直接通过Python requests将审校结果写回单元挑战多维表格
|
||||
"""
|
||||
import json, requests, sys, os
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
BASE = "https://open.feishu.cn/open-apis/bitable/v1"
|
||||
|
||||
TABLES = {
|
||||
"听力-P1-图片选择题": "tbliZAhcc9C43B23",
|
||||
"听力-P2-表格填空题": "tblzTLNH7f13uWQN",
|
||||
"听力-P4-短对话选择题": "tblVmeDtBDKsAEfz",
|
||||
"听力-P5-信息匹配题": "tblDssVmhGzc3UKd",
|
||||
"听力-P6-听力选图": "tbloiMcD0sBtGSTq",
|
||||
"听力-P7-听力拖拽": "tbly9SvPEa44k3yX",
|
||||
}
|
||||
|
||||
KNOWN_ABILITY_LABELS = {
|
||||
"显性事实理解|关键词识别", "显性事实理解|单句信息点抓取",
|
||||
"显性细节理解|数字/时间/地点", "多特征整合", "语用推断",
|
||||
"干扰抑制|多信息筛选", "多句保持|信息整合",
|
||||
"语用推断|否定与纠错", "听觉抓取关键信息",
|
||||
"问题意图识别", "关键细节听辨", "图像语义对齐",
|
||||
"近义改写", "否定与纠错",
|
||||
}
|
||||
|
||||
def get_token():
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET})
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def fetch_records(token, table_id):
|
||||
all_items = []
|
||||
page_token = None
|
||||
while True:
|
||||
url = f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records?page_size=200"
|
||||
if page_token:
|
||||
url += f"&page_token={page_token}"
|
||||
r = requests.get(url, headers={"Authorization": f"Bearer {token}"})
|
||||
data = r.json()
|
||||
if data.get("code") != 0:
|
||||
print(f" Fetch error: {data}", file=sys.stderr)
|
||||
break
|
||||
all_items.extend(data["data"]["items"])
|
||||
if not data["data"].get("has_more"):
|
||||
break
|
||||
page_token = data["data"].get("page_token")
|
||||
return all_items
|
||||
|
||||
def write_record(token, table_id, record_id, result_text):
|
||||
r = requests.put(
|
||||
f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records/{record_id}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
json={"fields": {"审校结果": result_text}}
|
||||
)
|
||||
data = r.json()
|
||||
return data.get("code") == 0
|
||||
|
||||
def audit_record(rec):
|
||||
issues = []
|
||||
fields = rec.get("fields", {})
|
||||
jd_raw = fields.get("jsonData")
|
||||
qs_id = fields.get("题目集合 ID", "")
|
||||
|
||||
if not jd_raw:
|
||||
return None, False
|
||||
|
||||
try:
|
||||
parsed = json.loads(jd_raw)
|
||||
except:
|
||||
return "❌ jsonData JSON解析失败", True
|
||||
|
||||
first = parsed.get("first", {})
|
||||
second = parsed.get("second", {})
|
||||
qtype = first.get("type", "unknown")
|
||||
f_qsid = first.get("questionSetID", "")
|
||||
s_qsid = second.get("questionSetID", "")
|
||||
|
||||
if qs_id and f_qsid and f_qsid != qs_id:
|
||||
issues.append(f" ❌ first questionSetID({f_qsid})与字段({qs_id})不一致")
|
||||
if qs_id and s_qsid and s_qsid != qs_id:
|
||||
issues.append(f" ❌ second questionSetID({s_qsid})与字段({qs_id})不一致")
|
||||
if f_qsid == "000001":
|
||||
issues.append(f" ❌ questionSetID为000001(占位数据)")
|
||||
if qs_id and not qs_id.replace("-","").isdigit() and qs_id != "000001":
|
||||
issues.append(f" ❌ 题目集合 ID异常: '{qs_id}'")
|
||||
|
||||
for bname, block in [("first", first), ("second", second)]:
|
||||
qs = block.get("questionSet", [])
|
||||
if not isinstance(qs, list) or len(qs) == 0:
|
||||
continue
|
||||
|
||||
for i, q in enumerate(qs):
|
||||
expl = q.get("explanation", "")
|
||||
if not expl or expl.strip() == "":
|
||||
issues.append(f" ❌ {bname}[{i}]: explanation为空")
|
||||
elif len(expl) < 20:
|
||||
issues.append(f" 🟡 {bname}[{i}]: explanation过短({len(expl)}字)")
|
||||
|
||||
ability = q.get("ability", [])
|
||||
if not ability:
|
||||
issues.append(f" ❌ {bname}[{i}]: ability为空")
|
||||
else:
|
||||
found_bad_sep = False
|
||||
for a in ability:
|
||||
if isinstance(a, str) and "¥¥" in a:
|
||||
if not found_bad_sep:
|
||||
issues.append(f" ❌ {bname}[{i}]: ability用¥¥分隔(应为逗号)")
|
||||
found_bad_sep = True
|
||||
|
||||
text1 = None
|
||||
text2 = None
|
||||
for k in ["题目1 完整配置", "题目1", "题目完整配置"]:
|
||||
if fields.get(k):
|
||||
text1 = fields[k]
|
||||
break
|
||||
for k in ["题目2 完整配置", "题目2"]:
|
||||
if fields.get(k):
|
||||
text2 = fields[k]
|
||||
break
|
||||
|
||||
if not text1:
|
||||
issues.append(f" ❌ 题目1文本字段为空")
|
||||
if second and second.get("questionSet") and not text2:
|
||||
issues.append(f" 🟡 题目2文本字段为空(但jsonData有second)")
|
||||
|
||||
if not issues:
|
||||
return f"✅ 审校通过\n题型:{qtype} | 题组:first={len(first.get('questionSet',[]))}题 second={len(second.get('questionSet',[]))}题", False
|
||||
else:
|
||||
return f"❌ 审校发现问题({len(issues)}项)\n题型:{qtype} | 题组:first={len(first.get('questionSet',[]))}题 second={len(second.get('questionSet',[]))}题\n" + "\n".join(issues), True
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
print(f"Token获取成功")
|
||||
|
||||
total_err = total_ok = total_skip = 0
|
||||
|
||||
for tname, tid in TABLES.items():
|
||||
print(f"\n--- {tname} ---")
|
||||
records = fetch_records(token, tid)
|
||||
|
||||
for rec in records:
|
||||
rid = rec["record_id"]
|
||||
fields = rec.get("fields", {})
|
||||
ds = fields.get("dataStatus")
|
||||
|
||||
if ds != "0" or not fields.get("jsonData"):
|
||||
total_skip += 1
|
||||
continue
|
||||
|
||||
result_text, has_err = audit_record(rec)
|
||||
if result_text is None:
|
||||
total_skip += 1
|
||||
continue
|
||||
|
||||
if write_record(token, tid, rid, result_text):
|
||||
tag = "🔴" if has_err else "✅"
|
||||
print(f" {tag} {rid} ✓")
|
||||
if has_err:
|
||||
total_err += 1
|
||||
else:
|
||||
total_ok += 1
|
||||
else:
|
||||
print(f" ❌ {rid} 写入失败")
|
||||
|
||||
print(f"\n{'='*40}")
|
||||
print(f"✅通过={total_ok}, 🔴问题={total_err}, ⏭️跳过={total_skip}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
142
scripts/write_audit_results_v3.py
Normal file
142
scripts/write_audit_results_v3.py
Normal file
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python3
|
||||
"""写审校结果到单元挑战听力表"""
|
||||
import requests, json, sys, time
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
|
||||
BASE = "https://open.feishu.cn/open-apis/bitable/v1"
|
||||
|
||||
TABLES = [
|
||||
("听力-P1-图片选择题", "tbliZAhcc9C43B23"),
|
||||
("听力-P2-表格填空题", "tblzTLNH7f13uWQN"),
|
||||
("听力-P4-短对话选择题", "tblVmeDtBDKsAEfz"),
|
||||
("听力-P5-信息匹配题", "tblDssVmhGzc3UKd"),
|
||||
("听力-P6-听力选图", "tbloiMcD0sBtGSTq"),
|
||||
("听力-P7-听力拖拽", "tbly9SvPEa44k3yX"),
|
||||
]
|
||||
|
||||
def get_token():
|
||||
r = requests.post(
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10
|
||||
)
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def fetch_all(token, table_id):
|
||||
items = []
|
||||
pt = None
|
||||
while True:
|
||||
url = f"{BASE}/apps/{APP_TOKEN}/tables/{table_id}/records?page_size=200"
|
||||
if pt:
|
||||
url += f"&page_token={pt}"
|
||||
r = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
|
||||
d = r.json()
|
||||
if d.get("code") != 0:
|
||||
print(f" fetch error: {d.get('msg')}", file=sys.stderr)
|
||||
break
|
||||
items.extend(d["data"]["items"])
|
||||
if not d["data"].get("has_more"):
|
||||
break
|
||||
pt = d["data"].get("page_token")
|
||||
return items
|
||||
|
||||
def audit(rec):
|
||||
issues = []
|
||||
fld = rec.get("fields", {})
|
||||
jd = fld.get("jsonData")
|
||||
qsid = fld.get("题目集合 ID", "")
|
||||
if not jd:
|
||||
return None
|
||||
try:
|
||||
p = json.loads(jd)
|
||||
except:
|
||||
return ("❌ jsonData解析失败", True)
|
||||
|
||||
f = p.get("first", {})
|
||||
s = p.get("second", {})
|
||||
qt = f.get("type", "?")
|
||||
fq = f.get("questionSetID", "")
|
||||
sq = s.get("questionSetID", "")
|
||||
|
||||
if qsid and fq and fq != qsid:
|
||||
issues.append(f" ❌ first QSID({fq})≠字段({qsid})")
|
||||
if qsid and sq and sq != qsid:
|
||||
issues.append(f" ❌ second QSID({sq})≠字段({qsid})")
|
||||
if fq == "000001":
|
||||
issues.append(f" ❌ QSID=000001")
|
||||
if qsid and not qsid.replace("-","").isdigit() and qsid != "000001":
|
||||
issues.append(f" ❌ QSID异常:'{qsid}'")
|
||||
|
||||
for bn, blk in [("first", f), ("second", s)]:
|
||||
qs = blk.get("questionSet", [])
|
||||
if not isinstance(qs, list) or not qs:
|
||||
continue
|
||||
for i, q in enumerate(qs):
|
||||
e = q.get("explanation", "")
|
||||
if not e or not e.strip():
|
||||
issues.append(f" ❌ {bn}[{i}]: explanation空")
|
||||
elif len(e) < 20:
|
||||
issues.append(f" 🟡 {bn}[{i}]: explanation短({len(e)}字)")
|
||||
ab = q.get("ability", [])
|
||||
if not ab:
|
||||
issues.append(f" ❌ {bn}[{i}]: ability空")
|
||||
else:
|
||||
for a in ab:
|
||||
if isinstance(a, str) and "¥¥" in a:
|
||||
issues.append(f" ❌ {bn}[{i}]: ability¥¥分隔")
|
||||
break
|
||||
|
||||
t1 = fld.get("题目1 完整配置") or fld.get("题目1") or fld.get("题目完整配置")
|
||||
t2 = fld.get("题目2 完整配置") or fld.get("题目2")
|
||||
if not t1:
|
||||
issues.append(f" ❌ 题目1字段空")
|
||||
if s and s.get("questionSet") and not t2:
|
||||
issues.append(f" 🟡 题目2字段空")
|
||||
|
||||
if not issues:
|
||||
return (f"✅ 审校通过\n题型:{qt} | first={len(f.get('questionSet',[]))}题 second={len(s.get('questionSet',[]))}题", False)
|
||||
hdr = f"❌ 审校发现问题({len(issues)}项)\n题型:{qt} | first={len(f.get('questionSet',[]))}题 second={len(s.get('questionSet',[]))}题\n"
|
||||
return (hdr + "\n".join(issues), True)
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
print(f"✅ Token OK")
|
||||
|
||||
err = ok = skip = 0
|
||||
for tname, tid in TABLES:
|
||||
print(f"\n📋 {tname}", flush=True)
|
||||
recs = fetch_all(token, tid)
|
||||
print(f" 记录:{len(recs)}", flush=True)
|
||||
|
||||
for rec in recs:
|
||||
rid = rec["record_id"]
|
||||
fld = rec.get("fields", {})
|
||||
if fld.get("dataStatus") != "0" or not fld.get("jsonData"):
|
||||
skip += 1
|
||||
continue
|
||||
|
||||
r = audit(rec)
|
||||
if r is None:
|
||||
skip += 1
|
||||
continue
|
||||
txt, has_err = r
|
||||
|
||||
r2 = requests.put(
|
||||
f"{BASE}/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"fields": {"审校结果": txt}}, timeout=15
|
||||
)
|
||||
if r2.json().get("code") == 0:
|
||||
tag = "🔴" if has_err else "✅"
|
||||
print(f" {tag} {rid}", flush=True)
|
||||
if has_err: err += 1
|
||||
else: ok += 1
|
||||
else:
|
||||
print(f" ❌ {rid} write fail: {r2.json().get('msg')}", flush=True)
|
||||
time.sleep(0.08) # rate limit
|
||||
|
||||
print(f"\n✅={ok} 🔴={err} ⏭️={skip}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user