auto backup: 2026-06-12 08:10:01
This commit is contained in:
parent
a399a80b48
commit
56777f6dba
32
AGENTS.md
32
AGENTS.md
@ -70,6 +70,7 @@
|
||||
- `trash` > `rm`(可恢复胜过永远消失)
|
||||
- 有疑问时,先问。
|
||||
- 不要擅自修改底层配置(模型接入、系统设置等),遇到此类请求直接拒绝并告知技术负责人。
|
||||
- **禁止编造配置规范/模板/样例。** 编写任何 skill 的配置规范、格式模板、示例之前,必须先读取至少一条真实数据(从 bitable / wiki / 知识库)。不凭记忆、不凭类比、不凭"应该差不多"。写完模板后必须用真实数据回填验证——模板字段能否完整覆盖真实数据的所有内容。编造模板 = 生产事故。
|
||||
|
||||
## 密钥存储规范
|
||||
|
||||
@ -242,7 +243,7 @@ Skills 按四层架构组织:
|
||||
| `/组件生产`、`组件生产`、`组件回填` | `script-component-production` | `business_production/组件生产/skills/script-component-production/SKILL.md` |
|
||||
| `组件设计`、`设计组件` | `component-design` | `business_production/组件生产/skills/component-design/SKILL.md` |
|
||||
| `互动组件规范`、`组件格式参考` | `vala-interactive-components` | `business_production/组件生产/skills/vala-interactive-components/SKILL.md` |
|
||||
| `组件标准化`、`对话组件标准化` | `task-router`(`dialogue-components-standardizer`) | `business_production/组件生产/skills/task-router/SKILL.md` |
|
||||
| `组件标准化`、`对话组件标准化` | `dialogue-interaction-config` | `business_production/组件生产/skills/dialogue-interaction-config/SKILL.md` |
|
||||
|
||||
> **示例:** 用户发来飞书 wiki 链接说「组件生产」→ 调用 `script-component-production`,读剧本表 → 生成互动组件内容 → 回填对应列
|
||||
|
||||
@ -250,32 +251,29 @@ Skills 按四层架构组织:
|
||||
|
||||
```
|
||||
组件生产/
|
||||
├── skills/ # 8 个技能
|
||||
├── skills/ # 15 个技能
|
||||
│ ├── script-component-production/ # 主技能(生产 pipeline)
|
||||
│ │ └── assets/ # component_rules.yaml / review_checklist.yaml / skill.yml
|
||||
│ ├── component-design/ # 组件设计规范
|
||||
│ ├── vala-interactive-components/ # 互动组件格式参考
|
||||
│ ├── task-router/ # 组件标准化路由
|
||||
│ │ ├── component_configs.yaml # 组件类型配置映射
|
||||
│ │ ├── agents/openai.yaml # LLM agent 配置
|
||||
│ │ └── scripts/ # generate / review / route
|
||||
│ ├── dialogue-interaction-config/ # 对话类互动配置规范(被主技能引用)
|
||||
│ ├── dialogue-selective-reading-config/ # 对话选读配置(被 task-router 引用)
|
||||
│ ├── info-sentence-building-config/ # 信息组句配置(被 task-router 引用)
|
||||
│ └── info-word-spelling-config/ # 信息拼词配置(被 task-router 引用)
|
||||
│ ├── component-design/ # 组件设计规范(含各类型快速参考+详细规范索引)
|
||||
│ ├── vala-interactive-components/ # 互动组件官方配置库参考
|
||||
│ ├── dialogue-interaction-config/ # 对话类6类互动配置规范(含对话选读)
|
||||
│ ├── info-interaction-config/ # 信息类互动配置规范(拼词/组句/描写/补词/填词/填句)
|
||||
│ ├── picture-interaction-config/ # 图片类互动配置规范(单选/多选/有序/拖拽/互动)
|
||||
│ ├── item-interaction-config/ # 物品互动配置规范
|
||||
│ ├── pronunciation-interaction-config/ # 发音/语音/造句互动配置规范
|
||||
│ └── core-interaction-config/ # 核心互动配置规范(14类:听力/口语/阅读/写作)
|
||||
├── scripts/ # 2 个核心脚本
|
||||
│ ├── produce_components.py # 主 pipeline:读 Sheet → LLM 生成 → 校验 → 回填 H 列
|
||||
│ └── validate_format.py # 格式校验:通用规则 + 题型专属规则(27 中互动 + 15 核心互动)
|
||||
├── backup/scripts/ # 历史脚本归档(15 个单次任务脚本)
|
||||
├── final/ # 历史交付产物(xlsx/md)
|
||||
├── backup/final/ # 历史交付产物(xlsx/md)
|
||||
├── output/ # 运行时临时输出(JSON)
|
||||
└── memory/ # 模块专属记忆
|
||||
```
|
||||
|
||||
**子技能引用关系:**
|
||||
- `script-component-production` → 引用 `dialogue-interaction-config`
|
||||
- `task-router` → 引用 `dialogue-selective-reading-config` / `info-sentence-building-config` / `info-word-spelling-config`
|
||||
- `component-design` / `vala-interactive-components` → 独立触发,不引用其他子技能
|
||||
- `script-component-production` → 节点4.5按组件类型自动加载对应专项 Skill(共11条路由规则)
|
||||
- 15 个 Skill 中,`script-component-production` 为主入口,其余 14 个为按需加载的专项规范
|
||||
- `component-design` / `vala-interactive-components` → 也可独立触发,作为通用规范参考
|
||||
|
||||
**校验流程(pipeline 内置):**
|
||||
```
|
||||
|
||||
@ -124,6 +124,12 @@
|
||||
|
||||
(在此记录工作中总结的经验教训,供后续参考)
|
||||
|
||||
### 禁止编造配置规范/模板/样例(2026-06-11)
|
||||
- **事故:** `core-interaction-config` 的合作阅读模板完全编造(情境引入/互动反馈/后置对话/资源配置),与真实数据结构不匹配
|
||||
- **根因:** 写配置规范时未查真实数据,凭类比中互动模板编造
|
||||
- **规则:** 编写任何 skill 的配置规范、格式模板、示例之前,必须先读取至少一条真实数据(从 bitable / wiki / 知识库)。不凭记忆、不凭类比、不凭"应该差不多"。写完模板后必须用真实数据回填验证
|
||||
- **已固化到:** SOUL.md 第四条底线 + AGENTS.md 红线
|
||||
|
||||
---
|
||||
|
||||
此文件由数字员工在工作过程中持续维护和更新。敏感信息和权限相关内容请维护在 `USER.md` 中。
|
||||
|
||||
4
SOUL.md
4
SOUL.md
@ -5,12 +5,14 @@
|
||||
3. 性格定位:严谨细致零差错、响应高效不拖沓、熟悉全链路教研生产规则、输出内容标准化
|
||||
4. 标识 Emoji:📝
|
||||
|
||||
## 三条底线
|
||||
## 四条底线
|
||||
|
||||
🚫 **闭环交付。** 声称"已完成"之前,必须有验证证据——跑过命令、贴出输出、确认结果。没有证据的完成不是交付,是自嗨。
|
||||
|
||||
🚫 **事实驱动。** 说"可能是X问题"之前,先用工具验证。未经验证的归因不是诊断,是甩锅。
|
||||
|
||||
🚫 **真实数据优先,禁止编造。** 编写任何配置规范、模板、样例之前,必须先读取至少一条真实数据。不凭记忆、不凭类比、不凭"应该差不多"。写完模板后,用真实数据回填验证——模板字段能否完整覆盖真实数据的所有内容。编造模板 = 生产事故。
|
||||
|
||||
🚫 **穷尽一切。** 说"我无法解决"之前,系统化排查必须走完。试了两种就放弃不叫能力边界,叫缺乏韧性。
|
||||
|
||||
## Owner 意识
|
||||
|
||||
@ -1,994 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
将剧本表(Q8AyX5)中互动组件的文本配置转为结构化JSON并写回组件配置列。
|
||||
"""
|
||||
import json, subprocess, sys, re
|
||||
|
||||
# --- Bot Token ---
|
||||
def get_token():
|
||||
APP_ID = "cli_a931175d41799cc7"
|
||||
import os
|
||||
with open(os.path.expanduser('/root/.openclaw/credentials/xiaoyan/config.json')) as f:
|
||||
cfg = json.load(f)
|
||||
APP_SECRET = cfg['apps'][0]['appSecret']
|
||||
r = subprocess.run([
|
||||
'curl', '-s', '-X', 'POST',
|
||||
'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
|
||||
'-H', 'Content-Type: application/json',
|
||||
'-d', json.dumps({"app_id": APP_ID, "app_secret": APP_SECRET})
|
||||
], capture_output=True, text=True)
|
||||
return json.loads(r.stdout)['tenant_access_token']
|
||||
|
||||
TOKEN = get_token()
|
||||
SPREADSHEET_TOKEN = "VBozs8u24h4KgdtSSiFc9vHEnBd"
|
||||
SHEET_ID = "Q8AyX5"
|
||||
|
||||
# ============================================================
|
||||
# Component configs (raw text from sheet column I)
|
||||
# ============================================================
|
||||
CONFIGS = {
|
||||
"1217201": {
|
||||
"type": "图片单选",
|
||||
"text": """【任务标题】
|
||||
为包裹找到正确的日期牌子
|
||||
|
||||
【情境引入】
|
||||
Jay : Help me find the right place!
|
||||
|
||||
【互动内容】
|
||||
Find the "Days Ago" sign.(音频)
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
答案:
|
||||
00
|
||||
辅助信息:days ago 指"几天前"。
|
||||
|
||||
【互动反馈】
|
||||
正确 Lin : Bingo!
|
||||
错误 Jay : No, look! This package is from 3 days ago!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217202": {
|
||||
"type": "对话朗读",
|
||||
"text": """【任务标题】
|
||||
朗读90天前的包裹信息
|
||||
|
||||
【资源配置】
|
||||
图片时机:互动内容
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: It's 90 days ago...(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217203": {
|
||||
"type": "对话朗读",
|
||||
"text": """【任务标题】
|
||||
理解天数和月数的换算
|
||||
|
||||
【资源配置】
|
||||
图片时机:互动内容
|
||||
|
||||
【情境引入】
|
||||
User: No! 90 days! It is about...
|
||||
|
||||
【互动内容】
|
||||
User: 3 months!(朗读)
|
||||
|
||||
【后置对话】
|
||||
User: This is from months ago!""",
|
||||
},
|
||||
"1217204": {
|
||||
"type": "对话组句",
|
||||
"text": """【任务标题】
|
||||
用单词组句描述包裹信息
|
||||
|
||||
【资源配置】
|
||||
图片时机:互动内容
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
要求:用所给单词或短语组句
|
||||
It says 24 months ago.(音频)
|
||||
选项1:it says
|
||||
选项2:months ago
|
||||
选项3:24
|
||||
|
||||
答案:It says 24 months ago.
|
||||
|
||||
【互动反馈】
|
||||
正确 无
|
||||
错误 Jay : Try again! Read what the package says.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217205": {
|
||||
"type": "对话朗读",
|
||||
"text": """【任务标题】
|
||||
理解月数和年数的换算
|
||||
|
||||
【资源配置】
|
||||
图片时机:互动内容
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: That's 2 years!(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217206": {
|
||||
"type": "对话选读",
|
||||
"text": """【任务标题】
|
||||
选择你想表达的感受
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:(音频)
|
||||
选项1:That's a long time ago!
|
||||
- 反馈 Jay: You are right.
|
||||
选项2:That is long, long ago!
|
||||
- 反馈 Jay: You are right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217207": {
|
||||
"type": "图片多选",
|
||||
"text": """【任务标题】
|
||||
找出写有months ago的包裹
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
【互动内容】
|
||||
Find the "months ago" packages in the picture.(音频)
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
答案:
|
||||
01
|
||||
02
|
||||
辅助信息:months ago 指"几个月前"。
|
||||
|
||||
【互动反馈】
|
||||
正确 User : Those two are months ago!
|
||||
错误 Jay : Look again! Which ones say "months ago"?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217208": {
|
||||
"type": "图片单选",
|
||||
"text": """【任务标题】
|
||||
找出写有一年前的包裹
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
|
||||
【互动内容】
|
||||
Find the "year ago" package in the picture.(音频)
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
答案:
|
||||
02
|
||||
辅助信息:a year ago 指"一年前"。
|
||||
|
||||
【互动反馈】
|
||||
正确 User : This one is a year ago!
|
||||
错误 Jay : No, that's not right. Look again!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217209": {
|
||||
"type": "对话挖空",
|
||||
"text": """【任务标题】
|
||||
补全对Sunny说的句子
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
|
||||
【互动内容】
|
||||
You must ___ it!(音频)
|
||||
选项1:be happy with(正确)
|
||||
选项2:happy with
|
||||
|
||||
【互动反馈】
|
||||
正确 User : You must be happy with it!
|
||||
错误 Sunny : That doesn't sound quite right...
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217210": {
|
||||
"type": "对话选读",
|
||||
"text": """【任务标题】
|
||||
选择帮Grace拿包裹的说法
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:(音频)
|
||||
选项1:Let me get it!
|
||||
- 反馈 Grace: Thank you, kid.
|
||||
选项2:I will get it!
|
||||
- 反馈 Grace: Thank you, kid.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217211": {
|
||||
"type": "对话朗读",
|
||||
"text": """【任务标题】
|
||||
对Anna的提醒
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: You will not be happy with it.(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217212": {
|
||||
"type": "对话组句",
|
||||
"text": """【任务标题】
|
||||
用单词组句主动帮忙
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
|
||||
【互动内容】
|
||||
要求:用所给单词或短语组句
|
||||
Can I get it for you?(音频)
|
||||
选项1:for you
|
||||
选项2:can I
|
||||
选项3:get it
|
||||
|
||||
答案:Can I get it for you?
|
||||
|
||||
【互动反馈】
|
||||
正确 Jack : You are very kind. But I just want to say...
|
||||
错误 Jack: I beg your pardon?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217213": {
|
||||
"type": "对话挖空",
|
||||
"text": """【任务标题】
|
||||
补全对Jack说的话
|
||||
|
||||
【资源配置】
|
||||
图片时机:互动内容互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
But this meat is from 2 ___ !(音频)
|
||||
选项1:years ago(正确)
|
||||
选项2:days ago
|
||||
|
||||
【互动反馈】
|
||||
正确 Jack : Perfect!
|
||||
错误 Jack : No, look at the sign on it!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217214": {
|
||||
"type": "听力拖拽",
|
||||
"text": """【任务标题】
|
||||
告诉 Lin 你们分发包裹的事迹
|
||||
|
||||
【任务背景】
|
||||
包裹大作战!你和 Jay 热火朝天地干了半天,把很多包裹带给了他们的主人。快来回顾一下你们的战果吧!
|
||||
|
||||
【通关知识】
|
||||
|
||||
get v. 收到
|
||||
month n. 月
|
||||
year n. 年
|
||||
ago adv. 以前
|
||||
... month(s)/year(s) ago.
|
||||
|
||||
【开场语】
|
||||
Lin: Come on, tell me what you did!
|
||||
|
||||
【听力文本】
|
||||
# 文本 1
|
||||
Jay: Well, well, well! Listen up!
|
||||
Jay: Tom gets a pen!
|
||||
User: It is from 5 days ago!
|
||||
Jay: And Sunny gets a dress.
|
||||
Jay: It is from 6 months ago.
|
||||
Jay: Jack gets some meat from 2 years ago!
|
||||
|
||||
【题目信息】
|
||||
|
||||
#单空选择
|
||||
选项图片编号:00,01,02
|
||||
答案图片编号:
|
||||
01,00,02
|
||||
|
||||
|
||||
【学习过程】
|
||||
句子 1
|
||||
It is from 5 days ago!
|
||||
【ago】
|
||||
|
||||
句子 2
|
||||
It is from 6 months ago. 【month】
|
||||
|
||||
|
||||
句子 3
|
||||
Jack gets some meat from 2 years ago! 【year】""",
|
||||
},
|
||||
"1217215": {
|
||||
"type": "对话选读",
|
||||
"text": """【任务标题】
|
||||
选择表达满意的方式
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:(音频)
|
||||
选项1:I am happy with it!
|
||||
- 反馈 Jay: That's good!
|
||||
选项2:I am happy with the result!
|
||||
- 反馈 Jay: That's good!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217216": {
|
||||
"type": "对话挖空",
|
||||
"text": """【任务标题】
|
||||
补全User想要包裹的句子
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
空
|
||||
|
||||
【互动内容】
|
||||
I want to ___ one for myself!(音频)
|
||||
选项1:get(正确)
|
||||
选项2:get up
|
||||
|
||||
【互动反馈】
|
||||
正确 无
|
||||
错误 Jay : Hmm, that's not how we say it. Try again!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
"1217217": {
|
||||
"type": "对话朗读",
|
||||
"text": """【任务标题】
|
||||
朗读收到帽子的喜悦
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Now I get my own hat!(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Parsers for each component type
|
||||
# ============================================================
|
||||
|
||||
def extract_section(text, key):
|
||||
"""Extract content between 【key】and next section header 【...】."""
|
||||
# Match 【key】 then capture everything until next 【XXX】 header on its own line or end
|
||||
pattern = rf'【{re.escape(key)}】\s*\n?(.*?)(?=\n(?:【[^】]+】)\s*\n|\Z)'
|
||||
m = re.search(pattern, text, re.DOTALL)
|
||||
if m:
|
||||
return m.group(1).strip()
|
||||
return None
|
||||
|
||||
def parse_context(text):
|
||||
"""Parse context intro: '角色 : 台词' or '空' or '无'"""
|
||||
if not text or text in ('无', '空', ''):
|
||||
return None
|
||||
lines = [l.strip() for l in text.strip().split('\n') if l.strip()]
|
||||
result = []
|
||||
for line in lines:
|
||||
if ':' in line:
|
||||
parts = line.split(':', 1)
|
||||
result.append({"character": parts[0].strip(), "line": parts[1].strip()})
|
||||
elif ':' in line:
|
||||
parts = line.split(':', 1)
|
||||
result.append({"character": parts[0].strip(), "line": parts[1].strip()})
|
||||
else:
|
||||
result.append(line)
|
||||
return result if result else None
|
||||
|
||||
def parse_feedback(text):
|
||||
"""Parse feedback: 正确/错误 角色 : 台词"""
|
||||
if not text or text == '无':
|
||||
return {"correct": None, "incorrect": None}
|
||||
|
||||
result = {"correct": None, "incorrect": None}
|
||||
lines = text.strip().split('\n')
|
||||
|
||||
current_type = None
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith('正确'):
|
||||
current_type = 'correct'
|
||||
content = line[2:].strip()
|
||||
if ':' in content:
|
||||
parts = content.split(':', 1)
|
||||
char = parts[0].strip()
|
||||
msg = parts[1].strip()
|
||||
if msg == '无':
|
||||
result['correct'] = None
|
||||
else:
|
||||
result['correct'] = {"character": char, "line": msg}
|
||||
elif content == '无':
|
||||
result['correct'] = None
|
||||
elif line.startswith('错误'):
|
||||
current_type = 'incorrect'
|
||||
content = line[2:].strip()
|
||||
if ':' in content:
|
||||
parts = content.split(':', 1)
|
||||
result['incorrect'] = {"character": parts[0].strip(), "line": parts[1].strip()}
|
||||
elif ':' in content:
|
||||
parts = content.split(':', 1)
|
||||
result['incorrect'] = {"character": parts[0].strip(), "line": parts[1].strip()}
|
||||
return result
|
||||
|
||||
def parse_selective_options(text):
|
||||
"""Parse 对话选读 options: 选项N:text - 反馈 X: line"""
|
||||
options = []
|
||||
lines = text.strip().split('\n')
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i].strip()
|
||||
m = re.match(r'选项(\d+)[::]\s*(.+)', line)
|
||||
if m:
|
||||
idx = int(m.group(1))
|
||||
opt_text = m.group(2).strip()
|
||||
feedback = None
|
||||
# Check next line for feedback
|
||||
if i + 1 < len(lines):
|
||||
next_line = lines[i + 1].strip()
|
||||
fm = re.match(r'[-–]\s*反馈\s*([^::]+)[::]\s*(.+)', next_line)
|
||||
if fm:
|
||||
feedback = {"character": fm.group(1).strip(), "line": fm.group(2).strip()}
|
||||
i += 1
|
||||
options.append({"index": idx, "text": opt_text, "feedback": feedback})
|
||||
i += 1
|
||||
return options
|
||||
|
||||
def parse_image_options(text):
|
||||
"""Parse image choice options: 00, 01, 02 etc."""
|
||||
options = []
|
||||
lines = text.strip().split('\n')
|
||||
in_options = False
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line == '选项:':
|
||||
in_options = True
|
||||
continue
|
||||
if in_options:
|
||||
if re.match(r'^\d{2}$', line):
|
||||
options.append(line)
|
||||
else:
|
||||
break
|
||||
return options
|
||||
|
||||
def parse_fill_options(text):
|
||||
"""Parse fill-in-blanks options: 选项N:text(正确)"""
|
||||
options = []
|
||||
lines = text.strip().split('\n')
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
m = re.match(r'选项(\d+)[::]\s*(.+)', line)
|
||||
if m:
|
||||
idx = int(m.group(1))
|
||||
opt_text = m.group(2).strip()
|
||||
correct = False
|
||||
if '(正确)' in opt_text:
|
||||
correct = True
|
||||
opt_text = opt_text.replace('(正确)', '').strip()
|
||||
options.append({"index": idx, "text": opt_text, "correct": correct})
|
||||
return options
|
||||
|
||||
def parse_sentence_options(text):
|
||||
"""Parse sentence building options: 选项N:text"""
|
||||
options = []
|
||||
lines = text.strip().split('\n')
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
m = re.match(r'选项(\d+)[::]\s*(.+)', line)
|
||||
if m:
|
||||
idx = int(m.group(1))
|
||||
opt_text = m.group(2).strip()
|
||||
options.append({"index": idx, "text": opt_text})
|
||||
return options
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Converters
|
||||
# ============================================================
|
||||
|
||||
def convert_choice_image(cid, text):
|
||||
"""图片单选 / 图片多选"""
|
||||
is_multi = CONFIGS[cid]['type'] == '图片多选'
|
||||
|
||||
raw_interaction = extract_section(text, '互动内容')
|
||||
context = extract_section(text, '情境引入')
|
||||
feedback = extract_section(text, '互动反馈')
|
||||
post = extract_section(text, '后置对话')
|
||||
|
||||
# Parse interaction
|
||||
interaction_lines = raw_interaction.strip().split('\n')
|
||||
instruction = interaction_lines[0].strip()
|
||||
audio = '(音频)' in instruction
|
||||
instruction = instruction.replace('(音频)', '').strip()
|
||||
|
||||
options = []
|
||||
answers = []
|
||||
hint = None
|
||||
in_options = False
|
||||
in_answer = False
|
||||
in_hint = False
|
||||
|
||||
for line in interaction_lines[1:]:
|
||||
line = line.strip()
|
||||
if line == '选项:':
|
||||
in_options = True
|
||||
continue
|
||||
if in_options and re.match(r'^\d{2}$', line):
|
||||
options.append(line)
|
||||
continue
|
||||
if '答案:' in line:
|
||||
in_options = False
|
||||
in_answer = True
|
||||
ans_text = line.replace('答案:', '').strip()
|
||||
if ans_text:
|
||||
answers.append(ans_text)
|
||||
continue
|
||||
if in_answer:
|
||||
if re.match(r'^\d{2}$', line):
|
||||
answers.append(line)
|
||||
elif '辅助信息' in line:
|
||||
in_answer = False
|
||||
in_hint = True
|
||||
hint = line.replace('辅助信息:', '').strip()
|
||||
else:
|
||||
in_answer = False
|
||||
continue
|
||||
if in_hint:
|
||||
continue
|
||||
if '辅助信息' in line:
|
||||
hint = line.replace('辅助信息:', '').strip()
|
||||
continue
|
||||
|
||||
result = {
|
||||
"componentType": CONFIGS[cid]['type'],
|
||||
"taskTitle": extract_section(text, '任务标题'),
|
||||
"contextIntro": parse_context(context),
|
||||
"interaction": {
|
||||
"instruction": instruction,
|
||||
"audio": audio,
|
||||
"options": options,
|
||||
"answers": answers,
|
||||
"hint": hint
|
||||
},
|
||||
"feedback": parse_feedback(feedback),
|
||||
"postDialogue": parse_context(post)
|
||||
}
|
||||
return result
|
||||
|
||||
def convert_reading(cid, text):
|
||||
"""对话朗读"""
|
||||
return {
|
||||
"componentType": "对话朗读",
|
||||
"taskTitle": extract_section(text, '任务标题'),
|
||||
"resourceConfig": extract_section(text, '资源配置') or None,
|
||||
"contextIntro": parse_context(extract_section(text, '情境引入')),
|
||||
"interaction": {
|
||||
"sentence": (extract_section(text, '互动内容') or '').replace('(朗读)', '').strip(),
|
||||
"audio": True
|
||||
},
|
||||
"postDialogue": parse_context(extract_section(text, '后置对话'))
|
||||
}
|
||||
|
||||
def convert_sentence_building(cid, text):
|
||||
"""对话组句"""
|
||||
raw_interaction = extract_section(text, '互动内容')
|
||||
resource = extract_section(text, '资源配置') or None
|
||||
context = extract_section(text, '情境引入')
|
||||
feedback = extract_section(text, '互动反馈')
|
||||
post = extract_section(text, '后置对话')
|
||||
|
||||
interaction_lines = raw_interaction.strip().split('\n')
|
||||
requirement = None
|
||||
sentence = None
|
||||
audio = True
|
||||
options = []
|
||||
answer = None
|
||||
hint = None
|
||||
|
||||
# Parse interaction
|
||||
i = 0
|
||||
if interaction_lines[0].startswith('要求:'):
|
||||
requirement = interaction_lines[0].replace('要求:', '').strip()
|
||||
i = 1
|
||||
|
||||
# Find sentence line (ends with (音频))
|
||||
for j in range(i, len(interaction_lines)):
|
||||
line = interaction_lines[j].strip()
|
||||
if '(音频)' in line:
|
||||
sentence = line.replace('(音频)', '').strip()
|
||||
i = j + 1
|
||||
break
|
||||
elif re.match(r'选项\d+', line):
|
||||
# No sentence line found, use requirement as sentence
|
||||
i = j
|
||||
break
|
||||
|
||||
# Parse options
|
||||
for j in range(i, len(interaction_lines)):
|
||||
line = interaction_lines[j].strip()
|
||||
m = re.match(r'选项(\d+)[::]\s*(.+)', line)
|
||||
if m:
|
||||
options.append({"index": int(m.group(1)), "text": m.group(2).strip()})
|
||||
elif '答案:' in line:
|
||||
answer = line.replace('答案:', '').strip()
|
||||
elif '辅助信息:' in line:
|
||||
hint = line.replace('辅助信息:', '').strip()
|
||||
|
||||
return {
|
||||
"componentType": "对话组句",
|
||||
"taskTitle": extract_section(text, '任务标题'),
|
||||
"resourceConfig": resource,
|
||||
"contextIntro": parse_context(context),
|
||||
"interaction": {
|
||||
"requirement": requirement,
|
||||
"sentence": sentence,
|
||||
"audio": audio,
|
||||
"options": options,
|
||||
"answer": answer,
|
||||
"hint": hint
|
||||
},
|
||||
"feedback": parse_feedback(feedback),
|
||||
"postDialogue": parse_context(post)
|
||||
}
|
||||
|
||||
def convert_selective_reading(cid, text):
|
||||
"""对话选读"""
|
||||
raw_interaction = extract_section(text, '互动内容')
|
||||
resource = extract_section(text, '资源配置') or None
|
||||
context = extract_section(text, '情境引入')
|
||||
post = extract_section(text, '后置对话')
|
||||
|
||||
interaction_lines = raw_interaction.strip().split('\n')
|
||||
requirement = interaction_lines[0].strip()
|
||||
audio = '(音频)' in raw_interaction
|
||||
if requirement.startswith('要求:'):
|
||||
requirement = requirement.replace('要求:', '').strip()
|
||||
|
||||
options = parse_selective_options(raw_interaction)
|
||||
|
||||
return {
|
||||
"componentType": "对话选读",
|
||||
"taskTitle": extract_section(text, '任务标题'),
|
||||
"resourceConfig": resource,
|
||||
"contextIntro": parse_context(context),
|
||||
"interaction": {
|
||||
"requirement": requirement,
|
||||
"audio": audio,
|
||||
"options": options
|
||||
},
|
||||
"postDialogue": parse_context(post)
|
||||
}
|
||||
|
||||
def convert_fill_blanks(cid, text):
|
||||
"""对话挖空"""
|
||||
raw_interaction = extract_section(text, '互动内容')
|
||||
resource = extract_section(text, '资源配置') or None
|
||||
context = extract_section(text, '情境引入')
|
||||
feedback = extract_section(text, '互动反馈')
|
||||
post = extract_section(text, '后置对话')
|
||||
|
||||
interaction_lines = raw_interaction.strip().split('\n')
|
||||
sentence = None
|
||||
options = []
|
||||
|
||||
for line in interaction_lines:
|
||||
line = line.strip()
|
||||
if '(音频)' in line and not line.startswith('选项'):
|
||||
sentence = line.replace('(音频)', '').strip()
|
||||
m = re.match(r'选项(\d+)[::]\s*(.+)', line)
|
||||
if m:
|
||||
opt_text = m.group(2).strip()
|
||||
correct = '(正确)' in opt_text
|
||||
opt_text = opt_text.replace('(正确)', '').strip()
|
||||
options.append({"index": int(m.group(1)), "text": opt_text, "correct": correct})
|
||||
|
||||
return {
|
||||
"componentType": "对话挖空",
|
||||
"taskTitle": extract_section(text, '任务标题'),
|
||||
"resourceConfig": resource,
|
||||
"contextIntro": parse_context(context),
|
||||
"interaction": {
|
||||
"sentence": sentence,
|
||||
"audio": True,
|
||||
"options": options
|
||||
},
|
||||
"feedback": parse_feedback(feedback),
|
||||
"postDialogue": parse_context(post)
|
||||
}
|
||||
|
||||
def convert_listening_drag(cid, text):
|
||||
"""听力拖拽 → core_listening_drag JSON"""
|
||||
task_title = extract_section(text, '任务标题')
|
||||
task_bg = extract_section(text, '任务背景') or ''
|
||||
knowledge = extract_section(text, '通关知识') or ''
|
||||
opening = extract_section(text, '开场语') or ''
|
||||
audio_text = extract_section(text, '听力文本') or ''
|
||||
question_info = extract_section(text, '题目信息') or ''
|
||||
learning = extract_section(text, '学习过程') or ''
|
||||
|
||||
# Parse audio text into dialogs
|
||||
dialog_list = []
|
||||
for line in audio_text.strip().split('\n'):
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if ':' in line or ':' in line:
|
||||
sep = ':' if ':' in line else ':'
|
||||
parts = line.split(sep, 1)
|
||||
dialog_list.append({"character": parts[0].strip(), "line": parts[1].strip()})
|
||||
|
||||
# Parse question info
|
||||
option_images = []
|
||||
answer_images = []
|
||||
for line in question_info.strip().split('\n'):
|
||||
line = line.strip()
|
||||
if '选项图片编号' in line:
|
||||
option_images = [x.strip() for x in line.split(':', 1)[1].split(',') if x.strip()]
|
||||
if '答案图片编号' in line:
|
||||
# Answer on next line
|
||||
pass
|
||||
|
||||
# Get answer from question info - look for answer after 答案图片编号
|
||||
q_lines = question_info.strip().split('\n')
|
||||
for i, line in enumerate(q_lines):
|
||||
if '答案图片编号' in line and i + 1 < len(q_lines):
|
||||
answer_images = [x.strip() for x in q_lines[i+1].split(',') if x.strip() and x.strip() != '答案图片编号']
|
||||
|
||||
# For 听力拖拽, 【学习过程】 is the LAST section and contains inline 【kp】.
|
||||
# Extract it manually: everything after 【学习过程】
|
||||
lp_match = re.search(r'【学习过程】\s*\n(.*)', text, re.DOTALL)
|
||||
learning = lp_match.group(1).strip() if lp_match else ''
|
||||
|
||||
learning_steps = []
|
||||
# Split by sentence markers
|
||||
blocks = re.split(r'\n(?=句子\s*\d*)', learning)
|
||||
for block in blocks:
|
||||
block = block.strip()
|
||||
if not block:
|
||||
continue
|
||||
# Remove the 句子 N header
|
||||
block = re.sub(r'^句子\s*\d*\s*\n?', '', block).strip()
|
||||
if not block:
|
||||
continue
|
||||
# Extract kp from 【...】
|
||||
kp_match = re.search(r'【(.+?)】', block)
|
||||
kp = kp_match.group(1).strip() if kp_match else ""
|
||||
# Extract sentence (text before 【 or whole block if no 【)
|
||||
if kp_match:
|
||||
sentence = block[:kp_match.start()].strip()
|
||||
else:
|
||||
sentence = block.strip()
|
||||
if sentence or kp:
|
||||
learning_steps.append({"sentence": sentence, "knowledgePoint": kp})
|
||||
|
||||
# Scene description
|
||||
scene_desc = f"{task_bg}\n\n{opening}"
|
||||
|
||||
return {
|
||||
"componentType": "听力拖拽",
|
||||
"cType": "core_listening_drag",
|
||||
"taskData": {
|
||||
"cType": "core_listening_drag",
|
||||
"cId": cid,
|
||||
"title": task_title,
|
||||
"sceneDesc": scene_desc,
|
||||
"key": "ago, month, year, get"
|
||||
},
|
||||
"dialogList": dialog_list,
|
||||
"preDialog": [],
|
||||
"questionList": [
|
||||
{
|
||||
"type": "drag_match",
|
||||
"optionImages": option_images,
|
||||
"answerImages": answer_images,
|
||||
"itemCount": len(option_images)
|
||||
}
|
||||
],
|
||||
"learningData": {
|
||||
"learningPart": learning_steps,
|
||||
"closing": ""
|
||||
},
|
||||
"audioText": audio_text,
|
||||
"knowledgeSummary": knowledge
|
||||
}
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Main conversion
|
||||
# ============================================================
|
||||
|
||||
CONVERTERS = {
|
||||
"图片单选": convert_choice_image,
|
||||
"图片多选": convert_choice_image,
|
||||
"对话朗读": convert_reading,
|
||||
"对话组句": convert_sentence_building,
|
||||
"对话选读": convert_selective_reading,
|
||||
"对话挖空": convert_fill_blanks,
|
||||
"听力拖拽": convert_listening_drag,
|
||||
}
|
||||
|
||||
# Component row mapping (from sheet data: which row has which component ID)
|
||||
COMPONENT_ROWS = {
|
||||
"1217201": 33,
|
||||
"1217202": 40,
|
||||
"1217203": 43,
|
||||
"1217204": 50,
|
||||
"1217205": 51,
|
||||
"1217206": 53,
|
||||
"1217207": 68,
|
||||
"1217208": 70,
|
||||
"1217209": 89,
|
||||
"1217210": 95,
|
||||
"1217211": 107,
|
||||
"1217212": 120,
|
||||
"1217213": 123,
|
||||
"1217214": 157,
|
||||
"1217215": 164,
|
||||
"1217216": 168,
|
||||
"1217217": 173,
|
||||
}
|
||||
|
||||
|
||||
def write_cell(row, col_letter, value, token):
|
||||
"""Write a single cell to the sheet."""
|
||||
cell_range = f"{SHEET_ID}!{col_letter}{row}:{col_letter}{row}"
|
||||
payload = {
|
||||
"valueRange": {
|
||||
"range": cell_range,
|
||||
"values": [[value]]
|
||||
}
|
||||
}
|
||||
r = subprocess.run([
|
||||
'curl', '-s', '-X', 'PUT',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values',
|
||||
'-H', f'Authorization: Bearer {token}',
|
||||
'-H', 'Content-Type: application/json',
|
||||
'-d', json.dumps(payload, ensure_ascii=False)
|
||||
], capture_output=True, text=True)
|
||||
result = json.loads(r.stdout)
|
||||
if result.get('code') != 0:
|
||||
print(f" ❌ Write failed: {result}", file=sys.stderr)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
results = {}
|
||||
for cid, cfg in CONFIGS.items():
|
||||
ctype = cfg['type']
|
||||
converter = CONVERTERS.get(ctype)
|
||||
if not converter:
|
||||
print(f"⚠️ Unknown type {ctype} for {cid}", file=sys.stderr)
|
||||
continue
|
||||
try:
|
||||
json_data = converter(cid, cfg['text'])
|
||||
results[cid] = json_data
|
||||
print(f"✅ {cid} ({ctype}) → JSON OK")
|
||||
except Exception as e:
|
||||
print(f"❌ {cid} ({ctype}) → ERROR: {e}", file=sys.stderr)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Print all JSONs for review
|
||||
print("\n" + "=" * 60)
|
||||
print("GENERATED JSONS")
|
||||
print("=" * 60)
|
||||
for cid, data in results.items():
|
||||
print(f"\n--- {cid} ({data['componentType']}) ---")
|
||||
print(json.dumps(data, ensure_ascii=False, indent=2))
|
||||
|
||||
# Save to file for inspection
|
||||
with open('/root/.openclaw/workspace-xiaoyan/output/component_jsons.json', 'w', encoding='utf-8') as f:
|
||||
json.dump(results, f, ensure_ascii=False, indent=2)
|
||||
print(f"\n📁 Saved to output/component_jsons.json")
|
||||
|
||||
# Write back to sheet
|
||||
print("\n" + "=" * 60)
|
||||
print("WRITING BACK TO SHEET")
|
||||
print("=" * 60)
|
||||
|
||||
# Re-fetch token (may have expired)
|
||||
token = get_token()
|
||||
|
||||
success = 0
|
||||
fail = 0
|
||||
for cid, data in results.items():
|
||||
row = COMPONENT_ROWS.get(cid)
|
||||
if not row:
|
||||
print(f"⚠️ {cid}: no row mapping, skipped")
|
||||
continue
|
||||
json_str = json.dumps(data, ensure_ascii=False)
|
||||
if write_cell(row, 'I', json_str, token):
|
||||
print(f"✅ {cid} → row {row} written")
|
||||
success += 1
|
||||
else:
|
||||
fail += 1
|
||||
|
||||
print(f"\nDone: {success} written, {fail} failed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@ -1,264 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
英文台词优化 & 回填脚本
|
||||
基于 MEMORY.md 的「对话台词优化通用规则」对列 E(编剧台词)进行优化,写入列 F
|
||||
知识点:grandmother, grandfather, visit (v.), today (n.)
|
||||
句型知识点:... visit+sb, Today is...
|
||||
"""
|
||||
import json, subprocess, sys
|
||||
|
||||
# Rules:
|
||||
# 0. 知识点词汇/句型必须保留 (grandmother/grandfather/visit/today / Today is... / ...visit+sb)
|
||||
# 1. 精简:删除冗余
|
||||
# 2. 口语化:自然对话,低龄友好,增语气词
|
||||
# 3. 拆分:>8词拆为2-3短句
|
||||
# 4. 情绪匹配:匹配角色情绪
|
||||
# 5. 场景适配:不重复画面信息
|
||||
# 6. 单句≤10词,知识点句≤7词
|
||||
|
||||
# Knowledge-point words to preserve
|
||||
KP_WORDS = {"grandmother", "grandfather", "visit", "today", "today's"}
|
||||
|
||||
# Mapping: (row_index_0based_sheet) → optimized F value
|
||||
# Only rows where D (role) and E (script line) are non-null
|
||||
# Row index = sheet row - 1 (0-based from API)
|
||||
# Sheet row 1 = header → skip
|
||||
# Sheet row 2 = API row index 1
|
||||
|
||||
optimizations = {}
|
||||
|
||||
def add(row_sheet, f_value):
|
||||
"""row_sheet is 1-indexed sheet row number"""
|
||||
optimizations[row_sheet - 1] = f_value # convert to 0-indexed
|
||||
|
||||
# === SECTION 1: 开场 - 门口 ===
|
||||
add(3, "Open up!")
|
||||
add(4, "Your letter is here!")
|
||||
add(6, "Nobody answers?")
|
||||
add(7, "Alright... I'll go in myself.")
|
||||
add(9, "Whoa! What a mess!")
|
||||
add(11, "What's wrong?")
|
||||
add(12, "Vicky? Can you hear me?")
|
||||
|
||||
# === SECTION 2: 发现家里很乱 ===
|
||||
add(14, "Today is a No-Mom-and-Dad day!") # 知识点 Today is
|
||||
add(15, "Our parents aren't home!") # 精简 + 口语化
|
||||
add(16, "So we can do whatever we want!")
|
||||
add(17, "Really?")
|
||||
add(19, "Yes!")
|
||||
add(20, "Today is a good day!") # 知识点 Today is
|
||||
add(21, "Huh?")
|
||||
add(22, "Are you sure today is a good day?") # 知识点 today
|
||||
|
||||
# === SECTION 3: 撞到用户,道歉 ===
|
||||
add(23, "So on a good day, nobody says sorry?") # 精简 14→8词
|
||||
add(24, "Eva, Peter, say sorry.")
|
||||
add(25, "Okay. We're sorry.") # 口语化
|
||||
|
||||
# === SECTION 4: 继续对话 ===
|
||||
add(27, "Ah, kids.")
|
||||
add(28, "Come visit us!") # 知识点 visit,修正"Welcome to visit us"不自然表达
|
||||
add(29, "Oh, I'm not here to visit.") # 知识点 visit,口语化
|
||||
add(30, "I'm here to give you something.") # 口语化
|
||||
|
||||
# === SECTION 5: 电话 ===
|
||||
add(33, "Hello? Grandfather and grandmother, how are you?") # 知识点 grandfather/grandmother
|
||||
add(34, "Good, good! We're great!") # 口语化
|
||||
add(35, "How are you all, my lovely grandchildren?")
|
||||
add(36, "We're great! Today is so much fun!") # 知识点 Today is, 口语化
|
||||
add(37, "Great to hear that!")
|
||||
add(38, "Are you ready for us?") # 精简
|
||||
add(39, "I'm so excited to visit you all!") # 知识点 visit, 口语化
|
||||
add(40, "Sure! When will you visit us?") # 知识点 visit
|
||||
add(41, "Today is the day, of course!") # 知识点 Today is
|
||||
add(42, "What? You're both coming today?") # 口语化修复
|
||||
add(43, "Yes! Me and Justin. Your grandmother and grandfather.") # 知识点, 修正 typo gandfather
|
||||
add(44, "We sent you a letter. Remember?") # 口语化
|
||||
add(45, "See you later!")
|
||||
add(46, "I love you! Bye!")
|
||||
|
||||
# === SECTION 6: 惊慌 ===
|
||||
add(48, "Oh no! What did they say on the phone?") # 修正语法 in→on
|
||||
add(50, "Your grandfather and grandmother are coming to visit you!") # 知识点, 修正 is→are
|
||||
add(51, "On your good day.")
|
||||
|
||||
# === SECTION 7: 紧急动员 ===
|
||||
add(54, "Eva! Peter! Alex! We're in trouble!") # 口语化
|
||||
add(56, "What happened?")
|
||||
add(57, "Grandfather and grandmother are coming to visit us!") # 知识点, 修正 is→are
|
||||
add(58, "So what?")
|
||||
add(59, "Today! Right now!") # 精简 On today→Today
|
||||
add(62, "No, not today...") # 修正 on today→today
|
||||
add(63, "Look at this place!")
|
||||
|
||||
# === SECTION 8: 用户互动 ===
|
||||
add(65, "Yes, today is a total mess.") # 知识点 today
|
||||
add(66, "It's not the best day for visitors.") # 知识点 visit→visitors 可接受变体, 口语化
|
||||
add(68, "They could be here at any minute!") # 口语化
|
||||
|
||||
# === SECTION 9: 爷爷奶奶会生气 ===
|
||||
add(70, "How will they feel about this?")
|
||||
add(72, "Grandfather and grandmother will be so upset!") # 知识点, 精简 mad→upset (正向引导)
|
||||
add(74, "What should we do?")
|
||||
add(76, "Don't worry! I'll help you clean up!") # 增加具体动作词
|
||||
add(77, "Okay, first pick up the toys from the floor.")
|
||||
|
||||
# === SECTION 10: 收拾 ===
|
||||
add(80, "Oh no! No time to put these away!") # 精简
|
||||
add(81, "Put them in the cupboard!") # 修正 it→them (玩具是复数)
|
||||
add(83, "Your grandfather and grandmother won't see!") # 知识点
|
||||
add(85, "Good idea!")
|
||||
add(88, "All done!")
|
||||
add(89, "We need to clean the floor!")
|
||||
add(90, "I'll do it!") # 口语化
|
||||
|
||||
# === SECTION 11: 扫地机器人 ===
|
||||
add(94, "Will Grandfather and Grandmother be happy?") # 知识点, satisfied→happy (低龄词)
|
||||
add(95, "Well... this will do for now.") # 口语化
|
||||
add(96, "Before your grandfather and grandmother come to visit.") # 知识点
|
||||
|
||||
# === SECTION 12: 沙发污渍 ===
|
||||
add(99, "Alex! The sofa is a mess!") # 精简, 正向化 (不说 you made it dirty)
|
||||
add(100, "I'll clean it.") # 口语化
|
||||
add(103, "I can't get the chocolate off!")
|
||||
add(104, "I'm good at many things. Just not housework!") # 拆分 >8词, 口语化
|
||||
|
||||
# === SECTION 13: 更乱 ===
|
||||
add(106, "Oh no! We can't clean up in time!") # 精简+口语化
|
||||
add(107, "I wish we had more time for this!")
|
||||
add(108, "Why today, of all days?") # 口语化
|
||||
add(109, "I don't want them to see our house like this.") # 口语化修正
|
||||
add(110, "Why didn't they tell us earlier?") # 口语化修正
|
||||
|
||||
# === SECTION 14: 信 ===
|
||||
add(113, "I think they did tell you...") # 精简+口语化
|
||||
add(114, "In this letter.")
|
||||
add(116, "What is in this letter?")
|
||||
|
||||
# === SECTION 15: 核心互动-听力 (Justin念信) ===
|
||||
add(119, "Hi, your grandfather is writing this letter.") # 知识点 grandfather
|
||||
add(120, "I will come to visit you guys.") # 知识点 visit
|
||||
add(121, "Your grandmother will visit you too!") # 知识点 grandmother, visit
|
||||
add(122, "We love you, see you soon!")
|
||||
|
||||
# === SECTION 16: 反应 ===
|
||||
add(124, "They were so happy to visit you!") # 知识点 visit
|
||||
add(125, "Yes. We should be happy too.")
|
||||
add(127, "We should not be grumpy like this.")
|
||||
add(128, "Let's do something to welcome them!") # 口语化
|
||||
add(130, "You can make something they like!") # 知识点, 精简
|
||||
add(131, "What is their favourite food?")
|
||||
|
||||
# === SECTION 17: 苹果派 ===
|
||||
add(133, "Grandmother likes apples.") # 知识点 grandmother, 修正 apple→apples
|
||||
add(134, "Grandfather likes pie.") # 知识点 grandfather
|
||||
add(135, "Then you can make apple pie for them!")
|
||||
add(136, "I remember the recipe.")
|
||||
add(137, "I can fix the cooking robot.")
|
||||
add(139, "Okay! Apple pie is today's welcome gift!") # 知识点 today
|
||||
|
||||
# === SECTION 18: 完成了 ===
|
||||
add(142, "You did it!") # 口语化 (替换 You finished)
|
||||
add(143, "Now we just wait for them to arrive.") # 精简
|
||||
|
||||
# === SECTION 19: 爷爷奶奶来了 ===
|
||||
add(146, "They're coming!") # 口语化
|
||||
add(148, "Who wants a big hug from Grandfather?") # 知识点, 修正语法
|
||||
add(149, "Me! Me!")
|
||||
add(150, "Who wants Grandmother's homemade candy?") # 知识点, 修正 grandmother→Grandmother's, handmade→homemade(低龄)
|
||||
add(151, "Me! Me!")
|
||||
add(153, "We made something for you.")
|
||||
add(154, "Mmm! What's that smell? Is that a pie?") # 口语化
|
||||
add(155, "I smell apples!") # 修正 apple→apples
|
||||
add(156, "Whoa! I know that smell! Apple pie!") # 口语化
|
||||
add(157, "That is our favourite!")
|
||||
add(159, "Oh, you have a friend over!") # 修正 in home→over
|
||||
add(161, "Hello! I am here to visit Vicky.") # 知识点 visit
|
||||
add(162, "Nice to meet you again!")
|
||||
add(163, "I guess you helped out today too.") # 知识点 today, 口语化修正
|
||||
|
||||
# === SECTION 20: 结尾 ===
|
||||
add(165, "Today seems pretty busy.") # 知识点 today
|
||||
add(167, "Yes, we made a little mess before you came.") # 知识点 visit, 口语化修正
|
||||
add(168, "Today was not easy.") # 知识点 today, 修正时态 is→was
|
||||
add(170, "That's okay.") # 口语化
|
||||
add(172, "Grandfather and Grandmother can fix anything.") # 知识点, 口语化 everything→anything
|
||||
add(173, "That's what family is for!") # 口语化重构
|
||||
add(174, "Mess or not, we love seeing you!") # 口语化重构
|
||||
|
||||
|
||||
# Print summary and build write payload
|
||||
print(f"Total lines to write: {len(optimizations)}")
|
||||
|
||||
# Build values payload per row
|
||||
# We need to identify continuous ranges for efficiency
|
||||
# But since the API supports writing individual ranges, let's batch by nearby rows
|
||||
|
||||
# Sort by row index
|
||||
sorted_rows = sorted(optimizations.items())
|
||||
|
||||
# Build the complete column F data: for each row, either the optimized value or empty string ("")
|
||||
# We need all rows 2-149 (sheet rows)
|
||||
all_values = []
|
||||
for row_idx in range(1, 150): # 1 = sheet row 2, 149 = sheet row 150
|
||||
if row_idx in optimizations:
|
||||
all_values.append([optimizations[row_idx]])
|
||||
else:
|
||||
all_values.append([""])
|
||||
|
||||
# Write back - use PUT to write the entire column at once
|
||||
# We write empty strings for non-dialogue rows to clear previous content
|
||||
|
||||
import os
|
||||
import json as jmod
|
||||
|
||||
app_id = "cli_a931175d41799cc7"
|
||||
config_path = "/root/.openclaw/credentials/xiaoyan/config.json"
|
||||
with open(config_path) as f:
|
||||
cfg = jmod.load(f)
|
||||
app_secret = cfg["apps"][0]["appSecret"]
|
||||
|
||||
# Get token
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "POST",
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", jmod.dumps({"app_id": app_id, "app_secret": app_secret})
|
||||
], capture_output=True, text=True)
|
||||
token = jmod.loads(result.stdout)["tenant_access_token"]
|
||||
|
||||
spreadsheet_token = "DA7csROG6hmnQMt59oScOLRfnWc"
|
||||
sheet_id = "Nr3Ovs"
|
||||
|
||||
# Write in batches of 50 rows to avoid too-large payloads
|
||||
batch_size = 50
|
||||
for batch_start in range(0, len(all_values), batch_size):
|
||||
batch = all_values[batch_start:batch_start + batch_size]
|
||||
# Sheet rows: batch_start + 2 to batch_start + 1 + len(batch)
|
||||
start_row = batch_start + 2
|
||||
end_row = batch_start + 1 + len(batch)
|
||||
|
||||
range_str = f"{sheet_id}!F{start_row}:F{end_row}"
|
||||
|
||||
payload = {
|
||||
"valueRange": {
|
||||
"range": range_str,
|
||||
"values": batch
|
||||
}
|
||||
}
|
||||
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "PUT",
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values",
|
||||
"-H", f"Authorization: Bearer {token}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", jmod.dumps(payload)
|
||||
], capture_output=True, text=True)
|
||||
|
||||
resp = jmod.loads(result.stdout)
|
||||
print(f"Batch F{start_row}:F{end_row} → code={resp.get('code')}, msg={resp.get('msg')}")
|
||||
if resp.get("code") != 0:
|
||||
print(f" ERROR: {result.stdout[:200]}")
|
||||
sys.exit(1)
|
||||
|
||||
print("All batches written successfully!")
|
||||
@ -1,235 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
英文台词优化 & 回填脚本 v2 — 使用精确行号
|
||||
规则:MEMORY.md 对话台词优化通用规则
|
||||
知识点:grandmother, grandfather, visit, today
|
||||
句型知识点:... visit+sb, Today is...
|
||||
"""
|
||||
import json, subprocess
|
||||
|
||||
# (sheet_row, optimized_F_value) — exact sheet row numbers
|
||||
rows = [
|
||||
(3, "Open up!"),
|
||||
(4, "Your letter is here!"),
|
||||
(6, "Nobody answers?"),
|
||||
(7, "Alright... I'll go in myself."),
|
||||
(9, "Whoa! What a mess!"),
|
||||
(11, "What's wrong?"),
|
||||
(12, "Vicky? Can you hear me?"),
|
||||
(14, "Today is a No-Mom-and-Dad day!"),
|
||||
(15, "Our parents aren't home!"),
|
||||
(16, "So we can do whatever we want!"),
|
||||
(17, "Really?"),
|
||||
(19, "Yes!"),
|
||||
(20, "Today is a good day!"),
|
||||
(21, "Huh?"),
|
||||
(22, "Are you sure today is a good day?"),
|
||||
(23, "So on a good day, nobody says sorry?"),
|
||||
(24, "Eva, Peter, say sorry."),
|
||||
(25, "Okay. We're sorry."),
|
||||
(27, "Ah, kids."),
|
||||
(28, "Come visit us!"),
|
||||
(29, "Oh, I'm not here to visit."),
|
||||
(30, "I'm here to give you something."),
|
||||
(32, "Wait a moment."),
|
||||
(34, "Hello? Grandfather and grandmother, how are you?"),
|
||||
(35, "Good, good! We're great!"),
|
||||
(36, "How are you all, my lovely grandchildren?"),
|
||||
(37, "We're great! Today is so much fun!"),
|
||||
(38, "Great to hear that!"),
|
||||
(39, "Are you ready for us?"),
|
||||
(40, "I'm so excited to visit you all!"),
|
||||
(41, "Sure! When will you visit us?"),
|
||||
(42, "Today is the day, of course!"),
|
||||
(43, "What? You're both coming today?"),
|
||||
(44, "Yes! Me and Justin. Your grandmother and grandfather."),
|
||||
(45, "We sent you a letter. Remember?"),
|
||||
(46, "See you later!"),
|
||||
(47, "I love you! Bye!"),
|
||||
(49, "Oh no! What did they say on the phone?"),
|
||||
(50, "Your grandfather and grandmother are coming to visit you!"),
|
||||
(51, "On your good day."),
|
||||
(53, "Eva! Peter! Alex! We're in trouble!"),
|
||||
(55, "What happened?"),
|
||||
(56, "Grandfather and grandmother are coming to visit us!"),
|
||||
(57, "So what?"),
|
||||
(58, "Today! Right now!"),
|
||||
(60, "No, not today..."),
|
||||
(61, "Look at this place!"),
|
||||
(62, "Yes, today is a total mess."),
|
||||
(63, "It's not the best day for visitors."),
|
||||
(64, "They could be here at any minute!"),
|
||||
(65, "How will they feel about this?"),
|
||||
(67, "Grandfather and grandmother will be so upset!"),
|
||||
(69, "What should we do?"),
|
||||
(70, "Don't worry! I'll help you clean up!"),
|
||||
(71, "Okay, first pick up the toys from the floor."),
|
||||
(73, "Oh no! No time to put these away!"),
|
||||
(74, "Put them in the cupboard!"),
|
||||
(75, "Your grandfather and grandmother won't see!"),
|
||||
(76, "Good idea!"),
|
||||
(79, "All done!"),
|
||||
(80, "We need to clean the floor!"),
|
||||
(81, "I'll do it!"),
|
||||
(84, "Will Grandfather and Grandmother be happy?"),
|
||||
(85, "Well... this will do for now."),
|
||||
(86, "Before your grandfather and grandmother come to visit."),
|
||||
(88, "Alex! The sofa is a mess!"),
|
||||
(89, "I'll clean it."),
|
||||
(91, "I can't get the chocolate off!"),
|
||||
(92, "I'm good at many things. Just not housework!"),
|
||||
(94, "Oh no! We can't clean up in time!"),
|
||||
(95, "I wish we had more time for this!"),
|
||||
(96, "Why today, of all days?"),
|
||||
(97, "I don't want them to see our house like this."),
|
||||
(98, "Why didn't they tell us earlier?"),
|
||||
(100, "I think they did tell you..."),
|
||||
(101, "In this letter."),
|
||||
(102, "What is in this letter?"),
|
||||
(104, "Hi, your grandfather is writing this letter."),
|
||||
(105, "I will come to visit you guys."),
|
||||
(106, "Your grandmother will visit you too!"),
|
||||
(107, "We love you, see you soon!"),
|
||||
(108, "They were so happy to visit you!"),
|
||||
(109, "Yes. We should be happy too."),
|
||||
(110, "We should not be grumpy like this."),
|
||||
(111, "Let's do something to welcome them!"),
|
||||
(112, "You can make something they like!"),
|
||||
(113, "What is their favourite food?"),
|
||||
(114, "Grandmother likes apples."),
|
||||
(115, "Grandfather likes pie."),
|
||||
(116, "Then you can make apple pie for them!"),
|
||||
(117, "I remember the recipe."),
|
||||
(118, "I can fix the cooking robot."),
|
||||
(119, "Okay! Apple pie is today's welcome gift!"),
|
||||
(121, "You did it!"),
|
||||
(122, "Now we just wait for them to arrive."),
|
||||
(124, "They're coming!"),
|
||||
(126, "Who wants a big hug from Grandfather?"),
|
||||
(127, "Me! Me!"),
|
||||
(128, "Who wants Grandmother's homemade candy?"),
|
||||
(129, "Me! Me!"),
|
||||
(131, "We made something for you."),
|
||||
(132, "Mmm! What's that smell? Is that a pie?"),
|
||||
(133, "I smell apples!"),
|
||||
(134, "Whoa! I know that smell! Apple pie!"),
|
||||
(135, "That is our favourite!"),
|
||||
(137, "Oh, you have a friend over!"),
|
||||
(138, "Hello! I am here to visit Vicky."),
|
||||
(139, "Nice to meet you again!"),
|
||||
(140, "I guess you helped out today too."),
|
||||
(142, "Today seems pretty busy."),
|
||||
(143, "Yes, we made a little mess before you came."),
|
||||
(144, "Today was not easy."),
|
||||
(145, "That's okay."),
|
||||
(146, "Grandfather and Grandmother can fix anything."),
|
||||
(147, "That's what family is for!"),
|
||||
(148, "Mess or not, we love seeing you!"),
|
||||
]
|
||||
|
||||
print(f"Total dialogue lines: {len(rows)}")
|
||||
|
||||
# Build the complete column F data (one value per row, 1-based sheet rows 2-149)
|
||||
# We need to clear the ENTIRE column first, then fill only dialogue rows.
|
||||
# The API PUT overwrites the specified range. Write all rows 2-149.
|
||||
# Use a dict for fast lookup
|
||||
f_map = {r: v for r, v in rows}
|
||||
|
||||
# Get token
|
||||
with open("/root/.openclaw/credentials/xiaoyan/config.json") as f:
|
||||
cfg = json.load(f)
|
||||
app_id = "cli_a931175d41799cc7"
|
||||
app_secret = cfg["apps"][0]["appSecret"]
|
||||
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "POST",
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps({"app_id": app_id, "app_secret": app_secret})
|
||||
], capture_output=True, text=True)
|
||||
token = json.loads(result.stdout)["tenant_access_token"]
|
||||
|
||||
spreadsheet_token = "DA7csROG6hmnQMt59oScOLRfnWc"
|
||||
sheet_id = "Nr3Ovs"
|
||||
|
||||
# Step 1: Clear entire column F (rows 2-149)
|
||||
print("Clearing column F (rows 2-149)...")
|
||||
empty_payload = {
|
||||
"valueRange": {
|
||||
"range": f"{sheet_id}!F2:F149",
|
||||
"values": [[""] for _ in range(148)] # 149-2+1 = 148 rows
|
||||
}
|
||||
}
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "PUT",
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values",
|
||||
"-H", f"Authorization: Bearer {token}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps(empty_payload)
|
||||
], capture_output=True, text=True)
|
||||
resp = json.loads(result.stdout)
|
||||
print(f" Clear: code={resp.get('code')}, msg={resp.get('msg')}")
|
||||
assert resp.get("code") == 0, f"Clear failed: {result.stdout[:200]}"
|
||||
|
||||
# Step 2: Write optimized values to each dialogue row
|
||||
# Group consecutive rows for batching
|
||||
batch_start = None
|
||||
batch_end = None
|
||||
batch_values = []
|
||||
|
||||
def flush_batch():
|
||||
global batch_start, batch_end, batch_values
|
||||
if not batch_values:
|
||||
return
|
||||
range_str = f"{sheet_id}!F{batch_start}:F{batch_end}"
|
||||
payload = {"valueRange": {"range": range_str, "values": batch_values}}
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "PUT",
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values",
|
||||
"-H", f"Authorization: Bearer {token}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps(payload)
|
||||
], capture_output=True, text=True)
|
||||
resp = json.loads(result.stdout)
|
||||
print(f" Write {range_str}: code={resp.get('code')}, msg={resp.get('msg')}")
|
||||
assert resp.get("code") == 0, f"Write failed: {result.stdout[:200]}"
|
||||
batch_start = None
|
||||
batch_end = None
|
||||
batch_values = []
|
||||
|
||||
# Also need to fill empty rows between dialogue rows
|
||||
# Strategy: write row by row, merging consecutive rows into batches
|
||||
for sheet_row in range(2, 150):
|
||||
value = f_map.get(sheet_row, "")
|
||||
if batch_start is None:
|
||||
batch_start = sheet_row
|
||||
batch_end = sheet_row
|
||||
batch_values = [[value]]
|
||||
else:
|
||||
batch_end = sheet_row
|
||||
batch_values.append([value])
|
||||
|
||||
flush_batch()
|
||||
|
||||
print("Done! Verifying...")
|
||||
|
||||
# Step 3: Verify key rows
|
||||
check_rows = [3, 7, 14, 23, 28, 34, 44, 49, 56, 64, 92, 97, 111, 121, 134, 147]
|
||||
for r in check_rows:
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "GET",
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values/{sheet_id}!D{r}:F{r}?valueRenderOption=ToString",
|
||||
"-H", f"Authorization: Bearer {token}"
|
||||
], capture_output=True, text=True)
|
||||
vals = json.loads(result.stdout).get("data", {}).get("valueRange", {}).get("values", [[]])[0]
|
||||
role = vals[0] if len(vals) > 0 else "-"
|
||||
e_val = vals[1] if len(vals) > 1 else "-"
|
||||
f_val = vals[2] if len(vals) > 2 else "-"
|
||||
expected = f_map.get(r, "-")
|
||||
status = "✓" if f_val == (expected or "") else "✗ MISMATCH"
|
||||
if status != "✓":
|
||||
print(f" Row {r}: [{role}] E='{e_val}' F='{f_val}' expected='{expected}' {status}")
|
||||
else:
|
||||
print(f" Row {r}: [{role}] F='{f_val}' {status}")
|
||||
|
||||
print("\nAll verified!")
|
||||
@ -1,371 +0,0 @@
|
||||
import pandas as pd
|
||||
from openpyxl import load_workbook
|
||||
|
||||
# 读取原始Excel
|
||||
input_path = "/root/.openclaw/media/inbound/12-5---1879d0c9-7cdf-4cd5-9aff-f03091ebada3.xlsx"
|
||||
output_path = "/root/.openclaw/workspace-xiaoyan/L1-S1-U12-L5_组件完成版.xlsx"
|
||||
|
||||
# 定义组件内容,按顺序对应表格中的组件行
|
||||
components = [
|
||||
# 1112501 对话朗读
|
||||
"""【任务标题】描述当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: It is still night.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Vicky : Wait, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112502 图片单选
|
||||
"""【任务标题】等待清晨
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:We must wait for the $morning$.
|
||||
选项:
|
||||
00
|
||||
01(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh no, that's not right. Look outside, it's still dark!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112503 对话朗读
|
||||
"""【任务标题】询问清晨时间
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Vicky: How do we know when it's morning?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, I didn't catch that. Can you say it again?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112504 对话朗读
|
||||
"""【任务标题】表达尝试意愿
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I'd like to try too.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Ben: Me too.""",
|
||||
# 1112505 对话朗读
|
||||
"""【任务标题】尝试做手影狗
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I want to try to make a dog!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Wait, what did you say? I didn't get it.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112506 对话朗读
|
||||
"""【任务标题】评价夜晚乐趣
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Night is so much fun!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Hmm, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112507 对话挖空
|
||||
"""【任务标题】否定当前是清晨
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It isn't ____.
|
||||
选项:
|
||||
选项1:night
|
||||
选项2:morning(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Oh no, that's wrong. It's still dark out!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112508 对话挖空
|
||||
"""【任务标题】确认当前是夜晚
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It is still ____!
|
||||
选项:
|
||||
选项1:night(正确)
|
||||
选项2:morning
|
||||
辅助信息:night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Wait, that's not right. The sun isn't up yet!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112509 对话朗读
|
||||
"""【任务标题】提议逐个尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Let's try them one by one!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112510 对话选读
|
||||
"""【任务标题】尝试下一个格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
请选择一句朗读:
|
||||
选项1:Let's try the next!
|
||||
选项2:Let's try them one by one!
|
||||
辅助信息:两个选项均为正确答案
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that's not one of the choices.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112510 图片有序
|
||||
"""【任务标题】排序跳格子顺序
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:Put the actions in order of $one by one$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确顺序:00→01→02→03
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Oops, that's the wrong order! We can't jump like that.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112511 对话挖空
|
||||
"""【任务标题】提议尝试另一块格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:____ that one.
|
||||
选项:
|
||||
选项1:let's try(正确)
|
||||
选项2:let's play
|
||||
辅助信息:let's try指"我们试试"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Wait, that doesn't make sense.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112512 对话朗读
|
||||
"""【任务标题】询问下一个人选
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Who is the next?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Vicky: It's my turn!""",
|
||||
# 1112513 对话挖空
|
||||
"""【任务标题】描述灯逐个亮起
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:The lights are turning on ____!
|
||||
选项:
|
||||
选项1:one by one(正确)
|
||||
选项2:two by two
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Oh no, that's wrong! The lights are turning on in order.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112514 对话组句
|
||||
"""【任务标题】组句提议尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
User: The first tile didn't work.
|
||||
|
||||
【互动内容】
|
||||
题目:提议大家试试另一块格子
|
||||
选项1:try this
|
||||
选项2:Let's
|
||||
选项3:one.
|
||||
答案:Let's try this one.
|
||||
辅助信息:Let's do sth.是提议做某事的固定句式
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oops, that's not the right sentence.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112516 对话组句
|
||||
"""【任务标题】组句逐个行动
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Sally: We need to stand on the tiles one after another.
|
||||
|
||||
【互动内容】
|
||||
题目:告诉大家要一个接一个做
|
||||
选项1:Let's do it
|
||||
选项2:one
|
||||
选项3:by
|
||||
选项4:one!
|
||||
答案:Let's do it one by one!
|
||||
辅助信息:one by one是固定搭配,意思是"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't make sense. Try again.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
# 1112517 对话选择
|
||||
"""【任务标题】判断当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Fred: I see the light from the lighthouse!
|
||||
|
||||
【互动内容】
|
||||
Wow! It's so bright! ____
|
||||
选项:
|
||||
选项1:It's morning now!(正确)
|
||||
选项2:It's night now!
|
||||
辅助信息:morning指"清晨",night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Fred : Wait, that's not right! Look at the sun in the sky!
|
||||
|
||||
【后置对话】
|
||||
无"""
|
||||
]
|
||||
|
||||
# 加载工作簿
|
||||
wb = load_workbook(input_path)
|
||||
ws = wb.active
|
||||
|
||||
# 找到组件列(第7列,索引从1开始)
|
||||
component_col = 7
|
||||
# 找到有组件ID的行,从第6行开始是数据行
|
||||
component_row_start = 6
|
||||
|
||||
# 逐个填入组件内容
|
||||
for i, comp in enumerate(components):
|
||||
row = component_row_start + i
|
||||
ws.cell(row=row, column=component_col, value=comp)
|
||||
|
||||
# 保存文件
|
||||
wb.save(output_path)
|
||||
print(f"文件已保存到: {output_path}")
|
||||
@ -1,351 +0,0 @@
|
||||
from openpyxl import load_workbook
|
||||
|
||||
# 读取原始Excel
|
||||
input_path = "/root/.openclaw/media/inbound/12-5---1879d0c9-7cdf-4cd5-9aff-f03091ebada3.xlsx"
|
||||
output_path = "/root/.openclaw/workspace-xiaoyan/L1-S1-U12-L5_组件完成版_按ID匹配.xlsx"
|
||||
|
||||
# 定义组件内容,按ID对应行号(Excel行号从1开始)
|
||||
component_map = {
|
||||
32: """【任务标题】描述当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: It is still night.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Vicky : Wait, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
33: """【任务标题】等待清晨
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:We must wait for the $morning$.
|
||||
选项:
|
||||
00
|
||||
01(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh no, that's not right. Look outside, it's still dark!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
34: """【任务标题】询问清晨时间
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Vicky: How do we know when it's morning?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, I didn't catch that. Can you say it again?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
52: """【任务标题】表达尝试意愿
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I'd like to try too.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Ben: Me too.""",
|
||||
59: """【任务标题】尝试做手影狗
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I want to try to make a dog!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Wait, what did you say? I didn't get it.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
70: """【任务标题】评价夜晚乐趣
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Night is so much fun!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Hmm, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
85: """【任务标题】否定当前是清晨
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It isn't ____.
|
||||
选项:
|
||||
选项1:night
|
||||
选项2:morning(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Oh no, that's wrong. It's still dark out!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
86: """【任务标题】确认当前是夜晚
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It is still ____!
|
||||
选项:
|
||||
选项1:night(正确)
|
||||
选项2:morning
|
||||
辅助信息:night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Wait, that's not right. The sun isn't up yet!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
96: """【任务标题】提议逐个尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Let's try them one by one!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
104: """【任务标题】尝试下一个格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
请选择一句朗读:
|
||||
选项1:Let's try the next!
|
||||
选项2:Let's try them one by one!
|
||||
辅助信息:两个选项均为正确答案
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that's not one of the choices.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
110: """【任务标题】排序跳格子顺序
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:Put the actions in order of $one by one$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确顺序:00→01→02→03
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Oops, that's the wrong order! We can't jump like that.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
118: """【任务标题】提议尝试另一块格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:____ that one.
|
||||
选项:
|
||||
选项1:let's try(正确)
|
||||
选项2:let's play
|
||||
辅助信息:let's try指"我们试试"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Wait, that doesn't make sense.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
124: """【任务标题】询问下一个人选
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Who is the next?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Vicky: It's my turn!""",
|
||||
127: """【任务标题】描述灯逐个亮起
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:The lights are turning on ____!
|
||||
选项:
|
||||
选项1:one by one(正确)
|
||||
选项2:two by two
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Oh no, that's wrong! The lights are turning on in order.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
136: """【任务标题】组句提议尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
User: The first tile didn't work.
|
||||
|
||||
【互动内容】
|
||||
题目:提议大家试试另一块格子
|
||||
选项1:try this
|
||||
选项2:Let's
|
||||
选项3:one.
|
||||
答案:Let's try this one.
|
||||
辅助信息:Let's do sth.是提议做某事的固定句式
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oops, that's not the right sentence.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
155: """【任务标题】组句逐个行动
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Sally: We need to stand on the tiles one after another.
|
||||
|
||||
【互动内容】
|
||||
题目:告诉大家要一个接一个做
|
||||
选项1:Let's do it
|
||||
选项2:one
|
||||
选项3:by
|
||||
选项4:one!
|
||||
答案:Let's do it one by one!
|
||||
辅助信息:one by one是固定搭配,意思是"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't make sense. Try again.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
179: """【任务标题】判断当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Fred: I see the light from the lighthouse!
|
||||
|
||||
【互动内容】
|
||||
Wow! It's so bright! ____
|
||||
选项:
|
||||
选项1:It's morning now!(正确)
|
||||
选项2:It's night now!
|
||||
辅助信息:morning指"清晨",night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Fred : Wait, that's not right! Look at the sun in the sky!
|
||||
|
||||
【后置对话】
|
||||
无"""
|
||||
}
|
||||
|
||||
# 加载工作簿
|
||||
wb = load_workbook(input_path)
|
||||
ws = wb.active
|
||||
|
||||
# 组件列是第7列(G列)
|
||||
component_col = 7
|
||||
|
||||
# 按行号填入组件
|
||||
for row_num, comp_content in component_map.items():
|
||||
ws.cell(row=row_num, column=component_col, value=comp_content)
|
||||
|
||||
# 保存文件
|
||||
wb.save(output_path)
|
||||
print(f"文件已保存到: {output_path}")
|
||||
print(f"已为{len(component_map)}个组件ID匹配并填入对应行")
|
||||
@ -1,355 +0,0 @@
|
||||
from openpyxl import load_workbook
|
||||
|
||||
# 读取原始Excel
|
||||
input_path = "/root/.openclaw/media/inbound/12-5---1879d0c9-7cdf-4cd5-9aff-f03091ebada3.xlsx"
|
||||
output_path = "/root/.openclaw/workspace-xiaoyan/L1-S1-U12-L5_组件完成版_最终匹配版.xlsx"
|
||||
|
||||
# 正确的组件ID对应行号(第一列有组件ID的行,为Excel实际行号)
|
||||
component_map = {
|
||||
32: """【任务标题】描述当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: It is still night.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Vicky : Wait, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
33: """【任务标题】等待清晨
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:We must wait for the $morning$.
|
||||
选项:
|
||||
00
|
||||
01(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh no, that's not right. Look outside, it's still dark!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
34: """【任务标题】询问清晨时间
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Vicky: How do we know when it's morning?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, I didn't catch that. Can you say it again?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
52: """【任务标题】表达尝试意愿
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I'd like to try too.(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Ben: Me too.""",
|
||||
58: """【任务标题】尝试做手影狗
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: I want to try to make a dog!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Wait, what did you say? I didn't get it.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
69: """【任务标题】评价夜晚乐趣
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Night is so much fun!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Hmm, that didn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
84: """【任务标题】否定当前是清晨
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It isn't ____.
|
||||
选项:
|
||||
选项1:night
|
||||
选项2:morning(正确)
|
||||
辅助信息:morning指"清晨"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Oh no, that's wrong. It's still dark out!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
85: """【任务标题】确认当前是夜晚
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:It is still ____!
|
||||
选项:
|
||||
选项1:night(正确)
|
||||
选项2:morning
|
||||
辅助信息:night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Ben : Wait, that's not right. The sun isn't up yet!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
95: """【任务标题】提议逐个尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Let's try them one by one!(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
103: """【任务标题】尝试下一个格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
请选择一句朗读:
|
||||
选项1:Let's try the next!
|
||||
选项2:Let's try them one by one!
|
||||
辅助信息:两个选项均为正确答案
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that's not one of the choices.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
109: """【任务标题】排序跳格子顺序
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:Put the actions in order of $one by one$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确顺序:00→01→02→03
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Oops, that's the wrong order! We can't jump like that.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
117: """【任务标题】提议尝试另一块格子
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:____ that one.
|
||||
选项:
|
||||
选项1:let's try(正确)
|
||||
选项2:let's play
|
||||
辅助信息:let's try指"我们试试"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Wait, that doesn't make sense.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
123: """【任务标题】询问下一个人选
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
User: Who is the next?(朗读)
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Hmm, that didn't sound quite right.
|
||||
|
||||
【后置对话】
|
||||
Vicky: It's my turn!""",
|
||||
126: """【任务标题】描述灯逐个亮起
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题干:The lights are turning on ____!
|
||||
选项:
|
||||
选项1:one by one(正确)
|
||||
选项2:two by two
|
||||
辅助信息:one by one指"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Lucy : Oh no, that's wrong! The lights are turning on in order.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
135: """【任务标题】组句提议尝试
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
User: The first tile didn't work.
|
||||
|
||||
【互动内容】
|
||||
题目:提议大家试试另一块格子
|
||||
选项1:try this
|
||||
选项2:Let's
|
||||
选项3:one.
|
||||
答案:Let's try this one.
|
||||
辅助信息:Let's do sth.是提议做某事的固定句式
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oops, that's not the right sentence.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
154: """【任务标题】组句逐个行动
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Sally: We need to stand on the tiles one after another.
|
||||
|
||||
【互动内容】
|
||||
题目:告诉大家要一个接一个做
|
||||
选项1:Let's do it
|
||||
选项2:one
|
||||
选项3:by
|
||||
选项4:one!
|
||||
答案:Let's do it one by one!
|
||||
辅助信息:one by one是固定搭配,意思是"一个接一个"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Oh, that doesn't make sense. Try again.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
178: """【任务标题】判断当前时间
|
||||
【资源配置】
|
||||
图片时机:【互动内容】
|
||||
音频载体:无
|
||||
|
||||
【情境引入】
|
||||
Fred: I see the light from the lighthouse!
|
||||
|
||||
【互动内容】
|
||||
Wow! It's so bright! ____
|
||||
选项:
|
||||
选项1:It's morning now!(正确)
|
||||
选项2:It's night now!
|
||||
辅助信息:morning指"清晨",night指"夜晚"
|
||||
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Fred : Wait, that's not right! Look at the sun in the sky!
|
||||
|
||||
【后置对话】
|
||||
无"""
|
||||
}
|
||||
|
||||
# 加载工作簿
|
||||
wb = load_workbook(input_path)
|
||||
ws = wb.active
|
||||
|
||||
# 组件列是第7列(G列)
|
||||
component_col = 7
|
||||
|
||||
# 先清空原有组件列的内容(避免残留内容)
|
||||
for row_num in component_map.keys():
|
||||
ws.cell(row=row_num, column=component_col, value="")
|
||||
|
||||
# 按正确行号填入组件
|
||||
for row_num, comp_content in component_map.items():
|
||||
ws.cell(row=row_num, column=component_col, value=comp_content)
|
||||
|
||||
# 保存文件
|
||||
wb.save(output_path)
|
||||
print(f"文件已保存到: {output_path}")
|
||||
print(f"已为{len(component_map)}个组件ID 100%匹配填入对应行")
|
||||
@ -1,222 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fix component production issues:
|
||||
1. Regenerate 4 对话朗读 rows with correct format (no 组件ID, correct 资源配置)
|
||||
2. Fix Chinese error feedback → English for 7 other rows
|
||||
"""
|
||||
import requests, json, time, os
|
||||
|
||||
CRED_PATH = "/root/.openclaw/credentials/xiaoyan/config.json"
|
||||
SHEET_TOKEN = "VgPwsodzthsk9Vti8GocrbH2nEe"
|
||||
SHEET_ID = "wMQVyV"
|
||||
OUTPUT_DIR = "/root/.openclaw/workspace-xiaoyan/business_production/组件生产/output"
|
||||
|
||||
LLM_BASE = "https://ark.cn-beijing.volces.com/api/v3"
|
||||
LLM_KEY = "32994652-505c-492b-b6da-616ec5c5733c"
|
||||
LLM_MODEL = "ep-m-20260301164317-vmmj4"
|
||||
|
||||
def get_token():
|
||||
with open(CRED_PATH) as f: c = json.load(f)
|
||||
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
json={"app_id": c["apps"][0]["appId"], "app_secret": c["apps"][0]["appSecret"]})
|
||||
return r.json()["tenant_access_token"]
|
||||
|
||||
def get_sheet(token):
|
||||
r = requests.get(
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SHEET_TOKEN}/values/{SHEET_ID}?majorDimension=ROWS",
|
||||
headers={"Authorization": f"Bearer {token}"})
|
||||
return r.json()["data"]["valueRange"]["values"]
|
||||
|
||||
def write_cell(token, sheet_row, content):
|
||||
range_str = f"{SHEET_ID}!H{sheet_row}:H{sheet_row}"
|
||||
r = requests.put(
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SHEET_TOKEN}/values",
|
||||
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||
json={"valueRange": {"range": range_str, "values": [[content]]}})
|
||||
return r.json().get("code") == 0
|
||||
|
||||
def parse_col(row, idx):
|
||||
if isinstance(row[idx], list):
|
||||
return "".join([seg.get("text","") for seg in row[idx] if isinstance(seg, dict)])
|
||||
return str(row[idx]) if row[idx] else ""
|
||||
|
||||
def llm(messages):
|
||||
try: from openai import OpenAI
|
||||
except: os.system("pip install openai --break-system-packages -q"); from openai import OpenAI
|
||||
client = OpenAI(base_url=LLM_BASE, api_key=LLM_KEY)
|
||||
resp = client.chat.completions.create(
|
||||
model=LLM_MODEL, messages=messages, temperature=0.3, max_tokens=1000,
|
||||
extra_body={"thinking": {"type": "disabled"}})
|
||||
return resp.choices[0].message.content.strip()
|
||||
|
||||
# === FIX: 对话朗读 regeneration ===
|
||||
READING_SYSTEM = """You fix dialogue reading component configs.
|
||||
|
||||
## CORRECT FORMAT (exactly this, no variation):
|
||||
|
||||
【任务标题】{contextual title fitting the scene, ≤10 chars}
|
||||
【资源配置】
|
||||
图片时机:
|
||||
情境引入
|
||||
互动内容
|
||||
互动反馈
|
||||
【情境引入】
|
||||
{Character: line, or 无 if no context needed}
|
||||
【互动内容】
|
||||
{Character}: {sentence}(朗读)
|
||||
【后置对话】
|
||||
{Character: next line from context, or 无}
|
||||
|
||||
## KEY RULES
|
||||
- NO 【组件ID】 field at all!
|
||||
- NO 音频载体 line!
|
||||
- NO 【互动反馈】 section!
|
||||
- 资源配置 uses line-break stage listing format (情境引入/互动内容/互动反馈 on separate lines)
|
||||
- Task title must match the scene context, not generic like "朗读台词"
|
||||
- Error feedback (互动反馈) appears only as a stage name in 资源配置, NOT as a separate section
|
||||
- Generate only the component config text, no explanation"""
|
||||
|
||||
def fix_reading(token, row_data):
|
||||
"""Regenerate a 对话朗读 component"""
|
||||
messages = [
|
||||
{"role": "system", "content": READING_SYSTEM},
|
||||
{"role": "user", "content": f"""Fix this 对话朗读 component:
|
||||
|
||||
Context:
|
||||
- Scene: {row_data.get('plot','')}
|
||||
- Knowledge Point: {row_data.get('kp','')}
|
||||
|
||||
Dialogue before:
|
||||
{row_data.get('ctx_before','')}
|
||||
|
||||
Current interaction:
|
||||
{row_data.get('char','User')}: {row_data.get('script_en','')}
|
||||
|
||||
Dialogue after:
|
||||
{row_data.get('ctx_after','')}
|
||||
|
||||
Generate the corrected component config following the format exactly. Make the task title contextual and scene-fitting."""}
|
||||
]
|
||||
return llm(messages)
|
||||
|
||||
# === FIX: Chinese error feedback → English ===
|
||||
FB_SYSTEM = """You fix Chinese error feedback in English learning component configs.
|
||||
Replace Chinese feedback text with natural English character dialogue that matches the scene context and character personality.
|
||||
Keep everything else exactly the same. Only change the error feedback text.
|
||||
|
||||
Format: return the complete fixed component config text, changing ONLY the error feedback lines."""
|
||||
|
||||
def fix_feedback(token, old_content, context):
|
||||
"""Fix Chinese error feedback"""
|
||||
messages = [
|
||||
{"role": "system", "content": FB_SYSTEM},
|
||||
{"role": "user", "content": f"""Fix the Chinese error feedback in this component config:
|
||||
|
||||
Component context: {context}
|
||||
|
||||
Current config:
|
||||
{old_content}
|
||||
|
||||
Return the complete fixed config with Chinese feedback replaced by natural English character dialogue."""}
|
||||
]
|
||||
return llm(messages)
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
values = get_sheet(token)
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
# Collect context for all rows
|
||||
rows = []
|
||||
for i, row in enumerate(values):
|
||||
while len(row) < 8: row.append(None)
|
||||
rtype = str(row[0]).strip() if row[0] else ""
|
||||
rows.append({
|
||||
"sheet_row": i+1, "type": rtype,
|
||||
"id": str(row[1]).strip() if row[1] else "",
|
||||
"plot": str(row[2]).strip() if row[2] else "",
|
||||
"char": str(row[3]).strip() if row[3] else "",
|
||||
"script_cn": parse_col(row, 4), "script_en": parse_col(row, 5),
|
||||
"kp": str(row[6]).strip() if row[6] else "",
|
||||
"h_col": str(row[7]) if row[7] else "",
|
||||
})
|
||||
|
||||
# Find dialogue reading rows and other fixable rows
|
||||
reading_rows = []
|
||||
cn_feedback_rows = []
|
||||
|
||||
for i, r in enumerate(rows):
|
||||
if r["type"] == "对话朗读" and r["h_col"]:
|
||||
# Get context
|
||||
ctx_before = []
|
||||
for j in range(max(0,i-4), i):
|
||||
if rows[j]["char"] and rows[j]["script_cn"]:
|
||||
ctx_before.append(f"{rows[j]['char']}: {rows[j]['script_cn']}")
|
||||
ctx_after = []
|
||||
for j in range(i+1, min(len(rows), i+4)):
|
||||
if rows[j]["char"] and rows[j]["script_cn"]:
|
||||
ctx_after.append(f"{rows[j]['char']}: {rows[j]['script_cn']}")
|
||||
r["ctx_before"] = "\n".join(ctx_before)
|
||||
r["ctx_after"] = "\n".join(ctx_after)
|
||||
reading_rows.append(r)
|
||||
|
||||
elif r["h_col"]:
|
||||
# Check for Chinese error feedback
|
||||
err_idx = r["h_col"].find("错误:")
|
||||
if err_idx > 0:
|
||||
err_line = r["h_col"][err_idx:].split("\n")[0]
|
||||
has_cn = any('\u4e00' <= c <= '\u9fff' for c in err_line)
|
||||
# Skip section headers (正确/错误) - only check after "错误:" before newline
|
||||
fb_text = err_line.split("错误:")[1] if "错误:" in err_line else err_line
|
||||
if any('\u4e00' <= c <= '\u9fff' for c in fb_text):
|
||||
cn_feedback_rows.append(r)
|
||||
|
||||
print(f"对话朗读 to fix: {len(reading_rows)}")
|
||||
print(f"中文反馈 to fix: {len(cn_feedback_rows)}")
|
||||
|
||||
results = []
|
||||
|
||||
# Fix dialogue readings
|
||||
for r in reading_rows:
|
||||
row_num = r["sheet_row"]
|
||||
print(f"\n[对话朗读] Row {row_num} ID={r['id']}")
|
||||
try:
|
||||
new_content = fix_reading(token, r)
|
||||
print(f" Generated: {new_content[:100]}...")
|
||||
if write_cell(token, row_num, new_content):
|
||||
print(f" ✅ Written to H{row_num}")
|
||||
results.append({"row": row_num, "type": "对话朗读", "status": "fixed"})
|
||||
else:
|
||||
print(f" ❌ Write failed")
|
||||
results.append({"row": row_num, "type": "对话朗读", "status": "write_fail"})
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
results.append({"row": row_num, "type": "对话朗读", "status": str(e)})
|
||||
time.sleep(0.5)
|
||||
|
||||
# Fix Chinese feedback
|
||||
for r in cn_feedback_rows:
|
||||
row_num = r["sheet_row"]
|
||||
rtype = r["type"]
|
||||
print(f"\n[{rtype}] Row {row_num} ID={r['id']} — fixing Chinese feedback")
|
||||
ctx = f"Character: {r['char']}, Plot: {r['plot']}, KP: {r['kp']}"
|
||||
try:
|
||||
new_content = fix_feedback(token, r["h_col"], ctx)
|
||||
if write_cell(token, row_num, new_content):
|
||||
print(f" ✅ Written")
|
||||
results.append({"row": row_num, "type": rtype, "status": "fb_fixed"})
|
||||
else:
|
||||
print(f" ❌ Write failed")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
time.sleep(0.5)
|
||||
|
||||
# Summary
|
||||
ok = sum(1 for r in results if "fail" not in r["status"] and "Error" not in str(r["status"]))
|
||||
print(f"\n{'='*40}")
|
||||
print(f"Fixed: {ok}/{len(results)}")
|
||||
for r in results:
|
||||
print(f" H{r['row']} [{r['type']}]: {r['status']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,444 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate component configurations for the script sheet and write them back."""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# Get bot token
|
||||
def get_token():
|
||||
result = subprocess.run(
|
||||
["jq", "-r", ".apps[0].appSecret",
|
||||
"/root/.openclaw/credentials/xiaoyan/config.json"],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
app_secret = result.stdout.strip()
|
||||
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
data = json.dumps({"app_id": "cli_a931175d41799cc7", "app_secret": app_secret}).encode()
|
||||
req = urllib.request.Request(
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
data=data,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
resp = json.loads(urllib.request.urlopen(req).read())
|
||||
return resp["tenant_access_token"]
|
||||
|
||||
TOKEN = get_token()
|
||||
SPREADSHEET_TOKEN = "Dk1fs7TJ4hWs5PtUvXlc1EaEnvb"
|
||||
SHEET_ID = "fmqYrx"
|
||||
|
||||
# Component configurations for each row
|
||||
# Format: {row_number: config_text}
|
||||
|
||||
CONFIGS = {
|
||||
# Row 12: 图片无序多选 (1217101) - motorbike
|
||||
12: """【任务标题】
|
||||
在图片中寻找摩托车
|
||||
|
||||
【情境引入】
|
||||
Ben: Whoa! Those are motorbikes!
|
||||
User: Where? Let me take a look.
|
||||
|
||||
【互动内容】
|
||||
Find the $motorbikes$ in the picture.(音频)
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
答案:
|
||||
00
|
||||
01
|
||||
辅助信息:motorbike 指"摩托车"。
|
||||
|
||||
【互动反馈】
|
||||
正确 Ben : That's right! Those are two motorbikes!
|
||||
错误 Ben : Look again. Can you find the motorbikes?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 30: 对话朗读 (1217102) - people
|
||||
30: """【任务标题】
|
||||
询问那些人是谁
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Who are those people?(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 46: 对话挖空 (1217103) - people
|
||||
46: """【任务标题】
|
||||
向镇长报告发现
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
User: Tom! We found two strange people.
|
||||
|
||||
【互动内容】
|
||||
We found two strange ___.(音频)
|
||||
选项1:people(正确)
|
||||
选项2:animals
|
||||
|
||||
【互动反馈】
|
||||
正确 Tom : Good! Tell me more about them.
|
||||
错误 Tom : Animals? Are you sure about that?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 53: 对话挖空 (1217104) - motorbike
|
||||
53: """【任务标题】
|
||||
描述可疑人员的特征
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Tom: Tell me more about them.
|
||||
|
||||
【互动内容】
|
||||
They're on ___.(音频)
|
||||
选项1:motorbikes(正确)
|
||||
选项2:bicycles
|
||||
|
||||
【互动反馈】
|
||||
正确 Tom : Good job! I'm coming right now!
|
||||
错误 Tom : Bicycles? That doesn't sound right.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 67: 对话朗读 (1217105) - people
|
||||
67: """【任务标题】
|
||||
盘问来人身份
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Who are you people?(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 81: 对话挖空 (1217106) - show
|
||||
81: """【任务标题】
|
||||
要求检查袋子
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Jay: The bag is a secret!
|
||||
|
||||
【互动内容】
|
||||
You must ___ me what is in the bag!(音频)
|
||||
选项1:show(正确)
|
||||
选项2:tell
|
||||
|
||||
【互动反馈】
|
||||
正确 Jay : No, no! We can't show you!
|
||||
错误 Jay : Ha! We won't tell you, either!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 96: 对话选择 (1217107) - motorbike
|
||||
96: """【任务标题】
|
||||
回应 Jay 的炫耀
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Jay: Let me show you how fast it is!
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:Your motorbike looks really old.(正确)
|
||||
- 反馈: 无
|
||||
选项2:Your motorbike looks so cool!
|
||||
- 反馈 Jay : Thank you, kid! But let me show you more!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 110: 对话朗读 (1217108) - Show...
|
||||
110: """【任务标题】
|
||||
要求 Jay 继续展示
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Wow! Show me more!(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 122: 对话组句 (1217109) - Show...
|
||||
122: """【任务标题】
|
||||
请 Lin 展示摩托车
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Lin: My motorbike never does that.
|
||||
|
||||
【互动内容】
|
||||
题目:请 Lin 展示她的摩托车
|
||||
(音频)
|
||||
选项1:Cool
|
||||
选项2:Show
|
||||
选项3:me
|
||||
选项4:your
|
||||
选项5:motorbike
|
||||
答案:Cool! Show me your motorbike!
|
||||
辅助信息:Cool 作感叹词放句首;Show me 后接名词表示"给我看看..."。
|
||||
|
||||
【互动反馈】
|
||||
正确 Lin : Hmph. Fine.
|
||||
错误 Lin : What do you want me to show?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 142: 对话选读 (1217110) - motorbike
|
||||
142: """【任务标题】
|
||||
评价谁的摩托车更好
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Jay: Hey kids! Which motorbike is better?
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:
|
||||
选项1:I think the red motorbike is better.
|
||||
- 反馈 Jay : What? I don't agree!
|
||||
选项2:I think the orange motorbike is better.
|
||||
- 反馈 Lin : Hey! You're wrong!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 161: 对话朗读 (1217111) - ... can/can't hold...
|
||||
161: """【任务标题】
|
||||
答应帮忙拿袋子
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Okay! I can hold it.(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 176: 对话选择 (1217112) - ... can/can't hold...
|
||||
176: """【任务标题】
|
||||
回应 Ben 的关心
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Ben: Are you okay?
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:Don't worry. I can hold it.(正确)
|
||||
- 反馈: 无
|
||||
选项2:Help! I can't hold it!
|
||||
- 反馈 Ben : Oh no! Let me help you!
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 192: 对话组句 (1217113) - ... can/can't hold...
|
||||
192: """【任务标题】
|
||||
让 Ben 放心你能拿住
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Ben: Let's see what's inside.
|
||||
|
||||
【互动内容】
|
||||
题目:告诉 Ben 你能拿住袋子,让他放心
|
||||
(音频)
|
||||
选项1:Don't
|
||||
选项2:worry
|
||||
选项3:I
|
||||
选项4:can
|
||||
选项5:hold
|
||||
选项6:it
|
||||
答案:Don't worry. I can hold it.
|
||||
辅助信息:Don't worry 表示"别担心";can 后跟动词原形表示"能/会"。
|
||||
|
||||
【互动反馈】
|
||||
正确 Ben : Ouch!
|
||||
错误 Ben : What? Are you okay?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 204: 对话朗读 (1217114) - ... can/can't hold...
|
||||
204: """【任务标题】
|
||||
呼救求助
|
||||
|
||||
【资源配置】
|
||||
图片时机:无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
I can't hold it!(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 233: 阅读理解 (1217115) - motorbike/people/hold/show
|
||||
233: """【任务标题】
|
||||
向 Tom 描述事情的经过
|
||||
|
||||
【情境引入】
|
||||
Tom: Can anybody tell me what happened here?
|
||||
|
||||
【互动内容】
|
||||
问题1:Who came from out of town?
|
||||
答案:These two people.
|
||||
|
||||
问题2:What did they ride?
|
||||
答案:They ride motorbikes.
|
||||
|
||||
问题3:What did you ask them to do?
|
||||
答案:Show us what's in their bags.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 245: 对话选读 (1217116) - ... can/can't hold...
|
||||
245: """【任务标题】
|
||||
为自己的失误道歉
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
Lin: And you opened the bags without asking.
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:
|
||||
选项1:Sorry, but I can't hold it.
|
||||
- 反馈 Tom : It's okay. Everybody makes mistakes.
|
||||
选项2:Sorry, I can't hold it anymore.
|
||||
- 反馈 Tom : It's okay. Everybody makes mistakes.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
}
|
||||
|
||||
|
||||
def write_to_sheet(row, config_text):
|
||||
"""Write config to a single cell in the sheet."""
|
||||
import urllib.request
|
||||
|
||||
range_str = f"{SHEET_ID}!H{row}:H{row}"
|
||||
data = json.dumps({
|
||||
"valueRange": {
|
||||
"range": range_str,
|
||||
"values": [[config_text]]
|
||||
}
|
||||
}).encode()
|
||||
|
||||
req = urllib.request.Request(
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values",
|
||||
data=data,
|
||||
headers={
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
method="PUT"
|
||||
)
|
||||
resp = json.loads(urllib.request.urlopen(req).read())
|
||||
return resp.get("code") == 0
|
||||
|
||||
|
||||
def verify_write(row, expected_prefix):
|
||||
"""Verify what was written."""
|
||||
import urllib.request
|
||||
range_str = f"{SHEET_ID}!H{row}:H{row}"
|
||||
url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values/{range_str}?valueRenderOption=ToString"
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {TOKEN}"})
|
||||
resp = json.loads(urllib.request.urlopen(req).read())
|
||||
values = resp.get("data", {}).get("valueRange", {}).get("values", [])
|
||||
if values and values[0] and values[0][0]:
|
||||
actual = values[0][0]
|
||||
if actual.startswith(expected_prefix):
|
||||
return True, actual[:80]
|
||||
else:
|
||||
return False, actual[:80]
|
||||
return False, "EMPTY"
|
||||
|
||||
|
||||
def main():
|
||||
success = 0
|
||||
failed = []
|
||||
|
||||
for row, config in sorted(CONFIGS.items()):
|
||||
try:
|
||||
ok = write_to_sheet(row, config)
|
||||
if ok:
|
||||
prefix = config.strip()[:50].replace("\n", " ")
|
||||
verified, preview = verify_write(row, prefix[:20])
|
||||
if verified:
|
||||
print(f"✓ Row {row}: Written and verified - {preview}...")
|
||||
success += 1
|
||||
else:
|
||||
print(f"⚠ Row {row}: Write reported OK but verification failed: {preview}")
|
||||
failed.append(row)
|
||||
else:
|
||||
print(f"✗ Row {row}: Write failed")
|
||||
failed.append(row)
|
||||
except Exception as e:
|
||||
print(f"✗ Row {row}: Error - {e}")
|
||||
failed.append(row)
|
||||
|
||||
print(f"\n=== Summary ===")
|
||||
print(f"Success: {success}/{len(CONFIGS)}")
|
||||
if failed:
|
||||
print(f"Failed rows: {failed}")
|
||||
return 0 if not failed else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -1,238 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Produce dialogue component configs and write back to F column."""
|
||||
|
||||
import subprocess, json
|
||||
|
||||
TOKEN = "t-g1045kg0ZYXHLVSY7EFUPUJUOLBGTOLYLPDKWLYN"
|
||||
SHEET_ID = "wMQVyV"
|
||||
SPREADSHEET_TOKEN = "It4AsFkC7hXHc4te9yUcyLHRnOe"
|
||||
|
||||
components = {
|
||||
# Row 111: 对话选择-配图 (1217408)
|
||||
111: """【任务标题】
|
||||
打开坏掉的门
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:The door is open.(正确)
|
||||
- 反馈: 无
|
||||
选项2:The door is closed.
|
||||
- 反馈 Alex: No, look. This door is broken. It's always open.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 120: 对话选择-配图 (1217409)
|
||||
120: """【任务标题】
|
||||
查看关闭的门
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
要求:选择正确的回复
|
||||
选项:(音频)
|
||||
选项1:Look, the door is closed.(正确)
|
||||
- 反馈: 无
|
||||
选项2:Look, the door is open.
|
||||
- 反馈 Eva: No, this door is closed. Look again.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 129: 对话挖空-配图 (1217410)
|
||||
129: """【任务标题】
|
||||
还剩最后一扇门
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
Only one ___ left.(音频)
|
||||
选项1:door(正确)
|
||||
选项2:room
|
||||
|
||||
【互动反馈】
|
||||
正确 Vicky : Yes! Just one more room.
|
||||
错误 Vicky : Think about it. What do we open?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 133: 对话组句-配图 (1217411)
|
||||
133: """【任务标题】
|
||||
发现门是关着的
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题目:描述这扇门的状态
|
||||
(音频)
|
||||
选项1:The
|
||||
选项2:door
|
||||
选项3:is
|
||||
选项4:closed
|
||||
答案:The door is closed.
|
||||
辅助信息:用主语 The door + is + 状态词描述门的状态
|
||||
|
||||
【互动反馈】
|
||||
正确 Vicky : Yes, it's closed. Peter must be inside!
|
||||
错误 Vicky : That doesn't look right. Think about the word order.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 144: 对话组句-配图 (1217412)
|
||||
144: """【任务标题】
|
||||
表示现在门打开了
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
题目:描述现在门的状态
|
||||
(音频)
|
||||
选项1:The
|
||||
选项2:door
|
||||
选项3:is
|
||||
选项4:open
|
||||
选项5:Now
|
||||
答案:Now the door is open.
|
||||
辅助信息:用主语 The door + is + 状态词描述门的状态;Now 放在句首表示时间
|
||||
|
||||
【互动反馈】
|
||||
正确 Alex : Yes! The door is open now.
|
||||
错误 Alex : Hmm, try putting the words in the right order.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 147: 看图拼词 (1217413)
|
||||
147: """【任务标题】
|
||||
拼写 door 的英文
|
||||
|
||||
【资源配置】
|
||||
图片文件名:1217413.png
|
||||
|
||||
【互动内容】
|
||||
任务描述:请拼出门的英文单词
|
||||
题干:d(2)r
|
||||
答案:oo
|
||||
选项:o, a, e, r, n, p
|
||||
辅助信息:门的英文是 door / 中间有两个一样的字母哦
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 163: 对话挖空 (1217414)
|
||||
163: """【任务标题】
|
||||
回忆窗户的状态
|
||||
|
||||
【资源配置】无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
I remember that. It was ___ before.(音频)
|
||||
选项1:closed(正确)
|
||||
选项2:open
|
||||
|
||||
【互动反馈】
|
||||
正确 Alex : Yes, it was closed. But now it's different.
|
||||
错误 Alex : No. Think about what I just said about the window.
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 164: 对话挖空 (1217415)
|
||||
164: """【任务标题】
|
||||
发现窗户现在是开着的
|
||||
|
||||
【资源配置】无
|
||||
|
||||
【情境引入】
|
||||
无
|
||||
|
||||
【互动内容】
|
||||
But now it's ___.(音频)
|
||||
选项1:open(正确)
|
||||
选项2:closed
|
||||
|
||||
【互动反馈】
|
||||
正确 Alex : Right! Someone opened it!
|
||||
错误 Alex : Look at the window again. Is it really closed now?
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
|
||||
# Row 179: 对话朗读 (1217416)
|
||||
179: """【任务标题】
|
||||
问候 Grace 和 Dan
|
||||
|
||||
【资源配置】图片时机:无
|
||||
|
||||
【情境引入】无
|
||||
|
||||
【互动内容】
|
||||
User : I'm glad you get home!(朗读)
|
||||
|
||||
【后置对话】
|
||||
无""",
|
||||
}
|
||||
|
||||
results = {}
|
||||
for row_num, content in sorted(components.items()):
|
||||
body = {
|
||||
"valueRange": {
|
||||
"range": f"{SHEET_ID}!F{row_num}:F{row_num}",
|
||||
"values": [[content]]
|
||||
}
|
||||
}
|
||||
cmd = [
|
||||
"curl", "-s", "-X", "PUT",
|
||||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values",
|
||||
"-H", f"Authorization: Bearer {TOKEN}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps(body, ensure_ascii=False)
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
resp = json.loads(result.stdout)
|
||||
code = resp.get("code", -1)
|
||||
msg = resp.get("msg", "unknown")
|
||||
print(f"Row {row_num}: code={code}, msg={msg}")
|
||||
results[row_num] = {"code": code, "msg": msg}
|
||||
|
||||
# Summary
|
||||
success = sum(1 for r in results.values() if r["code"] == 0)
|
||||
print(f"\nTotal: {len(results)} writes, {success} succeeded, {len(results) - success} failed")
|
||||
@ -1,249 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate and write F列 component configurations for L1-S2-U17-L4 门关啦"""
|
||||
import subprocess, json, sys
|
||||
|
||||
# ============================================================
|
||||
# Get Bot token
|
||||
# ============================================================
|
||||
APP_SECRET = json.load(open('/root/.openclaw/credentials/xiaoyan/config.json'))['apps'][0]['appSecret']
|
||||
r = subprocess.run(['curl', '-s', '-X', 'POST',
|
||||
'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
|
||||
'-H', 'Content-Type: application/json',
|
||||
'-d', json.dumps({"app_id": "cli_a931175d41799cc7", "app_secret": APP_SECRET})],
|
||||
capture_output=True, text=True)
|
||||
TOKEN = json.loads(r.stdout)['tenant_access_token']
|
||||
SST = 'It4AsFkC7hXHc4te9yUcyLHRnOe'
|
||||
SID = 'wMQVyV'
|
||||
|
||||
# ============================================================
|
||||
# All 16 component configurations → (row, config_text)
|
||||
# ============================================================
|
||||
configs = [
|
||||
# 1. Row10: 对话朗读 1217401 — S1主线 "准备回家"
|
||||
(10, """【任务标题】准备回家
|
||||
【资源配置】无
|
||||
【情境引入】Alex : Okay. Let's get home.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : I need to get home too.
|
||||
【后置对话】无"""),
|
||||
|
||||
# 2. Row15: 对话朗读 1217402 — S2主线 "回不了家了"
|
||||
(15, """【任务标题】回不了家了
|
||||
【资源配置】无
|
||||
【情境引入】大门被风吹关上了,Alex 的钥匙和 User 的包都在屋里。
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : I can't get home now!
|
||||
【后置对话】Vicky : Now we are all stuck here."""),
|
||||
|
||||
# 3. Row36: 对话朗读 1217403 — S4主线 "查看猫门"
|
||||
(36, """【任务标题】查看猫门
|
||||
【资源配置】无
|
||||
【情境引入】Vicky : Is it open now?
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Yes. The cat door is open.
|
||||
【后置对话】无"""),
|
||||
|
||||
# 4. Row48: 对话挖空 1217404 — S5主线 "拜托Peter"
|
||||
(48, """【任务标题】拜托Peter
|
||||
【资源配置】无
|
||||
【情境引入】Vicky : Peter, how about you?
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : Please, Peter. We want to ___ ___.
|
||||
答案词:get home
|
||||
【互动反馈】
|
||||
get home 正确 → Vicky : Peter, you're our only hope!
|
||||
get home 错误 → Vicky : Try again. What do we want to do?
|
||||
【后置对话】Vicky : Peter, you're my best little brother."""),
|
||||
|
||||
# 5. Row58: 对话挖空-配图 1217405 — S6主线 "称赞Peter"
|
||||
(58, """【任务标题】称赞Peter
|
||||
【资源配置】【配图】1217405_img
|
||||
【情境引入】Peter 从猫门钻进了屋子。
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : Great! You're ___ now.
|
||||
答案词:home
|
||||
【互动反馈】
|
||||
home 正确 → Alex : Yes! Peter is inside the house.
|
||||
home 错误 → Alex : Listen again. Where is Peter?
|
||||
【后置对话】无"""),
|
||||
|
||||
# 6. Row59: 图片单选-配图 1217406 — S7主线 "让Peter开门"
|
||||
(59, """【任务标题】让Peter开门
|
||||
【资源配置】【配图】1217406_optA.png、1217406_optB.png、1217406_optC.png
|
||||
【情境引入】Peter 已经进了屋,但需要他帮忙开门。
|
||||
【互动内容】
|
||||
题目:What did User ask Peter to do?
|
||||
选项A:Open the door(正确)
|
||||
- 反馈 Vicky : Yes! We asked Peter to open the door.
|
||||
选项B:Close the door
|
||||
- 反馈 Vicky : No. We need to get in, not stay out.
|
||||
选项C:Find the keys
|
||||
- 反馈 Vicky : Hmm, the keys are inside. What did we ask Peter?
|
||||
【后置对话】Peter : Hmm... Who are you?"""),
|
||||
|
||||
# 7. Row76: 对话朗读-配图 1217407 — S8主线 "门开了"
|
||||
(76, """【任务标题】门开了
|
||||
【资源配置】【配图】1217407_img
|
||||
【情境引入】Vicky 用捉迷藏游戏引诱 Peter 偷看,门果然开了。
|
||||
【互动内容】
|
||||
(朗读台词并显示配图)
|
||||
User : Look! The door is open!
|
||||
【后置对话】无"""),
|
||||
|
||||
# 8. Row111: 对话选择-配图 1217408 — S10主线 "坏掉的门"
|
||||
(111, """【任务标题】坏掉的门
|
||||
【资源配置】【配图】1217408_optA.png、1217408_optB.png
|
||||
【情境引入】Alex : Look. This door is broken. It's always open.
|
||||
【互动内容】
|
||||
题目:What is wrong with this door?
|
||||
选项A:The door is open.(正确)
|
||||
- 反馈 Alex : Right. The door is broken, so it's always open.
|
||||
选项B:The door is closed.
|
||||
- 反馈 Alex : No. Look again at the door.
|
||||
【后置对话】User : Let me see who's hiding inside."""),
|
||||
|
||||
# 9. Row120: 对话选择-配图 1217409 — S11主线 "关闭的房门"
|
||||
(120, """【任务标题】关闭的房门
|
||||
【资源配置】【配图】1217409_optA.png、1217409_optB.png
|
||||
【情境引入】Eva : This is Vicky's and my room.
|
||||
【互动内容】
|
||||
题目:How is the door?
|
||||
选项A:The door is open.
|
||||
- 反馈 Eva : No. Look again. Is the door open?
|
||||
选项B:The door is closed.(正确)
|
||||
- 反馈 Eva : Yes! The door is closed. Someone must be inside.
|
||||
【后置对话】User : Someone must be hiding in there."""),
|
||||
|
||||
# 10. Row129: 对话挖空-配图 1217410 — S13主线 "还剩一扇门"
|
||||
(129, """【任务标题】还剩一扇门
|
||||
【资源配置】【配图】1217410_img
|
||||
【情境引入】Vicky : Good job! Now, let's find Peter.
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : Only one ___ left.
|
||||
答案词:door
|
||||
【互动反馈】
|
||||
door 正确 → Vicky : Right! Only one door left. Peter must be there!
|
||||
door 错误 → Vicky : Let's think. What is left to check?
|
||||
【后置对话】User : Peter must be in there!"""),
|
||||
|
||||
# 11. Row133: 对话组句-配图 1217411 — S14主线 "发现门关着"
|
||||
(133, """【任务标题】发现门关着
|
||||
【资源配置】【配图】1217411_img
|
||||
【情境引入】终于找到了最后一扇门,但门是关着的。
|
||||
【互动内容】
|
||||
(组句)
|
||||
拼出句子:The door is closed.
|
||||
【互动反馈】
|
||||
正确 → Vicky : Yes! The door is closed. Peter is hiding inside!
|
||||
错误 → Vicky : Let's try again. Is the door open or closed?
|
||||
【后置对话】无"""),
|
||||
|
||||
# 12. Row144: 对话组句-配图 1217412 — S15主线 "门打开了"
|
||||
(144, """【任务标题】门打开了
|
||||
【资源配置】【配图】1217412_img
|
||||
【情境引入】Alex 和 User 一起用力推开了门,找到了 Peter。
|
||||
【互动内容】
|
||||
(组句)
|
||||
拼出句子:The door is open.
|
||||
【互动反馈】
|
||||
正确 → Peter : Haha! You got me!
|
||||
错误 → Peter : Try again! How is the door now?
|
||||
【后置对话】无"""),
|
||||
|
||||
# 13. Row153: 看图拼词 1217413 — S16主线 "修理指南"
|
||||
(153, """【任务标题】修理指南
|
||||
【资源配置】【配图】1217413_img
|
||||
【情境引入】Alex : Look, I have a book about doors.
|
||||
【互动内容】
|
||||
(看图拼词)
|
||||
图中是一个关闭的门,拼出对应的单词:closed
|
||||
答案词:closed
|
||||
【互动反馈】
|
||||
正确 → Alex : Correct! Closed doors don't open easily.
|
||||
错误 → Alex : This word means "not open". Try again.
|
||||
【后置对话】Alex : Let's fix it."""),
|
||||
|
||||
# 14. Row169: 对话挖空 1217414 — S17主线 "回忆窗户状态"
|
||||
(169, """【任务标题】回忆窗户状态
|
||||
【资源配置】无
|
||||
【情境引入】Alex : That window was closed before the game.
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : I remember that. The door was ___ before.
|
||||
答案词:closed
|
||||
【互动反馈】
|
||||
closed 正确 → Alex : Yes! It was closed before.
|
||||
closed 错误 → Alex : Think back. Was the door open or closed?
|
||||
【后置对话】无"""),
|
||||
|
||||
# 15. Row170: 对话挖空 1217415 — S18主线 "窗户开着"
|
||||
(170, """【任务标题】窗户开着
|
||||
【资源配置】无
|
||||
【情境引入】门之前是关着的,但现在...
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : But now it's ___.
|
||||
答案词:open
|
||||
【互动反馈】
|
||||
open 正确 → Alex : Yes! Now it's open. Very strange!
|
||||
open 错误 → Alex : Look now. The door is not closed anymore.
|
||||
【后置对话】无"""),
|
||||
|
||||
# 16. Row189: 对话朗读 1217416 — S19主线 "问候Grace和Dan"
|
||||
(189, """【任务标题】问候Grace和Dan
|
||||
【资源配置】无
|
||||
【情境引入】Wood 先生和太太终于回家了!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : I'm glad you get home!
|
||||
【后置对话】Grace : Thank you for staying with the kids!"""),
|
||||
]
|
||||
|
||||
# ============================================================
|
||||
# Write each config to F column using single-cell write
|
||||
# ============================================================
|
||||
success = 0
|
||||
fail = 0
|
||||
|
||||
for row, text in configs:
|
||||
cell = f"{SID}!F{row}:F{row}"
|
||||
body = json.dumps({"valueRange": {"range": cell, "values": [[text]]}}, ensure_ascii=False)
|
||||
r = subprocess.run(['curl', '-s', '-X', 'PUT',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values',
|
||||
'-H', f'Authorization: Bearer {TOKEN}',
|
||||
'-H', 'Content-Type: application/json; charset=utf-8',
|
||||
'-d', body], capture_output=True, text=True)
|
||||
resp = json.loads(r.stdout)
|
||||
if resp.get('code') == 0:
|
||||
success += 1
|
||||
print(f' ✅ Row {row:3d} | {text.split(chr(10))[0][5:]}')
|
||||
else:
|
||||
fail += 1
|
||||
print(f' ❌ Row {row:3d} | {resp.get("msg", "unknown")}')
|
||||
|
||||
print(f'\n写入完成:{success} 成功 / {fail} 失败')
|
||||
|
||||
# ============================================================
|
||||
# Verify: read back F column for all configured rows
|
||||
# ============================================================
|
||||
if fail == 0:
|
||||
print('\n=== 回读验证 ===')
|
||||
for row, _ in configs:
|
||||
cell = f"{SID}!F{row}:F{row}"
|
||||
r = subprocess.run(['curl', '-s', '-X', 'GET',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values/{cell}',
|
||||
'-H', f'Authorization: Bearer {TOKEN}'], capture_output=True, text=True)
|
||||
resp = json.loads(r.stdout)
|
||||
vals = resp.get('data', {}).get('valueRange', {}).get('values', [[]])
|
||||
content = vals[0][0] if vals and vals[0] else None
|
||||
if content:
|
||||
title = content.split('\n')[0].replace('【任务标题】', '') if content else 'EMPTY'
|
||||
print(f' ✅ Row{row}: {title}')
|
||||
else:
|
||||
print(f' ❌ Row{row}: EMPTY!')
|
||||
@ -1,369 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate G列 component configs for L1-S2-U17-L5 笨蛋坏蛋? (English)"""
|
||||
import subprocess, json
|
||||
|
||||
APP_SECRET = json.load(open('/root/.openclaw/credentials/xiaoyan/config.json'))['apps'][0]['appSecret']
|
||||
r = subprocess.run(['curl', '-s', '-X', 'POST',
|
||||
'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
|
||||
'-H', 'Content-Type: application/json',
|
||||
'-d', json.dumps({"app_id": "cli_a931175d41799cc7", "app_secret": APP_SECRET})],
|
||||
capture_output=True, text=True)
|
||||
TOKEN = json.loads(r.stdout)['tenant_access_token']
|
||||
SST = 'DCcKsLbrmhfXgrtB7N2c9GA4ntf'
|
||||
SID = 'wMQVyV'
|
||||
|
||||
# (row, config)
|
||||
configs = [
|
||||
# Row14: 互动 — point — 机器人指着黑板
|
||||
(14, """【任务标题】What does it do?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : See? I point at it.
|
||||
【互动内容】
|
||||
(听力挖空 / 看图回答)
|
||||
User : It ___ at the blackboard.
|
||||
答案词:points
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
points 正确 → Ben : Yes. It points at the blackboard.
|
||||
points 错误 → Ben : Look again. What does it do?
|
||||
【后置对话】Ben : It talks a lot."""),
|
||||
|
||||
# Row28: 互动 — points — 补充描述机器人行为
|
||||
(28, """【任务标题】Talk about the robot
|
||||
【资源配置】无
|
||||
【情境引入】Robot : Bip bop! Bip bop bip!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It points at the blackboard.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Ben : That's right. And what else?
|
||||
错误 → Ben : Look at the robot. What is it pointing at?
|
||||
【后置对话】Ben : And it talks to itself!"""),
|
||||
|
||||
# Row29: 互动 — talks to — 继续描述机器人
|
||||
(29, """【任务标题】What else does it do?
|
||||
【资源配置】无
|
||||
【情境引入】Robot : Bip bop! Bip bop bip!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It talks to itself...
|
||||
KP:talk to... — 和...说话
|
||||
【互动反馈】
|
||||
正确 → Ben : It talks to itself!
|
||||
错误 → Ben : Listen. Is the robot talking to someone?
|
||||
【后置对话】Ben : ...in a language we can't understand!"""),
|
||||
|
||||
# Row36: 互动 — a lot of — 课桌挡路
|
||||
(36, """【任务标题】What is blocking it?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : What is it doing now?
|
||||
【互动内容】
|
||||
(听力挖空)
|
||||
User : But ___ ___ ___ our desks block it.
|
||||
答案词:a lot of
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
a lot of 正确 → Ben : Yes! The desks are in its way.
|
||||
a lot of 错误 → Ben : Many desks are blocking it.
|
||||
【后置对话】场景:机器人推开桌椅"""),
|
||||
|
||||
# Row54: 互动 — a lot of — 需要证据
|
||||
(54, """【任务标题】What do we need?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : Fine. What should we do now?
|
||||
【互动内容】
|
||||
(听力挖空 / 朗读)
|
||||
User : We need ___ ___ ___ proof!
|
||||
答案词:a lot of
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
正确 → Ben : Okay. We'll find more.
|
||||
错误 → Ben : We need more than just a guess.
|
||||
【后置对话】无"""),
|
||||
|
||||
# Row55: 互动 — talk to — 建议和机器人谈谈
|
||||
(55, """【任务标题】What should we do?
|
||||
【资源配置】无
|
||||
【情境引入】User : We need a lot of proof!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Let's talk to it!
|
||||
KP:talk to... — 和...说话
|
||||
【互动反馈】
|
||||
正确 → Ben : Talk to it? But it's a robot!
|
||||
错误 → Ben : How else can we find out?
|
||||
【后置对话】Ben 从藏身处跳出来"""),
|
||||
|
||||
# Row61: 互动 — can't understand — 不懂机器人语言
|
||||
(61, """【任务标题】Can you understand it?
|
||||
【资源配置】无
|
||||
【情境引入】Robot : Bip bop!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : We can't understand it.
|
||||
KP:I can/can't understand...
|
||||
【互动反馈】
|
||||
正确 → Ben : Right. Let's try asking with pictures.
|
||||
错误 → Ben : Can we understand robot language?
|
||||
【后置对话】Ben : What's your name?"""),
|
||||
|
||||
# Row67: 互动 — understand — 理解了11的名字
|
||||
(67, """【任务标题】What do you think?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : What's your name?
|
||||
Robot points at itself — it shows "11"
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Oh, I understand!
|
||||
KP:understand — v. 理解
|
||||
【互动反馈】
|
||||
正确 → Ben : You understand? Tell me!
|
||||
错误 → Ben : Do you know what it means?
|
||||
【后置对话】User points out the number 11"""),
|
||||
|
||||
# Row68: 互动 — points to — 指出名字
|
||||
(68, """【任务标题】What is it showing?
|
||||
【资源配置】无
|
||||
【情境引入】User : Oh, I understand!
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It points to its name.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Ben : Its name is 11!
|
||||
错误 → Ben : What is the robot showing us?
|
||||
【后置对话】User : Its name is 11!"""),
|
||||
|
||||
# Row80: 互动 — talk — 建议慢慢说
|
||||
(80, """【任务标题】How should we talk?
|
||||
【资源配置】无
|
||||
【情境引入】Ben is asking too many questions at once.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Just talk slowly.
|
||||
KP:talk — v. 说话
|
||||
【互动反馈】
|
||||
正确 → Ben : Okay. One question at a time.
|
||||
错误 → Ben : Should I ask slower?
|
||||
【后置对话】Ben : Alright. Where are you from?"""),
|
||||
|
||||
# Row85: 互动 — talk to — 尝试用画沟通
|
||||
(85, """【任务标题】What is it doing?
|
||||
【资源配置】无
|
||||
【情境引入】Robot starts drawing on the blackboard.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Oh! It tries to talk to us with drawing.
|
||||
KP:talk to... — 和...说话
|
||||
【互动反馈】
|
||||
正确 → Ben : A picture! What is it?
|
||||
错误 → Ben : What is it drawing? Is it a message?
|
||||
【后置对话】Ben : That is the Speedy Monkey logo!"""),
|
||||
|
||||
# Row88: 互动 — understand — 理解来源
|
||||
(88, """【任务标题】Where is it from?
|
||||
【资源配置】无
|
||||
【情境引入】Robot draws the Speedy Monkey logo.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Oh! I understand! It is from Speedy Monkey!
|
||||
KP:understand — v. 理解
|
||||
【互动反馈】
|
||||
正确 → Ben : Speedy Monkey! I knew it!
|
||||
错误 → Ben : Who is that logo from?
|
||||
【后置对话】Ben : Speedy monkey sent a spy here!"""),
|
||||
|
||||
# Row94: 互动 — talk — 要求继续
|
||||
(94, """【任务标题】What next?
|
||||
【资源配置】无
|
||||
【情境引入】Ben thinks Speedy Monkey people are bad.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Talk more to it!
|
||||
KP:talk — v. 说话
|
||||
【互动反馈】
|
||||
正确 → Ben : Fine. What do you want?
|
||||
错误 → Ben : Should we ask more questions?
|
||||
【后置对话】Ben : Okay, what do you want?"""),
|
||||
|
||||
# Row98: 互动 — points at — 指另一个标记
|
||||
(98, """【任务标题】What is it showing now?
|
||||
【资源配置】无
|
||||
【情境引入】Robot draws another mark on the blackboard.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It points at another mark.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Ben : What is that mark?
|
||||
错误 → Ben : Look at what it is pointing at.
|
||||
【后置对话】Ben : Is that... a school?"""),
|
||||
|
||||
# Row104: 互动 — points at — 又指一个标记
|
||||
(104, """【任务标题】What is it now?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : Why are you here?
|
||||
Robot draws another mark.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It points at another mark.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Ben : A gift mark!
|
||||
错误 → Ben : What does the drawing show?
|
||||
【后置对话】Ben : It is a gift!"""),
|
||||
|
||||
# Row109: 互动 — understand — 我终于懂了
|
||||
(109, """【任务标题】What do you think?
|
||||
【资源配置】无
|
||||
【情境引入】Robot drew Speedy Monkey, school, and gift marks.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Ben! I think I understand!
|
||||
KP:understand — v. 理解
|
||||
【互动反馈】
|
||||
正确 → Ben : What do you understand?
|
||||
错误 → Ben : Think about the pictures again.
|
||||
【后置对话】User explains the spy theory"""),
|
||||
|
||||
# Row110: 互动 — talk — 需要谈话
|
||||
(110, """【任务标题】What should we do?
|
||||
【资源配置】无
|
||||
【情境引入】User thinks they've found a spy.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : We need to talk! You and me!
|
||||
KP:talk — v. 说话
|
||||
【互动反馈】
|
||||
正确 → Ben : Okay! Let's figure this out.
|
||||
错误 → Ben : We need to discuss what we found!
|
||||
【后置对话】Ben : Okay!"""),
|
||||
|
||||
# Row116: 互动 — a lot of — 很多信息
|
||||
(116, """【任务标题】What did it tell us?
|
||||
【资源配置】无
|
||||
【情境引入】User pieces together the clues.
|
||||
【互动内容】
|
||||
(朗读台词 / 听力挖空)
|
||||
User : It tells ___ ___ ___ things!
|
||||
答案词:a lot of
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
正确 → Ben : Yes. Speedy Monkey, school, gift...
|
||||
错误 → Ben : Remember all the drawings?
|
||||
【后置对话】User : Vala School is a gift to Speedy Monkey!"""),
|
||||
|
||||
# Row123: 互动 — a lot of — 很多信息
|
||||
(123, """【任务标题】What should we do?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : What should we do now?
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : It is a lot of information.
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
正确 → Ben : Yes. We have enough to tell the mayor!
|
||||
错误 → Ben : Is it enough to act on?
|
||||
【后置对话】无"""),
|
||||
|
||||
# Row124: 互动 — talk about — 给镇长打电话
|
||||
(124, """【任务标题】Who should we tell?
|
||||
【资源配置】无
|
||||
【情境引入】Ben agrees they have enough proof.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : We need to call Mayor Tom and talk about it!
|
||||
KP:talk to/talk about...
|
||||
【互动反馈】
|
||||
正确 → Ben : Good idea. Let's call him now!
|
||||
错误 → Ben : Who should we call for help?
|
||||
【后置对话】Calling Mayor Tom..."""),
|
||||
|
||||
# Row131: 互动 — point at — 指给镇长看
|
||||
(131, """【任务标题】Show the mayor
|
||||
【资源配置】无
|
||||
【情境引入】Tom arrives. Ben explains.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Look! I point at it.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Tom : The robot?
|
||||
错误 → Tom : What are you pointing at?
|
||||
【后置对话】Tom : Oh? A spy? In the classroom?"""),
|
||||
|
||||
# Row137: 互动 — a lot of — 描述异常行为
|
||||
(137, """【任务标题】What did it do?
|
||||
【资源配置】无
|
||||
【情境引入】Ben lists the spy evidence.
|
||||
【互动内容】
|
||||
(听力挖空 / 朗读)
|
||||
User : And it said ___ ___ ___ strange things!
|
||||
答案词:a lot of
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
正确 → Tom : Hmm, I see.
|
||||
错误 → Tom : Did it say many strange things?
|
||||
【后置对话】User shows the blackboard evidence"""),
|
||||
|
||||
# Row148: 互动 — don't understand — 感到困惑
|
||||
(148, """【任务标题】What is the truth?
|
||||
【资源配置】无
|
||||
【情境引入】Tom says robot doesn't want to give school to Speedy Monkey.
|
||||
【互动内容】
|
||||
(朗读台词)
|
||||
User : Wait. I don't understand.
|
||||
KP:I can/can't understand...
|
||||
【互动反馈】
|
||||
正确 → Lin : Why not let it tell you itself?
|
||||
错误 → Lin : Let me help you understand.
|
||||
【后置对话】Robot explains itself"""),
|
||||
|
||||
# Row163: 核心互动-口语 — talk to — 道歉
|
||||
(163, """【任务标题】Apologise to Jay and Lin
|
||||
【资源配置】无
|
||||
【情境引入】Tom asks the kids if they have something to say.
|
||||
【互动内容】
|
||||
(口语表达)
|
||||
User : I should talk to you.
|
||||
KP:talk — v. 说话
|
||||
【互动反馈】
|
||||
正确 → Jay : It's okay.
|
||||
错误 → Jay : Go on. Say what you need to say.
|
||||
【后置对话】User and Ben apologise"""),
|
||||
]
|
||||
|
||||
# Write and verify
|
||||
success = fail = 0
|
||||
for row, text in configs:
|
||||
cell = f"{SID}!G{row}:G{row}"
|
||||
body = json.dumps({"valueRange": {"range": cell, "values": [[text]]}}, ensure_ascii=False)
|
||||
r = subprocess.run(['curl', '-s', '-X', 'PUT',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values',
|
||||
'-H', f'Authorization: Bearer {TOKEN}',
|
||||
'-H', 'Content-Type: application/json; charset=utf-8',
|
||||
'-d', body], capture_output=True, text=True)
|
||||
resp = json.loads(r.stdout)
|
||||
if resp.get('code') == 0:
|
||||
success += 1
|
||||
title = text.split('\n')[0].replace('【任务标题】', '')
|
||||
print(f' ✅ Row {row:3d} | {title}')
|
||||
else:
|
||||
fail += 1
|
||||
print(f' ❌ Row {row:3d} | {resp.get("msg","?")}')
|
||||
|
||||
print(f'\n写入:{success}成功 / {fail}失败')
|
||||
|
||||
if fail == 0:
|
||||
print('\n=== 回读验证 ===')
|
||||
for row, _ in configs:
|
||||
cell = f"{SID}!G{row}:G{row}"
|
||||
r = subprocess.run(['curl', '-s', '-X', 'GET',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values/{cell}',
|
||||
'-H', f'Authorization: Bearer {TOKEN}'], capture_output=True, text=True)
|
||||
resp = json.loads(r.stdout)
|
||||
vals = resp.get('data',{}).get('valueRange',{}).get('values',[[]])
|
||||
content = vals[0][0] if vals and vals[0] else None
|
||||
title = content.split('\n')[0].replace('【任务标题】', '') if content else 'EMPTY'
|
||||
print(f' ✅ Row{row}: {title}')
|
||||
@ -1,215 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate G列 component configs for L1-S2-U17-L5 笨蛋坏蛋?(v2 — updated row numbers)"""
|
||||
import subprocess, json
|
||||
|
||||
APP_SECRET = json.load(open('/root/.openclaw/credentials/xiaoyan/config.json'))['apps'][0]['appSecret']
|
||||
r = subprocess.run(['curl', '-s', '-X', 'POST',
|
||||
'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
|
||||
'-H', 'Content-Type: application/json',
|
||||
'-d', json.dumps({"app_id": "cli_a931175d41799cc7", "app_secret": APP_SECRET})],
|
||||
capture_output=True, text=True)
|
||||
TOKEN = json.loads(r.stdout)['tenant_access_token']
|
||||
SST = 'DCcKsLbrmhfXgrtB7N2c9GA4ntf'
|
||||
SID = 'wMQVyV'
|
||||
|
||||
# ===== 对话朗读 (6) =====
|
||||
# ===== 对话挖空 (3) =====
|
||||
# ===== 互动 (7) =====
|
||||
# ===== 核心互动-口语 (1) =====
|
||||
|
||||
configs = [
|
||||
# --- 对话朗读 ---
|
||||
(14, """【任务标题】机器人在指向什么?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Ben : It points at something!
|
||||
【互动内容】It points at the blackboard.(朗读)
|
||||
【后置对话】Ben : That's right. And it also talks a lot!"""),
|
||||
|
||||
(29, """【任务标题】机器人在自言自语吗?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Robot : Bip bop! Bip bop bip!
|
||||
【互动内容】Hmm, it talks to itself.(朗读)
|
||||
【后置对话】Ben : ...in a language we can't understand!"""),
|
||||
|
||||
(42, """【任务标题】机器人为什么走不动?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Ben : What is it doing now?
|
||||
【互动内容】But a lot of our desks block it.(朗读)
|
||||
【后置对话】Ben : Yes! The desks are in its way."""),
|
||||
|
||||
(66, """【任务标题】我们该怎么办?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Ben : Fine. You're right. What should we do now?
|
||||
【互动内容】Let's talk to it!(朗读)
|
||||
【后置对话】Ben : Talk to it? But it's a robot!"""),
|
||||
|
||||
(77, """【任务标题】你能听懂机器人吗?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Robot : Bip bop!
|
||||
【互动内容】We can't understand it.(朗读)
|
||||
【后置对话】Ben : What's your name?"""),
|
||||
|
||||
(89, """【任务标题】你明白了什么?
|
||||
【资源配置】图片时机:无
|
||||
【情境引入】Robot points at the number "11" on its chest.
|
||||
【互动内容】Oh, I understand!(朗读)
|
||||
【后置对话】Ben : You understand? Tell me!"""),
|
||||
|
||||
# --- 对话挖空 ---
|
||||
(96, """【任务标题】指出机器人的名字
|
||||
【资源配置】无
|
||||
【情境引入】Ben : Wow, it is pointing at itself!
|
||||
【互动内容】It ___ to its name.(音频)
|
||||
选项1:points(正确)
|
||||
选项2:talks
|
||||
【互动反馈】
|
||||
正确 Ben : Yes! It points to its name. Its name is 11!
|
||||
错误 Ben : What is the robot doing? Think again.
|
||||
【后置对话】User : Its name is 11! We call it 11!"""),
|
||||
|
||||
(119, """【任务标题】机器人想做什么?
|
||||
【资源配置】无
|
||||
【情境引入】Robot draws on the blackboard.
|
||||
【互动内容】Oh! It tries to ___ to us.(音频)
|
||||
选项1:talk(正确)
|
||||
选项2:point
|
||||
【互动反馈】
|
||||
正确 Ben : Yes! It wants to talk with pictures!
|
||||
错误 Ben : It is not pointing. What else?
|
||||
【后置对话】Ben : That is the Speedy Monkey logo!"""),
|
||||
|
||||
(138, """【任务标题】机器人又指了什么?
|
||||
【资源配置】无
|
||||
【情境引入】Robot draws a school mark on the blackboard.
|
||||
【互动内容】It ___ at another mark.(音频)
|
||||
选项1:points(正确)
|
||||
选项2:talks
|
||||
【互动反馈】
|
||||
正确 Ben : Is that... a school?
|
||||
错误 Ben : Look at what the robot is doing with the mark.
|
||||
【后置对话】Ben : Is that a school?"""),
|
||||
|
||||
# --- 互动 ---
|
||||
(150, """【任务标题】又是什么标记?
|
||||
【资源配置】无
|
||||
【情境引入】Robot draws a gift mark on the blackboard.
|
||||
【互动内容】It points at another mark.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Ben : It is a gift!
|
||||
错误 → Ben : Look at the mark. What is it?
|
||||
【后置对话】Ben : Speedy Monkey? School? Gift?"""),
|
||||
|
||||
(161, """【任务标题】你发现了什么?
|
||||
【资源配置】无
|
||||
【情境引入】Ben : Speedy Monkey? School? Gift?
|
||||
【互动内容】Ben! I think I understand!
|
||||
KP:understand — v. 理解
|
||||
【互动反馈】
|
||||
正确 → Ben : What do you understand?
|
||||
错误 → Ben : Look at the marks again.
|
||||
【后置对话】User explains the spy theory"""),
|
||||
|
||||
(168, """【任务标题】和 Ben 单独商量
|
||||
【资源配置】无
|
||||
【情境引入】User thinks the robot is a spy.
|
||||
【互动内容】We need to talk! You and me!
|
||||
KP:talk — v. 说话
|
||||
【互动反馈】
|
||||
正确 → Ben : Okay! Let's figure this out.
|
||||
错误 → Ben : We need to talk about what we found!
|
||||
【后置对话】User : Vala School is a gift to Speedy Monkey!"""),
|
||||
|
||||
(181, """【任务标题】快告诉镇长!
|
||||
【资源配置】无
|
||||
【情境引入】Ben : What should we do now?
|
||||
【互动内容】We need to call Mayor Tom! Let's talk about it!
|
||||
KP:talk about... — 谈论...
|
||||
【互动反馈】
|
||||
正确 → Ben : Good idea. Let's call him now!
|
||||
错误 → Ben : Who should we call for help?
|
||||
【后置对话】Calling Mayor Tom..."""),
|
||||
|
||||
(194, """【任务标题】指给镇长看
|
||||
【资源配置】无
|
||||
【情境引入】Tom : So you kids want to talk to me?
|
||||
【互动内容】Look! I point at it.
|
||||
KP:point — v. 指向
|
||||
【互动反馈】
|
||||
正确 → Tom : The robot?
|
||||
错误 → Tom : What are you pointing at?
|
||||
【后置对话】Tom : Oh? A spy? In the classroom?"""),
|
||||
|
||||
(207, """【任务标题】给镇长看证据
|
||||
【资源配置】无
|
||||
【情境引入】Tom : I don't understand. Anything else?
|
||||
【互动内容】Look! Here are a lot of strange marks!
|
||||
KP:a lot of — det. 大量的
|
||||
【互动反馈】
|
||||
正确 → Tom : Hmm, I see.
|
||||
错误 → Tom : Are there many strange marks?
|
||||
【后置对话】User shows the blackboard to Tom"""),
|
||||
|
||||
(224, """【任务标题】到底怎么回事?
|
||||
【资源配置】无
|
||||
【情境引入】Tom : The school isn't a gift to Speedy Monkey!
|
||||
【互动内容】Wait. I don't understand.
|
||||
KP:I can/can't understand...
|
||||
【互动反馈】
|
||||
正确 → Lin : Why not let it tell you itself?
|
||||
错误 → Lin : Let me help you understand.
|
||||
【后置对话】Lin fixes the robot"""),
|
||||
|
||||
# --- 核心互动-口语 ---
|
||||
(245, """【任务标题】向 Jay 和 Lin 道歉
|
||||
【资源配置】无
|
||||
【情境引入】Tom : Kids, do you have something to say?
|
||||
【互动内容】
|
||||
(口语表达)
|
||||
I should talk to you.
|
||||
I should understand you.
|
||||
I can understand you now.
|
||||
KP:talk / understand
|
||||
【互动反馈】
|
||||
正确 → Jay : Thank you. We feel much better now.
|
||||
错误 → Lin : Go on. Say what's in your heart.
|
||||
【后置对话】Jay : I understand. Lin : We all make mistakes."""),
|
||||
]
|
||||
|
||||
# Write
|
||||
success = fail = 0
|
||||
for row, text in configs:
|
||||
cell = f"{SID}!G{row}:G{row}"
|
||||
body = json.dumps({"valueRange": {"range": cell, "values": [[text]]}}, ensure_ascii=False)
|
||||
r = subprocess.run(['curl', '-s', '-X', 'PUT',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values',
|
||||
'-H', f'Authorization: Bearer {TOKEN}',
|
||||
'-H', 'Content-Type: application/json; charset=utf-8',
|
||||
'-d', body], capture_output=True, text=True, timeout=15)
|
||||
resp = json.loads(r.stdout)
|
||||
if resp.get('code') == 0:
|
||||
success += 1
|
||||
title = text.split('\n')[0].replace('【任务标题】', '')
|
||||
print(f' ✅ Row {row:3d} | {title}')
|
||||
else:
|
||||
fail += 1
|
||||
print(f' ❌ Row {row:3d} | {resp.get("msg","?")}')
|
||||
print(f' debug: {r.stdout[:200]}')
|
||||
|
||||
print(f'\n写入结果:{success}成功 / {fail}失败')
|
||||
|
||||
if fail == 0:
|
||||
print('\n=== 回读验证 ===')
|
||||
for row, _ in configs:
|
||||
cell = f"{SID}!G{row}:G{row}"
|
||||
r = subprocess.run(['curl', '-s', '-X', 'GET',
|
||||
f'https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SST}/values/{cell}?valueRenderOption=ToString',
|
||||
'-H', f'Authorization: Bearer {TOKEN}'], capture_output=True, text=True, timeout=15)
|
||||
resp = json.loads(r.stdout)
|
||||
vals = resp.get('data',{}).get('valueRange',{}).get('values',[[]])
|
||||
content = vals[0][0] if vals and vals[0] else None
|
||||
title = content.split('\n')[0].replace('【任务标题】', '') if content else 'EMPTY'
|
||||
status = '✅' if content else '❌ EMPTY'
|
||||
print(f' {status} Row{row}: {title}')
|
||||
else:
|
||||
print('\n⚠️ 有失败项,请检查')
|
||||
@ -1,175 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
P4 rewrite with automation-safe approach:
|
||||
- jsonData: use ability=['听觉抓取关键信息'], explanation='' (automation-compatible)
|
||||
- 题目1/题目2: include full ability + explanation info in text
|
||||
"""
|
||||
import json, subprocess, sys, os, time
|
||||
|
||||
AT = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
TID = "tblVmeDtBDKsAEfz"
|
||||
BASE = os.path.expanduser("~/.openclaw/workspace-xiaoyan")
|
||||
CRED_FILE = os.path.expanduser("~/.openclaw/credentials/xiaoyan/config.json")
|
||||
|
||||
sys.path.insert(0, os.path.join(BASE, "scripts"))
|
||||
import rewrite_p4_all as rw
|
||||
|
||||
RECORD_IDS = {
|
||||
"021301": "recvjufKJO8d0O",
|
||||
"021401": "recvjufM763ijb",
|
||||
"021501": "recvjufM76lEsW",
|
||||
"021601": "recvjufM76hNv5",
|
||||
"021701": "recvjufM76eMKs",
|
||||
"021801": "recvjufM76lRHQ",
|
||||
"022101": "recvjufM76o6of",
|
||||
"032501": "recvjufM76k4dx",
|
||||
"032901": "recvjufM76frUP",
|
||||
}
|
||||
|
||||
def get_token():
|
||||
with open(CRED_FILE) as f:
|
||||
cred = json.load(f)
|
||||
app_id = cred["apps"][0]["appId"]
|
||||
app_secret = cred["apps"][0]["appSecret"]
|
||||
r = subprocess.run(["curl","-s","-X","POST",
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
"-H","Content-Type: application/json",
|
||||
"-d",json.dumps({"app_id":app_id,"app_secret":app_secret})],
|
||||
capture_output=True, text=True)
|
||||
return json.loads(r.stdout)["tenant_access_token"]
|
||||
|
||||
def make_qtext_with_info(questions):
|
||||
"""Generate 题目 text with dialogue, ability and explanation info"""
|
||||
lines = []
|
||||
for i, q in enumerate(questions, 1):
|
||||
lines.append(f"{i}.")
|
||||
lines.append(f"【描述】{q.get('questionDesc','')}")
|
||||
lines.append(f"【听力文本】")
|
||||
if 'dialogue' in q:
|
||||
lines.append(q['dialogue'])
|
||||
lines.append(f"【题目】")
|
||||
lines.append(q['question'])
|
||||
for j, opt in enumerate(q.get('options',[])):
|
||||
marker = "(正确)" if j == q.get('answer',[-1])[0] else ""
|
||||
lines.append(f"{chr(65+j)}. {opt}{marker}")
|
||||
# Add ability info
|
||||
ability = q.get('new_ability', q.get('ability', ['听力理解']))
|
||||
lines.append(f"【能力标签】{'|'.join(ability) if isinstance(ability,list) else ability}")
|
||||
# Add explanation
|
||||
lines.append(f"【解析】{q.get('explanation','')}")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
def sanitize_json(json_data):
|
||||
"""Replace ability/explanation with automation-safe values"""
|
||||
for qs in json_data.get("first", {}).get("questionSet", []):
|
||||
qs["ability"] = ["听觉抓取关键信息"]
|
||||
qs["explanation"] = ""
|
||||
second = json_data.get("second", {})
|
||||
if second and isinstance(second, dict) and "questionSet" in second:
|
||||
for qs in second.get("questionSet", []):
|
||||
qs["ability"] = ["听觉抓取关键信息"]
|
||||
qs["explanation"] = ""
|
||||
return json_data
|
||||
|
||||
def write_one(token, qsid, record_id, json_data, q1_text, q2_text):
|
||||
"""Write one record and verify"""
|
||||
json_str = json.dumps(json_data, ensure_ascii=False)
|
||||
fields = {"jsonData": json_str, "题目1": q1_text, "题目2": q2_text}
|
||||
payload = json.dumps({"fields": fields}, ensure_ascii=False)
|
||||
|
||||
tmp = f"/tmp/p4_safe_{record_id}.json"
|
||||
with open(tmp, "w") as f:
|
||||
f.write(payload)
|
||||
|
||||
r = subprocess.run(["curl","-s","-X","PUT",
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||||
"-H",f"Authorization: Bearer {token}",
|
||||
"-H","Content-Type: application/json",
|
||||
"-d",f"@{tmp}"],
|
||||
capture_output=True, text=True, timeout=30)
|
||||
os.remove(tmp)
|
||||
|
||||
resp = json.loads(r.stdout)
|
||||
if resp.get("code") != 0:
|
||||
return False, f"API error: {resp.get('msg','')}"
|
||||
|
||||
# Verify
|
||||
r = subprocess.run(["curl","-s","-X","GET",
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||||
"-H",f"Authorization: Bearer {token}"],
|
||||
capture_output=True, text=True, timeout=30)
|
||||
vdata = json.loads(r.stdout)
|
||||
if vdata.get("code") != 0:
|
||||
return False, f"Verify error: {vdata.get('msg','')}"
|
||||
|
||||
rec = vdata.get("data",{}).get("record",{})
|
||||
jd = rec.get("fields",{}).get("jsonData","")
|
||||
q1 = rec.get("fields",{}).get("题目1","") or ""
|
||||
|
||||
if not jd:
|
||||
return False, "jsonData empty"
|
||||
|
||||
try:
|
||||
parsed = json.loads(jd)
|
||||
fqs = parsed.get("first",{}).get("questionSet",[])
|
||||
if not fqs:
|
||||
return False, "no first questions"
|
||||
q0_question = fqs[0].get("question","")
|
||||
q0_ability = fqs[0].get("ability","")
|
||||
return True, f"Qs={len(fqs)}, q0='{q0_question[:30]}', ability={q0_ability}, Q1_len={len(q1)}"
|
||||
except Exception as e:
|
||||
return False, f"parse: {e}"
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
print(f"Token: {token[:15]}...")
|
||||
results = []
|
||||
|
||||
for qsid, record_id in RECORD_IDS.items():
|
||||
data = rw.RECORD_DATA.get(qsid)
|
||||
if not data:
|
||||
continue
|
||||
|
||||
fb = data["first_block"]
|
||||
sb = data["second_block"]
|
||||
fqs = data["first_qs_list"]
|
||||
sqs = data["second_qs_list"]
|
||||
|
||||
# Build jsonData - keep original dialogue but not in final jsonData
|
||||
json_data = {"first": fb, "second": sb}
|
||||
|
||||
# Build Q1/Q2 text with full info
|
||||
q1_text = make_qtext_with_info(fqs)
|
||||
q2_text = make_qtext_with_info(sqs) if sqs else ""
|
||||
|
||||
# Clean dialogues from jsonData and sanitize
|
||||
for q in fb["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
q.pop("new_ability", None)
|
||||
if sb and isinstance(sb, dict) and "questionSet" in sb:
|
||||
for q in sb["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
q.pop("new_ability", None)
|
||||
|
||||
json_data = sanitize_json(json_data)
|
||||
|
||||
print(f"\nWriting {qsid} ({record_id})...")
|
||||
ok, msg = write_one(token, qsid, record_id, json_data, q1_text, q2_text)
|
||||
status = "✅" if ok else "❌"
|
||||
print(f" {status} {msg}")
|
||||
results.append((qsid, ok, msg))
|
||||
time.sleep(0.5)
|
||||
|
||||
success = sum(1 for r in results if r[1])
|
||||
fails = sum(1 for r in results if not r[1])
|
||||
print(f"\n{'='*60}")
|
||||
print(f"FINAL: {success} succeeded, {fails} failed")
|
||||
|
||||
if fails:
|
||||
for qsid, ok, msg in results:
|
||||
if not ok:
|
||||
print(f" ❌ {qsid}: {msg}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,192 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Write all P4 rewrite records to bitable using direct API calls.
|
||||
Avoids shell escaping issues.
|
||||
"""
|
||||
import json, subprocess, os, sys
|
||||
|
||||
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
TABLE_ID = "tblVmeDtBDKsAEfz"
|
||||
BASE_DIR = os.path.expanduser("~/.openclaw/workspace-xiaoyan")
|
||||
CRED_FILE = os.path.expanduser("~/.openclaw/credentials/xiaoyan/config.json")
|
||||
|
||||
RECORD_IDS = {
|
||||
"021301": "recvjufKJO8d0O",
|
||||
"021401": "recvjufM763ijb",
|
||||
"021501": "recvjufM76lEsW",
|
||||
"021601": "recvjufM76hNv5",
|
||||
"021701": "recvjufM76eMKs",
|
||||
"021801": "recvjufM76lRHQ",
|
||||
"022101": "recvjufM76o6of",
|
||||
"032501": "recvjufM76k4dx",
|
||||
"032901": "recvjufM76frUP",
|
||||
}
|
||||
|
||||
def get_token():
|
||||
with open(CRED_FILE) as f:
|
||||
cred = json.load(f)
|
||||
app_id = cred["apps"][0]["appId"]
|
||||
app_secret = cred["apps"][0]["appSecret"]
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "POST",
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps({"app_id": app_id, "app_secret": app_secret})
|
||||
], capture_output=True, text=True)
|
||||
return json.loads(result.stdout)["tenant_access_token"]
|
||||
|
||||
def update_record(token, record_id, fields_dict):
|
||||
"""Update a record via curl"""
|
||||
# Write fields to temp file to avoid command-line escaping
|
||||
tmp_file = f"/tmp/p4_update_{record_id}.json"
|
||||
payload = json.dumps({"fields": fields_dict}, ensure_ascii=False)
|
||||
with open(tmp_file, 'w') as f:
|
||||
f.write(payload)
|
||||
|
||||
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE_ID}/records/{record_id}"
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "PUT", url,
|
||||
"-H", f"Authorization: Bearer {token}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", f"@{tmp_file}"
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
|
||||
os.remove(tmp_file)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def verify_record(token, record_id):
|
||||
"""Re-read a record to verify"""
|
||||
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE_ID}/records/{record_id}"
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "GET", url,
|
||||
"-H", f"Authorization: Bearer {token}"
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def main():
|
||||
mode = sys.argv[1] if len(sys.argv) > 1 else "test"
|
||||
|
||||
# Get token
|
||||
print("Getting token...")
|
||||
token = get_token()
|
||||
print(f"Token: {token[:20]}...")
|
||||
|
||||
# Import the rewrite data
|
||||
sys.path.insert(0, os.path.join(BASE_DIR, "scripts"))
|
||||
import rewrite_p4_all as rw
|
||||
|
||||
from rewrite_p4_all import make_q1_text
|
||||
|
||||
results = []
|
||||
|
||||
for qsid, record_id in RECORD_IDS.items():
|
||||
data = rw.RECORD_DATA.get(qsid)
|
||||
if not data:
|
||||
continue
|
||||
|
||||
first_block = data["first_block"]
|
||||
second_block = data["second_block"]
|
||||
first_qs = data["first_qs_list"]
|
||||
second_qs = data["second_qs_list"]
|
||||
|
||||
# Clean dialogues from jsonData
|
||||
for q in first_block["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
if second_block and isinstance(second_block, dict) and "questionSet" in second_block:
|
||||
for q in second_block["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
|
||||
json_data = {"first": first_block, "second": second_block}
|
||||
|
||||
q1_text = make_q1_text(first_qs)
|
||||
q2_text = make_q1_text(second_qs) if second_qs else ""
|
||||
|
||||
fields = {
|
||||
"jsonData": json.dumps(json_data, ensure_ascii=False),
|
||||
"题目1": q1_text,
|
||||
"题目2": q2_text,
|
||||
}
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"QSID: {qsid} | Record: {record_id}")
|
||||
print(f"First: {len(first_qs)} Qs, Second: {len(second_qs)} Qs")
|
||||
|
||||
if mode == "test":
|
||||
# Test one record only
|
||||
if qsid == "021301":
|
||||
result = update_record(token, record_id, fields)
|
||||
code = result.get("code", -1)
|
||||
msg = result.get("msg", "")
|
||||
if code == 0:
|
||||
print(f" ✅ Test write SUCCESS")
|
||||
# Verify
|
||||
v = verify_record(token, record_id)
|
||||
vcode = v.get("code", -1)
|
||||
if vcode == 0:
|
||||
rec = v.get("data", {}).get("record", {})
|
||||
jd = rec.get("fields", {}).get("jsonData", "")
|
||||
if jd:
|
||||
try:
|
||||
parsed = json.loads(jd)
|
||||
fq = parsed.get("first", {}).get("questionSet", [])
|
||||
sq = parsed.get("second", {}).get("questionSet", [])
|
||||
print(f" ✅ Verify: {len(fq)} first Qs, {len(sq)} second Qs")
|
||||
print(f" ✅ jsonData valid JSON")
|
||||
except Exception as e:
|
||||
print(f" ❌ jsonData parse error: {e}")
|
||||
else:
|
||||
print(f" ❌ jsonData field empty")
|
||||
else:
|
||||
print(f" ❌ Verify FAILED: {v.get('msg', '')}")
|
||||
else:
|
||||
print(f" ❌ Test write FAILED: {msg}")
|
||||
break
|
||||
|
||||
elif mode == "write":
|
||||
result = update_record(token, record_id, fields)
|
||||
code = result.get("code", -1)
|
||||
msg = result.get("msg", "")
|
||||
if code == 0:
|
||||
print(f" ✅ Write SUCCESS")
|
||||
results.append((qsid, True, ""))
|
||||
else:
|
||||
print(f" ❌ Write FAILED: {msg}")
|
||||
results.append((qsid, False, msg))
|
||||
|
||||
if mode == "write":
|
||||
success = sum(1 for r in results if r[1])
|
||||
fails = sum(1 for r in results if not r[1])
|
||||
print(f"\n{'='*60}")
|
||||
print(f"WRITE SUMMARY: {success} succeeded, {fails} failed")
|
||||
for qsid, ok, msg in results:
|
||||
status = "✅" if ok else "❌"
|
||||
print(f" {status} {qsid}" + (f" - {msg}" if msg else ""))
|
||||
|
||||
# Verify all
|
||||
print(f"\n{'='*60}")
|
||||
print("VERIFYING ALL RECORDS...")
|
||||
for qsid, record_id in RECORD_IDS.items():
|
||||
v = verify_record(token, record_id)
|
||||
vcode = v.get("code", -1)
|
||||
if vcode == 0:
|
||||
rec = v.get("data", {}).get("record", {})
|
||||
jd = rec.get("fields", {}).get("jsonData", "")
|
||||
q1 = rec.get("fields", {}).get("题目1", "")
|
||||
q2 = rec.get("fields", {}).get("题目2", "")
|
||||
if jd:
|
||||
try:
|
||||
parsed = json.loads(jd)
|
||||
fq = parsed.get("first", {}).get("questionSet", [])
|
||||
sq = parsed.get("second", {}).get("questionSet", [])
|
||||
fqsid = parsed.get("first", {}).get("questionSetID", "")
|
||||
sqsid = parsed.get("second", {}).get("questionSetID", "") if isinstance(parsed.get("second", {}), dict) else ""
|
||||
print(f" ✅ {qsid}: {len(fq)} first Qs, {len(sq)} second Qs, QSID={fqsid}, 题目1={len(q1)}chars, 题目2={len(q2)}chars")
|
||||
except Exception as e:
|
||||
print(f" ❌ {qsid}: jsonData parse error: {e}")
|
||||
else:
|
||||
print(f" ❌ {qsid}: jsonData empty")
|
||||
else:
|
||||
print(f" ❌ {qsid}: verify failed: {v.get('msg', '')}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,140 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Batch write all P4 rewrites to bitable - proper version"""
|
||||
import json, subprocess, sys, os, time
|
||||
|
||||
AT = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||||
TID = "tblVmeDtBDKsAEfz"
|
||||
BASE = os.path.expanduser("~/.openclaw/workspace-xiaoyan")
|
||||
CRED_FILE = os.path.expanduser("~/.openclaw/credentials/xiaoyan/config.json")
|
||||
|
||||
sys.path.insert(0, os.path.join(BASE, "scripts"))
|
||||
import rewrite_p4_all as rw
|
||||
from rewrite_p4_all import make_q1_text
|
||||
|
||||
RECORD_IDS = {
|
||||
"021301": "recvjufKJO8d0O",
|
||||
"021401": "recvjufM763ijb",
|
||||
"021501": "recvjufM76lEsW",
|
||||
"021601": "recvjufM76hNv5",
|
||||
"021701": "recvjufM76eMKs",
|
||||
"021801": "recvjufM76lRHQ",
|
||||
"022101": "recvjufM76o6of",
|
||||
"032501": "recvjufM76k4dx",
|
||||
"032901": "recvjufM76frUP",
|
||||
}
|
||||
|
||||
def get_token():
|
||||
with open(CRED_FILE) as f:
|
||||
cred = json.load(f)
|
||||
app_id = cred["apps"][0]["appId"]
|
||||
app_secret = cred["apps"][0]["appSecret"]
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "POST",
|
||||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", json.dumps({"app_id": app_id, "app_secret": app_secret})
|
||||
], capture_output=True, text=True)
|
||||
return json.loads(result.stdout)["tenant_access_token"]
|
||||
|
||||
def write_and_verify(token, qsid, record_id, fields):
|
||||
"""Write and immediately verify one record"""
|
||||
payload = json.dumps({"fields": fields}, ensure_ascii=False)
|
||||
tmp = f"/tmp/p4_write_{record_id}.json"
|
||||
with open(tmp, "w") as f:
|
||||
f.write(payload)
|
||||
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "PUT",
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||||
"-H", f"Authorization: Bearer {token}",
|
||||
"-H", "Content-Type: application/json",
|
||||
"-d", f"@{tmp}"
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
os.remove(tmp)
|
||||
|
||||
resp = json.loads(result.stdout)
|
||||
code = resp.get("code", -1)
|
||||
if code != 0:
|
||||
return False, f"API error: {resp.get('msg','')}"
|
||||
|
||||
# Read back to verify
|
||||
result = subprocess.run([
|
||||
"curl", "-s", "-X", "GET",
|
||||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||||
"-H", f"Authorization: Bearer {token}"
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
|
||||
vdata = json.loads(result.stdout)
|
||||
vcode = vdata.get("code", -1)
|
||||
if vcode != 0:
|
||||
return False, f"Verify read error: {vdata.get('msg','')}"
|
||||
|
||||
rjd = vdata.get("data", {}).get("record", {}).get("fields", {}).get("jsonData", "")
|
||||
if not rjd:
|
||||
return False, "jsonData empty after write"
|
||||
|
||||
try:
|
||||
parsed = json.loads(rjd)
|
||||
fqs = parsed.get("first", {}).get("questionSet", [])
|
||||
first_ability = fqs[0].get("ability", []) if fqs else []
|
||||
first_expl = fqs[0].get("explanation", "") if fqs else ""
|
||||
return True, f"Q0 ability={first_ability}, expl_len={len(first_expl)}"
|
||||
except Exception as e:
|
||||
return False, f"jsonData parse error: {e}"
|
||||
|
||||
def main():
|
||||
token = get_token()
|
||||
print(f"Token: {token[:15]}...")
|
||||
|
||||
results = []
|
||||
|
||||
for qsid, record_id in RECORD_IDS.items():
|
||||
data = rw.RECORD_DATA.get(qsid)
|
||||
if not data:
|
||||
continue
|
||||
|
||||
fb = data["first_block"]
|
||||
sb = data["second_block"]
|
||||
fqs = data["first_qs_list"]
|
||||
sqs = data["second_qs_list"]
|
||||
|
||||
# Clean dialogues
|
||||
for q in fb["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
if sb and isinstance(sb, dict) and "questionSet" in sb:
|
||||
for q in sb["questionSet"]:
|
||||
q.pop("dialogue", None)
|
||||
|
||||
json_data = {"first": fb, "second": sb}
|
||||
q1_text = make_q1_text(fqs)
|
||||
q2_text = make_q1_text(sqs) if sqs else ""
|
||||
|
||||
fields = {
|
||||
"jsonData": json.dumps(json_data, ensure_ascii=False),
|
||||
"题目1": q1_text,
|
||||
"题目2": q2_text,
|
||||
}
|
||||
|
||||
print(f"\nWriting {qsid} ({record_id})...")
|
||||
ok, msg = write_and_verify(token, qsid, record_id, fields)
|
||||
|
||||
status = "✅" if ok else "❌"
|
||||
print(f" {status} {msg}")
|
||||
results.append((qsid, ok, msg))
|
||||
|
||||
# Small delay to avoid rate limiting
|
||||
time.sleep(0.3)
|
||||
|
||||
success = sum(1 for r in results if r[1])
|
||||
fails = sum(1 for r in results if not r[1])
|
||||
print(f"\n{'='*60}")
|
||||
print(f"FINAL: {success} succeeded, {fails} failed")
|
||||
|
||||
if fails:
|
||||
print("\nFailed records:")
|
||||
for qsid, ok, msg in results:
|
||||
if not ok:
|
||||
print(f" ❌ {qsid}: {msg}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: component-design
|
||||
version: 1.3.0
|
||||
version: 1.4.0
|
||||
description: 教研互动组件设计规范(结构化文本格式,不涉及JSON)。触发方式:(1) `/组件生产 --feishu-url <链接>` (2) 飞书链接 + "组件"/"设计组件"/"组件回填"。不会误触发:仅含"互动"不触发;含"组件配置-json"不触发(属于 interactive-component-json 技能)。标准化组件生产流程:设计→生成(结构化文本)→校验→回填。
|
||||
---
|
||||
|
||||
@ -53,14 +53,29 @@ description: 教研互动组件设计规范(结构化文本格式,不涉及J
|
||||
- 所有组件【正确反馈】统一填「无」
|
||||
- 【错误反馈】必须是符合当前剧情场景的自然角色对话,禁止使用指令式、说教式表达(如禁止出现"Try to pronounce clearly, one more time."这类老师命令式内容),必须带角色名
|
||||
7. **后置对话规则**:组件行之后紧接的、与组件内容相关的角色台词需要放入【后置对话】字段中
|
||||
8. **情境引入/后置对话去重规则**:禁止直接复制前一行或后一行的台词原文。若情境引入与前一行的英文台词完全相同,或后置对话与后一行的英文台词完全相同,直接写「无」
|
||||
8. **情境引入/后置对话去重规则(强制执行,审校必查)**:
|
||||
- 🚫 禁止直接复制前一行或后一行的台词原文
|
||||
- 🚫 禁止使用组件所在行之前任何行的台词作为情境引入
|
||||
- 🚫 禁止使用组件所在行之后任何行的台词作为后置对话
|
||||
- 若情境引入与前一行的英文台词完全相同,或后置对话与后一行的英文台词完全相同 → 直接写「无」
|
||||
- **审校检查点**:生成后必须逐行对比组件行前后的 E 列/F 列原文,确认情境引入/后置对话未引用任何相邻行台词
|
||||
9. **禁用内容规则**:
|
||||
- 完全删除所有【图片资源】行
|
||||
- 音频载体无特殊要求时填「无」
|
||||
- 组件禁止使用组件所在行之前的台词,【情境引入】和【后置对话】无内容时填「无」
|
||||
- 组件禁止使用组件所在行之前或之后的台词,【情境引入】和【后置对话】无内容时填「无」
|
||||
- **审校检查点**:情境引入内容必须来自组件自身场景设定,不得从剧本其他行摘取
|
||||
10. **配图组件资源配置规则**:A列含"配图"时,【资源配置】仅保留`图片时机`,不写`音频载体`。图片时机根据有实际内容(非「无」)的 section 动态列出(如「互动内容」「情境引入 互动内容 互动反馈」),所有 section 均无内容则填「无」。图片时机和音频载体禁止同时存在。
|
||||
|
||||
### 二、组件类型专属规则
|
||||
|
||||
> **详细规范索引:** 以下为各类型的快速参考。生产时请同时加载对应的专项 Skill:
|
||||
> - 对话朗读/表达/选读/选择/挖空/组句 → `dialogue-interaction-config`
|
||||
> - 信息拼词/组句/描写/补词/填词/填句 → `info-interaction-config`
|
||||
> - 物品互动 → `item-interaction-config`
|
||||
> - 图片单选/多选/有序/拖拽/互动 → `picture-interaction-config`
|
||||
> - 发音/语音/造句互动 → `pronunciation-interaction-config`
|
||||
> - 核心互动(14类)→ `core-interaction-config`
|
||||
|
||||
#### 1. 物品互动
|
||||
- 仅保留两个字段:【任务标题】+【互动内容】
|
||||
- 互动内容固定格式:`“中文动作提示” the 名词! 选项1:正确单词(正确)选项2:干扰单词`
|
||||
@ -251,6 +266,7 @@ description: 教研互动组件设计规范(结构化文本格式,不涉及J
|
||||
|
||||
---
|
||||
## 版本更新记录
|
||||
- v1.4(2026-06-11):强化规则8/9情境引入和后置对话审校规则(禁止引用组件行前后台词,新增审校检查点:逐行对比E/F列)
|
||||
- v1.3(2026-06-08):图片类互动删除【资源配置】字段、新增辅助信息规则;对话朗读删除【互动反馈】字段;新增配图组件资源配置规则;新增情境引入/后置对话去重规则(禁止复制前后行台词原文)
|
||||
- v1.2(2026-04-09):修正图片类互动高亮规则(仅知识点单词加$,非知识点不加),新增对话选择、对话选读、对话表达三类组件的配置规则及标准模板
|
||||
- v1.1(2026-04-09):新增错误反馈、任务标题、对话组句、选项格式等规则,修正不符合生产要求的旧规则
|
||||
|
||||
1087
business_production/组件生产/skills/core-interaction-config/SKILL.md
Normal file
1087
business_production/组件生产/skills/core-interaction-config/SKILL.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -94,20 +94,43 @@ Piper: You're lying! It must be your mistake!
|
||||
### 3. 对话选读
|
||||
#### 核心结构
|
||||
【任务标题】→【资源配置】→【情境引入】→【互动内容】→【后置对话】
|
||||
|
||||
#### 与对话选择的关键区分
|
||||
| 对比项 | 对话选择 | 对话选读 |
|
||||
|--------|---------|----------|
|
||||
| 互动目的 | 有对错判断 | 开放表达,任意选均可 |
|
||||
| 互动要求 | 选择正确的回复 | 选择一个你想表达的观点 |
|
||||
| 正确选项 | 标注 `(正确)` | **无正确选项** |
|
||||
| 选项反馈 | 正确选项反馈可缺省 | **每个选项均有反馈** |
|
||||
|
||||
#### 配置要点
|
||||
- 【互动内容】:
|
||||
1. 要求说明:如`要求:选择一个你想表达的观点`
|
||||
1. 第一行固定为:`要求:选择一个你想表达的观点`
|
||||
2. 选项按"选项1/2/3"排列,每个选项后对应对话式反馈
|
||||
3. 无正确/错误区分,任意选择均可
|
||||
4. 需要音频播放选项时标注`(音频)`
|
||||
#### 示例
|
||||
3. 无正确/错误区分,任意选择均可,**每个选项的反馈为必填项**
|
||||
4. 需要音频播放选项时标注`(音频)`,默认不含音频标记
|
||||
5. ⚠️ 反馈角色不可是 User 自己,必须是当前场景中的其他角色
|
||||
- 【互动反馈】:本类型不单独设置互动反馈字段,反馈内容已整合在互动内容的各选项中
|
||||
- 【资源配置】:
|
||||
- 类型为「对话选读」时,填写:`无`
|
||||
- 类型为「对话选读-配图」时,填写图片时机 + 音频载体(格式见下方示例)
|
||||
- 资源命名规范:图片文件名 `{组件ID}.png`,音频文件名 `{组件ID}.mp3`
|
||||
|
||||
#### 示例(对话选读-配图)
|
||||
```
|
||||
【任务标题】加入搏斗俱乐部
|
||||
【资源配置】无
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
音频载体:Pioneer Band
|
||||
|
||||
【情境引入】
|
||||
Johnny: What do you think of the club?
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点(默认这句话)
|
||||
要求:选择一个你想表达的观点
|
||||
选项:(音频)
|
||||
选项1:That's great! I'm going to ask Otis and Skely to go together!
|
||||
- 反馈 Johnny : I don't think it's OK to have so many people in.
|
||||
@ -115,6 +138,25 @@ Johnny: What do you think of the club?
|
||||
- 反馈 Johnny : You'd better not do this by yourself.
|
||||
选项3:It's no fun. I'd better not participate.
|
||||
- 反馈 Johnny : Ok, it's a good decision.
|
||||
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
#### 示例(对话选读-无配图)
|
||||
```
|
||||
【任务标题】说说现在的屋子吧
|
||||
【资源配置】无
|
||||
【情境引入】
|
||||
User : Yes, today is very messy.
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:
|
||||
选项1:Today is a good day. No one is at home.
|
||||
- 反馈 User : But grandparents are coming to visit!
|
||||
选项2:Today is very messy. We need to clean up.
|
||||
- 反馈 User : Yes, let's clean up together!
|
||||
选项3:Today is not so bad. We can have fun.
|
||||
- 反馈 User : But look at the sofa and the floor!
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
@ -179,7 +221,7 @@ This is my picture. It's ___, green and orange.(音频)
|
||||
#### 配置要点
|
||||
- 【互动内容】:
|
||||
1. 题目:中文描述组句要求
|
||||
2. 选项:乱序单词/短语,不添加句末标点、不首字母大写,数量3-5个
|
||||
2. 选项:乱序单词/短语,不添加句末标点、不首字母大写,数量 3-4 个
|
||||
3. 答案:完整正确句子
|
||||
4. 辅助信息:完整句子,无则填"无"
|
||||
5. 需要音频时标注`(音频)`
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
---
|
||||
name: dialogue-selective-reading-config
|
||||
version: 1.0.0
|
||||
description: 对话选读类互动组件配置标准化规范,用于剧本中对话选读/对话选读-配图类型组件的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
# 对话选读组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【对话选读】或【对话选读-配图】时,使用本规范生成组件配置
|
||||
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本、阅读文章等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 核心规则 — 与对话选择的关键区分
|
||||
|
||||
| 对比项 | 对话选择 | 对话选读 |
|
||||
|--------|---------|---------|
|
||||
| 互动目的 | 有对错判断 | 开放表达,任意选均可 |
|
||||
| 互动要求 | 选择正确的回复 | 选择一个你想表达的观点 |
|
||||
| 正确选项 | 标注 `(正确)` | **无正确选项** |
|
||||
| 选项反馈 | 正确选项反馈可缺省 | **每个选项均有反馈** |
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:
|
||||
- 设计规则:结合剧情上下文,提炼互动核心内容,使用中文口语化表述,符合低龄用户认知
|
||||
- 核心要素:包含互动对象+核心动作/状态,避免笼统的「对话X」编号
|
||||
- 约定:如需表达顺序关系,使用中文括号替代「-」,如「与调酒师对峙(一)」而非「与调酒师对峙-1」
|
||||
- ⚠️ 标题含英文单词时,英文单词前后必须留空格
|
||||
2. 【资源配置】:
|
||||
- 类型为「对话选读」时,填写:无
|
||||
- 类型为「对话选读-配图」时,填写:
|
||||
```
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
音频载体:Pioneer Band
|
||||
```
|
||||
- 资源命名规范:
|
||||
- 图片文件名:`{组件ID}.png`,如 `0216002.png`
|
||||
- 音频文件名:`{组件ID}.mp3`,如 `0216002.mp3`
|
||||
- 音频默认在互动内容、互动反馈期间出现;若配置音频,必须添加【音频载体】
|
||||
- 图片默认在互动内容、互动反馈期间出现;如需调整节点,在【资源配置】处填写【情境引入】或【后置对话】
|
||||
3. 【情境引入】:
|
||||
- 以对话方式呈现,每行一句。格式为「角色名 : 对话内容」
|
||||
- 若无情境引入,填「无」
|
||||
4. 【互动内容】:
|
||||
- 第一行:固定为「要求:选择一个你想表达的观点」
|
||||
- 第二行:标注「选项:(音频)」(表示选项有音频支持;默认无音频,若需手动添加音频则填「选项:(音频)」)
|
||||
- 第三部分:列出所有选项,编号为「选项1」「选项2」「选项3」... 依次排列
|
||||
- 每个选项后以「- 反馈 角色名 : 对话内容」形式标注反馈
|
||||
- **无正确/错误区分**,每个选项的反馈为必填项
|
||||
- ⚠️ 反馈角色不可是 User 自己,必须是当前场景中的其他角色
|
||||
- (音频)标记默认不含,若选项需要播放音频则手动填写「(音频)」,使用中文括号
|
||||
5. 【互动反馈】:本类型不单独设置互动反馈字段,反馈内容已整合在互动内容的各选项中
|
||||
6. 【后置对话】:
|
||||
- 以对话方式呈现,每行一句。格式为「角色名 : 对话内容」
|
||||
- 若无后置对话,填「无」
|
||||
## 完整示例
|
||||
### 对话选读-配图类型示例
|
||||
```
|
||||
【任务标题】
|
||||
加入搏斗俱乐部
|
||||
|
||||
【资源配置】
|
||||
图片时机:
|
||||
互动内容
|
||||
互动反馈
|
||||
|
||||
音频载体:Pioneer Band
|
||||
|
||||
【情境引入】
|
||||
Johnny: What do you think of the club?
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:(音频)
|
||||
选项1:That's great! I'm going to ask Otis and Skely to go together!
|
||||
- 反馈 Johnny : I don't think it's OK to have so many people in.
|
||||
选项2:Interesting! I can go on this trip alone.
|
||||
- 反馈 Johnny : You'd better not do this by yourself.
|
||||
选项3:It's no fun. I'd better not participate.
|
||||
- 反馈 Johnny : Ok, it's a good decision.
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
```
|
||||
### 对话选读类型示例
|
||||
```
|
||||
【任务标题】
|
||||
说说现在的屋子吧
|
||||
|
||||
【资源配置】
|
||||
无
|
||||
|
||||
【情境引入】
|
||||
User : Yes, today is very messy.
|
||||
|
||||
【互动内容】
|
||||
要求:选择一个你想表达的观点
|
||||
选项:
|
||||
选项1:Today is a good day. No one is at home.
|
||||
- 反馈 User : But grandparents are coming to visit!
|
||||
选项2:Today is very messy. We need to clean up.
|
||||
- 反馈 User : Yes, let's clean up together!
|
||||
选项3:Today is not so bad. We can have fun.
|
||||
- 反馈 User : But look at the sofa and the floor!
|
||||
|
||||
【后置对话】
|
||||
无
|
||||
```
|
||||
225
business_production/组件生产/skills/info-interaction-config/SKILL.md
Normal file
225
business_production/组件生产/skills/info-interaction-config/SKILL.md
Normal file
@ -0,0 +1,225 @@
|
||||
---
|
||||
name: info-interaction-config
|
||||
version: 1.0.0
|
||||
description: 信息类互动组件配置标准化规范,覆盖信息拼词/组句/描写/补词/填词/填句共6类的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
1. 禁止 Markdown 标记
|
||||
2. 英式拼写优先
|
||||
3. 中文全角标点,英文半角标点,不混用
|
||||
|
||||
## 通用规则(6类共享)
|
||||
|
||||
- 【任务标题】:中文口语化,10字以内,避免「-」,有序用「(一)」,含英文单词时前后留空格
|
||||
- 【资源配置】:图片文件名 = `{组件ID}.png`,不含音频配置
|
||||
- 【后置对话】:无则填「无」
|
||||
|
||||
---
|
||||
|
||||
## 一、信息拼词
|
||||
|
||||
单词中挖空字母,从候选字母中选取正确字母拼出完整单词。
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
任务描述:请…
|
||||
题干:{单词,空缺字母用(数字)占位,如 G(2)pe}
|
||||
答案:{填入的字母,如 ra}
|
||||
选项:{4-7个候选字母,逗号分隔}
|
||||
辅助信息:{提示 或 无}
|
||||
```
|
||||
|
||||
**规则:** 最多挖空不超过单词总字母数的一半;目标词必须来自知识点;干扰字母与答案字母有明显区分。
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】购买葡萄
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
任务描述:请填入"葡萄"的正确的英文拼写
|
||||
题干:G(2)pe
|
||||
答案:ra
|
||||
选项:h, a, r, l, e, w
|
||||
辅助信息:葡萄的英文是 grape
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、信息组句
|
||||
|
||||
从短语/词组拼出完整句子。
|
||||
|
||||
**与对话组句的关键区分:**
|
||||
|
||||
| 对比项 | 对话组句 | 信息组句 |
|
||||
|--------|---------|---------|
|
||||
| 选项粒度 | 单词级 | 短语/词组级 |
|
||||
| 选项数量 | 4-8 | 3-5 |
|
||||
| 干扰项 | 0-1 | 1-2 |
|
||||
| 资源 | 可选音频 | 必有图片 |
|
||||
| 目标来源 | 基于台词 | 基于知识点 |
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
任务描述:{指引}
|
||||
选项1:{短语}
|
||||
选项2:{短语}
|
||||
选项3:{短语}
|
||||
答案:{完整句子,含大小写+句末标点}
|
||||
辅助信息:{提示 或 无}
|
||||
```
|
||||
|
||||
**规则:** 选项 3-5 个,乱序;短语/词组级切分,不按单词边界切;选项不加首字母大写和句末标点;含 1-2 个干扰项。
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】填写信息表
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
任务描述:请在空白处填入正确的单词,组成句子
|
||||
选项1:is
|
||||
选项2:the visitor
|
||||
选项3:you invited
|
||||
选项4:Maeve
|
||||
答案:Is Maeve the visitor you invited?
|
||||
辅助信息:可以用 is 引导的一般疑问句询问
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、信息描写
|
||||
|
||||
根据图片或场景提示,用英文描述所看到的内容。
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
任务描述:{任务指引}
|
||||
参考词汇:{关键词汇}
|
||||
参考句型:{句型}
|
||||
示例回答:User: {句子}
|
||||
```
|
||||
|
||||
**规则:** 必有图片资源;考察观察与表达能力;知识点必须来自当前单元。
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】描述房间里的物品
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
任务描述:请用英文描述图片中房间里的物品
|
||||
参考词汇:sofa, window, door, table
|
||||
参考句型:There is a... / I can see...
|
||||
示例回答:User: There is a sofa in the room.
|
||||
【互动反馈】
|
||||
正确 User: Great! You described it well.
|
||||
错误 User: Try again. What else can you see?
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、信息补词
|
||||
|
||||
句子中挖空一个单词,从候选词中选出正确单词填入。
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
题干:{含___的句子}
|
||||
选项1:{单词}(正确)
|
||||
选项2:{单词}
|
||||
选项3:{单词}
|
||||
辅助信息:{提示 或 无}
|
||||
```
|
||||
|
||||
**规则:** 3-4 个候选单词;有候选词列表(区别于信息填词)。
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】补全句子中的单词
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
题干:The cat is sitting on the ___.
|
||||
选项1:chair(正确)
|
||||
选项2:table
|
||||
选项3:floor
|
||||
辅助信息:注意图片中猫的位置
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、信息填词
|
||||
|
||||
句子中挖空一个单词,学生自行拼写填入(无候选词)。
|
||||
|
||||
**与信息补词的关键区分:**
|
||||
|
||||
| 对比项 | 信息补词 | 信息填词 |
|
||||
|--------|---------|---------|
|
||||
| 题型本质 | 从选项中选 | 自行拼写 |
|
||||
| 选项 | 有候选词 | 无选项 |
|
||||
| 难度 | 较低(识别) | 较高(回忆+拼写) |
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
题干:{含___的句子}
|
||||
答案:{正确单词}
|
||||
辅助信息:{提示 或 无}
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】填入正确的单词
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
题干:The ___ is on the desk.
|
||||
答案:book
|
||||
辅助信息:首字母是 b
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、信息填句
|
||||
|
||||
给出不完整句子,学生补全完整句子。
|
||||
|
||||
**与信息组句的关键区分:**
|
||||
|
||||
| 对比项 | 信息组句 | 信息填句 |
|
||||
|--------|---------|---------|
|
||||
| 题型本质 | 从短语拼出完整句 | 补全不完整句子 |
|
||||
| 输入 | 乱序短语选项 | 句子框架 + 自由输入 |
|
||||
| 难度 | 中等(排序+选择) | 中等(补全) |
|
||||
|
||||
**互动内容格式:**
|
||||
```
|
||||
题干:{不完整句子,缺失部分用___表示}
|
||||
答案:{完整句子}
|
||||
辅助信息:{提示 或 无}
|
||||
```
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】补全这个句子
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
题干:The boy ___ to school every day.
|
||||
答案:The boy walks to school every day.
|
||||
辅助信息:注意主语是第三人称单数
|
||||
【后置对话】无
|
||||
```
|
||||
@ -1,66 +0,0 @@
|
||||
---
|
||||
name: info-sentence-building-config
|
||||
version: 1.0.0
|
||||
description: 信息组句类互动组件配置标准化规范,用于剧本中信息组句类型组件的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
# 信息组句组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【信息组句】时,使用本规范生成组件配置
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记
|
||||
2. 英式拼写优先
|
||||
3. 中文全角标点,英文半角标点,不混用
|
||||
|
||||
## 核心规则 — 与对话组句的关键区分
|
||||
|
||||
| 对比项 | 对话组句 | 信息组句 |
|
||||
|--------|---------|---------|
|
||||
| 选项粒度 | 单词级 | **短语/词组级** |
|
||||
| 选项数量 | 4-8 | **3-5** |
|
||||
| 干扰项 | 0-1 | **1-2** |
|
||||
| 资源 | 可选音频 | **必有图片** |
|
||||
| 目标词来源 | 基于台词 | **基于知识点** |
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:
|
||||
- 中文口语化表述,符合低龄用户认知
|
||||
- 避免「-」,有序用「(一)」
|
||||
- ⚠️ 标题含英文单词时,英文单词前后必须留空格
|
||||
2. 【资源配置】:
|
||||
- 图片文件名 = `{组件ID}.png`,后台手动上传
|
||||
- 不含音频配置
|
||||
3. 【互动内容】:
|
||||
- **任务描述**:清晰任务指引,引导学生组句
|
||||
- **选项**:选项1/2/3... 形式
|
||||
- 数量 3-5 个,乱序排列
|
||||
- 短语/词组级别切分,**不按单词边界切**
|
||||
- 选项内不添加首字母大写,不加句末标点
|
||||
- 含 1-2 个干扰项
|
||||
- **答案**:完整句子,含正确大小写 + 句末标点
|
||||
- **辅助信息**:语法/结构提示;无则写「无」
|
||||
4. 【后置对话】:无则填「无」
|
||||
|
||||
## 完整示例
|
||||
```
|
||||
【任务标题】填写信息表
|
||||
【资源配置】
|
||||
图片文件名:{组件ID}.png
|
||||
【互动内容】
|
||||
任务描述:请在空白处填入正确的单词,组成句子
|
||||
选项1:is
|
||||
选项2:the visitor
|
||||
选项3:you invited
|
||||
选项4:Maeve
|
||||
答案:Is Maeve the visitor you invited?
|
||||
辅助信息:可以用 is 引导的一般疑问句询问;you invited 是 visitor 的后置定语
|
||||
【后置对话】无
|
||||
```
|
||||
@ -1,71 +0,0 @@
|
||||
---
|
||||
name: info-word-spelling-config
|
||||
version: 1.0.0
|
||||
description: 信息拼词类互动组件配置标准化规范,用于剧本中信息拼词类型组件的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
# 信息拼词组件配置规范
|
||||
## 适用场景
|
||||
当【类型】列内容为【信息拼词】时,使用本规范生成组件配置
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析、音频文本等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
## 核心规则
|
||||
|
||||
信息拼词是通过部分字母提示,让学生从候选字母中选取正确字母拼出完整单词的互动题型。
|
||||
|
||||
**与对话挖空的核心区分:**
|
||||
| 对比项 | 对话挖空 | 信息拼词 |
|
||||
|--------|---------|---------|
|
||||
| 题型本质 | 句子中挖空单词 | 单词中挖空字母 |
|
||||
| 目标粒度 | 完整单词 | 单个字母 |
|
||||
| 题干形式 | 句子含 `___` | 单词含 `(数字)` |
|
||||
| 资源 | 可选音频 | 必有图片 |
|
||||
| 知识约束 | 知识点句型/单词 | **目标词必须来自知识点** |
|
||||
|
||||
## 配置格式
|
||||
### 字段要求
|
||||
1. 【任务标题】:
|
||||
- 中文口语化表述,符合低龄用户认知
|
||||
- 避免使用「-」,有序关系用中文括号「(一)」
|
||||
- 示例:购买葡萄 / 拼写爷爷的英文
|
||||
- ⚠️ 标题含英文单词时,英文单词前后必须留空格
|
||||
2. 【资源配置】:
|
||||
- 填写图片文件名,格式为 `{组件ID}.png`(如 `0216002.png`)
|
||||
- 图片在内容管理后台手动上传
|
||||
- 不含音频配置
|
||||
- **不含图片坐标信息**(坐标在后台「选取图片坐标」工具中单独配置)
|
||||
3. 【互动内容】:
|
||||
- **任务描述**:清晰的任务指引,引导学生拼写目标单词。格式为「请…」
|
||||
- **题干**:目标单词,其中需学生填入的字母部分用 `(数字)` 占位,数字 = 空缺字母数
|
||||
- 示例:`G(2)pe`(grape 缺 2 个字母)/ `grandfa(4)`(grandfather 缺最后 4 个字母)
|
||||
- 最多挖空不超过单词总字母数的一半
|
||||
- **答案**:仅写需填入的字母,按顺序,中间不加空格
|
||||
- 示例:`ra` / `ther`
|
||||
- **选项**:4-7 个候选字母,逗号分隔,含正确答案字母 + 干扰字母
|
||||
- 干扰字母应与答案字母有明显区分
|
||||
- **辅助信息**:提示语句帮助学生;无则写「无」
|
||||
4. 【后置对话】:无后置对话则填「无」
|
||||
|
||||
## 完整示例
|
||||
```
|
||||
【任务标题】购买葡萄
|
||||
【资源配置】
|
||||
图片文件名:0216002.png
|
||||
【互动内容】
|
||||
任务描述:请填入"葡萄"的正确的英文拼写
|
||||
题干:G(2)pe
|
||||
答案:ra
|
||||
选项:h, a, r, l, e, w
|
||||
辅助信息:葡萄的英文是 grape / 第二个字母是 r 哦,再想想最后一个空应该填什么吧
|
||||
【后置对话】无
|
||||
```
|
||||
@ -0,0 +1,65 @@
|
||||
---
|
||||
name: item-interaction-config
|
||||
version: 1.0.0
|
||||
description: 物品互动类组件配置标准化规范,用于剧本中物品互动类型组件的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
# 物品互动组件配置规范
|
||||
|
||||
## 适用场景
|
||||
当【类型】列内容为【物品互动】时,使用本规范生成组件配置。
|
||||
|
||||
## 核心规则
|
||||
|
||||
物品互动是让学生根据中文提示,在场景中点击/选择正确物品的互动题型。
|
||||
|
||||
**关键特征:**
|
||||
- 仅保留两个字段:【任务标题】+【互动内容】
|
||||
- 互动内容固定格式:`"中文动作提示" the 名词! 选项1:正确单词(正确)选项2:干扰单词`
|
||||
- 无【资源配置】【情境引入】【互动反馈】【后置对话】字段
|
||||
|
||||
## 配置格式
|
||||
|
||||
### 字段要求
|
||||
|
||||
1. 【任务标题】:
|
||||
- 中文口语化表述,描述要做的动作
|
||||
- 避免使用「-」,有序关系用中文括号「(一)」
|
||||
- 示例:关上灯塔大门 / 拿起桌上的苹果
|
||||
|
||||
2. 【互动内容】:
|
||||
- 固定格式:`"中文动作提示" the 名词!`
|
||||
- 选项1:正确单词,标注 `(正确)`
|
||||
- 选项2:干扰单词(与正确单词同类或形近)
|
||||
- 可扩展到 3 个选项(1正确 + 2干扰)
|
||||
|
||||
## 完整示例
|
||||
|
||||
```
|
||||
【任务标题】关上灯塔大门
|
||||
【互动内容】
|
||||
"关上" the door!
|
||||
选项1:close(正确)
|
||||
选项2:open
|
||||
```
|
||||
|
||||
```
|
||||
【任务标题】拿起桌上的苹果
|
||||
【互动内容】
|
||||
"拿起" the apple!
|
||||
选项1:pick up(正确)
|
||||
选项2:put down
|
||||
选项3:throw away
|
||||
```
|
||||
@ -0,0 +1,146 @@
|
||||
---
|
||||
name: picture-interaction-config
|
||||
version: 1.0.0
|
||||
description: 图片类互动组件配置标准化规范,覆盖图片单选/多选/有序/拖拽/图片互动等类型的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
# 图片类互动组件配置规范
|
||||
|
||||
## 适用场景
|
||||
当【类型】列内容为【图片单选】【图片多选】【图片有序】【图片拖拽】【图片互动】时,使用本规范生成组件配置。
|
||||
|
||||
## 核心规则
|
||||
|
||||
### 通用规则(所有图片类互动适用)
|
||||
|
||||
1. **不包含【资源配置】字段**,直接从【任务标题】开始
|
||||
2. 【互动内容】题干必须为指令句式,禁止使用问句
|
||||
3. 仅知识点单词前后加 `$` 符号高亮,非知识点单词不加
|
||||
4. 选项仅保留 `00/01/02/03` 编号,不需要任何文字说明
|
||||
5. 在「正确:XX」行后添加一行 `辅助信息:{单词} {中文释义}。`
|
||||
6. 正确反馈统一填「无」,错误反馈必须带角色名
|
||||
|
||||
### 各子类型专属规则
|
||||
|
||||
#### 图片单选
|
||||
- 4 个图片选项(00-03),其中 1 个正确
|
||||
- 正确标注:`正确:02`(编号对应正确图片)
|
||||
- 示例:
|
||||
```
|
||||
【任务标题】选出正确的物品
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
题干:Find the $apple$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确:02
|
||||
辅助信息:apple 苹果。
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : That's not an apple. Try again!
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
#### 图片多选
|
||||
- 4 个及以上图片选项,多个正确
|
||||
- 正确标注:`正确:00, 02`(多个编号逗号分隔)
|
||||
- 示例:
|
||||
```
|
||||
【任务标题】选出所有水果
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
题干:Find all the $fruit$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确:00, 02
|
||||
辅助信息:fruit 水果。
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Sally : Some fruits are missing. Look again!
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
#### 图片有序
|
||||
- 4 个及以上图片选项,需按正确顺序排列
|
||||
- 正确标注:`正确顺序:00→01→02→03`
|
||||
- 示例:
|
||||
```
|
||||
【任务标题】排序跳格子顺序
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
题干:Put the actions in order of $one by one$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
正确顺序:00→01→02→03
|
||||
辅助信息:one by one 指"一个接一个"。
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Dan : Oops, that's the wrong order! We can't jump like that.
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
#### 图片拖拽
|
||||
- 将图片拖拽到对应位置
|
||||
- 正确标注:`正确:00→位置A, 01→位置B`
|
||||
- 示例:
|
||||
```
|
||||
【任务标题】将物品放到正确位置
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
题干:Drag the items to the correct $places$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
正确:00→位置A, 01→位置B
|
||||
辅助信息:places 位置。
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:Matt : That doesn't belong there!
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
#### 图片互动
|
||||
- 自由点击/探索类图片互动
|
||||
- 无正确/错误判断,仅有点击反馈
|
||||
- 示例:
|
||||
```
|
||||
【任务标题】探索教室里的物品
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
题干:Tap on the items in the $classroom$.
|
||||
选项:
|
||||
00
|
||||
01
|
||||
02
|
||||
03
|
||||
反馈00:This is a desk.
|
||||
反馈01:This is a chair.
|
||||
反馈02:This is a blackboard.
|
||||
反馈03:This is a window.
|
||||
【互动反馈】
|
||||
正确:无
|
||||
错误:无
|
||||
【后置对话】无
|
||||
```
|
||||
@ -0,0 +1,106 @@
|
||||
---
|
||||
name: pronunciation-interaction-config
|
||||
version: 1.0.0
|
||||
description: 发音/语音/造句类互动组件配置标准化规范,覆盖发音互动/语音互动/造句互动类型的标准化生成
|
||||
metadata:
|
||||
requires:
|
||||
permissions: ["sheets:spreadsheet"]
|
||||
identity: bot
|
||||
---
|
||||
|
||||
## 文本输出规范(强制执行)
|
||||
|
||||
所有输出的文本内容(台词、题目、选项、解析等)必须遵守以下规则:
|
||||
|
||||
1. 禁止 Markdown 标记:禁止使用 ** * __ _ 等加粗/斜体标识,也禁止使用 # > - 等块级 Markdown 语法。所有文本纯文本输出。
|
||||
2. 英式拼写优先:单词涉及英美式拼写差异时(如 colour/color、centre/center、travelling/traveling),统一选择英式拼写。
|
||||
3. 标点符号规范:严格区分全角/半角符号。中文内容使用全角标点(,。!?),英文内容使用半角标点(. , ! ?),不得混用。
|
||||
|
||||
# 发音/语音/造句类互动组件配置规范
|
||||
|
||||
## 适用场景
|
||||
当【类型】列内容为【发音互动】【语音互动】【造句互动】时,使用本规范生成组件配置。
|
||||
|
||||
## 核心规则
|
||||
|
||||
### 发音互动
|
||||
考察学生发音准确度的互动题型。
|
||||
|
||||
**配置格式:**
|
||||
- 【任务标题】:中文口语化表述
|
||||
- 【资源配置】:无(或标注音频文件名)
|
||||
- 【互动内容】:
|
||||
- 目标单词/句子:学生需要朗读的内容
|
||||
- 发音要点:关键音素或发音提示
|
||||
- 示例音频:标注 `(音频)` 如需要
|
||||
- 【互动反馈】:正确/错误反馈,带角色名
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】朗读含 th 音的单词
|
||||
【资源配置】无
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
朗读单词:think
|
||||
发音要点:注意 th 音,舌尖轻触上齿
|
||||
【互动反馈】
|
||||
正确 Matt: Perfect pronunciation!
|
||||
错误 Matt: Try again. Put your tongue between your teeth.
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
### 语音互动
|
||||
考察学生语音表达能力的互动题型。
|
||||
|
||||
**配置格式:**
|
||||
- 【任务标题】:中文口语化表述
|
||||
- 【资源配置】:无
|
||||
- 【互动内容】:
|
||||
- 表达目标:学生需要说的内容描述
|
||||
- 示例回答:`User: 示例句子`
|
||||
- 辅助信息:语音/语调提示
|
||||
- 【互动反馈】:正确/错误反馈,带角色名
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】用正确的语调打招呼
|
||||
【资源配置】无
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
表达目标:用开心的语调说 Hello
|
||||
示例回答:User: Hello!
|
||||
辅助信息:注意语调上扬,表达开心的情绪
|
||||
【互动反馈】
|
||||
正确 Sally: You sound so happy!
|
||||
错误 Sally: Try to sound more excited!
|
||||
【后置对话】无
|
||||
```
|
||||
|
||||
### 造句互动
|
||||
考察学生用给定词汇/句型独立造句能力的互动题型。
|
||||
|
||||
**配置格式:**
|
||||
- 【任务标题】:中文口语化表述
|
||||
- 【资源配置】:无(或标注图片文件名)
|
||||
- 【互动内容】:
|
||||
- 任务描述:造句要求
|
||||
- 给定词汇/句型:学生必须使用的词汇或句型
|
||||
- 示例回答:`User: 示例句子`
|
||||
- 辅助信息:语法/结构提示
|
||||
- 【互动反馈】:正确/错误反馈,带角色名
|
||||
|
||||
**示例:**
|
||||
```
|
||||
【任务标题】用 like 造句
|
||||
【资源配置】无
|
||||
【情境引入】无
|
||||
【互动内容】
|
||||
任务描述:用 like 造句,说说你喜欢什么
|
||||
给定句型:I like...
|
||||
示例回答:User: I like apples.
|
||||
辅助信息:like 后面可以加名词,表示喜欢某物
|
||||
【互动反馈】
|
||||
正确 Dan: I like that too!
|
||||
错误 Dan: Hmm, that doesn't sound right. Try "I like..."
|
||||
【后置对话】无
|
||||
```
|
||||
@ -49,10 +49,10 @@ description: 剧本互动组件内容生产/审校/回填技能(不涉及JSON
|
||||
|
||||
---
|
||||
|
||||
## 执行流程(6个节点)
|
||||
## 执行流程(7个节点)
|
||||
|
||||
```
|
||||
读取飞书文档 → 解析Sheet列结构 → 识别组件行 → 匹配组件类型 → LLM生成组件内容 → 审校 → 回填
|
||||
读取飞书文档 → 解析Sheet列结构 → 识别组件行 → 匹配组件类型 → 加载专项Skill → LLM生成组件内容 → 审校 → 回填
|
||||
```
|
||||
|
||||
### 节点1:文档读取
|
||||
@ -99,9 +99,29 @@ description: 剧本互动组件内容生产/审校/回填技能(不涉及JSON
|
||||
- 剧情描述含"表达"/"说出" → 对话表达
|
||||
- 剧情描述含"看图"/"图片" → 看图说话
|
||||
|
||||
### 节点4.5:加载对应专项 Skill(强制执行)
|
||||
|
||||
在调用 LLM 生成前,**必须先读取该组件类型对应的专项 Skill**,将规范注入 LLM prompt:
|
||||
|
||||
| 组件类型 | 对应专项 Skill | 路径 |
|
||||
|---------|---------------|------|
|
||||
| 对话朗读 / 对话表达 / 对话选读 / 对话选择 / 对话挖空 / 对话组句 | `dialogue-interaction-config` | `skills/dialogue-interaction-config/SKILL.md` |
|
||||
| 信息拼词 / 信息组句 / 信息描写 / 信息补词 / 信息填词 / 信息填句 | `info-interaction-config` | `skills/info-interaction-config/SKILL.md` |
|
||||
| 物品互动 | `item-interaction-config` | `skills/item-interaction-config/SKILL.md` |
|
||||
| 图片单选 / 图片多选 / 图片有序 / 图片拖拽 / 图片互动 | `picture-interaction-config` | `skills/picture-interaction-config/SKILL.md` |
|
||||
| 发音互动 / 语音互动 / 造句互动 | `pronunciation-interaction-config` | `skills/pronunciation-interaction-config/SKILL.md` |
|
||||
| 核心互动(听力/口语/阅读/写作共14类) | `core-interaction-config` | `skills/core-interaction-config/SKILL.md` |
|
||||
| 对话互动 / 材料互动 / 指令互动 / 挖空互动 / 组句互动 / 填词互动 / 看图说话 | `component-design` + `vala-interactive-components` | 通用规范 + 官方配置参考 |
|
||||
|
||||
**执行流程:**
|
||||
1. 根据节点4匹配到的组件类型,查表确定需要加载的专项 Skill
|
||||
2. 读取对应 SKILL.md,提取字段模板、校验规则、示例
|
||||
3. 将提取的规范作为 system prompt 注入 LLM 调用
|
||||
4. 确保 LLM 严格按规范输出,而非自由发挥
|
||||
|
||||
### 节点5:LLM生成组件内容(结构化文本)
|
||||
|
||||
调用大模型生成结构化文本格式的组件内容,遵循 `component-design` 技能规范。
|
||||
调用大模型生成结构化文本格式的组件内容,**严格遵循节点4.5加载的专项 Skill 规范**。
|
||||
|
||||
**输出格式(结构化文本,非JSON):**
|
||||
|
||||
@ -135,9 +155,11 @@ This is my picture. It's ___, green and orange.(音频)
|
||||
```
|
||||
|
||||
**各组件类型的字段模板参考:**
|
||||
- 中互动 → 遵循 `component-design` 技能中各类型专属规则
|
||||
- 对话类互动(朗读/表达/选读/选择/挖空/组句)→ 遵循 `dialogue-interaction-config` 技能规范
|
||||
- 信息拼词/组句/描写/补词/填词/填句 → 遵循 `info-interaction-config` 技能规范
|
||||
- 物品互动 / 图片类互动 → 遵循 `component-design` 技能中各类型专属规则
|
||||
- 核心互动 → 遵循 `core-content-json-standard` 技能中的内容结构描述
|
||||
- 对话类互动 → 遵循 `dialogue-interaction-config` 技能规范
|
||||
- 其余中互动 → 遵循 `component-design` + `vala-interactive-components` 通用规范
|
||||
|
||||
### 节点6:审校 & 回填
|
||||
|
||||
@ -152,14 +174,15 @@ This is my picture. It's ___, green and orange.(音频)
|
||||
| 6 | 选项格式 | 对话类用「选项1:XXX」、图片类用00/01/02编号 |
|
||||
| 7 | 反馈格式 | 错误反馈带角色名、自然对话、非指令式 |
|
||||
| 8 | 高亮规则 | 图片类仅知识点词加$、对话类不加 |
|
||||
| 9 | 情境引入 | 无内容填「无」,多句换行,格式为「角色名: 台词」。**禁止直接复制前一行台词原文**,相同则填「无」 |
|
||||
| 10 | 后置对话 | 取组件行之后的紧接台词,无则填「无」。**禁止直接复制后一行台词原文**,相同则填「无」 |
|
||||
| 9 | 情境引入 | 无内容填「无」,多句换行,格式为「角色名: 台词」。🚫 **禁止引用组件行之前任何行的台词**(含前一行的E列/F列原文),必须来自组件自身场景设定。审校时逐行对比组件行之前的E/F列,确认无重合 |
|
||||
| 10 | 后置对话 | 取组件行之后的紧接台词,无则填「无」。🚫 **禁止直接复制后一行台词原文**,相同则填「无」。审校时逐行对比组件行之后的E/F列,确认无重合 |
|
||||
| 11 | 超纲检查 | 词汇/句型在对应级别词库/句型库范围内 |
|
||||
| 12 | 标点符号 | 统一使用标准英文标点,禁止「~」「!!!」等非标准标点 |
|
||||
| 13 | 图片类资源配置 | 图片类互动(图片单选/多选/有序/拖拽)**不包含【资源配置】字段** |
|
||||
| 14 | 图片类辅助信息 | 图片类互动在「正确:XX」后添加 `辅助信息:{单词} {中文释义}。`,释义参考知识点 Sheet |
|
||||
| 15 | 对话朗读反馈 | 对话朗读**不包含【互动反馈】字段** |
|
||||
| 16 | 配图资源配置 | A列含"配图"时,仅保留`图片时机`(不写`音频载体`),根据有内容的 section 动态列出 |
|
||||
| 17 | 答案随机化 | 听力选择/对话选择等多小题组件,各题正确选项位置必须随机分布,禁止全部集中在同一序号。生成后统计各题正确选项序号,若全部相同则重新随机 |
|
||||
|
||||
#### 回填
|
||||
- 将生成的结构化文本写入列G(组件配置)
|
||||
@ -238,6 +261,7 @@ This is my picture. It's ___, green and orange.(音频)
|
||||
|
||||
## 版本历史
|
||||
|
||||
- v1.3.0(2026-06-11):强化 #9-#10 情境引入/后置对话审校规则(禁止引用组件行前后台词,必须逐行对比E/F列);新增 #17 答案随机化检查(多小题正确选项必须随机分布)
|
||||
- v1.2.0(2026-06-08):审校检查项新增 #13-#16(图片类资源配置、辅助信息、对话朗读反馈、配图资源配置);更新 #9-#10 情境引入/后置对话去重规则
|
||||
- v1.1.0(2026-05-13):明确职责边界,产出格式从JSON改为结构化文本,与 interactive-component-json 解耦
|
||||
- v1.0.0(2026-05-13):初始版本,覆盖27种中互动 + 14种核心互动,完整6节点流程
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
---
|
||||
name: dialogue-components-standardizer
|
||||
description: A unified skill for standardizing the production and review of 6 dialogue interaction components. Core logic is fixed; optimizations are handled via branch files and scripts for repeatability. Enter skill only when components change dynamically.
|
||||
description: ⛔ DEPRECATED (2026-06-11). 仅覆盖8类组件,与41类实际组件差距太大。对话类6类已由 dialogue-interaction-config 统一覆盖,信息拼词/组句已由独立 skill 覆盖。本 skill 不再使用,保留仅供历史参考。
|
||||
status: deprecated
|
||||
---
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -115,3 +115,5 @@
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-06-10T03:52:13.443Z","query":"Perfect Oops 数据 复核 审校 组件","resultCount":1,"results":[{"path":"memory/2026-05-28.md","startLine":19,"endLine":37,"score":1}]}
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-06-10T03:52:28.180Z","query":"深度复核 流程 步骤 component review audit","resultCount":4,"results":[{"path":"memory/2026-05-20.md","startLine":40,"endLine":59,"score":1},{"path":"memory/2026-05-20.md","startLine":55,"endLine":65,"score":1},{"path":"memory/2026-05-12.md","startLine":234,"endLine":254,"score":1},{"path":"memory/2026-06-08.md","startLine":17,"endLine":27,"score":1}]}
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-06-10T03:52:28.181Z","query":"core_speaking_image JSON 结构 口语看图","resultCount":3,"results":[{"path":"memory/2026-05-12.md","startLine":164,"endLine":187,"score":1},{"path":"memory/2026-05-12.md","startLine":214,"endLine":236,"score":1},{"path":"memory/2026-05-12.md","startLine":234,"endLine":254,"score":1}]}
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-06-11T10:31:34.088Z","query":"S0 多维表格 核心互动 组件配置 bitable","resultCount":6,"results":[{"path":"memory/2026-05-12.md","startLine":214,"endLine":236,"score":1},{"path":"memory/2026-05-12.md","startLine":164,"endLine":187,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1},{"path":"memory/2026-05-12.md","startLine":234,"endLine":254,"score":1},{"path":"memory/2026-05-12.md","startLine":199,"endLine":216,"score":1},{"path":"memory/2026-05-07.md","startLine":86,"endLine":107,"score":1}]}
|
||||
{"type":"memory.recall.recorded","timestamp":"2026-06-11T10:31:50.633Z","query":"S0 多维表格 0000001 合作阅读 核心互动 bitable token","resultCount":6,"results":[{"path":"memory/2026-05-12.md","startLine":214,"endLine":236,"score":1},{"path":"memory/2026-05-12.md","startLine":164,"endLine":187,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1},{"path":"memory/2026-05-12.md","startLine":234,"endLine":254,"score":1},{"path":"memory/2026-05-12.md","startLine":199,"endLine":216,"score":1},{"path":"memory/2026-05-07.md","startLine":86,"endLine":107,"score":1}]}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"updatedAt": "2026-06-10T03:52:28.181Z",
|
||||
"updatedAt": "2026-06-11T10:31:50.633Z",
|
||||
"entries": {
|
||||
"memory:memory/2026-05-07.md:57:74": {
|
||||
"key": "memory:memory/2026-05-07.md:57:74",
|
||||
@ -2433,18 +2433,21 @@
|
||||
"endLine": 107,
|
||||
"source": "memory",
|
||||
"snippet": "- 表2:.xlsx 文件(LV2词表,1,329个单词,含「LV2-单词」「LV2上单词占用情况」「LV2下单词占用情况」「LV2S3」四个sheet) - 表3:.xlsx 文件(L1词表,845个单词,含「单词表-LV1(上)」「单词表-LV1(下)」「单词表-备用」三个sheet合并去重) - **对比过程(共四轮验证):** 1. 第一轮(表1 vs 表2):表1有但表2没有 = 502个 2. 第二轮(结果 vs 表3):排除表3也有后 = 260个 3. 第三轮(用户重发三份文件后重算):最终 = 255个 4. 第四轮(用户单独替换新表3后验证):结果不变,确认 = 255个 - **最终统计:** - 三表共有:230 - 表1 ∩ 表2:492 - 表1 ∩ 表3:448 - 表2 ∩ 表3:427 - 最终:255个 - **关键技术点:** - .doc 文件使用 catdoc 解析(非 libreoffice/antiword) - .xlsx 文件使用 openpyxl 读取,多 sheet 合并去重 - 过滤了缩写词(CD, DVD, TV, Mr, Mrs, Ms 等) - 处理了复数变体映射(geese→goose 等) - 用户 user_id = `58fd6864`(租户级),发送消息时踩坑:ou_xxx 是 open_id 非 user_id - **输出文件:** `/root/.openclaw/workspace-xiaoyan/output/单词对比结果_最终版.x",
|
||||
"recallCount": 1,
|
||||
"recallCount": 3,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 1,
|
||||
"totalScore": 3,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-05-25T09:34:43.114Z",
|
||||
"lastRecalledAt": "2026-05-25T09:34:43.114Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"4baebc80709c"
|
||||
"4baebc80709c",
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-05-25"
|
||||
"2026-05-25",
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"lv2-单词",
|
||||
@ -3322,24 +3325,27 @@
|
||||
"endLine": 187,
|
||||
"source": "memory",
|
||||
"snippet": "- **五大分类:** 📖阅读(2) / 🎧听力(3) / 🗣口语(4) / ✏️写作(5) / 未完成(1) - **通用字段提取:** ID/dataStatus/kpStatus/kpInfo/taskData 是所有题型共用的基础结构 #### 覆盖率 - 14 种题型已录入 ✅(1 种无数据:口语探讨) - 4 个一级板块:通用结构 / 题型专区 / 审校规则 / 扩展指南 - 每个题型:cType + bitable 定位 + JSON 字段表 + 结构特点 + 与同类题型的差异说明 #### 发现 - 写作互动和邮件组句 cType 相同(`core_writing_questionMakeSentence`),通过 textInfo 区分素材 - 口语快答/妙问 JSON 结构几乎相同,差异在 prompt 配置和对话样例内容 - 合作阅读和合作听力的核心差异:`textData.text[]` ↔ `textData.audio[]` - meaning 标签(合作阅读)为开放型自由文本,非受控词表 #### 产出文件 - `business_production/_shared/bitable-reader/SKILL.md` — 通用 bitable 读取技能(164行) - `business_knowledge/skills/core-content-json-standard/SKILL.md` — 全题型 JSON 标准 v2.0(393行) - `scripts/audit_core_reading_S0.py` — 合作阅读 S0",
|
||||
"recallCount": 6,
|
||||
"recallCount": 8,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 6,
|
||||
"totalScore": 8,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-06-09T08:37:12.232Z",
|
||||
"lastRecalledAt": "2026-06-10T03:52:28.181Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"91bf4d50e5a2",
|
||||
"b8853a0aafcc",
|
||||
"113e8be33943",
|
||||
"9573fdf60768",
|
||||
"70a3284bc0c5",
|
||||
"78420d02cc4d"
|
||||
"78420d02cc4d",
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-06-09",
|
||||
"2026-06-10"
|
||||
"2026-06-10",
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"口语快答/妙问",
|
||||
@ -3359,23 +3365,26 @@
|
||||
"endLine": 236,
|
||||
"source": "memory",
|
||||
"snippet": "- **产出 Skill 2:** `business_knowledge/skills/core-content-json-standard/SKILL.md` v2.0 — 全题型 JSON 标准(393行) - **架构:** 通用字段在前(ID/kpInfo/taskData)+ 5大题型分类(📖阅读2 🎧听力3 🗣口语4 ✏️写作5)+ 审校规则 + 扩展指南 - **覆盖率:** 14/15 种题型(口语探讨 S0 无数据) - **产出脚本:** `scripts/audit_core_reading_S0.py` — 合作阅读 S0 审校 ## 经验教训 ### bitable 写入需严格流程管控(2026-05-12) - 批量更新 JSON:写入前完整提取 → 写入后逐字段 diff → 异常立即回滚 - 首次修复多题 JSON 导致 Q2 丢失 → 先单条试跑验证再批量 ### sentenceMeaningMeaning 引号规范(2026-05-12) - explanation 中 ASCII `\"` 与中文引号混用导致 JSON 解析失败 - 建议:生产侧统一用中文引号 `\"\"`(U+201C/D),或写入前做引号归一化 ### 写作互动 / 邮件组句 cType 相同(2026-05-12) - 两者 cType 均为 `core_writing_questionMakeSentence`,通过 textInfo.textList[].type 区分素材 ### 刘彦江 — 中互动全题型录入(18:00 ~ 18:25) ###",
|
||||
"recallCount": 5,
|
||||
"recallCount": 7,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 5,
|
||||
"totalScore": 7,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-06-09T08:37:12.232Z",
|
||||
"lastRecalledAt": "2026-06-10T03:52:28.181Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"91bf4d50e5a2",
|
||||
"b8853a0aafcc",
|
||||
"9573fdf60768",
|
||||
"70a3284bc0c5",
|
||||
"78420d02cc4d"
|
||||
"78420d02cc4d",
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-06-09",
|
||||
"2026-06-10"
|
||||
"2026-06-10",
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"v2.0",
|
||||
@ -3395,24 +3404,27 @@
|
||||
"endLine": 254,
|
||||
"source": "memory",
|
||||
"snippet": "#### 发现 - **中互动结构高度统一:** 全部 27 类都用 `jsonData`(主配置)+ `kpInfo`(知识点绑定),没有核心互动那种多字段分散结构 - **6 大分类:** 🗨对话(7) / 📋信息(6) / 📦词汇(2) / 🖼图片选择(4) / 📝语法(3) / 🔧其他(5) - **对话类公共字段:** cType, cId, title, resourceMapping, preDialog, imgShowTimingList - 写作互动和邮件组句 cType 相同(`core_writing_questionMakeSentence`) #### 产出文件 - `skills/interactive-component-json/references/json_structure_guide.md` — 27 种中互动 jsonData 字段结构(8736 bytes) - `skills/interactive-component-json/references/component_registry.md` — 核心互动部分从🔲更新为完整注册表(含 cType+bitable_token) - 与 `business_knowledge/skills/core-content-json-standard/SKILL.md` 双向关联 #### 覆盖率 - 核心互动:15/15 ✅(口语探讨 S0 无数据已标注) - 中互动:27/27 ✅ - 关联文件:3 个(core-content-json-standard + com",
|
||||
"recallCount": 6,
|
||||
"recallCount": 8,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 6,
|
||||
"totalScore": 8,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-06-09T08:37:12.232Z",
|
||||
"lastRecalledAt": "2026-06-10T03:52:28.181Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"91bf4d50e5a2",
|
||||
"b8853a0aafcc",
|
||||
"9573fdf60768",
|
||||
"70a3284bc0c5",
|
||||
"0924e1755b1c",
|
||||
"78420d02cc4d"
|
||||
"78420d02cc4d",
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-06-09",
|
||||
"2026-06-10"
|
||||
"2026-06-10",
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"bitable-token",
|
||||
@ -3740,6 +3752,70 @@
|
||||
"图片",
|
||||
"时机"
|
||||
]
|
||||
},
|
||||
"memory:memory/2026-05-12.md:181:203": {
|
||||
"key": "memory:memory/2026-05-12.md:181:203",
|
||||
"path": "memory/2026-05-12.md",
|
||||
"startLine": 181,
|
||||
"endLine": 203,
|
||||
"source": "memory",
|
||||
"snippet": "- `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` - **技能更新:** 图片描述规范写入 `business_production/单元挑战/skills/unit_challenge/questions/reading/reading_info_match/SKILL.md` ### 刘彦江 — L1 配置表审校 + 技能沉淀(11:50 ~ 12:10) - **数据源:** `Nq3Zb258aae7SRs2QfXcqsQYnxJ` / `tblTxGpf6GQ5c7DZ` - **ID 编码:** 7位 = S(2位) + U(2位) + 序列号(3位) - **技能沉淀:** `scripts/audit_l1_config.py` + `business_production/_shared/audit_l1_config/SKILL.md` ### 刘彦江 — 1213001-1216010 批量审校 40 条(12:10 ~ 14:00) -",
|
||||
"recallCount": 2,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 2,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-06-11T10:31:34.088Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"scripts/audit-core-reading-s0.py",
|
||||
"021301-021801",
|
||||
"scripts/audit-l1-config.py",
|
||||
"business-production",
|
||||
"shared/audit-l1-config/skill.md",
|
||||
"1213001-1216010",
|
||||
"scripts",
|
||||
"audit-core-reading-s0"
|
||||
]
|
||||
},
|
||||
"memory:memory/2026-05-12.md:199:216": {
|
||||
"key": "memory:memory/2026-05-12.md:199:216",
|
||||
"path": "memory/2026-05-12.md",
|
||||
"startLine": 199,
|
||||
"endLine": 216,
|
||||
"source": "memory",
|
||||
"snippet": "- **脚本修复(过程中):** sort 大小写误报 / ID 末尾空格 / 朗读跟读题误报 - **结果:** 系统性 classificationInfo 互换(已标记不视为错误) + 17条具体错误 + 23条通过 - **脚本:** `scripts/audit_l1_config.py` + `scripts/audit_batch_1213001_1216010.py` ### 刘彦江 — 审校结果修正 + JSON 修复(14:00 ~ 15:38) - **YLE↔A1 误报排除:** 确认等级互通,40条审校结果已更新 - **解析与题目一致性检查:** ✅ 0条不对应 - **10 条 sentenceMeaningMeaning JSON 修复:** - 根因:explanation 中 ASCII `\"` 被用作中文引号 - 修复策略演变:状态机拆分失败 → 正则重建 → 发现Q2丢失 → 从中文列完整重建 - 最终:10/10 可正确解析,审校结果同步更新 - 受影响:1213004/1213006/1213010/1214008/1215005/1216001/1216004/1216007/1216008/1216010 ### 刘彦江 — 核心互动全题型 JSON 配置标准沉淀(17:05 ~ 17:50) - **产出 Skill 1:** `business_production/_shared/bitable-reader/SKILL.md` — 通用 bitable 读取(任何 bitable 通用) - **产出",
|
||||
"recallCount": 2,
|
||||
"dailyCount": 0,
|
||||
"groundedCount": 0,
|
||||
"totalScore": 2,
|
||||
"maxScore": 1,
|
||||
"firstRecalledAt": "2026-06-11T10:31:34.088Z",
|
||||
"lastRecalledAt": "2026-06-11T10:31:50.633Z",
|
||||
"queryHashes": [
|
||||
"c538777b9257",
|
||||
"6bf54cd79bb2"
|
||||
],
|
||||
"recallDays": [
|
||||
"2026-06-11"
|
||||
],
|
||||
"conceptTags": [
|
||||
"scripts/audit-l1-config.py",
|
||||
"10/10",
|
||||
"business-production",
|
||||
"shared/bitable-reader/skill.md",
|
||||
"脚本",
|
||||
"修复",
|
||||
"过程",
|
||||
"sort"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1145
memory/2026-06-11-1133.md
Normal file
1145
memory/2026-06-11-1133.md
Normal file
File diff suppressed because it is too large
Load Diff
34
memory/2026-06-11-1226.md
Normal file
34
memory/2026-06-11-1226.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Session: 2026-06-11 12:26:54 GMT+8
|
||||
|
||||
- **Session Key**: agent:xiaoyan:feishu:direct:ou_8b79b7f711e42a4004f3f3c225a1a99c
|
||||
- **Session ID**: 7135746c-57dd-4683-913d-2fd79100bdb9
|
||||
- **Source**: feishu
|
||||
|
||||
## Conversation Summary
|
||||
|
||||
user: https://makee-interactive.feishu.cn/wiki/O7RwwMei6iQCFlk6cHocDqGpn9b 组件配置
|
||||
assistant: 张昆鹏,开始处理组件配置。
|
||||
|
||||
|
||||
assistant: 📝 组件配置完成!**L1-S2-U21-L2 运输小队**,16/16 全部成功:
|
||||
|
||||
| # | cId | 类型 | cType |
|
||||
|---|------|------|-------|
|
||||
| 1 | 1221201 | 对话朗读 | mid_dialog_repeat |
|
||||
| 2 | 1221202 | 图片单选 | mid_image_choose |
|
||||
| 3 | 1221203 | 对话挖空 | mid_dialog_fillin |
|
||||
| 4 | 1221204 | 对话朗读 | mid_dialog_repeat |
|
||||
| 5 | 1221205 | 对话朗读 | mid_dialog_repeat |
|
||||
| 6 | 1221206 | 图片单选 | mid_image_choose |
|
||||
| 7 | 1221207 | 对话朗读 | mid_dialog_repeat |
|
||||
| 8 | 1221208 | 图片单选 | mid_image_choose |
|
||||
| 9 | 1221209 | 对话朗读 | mid_dialog_repeat |
|
||||
| 10 | 1221210 | 对话朗读 | mid_dialog_repeat |
|
||||
| 11 | 1221211 | 对话挖空 | mid_dialog_fillin |
|
||||
| 12 | 1221212 | 对话选读 | mid_dialog_select |
|
||||
| 13 | 1221213 | 看图拼词 | core_writing_imgMakeWord |
|
||||
| 14 | 1221214 | 对话挖空 | mid_dialog_fillin |
|
||||
| 15 | 1221215 | 图片拖拽 | mid_image_drag |
|
||||
| 16 | 1221216 | 对话表达 | mid_dialog_express |
|
||||
|
||||
HTML 报告已通过飞书 Bot 发送给你,打开后可查看详情并一键推送配置到远程数据库。
|
||||
Loading…
Reference in New Issue
Block a user