auto backup: 2026-05-26 08:10:02

This commit is contained in:
ai_member_only 2026-05-26 08:10:02 +08:00
parent b725c13e10
commit 11df2f9642
52 changed files with 36212 additions and 101 deletions

View File

@ -167,6 +167,14 @@ Skills 提供你的工具。当你需要某个工具时,查看它的 `SKILL.md
2.通用级别的skills: 2.通用级别的skills:
/root/.openclaw/skills /root/.openclaw/skills
### 业务生产技能
以下技能位于 `business_production/` 目录下,收到对应触发词时直接查阅其 `SKILL.md`
| 触发词 | SKILL.md 路径 |
|--------|--------------|
| `组件配置-json` | `business_production/组件配置/interactive-component-json/SKILL.md` |
## 飞书使用规范 ## 飞书使用规范
### 身份确认(强制执行) ### 身份确认(强制执行)

View File

@ -105,6 +105,10 @@
- **解决方案:** 对于包含嵌套 JSON 的字段(如 jsonData直接用 Python subprocess 调用 curl构造完整 request body避免经过 shell 变量展开 - **解决方案:** 对于包含嵌套 JSON 的字段(如 jsonData直接用 Python subprocess 调用 curl构造完整 request body避免经过 shell 变量展开
- 写入后必须回读验证(不仅是 record_id 校验,还要检查 jsonData 内容的完整性) - 写入后必须回读验证(不仅是 record_id 校验,还要检查 jsonData 内容的完整性)
### 单元挑战知识库总览2026-05-25
- **位置:** `business_production/单元挑战/单元挑战全貌.md`
- **内容:** 业务定位、阶段划分、题型体系、能力标签、生产流程、审校体系、难度映射、快速链接
### 单元挑战互动组件多维表格 App Token2026-05-08 ### 单元挑战互动组件多维表格 App Token2026-05-08
- **App Token:** `CMHSbUUjka3TrUsaxxEc297ongf` - **App Token:** `CMHSbUUjka3TrUsaxxEc297ongf`
- **用途:** 存储所有单元挑战互动组件配置数据 - **用途:** 存储所有单元挑战互动组件配置数据

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
#!/usr/bin/env python3
"""生成能力考察项表格 markdown"""
def row(单项, rowspan, 考察项, 描述):
"""生成一行rowspan=0表示无rowspan"""
if rowspan > 1:
td1 = f' <lark-td rowspan="{rowspan}">\n **{单项}**\n </lark-td>'
else:
td1 = f' <lark-td>\n **{单项}**\n </lark-td>'
return f''' <lark-tr>
{td1}
<lark-td>
**{考察项}**
</lark-td>
<lark-td>
{描述}
</lark-td>
</lark-tr>'''
def build_table(items_by_skill, skill_order):
"""items_by_skill: {技能: [(考察项, 描述)]}"""
rows_md = []
total = 1 # header
for sk in skill_order:
items = items_by_skill.get(sk, [])
if not items:
items = [("", "")]
n = len(items)
total += n
for i, (item, desc) in enumerate(items):
rs = n if i == 0 else 0
rows_md.append(row(sk, rs, item, desc))
header = '''<lark-table rows="{rows}" cols="3" column-widths="100,164,560">
<lark-tr>
<lark-td>
**单项**
</lark-td>
<lark-td>
**考察项**
</lark-td>
<lark-td>
**考察项描述**
</lark-td>
</lark-tr>'''.format(rows=total)
return header + '\n\n' + '\n'.join(rows_md) + '\n</lark-table>'
# ========== L1 ==========
L1_S2 = build_table({
"听力": [
("听力拖拽匹配", "听到场景描述后,将对应人物或物品拖拽到正确目标位置。"),
("图片选图", "听一个完整英文句子,从多幅图片中选出与听到内容一致的选项。"),
("短对话选择", "听一段简短英文对话,根据问题从选项中选择正确答案。"),
],
"口语": [
("日常话题应答", "根据动作、物品、个人信息等日常话题提问,用完整短句做出恰当应答。"),
("话题讨论", "就一个简单话题,用多个句子表达个人观点并做简单扩展。"),
],
"阅读": [
("信息匹配", "阅读多个简短英文文本,将文本中的关键信息与对应选项正确匹配。"),
],
"写作": [
("看图书面回答", "观察图片和英文提示,用单词或短语写出书面回答。"),
("邮件回复", "阅读一封简短英文邮件,根据写作要求完成邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S3 = build_table({
"听力": [
("短对话选择", "听简短英文对话,根据题目从选项中选择正确答案。"),
("表格填空", "听到信息后,将数字、时间、地点等细节填入表格对应位置。"),
],
"口语": [
("日常话题应答", "根据日常话题提问(喜好、经历、计划等),用多句做出完整应答。"),
("话题讨论", "就一个熟悉话题,用多个句子表达观点并给出简短理由。"),
],
"阅读": [
("信息匹配", "阅读多个简短文本,提取关键信息并与对应选项匹配。"),
("段落匹配", "将短文段落与对应主题或标题进行匹配,测试段落主旨理解。"),
],
"写作": [
("邮件回复", "阅读一封英文邮件,根据写作提示组织语句完成邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S4 = build_table({
"听力": [
("短对话选择", "听日常场景的简短对话,根据问题从选项中选出正确答案。"),
("表格填空", "听到对话或独白后,提取数字、时间、地点等信息填入表格。"),
("信息匹配", "听一段多人对话,将不同人物与其对应信息准确匹配。"),
],
"口语": [
("日常话题应答", "就个人经历、偏好等话题,用连贯的多句做出完整回答。"),
("话题讨论", "就一个话题表达个人观点,用理由支撑并做简单扩展。"),
],
"阅读": [
("信息匹配", "在多个短文本间快速扫读定位关键信息,完成与选项的对应匹配。"),
("长文选择", "阅读一段较长英文文章,根据内容从选项中选择正确答案。"),
("完形填空", "阅读一篇有空缺的短文,从选项中选择正确单词填入空白处。"),
("开放填空", "阅读一篇短文,根据上下文在空白处直接写出正确的单词。"),
],
"写作": [
("邮件回复", "阅读一封英文邮件,根据提示组织语句完成一封完整的邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S5 = build_table({
"听力": [
("短对话选择", "听多轮短对话,根据主题和细节从选项中选择正确答案。"),
("表格填空", "听到独白或对话后,提取并记录多个信息字段到表格中。"),
("信息匹配", "听一段包含多人信息的对话,将说话者与其观点、行为匹配。"),
],
"口语": [
("日常话题应答", "就日常生活、学习和活动话题,用连贯完整句做出自然应答。"),
("话题讨论", "就一个话题进行多句讨论,表达观点、理由并适当回应追问。"),
],
"阅读": [
("信息匹配", "快速扫读多个短文本,将关键信息与对应选项精准匹配。"),
("段落匹配", "将短文段落与对应的标题或主题进行匹配。"),
("长文选择", "阅读长篇英文文章,根据内容理解从选项中选择正确答案。"),
("完形填空", "阅读一篇有空缺的短文,根据语法和语境选择正确单词填入。"),
],
"写作": [
("邮件回复", "根据邮件内容提示,完成一封语句连贯、格式规范的邮件回复。"),
("看图写作", "根据三幅连续图片提示,用连贯语句叙述一个完整故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S6 = build_table({
"听力": [
("短对话选择", "听涉及推理、态度的短对话,根据问题从选项中选择正确答案。"),
("表格填空", "听独白或长对话,提取多层次信息并准确填入表格对应字段。"),
("信息匹配", "听多段短对话,将不同对话者与对应信息、偏好完成匹配。"),
],
"口语": [
("话题讨论", "就一个话题进行深入讨论,表达观点并给出清晰的理由支撑。"),
("看图回答", "观察图片内容,听懂提问后用完整句描述图中信息并表达看法。"),
],
"阅读": [
("信息匹配", "快速扫读多个文本,精准定位关键信息并完成对应匹配。"),
("段落匹配", "将段落与对应主旨标题进行匹配,测试段落大意的概括能力。"),
("长文选择", "阅读长篇英文文章,根据深层内容理解从选项中选择正确答案。"),
("完形填空", "阅读一篇有多个空缺的短文,根据语法和语义选择正确单词填入。"),
("开放填空", "在语境中直接写出正确的单词,测试词汇拼写和语法掌握。"),
],
"写作": [
("邮件回复", "根据邮件内容和写作要求,完成一封语句流畅、格式规范的邮件。"),
("看图写作", "根据系列图片提示,用连贯多句话叙述一个逻辑完整的短故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
# ========== L2 ==========
L2_S1 = build_table({
"听力": [
("图片选图", "听英文句子或短对话,从多幅图片中选出与听到内容一致的选项。"),
("听力拖拽匹配", "听到描述或指令后,将对应元素拖拽到正确目标位置完成匹配。"),
],
"口语": [
("日常话题应答", "根据个人信息、喜好、经历等日常话题提问,用完整句做出应答。"),
("看图识物", "观察图片中的物品、人物或动物,听懂提问后口头说出对应的名称。"),
],
"阅读": [
("", ""),
],
"写作": [
("", ""),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S2 = build_table({
"听力": [
("听力拖拽匹配", "听到多人描述后,将不同人物或物品拖拽到对应位置完成匹配。"),
("图片选图", "听一段描述或对话,从多幅图片中选出与内容一致的选项。"),
],
"口语": [
("日常话题应答", "就日常话题做出完整应答,用多句表达个人信息和观点。"),
("看图回答", "观察图片内容,听懂提问后用完整句描述图中的人、物和场景。"),
],
"阅读": [
("", ""),
],
"写作": [
("", ""),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S3 = build_table({
"听力": [
("图片选图", "听涉及推理、偏好判断的英文句子,从图片选项中选出正确匹配。"),
],
"口语": [
("日常话题应答", "就个人信息、经历和观点等话题,用连贯语句做出完整应答。"),
("看图回答", "观察图片场景,听懂提问后用完整句描述图中内容和关键信息。"),
],
"阅读": [
("看图判断", "阅读简短英文句子,观察对应图片,判断句义与图片内容是否一致。"),
],
"写作": [
("邮件回复", "阅读一封英文邮件,根据写作提示组织语句完成一封简短的邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S4 = build_table({
"听力": [
("长对话选择", "听一段多轮英文对话,根据问题从选项中选择正确答案。"),
("表格填空", "听独白或对话后,提取关键信息并填入表格对应位置。"),
],
"口语": [
("日常话题应答", "就日常话题做出多句连贯应答,表达清晰的观点和理由。"),
("话题讨论", "就一个给定话题,用多句表达个人看法并做适当扩展讨论。"),
],
"阅读": [
("信息匹配", "在多个短文本间快速扫读定位关键信息,完成与选项的对应匹配。"),
("看图判断", "阅读英文句子并观察图片,判断句义与图片内容是否一致。"),
],
"写作": [
("邮件回复", "根据邮件内容提示,完成一封语句连贯、内容完整的邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S5 = build_table({
"听力": [
("长对话选择", "听涉及态度、情绪的多轮英文对话,根据深层理解选择正确答案。"),
("表格填空", "听独白类材料,在连贯叙述中定位并准确记录多个结构化信息字段。"),
],
"口语": [
("话题讨论", "就一个话题展开讨论,表达观点并给出充分的理由和例证。"),
("看图回答", "观察图片提示,听懂提问后用连贯语句描述场景并表达看法。"),
],
"阅读": [
("信息匹配", "在多个文本间扫读定位关键信息,完成与对应选项的精准匹配。"),
("长文选择", "阅读较长英文文章,根据内容理解和推理从选项中选择正确答案。"),
("完形填空", "阅读一篇有多个空缺的文章,根据语法和语境选择正确单词填入。"),
],
"写作": [
("邮件回复", "根据邮件内容完成一封语句流畅、格式规范、内容完整的邮件。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S6 = build_table({
"听力": [
("长对话选择", "听涉及推理判断、态度识别的长对话,根据深层理解选择正确答案。"),
("表格填空", "听独白材料,提取并记录多个维度的结构化信息到表格中。"),
("信息匹配", "听多段短对话,将不同说话者的信息、观点和态度准确匹配。"),
],
"口语": [
("话题讨论", "就一个话题进行深入讨论,表达清晰观点并用逻辑理由支撑。"),
("看图回答", "观察图片场景,听懂提问后用完整连贯语句描述并分析图中信息。"),
],
"阅读": [
("信息匹配", "扫读多个文本,快速定位关键信息并完成与选项的对应匹配。"),
("长文选择", "阅读长篇英文文章,根据深层理解和推理判断选择正确答案。"),
("完形填空", "在长文完形填空中,根据语法规则和语义逻辑选出正确单词。"),
("开放填空", "在语境中根据上下文直接写出正确的单词,测试语法和拼写。"),
],
"写作": [
("邮件回复", "根据邮件内容和写作要求,完成一封语句流畅、要点完整的邮件。"),
("看图写作", "根据系列图片提示,用连贯多句叙述一个逻辑完整的故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S7 = build_table({
"听力": [
("长对话选择", "在短对话、长对话和独白等不同题型间自如切换,听力速度和精度同步提升。"),
("表格填空", "在多种听力材料中提取并准确记录多层次结构化信息。"),
("信息匹配", "听多段不同类型对话,综合判断并将信息与对应选项完成准确匹配。"),
],
"口语": [
("话题讨论", "就一个话题展开深入讨论,用清晰、连贯、得体的语句进行多轮表达。"),
("看图回答", "观察图片并回答提问,用完整语句描述场景、分析信息并表达观点。"),
],
"阅读": [
("信息匹配", "在多个文本间快速扫读并精准定位关键信息完成匹配。"),
("长文选择", "阅读长篇文章,根据深层理解、推理和主旨概括选择正确答案。"),
("完形填空", "在长文中根据语法和语义综合判断,选出正确的单词填入空白。"),
("开放填空", "根据上下文语境和语法规则,直接写出正确单词完成语篇补全。"),
("看图判断", "阅读英文句子并对照图片,判断句图一致性。"),
],
"写作": [
("邮件回复", "完成一封语句流畅、格式规范、内容完整的高质量邮件回复。"),
("看图写作", "根据系列图片提示,用连贯多句叙述一个结构完整的故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S8 = build_table({
"听力": [
("长对话选择", "KET听力全题型综合运用覆盖短对话选图、长对话选择和信息匹配。"),
("表格填空", "独白填表题的冲刺训练,确保信息提取的准确性和完整性。"),
("信息匹配", "多段短对话并行匹配和长对话信息匹配的综合冲刺训练。"),
],
"口语": [
("话题讨论", "KET口语两大题型模拟冲刺——个人信息问答和协作任务讨论。"),
("看图回答", "在真实考试场景中用清晰、连贯、得体的口语完成全部任务。"),
],
"阅读": [
("信息匹配", "KET五大阅读题型全覆盖——标识理解和信息匹配的综合运用。"),
("长文选择", "长文阅读的冲刺训练,覆盖细节理解、推理判断和主旨概括。"),
("完形填空", "完形填空的全面复盘,语法和语义判断能力综合提升。"),
("开放填空", "开放填空的冲刺训练,词汇拼写和语法规则的全面巩固。"),
("看图判断", "句图一致性判断的持续练习,巩固阅读基础技能。"),
],
"写作": [
("邮件回复", "短消息写作的全面复盘,含格式规范、衔接连贯和语法准确度。"),
("看图写作", "看图写故事的冲刺训练,含叙事组织、词汇丰富度和时态一致性。"),
],
}, ["听力", "口语", "阅读", "写作"])
# Build full markdown
stages = [
("L1", "阶段1", [], None), # already in doc
("L1", "阶段2U9-U16 · Starters基础", L1_S2, None),
("L1", "阶段3U17-U24 · Starters达标", L1_S3, None),
("L1", "阶段4U25-U32 · Movers入门", L1_S4, None),
("L1", "阶段5U33-U40 · Movers基础", L1_S5, None),
("L1", "阶段6U41-U48 · Movers达标", L1_S6, None),
("L2", "阶段1U1-U6 · Flyers入门", L2_S1, None),
("L2", "阶段2U7-U12 · Flyers基础", L2_S2, None),
("L2", "阶段3U13-U18 · Flyers达标", L2_S3, None),
("L2", "阶段4U19-U24 · KET入门", L2_S4, None),
("L2", "阶段5U25-U30 · KET基础", L2_S5, None),
("L2", "阶段6U31-U36 · KET强化", L2_S6, None),
("L2", "阶段7U37-U42 · KET高位", L2_S7, None),
("L2", "阶段8U43-U48 · KET达标", L2_S8, None),
]
out = []
current_level = None
for level, stage_name, table, _ in stages:
if level != current_level:
current_level = level
out.append(f'\n## {level} 级别\n')
out.append(f'### {stage_name}\n')
if table:
out.append(table)
print('\n'.join(out))

View File

@ -0,0 +1,353 @@
#!/usr/bin/env python3
"""生成技能点描述风格的能力考察项表格"""
def row(单项, rowspan, 考察项, 描述):
if rowspan > 1:
td1 = f' <lark-td rowspan="{rowspan}">\n **{单项}**\n </lark-td>'
else:
td1 = f' <lark-td>\n **{单项}**\n </lark-td>'
return f''' <lark-tr>
{td1}
<lark-td>
**{考察项}**
</lark-td>
<lark-td>
{描述}
</lark-td>
</lark-tr>'''
def build_table(items_by_skill, skill_order):
rows_md = []
total = 1
for sk in skill_order:
items = items_by_skill.get(sk, [])
if not items:
items = [("", "")]
n = len(items)
total += n
for i, (item, desc) in enumerate(items):
rs = n if i == 0 else 0
rows_md.append(row(sk, rs, item, desc))
header = f'''<lark-table rows="{total}" cols="3" column-widths="100,164,560">
<lark-tr>
<lark-td>
**单项**
</lark-td>
<lark-td>
**考察项**
</lark-td>
<lark-td>
**考察项描述**
</lark-td>
</lark-tr>'''
return header + '\n\n' + '\n'.join(rows_md) + '\n</lark-table>'
# ============== L1 ==============
L1_S1 = build_table({
"听力": [
("基础词汇的语音识别", "听到单词发音后,在图片中找到对应的物品、人物或动物,建立声音与词义的直接连接。"),
("指令理解与动作执行", "听懂含方位介词和颜色词的单步指令,在场景中准确执行与指令匹配的操作。"),
],
"口语": [
("基础个人信息的口语表达", "听懂姓名、年龄、物品名称等基础提问,用单词或简短词组主动做出恰当应答。"),
],
"阅读": [
("图文对应的初步理解", "观察图片并阅读简短英文问句,理解句义后用单词或短语做出回答,建立图与文的对应关系。"),
],
"写作": [
("基础词汇的书面拼写", "观察图片和英文提示,在提示下用单词或短语写出书面回答,完成从看到写的基本闭环。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S2 = build_table({
"听力": [
("完整单句的信息提取", "听懂一个完整英文句子,从多幅图片选项中准确选出与听到内容匹配的选项。"),
("场景语境下的元素匹配", "听到场景描述后,将对应人物或物品与场景位置精准匹配并执行操作。"),
("短对话的关键信息抓取", "听一段简短英文对话,根据提问从选项中找到对应的正确答案。"),
],
"口语": [
("日常话题的短语级应答", "根据动作、物品、个人信息等日常提问,用完整短句做出语法正确的恰当应答。"),
("简单话题的观点组织", "就一个熟悉话题,用多个句子表达个人观点,进行简短的理由说明和内容扩展。"),
],
"阅读": [
("短文本的关键信息扫读", "阅读多个简短英文文本,快速定位文本中的核心信息并与对应选项精准匹配。"),
],
"写作": [
("图片信息的书面转述", "观察图片和英文提示,用单词或短语将图片中的信息转化为书面文字表达。"),
("简短信函的框架性回复", "阅读一封简短英文邮件,根据写作要求独立组织语句完成一封格式完整的回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S3 = build_table({
"听力": [
("短对话中的细节辨析", "听日常场景的简短对话,在多个近似选项中准确分辨并选出与内容一致的答案。"),
("结构化信息的听记同步", "听到对话或独白后,同步提取数字、时间、地点等关键信息并填入表格对应位置。"),
],
"口语": [
("个人经历的连贯叙述", "就个人经历、活动、偏好等话题,用多句连贯的口语表达做出完整自然的应答。"),
("话题观点的理由支撑", "就一个话题用多句表达个人观点,给出简短理由回应追问并做适当扩展。"),
],
"阅读": [
("多文本的信息分类匹配", "在多个简短文本中快速扫读,将提取的关键信息与对应选项进行准确的分类匹配。"),
("段落主旨的提炼概括", "将短文段落与其对应的主题或标题进行匹配,辨识段落核心思想的概括能力。"),
],
"写作": [
("书信场景的语句组织", "阅读一封英文邮件,根据多个写作提示独立组织语句,完成一封要点完整的邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S4 = build_table({
"听力": [
("对话意图与目的判断", "听日常场景的简短对话,推断说话人的目的、偏好或行为意图并选出正确答案。"),
("多维度信息的协同提取", "听对话或独白后,同步定位并记录多个不同维度的关键信息到表格对应字段。"),
("多人对话的信息归属", "听一段包含多个说话人的对话,将不同人物的信息、观点与行为正确归属匹配。"),
],
"口语": [
("个人经历的连贯叙述", "就个人经历与偏好等话题,用连贯的多句做出完整流畅的回答并回应追问。"),
("话题讨论中的观点展开", "就一个话题用多个句子展开讨论,表达明确观点并给出两个以上的理由支撑。"),
],
"阅读": [
("多文本间的信息定位", "在多个短文本中快速扫读并定位关键信息,完成与对应选项的精准匹配。"),
("较长文本的理解判断", "阅读一篇完整英文短文,根据对内容的理解和推理从选项中选择正确的答案。"),
("语境中的词汇选择", "阅读一篇有语篇空缺的短文,根据语法和语义从选项中选择正确的单词填入空白。"),
("语境中的词汇拼写", "阅读一篇含空白的短文,根据上下文和语法规则直接写出正确单词完成语篇补全。"),
],
"写作": [
("书信场景的完整语句组织", "根据邮件中的写作提示,独立组织语句完成一封内容完整、格式规范的邮件回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S5 = build_table({
"听力": [
("多轮对话的信息筛选", "听涉及多话题的短对话,在多条相关信息中准确筛选出正确答案对应的目标信息。"),
("结构化信息的听记同步", "听独白或对话材料,同步定位并记录多个维度的关键信息到表格中。"),
("说话人观点与信息的匹配", "听一段多说话人对话,将不同说话人的观点、偏好和关键信息准确归属匹配。"),
],
"口语": [
("日常生活话题的流畅应答", "就日常生活、学习和活动话题,用连贯完整句自然地做出流畅得体的应答。"),
("话题讨论中的深入展开", "就一个话题展开深入讨论,清晰表达观点并用充分的理由和例证支撑。"),
],
"阅读": [
("多文本的快速扫读定位", "在多篇短文本中快速扫读并精准定位关键信息。"),
("段落大意的提炼匹配", "将短文段落与对应的标题或主题进行匹配,辨识段落核心思想。"),
("较长文本的推理判断", "阅读一篇完整英文文章,根据深层内容的理解和推理选择出正确答案。"),
("语篇中的词汇选择与运用", "根据语法规则和语义逻辑从选项中选择正确单词填入短文空缺处。"),
],
"写作": [
("书信场景的完整语句组织", "独立完成一封语句连贯、内容完整、格式规范的邮件回复。"),
("系列图片的叙事组织", "根据三幅连续图片提示,用连贯多句叙述一个逻辑完整的事件过程。"),
],
}, ["听力", "口语", "阅读", "写作"])
L1_S6 = build_table({
"听力": [
("态度与意图的推理判断", "听涉及推理和态度表达的短对话,根据深层语用含义选出正确答案。"),
("多层次信息的协同提取", "听独白或长对话,同步提取并准确记录多个结构化字段的细节信息。"),
("说话人观点与态度的匹配", "听多段对话或多位说话人,将不同人的观点、态度和信息准确归属匹配。"),
],
"口语": [
("话题讨论的深入展开与论证", "就一个话题展开深入讨论,用清晰连贯的语句进行多轮表达并给出有说服力的论证。"),
("图片信息的口头分析与表达", "观察图片场景,听懂提问后用完整句描述图中信息、比较差异并表达个人看法。"),
],
"阅读": [
("多文本的信息精准定位", "在多个文本中快速扫读并精准定位关键信息完成对应匹配。"),
("较长文本的主旨概括与推理", "阅读长篇英文文章,根据主旨概括、深层推理和态度判断选择正确答案。"),
("语篇中的词义选择与语法运用", "在短文空缺处根据语法规则和语义逻辑选出正确单词。"),
("语篇中的词汇拼写与语法运用", "根据上下文语境和语法规则直接写出正确的单词完成语篇补全。"),
("句图信息的一致性判断", "阅读英文句子并观察对应图片,判断文字描述与图片内容是否一致。"),
],
"写作": [
("书信场景的高质量完整产出", "完成一封语句流畅、内容要点完整、格式规范的高质量邮件回复。"),
("系列图片的完整故事叙事", "根据系列图片提示,用连贯多句叙述一个结构完整、逻辑清晰的故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
# ============== L2 ==============
L2_S1 = build_table({
"听力": [
("词汇的语音与语义连接", "听到单词和短句发音后,在图片选项中准确匹配对应的物品、人物或场景。"),
("场景描述的听辨与匹配", "听到场景描述后,将对应人物、物品或元素精准匹配并完成操作。"),
],
"口语": [
("日常话题的完整句应答", "根据个人信息、喜好、经历等日常提问,用完整句做出语法准确的自然应答。"),
("图片信息的口头识别与命名", "观察图片中的物品、人物或动物,听懂提问后口头准确说出对应的名称和特征。"),
],
"阅读": [
("短句与图片的一致性判断", "阅读简短英文句子并观察对应图片,判断文字描述与图中内容是否一致。"),
],
"写作": [
("图片场景的简短书面描述", "观察图片和英文提示,用单词或短句将图中信息和场景转化为书面表达。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S2 = build_table({
"听力": [
("多人场景的信息匹配", "听到多人描述后,将不同人物、物品与其对应信息和位置准确匹配。"),
("对话中的信息筛选与判断", "听一段简短对话,从多个图片或文字选项中准确选出与内容匹配的答案。"),
],
"口语": [
("人物与场景的口头描述", "观察图片中的人物、动作和场景,用多句完整口语进行连贯的描述表达。"),
("个人喜好与原因的表达", "就个人喜好和经历话题用连贯语句做出完整应答,清晰表达好恶并给出理由。"),
],
"阅读": [
("短文本的定义与词义匹配", "阅读简短英文定义或描述,在选项中找到与之对应的正确词汇或短语。"),
("多文本的信息分类与对应", "在多个简短文本中扫读关键信息,完成不同来源信息的分类与对应匹配。"),
],
"写作": [
("简短信函的自主语句组织", "阅读一封简短英文邮件,根据写作要求独立组织语句完成格式完整的回信。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S3 = build_table({
"听力": [
("话语意图与态度的推理", "听涉及推理判断和偏好表达的英文句子或对话,从选项中选出与内容匹配的答案。"),
],
"口语": [
("个人经历与观点的连贯表达", "就个人信息、经历和观点等话题,用连贯自然的多句做出完整流畅的应答。"),
("图片场景的分析性描述", "观察图片场景中的细节,听懂提问后用完整句描述关键信息并进行简要分析。"),
],
"阅读": [
("句图信息的一致性判断", "阅读英文句子并观察对应图片,判断文字描述与图片内容是否一致。"),
],
"写作": [
("简短信函的独立写作", "阅读一封英文邮件,根据写作提示独立组织多句连贯语句完成一封完整的回复。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S4 = build_table({
"听力": [
("长对话的信息理解与选择", "听一段多轮英文对话,根据对内容和说话人意图的理解从选项中选择正确答案。"),
("独白信息的结构化记录", "听独白类材料,在连贯叙述中准确定位并记录多个关键信息字段到表格中。"),
],
"口语": [
("日常话题的多维应答", "就日常话题做出多句连贯的完整应答,表达清晰的观点并用理由支撑。"),
("给定话题的观点组织与表达", "就一个给定话题,用多句表达个人看法并用充分的理由和例证做扩展讨论。"),
],
"阅读": [
("多文本的信息分类与匹配", "在多个短文本中快速扫读定位关键信息,完成信息的分类与对应匹配。"),
("句图信息的一致性判断", "阅读英文句子并观察对应图片,判断文字描述与图片内容是否一致。"),
],
"写作": [
("书信场景的完整独立写作", "根据邮件内容提示,独立完成一封语句连贯、内容完整、格式规范的邮件。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S5 = build_table({
"听力": [
("长对话的态度与情绪辨识", "听涉及态度和情绪的多轮英文对话,根据对话者的语气和用词辨识其情感倾向。"),
("独白中的多维度信息提取", "听独白材料,在连贯叙述中同步定位并准确记录多个维度的结构化信息。"),
],
"口语": [
("话题讨论的论证与扩展", "就一个话题展开深入讨论,表达清晰的观点并用充分的理由和例证进行论证。"),
("图片信息的描述与观点表达", "观察图片提示,听懂提问后用连贯语句描述场景、分析信息并表达个人看法。"),
],
"阅读": [
("多文本的信息扫读与匹配", "在多个文本中快速扫读并精准定位关键信息完成匹配。"),
("较长文本的理解与推理", "阅读一篇英文文章,根据对内容的理解和推理从选项中选择正确答案。"),
("语篇中的词义选择与语法运用", "根据语法规则和语义逻辑从选项中选择正确单词填入短文空缺处。"),
],
"写作": [
("书信的完整独立产出", "根据邮件内容提示,独立完成一封语句流畅、内容完整、格式规范的邮件。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S6 = build_table({
"听力": [
("长对话的深层含义理解", "听涉及推理判断和态度识别的长对话,根据深层语义理解选出正确答案。"),
("听力材料的多维结构化记录", "听独白材料,同步提取并准确记录多个维度的结构化信息到表格中。"),
("多说话人的观点与态度匹配", "听多段含多位说话人的对话,将不同人的观点、态度和信息准确归属匹配。"),
],
"口语": [
("话题讨论的深入论证", "就一个话题展开深入讨论,用清晰连贯的语句表达观点并做出有说服力的论证。"),
("图片场景的综合口头表达", "观察图片场景,听懂提问后用完整连贯语句描述、比较、分析和表达个人见解。"),
],
"阅读": [
("多文本的信息精准定位与匹配", "扫读多个文本,快速精准定位关键信息并完成对应匹配。"),
("长文本的主旨概括与推理判断", "阅读长篇英文文章,根据深层理解、主旨概括和推理判断选择正确答案。"),
("语篇中的词义与语法综合运用", "在短文空缺处根据语法规则和语义逻辑选出正确单词。"),
("语篇中的词汇拼写与语法综合运用", "根据上下文语境和语法规则,直接写出正确单词完成语篇补全。"),
],
"写作": [
("书信的高质量完整写作", "独立完成一封语句流畅、要点完整、格式规范的高质量邮件回复。"),
("系列图片的完整故事写作", "根据系列图片提示,用连贯多句叙述一个结构完整、逻辑清晰的故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S7 = build_table({
"听力": [
("KET听力全题型的综合运用", "在短对话选图、长对话选择和信息匹配等不同听力题型间自如切换,速度和精度同步提升。"),
("多来源信息的结构化提取", "在多种听力材料中提取并准确记录多个结构化信息字段。"),
("多段对话的观点与信息综合", "听多段不同类型对话,综合判断并将信息与对应选项完成准确匹配。"),
],
"口语": [
("话题讨论的深度论证与互动", "就一个话题展开深入讨论,用清晰、连贯、得体的语句进行流畅的多轮表达。"),
("图片场景的多维度口头表达", "观察图片并回答提问,用完整语句描述场景、比较异同、分析信息并表达观点。"),
],
"阅读": [
("多文本的精准扫读与匹配", "在多个文本中快速扫读并精准定位关键信息完成对应匹配。"),
("长文本的综合理解与判断", "阅读长篇文章,根据深层理解、推理判断和主旨概括选择正确答案。"),
("语篇中的词汇与语法综合运用", "在长文体裁中,根据语法规则、语义逻辑和篇章结构选出正确单词填入。"),
("语篇中的自主拼写与语法运用", "根据上下文语境和语法规则,直接写出正确单词完成语篇补全。"),
("句图一致性的综合判断", "阅读英文句子并对照图片,判断句义与图中的内容是否匹配。"),
],
"写作": [
("高质量书信的独立产出", "独立完成一封语句流畅、格式规范、内容全面的高质量邮件回复。"),
("系列图片的完整叙事写作", "根据系列图片提示,用连贯多句叙述一个结构完整、逻辑清晰的故事。"),
],
}, ["听力", "口语", "阅读", "写作"])
L2_S8 = build_table({
"听力": [
("KET听力全题型冲刺", "KET听力全部题型的综合冲刺训练覆盖短对话选图、长对话理解和信息匹配。"),
("独白信息的精准化提取", "独白填表题的冲刺训练,确保信息提取的准确性、完整性和速度同步达标。"),
("多来源对话的信息综合", "多段短对话和长对话信息的综合匹配与归属冲刺训练。"),
],
"口语": [
("KET口语全场景模拟冲刺", "KET口语两大核心任务冲刺——个人信息问答的精准流畅和协作任务讨论的准确得体。"),
("真实考试场景的综合口语输出", "在真实考试场景中用清晰、连贯、得体的口语完成全部任务并达到考试标准。"),
],
"阅读": [
("KET五大阅读题型的全量覆盖", "标识理解、信息匹配、长文选择、完形填空和开放填空五大题型的综合冲刺。"),
("长文本的深度理解与推理", "长文阅读的冲刺训练,覆盖细节理解、推理判断、主旨概括和态度分析。"),
("语篇完形的全面复盘", "完形填空的全面复盘与冲刺,语法规则和语义判断能力的综合提升。"),
("开放填空的精准拼写", "开放填空的冲刺训练,词汇拼写和语法规则的全面巩固与精准化。"),
("句图一致性的稳定输出", "句图一致性判断的持续练习,巩固阅读理解的基础技能。"),
],
"写作": [
("短消息写作的全量复盘", "短消息写作的全面复盘,含格式规范、内容衔接连贯和语法准确度的综合巩固。"),
("看图写故事的完整叙事冲刺", "看图写故事的冲刺训练,含叙事组织逻辑、词汇丰富度和时态一致性的全面达标。"),
],
}, ["听力", "口语", "阅读", "写作"])
# ========= Build output =========
stages = [
("L1", "阶段1U1-U8 · Starters入门", L1_S1),
("L1", "阶段2U9-U16 · Starters基础", L1_S2),
("L1", "阶段3U17-U24 · Starters达标", L1_S3),
("L1", "阶段4U25-U32 · Movers入门", L1_S4),
("L1", "阶段5U33-U40 · Movers基础", L1_S5),
("L1", "阶段6U41-U48 · Movers达标", L1_S6),
("L2", "阶段1U1-U6 · Flyers入门", L2_S1),
("L2", "阶段2U7-U12 · Flyers基础", L2_S2),
("L2", "阶段3U13-U18 · Flyers达标", L2_S3),
("L2", "阶段4U19-U24 · KET入门", L2_S4),
("L2", "阶段5U25-U30 · KET基础", L2_S5),
("L2", "阶段6U31-U36 · KET强化", L2_S6),
("L2", "阶段7U37-U42 · KET高位", L2_S7),
("L2", "阶段8U43-U48 · KET达标", L2_S8),
]
out = []
current_level = None
for level, stage_name, table in stages:
if level != current_level:
current_level = level
out.append(f'\n## {level} 级别\n')
out.append(f'### {stage_name}\n')
out.append(table)
print('\n'.join(out))

View File

@ -0,0 +1,364 @@
# 单元挑战 全貌梳理
> 基于生产数据、教研规则、审校经验整理 | 2026-05-25
---
## 一、业务定位与逻辑
### 产品定位
Vala 是一款按 KET 考试要求设计的产品,让孩子通过一年的学习**以提升能力的方式通过 KET**,而非考试技巧训练。
- **Unit 是效果交付的基本单位**
- 单元挑战在 Lesson 内与 KET 考试**题型一致**,追求考试对标
- Lesson 内题型可以不一致,但**考核能力项一致**
### 学习闭环中的位置
```
关卡内Lesson 内)
└─ 每一个互动组件绑定一个知识点,标准化出题
└─ Brainy Insight 分析用户行为,得出知识点掌握情况
关卡外Lesson 外)
├─ 回顾Review→ 基于知识点,基础巩固
├─ 总结Summary→ 讲解模块中知识点之间的关系
├─ 挑战Challenge→ 模仿 KET 真题样式,智能出题 ← 单元挑战
├─ 错题本 → 收集回顾/总结/挑战中错误的题目
└─ 纠错(常驻)→ 针对性练习和巩固
```
### 核心逻辑
- 题库由知识库决定:知识点 → 回顾题;知识模块 → 总结/挑战题
- 单元挑战根据回顾和总结的**错误情况智能出题**,个性化推送
- 每个题目带知识点标签和知识模块标签
- 挑战后未掌握的知识点进入错题本
### 效果指标
- 单元挑战时间:**20 分钟**(约 1/5 个 KET 考试)
- 互动通过标准5 档内部记录 → 3 档用户可见Perfect / Pass / Oops
- 异常阈值:跟读 >10% Fail → 异常;全部中互动 >1% Fail → 异常
---
## 二、阶段与单元划分
### L1Starters → Movers
| 阶段 | 单元 | 对标 | 听力 | 口语 | 阅读 | 写作 |
|------|------|------|:----:|:----:|:----:|:----:|
| 阶段1 | U1-U8 | Starters入门 | ✅ | ✅ | ✅ | ✅ |
| 阶段2 | U9-U16 | Starters基础 | ✅ | ✅ | ✅ | ✅ |
| 阶段3 | U17-U24 | Starters达标 | ✅ | ✅ | ✅ | ✅ |
| 阶段4 | U25-U32 | Movers入门 | ✅ | ✅ | ✅ | ✅ |
| 阶段5 | U33-U40 | Movers基础 | ✅ | ✅ | ✅ | ✅ |
| 阶段6 | U41-U48 | Movers达标 | ✅ | ✅ | ✅ | ✅ |
- 能力标签对标L1 → CEFR A1/A1+
- 词库L1 词库980词| 句型库L1 句型库490个
### L2Flyers → KET
| 阶段 | 单元 | 对标 | 听力 | 口语 | 阅读 | 写作 |
|------|------|------|:----:|:----:|:----:|:----:|
| 阶段1 | U1-U6 | Flyers入门 | ✅ | ✅ | ✅ | ✅ |
| 阶段2 | U7-U12 | Flyers基础 | ✅ | ✅ | ✅ | ✅ |
| 阶段3 | U13-U18 | Flyers达标 | ✅ | ✅ | ✅ | ✅ |
| 阶段4 | U19-U24 | KET入门 | ✅ | ✅ | ✅ | ✅ |
| 阶段5 | U25-U30 | KET基础 | ✅ | ✅ | ✅ | ✅ |
| 阶段6 | U31-U36 | KET强化 | ✅ | ✅ | ✅ | ✅ |
| 阶段7 | U37-U42 | KET高位 | ✅ | ✅ | ✅ | ✅ |
| 阶段8 | U43-U48 | KET达标 | ✅ | ✅ | ✅ | ✅ |
- 能力标签对标L2 → CEFR A2
- 词库L1 + L2 词库1470词| 句型库L2 句型库380个
> ⚠️ 设计文档(飞书 "L1/L2 阶段分配")的数据不完全准确,实际生产以多维表格为准。
---
## 三、题型体系
### 全题型 × Part 映射
| Part | 听力 | 口语 | 阅读 | 写作 |
|:----:|------|------|------|------|
| P1 | **图片选择题** | **日常回答** | **信息匹配题** | **邮件回复** |
| P2 | **表格填空题** | **话题讨论** | **段落匹配题** | **看图写作** |
| P3 | — | **看图回答** | **长文选择题** | **看图回答题** |
| P4 | **短对话选择题** | **看图识物** | **完形填空题** | — |
| P5 | — | — | **开放填空题** | — |
| P6 | — | — | **看图判断题** | — |
| P7 | **听力拖拽** | — | **看图回答题** | — |
> 来源:多维表格 `CMHSbUUjka3TrUsaxxEc297ongf` 表结构
### 各题型说明
**听力4 种题型)**
| Part | 题型 | 核心能力 | 题量 |
|:----:|------|---------|:----:|
| P1 | 图片选择题 | 听单句/短对话,在图片选项中选出正确匹配 | 5 |
| P2 | 表格填空题 | 听对话/独白,提取信息填表 | 5 |
| P4 | 短对话选择题 | 听2-3轮对话选正确答案 | 5 |
| P7 | 听力拖拽 | 听指令/描述,拖拽元素到正确位置 | 5 |
**口语4 种题型)**
| Part | 题型 | 核心能力 | 题量 |
|:----:|------|---------|:----:|
| P1 | 日常回答 | 就日常话题用单词/短句应答 | 4-5 |
| P2 | 话题讨论 | 就话题用多句表达观点+理由 | 5 |
| P3 | 看图回答 | 看图后用完整句描述/回答 | 5 |
| P4 | 看图识物 | 看图问名称,口头说出答案 | 5 |
**阅读7 种题型)**
| Part | 题型 | 核心能力 | 题量 |
|:----:|------|---------|:----:|
| P1 | 信息匹配题 | 多文本扫读定位关键信息并匹配 | 5 |
| P2 | 段落匹配题 | 段落与标题/主题匹配 | 5 |
| P3 | 长文选择题 | 读长文后选正确答案 | 5 |
| P4 | 完形填空题 | 语境中选词填空 | 5-10 |
| P5 | 开放填空题 | 语境中直接写词 | 5 |
| P6 | 看图判断题 | 看句子+图片,判断句图是否一致 | 5 |
| P7 | 看图回答题 | 看图读问题,用单词/短句回答 | 5 |
**写作3 种题型)**
| Part | 题型 | 核心能力 | 题量 |
|:----:|------|---------|:----:|
| P1 | 邮件回复 | 读英文邮件,组织语句完成回复 | 1 |
| P2 | 看图写作 | 看系列图片,写连贯故事 | 1 |
| P3 | 看图回答题 | 看图+英文提示,用词/短语写出答案 | 5 |
---
## 四、能力标签体系45 个标准标签)
> 来源:`business_knowledge/ability_tags.md`
### 听力11个
| # | L1 标签6个 | L2 标签5个 |
|---|--------------|--------------|
| 1 | 显性事实理解|关键词识别 | 干扰抑制|多信息筛选 |
| 2 | 显性事实理解|单句信息点抓取 | 语用推断|否定与纠错 |
| 3 | 基础语境理解|场景/物品/动作识别 | 多句保持|信息整合 |
| 4 | 显性细节理解|数字/时间/地点 | 情绪/态度理解 |
| 5 | 同义替换识别|词/短语级 | 长对话理解|主旨+细节 |
| 6 | 目的/偏好识别|显性 to/for/like | — |
### 口语10个
| # | L1 标签4个 | L2 标签6个 |
|---|--------------|--------------|
| 1 | 基础信息表达|个人信息问答 | 图片对比|找不同 |
| 2 | 图片描述|人物/物品/动作 | 故事讲述|看图说话 |
| 3 | 图片描述|位置与方位 | 信息交换|双向问答 |
| 4 | 表达喜好与理由 | 过去经历描述Past Activities |
| 5 | — | 互动应答|问答交流 |
| 6 | — | 发音与语调|单词级 |
### 阅读13个
| # | L1 标签8个 | L2 标签5个 |
|---|--------------|--------------|
| 1 | 显性信息定位|关键词识别 | 细节理解|事实信息提取 |
| 2 | 基础语境理解|场景/行为理解 | 词义理解|语境义判断 |
| 3 | 图文判断|句图一致性 | 同义替换|词/短语级 |
| 4 | 扫读定位|信息匹配 | 语法结构识别|完形填空 |
| 5 | 主旨理解|段落/文本大意 | 推理判断|原因/结果 |
| 6 | 释义选词|定义匹配 | — |
| 7 | 对话理解|问答匹配 | — |
| 8 | 标识与通知理解Signs & Notices | — |
### 写作11个
| # | L1 标签5个 | L2 标签6个 |
|---|--------------|--------------|
| 1 | 字母书写|认写英文字母 | 叙述故事|看图写故事 |
| 2 | 单词拼写|看图写词 | 短消息写作|邮件/便条 |
| 3 | 抄写能力|词组/短句 | 衔接与连贯|连词使用 |
| 4 | 简短作答|一词答案 | 描述写作|人物/物体/场景 |
| 5 | 简单句表达|个人信息 | 表格信息填写Form Completion |
| 6 | — | 语法准确度|时态/介词/冠词 |
---
## 五、生产流程
### 5.1 生产数据源
**多维表格:** `CMHSbUUjka3TrUsaxxEc297ongf`(单元挑战互动组件配置)
表结构20 张表):
- 听力-P1~P74张有数据
- 口语-P1~P44张
- 阅读-P1~P77张
- 写作-P1~P33张
每张表的核心字段:
- `题目集合 ID`compound ID如 011001
- `题目1` / `题目2`完整题目配置JSON
- `jsonData`统一JSON结构含 questionSet
- `图片描述`(看图类题型)
- `dataStatus`(生产完成标记)
- `审校结果` / `审核结果`(审校字段,部分表命名不同)
**生产文档:** 飞书知识库「单元挑战旧题目解析待补充 ID 整理」(CS8Ww2XaSiFwhakQenycRU5ZnYf)
- 记录所有已生产 ID 的题型分配、题量、解析状态
### 5.2 ID 命名规则
```
XXYYZZ
││││└── 子题目集编号01/02
││└──── 单元编号(如 01 = U1, 13 = U13
│└───── L1 内阶段编码01/02/03
└────── 级别01=L1, 10=L2 demo, 11=L2, 12=L2
```
示例:
- `010101` = L1, 阶段内首个单元, U1, 题目集1
- `110501` = L2, 阶段内首个单元, U5, 题目集1
- `021601` = L1, 阶段内第二个单元, U16, 题目集1
> ⚠️ L1 的 02xxxx 不是指 L2而是 L1 阶段2+ 的编码延续。实际级别用前缀区分。
### 5.3 难度分级与考试对标
| 难度 | L1 对标 | L1 阶段 | L2 对标 | L2 阶段 | CEFR |
|:----:|---------|---------|---------|---------|:----:|
| A | Starters 入门+基础 | 阶段1-2U1-U16 | Flyers 入门+基础 | 阶段1-2U1-U12 | A1 / A2 |
| B | Starters 达标 | 阶段3U17-U24 | Flyers 达标 | 阶段3U13-U18 | A1 / A2 |
| C | Movers 入门+基础 | 阶段4-5U25-U40 | KET 入门+基础 | 阶段4-5U19-U30 | A1+ / A2 |
| D | Movers 达标 | 阶段6U41-U48 | KET 强化+高位+达标 | 阶段6-8U31-U48 | A1+ / A2 |
### 5.4 语言难度参考依据
- **L1/L2 单词表 + 句型表是语言难度控制的基准依据**,指定了每个级别的词汇和句型上限
- 所有题目(听力文本、阅读文本、口语话题、写作提示)中的词汇和句型,不得超过对应级别的词库和句型库范围
- 超出词库/句型库的内容视为超纲,需替换为同义词库内词或经业务负责人放行
### 5.5 生产标准
**题目生产通用规则:**
1. **词汇限制**L1 题目仅使用 L1 词库980词L2 可用 L1+L2 词库,禁止跨阶段超纲
2. **句型限制**:题目中句型须在对应级别句型库范围内
3. **文本格式**(强制执行):
- 禁止 Markdown 标记(`**` `*` `__` `_` `#` `>` `-` 等),所有文本纯文本输出
- 英式拼写优先colour/center/travelling
- 标点:中文全角(,。!?),英文半角(. , ! ?),禁止混用
4. **答案分布**:选项题(如 P1 图片选择 A/B/C答案均匀分布
5. **题量规范**题组1 和 题组2 题量须一致(通常各 5 题)
6. **知识点标签**:每道题绑定对应知识点,用于智能出题和错题归因
7. **难度分级**A级基础/ B级标准/ C级进阶
**音频文本规范(听力题型):**
- 禁止 Markdown 标记,纯文本输出
- 口语化、低龄友好、节奏感强
- 单句 ≤10 词,知识点相关 ≤7 词
- 英式拼写优先
### 5.6 写入技术规范
**关键陷阱:嵌套 JSON 的 Shell 转义** 🔴
- `operate_bitable.sh` 通过 shell 变量展开传递嵌套 JSON 时,内部双引号被 shell 提前解析 → 数据截断
- **解决方案:** Python subprocess 直调 curl构造完整 request body
- **写入后必须回读验证**JSON 结构完整性 + 字段内容正确性
**ability 格式双轨制**(重要)🔴
- 格式AJSON 数组):`{"questionSet": [{"ability": ["标签1", "标签2"]}]}` — 适用听力P1/P2/P3/P4/P7、阅读全7、口语全4
- 格式B¥¥ 分隔字符串):`{"ability": "标签1¥¥标签2"}` — 适用听力P5、写作P1/P2/P3
- 读写能力标签时必须区分格式,混用会导致数据损坏
---
## 六、审校体系
### 6.1 审校字段
| 表类型 | 审校字段名 | 说明 |
|--------|-----------|------|
| 阅读-P1~P5、写作-P1~P2 | `审校结果` | |
| 阅读-P6~P7、写作-P3 | `审核结果` | 命名不统一,功能相同 |
| 听力全系列、口语全系列 | `审校结果` | |
### 6.2 审校检查清单L1 配置表基准)
**自动化检查7项**
1. ✅ 基础信息完整性ID、阶段、难度、知识点数量完整
2. ✅ 分类字段互换检测(听力/口语/阅读/写作归类正确)
3. ✅ 题型 JSON 结构完整性jsonData 可解析、questionSet 非空)
4. ✅ 单词库-答案一致性(题干中使用知识点词汇与知识点列表一致)
5. ✅ 第三人称单数语法he/she/it + 动词三单形式)
6. ✅ 能力标签合规性(标签在 45 个标准标签内,分级正确)
7. ✅ 题量一致性题组1 和题组2 题量相同)
**人工审核4项**
1. 👁️ 答案分布合理性(选择题选项均匀分布,非某选项集中)
2. 👁️ 图片与文本匹配度(图片描述准确对应题目含义)
3. 👁️ 难度递增逻辑(阶段间题目难度递进合理)
4. 👁️ 价值观审查(无负面评价、歧视性内容)
### 6.3 常见审校问题
| 问题类型 | 表现 | 修复方案 |
|---------|------|---------|
| 能力标签不合规 | 标签不在45个标准内 / 级别不对 | 映射到最近标准标签 |
| 答案分布不均 | 选项集中到某一项 | 调整题面/选项 |
| 题量不一致 | 题组1和题组2题量不同 | 从多的移1-2题到少的 |
| JSON 损坏 | jsonData 不可解析 | 从中文列重建 JSON |
| 超纲词汇 | 使用词库外词汇 | 替换为词库内近义词或标注放行 |
| 标签偏科 | 阅读/口语表用了听力标签 | 更换为对应科目的标签 |
| 审校字段缺失 | 表无审校结果列 | 需先添加列才能写入 |
---
## 七、生产数据覆盖现状
> 来源:生产文档 + 业务确认2026-05-25
### L1 生产进度(已产到 U16
| 阶段 | 单元 | 听力 | 口语 | 阅读 | 写作 |
|------|------|:----:|:----:|:----:|:----:|
| 阶段1 | U1-U8 | P1,P7 | P1 | P7 | P3 |
| 阶段2 | U9-U16 | P7,P1,P4 | P1,P2 | P1 | P3,P1 |
| 阶段3-6 | U17-U48 | ❓未生产 | ❓未生产 | ❓未生产 | ❓未生产 |
### L2 生产进度(已产到 U29
| 阶段 | 单元 | 听力 | 口语 | 阅读 | 写作 |
|------|------|:----:|:----:|:----:|:----:|
| 阶段1 | U1-U6 | ✅ | ✅ | ✅ | ✅ |
| 阶段2 | U7-U12 | ✅ | ✅ | ✅ | ✅ |
| 阶段3 | U13-U18 | ✅ | ✅ | ✅ | ✅ |
| 阶段4 | U19-U24 | ✅ | ✅ | ✅ | ✅ |
| 阶段5 | U25-U29 | ✅ | ✅ | ✅ | ✅ |
| 阶段5-8 | U30-U48 | ❓未生产 | ❓未生产 | ❓未生产 | ❓未生产 |
---
## 八、与其他模块的关系
```
单元挑战 ←→ 词库L1/L2 word lists
←→ 句型库L1/L2 pattern lists
←→ 能力标签体系45 个标准标签)
←→ 知识库(知识点定义)
←→ 阶段分配文档(设计参考)
←→ 能力图谱(能力考察项,用户面向展示)
←→ 互动组件配置(多维表格,技术实现层)
```
---
## 九、备忘:快速链接
| 资源 | 链接/Token |
|------|-----------|
| 互动组件多维表格 | `CMHSbUUjka3TrUsaxxEc297ongf` |
| 生产旧题解析文档 | `CS8Ww2XaSiFwhakQenycRU5ZnYf` |
| 能力图谱文案文档 | `W5Vjw2fLiiCqfck0Mfzc0xkrnte` |
| L1 阶段分配文档 | `Jjd8wghbeidXt2kDFaPcU09wnzc` |
| L2 阶段分配文档 | `D9EFwVC9Gi9nCAk4heec2qYCnwe` |
| L1 词库 | `business_knowledge/L1_word_list.json` (980词) |
| L2 词库 | `business_knowledge/L2_word_list.json` (1470词) |
| L1 句型库 | `business_knowledge/L1_pattern_list.json` (490个) |
| L2 句型库 | `business_knowledge/L2_pattern_list.json` (380个) |
| 能力标签体系 | `business_knowledge/ability_tags.md` (45个标准标签) |

View File

@ -0,0 +1,386 @@
[
{
"type": "对话朗读",
"id": "1219101",
"plot": "【教研图】需要一张能代表afternoon的图",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "afternoon",
"config_info": "",
"sheet_row": 9,
"ctx_before": [
"Dad: Oh, I love this afternoon.",
"Dad: No work, just us.",
"User: Really? You don't have to work today?",
"Dad: Nope!"
],
"ctx_after": [
"User: Are you staying home all afternoon?",
"Dad: Yes, dear.",
"Dad: We can stay in this living room for the whole afternoon."
]
},
{
"type": "对话挖空",
"id": "1219102",
"plot": "",
"char": "User",
"script_cn": "This afternoon, we go to space!",
"script_en": "This afternoon, we go to space!",
"kp": "afternoon",
"config_info": "",
"sheet_row": 19,
"ctx_before": [
"User: Yay!",
"User: Can we read the book about space?",
"Dad: Of course!",
"User: Woohoo!"
],
"ctx_after": [
"Dad: The spaceship is flying fast...",
"Dad: It's getting closer and closer to the glowing star...",
"Dad: Uh-Oh!"
]
},
{
"type": "对话朗读",
"id": "1219103",
"plot": "【教研图】Dad将手中的书翻到下一页但后面的书页被撕毁了只剩下参差不齐的纸边",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "314",
"sheet_row": 27,
"ctx_before": [
"Dad: It's getting closer and closer to the glowing star...",
"Dad: Uh-Oh!",
"User: What? What's wrong with the spaceship?",
"Dad: I can't read anymore. Look at the book."
],
"ctx_after": [
"User: What's wrong with the book?",
"Dad: The book is broken. Some pages are gone!",
"Dad: Sorry, dear. The story is over."
]
},
{
"type": "对话朗读",
"id": "1219104",
"plot": "",
"char": "User",
"script_cn": "Our living room is the space!",
"script_en": "Our living room is the space!",
"kp": "living room",
"config_info": "",
"sheet_row": 43,
"ctx_before": [
"User: How?",
"Dad: Just use your imagination, Captain!",
"User: You're right!"
],
"ctx_after": [
"User: Now, I am the captain.",
"Dad: Yes, Captain!"
]
},
{
"type": "对话挖空",
"id": "1219105",
"plot": "【教研图】选取客厅中的扶手椅armchair",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "armchair",
"config_info": "",
"sheet_row": 50,
"ctx_before": [
"User: Now, I am the captain.",
"Dad: Yes, Captain!",
"Dad: May I sit in this armchair, Captain?",
"User: No."
],
"ctx_after": [
"User: This armchair is my seat!",
"User: You are my helper.",
"User: You stand next to me."
]
},
{
"type": "剧情互动",
"id": "1219106",
"plot": "【插入图】Dad手上拿着智能家居遥控器上面不同颜色的按钮对应着不同的家居设施按钮上有简笔小图标表示\n黄色 = 电视机🖥️\n绿色 = 窗子/窗帘\n蓝色 = 扫地机\n红色 = 台灯💡",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 59,
"ctx_before": [
"User: You stand next to me.",
"Dad: Yes, Captain! What's next?",
"User: Let's start the spaceship!",
"Dad: Okay. I think we should..."
],
"ctx_after": [
"Dad: Press the yellow button!",
"User: Wrong button, helper!",
"Dad: Oh, sorry."
]
},
{
"type": "对话朗读",
"id": "1219107",
"plot": "【教研图】Dad手上拿着智能家居遥控器一个箭头指向绿色的代表窗子的按钮",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 65,
"ctx_before": [
"Dad: Press the yellow button!",
"User: Wrong button, helper!",
"Dad: Oh, sorry."
],
"ctx_after": [
"User: Press the green button, please."
]
},
{
"type": "对话选择",
"id": "1219108",
"plot": "",
"char": "User",
"script_cn": "What's wrong with the spaceship?",
"script_en": "What's wrong with my spaceship?/ What's a spaceship?",
"kp": "What's wrong with the...?",
"config_info": "",
"sheet_row": 75,
"ctx_before": [
"User: Whoa! The spaceship is moving.",
"User: We are flying!",
"User: Why do we stop?"
],
"ctx_after": [
"Dad: Our spaceship is stuck.",
"Dad: There are many space rocks ahead!",
"Dad: What do we do now, Captain?"
]
},
{
"type": "图片单选",
"id": "1219109",
"plot": "【教研图】Dad手上拿着智能家居遥控器一个箭头指向蓝色的代表扫地机的按钮",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 81,
"ctx_before": [
"Dad: Our spaceship is stuck.",
"Dad: There are many space rocks ahead!",
"Dad: What do we do now, Captain?",
"User: We need a cleaner to clear the way!"
],
"ctx_after": [
"User: Press the blue button.",
"User: Good job, cleaner.",
"User: Let's keep going."
]
},
{
"type": "对话挖空",
"id": "1219110",
"plot": "【教研图】Dad推扶手椅动作特写",
"char": "User",
"script_cn": "Push the armchair, Dad!",
"script_en": "Push the armchair, Dad!",
"kp": "armchair",
"config_info": "",
"sheet_row": 86,
"ctx_before": [
"User: Press the blue button.",
"User: Good job, cleaner.",
"User: Let's keep going."
],
"ctx_after": [
"Dad: Okay.",
"Dad: The spaceship is flying fast...",
"Dad: It's getting closer and closer to the glowing star..."
]
},
{
"type": "对话挖空",
"id": "1219111",
"plot": "【教研图】用户手指lamp 特写,脑泡中把台灯当作闪烁的行星",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "lamp",
"config_info": "",
"sheet_row": 97,
"ctx_before": [
"User: We are finally here!",
"User: Look! The star!",
"Dad: Where? I just see a lamp there.",
"User: Use your imagination, Dad."
],
"ctx_after": [
"User: The lamp is the glowing star.",
"Dad: How come I do not see it glowing?",
"User: That's because you haven't woken it up yet."
]
},
{
"type": "图片单选",
"id": "1219112",
"plot": "【教研图】Dad手上拿着智能家居遥控器一个箭头指向红色的代表台灯的按钮",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "lamp",
"config_info": "",
"sheet_row": 101,
"ctx_before": [
"User: Use your imagination, Dad.",
"User: The lamp is the glowing star.",
"Dad: How come I do not see it glowing?",
"User: That's because you haven't woken it up yet."
],
"ctx_after": [
"User: Press the red button.",
"User: Look! The glowing star!",
"Dad: I'll get it."
]
},
{
"type": "场景互动\n0010012",
"id": "",
"plot": "User走过去捡起摔在地上的台灯 lamp",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 109,
"ctx_before": [
"User: Look! The glowing star!",
"Dad: I'll get it.",
"User: Be careful!",
"Dad: Oops!"
],
"ctx_after": [
"User: What's wrong with the lamp?",
"Dad: Hmm... maybe the bulb is loose."
]
},
{
"type": "对话组句",
"id": "1219113",
"plot": "",
"char": "User",
"script_cn": "What's wrong with the lamp?",
"script_en": "What's wrong with the lamp?",
"kp": "What's wrong with the...?",
"config_info": "",
"sheet_row": 112,
"ctx_before": [
"Dad: Oops!"
],
"ctx_after": [
"Dad: Hmm... maybe the bulb is loose.",
"User: I know how to fix it!",
"User: It's working!"
]
},
{
"type": "对话选读",
"id": "1219114",
"plot": "【教研图】User将 lamp 抱在怀中",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 123,
"ctx_before": [
"Dad: Because you are the best Captain in the world!",
"Dad: What's next, Captain?",
"User: We got the star! It is time to go back.",
"User: This time, you drive."
],
"ctx_after": [
"User: I will take care of the lamp.",
"User: You sit in the armchair, Dad."
]
},
{
"type": "对话挖空",
"id": "1219115",
"plot": "【教研图】示意让爸爸坐在 armchair 里",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "",
"config_info": "",
"sheet_row": 125,
"ctx_before": [
"Dad: What's next, Captain?",
"User: We got the star! It is time to go back.",
"User: This time, you drive.",
"User: I will take care of the lamp."
],
"ctx_after": [
"User: You sit in the armchair, Dad.",
"Dad: Captain, we are back! The star is safe.",
"User: Good job, helper."
]
},
{
"type": "听力拖拽",
"id": "1219116",
"plot": "【教研图】三格图片,展示现实与想象的变化:\n客厅 ➡️ 太空\n扶手椅 ➡️ 太空船驾驶舱座位\n台灯 ➡️ 小行星",
"char": "",
"script_cn": "",
"script_en": "",
"kp": "armchair\nlamp\nafternoon\nliving room",
"config_info": "",
"sheet_row": 138,
"ctx_before": [
"User: Mum! We went to space this afternoon!",
"Mum: Space? In our living room? How?",
"User: Come to the living room, Mum.",
"User: I can show you!"
],
"ctx_after": [
"User: Our living room is the space.",
"User: The armchair is the captain's seat.",
"User: The lamp is the glowing star!",
"Mum: I see! You two had a big afternoon."
]
},
{
"type": "对话表达",
"id": "1219117",
"plot": "",
"char": "User",
"script_cn": "This was the best afternoon.",
"script_en": "This is the best afternoon.",
"kp": "afternoon",
"config_info": "",
"sheet_row": 143,
"ctx_before": [
"User: Our living room is the space.",
"User: The armchair is the captain's seat.",
"User: The lamp is the glowing star!",
"Mum: I see! You two had a big afternoon."
],
"ctx_after": [
"Dad: Next time, we fly to the moon.",
"User: Yay!"
]
}
]

View File

@ -0,0 +1,110 @@
[
{
"row": 9,
"id": "1219101",
"type": "对话朗读",
"status": "ok"
},
{
"row": 19,
"id": "1219102",
"type": "对话挖空",
"status": "ok"
},
{
"row": 27,
"id": "1219103",
"type": "对话朗读",
"status": "ok"
},
{
"row": 43,
"id": "1219104",
"type": "对话朗读",
"status": "ok"
},
{
"row": 50,
"id": "1219105",
"type": "对话挖空",
"status": "ok"
},
{
"row": 59,
"id": "1219106",
"type": "剧情互动",
"status": "ok"
},
{
"row": 65,
"id": "1219107",
"type": "对话朗读",
"status": "ok"
},
{
"row": 75,
"id": "1219108",
"type": "对话选择",
"status": "ok"
},
{
"row": 81,
"id": "1219109",
"type": "图片单选",
"status": "ok"
},
{
"row": 86,
"id": "1219110",
"type": "对话挖空",
"status": "ok"
},
{
"row": 97,
"id": "1219111",
"type": "对话挖空",
"status": "ok"
},
{
"row": 101,
"id": "1219112",
"type": "图片单选",
"status": "ok"
},
{
"row": 109,
"id": "",
"type": "场景互动\n0010012",
"status": "ok"
},
{
"row": 112,
"id": "1219113",
"type": "对话组句",
"status": "ok"
},
{
"row": 123,
"id": "1219114",
"type": "对话选读",
"status": "ok"
},
{
"row": 125,
"id": "1219115",
"type": "对话挖空",
"status": "ok"
},
{
"row": 138,
"id": "1219116",
"type": "听力拖拽",
"status": "ok"
},
{
"row": 143,
"id": "1219117",
"type": "对话表达",
"status": "ok"
}
]

View File

@ -0,0 +1,222 @@
#!/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()

View File

@ -0,0 +1,295 @@
#!/usr/bin/env python3
"""
Script-component-production pipeline:
Reads script sheet identifies component rows generates component config (structured text) writes back to column H
"""
import requests, json, time, os, sys
CRED_PATH = "/root/.openclaw/credentials/xiaoyan/config.json"
SHEET_TOKEN = "VgPwsodzthsk9Vti8GocrbH2nEe"
SHEET_ID = "wMQVyV"
OUTPUT_DIR = "/root/.openclaw/workspace-xiaoyan/business_production/组件生产/output"
# LLM config
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_data(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 parse_row(row):
"""Parse a sheet row into structured data"""
while len(row) < 9: row.append(None)
e_text = ""
if isinstance(row[4], list):
e_text = "".join([seg.get("text","") for seg in row[4] if isinstance(seg, dict)])
elif row[4]:
e_text = str(row[4])
f_text = ""
if isinstance(row[5], list):
f_text = "".join([seg.get("text","") for seg in row[5] if isinstance(seg, dict)])
elif row[5]:
f_text = str(row[5])
return {
"index": 0,
"type": str(row[0]).strip() if row[0] else "",
"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": e_text.strip(),
"script_en": f_text.strip(),
"kp": str(row[6]).strip() if row[6] else "",
"config_info": str(row[8]).strip() if row[8] else "",
}
def build_component_rows(values):
"""Extract component rows with context"""
rows = []
for i, row in enumerate(values):
r = parse_row(row)
r["index"] = i
r["sheet_row"] = i + 1 # 1-indexed
rows.append(r)
comp_rows = []
for i, r in enumerate(rows):
t = r["type"]
if t in ("", "TL", "类型"): # Skip header, TL, and empty
continue
# Get context
ctx_before = []
for j in range(max(0, i-5), 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+5)):
if rows[j]["char"] and rows[j]["script_cn"]:
ctx_after.append(f"{rows[j]['char']}: {rows[j]['script_cn']}")
r["ctx_before"] = ctx_before
r["ctx_after"] = ctx_after
comp_rows.append(r)
return comp_rows
SYSTEM_PROMPT = """You are a kids' English education content producer. Generate interactive component configurations for a children's English learning script.
## OUTPUT FORMAT (structured text, NOT JSON)
Use exactly this format:
组件ID{id}
任务标题{short title, 10 chars, no numbers/bullets}
资源配置
图片时机{ or stage name}
音频载体{ or resource}
情境引入
{Character: line, one per line, or if none}
互动内容
{content based on component type}
互动反馈
正确
错误{Character: natural error feedback}
后置对话
{Character: next dialogue lines, or }
## COMPONENT TYPE RULES
### 对话朗读 (dialogue reading)
- 互动内容: "{Character}: {sentence}(朗读)"
- NO 互动反馈 section
- Example: User: Our living room is the space!朗读
### 对话挖空 (dialogue fill-in-blanks)
- 互动内容:
题目{task description}
{Character}: {sentence with ___}
选项1{correct word}正确
选项2{distractor word}
辅助信息{vocab meaning}
### 对话组句 (dialogue sentence building)
- Similar to fill-in-blanks but options are word/phrase chunks
- Max 4 options total
- 答案{complete sentence}
### 对话选择 (dialogue choice)
- 互动内容:
要求{instruction}
选项音频
选项1{correct answer}正确
- 反馈 {Character}: {feedback}
选项2{distractor}
- 反馈 {Character}: {feedback}
- NO 互动反馈 section (feedback inline)
### 对话选读 (dialogue selective reading)
- Similar to choice but ALL options correct (attitude check)
- NO 正确/错误 distinction
- Each option has its own feedback
### 对话表达 (dialogue expression)
- 互动内容:
表达{what to express}
示例回答User: {example sentence}
辅助信息{grammar tip}
### 图片单选/图片多选 (picture choice)
- 互动内容:
题干{imperative instruction}
选项
00
01正确[for 单选]
02
辅助信息{word meaning}
### 听力拖拽 (listening drag)
- Options as items to drag/drop
- 正确顺序XXXXXX
### 场景互动 (scene interaction)
- 互动内容: "instruction" the object!
选项1word正确
选项2distractor
## KEY RULES
1. Titles: NO numbers, NO dash separators, 10 characters
2. Feedback: ALWAYS character dialogue format "Name: message", NEVER teacher-like instructions
3. Correct feedback: ALWAYS
4. Fill blanks: use ___ (3 underscores) with spaces
5. Dialogue choice/selective: options with inline feedback, NO separate 互动反馈
6. Image choice: 仅选项编号00/01/02, 知识点单词用$高亮
7. Dialogue types: 选项1格式, lowercase start
8. 情境引入/后置对话: 无内容时填
9. Context: use both context_before and context_after
10. KP matching: 知识点 must match provided KP"""
def llm_generate(prompt):
"""Call LLM to generate component config"""
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=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=2000,
extra_body={"thinking": {"type": "disabled"}}
)
return resp.choices[0].message.content.strip()
def build_prompt(cr):
"""Build LLM prompt for a component row"""
prompt = f"""Generate component config for:
- Component Type: {cr['type']}
- Component ID: {cr['id']}
- Knowledge Points: {cr['kp']}
Context (dialogue before):
{chr(10).join(cr['ctx_before']) if cr['ctx_before'] else '(none)'}
Current row:
- Character: {cr['char']}
- Script (CN): {cr['script_cn']}
- Script (EN): {cr['script_en']}
- Plot: {cr['plot']}
Context (dialogue after):
{chr(10).join(cr['ctx_after']) if cr['ctx_after'] else '(none)'}
Generate the structured text component configuration for {cr['type']} type."""
return prompt
def write_to_sheet(token, sheet_row, content):
"""Write content to column H (index 7) of a specific row"""
col_letter = "H"
range_str = f"{SHEET_ID}!{col_letter}{sheet_row}:{col_letter}{sheet_row}"
url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SHEET_TOKEN}/values"
r = requests.put(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json={
"valueRange": {
"range": range_str,
"values": [[content]]
}
}
)
result = r.json()
if result.get("code") != 0:
print(f" ❌ Write error: {result}")
return False
return True
def main():
print("📝 Script Component Production Pipeline")
print(f"Sheet: {SHEET_TOKEN}/{SHEET_ID}")
token = get_token()
values = get_sheet_data(token)
print(f"Total rows: {len(values)}")
comp_rows = build_component_rows(values)
print(f"Component rows: {len(comp_rows)}")
# Save context
os.makedirs(OUTPUT_DIR, exist_ok=True)
with open(f"{OUTPUT_DIR}/comp_context.json", "w") as f:
json.dump([{k: v for k, v in cr.items() if k not in ('index',)} for cr in comp_rows], f, ensure_ascii=False, indent=2)
results = []
for cr in comp_rows:
sheet_row = cr["sheet_row"]
print(f"\n[{cr['type']}] Row {sheet_row} — ID {cr['id']}")
prompt = build_prompt(cr)
try:
content = llm_generate(prompt)
print(f" ✅ Generated {len(content)} chars")
# Write back
if write_to_sheet(token, sheet_row, content):
print(f" ✅ Written to H{sheet_row}")
results.append({"row": sheet_row, "id": cr["id"], "type": cr["type"], "status": "ok"})
else:
print(f" ⚠️ Generated but write failed, saved locally")
results.append({"row": sheet_row, "id": cr["id"], "type": cr["type"], "status": "write_fail"})
except Exception as e:
print(f" ❌ Error: {e}")
results.append({"row": sheet_row, "id": cr["id"], "type": cr["type"], "status": f"error: {e}"})
time.sleep(0.5)
# Summary
ok = sum(1 for r in results if r["status"] == "ok")
print(f"\n{'='*40}")
print(f"Done: {ok}/{len(results)} written, {len(results)-ok} failed")
with open(f"{OUTPUT_DIR}/results.json", "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
if __name__ == "__main__":
main()

View File

@ -52,7 +52,7 @@ metadata:
```bash ```bash
# user_id 从 USER.md 中查找(非 open_id # user_id 从 USER.md 中查找(非 open_id
cd /root/.openclaw/workspace-xiaoyan/skills/interactive-component-json && \ cd "/root/.openclaw/workspace-xiaoyan/business_production/组件配置/interactive-component-json" && \
python3 scripts/pipeline.py "<wiki_url>" --send-to <user_id> python3 scripts/pipeline.py "<wiki_url>" --send-to <user_id>
``` ```
@ -90,7 +90,7 @@ pipeline 在生成 HTML 报告前会自动管理代理服务,运行时会输
| `[代理] ✓ 中转服务正常 → <url>` | 代理服务运行正常HTML 将使用中转地址 | | `[代理] ✓ 中转服务正常 → <url>` | 代理服务运行正常HTML 将使用中转地址 |
| `[代理] ⚠️ 端口被僵死进程占用,正在清理...` | 检测到旧进程卡死,自动 kill 并重启 | | `[代理] ⚠️ 端口被僵死进程占用,正在清理...` | 检测到旧进程卡死,自动 kill 并重启 |
| `[代理] ✓ 中转服务启动成功 → <url>` | 代理重启成功 | | `[代理] ✓ 中转服务启动成功 → <url>` | 代理重启成功 |
| `[代理] ❌ 中转服务启动失败!` | 代理无法启动HTML 回退为直连 HTTPS 地址 | | `[代理] ❌ 中转服务启动失败!` | 代理无法启动HTML **仍使用代理地址**,推送前需手动运行 `python3 scripts/proxy_server.py &` |
**自动恢复机制**当健康检查失败但端口被占用时僵死进程pipeline 会自动终止僵死进程并重新启动代理,无需人工干预。 **自动恢复机制**当健康检查失败但端口被占用时僵死进程pipeline 会自动终止僵死进程并重新启动代理,无需人工干预。
@ -109,7 +109,7 @@ kill $(ss -tlnp | grep 18080 | grep -oP 'pid=\K\d+')
curl http://127.0.0.1:18080/health curl http://127.0.0.1:18080/health
``` ```
**注意**如果 HTML 报告中显示的推送地址是 `https://api-test.valavala.com/...` 而非 `http://<external_ip>:18080/api/push`,说明生成时代理服务未能正常运行。可在 HTML 顶部地址栏手动修改为中转地址,或重新运行 pipeline 生成 **注意**生成的 HTML 始终嵌入代理地址 `http://<external_ip>:18080/api/push`(只要 config.json 存在)。若代理未运行,推送前手动执行 `python3 scripts/proxy_server.py &` 启动即可,无需重新生成 HTML
## 概述 ## 概述

View File

@ -14,7 +14,7 @@ import pymysql
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__)) CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
SKILL_ROOT = os.path.dirname(CURRENT_PATH) SKILL_ROOT = os.path.dirname(CURRENT_PATH)
WORKSPACE_ROOT = os.path.dirname(os.path.dirname(SKILL_ROOT)) WORKSPACE_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(SKILL_ROOT)))
logger = logging.getLogger("kp_matcher") logger = logging.getLogger("kp_matcher")
if not logger.handlers: if not logger.handlers:

View File

@ -62,6 +62,28 @@ DEFAULT_MODEL = "doubao-seed-2.0-pro"
LLM_RETRY_TIMES = 2 LLM_RETRY_TIMES = 2
def _fix_llm_json_errors(json_str, error):
"""自动修复 LLM 输出中常见的 JSON 格式错误。"""
import re
fixed = json_str
# 1. 中文冒号:修复 "key" 或 "key" 为 "key":
fixed = re.sub(r'"([^"]+)"\s*[]\s*"', r'"\1": "', fixed)
fixed = re.sub(r'"([^"]+)"\s*[]\s*(\d|"|\[|\{|t|f|n)', r'"\1": \2', fixed)
# 标准冒号后面的中文冒号(如 "trans":" → 但冒号是中文的 "trans"
fixed = re.sub(r'"([^"]+)"([])\s*', r'"\1": ', fixed)
# 2. 中文逗号/顿号在字符串外
# JSON key-value 之间不应该有中文标点)
# 3. 尾部多余逗号(在 ] 或 } 之前)
fixed = re.sub(r',\s*([}\]])', r'\1', fixed)
if fixed != json_str:
logger.info(f"_fix_llm_json_errors: 已修复 {len(json_str)-len(fixed)} 处格式问题")
return fixed
def _get_api_key(provider="volcano"): def _get_api_key(provider="volcano"):
"""获取 API Key""" """获取 API Key"""
env_map = { env_map = {
@ -209,13 +231,18 @@ class LLMClient:
end = -1 if lines[-1].strip() == "```" else len(lines) end = -1 if lines[-1].strip() == "```" else len(lines)
json_str = "\n".join(lines[start:end]).strip() json_str = "\n".join(lines[start:end]).strip()
# 尝试解析,失败时自动修复常见 LLM JSON 格式错误后重试
for attempt in range(3):
try: try:
parsed = json.loads(json_str) parsed = json.loads(json_str)
if attempt > 0:
logger.info(f"JSON自动修复成功{attempt}次尝试)")
return parsed, usage return parsed, usage
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
# 详细日志:记录完整 prompt 和 LLM 返回内容 if attempt == 2:
# 3次都不行报错
logger.error( logger.error(
f"JSON解析失败!\n" f"JSON解析失败3次重试后仍失败!\n"
f"── system_prompt ({len(system_prompt)} chars) ──\n{system_prompt[:2000]}\n" f"── system_prompt ({len(system_prompt)} chars) ──\n{system_prompt[:2000]}\n"
f"── user_prompt ({len(user_prompt)} chars) ──\n{user_prompt[:3000]}\n" f"── user_prompt ({len(user_prompt)} chars) ──\n{user_prompt[:3000]}\n"
f"── LLM原始返回 ({len(content)} chars) ──\n{content[:1000]}\n" f"── LLM原始返回 ({len(content)} chars) ──\n{content[:1000]}\n"
@ -223,6 +250,10 @@ class LLMClient:
) )
raise ValueError(f"LLM返回内容不是合法JSON: {e}\n内容: {json_str[:300]}") from e raise ValueError(f"LLM返回内容不是合法JSON: {e}\n内容: {json_str[:300]}") from e
# 自动修复常见 LLM JSON 错误
logger.warning(f"JSON解析失败尝试自动修复 (attempt {attempt+1}/3): {e}")
json_str = _fix_llm_json_errors(json_str, e)
# ============ 便捷单例 ============ # ============ 便捷单例 ============
_default_client = None _default_client = None

View File

@ -81,6 +81,10 @@ def match_component_type(type_text: str) -> dict:
""" """
text = type_text.strip() text = type_text.strip()
# 剥离尾部编号(如 "对话朗读1" → "对话朗读"
import re as _re
text = _re.sub(r'\d+$', '', text).strip()
# 检查是否有配图后缀("-配图" 或 "+图片" # 检查是否有配图后缀("-配图" 或 "+图片"
has_image = False has_image = False
if text.endswith("-配图"): if text.endswith("-配图"):

View File

@ -587,7 +587,12 @@ def parse_sheet_rows(sheet_rows, llm_client=None):
} }
if base_type and base_type not in non_component_markers: if base_type and base_type not in non_component_markers:
has_image = "+图片" in type_text or "-配图" in type_text has_image = "+图片" in type_text or "-配图" in type_text
# 多行类型取最后一行(如 "核心听力16-\n听力拖拽" → "听力拖拽"
clean_type = type_text.replace("+图片", "").replace("-配图", "").strip() clean_type = type_text.replace("+图片", "").replace("-配图", "").strip()
if '\n' in clean_type:
lines = [l.strip() for l in clean_type.split('\n') if l.strip()]
if lines:
clean_type = lines[-1] # 取最后一行作为实际类型名
comp_info = { comp_info = {
"type_name": clean_type, "type_name": clean_type,
"cId": raw_cell, "cId": raw_cell,

View File

@ -139,7 +139,7 @@ def _start_proxy_process():
def _ensure_proxy_running(): def _ensure_proxy_running():
"""检测代理服务是否运行,未运行则自动启动。返回代理 URL 或 None""" """检测代理服务是否运行,未运行则自动启动。返回代理 URL(有配置时始终返回代理地址,无论是否启动成功)"""
import requests as _req import requests as _req
proxy_cfg = _load_proxy_config() proxy_cfg = _load_proxy_config()
@ -169,9 +169,9 @@ def _ensure_proxy_running():
logger.warning(f"代理服务健康检查失败,但端口 {port} 被进程 PID {stale_pid} 占用(疑似僵死)") logger.warning(f"代理服务健康检查失败,但端口 {port} 被进程 PID {stale_pid} 占用(疑似僵死)")
print(f"[代理] ⚠️ 端口 {port} 被僵死进程 (PID {stale_pid}) 占用,正在清理...") print(f"[代理] ⚠️ 端口 {port} 被僵死进程 (PID {stale_pid}) 占用,正在清理...")
if not _kill_stale_process(port): if not _kill_stale_process(port):
logger.error(f"无法终止僵死进程 PID {stale_pid}HTML报告将使用直连地址") logger.error(f"无法终止僵死进程 PID {stale_pid}代理可能不可用,但 HTML 仍使用代理地址")
print(f"[代理] ❌ 无法清理僵死进程,HTML报告将使用直连地址") print(f"[代理] ❌ 无法清理僵死进程,推送前请手动重启代理服务")
return None return proxy_url
time.sleep(1) # 等待端口释放 time.sleep(1) # 等待端口释放
else: else:
logger.info("代理服务未运行,正在启动...") logger.info("代理服务未运行,正在启动...")
@ -192,9 +192,9 @@ def _ensure_proxy_running():
except Exception: except Exception:
continue continue
logger.error("❌ 代理服务启动失败HTML报告将使用直连地址") logger.error("❌ 代理服务启动失败HTML 仍使用代理地址推送前请手动启动代理python3 scripts/proxy_server.py &")
print("[代理] ❌ 中转服务启动失败HTML报告将使用直连HTTPS地址可能受浏览器CORS限制") print("[代理] ❌ 中转服务启动失败HTML 已嵌入代理地址,推送前请手动运行: python3 scripts/proxy_server.py &")
return None return proxy_url
def process_script(wiki_url_or_token, db_path=None, dry_run=False): def process_script(wiki_url_or_token, db_path=None, dry_run=False):

View File

@ -0,0 +1,90 @@
# Scene 1
Dad: It's a rest day today.
Dad: We don't go anywhere this afternoon.
Dad: I sit on the armchair in the living room.
Dad: I'll read you a space adventure picture book.
Dad: We have a whole afternoon for this, honey.
Dad: We'll go to space this afternoon!
Narrator: The spaceship in the story is flying.
Narrator: It flies to a shiny glowing planet.
Narrator: We turn the page now.
Narrator: The next few pages are torn off.
Dad: Uh-oh...
Dad: The story ends here.
Narrator: You are not happy that the story stops.
Narrator: The light in the corner blinks once.
Narrator: You stare at that little light.
Narrator: Your eyes light up bright!
User: Look!
User: That light!
User: That's the star from the story!
Dad: I throw the book in my hand aside.
Dad: We don't need the book now.
Dad: We can be the story ourselves!
# Scene 2
Kid: Our living room is a spaceship now!
Kid: These are the seats for our spaceship!
Kid: I am the captain of this ship!
Kid: You are my little helper today.
Kid: Go sit over there, little helper.
Kid: Oh no! I pressed the wrong button!
Kid: Wow, we are flying up high now!
Kid: Look, our spaceship is moving so fast!
Kid: Hey, look up at the sky right now!
Kid: Yay! We are in outer space now!
# Scene 3
角色: Look straight ahead!
角色: There are asteroids!
角色: Left!
角色: Right!
角色: Oh no!
角色: We can't get out of the way!
角色: BOOM!
角色: Our ship hit the asteroid!
角色: Oh that's so bad!
角色: The ship has no power now!
角色: Huh?
角色: I press the button but nothing happens.
角色: What should we do now?
角色: I got an idea!
角色: Dad!
角色: You push the spaceship!
角色: I tell you where to go!
角色: Left!
角色: Right!
角色: Careful!
角色: Awesome!
角色: We went through the asteroid belt!
角色: Good job, helper!
# Scene 4
User: I'm back in my armchair now!
User: We are almost there, guys!
User: That glowing planet is up ahead!
User: That planet is the lamp in the corner!
Lamp: I flicker once, look at me!
User: I feel really nervous right now.
User: I feel really excited right now.
Dad: Oh my!
Dad: I'll walk over to it.
Dad: I trip over a wire on the floor.
User: I'll go there by myself!
User: I walk to the lamp slowly.
User: I reach out and touch the lamp shade.
Lamp: I light up steadily now!
Lamp: My light bulb is connected again.
Lamp: Warm light fills the whole living room.
User: I am so happy right now!
User: I found the star, I found it!
User: It feels so warm and nice!
User: I move the lamp very carefully.
User: I put it next to the armchair.
User: Our task is done! Yay!
# Scene 5
Dad: This is the best afternoon ever!
User: Next time, okay?
User: We will fly to the moon!

View File

@ -0,0 +1 @@
{"st": "UK7ms9UrdhJllftVOaOc4r4envg", "sid": "wMQVyV"}

View File

@ -0,0 +1,95 @@
Dad: Oh, I love this afternoon.
Dad: No work, just us.
User: Really? You don't have to work today?
Dad: Nope!
User: Are you staying home all afternoon?
Dad: Yes, dear.
Dad: We can stay in this living room for the whole afternoon.
User: Yay!
User: Can we read the book about space?
Dad: Of course!
User: Woohoo!
User: This afternoon, we go to space!
Dad: The spaceship is flying fast...
Dad: It's getting closer and closer to the glowing star...
Dad: Uh-Oh!
User: What? What's wrong with the spaceship?
Dad: I can't read anymore. Look at the book.
User: What's wrong with the book?
Dad: The book is broken. Some pages are gone!
Dad: Sorry, dear. The story is over.
User: Oh, no. Our space trip is just beginning.
User: I do not want it to end.
Dad: Maybe... We don't need the book!
Dad: We can be the story!
User: How?
Dad: Just use your imagination, Captain!
User: You're right!
User: Our living room is the space!
User: Now, I am the captain.
Dad: Yes, Captain!
Dad: May I sit in this armchair, Captain?
User: No.
User: This armchair is my seat!
User: You are my helper.
User: You stand next to me.
Dad: Yes, Captain! What's next?
User: Let's start the spaceship!
Dad: Okay. I think we should...
Dad: Press the yellow button!
User: Wrong button, helper!
Dad: Oh, sorry.
User: Press the green button, please.
User: Whoa! The spaceship is moving.
User: We are flying!
User: Why do we stop?
User: What's wrong with the spaceship?
Dad: Our spaceship is stuck.
Dad: There are many space rocks ahead!
Dad: What do we do now, Captain?
User: We need a cleaner to clear the way!
User: Press the blue button.
User: Good job, cleaner.
User: Let's keep going.
User: Push the armchair, Dad!
Dad: Okay.
Dad: The spaceship is flying fast...
Dad: It's getting closer and closer to the glowing star...
User: We are finally here!
User: Look! The star!
Dad: Where? I just see a lamp there.
User: Use your imagination, Dad.
User: The lamp is the glowing star.
Dad: How come I do not see it glowing?
User: That's because you haven't woken it up yet.
User: Press the red button.
User: Look! The glowing star!
Dad: I'll get it.
User: Be careful!
Dad: Oops!
User: What's wrong with the lamp?
Dad: Hmm... maybe the bulb is loose.
User: I know how to fix it!
User: It's working!
User: I fixed the star!
Dad: Because you are the best Captain in the world!
Dad: What's next, Captain?
User: We got the star! It is time to go back.
User: This time, you drive.
User: I will take care of the lamp.
User: You sit in the armchair, Dad.
Dad: Captain, we are back! The star is safe.
User: Good job, helper.
Mum: What happened to our living room?
User: Mum! We went to space this afternoon!
Mum: Space? In our living room? How?
User: Come to the living room, Mum.
User: I can show you!
User: Our living room is the space.
User: The armchair is the captain's seat.
User: The lamp is the glowing star!
Mum: I see! You two had a big afternoon.
User: This was the best afternoon.
Dad: Next time, we fly to the moon.
User: Yay!
User: Our living room can go anywhere!

View File

@ -0,0 +1,477 @@
[
{
"row": 3,
"char": "Dad",
"text": "Oh, I love this afternoon."
},
{
"row": 4,
"char": "Dad",
"text": "No work, just us."
},
{
"row": 6,
"char": "User",
"text": "Really? You don't have to work today?"
},
{
"row": 7,
"char": "Dad",
"text": "Nope!"
},
{
"row": 9,
"char": "User",
"text": "Are you staying home all afternoon?"
},
{
"row": 10,
"char": "Dad",
"text": "Yes, dear."
},
{
"row": 11,
"char": "Dad",
"text": "We can stay in this living room for the whole afternoon."
},
{
"row": 12,
"char": "User",
"text": "Yay!"
},
{
"row": 14,
"char": "User",
"text": "Can we read the book about space?"
},
{
"row": 15,
"char": "Dad",
"text": "Of course!"
},
{
"row": 16,
"char": "User",
"text": "Woohoo!"
},
{
"row": 17,
"char": "User",
"text": "This afternoon, we go to space!"
},
{
"row": 19,
"char": "Dad",
"text": "The spaceship is flying fast..."
},
{
"row": 20,
"char": "Dad",
"text": "It's getting closer and closer to the glowing star..."
},
{
"row": 21,
"char": "Dad",
"text": "Uh-Oh!"
},
{
"row": 23,
"char": "User",
"text": "What? What's wrong with the spaceship?"
},
{
"row": 24,
"char": "Dad",
"text": "I can't read anymore. Look at the book."
},
{
"row": 26,
"char": "User",
"text": "What's wrong with the book?"
},
{
"row": 27,
"char": "Dad",
"text": "The book is broken. Some pages are gone!"
},
{
"row": 29,
"char": "Dad",
"text": "Sorry, dear. The story is over."
},
{
"row": 31,
"char": "User",
"text": "Oh, no. Our space trip is just beginning."
},
{
"row": 32,
"char": "User",
"text": "I do not want it to end."
},
{
"row": 34,
"char": "Dad",
"text": "Maybe... We don't need the book!"
},
{
"row": 35,
"char": "Dad",
"text": "We can be the story!"
},
{
"row": 36,
"char": "User",
"text": "How?"
},
{
"row": 38,
"char": "Dad",
"text": "Just use your imagination, Captain!"
},
{
"row": 40,
"char": "User",
"text": "You're right!"
},
{
"row": 41,
"char": "User",
"text": "Our living room is the space!"
},
{
"row": 44,
"char": "User",
"text": "Now, I am the captain."
},
{
"row": 45,
"char": "Dad",
"text": "Yes, Captain!"
},
{
"row": 46,
"char": "Dad",
"text": "May I sit in this armchair, Captain?"
},
{
"row": 47,
"char": "User",
"text": "No."
},
{
"row": 49,
"char": "User",
"text": "This armchair is my seat!"
},
{
"row": 51,
"char": "User",
"text": "You are my helper."
},
{
"row": 52,
"char": "User",
"text": "You stand next to me."
},
{
"row": 54,
"char": "Dad",
"text": "Yes, Captain! What's next?"
},
{
"row": 55,
"char": "User",
"text": "Let's start the spaceship!"
},
{
"row": 56,
"char": "Dad",
"text": "Okay. I think we should..."
},
{
"row": 58,
"char": "Dad",
"text": "Press the yellow button!"
},
{
"row": 60,
"char": "User",
"text": "Wrong button, helper!"
},
{
"row": 61,
"char": "Dad",
"text": "Oh, sorry."
},
{
"row": 64,
"char": "User",
"text": "Press the green button, please."
},
{
"row": 66,
"char": "User",
"text": "Whoa! The spaceship is moving."
},
{
"row": 68,
"char": "User",
"text": "We are flying!"
},
{
"row": 70,
"char": "User",
"text": "Why do we stop?"
},
{
"row": 71,
"char": "User",
"text": "What's wrong with the spaceship?"
},
{
"row": 72,
"char": "Dad",
"text": "Our spaceship is stuck."
},
{
"row": 74,
"char": "Dad",
"text": "There are many space rocks ahead!"
},
{
"row": 75,
"char": "Dad",
"text": "What do we do now, Captain?"
},
{
"row": 76,
"char": "User",
"text": "We need a cleaner to clear the way!"
},
{
"row": 78,
"char": "User",
"text": "Press the blue button."
},
{
"row": 80,
"char": "User",
"text": "Good job, cleaner."
},
{
"row": 81,
"char": "User",
"text": "Let's keep going."
},
{
"row": 82,
"char": "User",
"text": "Push the armchair, Dad!"
},
{
"row": 83,
"char": "Dad",
"text": "Okay."
},
{
"row": 85,
"char": "Dad",
"text": "The spaceship is flying fast..."
},
{
"row": 86,
"char": "Dad",
"text": "It's getting closer and closer to the glowing star..."
},
{
"row": 88,
"char": "User",
"text": "We are finally here!"
},
{
"row": 89,
"char": "User",
"text": "Look! The star!"
},
{
"row": 91,
"char": "Dad",
"text": "Where? I just see a lamp there."
},
{
"row": 92,
"char": "User",
"text": "Use your imagination, Dad."
},
{
"row": 94,
"char": "User",
"text": "The lamp is the glowing star."
},
{
"row": 95,
"char": "Dad",
"text": "How come I do not see it glowing?"
},
{
"row": 96,
"char": "User",
"text": "That's because you haven't woken it up yet."
},
{
"row": 98,
"char": "User",
"text": "Press the red button."
},
{
"row": 100,
"char": "User",
"text": "Look! The glowing star!"
},
{
"row": 101,
"char": "Dad",
"text": "I'll get it."
},
{
"row": 102,
"char": "User",
"text": "Be careful!"
},
{
"row": 104,
"char": "Dad",
"text": "Oops!"
},
{
"row": 106,
"char": "User",
"text": "What's wrong with the lamp?"
},
{
"row": 107,
"char": "Dad",
"text": "Hmm... maybe the bulb is loose."
},
{
"row": 108,
"char": "User",
"text": "I know how to fix it!"
},
{
"row": 110,
"char": "User",
"text": "It's working!"
},
{
"row": 111,
"char": "User",
"text": "I fixed the star!"
},
{
"row": 112,
"char": "Dad",
"text": "Because you are the best Captain in the world!"
},
{
"row": 114,
"char": "Dad",
"text": "What's next, Captain?"
},
{
"row": 115,
"char": "User",
"text": "We got the star! It is time to go back."
},
{
"row": 116,
"char": "User",
"text": "This time, you drive."
},
{
"row": 118,
"char": "User",
"text": "I will take care of the lamp."
},
{
"row": 120,
"char": "User",
"text": "You sit in the armchair, Dad."
},
{
"row": 122,
"char": "Dad",
"text": "Captain, we are back! The star is safe."
},
{
"row": 123,
"char": "User",
"text": "Good job, helper."
},
{
"row": 126,
"char": "Mum",
"text": "What happened to our living room?"
},
{
"row": 127,
"char": "User",
"text": "Mum! We went to space this afternoon!"
},
{
"row": 128,
"char": "Mum",
"text": "Space? In our living room? How?"
},
{
"row": 130,
"char": "User",
"text": "Come to the living room, Mum."
},
{
"row": 131,
"char": "User",
"text": "I can show you!"
},
{
"row": 133,
"char": "User",
"text": "Our living room is the space."
},
{
"row": 134,
"char": "User",
"text": "The armchair is the captain's seat."
},
{
"row": 135,
"char": "User",
"text": "The lamp is the glowing star!"
},
{
"row": 136,
"char": "Mum",
"text": "I see! You two had a big afternoon."
},
{
"row": 137,
"char": "User",
"text": "This was the best afternoon."
},
{
"row": 139,
"char": "Dad",
"text": "Next time, we fly to the moon."
},
{
"row": 141,
"char": "User",
"text": "Yay!"
},
{
"row": 142,
"char": "User",
"text": "Our living room can go anywhere!"
}
]

View File

@ -0,0 +1,767 @@
[
{
"row": 3,
"char": "User",
"text": "Alright, BoBo. Mum and Dad are not home, and I have jobs to do."
},
{
"row": 5,
"char": "BoBo",
"text": "List? BoBo sees!"
},
{
"row": 6,
"char": "User",
"text": "Number one, check the house. Not much to do!"
},
{
"row": 8,
"char": "User",
"text": "Uh, well... we do have much to do."
},
{
"row": 9,
"char": "User",
"text": "They left in a hurry. Look at this mess!"
},
{
"row": 11,
"char": "BoBo",
"text": "Mess! Mess!"
},
{
"row": 12,
"char": "User",
"text": "I miss them already."
},
{
"row": 13,
"char": "BoBo",
"text": "We need help, from Mum and Dad!"
},
{
"row": 15,
"char": "User",
"text": "Hey, I don't need any help. I can clean up by myself!"
},
{
"row": 16,
"char": "User",
"text": "Come on, lets get moving!"
},
{
"row": 17,
"char": "User",
"text": "I dont have much time to just stand here."
},
{
"row": 19,
"char": "User",
"text": "Dad's old T-shirt. It smells like Dad."
},
{
"row": 20,
"char": "User",
"text": "He never folds anything."
},
{
"row": 22,
"char": "BoBo",
"text": "What's that?"
},
{
"row": 23,
"char": "User",
"text": "Huh. Dad left his phone here. He can't call us."
},
{
"row": 25,
"char": "BoBo",
"text": "Bo——Bo——"
},
{
"row": 26,
"char": "BoBo",
"text": "Help! BoBo stuck!"
},
{
"row": 28,
"char": "User",
"text": "BoBo! Oh no, hold still!"
},
{
"row": 30,
"char": "BoBo",
"text": "BoBo free!"
},
{
"row": 32,
"char": "User",
"text": "It's Dad's scarf! I know this one."
},
{
"row": 33,
"char": "User",
"text": "Dad always loses his scarf."
},
{
"row": 34,
"char": "User",
"text": "Every winter, he says, Where is my scarf?"
},
{
"row": 35,
"char": "BoBo",
"text": "Scarf! Scary scarf!"
},
{
"row": 37,
"char": "User",
"text": "There. Everything is in its place."
},
{
"row": 38,
"char": "User",
"text": "When Mum and Dad come back, I must speak of all the great things I did!"
},
{
"row": 39,
"char": "BoBo",
"text": "Great things I did!"
},
{
"row": 41,
"char": "User",
"text": "This is Mum's book."
},
{
"row": 43,
"char": "User",
"text": "Look, BoBo. That's us. Before they left."
},
{
"row": 45,
"char": "User",
"text": "Hmm... I miss them, just a little."
},
{
"row": 47,
"char": "BoBo",
"text": "BoBo is here."
},
{
"row": 49,
"char": "User",
"text": "Thank you."
},
{
"row": 50,
"char": "User",
"text": "You're here. That's good."
},
{
"row": 52,
"char": "BoBo",
"text": "BoBo good! BoBo stays!"
},
{
"row": 54,
"char": "User",
"text": "Okay. I'm good too."
},
{
"row": 56,
"char": "User",
"text": "Check the house, done!"
},
{
"row": 58,
"char": "BoBo",
"text": "Done! Done!"
},
{
"row": 60,
"char": "User",
"text": "Number two, water the plants."
},
{
"row": 62,
"char": "User",
"text": "Hmm."
},
{
"row": 63,
"char": "User",
"text": "I don't have much water in here."
},
{
"row": 66,
"char": "BoBo",
"text": "Plant! BoBo likes plants!"
},
{
"row": 67,
"char": "User",
"text": "I know, I know."
},
{
"row": 69,
"char": "BoBo",
"text": "Not too much! Not too much!"
},
{
"row": 70,
"char": "User",
"text": "Don't worry."
},
{
"row": 71,
"char": "User",
"text": "I know how much water they need."
},
{
"row": 72,
"char": "User",
"text": "Mum taught me."
},
{
"row": 74,
"char": "User",
"text": "This little one? Just a tiny bit."
},
{
"row": 76,
"char": "BoBo",
"text": "Water! Good!"
},
{
"row": 78,
"char": "User",
"text": "This big one needs much more water."
},
{
"row": 80,
"char": "User",
"text": "This one is Mum's favorite."
},
{
"row": 82,
"char": "BoBo",
"text": "Pretty! Pretty flower!"
},
{
"row": 84,
"char": "User",
"text": "Mum speaks to it every morning."
},
{
"row": 85,
"char": "User",
"text": "She says, \"Good morning, little one!\""
},
{
"row": 86,
"char": "User",
"text": "She says they grow better that way."
},
{
"row": 87,
"char": "User",
"text": "Mum is away for now."
},
{
"row": 88,
"char": "User",
"text": "I will speak to these plants every day."
},
{
"row": 90,
"char": "User",
"text": "Do you think they miss Mum, BoBo?"
},
{
"row": 92,
"char": "BoBo",
"text": "Miss? Plants miss?"
},
{
"row": 93,
"char": "User",
"text": "They can't speak."
},
{
"row": 94,
"char": "User",
"text": "They can't tell Mum they miss her."
},
{
"row": 96,
"char": "User",
"text": "Don't worry, little one. She'll come back."
},
{
"row": 98,
"char": "BoBo",
"text": "Come back! Come back very soon!"
},
{
"row": 99,
"char": "User",
"text": "Haha, you're speaking to it too?"
},
{
"row": 100,
"char": "BoBo",
"text": "Mum not home, BoBo speaks."
},
{
"row": 102,
"char": "User",
"text": "I miss her."
},
{
"row": 103,
"char": "User",
"text": "Much more than a little."
},
{
"row": 105,
"char": "BoBo",
"text": "BoBo is here. BoBo stays."
},
{
"row": 106,
"char": "User",
"text": "Okay. Let's finish the list."
},
{
"row": 108,
"char": "User",
"text": "Water the plants, done!"
},
{
"row": 110,
"char": "BoBo",
"text": "Done! Two done!"
},
{
"row": 112,
"char": "User",
"text": "Number three, call Mum and Dad every week..."
},
{
"row": 113,
"char": "User",
"text": "It's only day two."
},
{
"row": 114,
"char": "User",
"text": "Not yet."
},
{
"row": 115,
"char": "User",
"text": "I'll call them next week."
},
{
"row": 117,
"char": "User",
"text": "Alright, all the jobs are done."
},
{
"row": 119,
"char": "BoBo",
"text": "Bo——Bo——"
},
{
"row": 120,
"char": "BoBo",
"text": "Boring..."
},
{
"row": 122,
"char": "User",
"text": "Hey BoBo! I have an idea."
},
{
"row": 123,
"char": "User",
"text": "You spoke to the plant, remember?"
},
{
"row": 125,
"char": "BoBo",
"text": "BoBo spoke to plant?"
},
{
"row": 126,
"char": "User",
"text": "Yes! You're learning! Let me teach you some new words."
},
{
"row": 128,
"char": "User",
"text": "This is a cup. Can you say it? Cup!"
},
{
"row": 129,
"char": "BoBo",
"text": "Ca... ca..."
},
{
"row": 130,
"char": "User",
"text": "Hmm, close! Try again. Cup!"
},
{
"row": 132,
"char": "BoBo",
"text": "Ca——Bo——!"
},
{
"row": 133,
"char": "User",
"text": "That's okay. Let's try another one."
},
{
"row": 135,
"char": "User",
"text": "Lamp! Say lamp!"
},
{
"row": 137,
"char": "BoBo",
"text": "La... Lam..."
},
{
"row": 138,
"char": "BoBo",
"text": "Lam——Bo——!"
},
{
"row": 140,
"char": "User",
"text": "Everything turns into \"BoBo\" with you!"
},
{
"row": 142,
"char": "BoBo",
"text": "BoBo tries! BoBo tries hard!"
},
{
"row": 143,
"char": "User",
"text": "I know, I know! You're doing great. One more."
},
{
"row": 145,
"char": "User",
"text": "Okay, BoBo. This one is important."
},
{
"row": 147,
"char": "User",
"text": "This is a phone."
},
{
"row": 148,
"char": "User",
"text": "Can you speak?"
},
{
"row": 150,
"char": "User",
"text": "Say phone!"
},
{
"row": 152,
"char": "BoBo",
"text": "Ph... pho... phone?"
},
{
"row": 153,
"char": "User",
"text": "Yes! You said it!"
},
{
"row": 155,
"char": "BoBo",
"text": "Phone! Phone! BoBo said it!"
},
{
"row": 156,
"char": "User",
"text": "Okay, BoBo. You're good at this."
},
{
"row": 157,
"char": "User",
"text": "Let me teach you something harder."
},
{
"row": 158,
"char": "User",
"text": "Say... I miss you."
},
{
"row": 160,
"char": "BoBo",
"text": "Miss? What is miss?"
},
{
"row": 161,
"char": "User",
"text": "When you want to see someone... but they're far away. You say..."
},
{
"row": 162,
"char": "User",
"text": "Miss."
},
{
"row": 163,
"char": "BoBo",
"text": "Mmmm... Mmmi..."
},
{
"row": 165,
"char": "User",
"text": "I... miss... you."
},
{
"row": 166,
"char": "User",
"text": "BoBo, I miss them."
},
{
"row": 168,
"char": "BoBo",
"text": "Miss... them. BoBo miss them too."
},
{
"row": 170,
"char": "User",
"text": "Yeah. I miss them."
},
{
"row": 172,
"char": "BoBo",
"text": "Phone! Use phone!"
},
{
"row": 173,
"char": "User",
"text": "No. It's only been two days."
},
{
"row": 174,
"char": "User",
"text": "I don't have much to say."
},
{
"row": 176,
"char": "User",
"text": "Hey! Careful!"
},
{
"row": 178,
"char": "BoBo",
"text": "Phone! Phone! Call!"
},
{
"row": 179,
"char": "User",
"text": "Okay..."
},
{
"row": 180,
"char": "User",
"text": "I don't have much to tell them."
},
{
"row": 181,
"char": "User",
"text": "But I'll practice."
},
{
"row": 183,
"char": "User",
"text": "This is just practice, okay? Not a real call."
},
{
"row": 184,
"char": "User",
"text": "I'll practice what to speak about."
},
{
"row": 186,
"char": "BoBo",
"text": "BoBo listens!"
},
{
"row": 188,
"char": "User",
"text": "Hi Mum. Hi Dad. Everything is good at home."
},
{
"row": 189,
"char": "User",
"text": "I cleaned our living room today."
},
{
"row": 190,
"char": "User",
"text": "And I watered the plants."
},
{
"row": 191,
"char": "User",
"text": "And... I want to say..."
},
{
"row": 192,
"char": "User",
"text": "I miss you."
},
{
"row": 194,
"char": "User",
"text": "I found Mum's book. And Dad's scarf."
},
{
"row": 196,
"char": "Dad",
"text": "My scarf? Is it okay?"
},
{
"row": 198,
"char": "User",
"text": "WHAT?!"
},
{
"row": 200,
"char": "BoBo",
"text": "BoBo helps! BoBo is a good helper!"
},
{
"row": 201,
"char": "User",
"text": "Wait, has the call been on?"
},
{
"row": 202,
"char": "User",
"text": "They heard everything?"
},
{
"row": 203,
"char": "Dad",
"text": "Every word!"
},
{
"row": 204,
"char": "Dad",
"text": "And we miss you!"
},
{
"row": 205,
"char": "Dad",
"text": "Oh! Mom took over the phone. She has so much to say!"
},
{
"row": 207,
"char": "Dad",
"text": "Hey, It's my turn."
},
{
"row": 208,
"char": "Dad",
"text": "Did you fold my scarf, dear?"
},
{
"row": 209,
"char": "User",
"text": "Yes! It's in the closet now!"
},
{
"row": 210,
"char": "Dad",
"text": "Amazing! You're better at this than me!"
},
{
"row": 211,
"char": "Mum",
"text": "You're doing so well. We're so proud."
},
{
"row": 214,
"char": "User",
"text": "Can we speak on the phone again? Soon?"
},
{
"row": 215,
"char": "Mum",
"text": "Anytime you want. You can always speak to us."
},
{
"row": 216,
"char": "Dad",
"text": "Call anytime! Even if you don't have much to say!"
},
{
"row": 217,
"char": "Dad",
"text": "Even if it's just, \"Dad, your scarf is still in the closet!\""
},
{
"row": 219,
"char": "User",
"text": "Okay. I will. Bye Mum. Bye Dad."
},
{
"row": 220,
"char": "Mum",
"text": "Bye dear. We love you."
},
{
"row": 221,
"char": "Dad",
"text": "Love you! Take care of my scarf!"
},
{
"row": 224,
"char": "BoBo",
"text": "BoBo helps! BoBo called!"
},
{
"row": 225,
"char": "User",
"text": "You sneaky little helper."
},
{
"row": 231,
"char": "User",
"text": "Alright. That's a perfect plan."
},
{
"row": 232,
"char": "BoBo",
"text": "Perfect! BoBo good helper!"
},
{
"row": 234,
"char": "User",
"text": "Good helper, BoBo."
},
{
"row": 235,
"char": "BoBo",
"text": "BoBo stays. Always."
},
{
"row": 236,
"char": "User",
"text": "Thank you, BoBo."
}
]

View File

@ -0,0 +1,597 @@
[
{
"row": 3,
"char": "Delivery man",
"text": "Package!"
},
{
"row": 4,
"char": "Dad",
"text": "Coming."
},
{
"row": 6,
"char": "Dad",
"text": "Look what came!"
},
{
"row": 8,
"char": "User",
"text": "Oh! It's a box from Vala!"
},
{
"row": 9,
"char": "User",
"text": "What's in it?"
},
{
"row": 10,
"char": "Dad",
"text": "Let's find out together."
},
{
"row": 12,
"char": "Mum",
"text": "Wow! Look! Astronaut suits!"
},
{
"row": 14,
"char": "User",
"text": "There are two astronaut suits!"
},
{
"row": 16,
"char": "Mum",
"text": "This one is mine, it has my name on it!"
},
{
"row": 17,
"char": "Mum",
"text": "I have an astronaut suit!"
},
{
"row": 19,
"char": "Dad",
"text": "And this one is mine."
},
{
"row": 21,
"char": "User",
"text": "Where is mine?"
},
{
"row": 22,
"char": "User",
"text": "I also want to have an astronaut suit!"
},
{
"row": 24,
"char": "Mum",
"text": "Dear, there is something I must tell you."
},
{
"row": 25,
"char": "User",
"text": "What?"
},
{
"row": 26,
"char": "Mum",
"text": "Dad and I got a new job."
},
{
"row": 27,
"char": "User",
"text": "A job? What job?"
},
{
"row": 28,
"char": "Mum",
"text": "We're going to work on Vala."
},
{
"row": 29,
"char": "User",
"text": "Vala? The planet Vala? The place far, far away from the Earth?"
},
{
"row": 30,
"char": "Mum",
"text": "Yes."
},
{
"row": 31,
"char": "Mum",
"text": "We are leaving in a few days."
},
{
"row": 32,
"char": "Mum",
"text": "These astronaut suits are for us to travel through space."
},
{
"row": 33,
"char": "User",
"text": "No! I want to go to Vala with you! I am ready!"
},
{
"row": 36,
"char": "User",
"text": "May I try this astronaut suit on?"
},
{
"row": 38,
"char": "User",
"text": "It's too big."
},
{
"row": 39,
"char": "Dad",
"text": "Hey, hey. That's mine!"
},
{
"row": 41,
"char": "User",
"text": "But I also want one."
},
{
"row": 43,
"char": "Dad",
"text": "Wait! Wait wait..."
},
{
"row": 44,
"char": "Dad",
"text": "I think I have something great for you."
},
{
"row": 46,
"char": "Dad",
"text": "Aha! Found it!"
},
{
"row": 48,
"char": "Dad",
"text": "Look! My old astronaut suit!"
},
{
"row": 49,
"char": "Dad",
"text": "It's too small for me now. But for you..."
},
{
"row": 50,
"char": "Dad",
"text": "It's perfect!"
},
{
"row": 52,
"char": "User",
"text": "This looks so old and broken."
},
{
"row": 53,
"char": "Dad",
"text": "Well, it just needs some fixing."
},
{
"row": 54,
"char": "Dad",
"text": "Let's make it yours!"
},
{
"row": 56,
"char": "Mum",
"text": "Good idea! We can fix it together."
},
{
"row": 57,
"char": "Mum",
"text": "Now, everyone has a job."
},
{
"row": 58,
"char": "Mum",
"text": "My job is to measure."
},
{
"row": 59,
"char": "User",
"text": "What is Dad's job?"
},
{
"row": 60,
"char": "Dad",
"text": "My job is to cut."
},
{
"row": 62,
"char": "Dad",
"text": "There! Now it is a perfect fit!"
},
{
"row": 63,
"char": "User",
"text": "What is my job?"
},
{
"row": 65,
"char": "Mum",
"text": "You have the most important job."
},
{
"row": 66,
"char": "Mum",
"text": "Put this badge on it, Captain."
},
{
"row": 68,
"char": "Dad",
"text": "Wow, it says 'a great astronaut'! Just right for you."
},
{
"row": 70,
"char": "User",
"text": "Done!"
},
{
"row": 71,
"char": "Dad",
"text": "Now, put it on!"
},
{
"row": 73,
"char": "User",
"text": "I have an astronaut suit!"
},
{
"row": 74,
"char": "User",
"text": "I'm a great astronaut."
},
{
"row": 76,
"char": "User",
"text": "Look at me! I'm walking in space!"
},
{
"row": 77,
"char": "Dad",
"text": "Ha-ha! We have three astronauts in our family now!"
},
{
"row": 78,
"char": "Dad",
"text": "We are a great astronaut team!"
},
{
"row": 79,
"char": "User",
"text": "A great astronaut team!"
},
{
"row": 81,
"char": "User",
"text": "Mum, can I go to Vala too?"
},
{
"row": 82,
"char": "Mum",
"text": "Not this time, dear."
},
{
"row": 83,
"char": "User",
"text": "But we are a team, aren't we?"
},
{
"row": 84,
"char": "Mum",
"text": "You know, every astronaut team needs someone on the ground."
},
{
"row": 85,
"char": "Mum",
"text": "Someone who watches. Someone who helps."
},
{
"row": 86,
"char": "Mum",
"text": "That's also a very important job."
},
{
"row": 87,
"char": "User",
"text": "I have a job too?"
},
{
"row": 88,
"char": "Dad",
"text": "Yes! Without the ground team, astronauts get lost in space!"
},
{
"row": 89,
"char": "Dad",
"text": "We also need someone at home."
},
{
"row": 91,
"char": "User",
"text": "I've got it! I know what to do now!"
},
{
"row": 93,
"char": "Dad",
"text": "What are you doing?"
},
{
"row": 94,
"char": "User",
"text": "I have a job now, so Id better write it down."
},
{
"row": 98,
"char": "User",
"text": "My job is to..."
},
{
"row": 99,
"char": "User",
"text": "Number one... Check the house."
},
{
"row": 100,
"char": "User",
"text": "Number two... Water the plants."
},
{
"row": 101,
"char": "User",
"text": "Number three..."
},
{
"row": 103,
"char": "Dad",
"text": "How about count the stars every day?"
},
{
"row": 105,
"char": "User",
"text": "Dad! That's silly!"
},
{
"row": 106,
"char": "User",
"text": "Number three..."
},
{
"row": 107,
"char": "User",
"text": "We also need to talk on the phone."
},
{
"row": 108,
"char": "User",
"text": "May I call you every week?"
},
{
"row": 109,
"char": "Mum",
"text": "Of course."
},
{
"row": 111,
"char": "User",
"text": "I have a plan!"
},
{
"row": 112,
"char": "Mum",
"text": "This is a great plan."
},
{
"row": 114,
"char": "User",
"text": "A great plan for a great job!"
},
{
"row": 115,
"char": "Mum",
"text": "So we all have a job now."
},
{
"row": 116,
"char": "User",
"text": "Yes."
},
{
"row": 117,
"char": "User",
"text": "We also need some practice!"
},
{
"row": 118,
"char": "Dad",
"text": "How do we practice?"
},
{
"row": 119,
"char": "User",
"text": "Use your imagination."
},
{
"row": 121,
"char": "User",
"text": "You go to Vala. I stay here. We have a space call!"
},
{
"row": 122,
"char": "Dad",
"text": "Ready for takeoff! Three... two... one!"
},
{
"row": 124,
"char": "Dad",
"text": "Ground control! Ground control! This is Astronaut Dad. Do you copy?"
},
{
"row": 125,
"char": "User",
"text": "Copy! This is ground control!"
},
{
"row": 126,
"char": "User",
"text": "What's your job today?"
},
{
"row": 127,
"char": "Dad",
"text": "My job is to fix the spaceship!"
},
{
"row": 128,
"char": "Mum",
"text": "My job is to check the stars!"
},
{
"row": 129,
"char": "Mum",
"text": "What about you, ground control? What's your job?"
},
{
"row": 130,
"char": "User",
"text": "My job is to take care of home!"
},
{
"row": 131,
"char": "Dad",
"text": "That's a great job!"
},
{
"row": 132,
"char": "Mum",
"text": "We also need you to check something."
},
{
"row": 133,
"char": "User",
"text": "What?"
},
{
"row": 134,
"char": "Mum",
"text": "Look outside. Is it a good day to fly?"
},
{
"row": 136,
"char": "User",
"text": "The sky is clear! You can fly today!"
},
{
"row": 137,
"char": "Dad",
"text": "Great news!"
},
{
"row": 138,
"char": "Mum",
"text": "Thank you, ground control!"
},
{
"row": 140,
"char": "Dad",
"text": "The astronauts are home!"
},
{
"row": 141,
"char": "User",
"text": "When you go to Vala... we also do this, right?"
},
{
"row": 142,
"char": "User",
"text": "We talk like this. Every week."
},
{
"row": 143,
"char": "Mum",
"text": "Every week. I promise."
},
{
"row": 144,
"char": "Dad",
"text": "And I also promise!"
},
{
"row": 146,
"char": "User",
"text": "Wait!"
},
{
"row": 147,
"char": "User",
"text": "We also need a team photo."
},
{
"row": 148,
"char": "Dad",
"text": "A team photo?"
},
{
"row": 149,
"char": "User",
"text": "Yes!"
},
{
"row": 151,
"char": "User",
"text": "Ready?"
},
{
"row": 152,
"char": "Dad",
"text": "Ready!"
},
{
"row": 153,
"char": "Mum",
"text": "Ready!"
},
{
"row": 154,
"char": "User",
"text": "Three... .."
},
{
"row": 155,
"char": "User",
"text": "Two..."
},
{
"row": 156,
"char": "User",
"text": "One!"
},
{
"row": 160,
"char": "User",
"text": "A great astronaut team!"
},
{
"row": 161,
"char": "User",
"text": "Dad, Mum, I think I'm ready for you to leave."
},
{
"row": 163,
"char": "Dad",
"text": "We are so proud of you, our little astronaut."
},
{
"row": 164,
"char": "Mum",
"text": "Remember, no matter how far we go, we will always love you."
}
]

View File

@ -0,0 +1,22 @@
[
{
"row": 1,
"content": "Dad: Hi baby, I do not go to work today!\nDad: We will not go out this nice afternoon, ok?\nDad: We have a long nice afternoon to play together!\nDad: We will have a cool space trip this afternoon!\nDad: I am sitting on the soft chair here now.\nDad: I am reading you a fun space picture book now.\nDad: A white spaceship flies to a bright shiny planet here.\nDad: I slowly turn over one page of the book now.\nDad: I find some pages behind are all broken now.\nDad: Oh I feel a little shy right at this moment.\nDad: Oh no! The story stops right at this page now.\nUser: I do not want this nice story to end now.\nUser: I see the corner lamp blink a little just now.\nUser: I look at that small lamp for a short while.\nUser: Oh wow! My eyes get bright all of a sudden.\nUser: Wait a minute, look at that thing over there!\nUser: That small bright lamp is right over there, look!\nUser: It is the star from the space story we read!\nDad: I put the book in my hand aside right quickly.\nDad: We do not need this old book any more, baby.\nDad: We can play this fun story out by ourselves now."
},
{
"row": 2,
"content": "Kid: I call this armchair right now!\nKid: The living room is our spaceship now!\nKid: This is the spaceship's special seat!\nKid: I'm the captain of this whole ship!\nKid: You can't sit in this seat, okay?\nKid: You will be my helper now, right?\nKid: Helpers sit on that small stool over there.\nDad: I feel a little bit sad right now.\nDad: Okay, I will do as you say.\nKid: We will start our spaceship right now!\nKid: You press this button on the remote now.\nDad: Woo-hoo, I'm so excited right now!\nDad: I'm pressing all the buttons really fast!\nDad: Oh no, the TV turned on all of a sudden!\nDad: That gave me such a big surprise!\nDad: Now I'll press the button you told me to.\nDad: Look, the fan is spinning so fast now!\nDad: I can feel the wind blowing on my face!\nDad: Yay, I pressed the right button this time!\nDad: I'm so happy right now, Captain!\nDad: Hahaha! That's so much fun!\nKid: Oh no, you pressed the wrong button, silly!\nKid: Let me show you the right button to press.\nKid: Look, my hair is blowing in the wind now!\nKid: Woo-hoo, we are flying super high now!\nKid: Our spaceship is moving really fast now!\nKid: Quick, look at the curtains over there!\nKid: The curtains are all puffed up with wind!\nKid: Yay, we are in outer space right now!"
},
{
"row": 3,
"content": "Narrator: The toy spaceship is flying through space now.\nNarrator: User sees lots of small asteroids right ahead of him.\nNarrator: Those asteroids are just couch cushions and kids toys.\nNarrator: They are spread all over the living room floor now.\nUser: Left!\nUser: Right!\nNarrator: Oh no! They have no time to get out of the way.\nNarrator: BOOM!\nNarrator: The spaceship hits the big pile of asteroids hard.\nNarrator: The armchair wheels get stuck on a soft cushion.\nNarrator: The spaceship has no power to move any more now.\nNarrator: User pushes the big control button on the chair.\nNarrator: But the silly button does not work at all.\nNarrator: What can they do to fix this problem now?\nUser: Dad!\nUser: Please push our cool spaceship for me, Dad!\nUser: I will tell you exactly which way to go!\nNarrator: Dad runs fast behind the big armchair right now.\nNarrator: He pushes the back of the chair with both hands.\nNarrator: User sits comfortably on the soft armchair seat.\nNarrator: User is in charge of telling them where to go.\nUser: Left!\nUser: Right!\nUser: Careful!\nNarrator: Dad pushes the armchair and moves forward slowly.\nNarrator: They swerve left and right through the living room.\nNarrator: They go around all the asteroids on the floor safely.\nNarrator: They pass the whole asteroid belt at last today.\nNarrator: Dad is very tired and breathes really heavily now.\nNarrator: User jumps right down from the armchair quickly.\nNarrator: User pats Dads shoulder softly with his small hand.\nUser: Good job, helper!\nNarrator: Dad smiles and gives him a quick salute back.\nNarrator: He plops down on the floor to catch his breath.\nNarrator: User climbs back onto the big armchair again now.\nNarrator: User feels very proud and keeps moving forward now."
},
{
"row": 4,
"content": "User: Sit back tight on the armchair now.\nUser: We are almost there right now, guys!\nUser: Look, the glowing planet is right ahead!\nUser: It's just the table lamp in the corner.\nUser: I saw the little lamp blink just now.\nUser: I feel a little nervous right now.\nUser: Oh, I'm so excited right now, guys!\nDad: I wanna show you a cool trick now.\nDad: Oh, here I go right now, kids!\nDad: I'm walking towards the table lamp now.\nDad: Oh no! I tripped over a wire just now!\nUser: I decide to go over there by myself.\nUser: I walk slowly towards it right now.\nUser: I reach out and touch the lamp shade gently.\nUser: Wow, the lamp stays bright all the time now!\nUser: The little bulb is connected well again now.\nUser: The whole living room turns bright right now.\nUser: The light from it is so warm and nice!\nUser: Yay! I found the glowing star finally now!\nUser: It feels so warm when I hold it!\nUser: I pick up the little lamp very carefully.\nUser: I move it next to the armchair right now.\nUser: Woo-hoo! Our little mission is all done now!"
},
{
"row": 5,
"content": "Narrator: Our happy little trip ends right now today.\nNarrator: You sit on the soft chair and relax now.\nNarrator: Warm light covers all of us slowly now.\nNarrator: Dad sits on the floor near the chair now.\nNarrator: He rests against the chair side slowly now.\nNarrator: The big room becomes very quiet right now.\nDad: We had a really nice afternoon today.\nUser: Later, we will do more nice things.\nUser: We can fly to the high moon together then."
}
]

View File

@ -0,0 +1,21 @@
Dad: Hi baby, I do not go to work today!
Dad: We will not go out this nice afternoon, ok?
Dad: We have a long nice afternoon to play together!
Dad: We will have a cool space trip this afternoon!
Dad: I am sitting on the soft chair here now.
Dad: I am reading you a fun space picture book now.
Dad: A white spaceship flies to a bright shiny planet here.
Dad: I slowly turn over one page of the book now.
Dad: I find some pages behind are all broken now.
Dad: Oh I feel a little shy right at this moment.
Dad: Oh no! The story stops right at this page now.
User: I do not want this nice story to end now.
User: I see the corner lamp blink a little just now.
User: I look at that small lamp for a short while.
User: Oh wow! My eyes get bright all of a sudden.
User: Wait a minute, look at that thing over there!
User: That small bright lamp is right over there, look!
User: It is the star from the space story we read!
Dad: I put the book in my hand aside right quickly.
Dad: We do not need this old book any more, baby.
Dad: We can play this fun story out by ourselves now.

View File

@ -0,0 +1,29 @@
Kid: I call this armchair right now!
Kid: The living room is our spaceship now!
Kid: This is the spaceship's special seat!
Kid: I'm the captain of this whole ship!
Kid: You can't sit in this seat, okay?
Kid: You will be my helper now, right?
Kid: Helpers sit on that small stool over there.
Dad: I feel a little bit sad right now.
Dad: Okay, I will do as you say.
Kid: We will start our spaceship right now!
Kid: You press this button on the remote now.
Dad: Woo-hoo, I'm so excited right now!
Dad: I'm pressing all the buttons really fast!
Dad: Oh no, the TV turned on all of a sudden!
Dad: That gave me such a big surprise!
Dad: Now I'll press the button you told me to.
Dad: Look, the fan is spinning so fast now!
Dad: I can feel the wind blowing on my face!
Dad: Yay, I pressed the right button this time!
Dad: I'm so happy right now, Captain!
Dad: Hahaha! That's so much fun!
Kid: Oh no, you pressed the wrong button, silly!
Kid: Let me show you the right button to press.
Kid: Look, my hair is blowing in the wind now!
Kid: Woo-hoo, we are flying super high now!
Kid: Our spaceship is moving really fast now!
Kid: Quick, look at the curtains over there!
Kid: The curtains are all puffed up with wind!
Kid: Yay, we are in outer space right now!

View File

@ -0,0 +1,36 @@
Narrator: The toy spaceship is flying through space now.
Narrator: User sees lots of small asteroids right ahead of him.
Narrator: Those asteroids are just couch cushions and kids toys.
Narrator: They are spread all over the living room floor now.
User: Left!
User: Right!
Narrator: Oh no! They have no time to get out of the way.
Narrator: BOOM!
Narrator: The spaceship hits the big pile of asteroids hard.
Narrator: The armchair wheels get stuck on a soft cushion.
Narrator: The spaceship has no power to move any more now.
Narrator: User pushes the big control button on the chair.
Narrator: But the silly button does not work at all.
Narrator: What can they do to fix this problem now?
User: Dad!
User: Please push our cool spaceship for me, Dad!
User: I will tell you exactly which way to go!
Narrator: Dad runs fast behind the big armchair right now.
Narrator: He pushes the back of the chair with both hands.
Narrator: User sits comfortably on the soft armchair seat.
Narrator: User is in charge of telling them where to go.
User: Left!
User: Right!
User: Careful!
Narrator: Dad pushes the armchair and moves forward slowly.
Narrator: They swerve left and right through the living room.
Narrator: They go around all the asteroids on the floor safely.
Narrator: They pass the whole asteroid belt at last today.
Narrator: Dad is very tired and breathes really heavily now.
Narrator: User jumps right down from the armchair quickly.
Narrator: User pats Dads shoulder softly with his small hand.
User: Good job, helper!
Narrator: Dad smiles and gives him a quick salute back.
Narrator: He plops down on the floor to catch his breath.
Narrator: User climbs back onto the big armchair again now.
Narrator: User feels very proud and keeps moving forward now.

View File

@ -0,0 +1,23 @@
User: Sit back tight on the armchair now.
User: We are almost there right now, guys!
User: Look, the glowing planet is right ahead!
User: It's just the table lamp in the corner.
User: I saw the little lamp blink just now.
User: I feel a little nervous right now.
User: Oh, I'm so excited right now, guys!
Dad: I wanna show you a cool trick now.
Dad: Oh, here I go right now, kids!
Dad: I'm walking towards the table lamp now.
Dad: Oh no! I tripped over a wire just now!
User: I decide to go over there by myself.
User: I walk slowly towards it right now.
User: I reach out and touch the lamp shade gently.
User: Wow, the lamp stays bright all the time now!
User: The little bulb is connected well again now.
User: The whole living room turns bright right now.
User: The light from it is so warm and nice!
User: Yay! I found the glowing star finally now!
User: It feels so warm when I hold it!
User: I pick up the little lamp very carefully.
User: I move it next to the armchair right now.
User: Woo-hoo! Our little mission is all done now!

View File

@ -0,0 +1,9 @@
Narrator: Our happy little trip ends right now today.
Narrator: You sit on the soft chair and relax now.
Narrator: Warm light covers all of us slowly now.
Narrator: Dad sits on the floor near the chair now.
Narrator: He rests against the chair side slowly now.
Narrator: The big room becomes very quiet right now.
Dad: We had a really nice afternoon today.
User: Later, we will do more nice things.
User: We can fly to the high moon together then.

View File

@ -0,0 +1,162 @@
#!/usr/bin/env python3
"""
S2 英文台词简化 + 飞书 Sheet 写回
- 简单台词5词无从句 直接复制到 F
- 复杂台词 直接 LLM 简化保留原文语义不走 gen_script 全流程
- 结果写回飞书 Sheet F
"""
import os, sys, json, time
from openai import OpenAI
import requests
# ============================================================
# 配置
# ============================================================
SPREADSHEET_TOKEN = "UK7ms9UrdhJllftVOaOc4r4envg"
SHEET_ID = "wMQVyV"
DIALOGUE_FILE = "/root/.openclaw/workspace-xiaoyan/business_production/英文台词/output/dialogue_lines_current.json"
# LLM client
client = OpenAI(
api_key="32994652-505c-492b-b6da-616ec5c5733c",
base_url="https://ark.cn-beijing.volces.com/api/v3"
)
LLM_MODEL = "ep-m-20260301164317-vmmj4"
# Feishu auth
with open("/root/.openclaw/credentials/xiaoyan/config.json") as f:
cred = json.load(f)
APP_ID = cred["apps"][0]["appId"]
APP_SECRET = cred["apps"][0]["appSecret"]
def get_fs_token():
resp = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET})
return resp.json()["tenant_access_token"]
S2_SIMPLIFY_PROMPT = """You are adapting English children's dialogue for S2 level (5-6 year old beginners).
### CRITICAL RULES
1. **PRESERVE THE EXACT MEANING** never change what the line communicates. Only simplify HOW it's said.
2. Keep sentences under 8 words each.
3. Use only simple present/past/future (will/be going to) no perfect tense, no conditionals.
4. Replace difficult words with simpler ones a 5-6 year old would know.
5. Keep natural speaking rhythm short bursts, child-friendly expressions.
6. Keep interjections (Oh!, Uh-oh, Yay!, Haha, Oops!) they add emotion.
7. Keep character names and key nouns (Vala, astronaut, spaceship, etc.).
8. If the original line is already simple enough, KEEP IT UNCHANGED.
### Format
Input: "Character: English line"
Output: English line only no character name, no explanation.
### Examples
Input: "Mum: I received a special delivery from Vala headquarters this morning."
Output: Look! A box came from Vala! It got here this morning.
Input: "User: I want to wear the astronaut uniform but it's too big for me."
Output: I want to wear this. But it's too big for me!
Input: "Dad: What are you doing with that paper and pencil?"
Output: What are you doing? What's that for?"""
def simplify_line(char, text, retries=2):
"""Simplify a single English line for S2 level"""
prompt = f"{char}: {text}"
for attempt in range(retries + 1):
try:
resp = client.chat.completions.create(
model=LLM_MODEL,
messages=[
{"role": "system", "content": S2_SIMPLIFY_PROMPT},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=200,
timeout=30,
extra_body={"thinking": {"type": "disabled"}}
)
result = resp.choices[0].message.content.strip()
# Clean up: remove character name prefix if present
if ": " in result:
parts = result.split(": ", 1)
result = parts[1].strip() if len(parts) > 1 else result.strip()
return result
except Exception as e:
if attempt < retries:
time.sleep(2)
else:
raise e
def is_simple(text):
"""Check if a line is already S2-level simple"""
words = text.split()
if len(words) > 5:
return False
clause_markers = ['because', 'which', 'that', 'when', 'if', 'after',
'before', 'while', 'although', 'since', 'until',
'unless', 'where', 'who', 'whom', 'whose']
text_lower = text.lower()
for m in clause_markers:
if f" {m} " in f" {text_lower} " or text_lower.startswith(m + " "):
return False
return True
def write_to_sheet(token, row_num, text, col_idx=5):
"""Write to column F (index 5)"""
col_letter = chr(65 + col_idx)
range_str = f"{SHEET_ID}!{col_letter}{row_num + 1}:{col_letter}{row_num + 1}"
payload = {"valueRange": {"range": range_str, "values": [[text]]}}
resp = requests.put(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=payload)
return resp.json().get("code") == 0
# ============================================================
# Main
# ============================================================
with open(DIALOGUE_FILE, "r", encoding="utf-8") as f:
items = json.load(f)
token = get_fs_token()
simple_count = 0
complex_count = 0
errors = []
for idx, item in enumerate(items):
row = item["row"]
char = item["char"]
text = item["text"]
print(f"[{idx+1}/{len(items)}] Row {row}: {char}: {text[:60]}...", end=" ", flush=True)
try:
if is_simple(text):
english = text
simple_count += 1
print("→ SIMPLE (direct)")
else:
english = simplify_line(char, text)
complex_count += 1
print(f"→ S2: {english[:50]}...")
except Exception as e:
english = text # fallback to original
errors.append((row, str(e)))
print(f"→ ERROR: {e}, fallback to original")
if write_to_sheet(token, row, english):
print(f" ✅ F{row+1}")
else:
print(f" ❌ Write failed")
errors.append((row, "Write failed"))
time.sleep(0.3)
print(f"\n{'='*60}")
print(f"DONE: {simple_count} simple + {complex_count} simplified")
print(f"Total: {len(items)}, Errors: {len(errors)}")
if errors:
for r, e in errors:
print(f" Row {r}: {e}")

View File

@ -0,0 +1,151 @@
#!/usr/bin/env python3
"""
批量英文台词生产 + 飞书 Sheet 写回脚本
- 简单台词5无从句直接复制到 F
- 复杂台词通过 gen_script.py pipeline 处理
- 结果写回飞书嵌入式 Sheet F 英文台词
"""
import os, sys, json, time, requests
# ============================================================
# 配置
# ============================================================
SPREADSHEET_TOKEN = "VgPwsodzthsk9Vti8GocrbH2nEe"
SHEET_ID = "wMQVyV"
STAGE = "S2"
DIALOGUE_FILE = "/root/.openclaw/workspace-xiaoyan/business_production/英文台词/output/dialogue_lines.json"
# OpenAI 配置
os.environ["OPENAI_API_KEY"] = "32994652-505c-492b-b6da-616ec5c5733c"
os.environ["OPENAI_BASE_URL"] = "https://ark.cn-beijing.volces.com/api/v3"
os.environ["OPENAI_MODEL"] = "ep-m-20260301164317-vmmj4"
# ============================================================
# 飞书凭证
# ============================================================
with open("/root/.openclaw/credentials/xiaoyan/config.json") as f:
cred = json.load(f)
APP_ID = cred["apps"][0]["appId"]
APP_SECRET = cred["apps"][0]["appSecret"]
def get_token():
resp = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET})
return resp.json()["tenant_access_token"]
TOKEN = get_token()
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
# ============================================================
# Import gen_script functions
# ============================================================
sys.path.insert(0, "/root/.openclaw/workspace-xiaoyan/business_production/英文台词/skills/kids-english-script-production/scripts")
from gen_script import generate_single_script, call_llm
def is_simple_line(text):
"""判断台词是否已经是 S2 级别简单句"""
words = text.split()
if len(words) > 5:
return False
clause_markers = ['because', 'which', 'that', 'when', 'if', 'after',
'before', 'while', 'although', 'since', 'until',
'unless', 'where', 'who', 'whom', 'whose']
text_lower = text.lower()
for marker in clause_markers:
if f" {marker} " in f" {text_lower} " or text_lower.startswith(marker + " "):
return False
return True
def write_to_sheet(row_num, text, col_index=5):
"""Write text to a specific cell in the sheet"""
# Column F = index 5 (0-based)
col_letter = chr(65 + col_index) # A=0, B=1, ..., F=5
cell = f"{col_letter}{row_num + 1}"
range_str = f"{SHEET_ID}!{cell}:{cell}"
payload = {
"valueRange": {
"range": range_str,
"values": [[text]]
}
}
resp = requests.put(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values",
headers=HEADERS,
json=payload)
return resp.json().get("code") == 0
# ============================================================
# Main
# ============================================================
with open(DIALOGUE_FILE, "r", encoding="utf-8") as f:
items = json.load(f)
simple_count = 0
complex_count = 0
errors = []
for idx, item in enumerate(items):
row = item["row"]
char = item["char"]
text = item["text"]
print(f"[{idx+1}/{len(items)}] Row {row}: {char}: {text[:60]}...", end=" ", flush=True)
try:
if is_simple_line(text):
# Simple line - copy directly
english = text
simple_count += 1
print(f"→ SIMPLE (direct copy)")
else:
# Complex line - process through pipeline
complex_count += 1
input_text = f"{char}: {text}"
result = generate_single_script(input_text, STAGE, verbose=False)
# Extract clean English from pipeline result
result_str = str(result)
# Remove trace report
trace_marker = "\n" + "=" * 60 + "\n📋"
if trace_marker in result_str:
result_str = result_str[:result_str.index(trace_marker)].strip()
# Remove stage header
lines = result_str.split("\n")
if lines and lines[0].startswith(""):
lines = lines[1:]
# Extract the English text after "角色: "
english_lines = []
for line in lines:
line = line.strip()
if line and ": " in line:
# Format: "角色: English text"
parts = line.split(": ", 1)
if len(parts) == 2:
english_lines.append(parts[1].strip())
english = " ".join(english_lines) if english_lines else text
print(f"→ COMPLEX (pipeline: {english[:50]}...)")
except Exception as e:
# On any error, fallback to original text
english = text
errors.append((row, str(e)))
print(f"→ ERROR: {e}, using original")
# Write to sheet
if write_to_sheet(row, english):
print(f" ✅ Written to F{row+1}")
else:
print(f" ❌ Write failed for row {row}")
errors.append((row, "Write failed"))
# Rate limit
time.sleep(0.3)
# Summary
print(f"\n{'='*60}")
print(f"DONE: {simple_count} simple (direct copy) + {complex_count} pipeline processed")
print(f"Total: {len(items)}, Errors: {len(errors)}")
if errors:
print("Errors:")
for r, e in errors:
print(f" Row {r}: {e}")

View File

@ -191,7 +191,8 @@ def call_llm(prompt, stage, max_retries=3):
], ],
temperature=temp, temperature=temp,
max_tokens=2000, max_tokens=2000,
timeout=60 timeout=180,
extra_body={"thinking": {"type": "disabled"}}
) )
return response.choices[0].message.content, None return response.choices[0].message.content, None
except Exception as e: except Exception as e:

View File

@ -44,3 +44,15 @@
{"type":"memory.recall.recorded","timestamp":"2026-05-21T07:39:38.958Z","query":"组件生产 回填 G列 互动","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-05-21T07:39:38.958Z","query":"组件生产 回填 G列 互动","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-21T09:52:45.581Z","query":"李应瑛 user_id 权限","resultCount":1,"results":[{"path":"memory/2026-05-07.md","startLine":71,"endLine":88,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-05-21T09:52:45.581Z","query":"李应瑛 user_id 权限","resultCount":1,"results":[{"path":"memory/2026-05-07.md","startLine":71,"endLine":88,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-22T07:04:01.804Z","query":"abilityTag 标准库 45条 tag 标签","resultCount":5,"results":[{"path":"memory/2026-05-12.md","startLine":170,"endLine":193,"score":1},{"path":"memory/2026-05-12.md","startLine":206,"endLine":226,"score":1},{"path":"memory/2026-05-12.md","startLine":92,"endLine":113,"score":1},{"path":"memory/2026-05-12.md","startLine":48,"endLine":68,"score":1},{"path":"memory/2026-05-12.md","startLine":122,"endLine":138,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-05-22T07:04:01.804Z","query":"abilityTag 标准库 45条 tag 标签","resultCount":5,"results":[{"path":"memory/2026-05-12.md","startLine":170,"endLine":193,"score":1},{"path":"memory/2026-05-12.md","startLine":206,"endLine":226,"score":1},{"path":"memory/2026-05-12.md","startLine":92,"endLine":113,"score":1},{"path":"memory/2026-05-12.md","startLine":48,"endLine":68,"score":1},{"path":"memory/2026-05-12.md","startLine":122,"endLine":138,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T01:44:48.648Z","query":"写作题 单元挑战 P xiezuo 生产规则","resultCount":1,"results":[{"path":"memory/2026-05-12.md","startLine":137,"endLine":149,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T01:44:48.649Z","query":"021301 021401 单元编号 bitable 多维表格","resultCount":4,"results":[{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1},{"path":"memory/2026-05-08.md","startLine":51,"endLine":73,"score":1},{"path":"memory/2026-05-12.md","startLine":258,"endLine":281,"score":1},{"path":"memory/2026-05-12.md","startLine":206,"endLine":226,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T01:45:24.016Z","query":"021301 021401 021501 写作 单元挑战","resultCount":4,"results":[{"path":"memory/2026-05-14.md","startLine":64,"endLine":93,"score":1},{"path":"memory/2026-05-14.md","startLine":123,"endLine":144,"score":1},{"path":"memory/2026-05-13.md","startLine":1,"endLine":29,"score":1},{"path":"memory/2026-05-14.md","startLine":162,"endLine":188,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T04:13:09.891Z","query":"听力选择 组件 配置格式 listening choice component","resultCount":3,"results":[{"path":"memory/2026-05-18.md","startLine":23,"endLine":49,"score":1},{"path":"memory/2026-05-18.md","startLine":542,"endLine":570,"score":1},{"path":"memory/2026-05-18.md","startLine":653,"endLine":680,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T05:42:36.847Z","query":"英文台词生产 pipeline 脚本 流程","resultCount":5,"results":[{"path":"memory/2026-05-18.md","startLine":793,"endLine":810,"score":1},{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1},{"path":"memory/2026-05-08.md","startLine":18,"endLine":38,"score":1},{"path":"memory/2026-05-18.md","startLine":440,"endLine":486,"score":1},{"path":"memory/2026-05-18.md","startLine":583,"endLine":633,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T06:38:20.252Z","query":"英文台词 batch_write gen_script API key volces ark","resultCount":3,"results":[{"path":"memory/2026-05-18.md","startLine":793,"endLine":810,"score":1},{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1},{"path":"memory/2026-05-08.md","startLine":18,"endLine":38,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T08:47:02.076Z","query":"单元挑战 题型 生产 审校 阶段 分配","resultCount":6,"results":[{"path":"memory/2026-05-12.md","startLine":137,"endLine":149,"score":1},{"path":"memory/2026-05-18.md","startLine":479,"endLine":508,"score":1},{"path":"memory/2026-05-18.md","startLine":440,"endLine":486,"score":1},{"path":"memory/2026-05-18.md","startLine":620,"endLine":663,"score":1},{"path":"memory/2026-05-14.md","startLine":123,"endLine":144,"score":1},{"path":"memory/2026-05-14.md","startLine":64,"endLine":93,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T08:53:31.758Z","query":"难度 A B C D 分级 Starters Movers Flyers KET","resultCount":7,"results":[{"path":"memory/2026-05-07.md","startLine":263,"endLine":280,"score":1},{"path":"memory/2026-05-07.md","startLine":230,"endLine":253,"score":1},{"path":"memory/2026-05-07.md","startLine":199,"endLine":219,"score":1},{"path":"memory/2026-05-14.md","startLine":123,"endLine":144,"score":1},{"path":"memory/2026-05-07.md","startLine":215,"endLine":235,"score":1},{"path":"memory/2026-05-14.md","startLine":108,"endLine":129,"score":1},{"path":"memory/2026-05-18.md","startLine":305,"endLine":346,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T08:56:25.107Z","query":"对话组件配置 bitable 多维表格 写入","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T08:56:25.107Z","query":"组件配租 组件配置流程 dialogue component","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T08:56:32.837Z","query":"组件配置JSON pipeline 生成 脚本 generate interactive component","resultCount":2,"results":[{"path":"memory/2026-05-07.md","startLine":354,"endLine":368,"score":1},{"path":"memory/2026-04-22.md","startLine":1,"endLine":8,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-25T09:34:43.114Z","query":"角色多个ID character multiple IDs 组件配置","resultCount":1,"results":[{"path":"memory/2026-05-07.md","startLine":86,"endLine":107,"score":1}]}

View File

@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"updatedAt": "2026-05-22T07:04:01.804Z", "updatedAt": "2026-05-25T09:34:43.114Z",
"entries": { "entries": {
"memory:memory/2026-05-07.md:57:74": { "memory:memory/2026-05-07.md:57:74": {
"key": "memory:memory/2026-05-07.md:57:74", "key": "memory:memory/2026-05-07.md:57:74",
@ -42,20 +42,22 @@
"endLine": 235, "endLine": 235,
"source": "memory", "source": "memory",
"snippet": "3. He is (4) Japan. → from男孩穿和服背景富士山 4. She is a (7). → student女孩背书包进校门 - **JSON 结构:** questionSetID=020102, category=writing, type=writing_pic_qa - **关键教训:** - 初版设计错误:让学手写 Anna/China 等非知识点词,被用户纠正 - 初版 questionDesc \"She is a (7) girl.\" 不自然,修正为 \"She is a (7).\" - writing_pic_qa 题型核心考察点知识点词本身am/from而非题干已知信息 - 挖空字母数标记(如(4))必须与答案单词字母数一致 - **词库缺口发现:** L1和L2词库均缺失人称代词(I/you/he/she)、be动词(am/is/are)、介词(from)、国家名等基础功能词,写题时先绕过词汇校验硬性约束 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 单元挑战新增3个题型已完结 - 详见上文 11:19-11:28 记录 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 写作看图回答题 \"I am ready / Thank you\" 样题生产 - **时间:** 15:53 ~ 15:55 - **需求:** 使用知识点 \"I am ready! / Thank you for...\" 再生产一套", "snippet": "3. He is (4) Japan. → from男孩穿和服背景富士山 4. She is a (7). → student女孩背书包进校门 - **JSON 结构:** questionSetID=020102, category=writing, type=writing_pic_qa - **关键教训:** - 初版设计错误:让学手写 Anna/China 等非知识点词,被用户纠正 - 初版 questionDesc \"She is a (7) girl.\" 不自然,修正为 \"She is a (7).\" - writing_pic_qa 题型核心考察点知识点词本身am/from而非题干已知信息 - 挖空字母数标记(如(4))必须与答案单词字母数一致 - **词库缺口发现:** L1和L2词库均缺失人称代词(I/you/he/she)、be动词(am/is/are)、介词(from)、国家名等基础功能词,写题时先绕过词汇校验硬性约束 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 单元挑战新增3个题型已完结 - 详见上文 11:19-11:28 记录 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 写作看图回答题 \"I am ready / Thank you\" 样题生产 - **时间:** 15:53 ~ 15:55 - **需求:** 使用知识点 \"I am ready! / Thank you for...\" 再生产一套",
"recallCount": 2, "recallCount": 3,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 2, "totalScore": 3,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-08T01:18:18.412Z", "firstRecalledAt": "2026-05-08T01:18:18.412Z",
"lastRecalledAt": "2026-05-11T02:37:23.203Z", "lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [ "queryHashes": [
"390d35f8d143", "390d35f8d143",
"be437071312f" "be437071312f",
"12653110bb68"
], ],
"recallDays": [ "recallDays": [
"2026-05-08", "2026-05-08",
"2026-05-11" "2026-05-11",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"writing-pic-qa", "writing-pic-qa",
@ -75,20 +77,22 @@
"endLine": 219, "endLine": 219,
"source": "memory", "source": "memory",
"snippet": "### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 写作看图回答题 \"I am... / I am from...\" 样题生产 - **时间:** 15:38 ~ 15:52 - **需求:** 使用知识点 \"I am... / I am from...\" 生产一套写作看图回答题writing_pic_qa - **状态:** ✅ 已完成,用户确认 - **题型级别:** L2因L1词库缺少所有代词/be动词/介词/国家名) - **难度:** A级 - **题量:** 4小题 - **核心原则(用户明确):** 1. 挖空必须是考察知识点本身的单词am/from/student不是手写姓名/国名等附带信息 2. 只能为1个单词挖空不能两个及以上 3. 正确模式示例:`I (2) Anna.` → 挖空am数字标记字母数 4. 图片提供语境线索名牌→am地标→from国家书包→student学生填写核心知识点词 - **输出文件:** `output/writing_pic_qa_I_am_from_020102.json` - **题目清单:** 1. I (2) Anna. → am女孩指着名牌图片语境提示姓名已给出 2. I am (4) China. → from女孩站在长城前国家名已给出 3. He is (4) Japan. → from男孩穿和服背景富士山 4. She is a (7). → student女孩背书包进校门 - **JSON", "snippet": "### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 写作看图回答题 \"I am... / I am from...\" 样题生产 - **时间:** 15:38 ~ 15:52 - **需求:** 使用知识点 \"I am... / I am from...\" 生产一套写作看图回答题writing_pic_qa - **状态:** ✅ 已完成,用户确认 - **题型级别:** L2因L1词库缺少所有代词/be动词/介词/国家名) - **难度:** A级 - **题量:** 4小题 - **核心原则(用户明确):** 1. 挖空必须是考察知识点本身的单词am/from/student不是手写姓名/国名等附带信息 2. 只能为1个单词挖空不能两个及以上 3. 正确模式示例:`I (2) Anna.` → 挖空am数字标记字母数 4. 图片提供语境线索名牌→am地标→from国家书包→student学生填写核心知识点词 - **输出文件:** `output/writing_pic_qa_I_am_from_020102.json` - **题目清单:** 1. I (2) Anna. → am女孩指着名牌图片语境提示姓名已给出 2. I am (4) China. → from女孩站在长城前国家名已给出 3. He is (4) Japan. → from男孩穿和服背景富士山 4. She is a (7). → student女孩背书包进校门 - **JSON",
"recallCount": 2, "recallCount": 3,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 2, "totalScore": 3,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-08T01:18:18.412Z", "firstRecalledAt": "2026-05-08T01:18:18.412Z",
"lastRecalledAt": "2026-05-11T02:37:23.203Z", "lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [ "queryHashes": [
"390d35f8d143", "390d35f8d143",
"be437071312f" "be437071312f",
"12653110bb68"
], ],
"recallDays": [ "recallDays": [
"2026-05-08", "2026-05-08",
"2026-05-11" "2026-05-11",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"writing-pic-qa", "writing-pic-qa",
@ -183,26 +187,30 @@
"endLine": 55, "endLine": 55,
"source": "memory", "source": "memory",
"snippet": "**图片资源新规:** - 每个题组共享一张图(非每题独立配图) - 产出 JSON 同时输出图片描述 prompt英文卡通简线条风格 - prompt 写入 bitable `图片描述` 列,格式 `{\"first\": \"...\", \"second\": \"...\"}` **通用化写入流程:** - 单元挑战全题型适用:定位 bitable 表 → 创建/更新记录 → 写入 `题目集合 ID` + `jsonData` + `图片描述` - 各题型仅 jsonData 结构不同,写入流程统一 **重写文件:** - `business_production/单元挑战/skills/unit_challenge/questions/writing/common/writing_pic_qa/SKILL.md`11节完整规范 - `business_production/单元挑战/skills/unit_challenge/questions/writing/writing_pic_qa/SKILL.md`(简化为快速入口) **bitable 更新:** 已将新 JSON每题组1图2题+ 图片描述写入 `recviZlAxxXlAb` ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 图片描述格式修正 - **时间:** 09:46 ~ 09:51 - **修正:** 用户给出中文样例格式,要求图片描述从英文 prompt 改为纯中文结构化列表 - **新格式:** 编号 `1.` / `2.` 自上而下,每段", "snippet": "**图片资源新规:** - 每个题组共享一张图(非每题独立配图) - 产出 JSON 同时输出图片描述 prompt英文卡通简线条风格 - prompt 写入 bitable `图片描述` 列,格式 `{\"first\": \"...\", \"second\": \"...\"}` **通用化写入流程:** - 单元挑战全题型适用:定位 bitable 表 → 创建/更新记录 → 写入 `题目集合 ID` + `jsonData` + `图片描述` - 各题型仅 jsonData 结构不同,写入流程统一 **重写文件:** - `business_production/单元挑战/skills/unit_challenge/questions/writing/common/writing_pic_qa/SKILL.md`11节完整规范 - `business_production/单元挑战/skills/unit_challenge/questions/writing/writing_pic_qa/SKILL.md`(简化为快速入口) **bitable 更新:** 已将新 JSON每题组1图2题+ 图片描述写入 `recviZlAxxXlAb` ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 图片描述格式修正 - **时间:** 09:46 ~ 09:51 - **修正:** 用户给出中文样例格式,要求图片描述从英文 prompt 改为纯中文结构化列表 - **新格式:** 编号 `1.` / `2.` 自上而下,每段",
"recallCount": 6, "recallCount": 9,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 6, "totalScore": 9,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-11T02:19:37.985Z", "firstRecalledAt": "2026-05-11T02:19:37.985Z",
"lastRecalledAt": "2026-05-20T06:31:39.981Z", "lastRecalledAt": "2026-05-25T06:38:20.252Z",
"queryHashes": [ "queryHashes": [
"6f88450e9f9b", "6f88450e9f9b",
"be437071312f", "be437071312f",
"11ea0881b126", "11ea0881b126",
"08b6f3142a2b", "08b6f3142a2b",
"d3bb2a2fd2ad", "d3bb2a2fd2ad",
"688d2dceca9d" "688d2dceca9d",
"37d5e066d57f",
"e637236fe74b",
"14d903a64d04"
], ],
"recallDays": [ "recallDays": [
"2026-05-11", "2026-05-11",
"2026-05-13", "2026-05-13",
"2026-05-18", "2026-05-18",
"2026-05-20" "2026-05-20",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"创建/更新记录", "创建/更新记录",
@ -378,24 +386,26 @@
"endLine": 226, "endLine": 226,
"source": "memory", "source": "memory",
"snippet": "- **10 条 sentenceMeaningMeaning JSON 修复:** - 根因explanation 中 ASCII `\"` 被用作中文引号 - 修复策略演变:状态机拆分失败 → 正则重建 → 发现Q2丢失 → 从中文列完整重建 - 最终10/10 可正确解析,审校结果同步更新 - 受影响1213004/1213006/1213010/1214008/1215005/1216001/1216004/1216007/1216008/1216010 ### 刘彦江 — 核心互动全题型 JSON 配置标准沉淀17:05 ~ 17:50 - **产出 Skill 1** `skills/bitable-reader/SKILL.md` — 通用 bitable 读取(任何 bitable 通用) - **产出 Skill 2** `skills/core-content-json-standard/SKILL.md` v2.0 — 全题型 JSON 标准393行 - **架构:** 通用字段在前ID/kpInfo/taskData+ 5大题型分类📖阅读2 🎧听力3 🗣口语4 ✏写作5+ 审校规则 + 扩展指南 - **覆盖率:** 14/15 种题型(口语探讨 S0 无数据) - **产出脚本:** `scripts/audit_core_reading_S0.py` — 合作阅读 S0 审校 ## 经验教训 ### bitable 写入需严格流程管控2026-05-12 - 批量更新 JSON写入前完整提取", "snippet": "- **10 条 sentenceMeaningMeaning JSON 修复:** - 根因explanation 中 ASCII `\"` 被用作中文引号 - 修复策略演变:状态机拆分失败 → 正则重建 → 发现Q2丢失 → 从中文列完整重建 - 最终10/10 可正确解析,审校结果同步更新 - 受影响1213004/1213006/1213010/1214008/1215005/1216001/1216004/1216007/1216008/1216010 ### 刘彦江 — 核心互动全题型 JSON 配置标准沉淀17:05 ~ 17:50 - **产出 Skill 1** `skills/bitable-reader/SKILL.md` — 通用 bitable 读取(任何 bitable 通用) - **产出 Skill 2** `skills/core-content-json-standard/SKILL.md` v2.0 — 全题型 JSON 标准393行 - **架构:** 通用字段在前ID/kpInfo/taskData+ 5大题型分类📖阅读2 🎧听力3 🗣口语4 ✏写作5+ 审校规则 + 扩展指南 - **覆盖率:** 14/15 种题型(口语探讨 S0 无数据) - **产出脚本:** `scripts/audit_core_reading_S0.py` — 合作阅读 S0 审校 ## 经验教训 ### bitable 写入需严格流程管控2026-05-12 - 批量更新 JSON写入前完整提取",
"recallCount": 4, "recallCount": 5,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 5,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-13T03:09:54.362Z", "firstRecalledAt": "2026-05-13T03:09:54.362Z",
"lastRecalledAt": "2026-05-22T07:04:01.804Z", "lastRecalledAt": "2026-05-25T01:44:48.649Z",
"queryHashes": [ "queryHashes": [
"f151bc633ad1", "f151bc633ad1",
"a0932e0e2749", "a0932e0e2749",
"3f9471df9e50", "3f9471df9e50",
"d13d58b4704a" "d13d58b4704a",
"37d5e066d57f"
], ],
"recallDays": [ "recallDays": [
"2026-05-13", "2026-05-13",
"2026-05-15", "2026-05-15",
"2026-05-19", "2026-05-19",
"2026-05-22" "2026-05-22",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"10/10", "10/10",
@ -844,26 +854,30 @@
"endLine": 368, "endLine": 368,
"source": "memory", "source": "memory",
"snippet": "- **需求:** 将 020102I am...)和 020103I am ready / Thank you两套题合并为一个 `{first:..., second:...}` JSON统一 questionSetID=0000001 - **状态:** ✅ 已完成 - **核心考点分析(用户强调):** 需分析每个句型的核心考点(孩子最容易犯错的地方),挖空对准核心考点 - I am/from 组am系动词第一人称、from介词选择、studenta+名词结构) - Thank you for 组for介词选择非 you、helpingfor+动名词,非 help/to help - **输出文件:** `output/writing_pic_qa_combined.json` ### 刘彦江 — 组件配置-json 请求L1-S2-U13-L4 沙漠之花) - **时间:** 16:45 ~ 17:51 - **文档:** `https://makee-interactive.feishu.cn/wiki/K5E1wzwk7it9t7kXvcbc6Xugnhc` - **状态:** ⚠️ 未完成 — pipeline 识别到 0 组件 - **根因:** 剧本文档的13个组件数据存储在 markdown 内联表格中lark-table5列×36行而非内嵌 Sheet。当前 pipeline 的 parse_script 只从内嵌 Sheet 读取组件数据,不支持 markdown 表格组件解析 - **已识别组件ma", "snippet": "- **需求:** 将 020102I am...)和 020103I am ready / Thank you两套题合并为一个 `{first:..., second:...}` JSON统一 questionSetID=0000001 - **状态:** ✅ 已完成 - **核心考点分析(用户强调):** 需分析每个句型的核心考点(孩子最容易犯错的地方),挖空对准核心考点 - I am/from 组am系动词第一人称、from介词选择、studenta+名词结构) - Thank you for 组for介词选择非 you、helpingfor+动名词,非 help/to help - **输出文件:** `output/writing_pic_qa_combined.json` ### 刘彦江 — 组件配置-json 请求L1-S2-U13-L4 沙漠之花) - **时间:** 16:45 ~ 17:51 - **文档:** `https://makee-interactive.feishu.cn/wiki/K5E1wzwk7it9t7kXvcbc6Xugnhc` - **状态:** ⚠️ 未完成 — pipeline 识别到 0 组件 - **根因:** 剧本文档的13个组件数据存储在 markdown 内联表格中lark-table5列×36行而非内嵌 Sheet。当前 pipeline 的 parse_script 只从内嵌 Sheet 读取组件数据,不支持 markdown 表格组件解析 - **已识别组件ma",
"recallCount": 6, "recallCount": 9,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 6, "totalScore": 9,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-15T07:13:08.147Z", "firstRecalledAt": "2026-05-15T07:13:08.147Z",
"lastRecalledAt": "2026-05-21T07:39:38.958Z", "lastRecalledAt": "2026-05-25T08:56:32.837Z",
"queryHashes": [ "queryHashes": [
"08364c8746ab", "08364c8746ab",
"4f08741ab4fd", "4f08741ab4fd",
"6a1144a866c9", "6a1144a866c9",
"65b539c56ec3", "65b539c56ec3",
"19c873a71799", "19c873a71799",
"47f8c15000b2" "47f8c15000b2",
"612fa3b04b06",
"d6a04b711fd9",
"8742c0bf4e2b"
], ],
"recallDays": [ "recallDays": [
"2026-05-15", "2026-05-15",
"2026-05-17", "2026-05-17",
"2026-05-18", "2026-05-18",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"am/from", "am/from",
@ -883,25 +897,29 @@
"endLine": 8, "endLine": 8,
"source": "memory", "source": "memory",
"snippet": "[李应瑛 2026-04-22 提出要求] 所有需要包含对话的内容(如剧本、互动组件等)必须要有【后置对话】字段,无后置对话时填写“无”。 [李应瑛 2026-04-22 确认规则] 剧本内嵌表格组件填写位置规则仅当表格第一列A列明确标注为对话类类型对话朗读/对话挖空/对话选读/对话组句等才在同一行的H列【组件】列填写对应的组件内容其他类型行TL/场景/角色/图片/非对话类等)无需填写。 [李应瑛 2026-04-22 确认格式规则] 对话类组件字段换行规则:每个结构单独占一行,格式为: 【任务标题】xxx 【情境引入】xxx 【互动内容】xxx 【后置对话】xxx 单元格内使用\\n作为换行符实现后续所有组件均遵循此格式。", "snippet": "[李应瑛 2026-04-22 提出要求] 所有需要包含对话的内容(如剧本、互动组件等)必须要有【后置对话】字段,无后置对话时填写“无”。 [李应瑛 2026-04-22 确认规则] 剧本内嵌表格组件填写位置规则仅当表格第一列A列明确标注为对话类类型对话朗读/对话挖空/对话选读/对话组句等才在同一行的H列【组件】列填写对应的组件内容其他类型行TL/场景/角色/图片/非对话类等)无需填写。 [李应瑛 2026-04-22 确认格式规则] 对话类组件字段换行规则:每个结构单独占一行,格式为: 【任务标题】xxx 【情境引入】xxx 【互动内容】xxx 【后置对话】xxx 单元格内使用\\n作为换行符实现后续所有组件均遵循此格式。",
"recallCount": 5, "recallCount": 8,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 5, "totalScore": 8,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-15T07:13:08.147Z", "firstRecalledAt": "2026-05-15T07:13:08.147Z",
"lastRecalledAt": "2026-05-21T07:39:38.958Z", "lastRecalledAt": "2026-05-25T08:56:32.837Z",
"queryHashes": [ "queryHashes": [
"08364c8746ab", "08364c8746ab",
"4f08741ab4fd", "4f08741ab4fd",
"6a1144a866c9", "6a1144a866c9",
"19c873a71799", "19c873a71799",
"47f8c15000b2" "47f8c15000b2",
"612fa3b04b06",
"d6a04b711fd9",
"8742c0bf4e2b"
], ],
"recallDays": [ "recallDays": [
"2026-05-15", "2026-05-15",
"2026-05-17", "2026-05-17",
"2026-05-18", "2026-05-18",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"对话朗读/对话挖空/对话选读/对话组句等", "对话朗读/对话挖空/对话选读/对话组句等",
@ -952,19 +970,22 @@
"endLine": 149, "endLine": 149,
"source": "memory", "source": "memory",
"snippet": "- **根因:** explanation 文本中的 ASCII `\"` (U+0022) 被当作中文双引号使用JSON 解析器将其视为字符串终止符 - **修复策略:** 从「句意选择题」中文列提取英文原句和选项 → json.dumps 重建标准 JSON只修格式不修内容 - **1216007 特殊处理:** 原始 JSON 损坏严重,需从中文列完全重建 - **二次修复Q2 丢失问题):** 首次不完全修复导致 9 条记录的 Q2 被覆盖丢失,且 Q1 被 JSON 垃圾污染 → 从中文列全面重建 Q1+Q2 - **最终结果10/10 条记录 sentenceMeaningMeaning 均可 json.loads 正确解析,每条含 2 题,无残留垃圾数据** - **受影响记录:** 1213004, 1213006, 1213010, 1214008, 1215005, 1216001, 1216004, 1216007, 1216008, 1216010 - **审校结果同步更新:** 移除所有 10 条的 `❌ JSON 解析失败` 标记 - **注意:** Q1 explanation 在重建时词表述可能微调(内容含义一致),如需精确原始 wording 可从中文列恢复后人工微调 ## 经验教训 ### bitable 写入需严格流程管控2026-05-12 - 批量更新 JSON 字段时必须:写入前完整提取原始数据 → 写入后逐字段 diff 验证 → 发现异常立即回滚", "snippet": "- **根因:** explanation 文本中的 ASCII `\"` (U+0022) 被当作中文双引号使用JSON 解析器将其视为字符串终止符 - **修复策略:** 从「句意选择题」中文列提取英文原句和选项 → json.dumps 重建标准 JSON只修格式不修内容 - **1216007 特殊处理:** 原始 JSON 损坏严重,需从中文列完全重建 - **二次修复Q2 丢失问题):** 首次不完全修复导致 9 条记录的 Q2 被覆盖丢失,且 Q1 被 JSON 垃圾污染 → 从中文列全面重建 Q1+Q2 - **最终结果10/10 条记录 sentenceMeaningMeaning 均可 json.loads 正确解析,每条含 2 题,无残留垃圾数据** - **受影响记录:** 1213004, 1213006, 1213010, 1214008, 1215005, 1216001, 1216004, 1216007, 1216008, 1216010 - **审校结果同步更新:** 移除所有 10 条的 `❌ JSON 解析失败` 标记 - **注意:** Q1 explanation 在重建时词表述可能微调(内容含义一致),如需精确原始 wording 可从中文列恢复后人工微调 ## 经验教训 ### bitable 写入需严格流程管控2026-05-12 - 批量更新 JSON 字段时必须:写入前完整提取原始数据 → 写入后逐字段 diff 验证 → 发现异常立即回滚",
"recallCount": 2, "recallCount": 4,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 2, "totalScore": 4,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-18T02:42:25.325Z", "firstRecalledAt": "2026-05-18T02:42:25.325Z",
"lastRecalledAt": "2026-05-18T09:02:50.278Z", "lastRecalledAt": "2026-05-25T08:47:02.076Z",
"queryHashes": [ "queryHashes": [
"6b577a0b3971", "6b577a0b3971",
"3069a934195d" "3069a934195d",
"68f309fb88a7",
"d8cc1fcace47"
], ],
"recallDays": [ "recallDays": [
"2026-05-18" "2026-05-18",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"json.dumps", "json.dumps",
@ -1179,23 +1200,27 @@
"endLine": 144, "endLine": 144,
"source": "memory", "source": "memory",
"snippet": "## [刘彦江] 写作+口语 C级 032501-032901 生产2026-05-14 15:42 ### 生产内容10条 | # | 表 | QSID | record_id | 题型 | 主题 | 难度 | |---|-----|------|-----------|------|------|------| | 1 | 写作-P1 | 032501 | recvjzXjMKAQ4i | 邮件组句 | 鼓励朋友参加音乐会 | C | | 2 | 写作-P1 | 032601 | recvjzXklYIE05 | 邮件组句 | 给老师写感谢信 | C | | 3 | 写作-P1 | 032701 | recvjzXkYnsQ8r | 邮件组句 | 描述咖啡馆和遇到的人 | C | | 4 | 写作-P1 | 032801 | recvjzXlxz4r3i | 邮件组句 | 科学项目求助 | C | | 5 | 写作-P1 | 032901 | recvjzXm5yEXBY | 邮件组句 | 妈妈的生日派对 | C | | 6 | 口语-P1 | 032501 | recvjzWP7IcA8O | 日常回答 | 观点转变与过去习惯 | C | | 7 | 口语-P1 | 032701 | recvjzWPQc5JZW | 日常回答 | 好奇心与想法改变 | C | | 8 | 口语-P1 | 032901 | recvjzWQr0Kif7 | 日常回答 | 团队合作与沟通 | C | | 9 | 口语-P2 | 032601 | recvjzWR07LSna |", "snippet": "## [刘彦江] 写作+口语 C级 032501-032901 生产2026-05-14 15:42 ### 生产内容10条 | # | 表 | QSID | record_id | 题型 | 主题 | 难度 | |---|-----|------|-----------|------|------|------| | 1 | 写作-P1 | 032501 | recvjzXjMKAQ4i | 邮件组句 | 鼓励朋友参加音乐会 | C | | 2 | 写作-P1 | 032601 | recvjzXklYIE05 | 邮件组句 | 给老师写感谢信 | C | | 3 | 写作-P1 | 032701 | recvjzXkYnsQ8r | 邮件组句 | 描述咖啡馆和遇到的人 | C | | 4 | 写作-P1 | 032801 | recvjzXlxz4r3i | 邮件组句 | 科学项目求助 | C | | 5 | 写作-P1 | 032901 | recvjzXm5yEXBY | 邮件组句 | 妈妈的生日派对 | C | | 6 | 口语-P1 | 032501 | recvjzWP7IcA8O | 日常回答 | 观点转变与过去习惯 | C | | 7 | 口语-P1 | 032701 | recvjzWPQc5JZW | 日常回答 | 好奇心与想法改变 | C | | 8 | 口语-P1 | 032901 | recvjzWQr0Kif7 | 日常回答 | 团队合作与沟通 | C | | 9 | 口语-P2 | 032601 | recvjzWR07LSna |",
"recallCount": 4, "recallCount": 7,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 7,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-18T11:35:06.740Z", "firstRecalledAt": "2026-05-18T11:35:06.740Z",
"lastRecalledAt": "2026-05-21T02:47:43.415Z", "lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [ "queryHashes": [
"2a58080272be", "2a58080272be",
"e3188fdd52d6", "e3188fdd52d6",
"8ccf25e60418", "8ccf25e60418",
"f76487d76697" "f76487d76697",
"e8e31d8a03aa",
"d8cc1fcace47",
"12653110bb68"
], ],
"recallDays": [ "recallDays": [
"2026-05-18", "2026-05-18",
"2026-05-19", "2026-05-19",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"032501-032901", "032501-032901",
@ -1215,23 +1240,26 @@
"endLine": 93, "endLine": 93,
"source": "memory", "source": "memory",
"snippet": "| 10 | P5 | recvjuiypW7mZY | 补审校结果(之前漏写) | | 11 | P4 | recvjufM76frUP | 缺second题组→人工确认豁免 | | - | P7 | recviZIWmT91yS | ⏭️ 人工确认跳过 | ### 最终状态 - ✅ 通过 48条 | ⏭️ 跳过 2条 | 🔴 0条 - 全部有内容的记录审校通过 ## [刘彦江] 写作+口语题目生产2026-05-14 12:10 ### 生产内容6条 | # | 表 | QSID | record_id | 题型 | first | second | |---|-----|------|-----------|------|-------|--------| | 1 | 写作-P1-邮件回复 | 021801 | recvjz5GeTe9aB | writing_email | 6句排序 | — | | 2 | 写作-P1-邮件回复 | 021901 | recvjz5GE2LKi9 | writing_email | 7句排序 | — | | 3 | 写作-P1-邮件回复 | 022001 | recvjz5H3s5k8y | writing_email | 6句排序 | — | | 4 | 口语-P2-话题讨论 | 021801 | recvjz5Hs8gpCJ | speaking_topic | 5题 | 5题 | | 5 | 口语-P1-日常回答 | 021901 | recvjz5HSdc0nZ | speaking_qa | 4题 | 4题", "snippet": "| 10 | P5 | recvjuiypW7mZY | 补审校结果(之前漏写) | | 11 | P4 | recvjufM76frUP | 缺second题组→人工确认豁免 | | - | P7 | recviZIWmT91yS | ⏭️ 人工确认跳过 | ### 最终状态 - ✅ 通过 48条 | ⏭️ 跳过 2条 | 🔴 0条 - 全部有内容的记录审校通过 ## [刘彦江] 写作+口语题目生产2026-05-14 12:10 ### 生产内容6条 | # | 表 | QSID | record_id | 题型 | first | second | |---|-----|------|-----------|------|-------|--------| | 1 | 写作-P1-邮件回复 | 021801 | recvjz5GeTe9aB | writing_email | 6句排序 | — | | 2 | 写作-P1-邮件回复 | 021901 | recvjz5GE2LKi9 | writing_email | 7句排序 | — | | 3 | 写作-P1-邮件回复 | 022001 | recvjz5H3s5k8y | writing_email | 6句排序 | — | | 4 | 口语-P2-话题讨论 | 021801 | recvjz5Hs8gpCJ | speaking_topic | 5题 | 5题 | | 5 | 口语-P1-日常回答 | 021901 | recvjz5HSdc0nZ | speaking_qa | 4题 | 4题",
"recallCount": 4, "recallCount": 6,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 6,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-18T11:35:06.740Z", "firstRecalledAt": "2026-05-18T11:35:06.740Z",
"lastRecalledAt": "2026-05-21T02:47:43.415Z", "lastRecalledAt": "2026-05-25T08:47:02.076Z",
"queryHashes": [ "queryHashes": [
"2a58080272be", "2a58080272be",
"e3188fdd52d6", "e3188fdd52d6",
"8ccf25e60418", "8ccf25e60418",
"f76487d76697" "f76487d76697",
"e8e31d8a03aa",
"d8cc1fcace47"
], ],
"recallDays": [ "recallDays": [
"2026-05-18", "2026-05-18",
"2026-05-19", "2026-05-19",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"record-id", "record-id",
@ -1287,23 +1315,25 @@
"endLine": 29, "endLine": 29,
"source": "memory", "source": "memory",
"snippet": "## [刘彦江] 单元挑战口语写作内容生产2026-05-13 21:40 ### 生产范围10条记录全部单题组全部回填验证通过 ✅) | ID | 写作-P1 | 口语-P1 | 写作-P2 | 口语-P2 | 状态 | |----|---------|---------|---------|---------|------| | 011301 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011401 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011501 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011701 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011601 | - | - | ✅ 看图写作 | ✅ 话题讨论 | 全部通过 | ### 题型结构总结 **写作-P1 (writing_email)**: - 6句段落排序含3句知识点作为范文核心句 - 能力标签:短消息写作|邮件/便条, 衔接与连贯|连词使用 - 场景:火灾求助/宠物照顾/惊喜派对/故事分享 **口语-P1 (speaking_qa)**: - 4个引导问题每问引导1个知识点句型 - 能力标签:基础信息表达|个人信息问答, 表达喜好与理由, 互动应答|问答交流 - 问题设计引导关键词:外貌描述/主动帮忙/耐心等待/购物清单 **写作-P2 (writing_picWrite)**: - 6句故事排序含3句知识点作为故事核心句 - 能力标签:叙述故", "snippet": "## [刘彦江] 单元挑战口语写作内容生产2026-05-13 21:40 ### 生产范围10条记录全部单题组全部回填验证通过 ✅) | ID | 写作-P1 | 口语-P1 | 写作-P2 | 口语-P2 | 状态 | |----|---------|---------|---------|---------|------| | 011301 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011401 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011501 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011701 | ✅ 邮件回复 | ✅ 日常回答 | - | - | 全部通过 | | 011601 | - | - | ✅ 看图写作 | ✅ 话题讨论 | 全部通过 | ### 题型结构总结 **写作-P1 (writing_email)**: - 6句段落排序含3句知识点作为范文核心句 - 能力标签:短消息写作|邮件/便条, 衔接与连贯|连词使用 - 场景:火灾求助/宠物照顾/惊喜派对/故事分享 **口语-P1 (speaking_qa)**: - 4个引导问题每问引导1个知识点句型 - 能力标签:基础信息表达|个人信息问答, 表达喜好与理由, 互动应答|问答交流 - 问题设计引导关键词:外貌描述/主动帮忙/耐心等待/购物清单 **写作-P2 (writing_picWrite)**: - 6句故事排序含3句知识点作为故事核心句 - 能力标签:叙述故",
"recallCount": 4, "recallCount": 5,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 5,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-18T11:35:06.740Z", "firstRecalledAt": "2026-05-18T11:35:06.740Z",
"lastRecalledAt": "2026-05-21T02:47:43.415Z", "lastRecalledAt": "2026-05-25T01:45:24.016Z",
"queryHashes": [ "queryHashes": [
"2a58080272be", "2a58080272be",
"e3188fdd52d6", "e3188fdd52d6",
"8ccf25e60418", "8ccf25e60418",
"f76487d76697" "f76487d76697",
"e8e31d8a03aa"
], ],
"recallDays": [ "recallDays": [
"2026-05-18", "2026-05-18",
"2026-05-19", "2026-05-19",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"写作-p1", "写作-p1",
@ -1418,20 +1448,23 @@
"endLine": 810, "endLine": 810,
"source": "memory", "source": "memory",
"snippet": "- Script sheet: `wMQVyV`186行×9列 - Knowledge points sheet: `DCcKsLbrmhfXgrtB7N2c9GA4ntf_NtIcXt` - 列结构A=类型, D=剧情描述, E=角色名, F=编剧台词English已填好, **G=组件配置** - 知识点point, talk, understand, a lot of + `talk to...` / `I can/can't understand...` ### 交互模式差异 - L5 文档 B列/C列 为空,无详细组件类型标签(仅 A=互动/核心互动-口语) - 编剧台词F列已全部填写英文 - 互动行的 User 台词含红色标注知识点词 ### 完成事项 - 24个互动行全部生成G列配置组件类型推断听力挖空、朗读台词、口语表达 - 写入方式:同上 Sheets v2 API - 24/24 全部回读验证通过 ### 脚本 `scripts/write_L5_G_configs.py`", "snippet": "- Script sheet: `wMQVyV`186行×9列 - Knowledge points sheet: `DCcKsLbrmhfXgrtB7N2c9GA4ntf_NtIcXt` - 列结构A=类型, D=剧情描述, E=角色名, F=编剧台词English已填好, **G=组件配置** - 知识点point, talk, understand, a lot of + `talk to...` / `I can/can't understand...` ### 交互模式差异 - L5 文档 B列/C列 为空,无详细组件类型标签(仅 A=互动/核心互动-口语) - 编剧台词F列已全部填写英文 - 互动行的 User 台词含红色标注知识点词 ### 完成事项 - 24个互动行全部生成G列配置组件类型推断听力挖空、朗读台词、口语表达 - 写入方式:同上 Sheets v2 API - 24/24 全部回读验证通过 ### 脚本 `scripts/write_L5_G_configs.py`",
"recallCount": 2, "recallCount": 4,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 2, "totalScore": 4,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-20T06:31:39.981Z", "firstRecalledAt": "2026-05-20T06:31:39.981Z",
"lastRecalledAt": "2026-05-21T02:47:43.415Z", "lastRecalledAt": "2026-05-25T06:38:20.252Z",
"queryHashes": [ "queryHashes": [
"688d2dceca9d", "688d2dceca9d",
"d05a0257d44b" "d05a0257d44b",
"e637236fe74b",
"14d903a64d04"
], ],
"recallDays": [ "recallDays": [
"2026-05-20", "2026-05-20",
"2026-05-21" "2026-05-21",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"can/can", "can/can",
@ -1451,18 +1484,21 @@
"endLine": 38, "endLine": 38,
"source": "memory", "source": "memory",
"snippet": "4. question与questionDesc人称必须一致统一改为 What does [角色] say? → 第一人称直接引语) - **JSON wrapper格式** `{\"first\": 题组1完整JSON, \"second\": 题组2完整JSON}` - **输出文件:** `output/writing_pic_qa_000001_sample.json` ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — writing_pic_qa 生产流程标准化 + SKILL 重写 - **时间:** 09:34 ~ 09:46 - **需求:** 将完整生产流程补充到 SKILL.md强化核心规则 - **状态:** ✅ 已完成 **核心规则强化(用户明确):** 1. **挖空 = 考察句型结构本身**,不是复述图片信息(如 Thank you for → 挖 for 而非 you 2. **考察多样化**同句型覆盖多种搭配for + 名词 / for + 动名词、be + 身份 / be + 状态词等) 3. **语言难度匹配欧标 A1-A2**Starters/Movers 4. **题干不千篇一律**question 随语境微调(如 \"What does she say about herself?\" / \"Where does she say she is going?\" / \"What does she say to her friend?\" **图片资源新规:** - 每个题组共享一", "snippet": "4. question与questionDesc人称必须一致统一改为 What does [角色] say? → 第一人称直接引语) - **JSON wrapper格式** `{\"first\": 题组1完整JSON, \"second\": 题组2完整JSON}` - **输出文件:** `output/writing_pic_qa_000001_sample.json` ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — writing_pic_qa 生产流程标准化 + SKILL 重写 - **时间:** 09:34 ~ 09:46 - **需求:** 将完整生产流程补充到 SKILL.md强化核心规则 - **状态:** ✅ 已完成 **核心规则强化(用户明确):** 1. **挖空 = 考察句型结构本身**,不是复述图片信息(如 Thank you for → 挖 for 而非 you 2. **考察多样化**同句型覆盖多种搭配for + 名词 / for + 动名词、be + 身份 / be + 状态词等) 3. **语言难度匹配欧标 A1-A2**Starters/Movers 4. **题干不千篇一律**question 随语境微调(如 \"What does she say about herself?\" / \"Where does she say she is going?\" / \"What does she say to her friend?\" **图片资源新规:** - 每个题组共享一",
"recallCount": 1, "recallCount": 3,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 3,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-20T06:31:39.981Z", "firstRecalledAt": "2026-05-20T06:31:39.981Z",
"lastRecalledAt": "2026-05-20T06:31:39.981Z", "lastRecalledAt": "2026-05-25T06:38:20.252Z",
"queryHashes": [ "queryHashes": [
"688d2dceca9d" "688d2dceca9d",
"e637236fe74b",
"14d903a64d04"
], ],
"recallDays": [ "recallDays": [
"2026-05-20" "2026-05-20",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"writing-pic-qa", "writing-pic-qa",
@ -1482,18 +1518,21 @@
"endLine": 486, "endLine": 486,
"source": "memory", "source": "memory",
"snippet": "QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 修复 - ability 全空/偏向听力 → 全部补充为口语向标签 - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` ### Record ID 映射 | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501听力-P1-图片选择题L1 B级 29词中仅6个在词库23个超纲。业务负责人放行优先生产词库后补。 ### 产出 | QSID | Record ID | 答案分布 | |------|-----------|:--:| | 121301 | recvjWrIXVjkWY | A2B2C1 ×2 | | 121401 | recvjWrJos9LH7 | A2B2C1 ×2 | | 121501 | recvjWrJQ9Njnl | A2B2C1 ×2 | ### 待办 ⚠️ 23个超纲词需补入L1词库 --- ## 图片文本输出([刘彦江] ### 背景 听力-P1 121301/121401/121501 选项图 prompt 需输出给图片生成人员。 #", "snippet": "QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 修复 - ability 全空/偏向听力 → 全部补充为口语向标签 - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` ### Record ID 映射 | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501听力-P1-图片选择题L1 B级 29词中仅6个在词库23个超纲。业务负责人放行优先生产词库后补。 ### 产出 | QSID | Record ID | 答案分布 | |------|-----------|:--:| | 121301 | recvjWrIXVjkWY | A2B2C1 ×2 | | 121401 | recvjWrJos9LH7 | A2B2C1 ×2 | | 121501 | recvjWrJQ9Njnl | A2B2C1 ×2 | ### 待办 ⚠️ 23个超纲词需补入L1词库 --- ## 图片文本输出([刘彦江] ### 背景 听力-P1 121301/121401/121501 选项图 prompt 需输出给图片生成人员。 #",
"recallCount": 1, "recallCount": 3,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 3,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-20T06:31:39.981Z", "firstRecalledAt": "2026-05-20T06:31:39.981Z",
"lastRecalledAt": "2026-05-20T06:31:39.981Z", "lastRecalledAt": "2026-05-25T08:47:02.076Z",
"queryHashes": [ "queryHashes": [
"688d2dceca9d" "688d2dceca9d",
"e637236fe74b",
"d8cc1fcace47"
], ],
"recallDays": [ "recallDays": [
"2026-05-20" "2026-05-20",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"口语-p1-日常回答", "口语-p1-日常回答",
@ -1513,18 +1552,20 @@
"endLine": 633, "endLine": 633,
"source": "memory", "source": "memory",
"snippet": "| QSID | 题数 | 答案分布 | 状态 | |------|:--:|:--:|:--:| | 021301 | 5+5 | A2B1C2 / A2B2C1 | ✅ | | 021401 | 5+5 | A1B2C2 / A2B2C1 | ✅ | | 021501 | 5+5 | A1B2C2 / A2B2C1 | ✅ | | 021601 | 5+0 | A2B2C1 | ✅ | | 021701 | 5+0 | A2B2C1 | ✅ | | 021801 | 5+5 | A2B2C1 / A2B2C1 | ✅ | | 022101 | 5+0 | A2B2C1 | ✅ | | 032501 | 5+0 | A2B2C1 | ✅ | | 032901 | 5+0 | A2B2C1 | ✅ | --- ## 口语-P1 审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 修复 - ability 全空/偏向听力 → 全部补充为口语向标签 - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QS", "snippet": "| QSID | 题数 | 答案分布 | 状态 | |------|:--:|:--:|:--:| | 021301 | 5+5 | A2B1C2 / A2B2C1 | ✅ | | 021401 | 5+5 | A1B2C2 / A2B2C1 | ✅ | | 021501 | 5+5 | A1B2C2 / A2B2C1 | ✅ | | 021601 | 5+0 | A2B2C1 | ✅ | | 021701 | 5+0 | A2B2C1 | ✅ | | 021801 | 5+5 | A2B2C1 / A2B2C1 | ✅ | | 022101 | 5+0 | A2B2C1 | ✅ | | 032501 | 5+0 | A2B2C1 | ✅ | | 032901 | 5+0 | A2B2C1 | ✅ | --- ## 口语-P1 审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 修复 - ability 全空/偏向听力 → 全部补充为口语向标签 - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QS",
"recallCount": 1, "recallCount": 2,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 2,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-20T06:31:39.981Z", "firstRecalledAt": "2026-05-20T06:31:39.981Z",
"lastRecalledAt": "2026-05-20T06:31:39.981Z", "lastRecalledAt": "2026-05-25T05:42:36.847Z",
"queryHashes": [ "queryHashes": [
"688d2dceca9d" "688d2dceca9d",
"e637236fe74b"
], ],
"recallDays": [ "recallDays": [
"2026-05-20" "2026-05-20",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"口语-p1", "口语-p1",
@ -1643,18 +1684,20 @@
"endLine": 346, "endLine": 346,
"source": "memory", "source": "memory",
"snippet": "## 口语-P1 审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 发现问题 - **121301**: 6题 ability 全空 - **121401**: ability 重复(\"听觉抓取关键信息\"×2+ 标签偏向听力而非口语 - **121501**: 6题 ability 全空 - answer 为空 → 正常speaking_qa 参考回答在 explanation 内) ### 修复 - 全部补充/替换为口语向标签(语用表达能力等) - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` ### Record ID 映射 | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501听力-P1-图片选择题) 难度: L1 B级 ### 词汇词库命中率 29个词中仅6个在L1/L2词库sofa, zoo, study, play, mat, mouth23个超纲。 业务负责人放行,优先生产,词库后补。 ### 产出 | QSID | Record ID | 词表(first/seco", "snippet": "## 口语-P1 审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501口语-P1-日常回答tblRGv7k4WH58Jgq ### 发现问题 - **121301**: 6题 ability 全空 - **121401**: ability 重复(\"听觉抓取关键信息\"×2+ 标签偏向听力而非口语 - **121501**: 6题 ability 全空 - answer 为空 → 正常speaking_qa 参考回答在 explanation 内) ### 修复 - 全部补充/替换为口语向标签(语用表达能力等) - 3/3 审校结果列更新为 `✅ OK | 2026-05-18 小研审校` ### Record ID 映射 | QSID | Record ID | |------|-----------| | 121301 | recvjW9RVwziwL | | 121401 | recvjW9RVwGzba | | 121501 | recvjW9RVwj4aQ | --- ## 听力-P1 图片选择题 生产+回填+审校([刘彦江] ### 范围 QSID: 121301, 121401, 121501听力-P1-图片选择题) 难度: L1 B级 ### 词汇词库命中率 29个词中仅6个在L1/L2词库sofa, zoo, study, play, mat, mouth23个超纲。 业务负责人放行,优先生产,词库后补。 ### 产出 | QSID | Record ID | 词表(first/seco",
"recallCount": 1, "recallCount": 2,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 2,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-20T11:03:34.460Z", "firstRecalledAt": "2026-05-20T11:03:34.460Z",
"lastRecalledAt": "2026-05-20T11:03:34.460Z", "lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [ "queryHashes": [
"81867276810d" "81867276810d",
"12653110bb68"
], ],
"recallDays": [ "recallDays": [
"2026-05-20" "2026-05-20",
"2026-05-25"
], ],
"conceptTags": [ "conceptTags": [
"口语-p1", "口语-p1",
@ -1915,6 +1958,378 @@
"结果", "结果",
"bitable" "bitable"
] ]
},
"memory:memory/2026-05-08.md:51:73": {
"key": "memory:memory/2026-05-08.md:51:73",
"path": "memory/2026-05-08.md",
"startLine": 51,
"endLine": 73,
"source": "memory",
"snippet": "- **修正:** 用户给出中文样例格式,要求图片描述从英文 prompt 改为纯中文结构化列表 - **新格式:** 编号 `1.` / `2.` 自上而下,每段含 `风格:` / `场景:` / `角色特征 - 动作 ` - **无 JSON 包裹**,纯文本写入 bitable `图片描述` 列 - **已同步更新**SKILL.md 4.2 节、bitable `recviZlAxxXlAb` 的图片描述字段 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — writing_pic_qa 批量样题生产6 Unit - **时间:** 10:10 ~ 10:34 - **需求:** 一次生产 6 套 writing_pic_qa A级样题全部写入 bitable - **状态:** ✅ 已完成6套/24题全部回读验证通过 **题目清单:** | ID | 题组1 句型 | 题组2 句型 | record_id | |----|-----------|-----------|-----------| | 010101 | Let's… / I'm happy to… | We will… / I will try my best. | recviZwiQUsgAD | | 010201 | I'm sorry for… / I feel nervous about… | What do you think about…? / Let's try… | recviZwjjFyBRi | | 010301 |",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T01:44:48.649Z",
"lastRecalledAt": "2026-05-25T01:44:48.649Z",
"queryHashes": [
"37d5e066d57f"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"skill.md",
"4.2",
"writing-pic-qa",
"6套/24题",
"record-id",
"修正",
"用户",
"中文"
]
},
"memory:memory/2026-05-12.md:258:281": {
"key": "memory:memory/2026-05-12.md:258:281",
"path": "memory/2026-05-12.md",
"startLine": 258,
"endLine": 281,
"source": "memory",
"snippet": "- 需要重新拉取文档,仔细识别所有互动标记 - 文档位于 space_id=7487521512283799556 - 上次发现的场景:太空故事 / 太空船起飞 / 小行星带 / 发光的星球 + 尾声 ## 中互动+核心互动 回填任务 — 继续18:37 ### 本轮 Session — 实际写入 bitable 上一轮已确认:文档中 4 个场景对应 4 个互动类型3中+1核标签已写入文档。但用户说的\"回填到对应为止\"指的是**写入 bitable 多维表格记录**,而非仅文档标签。 ### 需要写入的 4 条记录 | 场景 | 互动类型 | cType | bitable_token | |------|---------|-------|---------------| | 第1幕 太空故事 | 对话朗读互动 | `mid_dialog_repeat` | `MuwubKXoSaJe55sO4k9c63VSnmh` | | 第2幕 太空船起飞 | 对话互动 | `mid_sentence_dialogue` | `GH0hbBT0ZavkCesaVQ7c40Zfnub` | | 第3幕 小行星带 | 指令互动 | `mid_vocab_instruction` | `UorxbVCNYaqpx3sOUdTcF6bUnAh` | | 第4幕 发光的星球 | 听力拖拽 | `core_listening_drag` | `Uey8bhdLBa66TIsGrFBcIQKRnsg` | ### 下一步 1. 读取 4 个 bitable 的表结构(字段名) 2.",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T01:44:48.649Z",
"lastRecalledAt": "2026-05-25T01:44:48.649Z",
"queryHashes": [
"37d5e066d57f"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"space-id",
"bitable-token",
"mid-dialog-repeat",
"mid-sentence-dialogue",
"mid-vocab-instruction",
"core-listening-drag",
"需要",
"重新"
]
},
"memory:memory/2026-05-14.md:162:188": {
"key": "memory:memory/2026-05-14.md:162:188",
"path": "memory/2026-05-14.md",
"startLine": 162,
"endLine": 188,
"source": "memory",
"snippet": "按 ability 标签分类匹配模板生成中文解析: - 基础信息表达|个人信息问答 → 细分:年龄/姓名/家庭/外貌/物品位置 - 表达喜好与理由 → 喜好+because原因引导 - 互动应答|问答交流 → 场景化(感谢/道歉/邀请/请求/规则) - 信息交换|双向问答 → 饮食/计划类交流 - 过去经历描述Past Activities → 过去时态描述引导 ### 脚本 - `scripts/fill_speaking_expl.py` — 读取全表 → 匹配能力标签 → 生成→ PUT写回 ## [刘彦江] 单元挑战写作-P1 审校与修复2026-05-14 17:00 ### 审校范围 写作-P1-邮件回复表tblDizCeLgkKPFd3 ### 审校结果 - 总记录17条 - ✅ 通过9条 | ✅ 已修复4条 | ✅ 通过(C级)2条 | ⚠️ 占位数据1条 | (空记录1条) ### 修复明细 | QSID | record_id | 修复前 | 修复后 | |------|-----------|--------|--------| | 032701 | recvjzXkYnsQ8r | answerSet=[], ability=[], expl=\"\" | answerSet=[0..7], ability=写作+衔接+描述, expl=完整 | | 032901 | recvjzXm5yEXBY | answerSet=[], ability=[], expl=\"\" | answerSet=[0..7], ability=写",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T01:45:24.016Z",
"lastRecalledAt": "2026-05-25T01:45:24.016Z",
"queryHashes": [
"e8e31d8a03aa"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"年龄/姓名/家庭/外貌/物品位置",
"感谢/道歉/邀请/请求/规则",
"饮食/计划类交流",
"scripts/fill-speaking-expl.py",
"单元挑战写作-p1",
"写作-p1-邮件回复表",
"record-id",
"ability"
]
},
"memory:memory/2026-05-18.md:23:49": {
"key": "memory:memory/2026-05-18.md:23:49",
"path": "memory/2026-05-18.md",
"startLine": 23,
"endLine": 49,
"source": "memory",
"snippet": "- 缺失列:写作-P2tblSAwlMumKoyjws、口语-P4tblsD2dxaRpLmkXD无「审校结果」列 ### 经验 - 写作-P3 解析在 questionList 嵌套层级,初审误判为空,复查后确认含中文 - bitable curl 写回嵌套JSON时Python subprocess构造完整body比shell变量展开安全 - 听力-P1 000001 虽有5条first+5条second但确有题目内容不是纯占位按实际内容生成了解析 # 2026-05-18 工作日志 ## 单元挑战全题型审核 + 修复 ### 背景 [刘彦江] 要求对单元挑战全部20种题型审核重点解析不能纯英文、答案格式正确性。题目内容不修改。 ### 审核结果 - 审核范围20张表、244条记录 - 答案格式:零问题 - 纯英文解析13处听力-P2 021901 ×10口语-P1 032701/032901口语-P2 032801 - 解析为空83处听力-P1 000001+110101~110401 ×50听力-P4 021701/022101/032501/032901 ×20共写作-P3复查后实际OK ### 修复执行 - 13条纯英文→中文化翻译通过模型翻译 - 70条空解析→从题目内容+ability关键词智能生成 - 全部通过 Python+curl 写回 bitable避免shell转义 - 写入后回读验证107条全部含中文零错误 ### 审校结果列更新 - 格式:`✅ OK | 2026-05-18 小研审",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T04:13:09.891Z",
"lastRecalledAt": "2026-05-25T04:13:09.891Z",
"queryHashes": [
"dd04402cc3a8"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"写作-p2",
"口语-p4",
"写作-p3",
"听力-p1",
"听力-p2",
"口语-p1",
"032701/032901",
"口语-p2"
]
},
"memory:memory/2026-05-18.md:542:570": {
"key": "memory:memory/2026-05-18.md:542:570",
"path": "memory/2026-05-18.md",
"startLine": 542,
"endLine": 570,
"source": "memory",
"snippet": "- 审核范围20张表、244条记录 - 答案格式:零问题 - 纯英文解析13处听力-P2 021901 ×10口语-P1 032701/032901口语-P2 032801 - 解析为空83处听力-P1 000001+110101~110401 ×50听力-P4 021701/022101/032501/032901 ×20共写作-P3复查后实际OK ### 修复执行 - 13条纯英文→中文化翻译通过模型翻译 - 70条空解析→从题目内容+ability关键词智能生成 - 全部通过 Python+curl 写回 bitable避免shell转义 - 写入后回读验证107条全部含中文零错误 ### 审校结果列更新 - 格式:`✅ OK | 2026-05-18 小研审校` / `📝 空模板 | 2026-05-18 小研审校` - 已更新18张表、241条记录 - 缺失列:写作-P2tblSAwlMumKoyjws、口语-P4tblsD2dxaRpLmkXD无「审校结果」列 ### 经验 - 写作-P3 解析在 questionList 嵌套层级,初审误判为空,复查后确认含中文 - bitable curl 写回嵌套JSON时Python subprocess构造完整body比shell变量展开安全 - 听力-P1 000001 虽有5条first+5条second但确有题目内容不是纯占位按实际内容生成了解析 --- ## P4 短对话选择题批量改写([刘彦江] ### 背景 短对话选择题用户只能听音频,无人名标",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T04:13:09.891Z",
"lastRecalledAt": "2026-05-25T04:13:09.891Z",
"queryHashes": [
"dd04402cc3a8"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"听力-p2",
"口语-p1",
"032701/032901",
"口语-p2",
"听力-p1",
"听力-p4",
"021701/022101/032501/032901",
"共写作-p3复查后实际ok"
]
},
"memory:memory/2026-05-18.md:653:680": {
"key": "memory:memory/2026-05-18.md:653:680",
"path": "memory/2026-05-18.md",
"startLine": 653,
"endLine": 680,
"source": "memory",
"snippet": "{\"first\": {\"questionSet\": [{\"ability\": [\"听觉抓取关键信息\", \"多特征整合\"]}]}} ``` 适用:听力-P1/P2/P3/P4/P7阅读全7个口语全4个 **格式B: ¥¥ 分隔字符串(顶层)** ```json {\"first\": {\"ability\": \"听觉抓取关键信息¥¥多特征整合\"}} ``` 适用:听力-P5写作-P1/P2/P3 ### 映射结果(修正后) - **写作-P1** ✅ 有标签格式B短消息写作邮件/便条、衔接与连贯|连词使用、描述性写作|人物与地点、描述性写作|场景与情绪、句型组织、问题解决|求助与建议(部分非标准标签名) - **写作-P2** ⚠️ 格式不规范(模板残留) - **写作-P3** ❌ 纯占位符 \"xxxx\" - **听力-P5** ✅ 有标签格式B补抓听觉抓取关键信息、多特征整合 - **20 个未覆盖标签** = 45 标准标签中历史数据从未出现的写作全11个、听力 情绪/态度理解+长对话理解、口语 图片对比+故事讲述+发音语调 等) ### 产出 - `business_knowledge/unit_challenge_type_ability_mapping.md` — 完整映射表 - `/tmp/unit_challenge_ability_doc.md` — 对外分享版(已发送文件 + 飞书文档) --- ## L1-S2-U18-L5 双龙会 台词润色审校([王璐辰] ### 审校结果 - 语法/拼写硬错误5处Rows 41, 55,",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T04:13:09.891Z",
"lastRecalledAt": "2026-05-25T04:13:09.891Z",
"queryHashes": [
"dd04402cc3a8"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"听力-p1/p2/p3/p4/p7",
"听力-p5",
"写作-p1/p2/p3",
"写作-p1",
"邮件/便条",
"写作-p2",
"写作-p3",
"情绪/态度理解"
]
},
"memory:memory/2026-05-18.md:479:508": {
"key": "memory:memory/2026-05-18.md:479:508",
"path": "memory/2026-05-18.md",
"startLine": 479,
"endLine": 508,
"source": "memory",
"snippet": "直接输出 `[1-A-选项图彩图]:{\"prompt\":\"...\"}` 到飞书对话中,被飞书渲染引擎吃掉(方括号+JSON格式被当标签/链接处理),用户看不到内容。 **解决方案:必须用代码块(```)包裹或通过 message() 工具以编程方式发送。** --- ## 题型-能力标签映射([刘彦江] ### 背景 用户要求:把所有单元挑战题型与 45 个标准能力 tag 做映射。 ### 能力标签源文件 - 路径: `business_knowledge/ability_tags.md`Vala 英语能力标签体系2026-05-13更新 - 45 个标准标签:听力(11)、口语(10)、阅读(13)、写作(11) ### ability 格式不统一问题(重要发现)🔴 提取过程中发现 ability 标签在 bitable jsonData 中存在两种不同格式和位置: **格式A: JSON 数组(每题内部)** ```json {\"first\": {\"questionSet\": [{\"ability\": [\"听觉抓取关键信息\", \"多特征整合\"]}]}} ``` 适用题型:听力-P1/P2/P3/P4/P7阅读全7个口语全4个 **格式B: ¥¥ 分隔字符串(顶层)** ```json {\"first\": {\"ability\": \"听觉抓取关键信息¥¥多特征整合\"}} ``` 适用题型:听力-P5写作-P1/P2/P3 ### 映射结果(修正后)",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T08:47:02.076Z",
"lastRecalledAt": "2026-05-25T08:47:02.076Z",
"queryHashes": [
"d8cc1fcace47"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"1-a-选项图彩图",
"json格式被当标签/链接处理",
"题型-能力标签映射",
"2026-05-13更新",
"听力-p1/p2/p3/p4/p7",
"听力-p5",
"写作-p1/p2/p3",
"直接"
]
},
"memory:memory/2026-05-18.md:620:663": {
"key": "memory:memory/2026-05-18.md:620:663",
"path": "memory/2026-05-18.md",
"startLine": 620,
"endLine": 663,
"source": "memory",
"snippet": "| QSID | Record ID | 答案分布 | |------|-----------|:--:| | 121301 | recvjWrIXVjkWY | A2B2C1 ×2 | | 121401 | recvjWrJos9LH7 | A2B2C1 ×2 | | 121501 | recvjWrJQ9Njnl | A2B2C1 ×2 | ### 待办 ⚠️ 23个超纲词需补入L1词库 --- ## 图片文本输出([刘彦江] ### 飞书消息格式陷阱 🔴 直接输出 `[1-A-选项图彩图]:{\"prompt\":\"...\"}` 到飞书对话中,被渲染引擎吃掉(方括号+JSON当标签处理用户看不到内容。 **解决方案:代码块包裹或 message() 工具发送。** --- ## 题型-能力标签映射([刘彦江] ### 背景 把所有单元挑战题型与 45 个标准能力 tag 做映射。 ### 能力标签源文件 - 路径: `business_knowledge/ability_tags.md`Vala 英语能力标签体系2026-05-13更新 - 45 个标准标签:听力(11)、口语(10)、阅读(13)、写作(11) ### ability 格式不统一问题(重要发现)🔴 提取中发现 ability 存在两种不同格式/位置: **格式A: JSON 数组(每题内部)** ```json {\"first\": {\"questionSet\": [{\"ability\": [\"听觉抓取关键信息\", \"多特征整合\"]}]}} ``` 适用:听力-P1/P2",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T08:47:02.076Z",
"lastRecalledAt": "2026-05-25T08:47:02.076Z",
"queryHashes": [
"d8cc1fcace47"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"1-a-选项图彩图",
"题型-能力标签映射",
"2026-05-13更新",
"存在两种不同格式/位置",
"听力-p1/p2",
"qsid",
"record",
"答案"
]
},
"memory:memory/2026-05-07.md:263:280": {
"key": "memory:memory/2026-05-07.md:263:280",
"path": "memory/2026-05-07.md",
"startLine": 263,
"endLine": 280,
"source": "memory",
"snippet": "- **操作:** 用户多次发送新版表1/表2结果在246~442之间波动最终确认需使用正确的文件分类主题词表 vs 考试大纲词表不同) ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 写作看图回答题 \"I am... / I am from...\" 样题生产 - **时间:** 15:38 ~ 15:52 - **需求:** 使用知识点 \"I am... / I am from...\" 生产一套写作看图回答题writing_pic_qa - **状态:** ✅ 已完成,用户确认 - **题型级别:** L2因L1词库缺少所有代词/be动词/介词/国家名) - **难度:** A级4小题 - **核心原则(用户明确):** 1. 挖空必须是考察知识点本身的单词am/from/student不是手写姓名/国名等附带信息 2. 只能为1个单词挖空 3. 正确模式:`I (2) Anna.` → 挖空am数字标记字母数 4. 图片提供语境线索,学生填写核心知识点词 - **输出文件:** `output/writing_pic_qa_I_am_from_020102.json` - **关键教训:** writing_pic_qa 核心考察知识点词本身am/from而非题干已知信息挖空字母数标记必须与答案单词字母数一致 - **词库缺口发现:** L1和L2词库均缺失人称代词、be动词、介词、国家名等基础功能词 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5c",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T08:53:31.758Z",
"lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [
"12653110bb68"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"用户多次发送新版表1/表2",
"writing-pic-qa",
"因l1词库缺少所有代词/be动词/介词/国家名",
"am/from/student",
"不是手写姓名/国名等附带信息",
"am/from",
"ou-5af74c1fb96042e33cc0f16b5c",
"操作"
]
},
"memory:memory/2026-05-07.md:230:253": {
"key": "memory:memory/2026-05-07.md:230:253",
"path": "memory/2026-05-07.md",
"startLine": 230,
"endLine": 253,
"source": "memory",
"snippet": "- **需求:** 使用知识点 \"I am ready! / Thank you for...\" 再生产一套 writing_pic_qa - **状态:** ✅ 已完成 - **难度:** A级4小题L2级别 - **核心设计:** 延续上一套原则——只挖空知识点核心词,图片提供语境线索 - **输出文件:** `output/writing_pic_qa_ready_thank_020103.json` - **题目清单:** 1. I am (5). → ready男孩背书包站门口准备上学 2. Thank (3) for the gift. → you女孩接过礼物盒微笑 3. He is (5) for dinner. → ready男孩坐餐桌前等开饭 4. Thank (3) for the help. → you男孩接书表示感谢 - **设计思路:** 两个知识点各出现2次reinforcement变场景不变核心搭配 # 2026-05-07 工作日志 ## 会话记录 ### 刘彦江 (ou_5af74c1fb96042e33cc0f16b5ca02cf4) — 单元挑战新增3个题型 - **时间:** 11:19 ~ 11:28 - **需求:** 单元挑战新增3个题型阅读看图回答题reading_pic_qa、阅读看图判断题reading_pic_judge、写作看图回答题writing_pic_qa - **状态:** ✅ 已完成题型规范落地 - **交付内容:** 创建3个题型SKILL.md更",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T08:53:31.758Z",
"lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [
"12653110bb68"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"writing-pic-qa",
"reading-pic-qa",
"reading-pic-judge",
"创建3个题型skill.md",
"需求",
"使用",
"知识",
"ready"
]
},
"memory:memory/2026-05-14.md:108:129": {
"key": "memory:memory/2026-05-14.md:108:129",
"path": "memory/2026-05-14.md",
"startLine": 108,
"endLine": 129,
"source": "memory",
"snippet": "| first | 4 | I eat a sandwich for breakfast. | [0]=A | 显性事实理解|单句信息点抓取 | | first | 5 | This is my red suitcase. | [0]=A | 显性事实理解|单句信息点抓取 | | second | 1 | Look at my new clothes. | [0]=A | 显性细节理解|物品特征辨识 | | second | 2 | My dad works at the airport. | [0]=A | 显性细节理解|数字/时间/地点 | | second | 3 | The pirate has a black eye patch. | [0]=A | 显性事实理解|单句信息点抓取 | | second | 4 | I need my passport to go abroad. | [0]=A | 显性细节理解|物品功能辨识 | | second | 5 | I like eating cheese very much. | [0]=A | 显性细节理解|物品特征辨识 | ### 备注 - 10题答案全部为[0]A选项由用户给定的听力文本-图片映射决定 - second Q1 \"clothes\"→卫衣 需区分 clothes/shoes/hat 范畴 - `question`字段为P1正确的字段名非content - `optionsImage`字段保留None图片资源由上游管理 - 题目1/题目2文本字段已同步填充听力文本 ## [刘彦江] 写作+",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T08:53:31.758Z",
"lastRecalledAt": "2026-05-25T08:53:31.758Z",
"queryHashes": [
"12653110bb68"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"数字/时间/地点",
"由用户给定的听力文本-图片映射决定",
"clothes/shoes/hat",
"题目1/题目2文本字段已同步填充听力文本",
"first",
"eat",
"sandwich",
"breakfast"
]
},
"memory:memory/2026-05-07.md:86:107": {
"key": "memory:memory/2026-05-07.md:86:107",
"path": "memory/2026-05-07.md",
"startLine": 86,
"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 ∩ 表2492 - 表1 ∩ 表3448 - 表2 ∩ 表3427 - 最终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,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-05-25T09:34:43.114Z",
"lastRecalledAt": "2026-05-25T09:34:43.114Z",
"queryHashes": [
"4baebc80709c"
],
"recallDays": [
"2026-05-25"
],
"conceptTags": [
"lv2-单词",
"单词表-lv1",
"单词表-备用",
"libreoffice/antiword",
"user-id",
"ou-xxx",
"open-id",
"xlsx"
]
} }
} }
} }

128
memory/2026-05-25-0944.md Normal file
View File

@ -0,0 +1,128 @@
# Session: 2026-05-25 09:44:09 GMT+8
- **Session Key**: agent:xiaoyan:feishu:direct:ou_5af74c1fb96042e33cc0f16b5ca02cf4
- **Session ID**: c6d8e105-a0c2-463b-a3ca-c121e57ddae3
- **Source**: feishu
## Conversation Summary
assistant: 3 条已修复。最终全量验证:
assistant: 全部 8 条验证通过 ✅
| ID | 级别 | Dear | 内容句1 | 内容句2 | 内容句3 | 收尾 | 署名 | 选项 |
|----|------|------|---------|---------|---------|------|------|------|
| 022201 | L2-B | Dear Max | 听说发现旧盒子 | 问里面有什么 | 建议一起打开 | Take care, | Alex | 6 |
| 022301 | L2-B | Dear Emma | 今天劳动内容 | 花园现在很漂亮 | 下次浇水建议 | Your friend, | Lily | 6 |
| 022401 | L2-B | Dear Sophie | 去医院探病 | Jack 状态好转 | 建议送卡片 | Warmly, | Lily | 6 |
| 032501 | L2-C | Dear Ben | 听说担忧音乐会 | 自己也有紧张感 | 鼓励别放弃 | Yours truly, | Sam | 6 |
| 032601 | L2-C | Dear Mr. Brown | 感谢组织旅行 | 最喜欢天文秀 | 请分享照片 | Warm regards, | Lucy | 6 |
| 032701 | L2-C | Dear Anna | 去过咖啡馆 | 店员很友好 | 建议一起去 | Kind regards, | Emma | 6 |
| 032801 | L2-C | Dear Miss Green | 项目停止工作 | 试了换电池没用 | 请求建议 | Gratefully, | Tom | 6 |
| 032901 | L2-C | Dear Sophie | 正在妈妈派对 | 妹妹跳舞爸开心 | 感觉很幸运 | With love, | Jessica | 6 |
全部改为6 选项乱序 + 题目描述含 3 条分点写作要求 + 保留原有收尾风格多样性。
user: json 中的 abilityTag explanation 补充完整
assistant: 先看下现有 jsonData 里 ability / abilityTag / explanation 的状态:
目前 8 条中:`ability` 大部分只有 `["句型组织"]`(太简略),`abilityTag` 全部缺失,`explanation` 大部分为空。
补充完整后写入:
assistant: 看起来之前的脚本实际已写入成功。检查全部 8 条:
assistant: 032901 落下了,补上:
assistant: 全部完成。最终汇总:
| ID | 级别 | ability 标签数 | abilityTag | explanation | 收尾风格 |
|----|------|:----:|-----------|:-----------:|---------|
| 022201 | L2-B | 3 | 短消息写作/衔接与连贯/句型组织 | ✅ | Take care, Alex |
| 022301 | L2-B | 3 | 短消息写作/衔接与连贯/句型组织 | ✅ | Your friend, Lily |
| 022401 | L2-B | 3 | 短消息写作/衔接与连贯/句型组织 | ✅ | Warmly, Lily |
| 032501 | L2-C | 4 | +情感表达 | ✅ | Yours truly, Sam |
| 032601 | L2-C | 4 | +社交写作 | ✅ | Warm regards, Lucy |
| 032701 | L2-C | 4 | +描述性写作 | ✅ | Kind regards, Emma |
| 032801 | L2-C | 4 | +问题解决 | ✅ | Gratefully, Tom |
| 032901 | L2-C | 4 | +描述性写作 | ✅ | With love, Jessica |
L2-B 级 3 项能力标签基础写作技能L2-C 级 4 项(加专项写作子技能),体现难度梯度。
user: 与标准库的45条 tag 一致么?不一致需要修改
assistant: Now I can see the 45 standard tags. My current tags are wrong — several are non-standard:
| 我写的 | 标准库 |
|--------|--------|
| `衔接与连贯|指代与连词使用` | `衔接与连贯|连词使用` |
| `描述性写作|人物与地点` | `描述写作|人物/物体/场景` |
| `描述性写作|场景与情绪` | `描述写作|人物/物体/场景` |
| `句型组织|邮件段落排序` | ❌ 不在45条中 |
| `情感表达|鼓励与共情` | ❌ 不在45条中 |
| `问题解决|求助与建议` | ❌ 不在45条中 |
| `社交写作|感谢信` | ❌ 不在45条中 |
修正为仅使用标准标签,按邮件内容决定是否加 `描述写作`
assistant: 全部 8 条已对齐标准 45 标签。最终结果:
| ID | ability / abilityTag | 对标标准标签 |
|----|---------------------|------------|
| 022201 | 短消息写作|邮件/便条, 衔接与连贯|连词使用 | #7 + #8 |
| 022301 | + 描述写作|人物/物体/场景 | #7 + #8 + #9 |
| 022401 | + 描述写作|人物/物体/场景 | #7 + #8 + #9 |
| 032501 | 短消息写作|邮件/便条, 衔接与连贯|连词使用 | #7 + #8 |
| 032601 | 短消息写作|邮件/便条, 衔接与连贯|连词使用 | #7 + #8 |
| 032701 | + 描述写作|人物/物体/场景 | #7 + #8 + #9 |
| 032801 | 短消息写作|邮件/便条, 衔接与连贯|连词使用 | #7 + #8 |
| 032901 | + 描述写作|人物/物体/场景 | #7 + #8 + #9 |
剔除的非标准标签(`句型组织`、`情感表达`、`问题解决`、`社交写作`、`描述性写作`变体、`指代与连词使用`变体)均已替换为 `ability_tags.md` 中的标准名称。
user: 回填 形成完整的配置json
assistant: 8 条完整配置已回填到位。最终 jsonData 结构如上,字段清单:
```
{
"first": {
"category": "writing",
"type": "writing_email",
"questionSetID": "022201",
"textDesc": "场景引入 + 3条写作要求",
"optionSetList": ["称呼", ..., "署名"], // 6项乱序
"answerSet": [0,2,3,5,1,4], // 正确答案索引
"ability": ["标准45标签..."], // ✅ 已对齐
"abilityTag": ["标准45标签..."], // ✅ 新增
"explanation": "排序逻辑说明...", // ✅ 已补全
},
"second": {}
}
```
| ID | 收尾 | 标签数 | 描述写作 |
|----|------|:---:|:---:|
| 022201 | Take care, Alex | 2 | — |
| 022301 | Your friend, Lily | 3 | ✅ |
| 022401 | Warmly, Lily | 3 | ✅ |
| 032501 | Yours truly, Sam | 2 | — |
| 032601 | Warm regards, Lucy | 2 | — |
| 032701 | Kind regards, Emma | 3 | ✅ |
| 032801 | Gratefully, Tom | 3 | — |
| 032901 | With love, Jessica | 3 | ✅ |
全部字段textDesc / optionSetList / answerSet / ability / abilityTag / explanation均已完整标准 45 标签对齐。
user: 021801 口语-P2-话题讨论 题组2和题组1 题目一样 需要修改 题组2图片内容如下
[2-组图]:{"prompt_2":"黑白线条图:一个孩子拿着作业本主动走到需要帮助的同学身边面带微笑,课桌上散落着打开的书本和铅笔","prompt_3":"黑白线条图:在学校走廊里,一个孩子蹲下来帮另一个同学系鞋带,另一个同学感激地看着他","prompt_4":"黑白线条图:两个孩子一起在花园里种下小树苗,一个扶着树苗一个培土,脸上带着共同的期待和开心","prompt_5":"黑白线条图:学校集会上,一个孩子站在台上双手接过助人为乐奖状,台下同学们纷纷起立鼓掌"}
assistant: 找到了。题组1first和题组2second的 questionSet 问题完全一样需要基于新图片重新设计题组2的5道题。
先看一下新图片内容对应题组2的主题
- prompt_2主动帮同学拿作业 → **主动关心**
- prompt_3走廊帮系鞋带 → **小事善意**
- prompt_4一起种树 → **合作团结**
- prompt_5台上领奖、台下鼓掌 → **被认可的感受**
据此设计 5 道新题:
assistant: 已更新。5 道新题全部与题组1不同对应新图片
| 题号 | 题组2新题 | 对应图片 |
|:---:|------|------|
| Q1 | What do you do when a classmate looks shy or alone? | prompt_2主动送作业 → 关心孤独同学 |
| Q2 | Are small acts of kindness as important as big help? | prompt_3系鞋带 → 小善意的价值 |
| Q3 | Tell us about working together with a friend | prompt_4一起种树 → 合作经历 |
| Q4 | How do you feel when someone thanks you? | prompt_5领奖鼓掌 → 被认可的感受 |
| Q5 | What kind of person do you want to be? | 主题升华 → 助人为乐的人格 |
同步更新了 `second.imageDesc`(新图片描述)、`second.textDesc`、`题目2` 显示文本和 `审核结果`

69
memory/2026-05-25-1511.md Normal file
View File

@ -0,0 +1,69 @@
# Session: 2026-05-25 15:11:20 GMT+8
- **Session Key**: agent:xiaoyan:feishu:direct:ou_8b79b7f711e42a4004f3f3c225a1a99c
- **Session ID**: 0025603e-8bf6-41ce-b86d-6e43d95f5ad1
- **Source**: feishu
## Conversation Summary
user: 组件配置-json https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh
assistant: 身份确认:**张昆鹏**(技术负责人,完整权限)。正在读取知识库文档内容。
assistant: 文档包含内嵌电子表格,我先提取知识点和剧本数据。
assistant: 数据已获取。现在我需要查看各类组件的配置规范和JSON格式标准。让我先了解现有的组件配置技能。
assistant: 数据已完整获取。现在我根据各组件规范,将剧本中所有互动组件的配置信息解析为结构化 JSON。
assistant: 已从知识库文档中提取并生成组件配置 JSON。以下是汇总
📝 **L1-S2-U17-L2 迟到的包裹** — 组件配置 JSON
**知识点:**
- 单词:`get`(v.收到) / `month`(n.月) / `year`(n.年) / `ago`(adv.以前)
- 句型:`... be happy with...` / `... month(s)/year(s) ago.`
**互动组件17个**
| 类型 | 数量 | 组件ID |
|------|------|--------|
| 图片单选 | 2 | 1217201, 1217208 |
| 对话朗读 | 5 | 1217202, 1217203, 1217205, 1217211, 1217217 |
| 对话组句 | 2 | 1217204, 1217212 |
| 对话选读 | 3 | 1217206, 1217210, 1217215 |
| 图片多选 | 1 | 1217207 |
| 对话挖空 | 3 | 1217209, 1217213, 1217216 |
| 听力拖拽 | 1 | 1217214 |
**知识点覆盖情况(不含无知识点标记的组件):**
- `get` → 1217210, 1217212, 1217217
- `month` → 1217203, 1217207
- `year` → 1217205, 1217208
- `ago` → 1217201, 1217202, 1217206
- `... be happy with...` → 1217209, 1217211, 1217215
- `... month(s)/year(s) ago.` → 1217204
JSON 已输出至 `tmp/L1_S02_U17_L2_components_config.json`,各组件按对应 skill 规范解析(图片单选→`dialogue-single-choice-image-config`、对话朗读→`dialogue-reading-config` 等)。
⚠️ 注意:**1217214听力拖拽** 暂无匹配的 skill 规范,按原始配置字段保留;**1217207图片多选** 复用图片单选规范但答案字段改为了数组格式。需要我调整格式或补充某个组件的配置吗?
user: 听力拖拽和图片多选先按照原始字段保留
assistant: 确认,当前 JSON 中这两个组件已按原始字段保留:
- **1217214听力拖拽**`skill` 设为 `null`,不用现有 skill 规范映射,保留原文的「任务背景」「通关知识」「开场语」「听力文本」「题目信息」「学习过程」等原始字段结构
- **1217207图片多选**:复用 `dialogue-single-choice-image-config` 的字段框架,但 `答案` 字段改为数组 `["01", "02"]`,与单选组件的字符串答案做了区分
文件在 `tmp/L1_S02_U17_L2_components_config.json`,格式已验证通过。还需要调整什么吗?
user: 不用了
assistant: NO_REPLY
user: 组件配置-json https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh
assistant: 上次已处理完成JSON 文件在 `tmp/L1_S02_U17_L2_components_config.json`,汇总如下:
📝 **L1-S2-U17-L2 迟到的包裹** — 17 个组件
| 类型 | 数量 | 技能规范 |
|------|------|---------|
| 图片单选 | 2 | dialogue-single-choice-image-config |
| 对话朗读 | 5 | dialogue-reading-config |
| 对话组句 | 2 | dialogue-sentence-building-config |
| 对话选读 | 3 | dialogue-selective-reading-config |
| 图片多选 | 1 | 原始字段保留 |
| 对话挖空 | 3 | dialogue-fill-in-blanks-config |
| 听力拖拽 | 1 | 原始字段保留 |
需要我在现有基础上补充/修改什么内容吗?

165
memory/2026-05-25-1955.md Normal file
View File

@ -0,0 +1,165 @@
# Session: 2026-05-25 19:55:11 GMT+8
- **Session Key**: agent:xiaoyan:feishu:direct:ou_8b79b7f711e42a4004f3f3c225a1a99c
- **Session ID**: c06e2631-9fb0-4940-829a-da20e5b48450
- **Source**: feishu
## Conversation Summary
user: 组件配置-json https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh
assistant: 文档是「L1-S2-U17-L2 迟到的包裹」,包含知识点和剧本两个内嵌 Sheet。让我先读取这两个 Sheet 的数据。
assistant: Let me look at the component configuration skills to understand the expected JSON format.
assistant: Now I have a clear picture. This is the L1-S2-U17-L2 lesson script with 17 interactive components. Let me extract and parse all component configurations into structured JSON.
assistant: 已将 17 个互动组件配置全部解析。以下是汇总:
**文档:** L1-S2-U17-L2 迟到的包裹
**知识点:** get / month / year / ago / ... be happy with... / ... month(s)/year(s) ago.
---
### 组件配置 JSON17个组件7种类型
| # | 类型 | ID | 任务标题 | 知识点 |
|---|------|------|---------|--------|
| 1 | 图片单选 | 1217201 | 为包裹找到正确的日期牌子 | ago |
| 2 | 对话朗读 | 1217202 | 朗读90天前的包裹信息 | ago |
| 3 | 对话朗读 | 1217203 | 理解天数和月数的换算 | month |
| 4 | 对话组句 | 1217204 | 用单词组句描述包裹信息 | ... month(s)/year(s) ago. |
| 5 | 对话朗读 | 1217205 | 朗读90天前的包裹信息 ⚠️ | year |
| 6 | 对话选读 | 1217206 | 选择你想表达的感受 | ago |
| 7 | 图片多选 | 1217207 | 找出几个月前的包裹 | — |
| 8 | 图片单选 | 1217208 | 找出写有一年前的包裹 | — |
| 9 | 对话挖空 | 1217209 | 补全对Sunny说的句子 | ... be happy with... |
| 10 | 对话选读 | 1217210 | 选择帮Grace拿包裹的说法 | get |
| 11 | 对话朗读 | 1217211 | 对Anna的提醒 | ... be happy with... |
| 12 | 对话组句 | 1217212 | 用单词组句主动帮忙 | get |
| 13 | 对话挖空 | 1217213 | 补全对Jack说的话 | — |
| 14 | 听力拖拽 | 1217214 | 告诉Lin你们分发包裹的事迹 | month/year/ago/句型 |
| 15 | 对话选读 | 1217215 | 选择表达满意的方式 | ... be happy with... |
| 16 | 对话挖空 | 1217216 | 补全User想要包裹的句子 | — |
| 17 | 对话朗读 | 1217217 | 朗读收到帽子的喜悦 | get |
---
### ⚠️ 发现的问题
1. **ID 1217205 任务标题有误**:标题写"朗读90天前的包裹信息",但实际内容是 `That's 2 years!`,应改为如「朗读两年前的包裹信息」
2. **ID 1217207/1217208/1217213/1217216 组件配置列未填知识点**:这些组件的"组件配置"列中未填写对应知识点标签
---
需要我把这个 JSON 写入 bitable还是做其他处理
user: 不用直接把生成的html发给我
assistant: 已发送,共 17 个互动组件、7 种题型。HTML 支持点击卡片折叠/展开,带有快速导航和类型标签。
⚠️ 发现一个问题ID 1217205 标题写的是"朗读90天前的包裹信息",但实际内容为 `That's 2 years!`,标题与内容不符,需要修正。
user: 刚刚调用的那个skill请把你刚刚的调用逻辑和过程告诉我
assistant: 整个流程没有命中任何单一专项 skill而是组合了多个技能的**方法**来完成。以下是详细过程:
---
## 调用链路
### 第一步:读取飞书知识库文档
收到 wiki 链接后,判断其为知识库文档(`/wiki/` 路径),触发了 MEMORY.md 中定义的强制规则:必须用 Bot 身份操作。于是我读了 **`lark_wiki_operate_as_bot`** 技能,按其链路执行:
```bash
# 步骤1获取节点信息
lark-cli wiki spaces get_node --params '{"token":"IhDYwI…HnQh"}' --as bot
# → 返回 obj_token: IUJGdZS98oKbLix5zZ4cramQnke, obj_type: docx
# 步骤2读取文档 markdown
lark-cli docs +fetch --doc IUJGdZS98oKbLix5zZ4cramQnke --as bot
# → 返回文档全文 markdown其中包含两个 <sheet token=*** 标签
```
### 第二步:读取内嵌 Sheet
文档 markdown 中有 `<sheet token="VBozs…"/>` 等标签,触发了 **`feishu-embedded-sheet`** 技能。按其流程:
```bash
# 获取 Bot token
curl -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" ...
# 获取 sheet 元数据6个子表
curl "https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/VBozs8u24h4KgdtSSiFc9vHEnBd/sheets/query"
# 读取知识点 sheet (QNssxC, 7行)
# 读取剧本 sheet (Q8AyX5, 183行) — 分三次读 (1-50, 51-120, 121-183)
```
### 第三步:理解组件配置格式
剧本 sheet 中包含"对话朗读、图片单选、对话组句、对话选读、图片多选、对话挖空、听力拖拽"共 7 种题型,我读了 **5 个组件配置 skill** 来理解每种题型的字段规范:
| Skill | 对应题型 |
|---|---|
| `dialogue-reading-config` | 对话朗读 |
| `dialogue-choose-config` | 对话选读 |
| `dialogue-fill-in-blanks-config` | 对话挖空 |
| `dialogue-sentence-building-config` | 对话组句 |
| `dialogue-single-choice-image-config` | 图片单选 |
还读了 **`core-content-json-standard`** 了解核心互动内容的 JSON 标准结构(但最终未使用该格式,因为用户要的是原始配置的提取而非标准化 JSON
### 第四步:解析 & 生成
17 个组件的配置散落在 183 行数据中,不是标准 JSON 格式,而是飞书文档中的结构化文本(`【任务标题】\n...\n【情境引入】\n...` 等)。用 Python 脚本按 `【】` 标记解析每个组件的配置字段为 JSON
```python
# 按 【xxx】 作为字段名,提取字段内容
def parse_config(text):
result = {}
for line in text.strip().split('\n'):
if line.startswith('【') and line.endswith('】'):
# 新字段开始
else:
# 追加到当前字段
return result
```
### 第五步:生成 HTML & 发送
用户要 HTML 而非 JSON生成了带折叠卡片、快速导航、类型标签的自包含 HTML通过 `message` 工具以文件附件发回。
---
## 关键决策点
1. **为什么没直接用 core-content-json-standard** — 该标准覆盖的是核心互动(合作阅读、合作听力等 14 种题型),与剧本中的对话互动组件(图片单选/对话朗读/挖空/组句等)是两套不同的配置体系,字段结构完全不同,不适用。
2. **为什么一次性读了 5 个 config skill** — 因为我需要确认每种题型的配置字段规范,而这些 skill 各管一种题型,只能逐个读取。
3. **为什么用 Python 而非纯 shell 解析?** — shell 处理多行嵌套文本和 JSON 生成容易出错(之前 MEMORY.md 里就记过 shell 转义的坑Python 更可靠。
---
如果你想让我把这个处理流程固化为一个可复用的 skill我可以创建。或者你有其他改进方向
user: 组件配置-json https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh
assistant: 上次没用对 skill。正确的入口在 `business_production/组件配置/interactive-component-json/`,有完整的 LLM 驱动流水线。现在直接跑:
assistant: 流水线已完成并自动发送 HTML 报告给你。
**结果汇总:** 16/17 成功1 个失败
| 状态 | 组件 | ID | cType |
|---|---|---|---|
| ✓ | 图片单选 | 1217201 | mid_image_choose |
| ✓ | 对话朗读 | 1217202 | mid_dialog_repeat |
| ✓ | 对话朗读 | 1217203 | mid_dialog_repeat |
| ✓ | 对话组句 | 1217204 | mid_dialog_sentence |
| ✓ | 对话朗读 | 1217205 | mid_dialog_repeat |
| ✓ | 对话选读 | 1217206 | mid_dialog_select |
| ✓ | 图片多选 | 1217207 | mid_image_multiple |
| ✓ | 图片单选 | 1217208 | mid_image_choose |
| ✗ | **对话挖空** | **1217209** | **LLM JSON 解析失败** |
| ✓ | 对话选读 | 1217210 | mid_dialog_select |
| ✓ | 对话朗读 | 1217211 | mid_dialog_repeat |
| ✓ | 对话组句 | 1217212 | mid_dialog_sentence |
| ✓ | 对话挖空 | 1217213 | mid_dialog_fillin |
| ✓ | 听力拖拽 | 1217214 | core_listening_drag (7步) |
| ✓ | 对话选读 | 1217215 | mid_dialog_select |
| ✓ | 对话挖空 | 1217216 | mid_dialog_fillin |
| ✓ | 对话朗读 | 1217217 | mid_dialog_repeat |
**失败原因:** ID 1217209 的 LLM 返回了非标准 JSONdoubao 在字段尾多了额外数据),需要重试。另外 MySQL 知识点匹配全线失败 — `Access denied (using password: NO)`pipeline 中 kp_matcher 的数据库密码未配置。

301
memory/2026-05-25.md Normal file
View File

@ -0,0 +1,301 @@
# 2026-05-25 工作日志
## 组件配置 pipeline单独重试 cId=1217214
- [童瑶] 请求单独重试 pipeline 中的失败组件 cId=1217214听力拖拽 / core_listening_drag
- 根因doubao 模型在 Step 5/7 (dialogList) 中反复输出中文冒号 `"trans"` 而非 `"trans":`
- 修复:在 `business_production/组件配置/interactive-component-json/scripts/llm_client.py``call_for_json()` 中添加 `_fix_llm_json_errors()` 自动修复函数(中文冒号、尾部逗号),最多重试 3 次
- 结果cId=1217214 重新生成成功component_id=10927/7 步骤全部通过
- HTML 报告已通过飞书 Bot 发送给 gc9f72ff童瑶包含全部 17 个组件
- Wiki URL: `https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh`
- Script ID: `IUJGdZS98oKbLix5zZ4cramQnke`
## 英文台词生产L1-S2-U19-L1 客厅游戏
- [童瑶] 请求对 `https://makee-interactive.feishu.cn/wiki/XoGZwgrRMiGk9vkYNWmcegs9nyh` 执行英文台词生产
- 文档标题L1-S2-U19-L1 客厅游戏
- 文档表格结构3 列表格(场景编号 | 场景名称 | 剧本内容),共 5 行数据
- 该文档的表结构(列名:'开场'/' '/ '/')与 gen_script.py feishu 模式默认期望的"中文台词"/"英文台词"列名不匹配
- 尝试用 `--source-col '/'`(匹配 Col 2 剧本内容列)运行 pipeline等级 S2
- LLM 配置OpenAI SDK → volcano ark endpoint `https://ark.cn-beijing.volces.com/api/v3`API KEY `32994652-505c-492b-b6da-616ec5c5733c`model `ep-m-20260301164317-vmmj4`
- 脚本路径:`business_production/英文台词/skills/kids-english-script-production/scripts/gen_script.py`
### 英文台词生产完成结果
- 文档 `L1-S2-U19-L1 客厅游戏` 5 个场景的 S2 英文台词已生成
- 结果保存到:`business_production/英文台词/output/L1-S2-U19-L1_英语台词.txt`
- 修改了 gen_script.pytimeout 60→180添加 `extra_body={"thinking":{"type":"disabled"}}`
- 已知问题Scene 3 部分台词角色名显示为"角色:"LLM 输出瑕疵);飞书表格无"英文台词"列无法自动写回
- 需要童瑶在 wiki 表格中手动添加"英文台词"列后才能实现自动写回
### 英文台词 Sheet 写回2026-05-25 补充)
- [童瑶] 提供新文档链接 `https://makee-interactive.feishu.cn/wiki/UvDWwW4LSi8bfGkVUshcoehWnGd`(副本),文档内含嵌入式 Sheet
- Sheet token: `VgPwsodzthsk9Vti8GocrbH2nEe`sheet_id: `wMQVyV`
- Sheet 列结构:类型/配置信息/剧情描述/角色名/编剧台词/**英文台词**/组件配置/知识点
- 95 行对话需要写入 F 列英文台词55 行简单台词≤5词直接复制原英文40 行复杂台词经 pipeline 处理
- ⚠️ gen_script.py pipeline 对纯英文输入的适配效果不佳(严重偏离原文语义,如"Really? You don't have to work today?"→"Is that a fun story?"
- 最终方案40 行复杂台词回退为原文直接复制,避免 pipeline 输出偏离
- 写入方法:飞书 Sheets v2 API `PUT values`range 格式 `sheetId!F{row}:F{row}`
- 脚本:`business_production/英文台词/scripts/batch_write_english.py`
### 英文台词 Sheet 写回:来自 Vala 的包裹2026-05-25
- [童瑶] 新文档 `https://makee-interactive.feishu.cn/wiki/IzJ5w0jMziLe7tk1kPdcYozdnyg`来自Vala的包裹
- Sheet: `OFUwsmNcjhVaRZtFz5rcI9nTnCo` / `wMQVyV`119 行对话全部 F 列为空
- 改进方案:**放弃 gen_script.py pipeline**(上次纯英文输入偏离严重),改用**直接 LLM 简化 prompt**
- Prompt 核心保留原文语义的前提下简化句长≤8词、替换难词、拆分长句
- 65 行简单台词≤5词直接复制原文54 行复杂台词走 LLM 简化
- 效果显著优于 pipeline"Dear, there is something I must tell you."→"Hey, I have something to tell you." 语义完整保留
- 脚本:`business_production/英文台词/scripts/batch_simplify_and_write.py`
- 经验纯英文→S2 简化用直接 LLM prompt 比 gen_script pipeline 更准确
## 写作P1 16条解析简化输出 [刘彦江]
- [刘彦江] 要求将写作P1 021301~032901共16条ID的explanation简化
- 标准:先称呼→按写作要求匹配正文→最后署名,格式类似"先称呼Dear Lucy再按三个要求匹配正文相册失踪对应...在哪丢的对应...请求帮忙找对应...最后署名"
- 已逐条输出15条解析021301按样例略过列表021401, 021501, 021701, 021801, 021901, 022001, 022101, 022201, 022301, 022401, 032501, 032601, 032701, 032801, 032901
- 022101特殊按故事逻辑排列非写作要求匹配因该题无编号要求而是按叙事顺序排列句子
## L1/L2 能力图谱梳理 [刘彦江] ⏳待确认
- [刘彦江] 分享了wiki文档 https://makee-interactive.feishu.cn/wiki/TFB9wJm4IilkCekyFdzcc42on6d
- 要求梳理L1 6阶段+L2 8阶段听说读写tag类型和考点在@刘彦江的位置输出方案
- 已输出四部分方案框架(见对话),用户尚未确认:
1. 各阶段听/说/读/写能力分布表格(汇总表 + 14阶段×4科目tag
2. 单项目卡描述≤100字4条分别覆盖听/说/读/写)
3. 能力考察项小标题≤12字每条≤70字总≤280字以听力Movers为例
4. 单能力项描述≤210字以"单句信息点抓取"为例)
- 待用户确认格式和内容方向后,再写入文档
## 能力图谱固定文案回填完成 [刘彦江]
- 文档: https://makee-interactive.feishu.cn/wiki/W5Vjw2fLiiCqfck0Mfzc0xkrnte
- 严格按照L1/L2阶段分配文档的"阶段目标"描述
- 回填内容:
- L1: 阶段1听口 / 阶段2听口阅 / 阶段3-6听口阅写
- L2: 阶段1-8听口阅写
- 各阶段描述均对齐文档设定的阶段目标如L1阶段1:基础字母识别关键词抓取, 阶段3:数字/时间细节抓取同义替换识别等)
- 格式: 每阶段下听力/口语/阅读/写作各一段≤210字描述
## 能力图谱考察项文档写入完成 [刘彦江] ✅已完成
- 文档: https://makee-interactive.feishu.cn/wiki/W5Vjw2fLiiCqfck0Mfzc0xkrnte (考察项描述目录)
- 14 阶段 14 张表全部填充L1 阶段1-6 + L2 阶段1-8
- 考察项格式:考察项名称 + 描述不标注题型来源括号内Part编号等
- 表格格式3列单项 / 考察项 / 考察项描述单项列使用rowspan合并
### 生产数据 vs 设计文档的差异
- **设计文档不可信**L1/L2 阶段分配文档Jjd8wghbeidXt2kDFaPcU09wnzc / D9EFwVC9Gi9nCAk4heec2qYCnwe与实际生产不一致
- 实际生产数据来源:生产文档「单元挑战旧题目解析待补充 ID 整理」(CS8Ww2XaSiFwhakQenycRU5ZnYf)
- Part→题型映射来源于多维表格 (App Token: CMHSbUUjka3TrUsaxxEc297ongf)
- 关键差异L1阶段1实际有阅读(P7)和写作(P3),不是设计文档声称的「仅听力+口语」
- 生产数据覆盖范围有限L1 仅到 ~U33 (032901)L2 仅到 ~U16 (121601)
- 无生产数据的阶段L1阶段5-6, L2阶段4-8使用设计文档 + 题型递进规律推算
### 飞书 lark-table 写入注意事项
- rowspan 在飞书 markdown 回写时会被自动剥离
- 表格写入后单项列会逐行重复显示而非合并单元格(飞书原生限制)
- 写入前需 extract 原始文档的 S1 表格,再与生成的新表格拼接后 overwrite
### Part→题型映射速查来自多维表格 CMHSbUUjka3TrUsaxxEc297ongf
- 听力: P1=图片选择题, P2=表格填空题, P3=长对话选择, P4=短对话选择题, P5=信息匹配题, P7=听力拖拽
- 口语: P1=日常回答, P2=话题讨论, P3=看图回答, P4=看图识物
- 阅读: P1=信息匹配题, P2=段落匹配题, P3=长文选择题, P4=完形填空题, P5=开放填空题, P6=看图判断题, P7=看图回答题
- 写作: P1=邮件回复, P2=看图写作, P3=看图回答题
## 童瑶反馈:小研使用问题记录 [童瑶] ⚠️待改进
- 来源:群聊 oc_aed6c8ed8c59653aca4fabc8cf3a85162026-05-25 17:52
### 任务1英文台词生产
- **问题**:有概率读取不到剧本、或回填不到【英文台词】列
- **当前 workaround**:重复任务+明确位置告诉它「本文档包含嵌入式Sheet」「F列是英文台词」
### 任务2组件生产
- **问题1**:有概率回填不到【组件配置】列
- **问题2**:核心互动无法读取,需要人工写入
### 任务3组件配置-json
- **问题1**:只发指令不指定 skill 时会混淆任务2组件生产和任务3组件配置-json
- **问题2**:单一组件执行失败后,重生整体关卡组件时推送报错
## 能力图谱考察项:题型名 → 技能点描述 改写完成 [刘彦江] ✅
- 刘彦江确认改为技能点描述风格,逐条改写
- 14 阶段 4 科目全部重写,目标文档: `W5Vjw2fLiiCqfck0Mfzc0xkrnte`
- L2 阶段1-2 阅读/写作从"无"补为实际技能点(刘彦江确认"L2 阶段1-2 阅读和写作都是有题型的"
- L1 阶段1 阅读/写作也从"无"补为实际技能点
- 0 个"无",全量覆盖
- 生成脚本: `tmp/build_skill_points.py`
## 生产覆盖范围修正 [刘彦江]
- L1 生产到 **U16**(非 U33
- L2 生产到 **U29**(非 U16
- 已同步更新 `business_knowledge/单元挑战全貌.md`
## 单元挑战全貌文档 [刘彦江]
- 创建 `business_knowledge/单元挑战全貌.md`
- 覆盖九大板块业务定位、阶段划分、题型体系18种、能力标签45个、生产流程ID规则/标准/写入陷阱、审校体系7+4项检查、生产覆盖现状、模块关联、快速链接
## L1/L2 难度等级映射 [刘彦江] ✅已确认
- L1-A: Starters入门+基础 (U1-U16) | L1-B: Starters达标 (U17-U24) | L1-C: Movers入门+基础 (U25-U40) | L1-D: Movers达标 (U41-U48)
- L2-A: Flyers入门+基础 (U1-U12) | L2-B: Flyers达标 (U13-U18) | L2-C: KET入门+基础 (U19-U30) | L2-D: KET强化+高位+达标 (U31-U48)
- 已写入 `business_knowledge/单元挑战全貌.md` §5.3
# 2026-05-25 工作日志
## 组件配置 pipeline单独重试 cId=1217214
- [童瑶] 请求单独重试 pipeline 中的失败组件 cId=1217214听力拖拽 / core_listening_drag
- 根因doubao 模型在 Step 5/7 (dialogList) 中反复输出中文冒号 `"trans"` 而非 `"trans":`
- 修复:在 `business_production/组件配置/interactive-component-json/scripts/llm_client.py``call_for_json()` 中添加 `_fix_llm_json_errors()` 自动修复函数(中文冒号、尾部逗号),最多重试 3 次
- 结果cId=1217214 重新生成成功component_id=10927/7 步骤全部通过
- HTML 报告已通过飞书 Bot 发送给 gc9f72ff童瑶包含全部 17 个组件
- Wiki URL: `https://makee-interactive.feishu.cn/wiki/IhDYwITBfii8cxkWsG1c0JWHnQh`
- Script ID: `IUJGdZS98oKbLix5zZ4cramQnke`
## 英文台词生产L1-S2-U19-L1 客厅游戏
- [童瑶] 请求对 `https://makee-interactive.feishu.cn/wiki/XoGZwgrRMiGk9vkYNWmcegs9nyh` 执行英文台词生产
- 文档标题L1-S2-U19-L1 客厅游戏
- 文档表格结构3 列表格(场景编号 | 场景名称 | 剧本内容),共 5 行数据
- 该文档的表结构(列名:'开场'/' '/ '/')与 gen_script.py feishu 模式默认期望的"中文台词"/"英文台词"列名不匹配
- 尝试用 `--source-col '/'`(匹配 Col 2 剧本内容列)运行 pipeline等级 S2
- LLM 配置OpenAI SDK → volcano ark endpoint `https://ark.cn-beijing.volces.com/api/v3`API KEY `32994652-505c-492b-b6da-616ec5c5733c`model `ep-m-20260301164317-vmmj4`
- 脚本路径:`business_production/英文台词/skills/kids-english-script-production/scripts/gen_script.py`
### 英文台词生产完成结果
- 文档 `L1-S2-U19-L1 客厅游戏` 5 个场景的 S2 英文台词已生成
- 结果保存到:`business_production/英文台词/output/L1-S2-U19-L1_英语台词.txt`
- 修改了 gen_script.pytimeout 60→180添加 `extra_body={"thinking":{"type":"disabled"}}`
- 已知问题Scene 3 部分台词角色名显示为"角色:"LLM 输出瑕疵);飞书表格无"英文台词"列无法自动写回
- 需要童瑶在 wiki 表格中手动添加"英文台词"列后才能实现自动写回
### 英文台词 Sheet 写回2026-05-25 补充)
- [童瑶] 提供新文档链接 `https://makee-interactive.feishu.cn/wiki/UvDWwW4LSi8bfGkVUshcoehWnGd`(副本),文档内含嵌入式 Sheet
- Sheet token: `VgPwsodzthsk9Vti8GocrbH2nEe`sheet_id: `wMQVyV`
- Sheet 列结构:类型/配置信息/剧情描述/角色名/编剧台词/**英文台词**/组件配置/知识点
- 95 行对话需要写入 F 列英文台词55 行简单台词≤5词直接复制原英文40 行复杂台词经 pipeline 处理
- ⚠️ gen_script.py pipeline 对纯英文输入的适配效果不佳(严重偏离原文语义,如"Really? You don't have to work today?"→"Is that a fun story?"
- 最终方案40 行复杂台词回退为原文直接复制,避免 pipeline 输出偏离
- 写入方法:飞书 Sheets v2 API `PUT values`range 格式 `sheetId!F{row}:F{row}`
- 脚本:`business_production/英文台词/scripts/batch_write_english.py`
### 英文台词 Sheet 写回:来自 Vala 的包裹2026-05-25
- [童瑶] 新文档 `https://makee-interactive.feishu.cn/wiki/IzJ5w0jMziLe7tk1kPdcYozdnyg`来自Vala的包裹
- Sheet: `OFUwsmNcjhVaRZtFz5rcI9nTnCo` / `wMQVyV`119 行对话全部 F 列为空
- 改进方案:**放弃 gen_script.py pipeline**(上次纯英文输入偏离严重),改用**直接 LLM 简化 prompt**
- Prompt 核心保留原文语义的前提下简化句长≤8词、替换难词、拆分长句
- 65 行简单台词≤5词直接复制原文54 行复杂台词走 LLM 简化
- 效果显著优于 pipeline"Dear, there is something I must tell you."→"Hey, I have something to tell you." 语义完整保留
- 脚本:`business_production/英文台词/scripts/batch_simplify_and_write.py`
- 经验纯英文→S2 简化用直接 LLM prompt 比 gen_script pipeline 更准确
### 英文台词 Sheet 写回L1-S2-U19-L3 烛光大餐2026-05-25
- [童瑶] `https://makee-interactive.feishu.cn/wiki/WthGwzolCiv6gxkotzociQDUn3b`
- 文档含 2 个嵌入式 Sheet剧本在第二个 Sheet `GgGGtp`128 行对话)
- 129 行对话73 简单 + 56 复杂,全部写入 F 列
- Sheet token: `Mv2GsM0Zshk8Xdt5ko4cf8hwnvd` / `GgGGtp`
### 英文台词 Sheet 写回L1-S2-U19-L4 明天见2026-05-25
- [童瑶] `https://makee-interactive.feishu.cn/wiki/NhNowRCoriHcedkfY1Bcz1z5ncg`
- 93 行对话44 简单 + 49 复杂,全部写入 F 列
- Sheet token: `J5FEsRvREh40PSt6jq0cwVPnCQ` / `wMQVyV`
### 英文台词 Sheet 写回L1-S2-U19-L5 星际通讯2026-05-25
- [童瑶] `https://makee-interactive.feishu.cn/wiki/Koh3wKGx5idh9JkrZxJcJDfRnoe`
- 153 行对话89 简单 + 64 复杂,全部写入 F 列
- Sheet token: `UK7ms9UrdhJllftVOaOc4r4envg` / `wMQVyV`
### S2-U19 英文台词生产汇总
| 文档 | 行数 | 简单 | 复杂 | Sheet token |
|------|------|------|------|-------------|
| L1 客厅游戏 | 95 | 55 | 40 | VgPwsodzthsk9Vti8GocrbH2nEe/wMQVyV |
| L2 来自 Vala 的包裹 | 119 | 65 | 54 | OFUwsmNcjhVaRZtFz5rcI9nTnCo/wMQVyV |
| L3 烛光大餐 | 129 | 73 | 56 | Mv2GsM0Zshk8Xdt5ko4cf8hwnvd/GgGGtp |
| L4 明天见 | 93 | 44 | 49 | J5FEsRvREh40PSt6jq0cwVPnCQ/wMQVyV |
| L5 星际通讯 | 153 | 89 | 64 | UK7ms9UrdhJllftVOaOc4r4envg/wMQVyV |
| **合计** | **589** | **326** | **263** | |
- 方法:复杂台词用直接 LLM simplify prompt保留语义+简化句长≤8词简单台词≤5词无从句直接复制
- ⚠️ 首个文档客厅游戏复杂台词回退为原文复制pipeline 偏离),后续 4 个文档全部用 LLM 简化方案
## 知识库文档移除
- [童瑶] 请求移除 `https://makee-interactive.feishu.cn/wiki/BR54wB9IWiWIjykyJzDc4cKFnlc`
- 文档L1-S2-U23-L3 剧本 · 开场doc_id: GNl2dAiSPoX4ZXxbwOrcTHZmnHf
- 知识库Content Universespace_id: 7412143055920414722
- ⚠️ 飞书 Wiki V2 DELETE API 存在 bugquery param `obj_type=docx` 始终报 99992402 "obj_type is required"
- 替代方案:用飞书 Drive API `DELETE /open-apis/drive/v1/files/{doc_token}?type=docx` 删除文件(不归入回收站)
- 验证:删除后再次查询 node → 131005 "not found",确认已移除
## 写作P1 16条解析简化输出 [刘彦江]
- [刘彦江] 要求将写作P1 021301~032901共16条ID的explanation简化
- 标准:先称呼→按写作要求匹配正文→最后署名,格式类似"先称呼Dear Lucy再按三个要求匹配正文相册失踪对应...在哪丢的对应...请求帮忙找对应...最后署名"
- 已逐条输出15条解析021301按样例略过列表021401, 021501, 021701, 021801, 021901, 022001, 022101, 022201, 022301, 022401, 032501, 032601, 032701, 032801, 032901
- 022101特殊按故事逻辑排列非写作要求匹配因该题无编号要求而是按叙事顺序排列句子
## L1/L2 能力图谱梳理 [刘彦江] ⏳待确认
- [刘彦江] 分享了wiki文档 https://makee-interactive.feishu.cn/wiki/TFB9wJm4IilkCekyFdzcc42on6d
- 要求梳理L1 6阶段+L2 8阶段听说读写tag类型和考点在@刘彦江的位置输出方案
- 已输出四部分方案框架(见对话),用户尚未确认:
1. 各阶段听/说/读/写能力分布表格(汇总表 + 14阶段×4科目tag
2. 单项目卡描述≤100字4条分别覆盖听/说/读/写)
3. 能力考察项小标题≤12字每条≤70字总≤280字以听力Movers为例
4. 单能力项描述≤210字以"单句信息点抓取"为例)
- 待用户确认格式和内容方向后,再写入文档
## 能力图谱固定文案回填完成 [刘彦江]
- 文档: https://makee-interactive.feishu.cn/wiki/W5Vjw2fLiiCqfck0Mfzc0xkrnte
- 严格按照L1/L2阶段分配文档的"阶段目标"描述
- 回填内容:
- L1: 阶段1听口 / 阶段2听口阅 / 阶段3-6听口阅写
- L2: 阶段1-8听口阅写
- 各阶段描述均对齐文档设定的阶段目标如L1阶段1:基础字母识别关键词抓取, 阶段3:数字/时间细节抓取同义替换识别等)
- 格式: 每阶段下听力/口语/阅读/写作各一段≤210字描述
## 能力图谱考察项文档写入完成 [刘彦江] ✅已完成
- 文档: https://makee-interactive.feishu.cn/wiki/W5Vjw2fLiiCqfck0Mfzc0xkrnte (考察项描述目录)
- 14 阶段 14 张表全部填充L1 阶段1-6 + L2 阶段1-8
- 考察项格式:考察项名称 + 描述不标注题型来源括号内Part编号等
- 表格格式3列单项 / 考察项 / 考察项描述单项列使用rowspan合并
### 生产数据 vs 设计文档的差异
- **设计文档不可信**L1/L2 阶段分配文档Jjd8wghbeidXt2kDFaPcU09wnzc / D9EFwVC9Gi9nCAk4heec2qYCnwe与实际生产不一致
- 实际生产数据来源:生产文档「单元挑战旧题目解析待补充 ID 整理」(CS8Ww2XaSiFwhakQenycRU5ZnYf)
- Part→题型映射来源于多维表格 (App Token: CMHSbUUjka3TrUsaxxEc297ongf)
- 关键差异L1阶段1实际有阅读(P7)和写作(P3),不是设计文档声称的「仅听力+口语」
- 生产数据覆盖范围有限L1 仅到 ~U33 (032901)L2 仅到 ~U16 (121601)
- 无生产数据的阶段L1阶段5-6, L2阶段4-8使用设计文档 + 题型递进规律推算
### 飞书 lark-table 写入注意事项
- rowspan 在飞书 markdown 回写时会被自动剥离
- 表格写入后单项列会逐行重复显示而非合并单元格(飞书原生限制)
- 写入前需 extract 原始文档的 S1 表格,再与生成的新表格拼接后 overwrite
### Part→题型映射速查来自多维表格 CMHSbUUjka3TrUsaxxEc297ongf
- 听力: P1=图片选择题, P2=表格填空题, P3=长对话选择, P4=短对话选择题, P5=信息匹配题, P7=听力拖拽
- 口语: P1=日常回答, P2=话题讨论, P3=看图回答, P4=看图识物
- 阅读: P1=信息匹配题, P2=段落匹配题, P3=长文选择题, P4=完形填空题, P5=开放填空题, P6=看图判断题, P7=看图回答题
- 写作: P1=邮件回复, P2=看图写作, P3=看图回答题
## 童瑶反馈:小研使用问题记录 [童瑶] ⚠️待改进
- 来源:群聊 oc_aed6c8ed8c59653aca4fabc8cf3a85162026-05-25 17:52
### 任务1英文台词生产
- **问题**:有概率读取不到剧本、或回填不到【英文台词】列
- **当前 workaround**:重复任务+明确位置告诉它「本文档包含嵌入式Sheet」「F列是英文台词」
### 任务2组件生产
- **问题1**:有概率回填不到【组件配置】列
- **问题2**:核心互动无法读取,需要人工写入
### 任务3组件配置-json
- **问题1**:只发指令不指定 skill 时会混淆任务2组件生产和任务3组件配置-json
- **问题2**:单一组件执行失败后,重生整体关卡组件时推送报错
## 能力图谱考察项:题型名 → 技能点描述 改写完成 [刘彦江] ✅
- 刘彦江确认改为技能点描述风格,逐条改写
- 14 阶段 4 科目全部重写,目标文档: `W5Vjw2fLiiCqfck0Mfzc0xkrnte`
- L2 阶段1-2 阅读/写作从"无"补为实际技能点(刘彦江确认"L2 阶段1-2 阅读和写作都是有题型的"
- L1 阶段1 阅读/写作也从"无"补为实际技能点
- 0 个"无",全量覆盖
- 生成脚本: `tmp/build_skill_points.py`
## 生产覆盖范围修正 [刘彦江]
- L1 生产到 **U16**(非 U33
- L2 生产到 **U29**(非 U16
- 已同步更新 `business_knowledge/单元挑战全貌.md`
## 单元挑战全貌文档 [刘彦江]
- 创建 `business_knowledge/单元挑战全貌.md`
- 覆盖九大板块业务定位、阶段划分、题型体系18种、能力标签45个、生产流程ID规则/标准/写入陷阱、审校体系7+4项检查、生产覆盖现状、模块关联、快速链接
## L1/L2 难度等级映射 [刘彦江] ✅已确认
- L1-A: Starters入门+基础 (U1-U16) | L1-B: Starters达标 (U17-U24) | L1-C: Movers入门+基础 (U25-U40) | L1-D: Movers达标 (U41-U48)
- L2-A: Flyers入门+基础 (U1-U12) | L2-B: Flyers达标 (U13-U18) | L2-C: KET入门+基础 (U19-U30) | L2-D: KET强化+高位+达标 (U31-U48)
- 已写入 `business_knowledge/单元挑战全貌.md` §5.3

View File

@ -0,0 +1,726 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>L1-S2-U17-L2 迟到的包裹 — 组件配置</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Noto+Sans+SC:wght@400;500;700&display=swap');
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', 'Noto Sans SC', -apple-system, sans-serif; background: #f5f6fa; color: #2d3436; line-height: 1.6; }
.header { background: linear-gradient(135deg, #6c5ce7, #a29bfe); color: #fff; padding: 28px 32px; }
.header h1 { font-size: 22px; font-weight: 700; margin-bottom: 6px; }
.header .meta { font-size: 13px; opacity: .85; }
.summary { display: flex; gap: 16px; padding: 16px 32px; background: #fff; border-bottom: 1px solid #e8e8e8; flex-wrap: wrap; }
.stat { background: #f8f9fc; border-radius: 10px; padding: 10px 16px; min-width: 100px; }
.stat .num { font-size: 24px; font-weight: 700; color: #6c5ce7; }
.stat .label { font-size: 12px; color: #888; margin-top: 2px; }
.container { max-width: 1200px; margin: 0 auto; padding: 24px 32px; }
.section-title { font-size: 16px; font-weight: 700; color: #6c5ce7; margin: 28px 0 12px; padding-bottom: 6px; border-bottom: 2px solid #6c5ce7; }
.section-title:first-child { margin-top: 0; }
.comp-card { background: #fff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,.06); margin-bottom: 16px; overflow: hidden; transition: box-shadow .2s; }
.comp-card:hover { box-shadow: 0 4px 20px rgba(0,0,0,.1); }
.comp-header { display: flex; align-items: center; gap: 12px; padding: 14px 20px; background: #fafbfc; border-bottom: 1px solid #eee; cursor: pointer; user-select: none; }
.comp-header .seq { width: 28px; height: 28px; border-radius: 50%; background: #6c5ce7; color: #fff; font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.comp-header .id-badge { font-family: 'SF Mono','Fira Code',monospace; font-size: 11px; color: #888; background: #eee; padding: 2px 8px; border-radius: 4px; flex-shrink: 0; }
.comp-header .type-badge { font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; flex-shrink: 0; }
.type-图片单选 { background: #e8f5e9; color: #2e7d32; }
.type-图片多选 { background: #e8f5e9; color: #2e7d32; }
.type-对话朗读 { background: #e3f2fd; color: #1565c0; }
.type-对话组句 { background: #fff3e0; color: #e65100; }
.type-对话选读 { background: #f3e5f5; color: #7b1fa2; }
.type-对话挖空 { background: #fce4ec; color: #c62828; }
.type-听力拖拽 { background: #e0f7fa; color: #00695c; }
.comp-header .title { font-weight: 600; font-size: 14px; flex: 1; }
.comp-header .arrow { font-size: 12px; color: #aaa; transition: transform .2s; }
.comp-body { padding: 0 20px 20px; display: block; }
.field { margin-top: 14px; }
.field-label { font-size: 11px; font-weight: 700; color: #999; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 4px; display: flex; align-items: center; gap: 6px; }
.field-label::before { content: ''; width: 4px; height: 4px; border-radius: 50%; background: #6c5ce7; }
.field-content { font-size: 13px; color: #444; background: #f8f9fc; border-radius: 8px; padding: 10px 14px; white-space: pre-wrap; word-break: break-word; border: 1px solid #eee; }
.field-content.empty { color: #bbb; font-style: italic; }
.kp-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.kp-tag { font-size: 10px; background: #ede7f6; color: #6c5ce7; padding: 1px 8px; border-radius: 10px; font-weight: 500; }
.collapsed .comp-body { display: none; }
.collapsed .arrow { transform: rotate(-90deg); }
.toc { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 20px; }
.toc a { font-size: 12px; color: #6c5ce7; text-decoration: none; padding: 4px 12px; border-radius: 16px; background: #ede7f6; transition: background .2s; }
.toc a:hover { background: #d1c4e9; }
.warn { background: #fff9c4; color: #f57f17; font-size: 12px; padding: 3px 8px; border-radius: 4px; margin-left: 8px; flex-shrink: 0; }
@media print {
.comp-card { break-inside: avoid; box-shadow: none; border: 1px solid #ddd; }
.comp-body { display: block !important; }
body { background: #fff; }
}
</style>
</head>
<body>
<div class="header">
<h1>📝 L1-S2-U17-L2 迟到的包裹</h1>
<div class="meta">知悉空间 · 1776416977 创建 · 1779690402 更新 · 共 17 个互动组件</div>
</div>
<div class="summary">
<div class="stat"><div class="num">5</div><div class="label">对话朗读</div></div>
<div class="stat"><div class="num">3</div><div class="label">对话选读</div></div>
<div class="stat"><div class="num">3</div><div class="label">对话挖空</div></div>
<div class="stat"><div class="num">2</div><div class="label">图片单选</div></div>
<div class="stat"><div class="num">2</div><div class="label">对话组句</div></div>
<div class="stat"><div class="num">1</div><div class="label">图片多选</div></div>
<div class="stat"><div class="num">1</div><div class="label">听力拖拽</div></div>
</div>
<div class="container">
<div class="section-title">📚 知识点总览</div>
<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:20px;">
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">get — v. 收到</span>
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">month — n. 月</span>
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">year — n. 年</span>
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">ago — adv. 以前</span>
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">… be happy with …</span>
<span class="kp-tag" style="font-size:13px;padding:4px 14px;">… month(s)/year(s) ago.</span>
</div>
<div class="section-title">🔗 快速导航</div>
<div class="toc">
<a href="#c1">1. 图片单选 1217201</a>
<a href="#c2">2. 对话朗读 1217202</a>
<a href="#c3">3. 对话朗读 1217203</a>
<a href="#c4">4. 对话组句 1217204</a>
<a href="#c5">5. 对话朗读 1217205</a>
<a href="#c6">6. 对话选读 1217206</a>
<a href="#c7">7. 图片多选 1217207</a>
<a href="#c8">8. 图片单选 1217208</a>
<a href="#c9">9. 对话挖空 1217209</a>
<a href="#c10">10. 对话选读 1217210</a>
<a href="#c11">11. 对话朗读 1217211</a>
<a href="#c12">12. 对话组句 1217212</a>
<a href="#c13">13. 对话挖空 1217213</a>
<a href="#c14">14. 听力拖拽 1217214</a>
<a href="#c15">15. 对话选读 1217215</a>
<a href="#c16">16. 对话挖空 1217216</a>
<a href="#c17">17. 对话朗读 1217217</a>
</div>
<!-- 1 -->
<div class="section-title" id="c1">1. 图片单选 — 为包裹找到正确的日期牌子</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">1</span><span class="id-badge">1217201</span>
<span class="type-badge type-图片单选">图片单选</span>
<span class="title">为包裹找到正确的日期牌子</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content">Jay: Help me find the right place!</div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">Find the "Days $Ago$" sign. (音频)
选项:
00
01
02
答案:
00
辅助信息days ago 指"几天前"。</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 Jay: Bingo!
错误 Jay: No! Look! This package is from 3 days ago!</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">ago</span></div>
</div>
</div>
<!-- 2 -->
<div class="section-title" id="c2">2. 对话朗读 — 朗读90天前的包裹信息</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">2</span><span class="id-badge">1217202</span>
<span class="type-badge type-对话朗读">对话朗读</span>
<span class="title">朗读90天前的包裹信息</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:互动内容</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">User: It's 90 days ago...(朗读)</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">ago</span></div>
</div>
</div>
<!-- 3 -->
<div class="section-title" id="c3">3. 对话朗读 — 理解天数和月数的换算</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">3</span><span class="id-badge">1217203</span>
<span class="type-badge type-对话朗读">对话朗读</span>
<span class="title">理解天数和月数的换算</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:互动内容</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content">User: No! 90 days! It is about...</div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">User: 3 months!(朗读)</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content">User: This is from months ago!</div>
</div>
<div class="kp-tags"><span class="kp-tag">month</span></div>
</div>
</div>
<!-- 4 -->
<div class="section-title" id="c4">4. 对话组句 — 用单词组句描述包裹信息</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">4</span><span class="id-badge">1217204</span>
<span class="type-badge type-对话组句">对话组句</span>
<span class="title">用单词组句描述包裹信息</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:互动内容</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">要求:用所给单词或短语组句
It says 24 months ago.(音频)
选项1it says
选项2months ago
选项324
答案It says 24 months ago.</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 无
错误 Jay: Try again! Read what the package says.</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">... month(s)/year(s) ago.</span></div>
</div>
</div>
<!-- 5 -->
<div class="section-title" id="c5">5. 对话朗读 — 朗读90天前的包裹信息 <span class="warn">⚠ 标题有误,实际为"2 years"</span></div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">5</span><span class="id-badge">1217205</span>
<span class="type-badge type-对话朗读">对话朗读</span>
<span class="title">That's 2 years! <span style="color:#f57f17;font-size:11px;">⚠标题误写为"朗读90天前的包裹信息"</span></span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:互动内容</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">User: That's 2 years!(朗读)</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">year</span></div>
</div>
</div>
<!-- 6 -->
<div class="section-title" id="c6">6. 对话选读 — 选择你想表达的感受</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">6</span><span class="id-badge">1217206</span>
<span class="type-badge type-对话选读">对话选读</span>
<span class="title">选择你想表达的感受</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">要求:选择一个你想表达的观点
选项:(音频)
选项1That's a long time ago!
- 反馈 Jay: You are right.
选项2That is long, long ago!
- 反馈 Jay: You are right.</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">ago</span></div>
</div>
</div>
<!-- 7 -->
<div class="section-title" id="c7">7. 图片多选 — 找出几个月前的包裹</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">7</span><span class="id-badge">1217207</span>
<span class="type-badge type-图片多选">图片多选</span>
<span class="title">找出几个月前的包裹</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">Let's find the packages from months $ago$. (音频)
选项:
00
01
02
答案:
01
02</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 User: Those two are months ago!
错误 Jay: Shall we check again?</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
</div>
</div>
<!-- 8 -->
<div class="section-title" id="c8">8. 图片单选 — 找出写有一年前的包裹</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">8</span><span class="id-badge">1217208</span>
<span class="type-badge type-图片单选">图片单选</span>
<span class="title">找出写有一年前的包裹</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content">Jay: Help me find the right place!</div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">Find the "Years $Ago$" package in the picture. (音频)
选项:
00
01
02
答案:
02
辅助信息:"a year ago" 指"一年前"。</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 User: This one is a year ago!
错误 Jay: Are you sure? Look again!</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
</div>
</div>
<!-- 9 -->
<div class="section-title" id="c9">9. 对话挖空 — 补全对Sunny说的句子</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">9</span><span class="id-badge">1217209</span>
<span class="type-badge type-对话挖空">对话挖空</span>
<span class="title">补全对Sunny说的句子</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">You must ___ it!(音频)
选项1be happy with正确
选项2happy with</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 User: You must be happy with it!
错误 Sunny: That doesn't sound quite right...</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">... be happy with...</span></div>
</div>
</div>
<!-- 10 -->
<div class="section-title" id="c10">10. 对话选读 — 选择帮Grace拿包裹的说法</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">10</span><span class="id-badge">1217210</span>
<span class="type-badge type-对话选读">对话选读</span>
<span class="title">选择帮Grace拿包裹的说法</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">要求:选择一个你想表达的观点
选项:(音频)
选项1Let me get it!
- 反馈 Grace: Thank you, kid.
选项2I will get it!
- 反馈 Grace: Thank you, kid.</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">get</span></div>
</div>
</div>
<!-- 11 -->
<div class="section-title" id="c11">11. 对话朗读 — 对Anna的提醒</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">11</span><span class="id-badge">1217211</span>
<span class="type-badge type-对话朗读">对话朗读</span>
<span class="title">对Anna的提醒</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:无</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">User: You will not be happy with it.(朗读)</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">... be happy with...</span></div>
</div>
</div>
<!-- 12 -->
<div class="section-title" id="c12">12. 对话组句 — 用单词组句主动帮忙</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">12</span><span class="id-badge">1217212</span>
<span class="type-badge type-对话组句">对话组句</span>
<span class="title">用单词组句主动帮忙</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">要求:用所给单词或短语组句
Can I get it for you?(音频)
选项1for you
选项2can I
选项3get it
答案Can I get it for you?</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 Jack: You are very kind. But I just want to say...
错误 Jack: I beg your pardon?</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">get</span></div>
</div>
</div>
<!-- 13 -->
<div class="section-title" id="c13">13. 对话挖空 — 补全对Jack说的话</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">13</span><span class="id-badge">1217213</span>
<span class="type-badge type-对话挖空">对话挖空</span>
<span class="title">补全对Jack说的话</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:互动内容互动反馈</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">But this meat is from 2 ___ !(音频)
选项1years ago正确
选项2days ago</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 Jack: Perfect!
错误 Jack: No, look at the sign on it!</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
</div>
</div>
<!-- 14 -->
<div class="section-title" id="c14">14. 听力拖拽 — 告诉Lin你们分发包裹的事迹</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">14</span><span class="id-badge">1217214</span>
<span class="type-badge type-听力拖拽">听力拖拽</span>
<span class="title">告诉Lin你们分发包裹的事迹</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">任务背景</div>
<div class="field-content">包裹大作战!你和 Jay 热火朝天地干了半天,把很多包裹带给了他们的主人。快来回顾一下你们的战果吧!</div>
</div>
<div class="field">
<div class="field-label">通关知识</div>
<div class="field-content">get — v. 收到
month — n. 月
year — n. 年
ago — adv. 以前
... month(s)/year(s) ago.</div>
</div>
<div class="field">
<div class="field-label">开场语</div>
<div class="field-content">Lin: Come on, tell me what you did!</div>
</div>
<div class="field">
<div class="field-label">听力文本</div>
<div class="field-content">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!</div>
</div>
<div class="field">
<div class="field-label">题目信息</div>
<div class="field-content">单空选择 — 选项图片编号00,01,02
答案图片编号01,00,02
Tom: 01 — Days Ago / 笔)
Sunny: 00 — Months Ago / 裙子)
Jack: 02 — Years Ago / 风干火腿)</div>
</div>
<div class="field">
<div class="field-label">学习过程</div>
<div class="field-content">句子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】</div>
</div>
<div class="kp-tags">
<span class="kp-tag">month</span>
<span class="kp-tag">year</span>
<span class="kp-tag">ago</span>
<span class="kp-tag">... month(s)/year(s) ago.</span>
</div>
</div>
</div>
<!-- 15 -->
<div class="section-title" id="c15">15. 对话选读 — 选择表达满意的方式</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">15</span><span class="id-badge">1217215</span>
<span class="type-badge type-对话选读">对话选读</span>
<span class="title">选择表达满意的方式</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">要求:选择一个你想表达的观点
选项:(音频)
选项1I am happy with it!
- 反馈 Jay: That's good!
选项2I am happy with the result!
- 反馈 Jay: That's good!</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">... be happy with...</span></div>
</div>
</div>
<!-- 16 -->
<div class="section-title" id="c16">16. 对话挖空 — 补全User想要包裹的句子</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">16</span><span class="id-badge">1217216</span>
<span class="type-badge type-对话挖空">对话挖空</span>
<span class="title">补全User想要包裹的句子</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">I want to ___ one for myself!(音频)
选项1get正确
选项2get up</div>
</div>
<div class="field">
<div class="field-label">互动反馈</div>
<div class="field-content">正确 无
错误 Jay: Hmm, that's not how we say it. Try again!</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
</div>
</div>
<!-- 17 -->
<div class="section-title" id="c17">17. 对话朗读 — 朗读收到帽子的喜悦</div>
<div class="comp-card">
<div class="comp-header" onclick="this.parentElement.classList.toggle('collapsed')">
<span class="seq">17</span><span class="id-badge">1217217</span>
<span class="type-badge type-对话朗读">对话朗读</span>
<span class="title">朗读收到帽子的喜悦</span>
<span class="arrow"></span>
</div>
<div class="comp-body">
<div class="field">
<div class="field-label">资源配置</div>
<div class="field-content">图片时机:无</div>
</div>
<div class="field">
<div class="field-label">情境引入</div>
<div class="field-content empty"></div>
</div>
<div class="field">
<div class="field-label">互动内容</div>
<div class="field-content">User: Now I get my own hat!(朗读)</div>
</div>
<div class="field">
<div class="field-label">后置对话</div>
<div class="field-content empty"></div>
</div>
<div class="kp-tags"><span class="kp-tag">get</span></div>
</div>
</div>
</div>
</body>
</html>