auto backup: 2026-06-19 08:10:02

This commit is contained in:
ai_member_only 2026-06-19 08:10:02 +08:00
parent df37e6be85
commit 224a79e902
13 changed files with 6121 additions and 76 deletions

View File

@ -233,6 +233,120 @@ else:
write_range(f"F{row}:F{row}", [data[row]]) write_range(f"F{row}:F{row}", [data[row]])
``` ```
## 读取后错行/乱行校验(强制执行)
### 校验目标
读取 Sheet 数据后,必须自动检测关键列之间的行号对齐关系,防止以下问题:
- 组件配置G列写入了错误行导致内容与组件名称A列错位
- 英文台词F列写入了错误行导致台词与角色E列错位
- 批量写入时行号偏移导致整列数据整体下移/上移
### 校验规则(剧本表格 A-I 列)
#### 规则1A列-G列 对齐校验(组件类型 vs 组件配置)
```
如果 A列[row] 是组件类型(匹配:对话朗读|对话挖空|对话选择|对话组句|对话表达|对话选读|图片单选|图片多选|信息拼词|看图选词|听力\S+|阅读\S+|写作\S+|口语\S+
→ G列[row] 必须非空(包含组件配置内容)
如果 G列[row] 非空(包含组件配置内容)
→ A列[row] 必须是组件类型(不能是 TL / 空 / 其他非组件标记)
```
#### 规则2B列-G列 对齐校验组件ID vs 组件配置)
```
如果 B列[row] 是数字组件ID
→ G列[row] 必须非空
如果 G列[row] 非空且包含 "【组件ID】" 标记
→ 提取的组件ID 必须与 B列[row] 一致
```
#### 规则3E列-F列 对齐校验(角色名 vs 英文台词)
```
如果 E列[row] 非空(有角色名)且 A列[row] 不是 TL / 空(非纯剧情行)
→ F列[row] 建议非空(角色说话应有台词)
→ 若 F列[row] 为空,标记为"疑似缺失"(可能是剧情描述行,需人工确认)
```
#### 规则4G列 内容归属校验(防止配置写入非组件行)
```
扫描 G列 所有非空单元格:
如果 G列[row] 包含组件配置特征("【任务标题】" / "【资源配置】" / "【互动内容】"
且 A列[row] 为 TL / 空 / 非组件类型
→ 标记为"错行":组件配置写入了非组件行
```
### 校验执行流程
```python
# 读取 Sheet 数据后立即执行
def validate_sheet_alignment(rows):
errors = []
warnings = []
component_pattern = re.compile(
r'^(对话朗读|对话挖空|对话选择|对话组句|对话表达|对话选读|'
r'图片单选|图片多选|信息拼词|看图选词|'
r'听力\S+|阅读\S+|写作\S+|口语\S+)'
)
for i, row in enumerate(rows):
row_num = i + 1 # 1-indexed
a_val = row[0] if len(row) > 0 else None # A列类型
b_val = row[1] if len(row) > 1 else None # B列ID
e_val = row[4] if len(row) > 4 else None # E列角色名
f_val = row[5] if len(row) > 5 else None # F列英文台词
g_val = row[6] if len(row) > 6 else None # G列组件配置
# 规则1A-G 对齐
if a_val and component_pattern.match(str(a_val)):
if not g_val:
errors.append(f"行{row_num}: A列=[{a_val}] 但 G列为空组件配置缺失")
if g_val and '【任务标题】' in str(g_val):
if not a_val or not component_pattern.match(str(a_val)):
errors.append(f"行{row_num}: G列有组件配置但 A列=[{a_val}] 非组件类型,疑似错行")
# 规则2B-G 对齐
if b_val and str(b_val).isdigit():
if not g_val:
errors.append(f"行{row_num}: B列=[{b_val}] 但 G列为空组件配置缺失")
elif '【组件ID】' in str(g_val):
g_id = extract_component_id(str(g_val))
if g_id and str(g_id) != str(b_val):
errors.append(f"行{row_num}: B列ID=[{b_val}] 与 G列组件ID=[{g_id}] 不一致")
# 规则3E-F 对齐
if e_val and a_val and a_val not in ('TL', ''):
if not f_val:
warnings.append(f"行{row_num}: E列=[{e_val}] 但 F列为空疑似台词缺失")
# 规则4G列归属
if g_val and ('【任务标题】' in str(g_val) or '【互动内容】' in str(g_val)):
if not a_val or a_val in ('TL', ''):
errors.append(f"行{row_num}: G列有组件配置但 A列=[{a_val}],组件配置错行到非组件行")
return errors, warnings
```
### 校验结果处理
| 级别 | 条件 | 处理方式 |
|------|------|---------|
| **错误 (Error)** | A-G 不对齐 / B-G ID不一致 / G列错行到非组件行 | 立即报告用户,附具体行号和错位内容,暂停后续写入操作 |
| **警告 (Warning)** | E-F 疑似缺失 / 其他非关键不对齐 | 汇总报告,继续执行但标注"需人工确认" |
### 校验触发时机
1. **读取后立即校验**:任何读取 Sheet 数据的操作完成后,自动执行上述校验
2. **写入前校验**:写入操作前,先读取目标区域,校验当前数据对齐状态
3. **写入后回读校验**:写入完成后回读,再次执行对齐校验,确保写入未引入新错位
## 异常处理 ## 异常处理
| 错误码 | 含义 | 处理方式 | | 错误码 | 含义 | 处理方式 |

View File

@ -31,18 +31,35 @@ metadata:
## 通用配置规则(所有对话类互动通用) ## 通用配置规则(所有对话类互动通用)
### 通用字段规范 ### 通用字段规范
> ⚠️ **禁止字段**G列组件内容中**禁止**出现 `【组件ID】`B列已有、`【知识点】`H列已有
| 字段 | 要求 | 示例 | | 字段 | 要求 | 示例 |
|------|------|------| |------|------|------|
| 【任务标题】 | 10字以内清晰说明任务内容避免使用"-",多部分用"(一)"标识 | 与调酒师对峙(一) | | 【任务标题】 | 10字以内清晰说明任务内容避免使用"-",多部分用"(一)"标识 | 与调酒师对峙(一) |
| 【情境引入】 | 每行一句对话,格式为`角色名: 对话内容`,无情境引入填"无" | User: He already ran away.<br>Piper: I didn't see him on my way here. | | 【情境引入】 | 每行一句对话,格式为`角色名: 对话内容`,无情境引入填"无"。🚫 **禁止编造**,必须来自台词池(组件行 F 列 + 后续连续 User 台词)。单句台词池且含知识点 → 填「无」 | User: He already ran away.<br>Piper: I didn't see him on my way here. |
| 【后置对话】 | 每行一句对话,无后置对话填"无" | 无 | | 【后置对话】 | 每行一句对话,无后置对话填"无"。🚫 **禁止编造**,必须来自台词池。知识点之后无 User 台词 → 填「无」 | 无 |
| 【资源配置】 | 无资源填"无";有资源时填写资源命名和出现时机:<br>1. 图片命名:`组件ID.png`<br>2. 音频命名:`组件ID.mp3`<br>3. 出现时机:可填【情境引入】/【互动内容】/【互动反馈】/【后置对话】,多时机并列 | 图片时机:<br>互动内容<br>互动反馈<br>音频载体Pioneer Band | | 【资源配置】 | 无资源填"无";有资源时填写资源出现的时机(如"情境引入""互动内容"),多时机并列换行<br>🚫 禁止使用组件ID命名文件`1224204.png`),文件名由下游系统自动生成<br>🚫 不需要"图片时机:""音频载体:"等前缀 | 情境引入<br>互动内容<br>互动反馈 |
| 【互动反馈】 | 分正确反馈和错误反馈,格式为`角色名: 反馈内容`,正确反馈非必填,无则填"无" | 正确 Piper: Thank you, my friend.<br>错误 Piper: I don't think so. | | 【互动反馈】 | 分正确反馈和错误反馈,格式为`角色名: 反馈内容`,正确反馈非必填,无则填"无" | 正确 Piper: Thank you, my friend.<br>错误 Piper: I don't think so. |
--- ---
## 知识点优先分配规则(强制执行) ## 知识点优先分配规则(强制执行)
### 台词池规则(强制执行)
**组件内容除【互动反馈】外,其余台词均来自台词池,禁止编造。**
**台词池定义:** 组件行 F 列 + 后续连续 User 台词(到 TL / 下一组件截止)。
**分配规则:**
- 含知识点的台词 → 【互动内容】
- 知识点之前的 User 台词 → 【情境引入】
- 知识点之后的 User 台词 → 【后置对话】或选项反馈
- 单句台词池且含知识点 → 【情境引入】填「无」
> ⚠️ 核心互动不适用此规则。
### 核心原则 ### 核心原则
当组件中 User 有多句台词时,**【互动内容】必须是包含知识点的那句台词**。不包含知识点的台词,根据其与知识点台词的相对位置分配: 当组件中 User 有多句台词时,**【互动内容】必须是包含知识点的那句台词**。不包含知识点的台词,根据其与知识点台词的相对位置分配:
@ -196,19 +213,16 @@ Piper: You're lying! It must be your mistake!
- 【互动反馈】:本类型不单独设置互动反馈字段,反馈内容已整合在互动内容的各选项中 - 【互动反馈】:本类型不单独设置互动反馈字段,反馈内容已整合在互动内容的各选项中
- 【资源配置】: - 【资源配置】:
- 类型为「对话选读」时,填写:`无` - 类型为「对话选读」时,填写:`无`
- 类型为「对话选读-配图」时,填写图片时机 + 音频载体(格式见下方示例) - 类型为「对话选读-配图」时,填写资源出现时机(格式见下方示例)
- 资源命名规范:图片文件名 `{组件ID}.png`,音频文件名 `{组件ID}.mp3` - 资源描述出现时机(非文件名),文件名由下游系统自动生成
#### 示例(对话选读-配图) #### 示例(对话选读-配图)
``` ```
【任务标题】加入搏斗俱乐部 【任务标题】加入搏斗俱乐部
【资源配置】 【资源配置】
图片时机:
互动内容 互动内容
互动反馈 互动反馈
音频载体Pioneer Band
【情境引入】 【情境引入】
Johnny: What do you think of the club? Johnny: What do you think of the club?

View File

@ -16,8 +16,10 @@ metadata:
## 通用规则6类共享 ## 通用规则6类共享
> ⚠️ **禁止字段**G列组件内容中**禁止**出现 `【组件ID】`B列已有、`【知识点】`H列已有
- 【任务标题】中文口语化10字以内避免「-」,有序用「(一)」,含英文单词时前后留空格 - 【任务标题】中文口语化10字以内避免「-」,有序用「(一)」,含英文单词时前后留空格
- 【资源配置】:图片文件名 = `{组件ID}.png`,不含音频配置 - 【资源配置】:描述资源出现的时机(如"情境引入""互动内容"),非文件名。无资源填"无"。🚫 禁止使用组件ID命名文件`1224204.png`),文件名由下游系统自动生成
- 【后置对话】:无则填「无」 - 【后置对话】:无则填「无」
--- ---
@ -41,7 +43,7 @@ metadata:
``` ```
【任务标题】购买葡萄 【任务标题】购买葡萄
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
任务描述:请填入"葡萄"的正确的英文拼写 任务描述:请填入"葡萄"的正确的英文拼写
题干G(2)pe 题干G(2)pe
@ -83,7 +85,7 @@ metadata:
``` ```
【任务标题】填写信息表 【任务标题】填写信息表
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
任务描述:请在空白处填入正确的单词,组成句子 任务描述:请在空白处填入正确的单词,组成句子
选项1is 选项1is
@ -115,7 +117,7 @@ metadata:
``` ```
【任务标题】描述房间里的物品 【任务标题】描述房间里的物品
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
任务描述:请用英文描述图片中房间里的物品 任务描述:请用英文描述图片中房间里的物品
参考词汇sofa, window, door, table 参考词汇sofa, window, door, table
@ -148,7 +150,7 @@ metadata:
``` ```
【任务标题】补全句子中的单词 【任务标题】补全句子中的单词
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
题干The cat is sitting on the ___. 题干The cat is sitting on the ___.
选项1chair正确 选项1chair正确
@ -183,7 +185,7 @@ metadata:
``` ```
【任务标题】填入正确的单词 【任务标题】填入正确的单词
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
题干The ___ is on the desk. 题干The ___ is on the desk.
答案book 答案book
@ -216,7 +218,7 @@ metadata:
``` ```
【任务标题】补全这个句子 【任务标题】补全这个句子
【资源配置】 【资源配置】
图片文件名0216002.png 互动内容
【互动内容】 【互动内容】
题干The boy ___ to school every day. 题干The boy ___ to school every day.
答案The boy walks to school every day. 答案The boy walks to school every day.

View File

@ -60,6 +60,22 @@ description: 剧本互动组件内容生产/审校/回填技能不涉及JSON
- 识别嵌入的 Sheet token`<sheet token="xxx_yyy"/>` - 识别嵌入的 Sheet token`<sheet token="xxx_yyy"/>`
- 读取 Sheet 元数据sheet_id / 行数 / 列数 / 冻结行) - 读取 Sheet 元数据sheet_id / 行数 / 列数 / 冻结行)
### 节点1.5:错行/乱行校验(强制执行)
**读取 Sheet 数据后,在进入列结构解析前,必须先执行 `feishu-embedded-sheet` 技能中的「读取后错行/乱行校验」:**
校验内容(详见 `feishu-embedded-sheet` SKILL.md「读取后错行/乱行校验」章节):
- **规则1A列-G列对齐** — 组件类型行必须有组件配置,组件配置不能出现在非组件行
- **规则2B列-G列对齐** — 组件ID与G列中的【组件ID】必须一致
- **规则3E列-F列对齐** — 有角色名的行应有对应台词
- **规则4G列归属校验** — 组件配置不能错位到 TL / 空行
**校验结果处理:**
- 发现 Error错行/乱行)→ 立即报告用户,附具体行号和错位内容,**暂停后续所有操作**
- 发现 Warning疑似缺失→ 汇总报告,继续执行但标注"需人工确认"
**校验通过后才能进入节点2。**
### 节点2列结构解析 ### 节点2列结构解析
标准剧本表格列: 标准剧本表格列:
| A | B | C | D | E | F | G | H | | A | B | C | D | E | F | G | H |
@ -129,11 +145,8 @@ description: 剧本互动组件内容生产/审校/回填技能不涉及JSON
所有组件内容按以下字段顺序输出,无内容的字段填「无」: 所有组件内容按以下字段顺序输出,无内容的字段填「无」:
``` ```
【组件ID】020501
【任务标题】介绍照片 【任务标题】介绍照片
【资源配置】 【资源配置】无
图片时机:无
音频载体:无
【情境引入】 【情境引入】
Johnny : What's That? Johnny : What's That?
@ -149,10 +162,13 @@ This is my picture. It's ___, green and orange.(音频)
【后置对话】 【后置对话】
```
【知识点】 **禁止输出的字段:**
单词blue, orange - ❌ `【组件ID】` — 组件ID已在B列存储G列无需重复
句型It is... - ❌ `【知识点】` — 知识点已在H列存储G列无需重复
- ❌ 资源配置中使用组件ID命名文件`1224204.png`)— 资源文件名由下游系统自动生成
- ❌ 资源配置中使用"图片时机:""音频载体:"等前缀 — 直接写出现时机即可
--- ---
@ -161,7 +177,6 @@ This is my picture. It's ___, green and orange.(音频)
对话选读的选项默认带音频标记`(音频)`,不需要音频时标注`(无音频)` 对话选读的选项默认带音频标记`(音频)`,不需要音频时标注`(无音频)`
``` ```
【组件ID】020501
【任务标题】解释他们的歉意 【任务标题】解释他们的歉意
【资源配置】无 【资源配置】无
【情境引入】无 【情境引入】无
@ -173,8 +188,6 @@ This is my picture. It's ___, green and orange.(音频)
选项2They feel bad about what they did. 选项2They feel bad about what they did.
- 反馈 DiDi: It's okay. - 反馈 DiDi: It's okay.
【后置对话】无 【后置对话】无
【知识点】
句型They feel...
``` ```
``` ```
@ -198,17 +211,19 @@ This is my picture. It's ___, green and orange.(音频)
| 6 | 选项格式 | 对话类用「选项1XXX」、图片类用00/01/02编号 | | 6 | 选项格式 | 对话类用「选项1XXX」、图片类用00/01/02编号 |
| 7 | 反馈格式 | 错误反馈带角色名、自然对话、非指令式 | | 7 | 反馈格式 | 错误反馈带角色名、自然对话、非指令式 |
| 8 | 高亮规则 | 图片类仅知识点词加$、对话类不加 | | 8 | 高亮规则 | 图片类仅知识点词加$、对话类不加 |
| 9 | 情境引入 | 无内容填「无」,多句换行,格式为「角色名: 台词」。🚫 **禁止引用组件行之前任何行的台词**含前一行的E列/F列原文必须来自组件自身场景设定。审校时逐行对比组件行之前的E/F列确认无重合 | | 9 | 情境引入 | 无内容填「无」,多句换行,格式为「角色名: 台词」。🚫 **禁止编造**,必须来自台词池(见检查项 11.1)。单句台词池且含知识点 → 填「无」。审校时逐行对比 G 列情境引入与台词池,发现编造即删除 |
| 10 | 后置对话 | 取组件行之后的紧接台词,无则填「无」。🚫 **禁止直接复制后一行台词原文**相同则填「无」。审校时逐行对比组件行之后的E/F列确认无重合 | | 10 | 后置对话 | 无内容填「无」。🚫 **禁止编造**,必须来自台词池(见检查项 11.1)。知识点之后无 User 台词 → 填「无」。审校时逐行对比 G 列后置对话与台词池,发现编造即删除 |
| 11 | 知识点优先分配 | **【互动内容】必须包含知识点**。当 User 有多句台词时,不包含知识点的台词:在知识点台词之前放入【情境引入】,在知识点台词之后放入【后置对话】。审校时逐一检查每句 User 台词的分配是否符合此规则 | | 11 | 知识点优先分配 | **【互动内容】必须包含知识点**。当 User 有多句台词时,不包含知识点的台词:在知识点台词之前放入【情境引入】,在知识点台词之后放入【后置对话】。审校时逐一检查每句 User 台词的分配是否符合此规则 |
| 11.1 | 台词池规则 | **组件内容除【互动反馈】外,其余台词均来自台词池,禁止编造。** 台词池 = 组件行 F 列 + 后续连续 User 台词(到 TL/下一组件截止)。分配规则:含知识点的台词 → 【互动内容】;知识点之前的 User 台词 → 【情境引入】;知识点之后的 User 台词 → 【后置对话】或选项反馈。单句台词池且含知识点 → 【情境引入】填「无」。核心互动不适用此规则。审校时逐行对比 G 列情境引入/后置对话与台词池,发现编造即删除 |
| 12 | 超纲检查 | 词汇/句型在对应级别词库/句型库范围内 | | 12 | 超纲检查 | 词汇/句型在对应级别词库/句型库范围内 |
| 13 | 标点符号 | 统一使用标准英文标点,禁止「~」「!!!」等非标准标点 | | 13 | 标点符号 | 统一使用标准英文标点,禁止「~」「!!!」等非标准标点 |
| 14 | 图片类资源配置 | 图片类互动(图片单选/多选/有序/拖拽)**不包含【资源配置】字段** | | 14 | 图片类资源配置 | 图片类互动(图片单选/多选/有序/拖拽)**不包含【资源配置】字段** |
| 15 | 图片类辅助信息 | 图片类互动在「正确XX」后添加 `辅助信息:{单词} {中文释义}。`,释义参考知识点 Sheet | | 15 | 图片类辅助信息 | 图片类互动在「正确XX」后添加 `辅助信息:{单词} {中文释义}。`,释义参考知识点 Sheet |
| 16 | 对话朗读反馈 | 对话朗读**不包含【互动反馈】字段** | | 16 | 对话朗读反馈 | 对话朗读**不包含【互动反馈】字段** |
| 17 | 配图资源配置 | A列含"配图"时,仅保留`图片时机`(不写`音频载体`),根据有内容的 section 动态列出 | | 17 | 配图资源配置 | A列含"配图"时,【资源配置】直接列出资源出现的时机(如"情境引入""互动内容"),不需要"图片时机:""音频载体:"等前缀 |
| 18 | 答案随机化 | 听力选择/对话选择等多小题组件,各题正确选项位置必须随机分布,禁止全部集中在同一序号。生成后统计各题正确选项序号,若全部相同则重新随机 | | 18 | 答案随机化 | 听力选择/对话选择等多小题组件,各题正确选项位置必须随机分布,禁止全部集中在同一序号。生成后统计各题正确选项序号,若全部相同则重新随机 |
| 19 | 对话选读选项音频 | 对话选读类型,选项默认带音频标记`(音频)`,不需要音频时标注`(无音频)`。生成后检查每个选项行是否包含音频标记 | | 19 | 对话选读选项音频 | 对话选读类型,选项默认带音频标记`(音频)`,不需要音频时标注`(无音频)`。生成后检查每个选项行是否包含音频标记 |
| 20 | 禁止冗余字段 | G列组件内容中**禁止出现**以下字段:`【组件ID】`B列已有、`【知识点】`H列已有、资源配置中使用组件ID命名文件`1224204.png`。审校时扫描全部G列内容发现即删除 |
#### 回填 #### 回填
- 将生成的结构化文本写入列G组件配置 - 将生成的结构化文本写入列G组件配置

View File

@ -278,3 +278,35 @@ taskData textData sequenceData learningData
- 看图选词 (ID=1201001): 5步生成全部通过taskData/questionGroupData/studyData 结构正确,耗时~47s - 看图选词 (ID=1201001): 5步生成全部通过taskData/questionGroupData/studyData 结构正确,耗时~47s
- 口语快答 (ID=0325001): 7步生成全部通过taskData/settingData/configData/learningData 结构正确,耗时~90s - 口语快答 (ID=0325001): 7步生成全部通过taskData/settingData/configData/learningData 结构正确,耗时~90s
- HTML验证报告: `outputs/V5核心互动验证 - imageDrag + speaking` - HTML验证报告: `outputs/V5核心互动验证 - imageDrag + speaking`
---
## v9 写作类核心互动-看图组句 学习内容提取修复2026-06-18
### 问题
`core_writing_imgMakeSentence`(看图组句)和 `core_writing_imgWrite`(看图撰写)的 Phase 12.7 实现中,
`学习内容` 字段在剧本配置中无 `【学习内容】` section 时错误地回退到 `知识`(词汇表),导致:
1. Step 1学习流程配置以词汇而非句子作为练习目标生成内容错误
2. Step 5studyInfo`leadIn.image` 无图片编号可关联,图片配对失败
### 根本原因
写作互动 bitable 工作流中,`学习内容` 是独立的 LLM 提取步骤(从写作材料答案+图片编号生成)。
新流程合并后,该步骤被遗漏,未作规则化替代。
### 修复
`scripts/generate_json.py` 中新增:
- **`_extract_writing_material_learning_content(writing_material_text)`**:规则解析写作材料,
提取每个 `# 句子 N` 块的答案和图片编号,按图片编号排序,输出格式 `答案 图片编号` 每行一条。
- **`_generate_core_writing()` 中自动触发**:对 `is_img_type` 类型且无 `【学习内容】` section 时,
调用上述函数覆盖 `fields["学习内容"]`,同时应用于 Step 1 和 Step 5。
### 输出样例(对应看图组句样例配置)
```
astronauts 00
great astronaut 01
Mum and Dad have jobs. 02
I have a job too! 02
```
### 最终推送 JSON看图组句 / 看图撰写)
`taskInfo` · `textInfo` · `studyInfo` · `evalInfo`(共 4 个,已在 html_report.py PUSH_FIELD_MAP 注册)

View File

@ -1796,6 +1796,54 @@ def generate_core_listening_choose(cId, teaching_config, character_map=None, llm
# ============ 写作类核心互动4种 ============ # ============ 写作类核心互动4种 ============
def _extract_writing_material_learning_content(writing_material_text):
"""
从看图类写作材料中提取每个句子的答案和图片编号 studyInfo 图片关联使用
等同于 写作互动 bitable 工作流中的"学习内容"LLM提取步骤但改为规则实现
- 对每个 "# 句子 N" 提取图片编号和答案
- 如无图片编号则跳过如答案为空或"/"则跳过
- 按图片编号排序
- 输出格式: "答案 图片编号" 每行一条
示例输出:
astronauts 00
great astronaut 01
Mum and Dad have jobs. 02
I have a job too! 02
"""
results = []
# 找出每个句子块
sentence_blocks = re.findall(
r'# 句子\s+\d+.*?(?=\n# 句子\s+\d+|\Z)',
writing_material_text,
re.DOTALL,
)
for block in sentence_blocks:
# 提取图片编号
img_match = re.search(r'##\s*图片编号\s*\n\s*(\d+)', block)
if not img_match:
continue
img_num = img_match.group(1).strip().zfill(2)
# 提取答案(答案:/答案: 后第一个非空行)
ans_match = re.search(r'答案[:]\s*\n(.+)', block)
if not ans_match:
continue
answer = ans_match.group(1).strip()
if answer and answer != '/':
results.append((img_num, answer))
if not results:
return ""
results.sort(key=lambda x: x[0])
return '\n'.join(f"{answer} {img_num}" for img_num, answer in results)
def parse_core_writing_fields(teaching_config): def parse_core_writing_fields(teaching_config):
""" """
从组件配置文本中提取写作类核心互动所需的输入字段 从组件配置文本中提取写作类核心互动所需的输入字段
@ -1897,6 +1945,14 @@ def _generate_core_writing(cId, cType, teaching_config, character_map=None, llm_
else: else:
build_prompt = lambda step, repl: build_writing_question_prompt(cType, step, repl) build_prompt = lambda step, repl: build_writing_question_prompt(cType, step, repl)
# 看图类写作:从写作材料中提取学习内容(答案+图片编号),覆盖兜底的知识字段。
# 对应 写作互动 bitable 工作流中的"学习内容"提取步骤,这里改为规则实现。
if is_img_type and "【学习内容】" not in teaching_config:
extracted_lx = _extract_writing_material_learning_content(fields.get("写作材料", ""))
if extracted_lx:
fields["学习内容"] = extracted_lx
logger.info(f" [学习内容] 从写作材料规则提取: {len(extracted_lx)} 字符")
log_prefix = f"[{cType}]" log_prefix = f"[{cType}]"
logger.info(f"{log_prefix} 开始6步生成: cId={cId}") logger.info(f"{log_prefix} 开始6步生成: cId={cId}")

View File

@ -29,8 +29,9 @@ description: 用英语母语儿童思维生成自然地道的分级英文台词
- ✅ 科幻词自动降级:内置可配置科幻词映射表,复杂词汇自动转换成儿童易懂表达 - ✅ 科幻词自动降级:内置可配置科幻词映射表,复杂词汇自动转换成儿童易懂表达
- ✅ 批量处理:支持单个文件/目录批量处理,自动保存结果到指定路径 - ✅ 批量处理:支持单个文件/目录批量处理,自动保存结果到指定路径
## 执行流程(6个可观测节点,按语言类型自动分流) ## 执行流程(7个可观测节点,按语言类型自动分流)
每个节点独立运行,输出中间产物+状态,可逐步审查定位问题: 每个节点独立运行,输出中间产物+状态,可逐步审查定位问题:
0. **错行/乱行校验**(纯代码,飞书模式强制执行):读取 Sheet 数据后立即执行 `feishu-embedded-sheet` 技能中的「读取后错行/乱行校验」——检查 A-G 列对齐、B-G 列 ID 一致、E-F 列角色台词对齐、G 列归属。发现 Error 立即报告用户并暂停Warning 汇总报告但继续。校验通过后才进入节点1。
1. **输入解析**(纯代码):检测输入语言类型、角色、行数 → 决定后续处理路径 1. **输入解析**(纯代码):检测输入语言类型、角色、行数 → 决定后续处理路径
2. **输入归一**LLM #1,按语言分流): 2. **输入归一**LLM #1,按语言分流):
- 中英混合(主要场景)→ 归一为标准中文「角色: 台词」 - 中英混合(主要场景)→ 归一为标准中文「角色: 台词」

View File

@ -66,13 +66,17 @@ description: 剧本英文台词后处理复核。纯代码规则链,逐项检
``` ```
用户发送 "剧本复核 <飞书链接>" 用户发送 "剧本复核 <飞书链接>"
├── 0. 错行/乱行校验(强制执行):读取 Sheet 后立即执行
`feishu-embedded-sheet` 技能中的「读取后错行/乱行校验」
│ 检查 A-G 列对齐、B-G 列 ID 一致、E-F 列角色台词对齐、G 列归属
│ 发现 Error → 立即报告用户并暂停Warning → 汇总报告但继续
├── 1. 解析飞书链接 → 获取文档 → 定位内嵌 Sheet ├── 1. 解析飞书链接 → 获取文档 → 定位内嵌 Sheet
├── 2. 读取 F 列全部内容(含行号) ├── 2. 读取 F 列全部内容(含行号)
├── 3. 按规则链顺序执行: ├── 3. 按规则链顺序执行:
│ ├── 规则1长句拆分如需插入行从下往上处理 │ ├── 规则1长句拆分如需插入行从下往上处理
│ └── 规则2标点检查逐行扫描 + 修正) │ └── 规则2标点检查逐行扫描 + 修正)
├── 4. 输出操作报告 ├── 4. 输出操作报告
└── 5. 回读验证 └── 5. 回读验证(含二次错行校验)
``` ```
## 输出格式 ## 输出格式

View File

@ -131,3 +131,9 @@
{"type":"memory.recall.recorded","timestamp":"2026-06-17T02:46:50.273Z","query":"武钰涵 reading_pic_judge 题组 审校 2026-06","resultCount":4,"results":[{"path":"memory/2026-05-07.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-11.md","startLine":1,"endLine":25,"score":1},{"path":"memory/2026-05-17.md","startLine":19,"endLine":40,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-17T02:46:50.273Z","query":"武钰涵 reading_pic_judge 题组 审校 2026-06","resultCount":4,"results":[{"path":"memory/2026-05-07.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-11.md","startLine":1,"endLine":25,"score":1},{"path":"memory/2026-05-17.md","startLine":19,"endLine":40,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-17T02:47:04.085Z","query":"武钰涵 ou_a4aaa641585b38d1042608b9b7f05a17 审校 看图判断","resultCount":4,"results":[{"path":"memory/2026-05-27.md","startLine":1,"endLine":16,"score":1},{"path":"memory/2026-05-14.md","startLine":257,"endLine":266,"score":1},{"path":"memory/2026-05-18.md","startLine":583,"endLine":633,"score":1},{"path":"memory/2026-05-18.md","startLine":305,"endLine":346,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-17T02:47:04.085Z","query":"武钰涵 ou_a4aaa641585b38d1042608b9b7f05a17 审校 看图判断","resultCount":4,"results":[{"path":"memory/2026-05-27.md","startLine":1,"endLine":16,"score":1},{"path":"memory/2026-05-14.md","startLine":257,"endLine":266,"score":1},{"path":"memory/2026-05-18.md","startLine":583,"endLine":633,"score":1},{"path":"memory/2026-05-18.md","startLine":305,"endLine":346,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-17T02:48:55.170Z","query":"武钰涵 reading_pic_judge 题组1 题组2 This is my bus What time 2026-06-17","resultCount":4,"results":[{"path":"memory/2026-05-07.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-11.md","startLine":1,"endLine":25,"score":1},{"path":"memory/2026-05-17.md","startLine":19,"endLine":40,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-17T02:48:55.170Z","query":"武钰涵 reading_pic_judge 题组1 题组2 This is my bus What time 2026-06-17","resultCount":4,"results":[{"path":"memory/2026-05-07.md","startLine":1,"endLine":20,"score":1},{"path":"memory/2026-05-11.md","startLine":1,"endLine":25,"score":1},{"path":"memory/2026-05-17.md","startLine":19,"endLine":40,"score":1},{"path":"memory/2026-05-12.md","startLine":181,"endLine":203,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T02:21:31.142Z","query":"L2 A级 句子题型 单元挑战 难度分级","resultCount":2,"results":[{"path":"memory/2026-05-25.md","startLine":283,"endLine":302,"score":1},{"path":"memory/2026-05-25.md","startLine":118,"endLine":137,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T04:35:22.376Z","query":"L1 剧本 单元数 阶段 unit 数量","resultCount":5,"results":[{"path":"memory/2026-05-26.md","startLine":130,"endLine":166,"score":1},{"path":"memory/2026-05-28.md","startLine":46,"endLine":62,"score":1},{"path":"memory/2026-05-25.md","startLine":283,"endLine":302,"score":1},{"path":"memory/2026-05-29.md","startLine":1,"endLine":14,"score":1},{"path":"memory/2026-05-25.md","startLine":118,"endLine":137,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T04:35:56.737Z","query":"L1 剧情 每单元 集数 lesson 数量","resultCount":5,"results":[{"path":"memory/2026-05-26.md","startLine":130,"endLine":166,"score":1},{"path":"memory/2026-05-28.md","startLine":46,"endLine":62,"score":1},{"path":"memory/2026-05-25.md","startLine":283,"endLine":302,"score":1},{"path":"memory/2026-05-29.md","startLine":1,"endLine":14,"score":1},{"path":"memory/2026-05-25.md","startLine":118,"endLine":137,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T04:36:05.631Z","query":"英文台词 L1 每单元 lesson 数量 5课 结构","resultCount":6,"results":[{"path":"memory/2026-05-28.md","startLine":46,"endLine":62,"score":1},{"path":"memory/2026-05-28.md","startLine":60,"endLine":66,"score":1},{"path":"memory/2026-05-29.md","startLine":1,"endLine":14,"score":1},{"path":"memory/2026-05-28.md","startLine":35,"endLine":49,"score":1},{"path":"memory/2026-05-18.md","startLine":783,"endLine":810,"score":1},{"path":"memory/2026-05-08.md","startLine":33,"endLine":55,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T04:36:16.755Z","query":"L1 每单元 lesson 5课 L1-L5 结构","resultCount":5,"results":[{"path":"memory/2026-05-26.md","startLine":130,"endLine":166,"score":1},{"path":"memory/2026-05-28.md","startLine":46,"endLine":62,"score":1},{"path":"memory/2026-05-25.md","startLine":283,"endLine":302,"score":1},{"path":"memory/2026-05-29.md","startLine":1,"endLine":14,"score":1},{"path":"memory/2026-05-25.md","startLine":118,"endLine":137,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T08:09:19.223Z","query":"L1 句子 结构 第三级 知识维度 句型结构 看图组句 句子补全","resultCount":2,"results":[{"path":"memory/2026-05-26.md","startLine":130,"endLine":166,"score":1},{"path":"memory/2026-05-28.md","startLine":46,"endLine":62,"score":1}]}

View File

@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"updatedAt": "2026-06-17T02:48:55.170Z", "updatedAt": "2026-06-18T08:09:19.223Z",
"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",
@ -209,13 +209,13 @@
"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": 14, "recallCount": 15,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 14, "totalScore": 15,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-11T02:19:37.985Z", "firstRecalledAt": "2026-05-11T02:19:37.985Z",
"lastRecalledAt": "2026-06-10T02:20:27.209Z", "lastRecalledAt": "2026-06-18T04:36:05.631Z",
"queryHashes": [ "queryHashes": [
"6f88450e9f9b", "6f88450e9f9b",
"be437071312f", "be437071312f",
@ -230,7 +230,8 @@
"240a6a5dca41", "240a6a5dca41",
"7e6aa000abdb", "7e6aa000abdb",
"9018e8896dcd", "9018e8896dcd",
"3ac726b21876" "3ac726b21876",
"533765637e65"
], ],
"recallDays": [ "recallDays": [
"2026-05-11", "2026-05-11",
@ -240,7 +241,8 @@
"2026-05-25", "2026-05-25",
"2026-05-26", "2026-05-26",
"2026-06-02", "2026-06-02",
"2026-06-10" "2026-06-10",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"创建/更新记录", "创建/更新记录",
@ -2750,13 +2752,13 @@
"endLine": 62, "endLine": 62,
"source": "memory", "source": "memory",
"snippet": "- B级规则听力句子 5-8 词(均 7 词),每组 3 张同类物品不同属性图片 - 能力标签:显性事实理解|关键词识别 ×2 + 基础语境理解|场景/物品/动作识别 ## 梁辰user_id: ou_28f02dcada1193913cfbb6310f8daf07— HTML 诊断页面教研规则 JS 文件 - 用户有一个 L1 关卡诊断工作台 HTML 页面(部署在腾讯云空间),当前只做数量级统计,缺少教研规则校验 - 需求:提供可嵌入 HTML 的前端 JS 校验规则文件,使诊断有据可依 - 输出:`output/l1_pedagogy_rules.js`42KB包含 8 个校验维度: 1. 词汇超纲检测(基于 L1/L2 词库) 2. 英式拼写检测color→colour 等 115 组映射) 3. Markdown 标记检测(`**`/`#`/`>` 等) 4. 标点规范检测(全角混入、``、`!!!` 5. 题型-阶段匹配校验20 种题型对应的 L1/L2 阶段映射) 6. 台词质量分析(句子长度、负面评价) 7. 知识点曝光度 8. 句型合规检测 - 接入方式:`<script src=\"l1_pedagogy_rules.js\"></script>` + 调用 `PedagogyRules.validate(summary, level)` - 数据源L1 词库 147 词(过滤 enabled=true、L2 词库 52 词、L1 句型 8 个、L2 句型(从 437MB bitable 导出中提取唯一结", "snippet": "- B级规则听力句子 5-8 词(均 7 词),每组 3 张同类物品不同属性图片 - 能力标签:显性事实理解|关键词识别 ×2 + 基础语境理解|场景/物品/动作识别 ## 梁辰user_id: ou_28f02dcada1193913cfbb6310f8daf07— HTML 诊断页面教研规则 JS 文件 - 用户有一个 L1 关卡诊断工作台 HTML 页面(部署在腾讯云空间),当前只做数量级统计,缺少教研规则校验 - 需求:提供可嵌入 HTML 的前端 JS 校验规则文件,使诊断有据可依 - 输出:`output/l1_pedagogy_rules.js`42KB包含 8 个校验维度: 1. 词汇超纲检测(基于 L1/L2 词库) 2. 英式拼写检测color→colour 等 115 组映射) 3. Markdown 标记检测(`**`/`#`/`>` 等) 4. 标点规范检测(全角混入、``、`!!!` 5. 题型-阶段匹配校验20 种题型对应的 L1/L2 阶段映射) 6. 台词质量分析(句子长度、负面评价) 7. 知识点曝光度 8. 句型合规检测 - 接入方式:`<script src=\"l1_pedagogy_rules.js\"></script>` + 调用 `PedagogyRules.validate(summary, level)` - 数据源L1 词库 147 词(过滤 enabled=true、L2 词库 52 词、L1 句型 8 个、L2 句型(从 437MB bitable 导出中提取唯一结",
"recallCount": 10, "recallCount": 15,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 10, "totalScore": 15,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T00:23:17.391Z", "firstRecalledAt": "2026-05-29T00:23:17.391Z",
"lastRecalledAt": "2026-06-17T02:17:21.800Z", "lastRecalledAt": "2026-06-18T08:09:19.223Z",
"queryHashes": [ "queryHashes": [
"c1d4076205e1", "c1d4076205e1",
"4aa0ef719160", "4aa0ef719160",
@ -2767,14 +2769,20 @@
"3ac726b21876", "3ac726b21876",
"867f7264cd0e", "867f7264cd0e",
"5f16a7426a41", "5f16a7426a41",
"7c761b49b948" "7c761b49b948",
"f7926d356e13",
"341edb569d53",
"533765637e65",
"367cd3303e1d",
"fc0ce35c5668"
], ],
"recallDays": [ "recallDays": [
"2026-05-29", "2026-05-29",
"2026-06-01", "2026-06-01",
"2026-06-02", "2026-06-02",
"2026-06-10", "2026-06-10",
"2026-06-17" "2026-06-17",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"5-8", "5-8",
@ -2859,18 +2867,23 @@
"endLine": 166, "endLine": 166,
"source": "memory", "source": "memory",
"snippet": "## 英文台词生产 [童瑶] — L1-S2-U20 全系列 ### L1-S2-U20-L1 冠军计划 - **文档:** `EbkUwEjaticOkHknf0icsQ2Yn4Q` | Sheet `6aqvM2` - 对话 148 行,写入 E 列 ✅ ### L1-S2-U20-L2 发球大战 - **文档:** `BvSyw1vlfiwCr5kjkPmcUYXynZd` | Sheet `wMQVyV` - 对话 135 行,写入 F 列 ✅ ### L1-S2-U20-L3 曲棍球练习赛 - **文档:** `MrsAwcYq2iCy7Tkk3dkclS0mnlg` | Sheet `6aqvM2` - 对话 149 行28 行修改,写入 F 列 ✅ - 知识点hockey/interesting/one/try + `have a try`/`One...the other...` ### L1-S2-U20-L4 网球明星 - **文档:** `GT4awLQx9iOfWHk00ZFcHQzbnzT` | Sheet `wMQVyV` - 对话 112 行26 行修改,写入 F 列 ✅ - 知识点tennis/tennis racket/bounce/wave + `wave(s) to`/`Hit the ball!` ### L1-S2-U20-L5 足球接力赛 - **文档:** `VEGwwoVdTiFu00koNoOc1MGhnec` | Sheet `AV1gO0` - 对话 137 行28 行修改,写入 F 列 ✅ - 知识点:", "snippet": "## 英文台词生产 [童瑶] — L1-S2-U20 全系列 ### L1-S2-U20-L1 冠军计划 - **文档:** `EbkUwEjaticOkHknf0icsQ2Yn4Q` | Sheet `6aqvM2` - 对话 148 行,写入 E 列 ✅ ### L1-S2-U20-L2 发球大战 - **文档:** `BvSyw1vlfiwCr5kjkPmcUYXynZd` | Sheet `wMQVyV` - 对话 135 行,写入 F 列 ✅ ### L1-S2-U20-L3 曲棍球练习赛 - **文档:** `MrsAwcYq2iCy7Tkk3dkclS0mnlg` | Sheet `6aqvM2` - 对话 149 行28 行修改,写入 F 列 ✅ - 知识点hockey/interesting/one/try + `have a try`/`One...the other...` ### L1-S2-U20-L4 网球明星 - **文档:** `GT4awLQx9iOfWHk00ZFcHQzbnzT` | Sheet `wMQVyV` - 对话 112 行26 行修改,写入 F 列 ✅ - 知识点tennis/tennis racket/bounce/wave + `wave(s) to`/`Hit the ball!` ### L1-S2-U20-L5 足球接力赛 - **文档:** `VEGwwoVdTiFu00koNoOc1MGhnec` | Sheet `AV1gO0` - 对话 137 行28 行修改,写入 F 列 ✅ - 知识点:",
"recallCount": 1, "recallCount": 5,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 5,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T02:33:30.526Z", "firstRecalledAt": "2026-05-29T02:33:30.526Z",
"lastRecalledAt": "2026-05-29T02:33:30.526Z", "lastRecalledAt": "2026-06-18T08:09:19.223Z",
"queryHashes": [ "queryHashes": [
"4aa0ef719160" "4aa0ef719160",
"f7926d356e13",
"341edb569d53",
"367cd3303e1d",
"fc0ce35c5668"
], ],
"recallDays": [ "recallDays": [
"2026-05-29" "2026-05-29",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"l1-s2-u20", "l1-s2-u20",
@ -2890,23 +2903,28 @@
"endLine": 302, "endLine": 302,
"source": "memory", "source": "memory",
"snippet": "- 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) - 已写入", "snippet": "- 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) - 已写入",
"recallCount": 4, "recallCount": 8,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 8,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T02:33:30.526Z", "firstRecalledAt": "2026-05-29T02:33:30.526Z",
"lastRecalledAt": "2026-06-10T02:20:22.635Z", "lastRecalledAt": "2026-06-18T04:36:16.755Z",
"queryHashes": [ "queryHashes": [
"4aa0ef719160", "4aa0ef719160",
"20f6c2d072df", "20f6c2d072df",
"068db47fdc05", "068db47fdc05",
"6568231ab2d7" "6568231ab2d7",
"617d5faf5a33",
"f7926d356e13",
"341edb569d53",
"367cd3303e1d"
], ],
"recallDays": [ "recallDays": [
"2026-05-29", "2026-05-29",
"2026-06-08", "2026-06-08",
"2026-06-10" "2026-06-10",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"阶段1-2", "阶段1-2",
@ -2926,23 +2944,28 @@
"endLine": 137, "endLine": 137,
"source": "memory", "source": "memory",
"snippet": "- 生成脚本: `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_listenin", "snippet": "- 生成脚本: `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_listenin",
"recallCount": 4, "recallCount": 8,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 8,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T02:33:30.526Z", "firstRecalledAt": "2026-05-29T02:33:30.526Z",
"lastRecalledAt": "2026-06-10T02:20:22.635Z", "lastRecalledAt": "2026-06-18T04:36:16.755Z",
"queryHashes": [ "queryHashes": [
"4aa0ef719160", "4aa0ef719160",
"20f6c2d072df", "20f6c2d072df",
"068db47fdc05", "068db47fdc05",
"6568231ab2d7" "6568231ab2d7",
"617d5faf5a33",
"f7926d356e13",
"341edb569d53",
"367cd3303e1d"
], ],
"recallDays": [ "recallDays": [
"2026-05-29", "2026-05-29",
"2026-06-08", "2026-06-08",
"2026-06-10" "2026-06-10",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"tmp/build-skill-points.py", "tmp/build-skill-points.py",
@ -2962,13 +2985,13 @@
"endLine": 66, "endLine": 66,
"source": "memory", "source": "memory",
"snippet": "8. 句型合规检测 - 接入方式:`<script src=\"l1_pedagogy_rules.js\"></script>` + 调用 `PedagogyRules.validate(summary, level)` - 数据源L1 词库 147 词(过滤 enabled=true、L2 词库 52 词、L1 句型 8 个、L2 句型(从 437MB bitable 导出中提取唯一结构) - 技术注意L2_pattern_list.json 体积 437MB1,082,450 条记录),直接嵌入前端不可行,已提取唯一句型结构后嵌入 - 所有 6 个测试用例通过 - 用户后续想尝试其他对接方式API 模式 / 飞书 Bot 联动 / CI 集成)", "snippet": "8. 句型合规检测 - 接入方式:`<script src=\"l1_pedagogy_rules.js\"></script>` + 调用 `PedagogyRules.validate(summary, level)` - 数据源L1 词库 147 词(过滤 enabled=true、L2 词库 52 词、L1 句型 8 个、L2 句型(从 437MB bitable 导出中提取唯一结构) - 技术注意L2_pattern_list.json 体积 437MB1,082,450 条记录),直接嵌入前端不可行,已提取唯一句型结构后嵌入 - 所有 6 个测试用例通过 - 用户后续想尝试其他对接方式API 模式 / 飞书 Bot 联动 / CI 集成)",
"recallCount": 9, "recallCount": 10,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 9, "totalScore": 10,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T02:33:30.526Z", "firstRecalledAt": "2026-05-29T02:33:30.526Z",
"lastRecalledAt": "2026-06-17T02:17:21.800Z", "lastRecalledAt": "2026-06-18T04:36:05.631Z",
"queryHashes": [ "queryHashes": [
"4aa0ef719160", "4aa0ef719160",
"e30c130b9d1d", "e30c130b9d1d",
@ -2978,14 +3001,16 @@
"3ac726b21876", "3ac726b21876",
"867f7264cd0e", "867f7264cd0e",
"5f16a7426a41", "5f16a7426a41",
"7c761b49b948" "7c761b49b948",
"533765637e65"
], ],
"recallDays": [ "recallDays": [
"2026-05-29", "2026-05-29",
"2026-06-01", "2026-06-01",
"2026-06-02", "2026-06-02",
"2026-06-10", "2026-06-10",
"2026-06-17" "2026-06-17",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"l1-pedagogy-rules.js", "l1-pedagogy-rules.js",
@ -3005,25 +3030,30 @@
"endLine": 14, "endLine": 14,
"source": "memory", "source": "memory",
"snippet": "## [梁晨] L1 Pedagogy Rules v4.0.0 交付 - 在 v3 基础上新增 5 个校验维度(来自 16 个教研 skill 规则提取): 6. 组件合规性12 种题型规则,来自 11 个 dialogue/info config skills 7. 字段完整性7 项自动检查,来自 audit_l1_config 8. 掌握度预测W_i×M_i 加权公式,来自 knowledge-mastery-calculator 9. 格式规范(标题/Markdown/标点/英式拼写/价值观,来自全量文本规范) 10. 语法检测(三单/主谓一致/双重否定,来自 audit_l1_config - 输出:`output/l1_pedagogy_rules_v4.js`59KB - 数据L1 147 词、L2 52 词、L1 8 句型、L2 1 句型、89 组英式拼写映射、12 种题型规则 - 已通过飞书 Bot 发送给梁晨 - API 兼容 v3不加 options 参数即为原行为;加 component/componentExposures 启用新维度 - 能力边界:内容质量诊断(第一层筛选),不是全链路归因(看不到 UX/服务端/学生侧因素)", "snippet": "## [梁晨] L1 Pedagogy Rules v4.0.0 交付 - 在 v3 基础上新增 5 个校验维度(来自 16 个教研 skill 规则提取): 6. 组件合规性12 种题型规则,来自 11 个 dialogue/info config skills 7. 字段完整性7 项自动检查,来自 audit_l1_config 8. 掌握度预测W_i×M_i 加权公式,来自 knowledge-mastery-calculator 9. 格式规范(标题/Markdown/标点/英式拼写/价值观,来自全量文本规范) 10. 语法检测(三单/主谓一致/双重否定,来自 audit_l1_config - 输出:`output/l1_pedagogy_rules_v4.js`59KB - 数据L1 147 词、L2 52 词、L1 8 句型、L2 1 句型、89 组英式拼写映射、12 种题型规则 - 已通过飞书 Bot 发送给梁晨 - API 兼容 v3不加 options 参数即为原行为;加 component/componentExposures 启用新维度 - 能力边界:内容质量诊断(第一层筛选),不是全链路归因(看不到 UX/服务端/学生侧因素)",
"recallCount": 6, "recallCount": 10,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 6, "totalScore": 10,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-06-02T01:49:17.841Z", "firstRecalledAt": "2026-06-02T01:49:17.841Z",
"lastRecalledAt": "2026-06-17T02:17:21.800Z", "lastRecalledAt": "2026-06-18T04:36:16.755Z",
"queryHashes": [ "queryHashes": [
"7e6aa000abdb", "7e6aa000abdb",
"094bfb865b29", "094bfb865b29",
"3ac726b21876", "3ac726b21876",
"867f7264cd0e", "867f7264cd0e",
"5f16a7426a41", "5f16a7426a41",
"7c761b49b948" "7c761b49b948",
"f7926d356e13",
"341edb569d53",
"533765637e65",
"367cd3303e1d"
], ],
"recallDays": [ "recallDays": [
"2026-06-02", "2026-06-02",
"2026-06-10", "2026-06-10",
"2026-06-17" "2026-06-17",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"v4.0.0", "v4.0.0",
@ -3043,25 +3073,27 @@
"endLine": 49, "endLine": 49,
"source": "memory", "source": "memory",
"snippet": "- 答案设为[2](英语的),与申报 adj. 英文的不符,应为[0] - 🟡 rubber (1218116):释义题例句\"an eraser made of rubber\"解释的是橡胶材料,非橡皮擦工具 - 🟡 Chinese(n.) (1218113):例句\"Chinese food\"中 Chinese 是形容词非名词,与题目义项\"中文\"不符 - 🟢 fun (1218119):解析末尾多余一个 `\"` - 🟢 eraser (1218111)`\"an eraser表示\"` 缺少空格 ## 武钰涵 — 听力-P1-图片选择题生产 - 题目集合 ID: 121601难度 B级L1 第3-4阶段Starters 3 - 知识点验证10个词中仅 run(v.) 在 L1 词库feetfoot 的复数)可视为已有,其余 8 个bus, taxi, trousers, shorts, winter, snow, cold, bee不在 L1/L2 词库 - 用户指示直接生产,已按 SKILL 规范生成 2 个题组各5题含听力文本、图片描述、正确答案、能力标签 - 已按 bitable 配置格式输出完整 jsonData + 题目完整配置 + 图片描述 - B级规则听力句子 5-8 词(均 7 词),每组 3 张同类物品不同属性图片 - 能力标签:显性事实理解|关键词识别 ×2 + 基础语境理解|场景/物品/动作识别 ## 梁辰user_id: ou_28f02dcada1193913cfbb6310f8daf07— HTML 诊断页面", "snippet": "- 答案设为[2](英语的),与申报 adj. 英文的不符,应为[0] - 🟡 rubber (1218116):释义题例句\"an eraser made of rubber\"解释的是橡胶材料,非橡皮擦工具 - 🟡 Chinese(n.) (1218113):例句\"Chinese food\"中 Chinese 是形容词非名词,与题目义项\"中文\"不符 - 🟢 fun (1218119):解析末尾多余一个 `\"` - 🟢 eraser (1218111)`\"an eraser表示\"` 缺少空格 ## 武钰涵 — 听力-P1-图片选择题生产 - 题目集合 ID: 121601难度 B级L1 第3-4阶段Starters 3 - 知识点验证10个词中仅 run(v.) 在 L1 词库feetfoot 的复数)可视为已有,其余 8 个bus, taxi, trousers, shorts, winter, snow, cold, bee不在 L1/L2 词库 - 用户指示直接生产,已按 SKILL 规范生成 2 个题组各5题含听力文本、图片描述、正确答案、能力标签 - 已按 bitable 配置格式输出完整 jsonData + 题目完整配置 + 图片描述 - B级规则听力句子 5-8 词(均 7 词),每组 3 张同类物品不同属性图片 - 能力标签:显性事实理解|关键词识别 ×2 + 基础语境理解|场景/物品/动作识别 ## 梁辰user_id: ou_28f02dcada1193913cfbb6310f8daf07— HTML 诊断页面",
"recallCount": 6, "recallCount": 7,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 6, "totalScore": 7,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-06-02T01:49:17.841Z", "firstRecalledAt": "2026-06-02T01:49:17.841Z",
"lastRecalledAt": "2026-06-17T02:17:21.800Z", "lastRecalledAt": "2026-06-18T04:36:05.631Z",
"queryHashes": [ "queryHashes": [
"7e6aa000abdb", "7e6aa000abdb",
"094bfb865b29", "094bfb865b29",
"3ac726b21876", "3ac726b21876",
"867f7264cd0e", "867f7264cd0e",
"5f16a7426a41", "5f16a7426a41",
"7c761b49b948" "7c761b49b948",
"533765637e65"
], ],
"recallDays": [ "recallDays": [
"2026-06-02", "2026-06-02",
"2026-06-10", "2026-06-10",
"2026-06-17" "2026-06-17",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"听力-p1-图片选择题生产", "听力-p1-图片选择题生产",
@ -3344,21 +3376,23 @@
"endLine": 810, "endLine": 810,
"source": "memory", "source": "memory",
"snippet": "--- ## [李应瑛] L1-S2-U17-L5 笨蛋坏蛋英文生产2026-05-18 21:15 ### 背景 李应瑛发送知识库文档 `U1zEwHZaaie07TkjmOOchurgnIh`L1-S2-U17-L5 笨蛋坏蛋?),要求\"英文生产\"。 ### 文档结构与L3/L4不同 - Wiki token: `U1zEwHZaaie07TkjmOOchurgnIh` - Spreadsheet token: `DCcKsLbrmhfXgrtB7N2c9GA4ntf` - 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_", "snippet": "--- ## [李应瑛] L1-S2-U17-L5 笨蛋坏蛋英文生产2026-05-18 21:15 ### 背景 李应瑛发送知识库文档 `U1zEwHZaaie07TkjmOOchurgnIh`L1-S2-U17-L5 笨蛋坏蛋?),要求\"英文生产\"。 ### 文档结构与L3/L4不同 - Wiki token: `U1zEwHZaaie07TkjmOOchurgnIh` - Spreadsheet token: `DCcKsLbrmhfXgrtB7N2c9GA4ntf` - 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_",
"recallCount": 3, "recallCount": 4,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 3, "totalScore": 4,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-06-09T07:21:33.704Z", "firstRecalledAt": "2026-06-09T07:21:33.704Z",
"lastRecalledAt": "2026-06-10T02:20:12.701Z", "lastRecalledAt": "2026-06-18T04:36:05.631Z",
"queryHashes": [ "queryHashes": [
"ff0d0637f255", "ff0d0637f255",
"f525b14a0c5b", "f525b14a0c5b",
"9018e8896dcd" "9018e8896dcd",
"533765637e65"
], ],
"recallDays": [ "recallDays": [
"2026-06-09", "2026-06-09",
"2026-06-10" "2026-06-10",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"l1-s2-u17-l5", "l1-s2-u17-l5",