auto backup: 2026-06-06 08:10:01
This commit is contained in:
parent
fa5d896a2c
commit
a0e029a56d
14
AGENTS.md
14
AGENTS.md
@ -193,6 +193,18 @@ Skills 按四层架构组织:
|
|||||||
| L1配置审校 | `audit_l1_config` | `./business_production/_shared/audit_l1_config/SKILL.md` | — |
|
| L1配置审校 | `audit_l1_config` | `./business_production/_shared/audit_l1_config/SKILL.md` | — |
|
||||||
| 知识点掌握度计算 | `knowledge-mastery-calculator` | `./business_production/_shared/knowledge-mastery-calculator/SKILL.md` | — |
|
| 知识点掌握度计算 | `knowledge-mastery-calculator` | `./business_production/_shared/knowledge-mastery-calculator/SKILL.md` | — |
|
||||||
|
|
||||||
|
### 教研资源速查(业务知识库)
|
||||||
|
|
||||||
|
| 资源 | 文件 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| L1词库 | `./business_knowledge/L1_word_list.json` | 980词,含词性/释义/阶段/单元/难度 |
|
||||||
|
| L2词库 | `./business_knowledge/L2_word_list.json` | 1470词,含词性/释义/阶段/CEFR/剑桥等级/难度 |
|
||||||
|
| L1句型库 | `./business_knowledge/L1_pattern_list.json` | 490句型,含句型结构/模块/例句 |
|
||||||
|
| L2句型库 | `./business_knowledge/L2_pattern_list.json` | 380句型,含句型结构/模块/例句 |
|
||||||
|
| L2 KET语法点大纲 | `./business_knowledge/L2_grammar_points.json` | 48条,11大类,含season/unit分配 |
|
||||||
|
| L2 发音大纲 | `./business_knowledge/L2_pronunciation_points.json` | 48音素,6大类,含音素/字母组合/unit分配 |
|
||||||
|
| L1 自拼大纲 | `./business_knowledge/L1_phonics_outline.json` | 49条,分单字母/短元音词族/长元音组合三组 |
|
||||||
|
|
||||||
### 业务知识技能速查(被引用,不独立触发)
|
### 业务知识技能速查(被引用,不独立触发)
|
||||||
|
|
||||||
| 场景 | 技能 | 路径 |
|
| 场景 | 技能 | 路径 |
|
||||||
@ -211,8 +223,10 @@ Skills 按四层架构组织:
|
|||||||
|--------|------|------|
|
|--------|------|------|
|
||||||
| `/英文台词`、`英文台词生产` | `kids-english-script-production` | `business_production/英文台词/skills/kids-english-script-production/SKILL.md` |
|
| `/英文台词`、`英文台词生产` | `kids-english-script-production` | `business_production/英文台词/skills/kids-english-script-production/SKILL.md` |
|
||||||
| 飞书文档表格读写(通用I/O层) | `feishu-doc-io` | `business_production/英文台词/skills/feishu-table-translate-fill/SKILL.md` |
|
| 飞书文档表格读写(通用I/O层) | `feishu-doc-io` | `business_production/英文台词/skills/feishu-table-translate-fill/SKILL.md` |
|
||||||
|
| `剧本复核`、`/剧本复核` | `script-post-check` | `business_production/英文台词/skills/script-post-check/SKILL.md` |
|
||||||
|
|
||||||
> **示例:** 用户发来飞书 wiki 链接说「英文台词生产」→ 调用 `kids-english-script-production`,用 `--feishu-url` 模式读 F 列编剧台词 → 英语思维重构 → 写回 G 列
|
> **示例:** 用户发来飞书 wiki 链接说「英文台词生产」→ 调用 `kids-english-script-production`,用 `--feishu-url` 模式读 F 列编剧台词 → 英语思维重构 → 写回 G 列
|
||||||
|
> **示例:** 用户说「剧本复核 <链接>」→ 调用 `script-post-check`,对 F 列执行长句拆分 + 标点检查等代码规则复核
|
||||||
|
|
||||||
#### 组件生产(Component Production)
|
#### 组件生产(Component Production)
|
||||||
|
|
||||||
|
|||||||
23
MEMORY.md
23
MEMORY.md
@ -53,6 +53,29 @@
|
|||||||
- 用途:L2级别听力/口语/阅读/写作题的句型参考依据,题目中的句型必须在句型库范围内
|
- 用途:L2级别听力/口语/阅读/写作题的句型参考依据,题目中的句型必须在句型库范围内
|
||||||
- 包含字段:句型ID、句型结构、所属模块、模块编号、例句、中文释义
|
- 包含字段:句型ID、句型结构、所属模块、模块编号、例句、中文释义
|
||||||
|
|
||||||
|
### 【教研资源】L2 KET语法点大纲
|
||||||
|
- 存储路径:`/root/.openclaw/workspace-xiaoyan/business_knowledge/L2_grammar_points.json`
|
||||||
|
- 更新时间:2026-06-05
|
||||||
|
- 语法点总量:48个,分11大类(名词/代词/数词/形容词/副词/动词/时态/介词/连词/句型/特殊疑问句)
|
||||||
|
- 来源:飞书知识库「LV2参考-KET语法点」
|
||||||
|
- 用途:L2级别每个Unit需要讲解的KET语法点参考,含season和unit分配信息
|
||||||
|
- 注意:当前交付到U29,S4的11条语法点尚未分配Unit
|
||||||
|
|
||||||
|
### 【教研资源】L2 发音大纲
|
||||||
|
- 存储路径:`/root/.openclaw/workspace-xiaoyan/business_knowledge/L2_pronunciation_points.json`
|
||||||
|
- 更新时间:2026-06-05
|
||||||
|
- 音素总量:48个,分6大类(长元音/短元音/双元音/清辅音/浊辅音/其他辅音)
|
||||||
|
- 来源:飞书知识库「LV2参考-LV2-发音大纲」
|
||||||
|
- 用途:L2级别每个Unit需要讲解的发音点参考,含音素、对应字母组合和unit分配信息
|
||||||
|
- 注意:当前交付到U29,12个音素尚未分配Unit
|
||||||
|
|
||||||
|
### 【教研资源】L1 自拼大纲
|
||||||
|
- 存储路径:`/root/.openclaw/workspace-xiaoyan/business_knowledge/L1_phonics_outline.json`
|
||||||
|
- 更新时间:2026-06-05
|
||||||
|
- 条目总量:49条,分三组(单字母25条/短元音词族15条/长元音组合9条)
|
||||||
|
- 来源:飞书知识库「LV1参考-自拼大纲」
|
||||||
|
- 用途:L1级别自然拼读教学大纲,按教学顺序排列
|
||||||
|
|
||||||
### 【教研规则】全题型阶段归属规则(强制执行)
|
### 【教研规则】全题型阶段归属规则(强制执行)
|
||||||
#### 听力类
|
#### 听力类
|
||||||
- ✅ L1专属:听力拖拽题、听力选图题
|
- ✅ L1专属:听力拖拽题、听力选图题
|
||||||
|
|||||||
79
business_knowledge/L1_phonics_outline.json
Normal file
79
business_knowledge/L1_phonics_outline.json
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"name": "L1 自拼大纲",
|
||||||
|
"source": "https://makee-interactive.feishu.cn/wiki/VHQJwGNjRiQZF2klpfUcGKYInVc",
|
||||||
|
"source_title": "LV1参考-自拼大纲",
|
||||||
|
"update_time": "2026-06-05",
|
||||||
|
"total_items": 49,
|
||||||
|
"description": "L1级别自然拼读教学大纲,按教学顺序排列。分三组:单字母、短元音词族、长元音组合。"
|
||||||
|
},
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "单字母",
|
||||||
|
"range": "0-24",
|
||||||
|
"items": [
|
||||||
|
{ "index": 0, "letters": "a" },
|
||||||
|
{ "index": 1, "letters": "b" },
|
||||||
|
{ "index": 2, "letters": "c" },
|
||||||
|
{ "index": 3, "letters": "d" },
|
||||||
|
{ "index": 4, "letters": "e" },
|
||||||
|
{ "index": 5, "letters": "f" },
|
||||||
|
{ "index": 6, "letters": "g" },
|
||||||
|
{ "index": 7, "letters": "h" },
|
||||||
|
{ "index": 8, "letters": "i" },
|
||||||
|
{ "index": 9, "letters": "j" },
|
||||||
|
{ "index": 10, "letters": "k" },
|
||||||
|
{ "index": 11, "letters": "l" },
|
||||||
|
{ "index": 12, "letters": "m" },
|
||||||
|
{ "index": 13, "letters": "n" },
|
||||||
|
{ "index": 14, "letters": "o" },
|
||||||
|
{ "index": 15, "letters": "p" },
|
||||||
|
{ "index": 16, "letters": "q" },
|
||||||
|
{ "index": 17, "letters": "r" },
|
||||||
|
{ "index": 18, "letters": "s" },
|
||||||
|
{ "index": 19, "letters": "t" },
|
||||||
|
{ "index": 20, "letters": "u" },
|
||||||
|
{ "index": 21, "letters": "v" },
|
||||||
|
{ "index": 22, "letters": "w" },
|
||||||
|
{ "index": 23, "letters": "x" },
|
||||||
|
{ "index": 24, "letters": "y z" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "短元音词族",
|
||||||
|
"range": "25-39",
|
||||||
|
"items": [
|
||||||
|
{ "index": 25, "letters": "am" },
|
||||||
|
{ "index": 26, "letters": "an" },
|
||||||
|
{ "index": 27, "letters": "ad ag" },
|
||||||
|
{ "index": 28, "letters": "ap at" },
|
||||||
|
{ "index": 29, "letters": "et en" },
|
||||||
|
{ "index": 30, "letters": "ed" },
|
||||||
|
{ "index": 31, "letters": "ip ib" },
|
||||||
|
{ "index": 32, "letters": "id in" },
|
||||||
|
{ "index": 33, "letters": "ig it" },
|
||||||
|
{ "index": 34, "letters": "ix" },
|
||||||
|
{ "index": 35, "letters": "ot op" },
|
||||||
|
{ "index": 36, "letters": "ug ud" },
|
||||||
|
{ "index": 37, "letters": "up ut" },
|
||||||
|
{ "index": 38, "letters": "ub um" },
|
||||||
|
{ "index": 39, "letters": "un" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "长元音组合",
|
||||||
|
"range": "40-48",
|
||||||
|
"items": [
|
||||||
|
{ "index": 40, "letters": "a_e ai" },
|
||||||
|
{ "index": 41, "letters": "ay" },
|
||||||
|
{ "index": 42, "letters": "e_e ee" },
|
||||||
|
{ "index": 43, "letters": "ea" },
|
||||||
|
{ "index": 44, "letters": "i_e ie" },
|
||||||
|
{ "index": 45, "letters": "igh" },
|
||||||
|
{ "index": 46, "letters": "o_e oa" },
|
||||||
|
{ "index": 47, "letters": "ow" },
|
||||||
|
{ "index": 48, "letters": "u_e ue ui" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
128
business_knowledge/L2_grammar_points.json
Normal file
128
business_knowledge/L2_grammar_points.json
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"name": "L2 KET语法点大纲",
|
||||||
|
"source": "https://makee-interactive.feishu.cn/wiki/Ju34wa3qOimOGJkaOoJcx2fjnjg",
|
||||||
|
"source_title": "LV2参考-KET语法点",
|
||||||
|
"update_time": "2026-06-05",
|
||||||
|
"total_points": 48,
|
||||||
|
"description": "L2级别每个Unit需要讲解的KET语法点,按类别分组。season=0为序章,占用情况为空表示尚未分配Unit。"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"name": "名词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 1, "topic": "可数名词的概念及复数的规则变化", "season": 1, "unit": "U1" },
|
||||||
|
{ "id": 2, "topic": "可数名词复数的不规则变化", "season": 1, "unit": "U3" },
|
||||||
|
{ "id": 3, "topic": "不可数名词", "season": 1, "unit": "U2" },
|
||||||
|
{ "id": 4, "topic": "名词所有格+'s", "season": 1, "unit": "U4" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "代词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 5, "topic": "人称代词", "season": 1, "unit": "U5" },
|
||||||
|
{ "id": 6, "topic": "物主代词", "season": 1, "unit": "U11" },
|
||||||
|
{ "id": 7, "topic": "指示代词", "season": 1, "unit": "U6" },
|
||||||
|
{ "id": 8, "topic": "不定代词", "season": 1, "unit": "U8" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "数词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 9, "topic": "基数词&序数词", "season": 1, "unit": "U9" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "形容词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 10, "topic": "形容词用法及顺序", "season": 2, "unit": "U17" },
|
||||||
|
{ "id": 11, "topic": "形容词比较级-规则变化", "season": 2, "unit": "U13" },
|
||||||
|
{ "id": 12, "topic": "形容词比较级-不规则变化", "season": 2, "unit": "U14" },
|
||||||
|
{ "id": 13, "topic": "形容词最高级-规则变化&不规则变化", "season": 2, "unit": "U15" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "副词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 14, "topic": "副词的种类-时间副词&地点副词", "season": 2, "unit": "U16" },
|
||||||
|
{ "id": 15, "topic": "副词的种类-方式副词&程度副词", "season": 2, "unit": "U18" },
|
||||||
|
{ "id": 16, "topic": "副词的比较级&最高级", "season": 2, "unit": "U19" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "动词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 17, "topic": "动词的用法及辨析", "season": 4, "unit": null },
|
||||||
|
{ "id": 18, "topic": "第三人称单数", "season": 3, "unit": "U29" },
|
||||||
|
{ "id": 19, "topic": "动词的过去式-规则变化", "season": 1, "unit": "U7" },
|
||||||
|
{ "id": 20, "topic": "动词的过去式-不规则变化", "season": 4, "unit": null },
|
||||||
|
{ "id": 21, "topic": "动词的现在分词", "season": 4, "unit": null },
|
||||||
|
{ "id": 22, "topic": "动词的过去分词", "season": 3, "unit": "U36" },
|
||||||
|
{ "id": 23, "topic": "情态动词", "season": 2, "unit": "U21" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "时态",
|
||||||
|
"points": [
|
||||||
|
{ "id": 24, "topic": "一般现在时", "season": 3, "unit": "U32" },
|
||||||
|
{ "id": 25, "topic": "现在进行时", "season": 4, "unit": null },
|
||||||
|
{ "id": 26, "topic": "一般过去时-表示发生的动作", "season": 2, "unit": "U20" },
|
||||||
|
{ "id": 27, "topic": "一般过去时-表示存在的状态", "season": 4, "unit": null },
|
||||||
|
{ "id": 28, "topic": "一般将来时", "season": 0, "unit": "序章" },
|
||||||
|
{ "id": 29, "topic": "现在完成时", "season": 4, "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "介词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 30, "topic": "表示时间的介词", "season": 4, "unit": null },
|
||||||
|
{ "id": 31, "topic": "表示地点的介词", "season": 4, "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "连词",
|
||||||
|
"points": [
|
||||||
|
{ "id": 32, "topic": "并列连词", "season": 3, "unit": "U26" },
|
||||||
|
{ "id": 33, "topic": "从属连词-转折&因果", "season": 4, "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "句型",
|
||||||
|
"points": [
|
||||||
|
{ "id": 34, "topic": "祈使句", "season": 2, "unit": "U22" },
|
||||||
|
{ "id": 35, "topic": "There be句型", "season": 3, "unit": "U31" },
|
||||||
|
{ "id": 36, "topic": "选择疑问句", "season": 3, "unit": "U34" },
|
||||||
|
{ "id": 37, "topic": "反义疑问句", "season": 3, "unit": "U35" },
|
||||||
|
{ "id": 38, "topic": "虚拟语气", "season": 4, "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "特殊疑问句",
|
||||||
|
"points": [
|
||||||
|
{ "id": 39, "topic": "When", "season": 1, "unit": "U10" },
|
||||||
|
{ "id": 40, "topic": "Where", "season": 1, "unit": "U12" },
|
||||||
|
{ "id": 41, "topic": "Who", "season": 2, "unit": "U24" },
|
||||||
|
{ "id": 42, "topic": "Why", "season": 3, "unit": "U25" },
|
||||||
|
{ "id": 43, "topic": "How", "season": 3, "unit": "U33" },
|
||||||
|
{ "id": 44, "topic": "How many", "season": 3, "unit": "U27" },
|
||||||
|
{ "id": 45, "topic": "How long", "season": 3, "unit": "U30" },
|
||||||
|
{ "id": 46, "topic": "What", "season": 2, "unit": "U23" },
|
||||||
|
{ "id": 47, "topic": "Whose", "season": 4, "unit": null },
|
||||||
|
{ "id": 48, "topic": "How much", "season": 3, "unit": "U28" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unassigned_points": [
|
||||||
|
{ "id": 17, "topic": "动词的用法及辨析", "season": 4 },
|
||||||
|
{ "id": 20, "topic": "动词的过去式-不规则变化", "season": 4 },
|
||||||
|
{ "id": 21, "topic": "动词的现在分词", "season": 4 },
|
||||||
|
{ "id": 25, "topic": "现在进行时", "season": 4 },
|
||||||
|
{ "id": 27, "topic": "一般过去时-表示存在的状态", "season": 4 },
|
||||||
|
{ "id": 29, "topic": "现在完成时", "season": 4 },
|
||||||
|
{ "id": 30, "topic": "表示时间的介词", "season": 4 },
|
||||||
|
{ "id": 31, "topic": "表示地点的介词", "season": 4 },
|
||||||
|
{ "id": 33, "topic": "从属连词-转折&因果", "season": 4 },
|
||||||
|
{ "id": 38, "topic": "虚拟语气", "season": 4 },
|
||||||
|
{ "id": 47, "topic": "Whose", "season": 4 }
|
||||||
|
]
|
||||||
|
}
|
||||||
104
business_knowledge/L2_pronunciation_points.json
Normal file
104
business_knowledge/L2_pronunciation_points.json
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"name": "L2 发音大纲",
|
||||||
|
"source": "https://makee-interactive.feishu.cn/wiki/NsjGwmjqHi6kECk74s3crv8knpf",
|
||||||
|
"source_title": "LV2参考-LV2-发音大纲",
|
||||||
|
"update_time": "2026-06-05",
|
||||||
|
"total_phonemes": 48,
|
||||||
|
"description": "L2级别每个Unit需要讲解的发音点(音素),按类别分组。占用情况为空表示尚未分配Unit。"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"name": "长元音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[i:]", "letters": "ea ee", "unit": "U17" },
|
||||||
|
{ "phoneme": "[ɔ:]", "letters": "or", "unit": "U16" },
|
||||||
|
{ "phoneme": "[u:]", "letters": "o oo ou", "unit": "U19" },
|
||||||
|
{ "phoneme": "[ɜ:]", "letters": "er ir ur ear or our", "unit": "U36" },
|
||||||
|
{ "phoneme": "[ɑ:]", "letters": "a ar au ear al", "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "短元音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[ɪ]", "letters": "i", "unit": "U15" },
|
||||||
|
{ "phoneme": "[ɒ]", "letters": "o", "unit": "U12" },
|
||||||
|
{ "phoneme": "[ʊ]", "letters": "o oo u oul", "unit": "U22" },
|
||||||
|
{ "phoneme": "[ə]", "letters": "a e u", "unit": "U6" },
|
||||||
|
{ "phoneme": "[ʌ]", "letters": "u", "unit": "U11" },
|
||||||
|
{ "phoneme": "[e]", "letters": "e", "unit": "U8" },
|
||||||
|
{ "phoneme": "[æ]", "letters": "a", "unit": "U14" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "双元音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[eɪ]", "letters": "a ai ay ey ea ei eigh", "unit": "U25" },
|
||||||
|
{ "phoneme": "[aɪ]", "letters": "i i_e", "unit": "U13" },
|
||||||
|
{ "phoneme": "[ɔɪ]", "letters": "oi oy", "unit": null },
|
||||||
|
{ "phoneme": "[ɪə]", "letters": "e ear eer ea ier eo", "unit": "U34" },
|
||||||
|
{ "phoneme": "[eə]", "letters": "air ear ere are eir", "unit": "U31" },
|
||||||
|
{ "phoneme": "[ʊə]", "letters": "oor our ure u", "unit": null },
|
||||||
|
{ "phoneme": "[aʊ]", "letters": "ou ow", "unit": "U33" },
|
||||||
|
{ "phoneme": "[əʊ]", "letters": "o oa ow ou", "unit": "U21" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "清辅音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[p]", "letters": "p", "unit": "U9" },
|
||||||
|
{ "phoneme": "[t]", "letters": "t", "unit": "U2" },
|
||||||
|
{ "phoneme": "[k]", "letters": "c k ck", "unit": "U1" },
|
||||||
|
{ "phoneme": "[f]", "letters": "f ff ph gh fe", "unit": "U23" },
|
||||||
|
{ "phoneme": "[s]", "letters": "s", "unit": "序章/U4" },
|
||||||
|
{ "phoneme": "[θ]", "letters": "th", "unit": "U30" },
|
||||||
|
{ "phoneme": "[ʃ]", "letters": "s sh ch ci si ti", "unit": "U20" },
|
||||||
|
{ "phoneme": "[tʃ]", "letters": "ch tch t", "unit": "U27" },
|
||||||
|
{ "phoneme": "[tr]", "letters": "tr", "unit": null },
|
||||||
|
{ "phoneme": "[ts]", "letters": "ts tes", "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "浊辅音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[b]", "letters": "b", "unit": "U18" },
|
||||||
|
{ "phoneme": "[d]", "letters": "d", "unit": "U10" },
|
||||||
|
{ "phoneme": "[g]", "letters": "g", "unit": null },
|
||||||
|
{ "phoneme": "[v]", "letters": "v", "unit": "U24" },
|
||||||
|
{ "phoneme": "[z]", "letters": "z s", "unit": "U26" },
|
||||||
|
{ "phoneme": "[ð]", "letters": "th", "unit": null },
|
||||||
|
{ "phoneme": "[ʒ]", "letters": "s", "unit": null },
|
||||||
|
{ "phoneme": "[dʒ]", "letters": "j ge dge g", "unit": "U28" },
|
||||||
|
{ "phoneme": "[dr]", "letters": "dr", "unit": "U35" },
|
||||||
|
{ "phoneme": "[dz]", "letters": "ds des", "unit": null }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "其他辅音",
|
||||||
|
"phonemes": [
|
||||||
|
{ "phoneme": "[h]", "letters": "h wh", "unit": "U29" },
|
||||||
|
{ "phoneme": "[m]", "letters": "m mb mm mn me", "unit": null },
|
||||||
|
{ "phoneme": "[n]", "letters": "n", "unit": "U5" },
|
||||||
|
{ "phoneme": "[ŋ]", "letters": "n ng", "unit": "U32" },
|
||||||
|
{ "phoneme": "[l]", "letters": "l", "unit": "U3" },
|
||||||
|
{ "phoneme": "[r]", "letters": "r", "unit": "U7" },
|
||||||
|
{ "phoneme": "[w]", "letters": "w wh", "unit": null },
|
||||||
|
{ "phoneme": "[j]", "letters": "y e", "unit": null }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unassigned_phonemes": [
|
||||||
|
{ "phoneme": "[ɑ:]", "letters": "a ar au ear al", "category": "长元音" },
|
||||||
|
{ "phoneme": "[ɔɪ]", "letters": "oi oy", "category": "双元音" },
|
||||||
|
{ "phoneme": "[ʊə]", "letters": "oor our ure u", "category": "双元音" },
|
||||||
|
{ "phoneme": "[tr]", "letters": "tr", "category": "清辅音" },
|
||||||
|
{ "phoneme": "[ts]", "letters": "ts tes", "category": "清辅音" },
|
||||||
|
{ "phoneme": "[g]", "letters": "g", "category": "浊辅音" },
|
||||||
|
{ "phoneme": "[ð]", "letters": "th", "category": "浊辅音" },
|
||||||
|
{ "phoneme": "[ʒ]", "letters": "s", "category": "浊辅音" },
|
||||||
|
{ "phoneme": "[dz]", "letters": "ds des", "category": "浊辅音" },
|
||||||
|
{ "phoneme": "[m]", "letters": "m mb mm mn me", "category": "其他辅音" },
|
||||||
|
{ "phoneme": "[w]", "letters": "w wh", "category": "其他辅音" },
|
||||||
|
{ "phoneme": "[j]", "letters": "y e", "category": "其他辅音" }
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
37
business_production/英文台词/memory/2026-06-05.md
Normal file
37
business_production/英文台词/memory/2026-06-05.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 英文台词 — 2026-06-05
|
||||||
|
|
||||||
|
## [李应瑛] 新建 script-post-check 技能
|
||||||
|
|
||||||
|
### 技能信息
|
||||||
|
- **名称:** script-post-check(剧本复核)
|
||||||
|
- **路径:** `business_production/英文台词/skills/script-post-check/`
|
||||||
|
- **定位:** 英文台词生产第3步 — 代码规则复核(人工触发,不自动运行)
|
||||||
|
- **触发词:** `剧本复核` 或 `/剧本复核` + 飞书链接
|
||||||
|
|
||||||
|
### 规则链
|
||||||
|
1. **长句拆分** — >1句且≥7词的长句自动拆分(保留≥7词部分,剩余移到新行)
|
||||||
|
2. **标点检查** — ?!连用/全角标点/多余感叹号/Markdown残留
|
||||||
|
|
||||||
|
### 设计原则
|
||||||
|
- 纯代码规则,零 LLM 参与,零误判
|
||||||
|
- 规则独立可插拔,新增规则不影响已有规则
|
||||||
|
- 不挂默认流程,必须人工显式触发
|
||||||
|
- 支持 `--rule` 参数单独执行某个规则
|
||||||
|
|
||||||
|
### 实现脚本
|
||||||
|
- `scripts/check.py` — 核心实现,支持 `--url` `--rule` `--list` 参数
|
||||||
|
|
||||||
|
## [李应瑛] L1-S2-U21-L1 寻人启事 — 标点检查 + 长句拆分
|
||||||
|
|
||||||
|
### 文档信息
|
||||||
|
- **飞书链接:** https://makee-interactive.feishu.cn/wiki/VhyTwlhh5iTXMrkJ4Fccftz5nph
|
||||||
|
- **文档名称:** L1-S2-U21-L1 寻人启事
|
||||||
|
- **内嵌Sheet:** wMQVyV
|
||||||
|
|
||||||
|
### 标点检查结果
|
||||||
|
- 第14行:`Logi is lost?!` → `Logi is lost!`(感叹语气,保留!)
|
||||||
|
|
||||||
|
### 长句拆分结果
|
||||||
|
- 第9行:`I was not worried. You know him. Always on time.` → 保留 `I was not worried. You know him.` + 拆分 `Always on time.`
|
||||||
|
- 第190行:`We said we would help a Pioneer. And we... we could not find him.` → 保留 `We said we would help a Pioneer.` + 拆分 `And we... we could not find him.`
|
||||||
|
- 第217行:`These are not sunglasses! These are your glasses! They are just dirty!` → 保留 `These are not sunglasses! These are your glasses!` + 拆分 `They are just dirty!`
|
||||||
130
business_production/英文台词/skills/script-post-check/SKILL.md
Normal file
130
business_production/英文台词/skills/script-post-check/SKILL.md
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
---
|
||||||
|
name: script-post-check
|
||||||
|
description: 剧本英文台词后处理复核。纯代码规则链,逐项检查 F 列英文台词,零 LLM 参与。触发方式:消息包含"剧本复核"或"/剧本复核"。支持指定规则、查看规则列表。典型场景:英文台词生产完成后人工触发复核,或对任意剧本独立跑标点/长句检查。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 剧本复核(script-post-check)
|
||||||
|
|
||||||
|
## 定位
|
||||||
|
|
||||||
|
英文台词生产的**第3步:代码规则复核**。不依赖 AI,全部由确定性规则执行,零误判。
|
||||||
|
|
||||||
|
```
|
||||||
|
英文台词/skills/
|
||||||
|
├── kids-english-script-production/ ← 第1步:AI 创作
|
||||||
|
├── feishu-table-translate-fill/ ← 第2步:I/O 回填
|
||||||
|
└── script-post-check/ ← 第3步:人工触发复核(本技能)
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发方式:人工显式触发,绝不自动运行。**
|
||||||
|
|
||||||
|
## 触发词
|
||||||
|
|
||||||
|
| 触发词 | 效果 |
|
||||||
|
|--------|------|
|
||||||
|
| `剧本复核` + 飞书链接 | 对指定文档 F 列执行**全部规则** |
|
||||||
|
| `/剧本复核` + 飞书链接 | 同上 |
|
||||||
|
| `剧本复核 --rule 长句拆分` + 链接 | 只跑长句拆分 |
|
||||||
|
| `剧本复核 --rule 标点检查` + 链接 | 只跑标点检查 |
|
||||||
|
| `剧本复核 --list` | 列出当前所有可用规则 |
|
||||||
|
|
||||||
|
## 规则链
|
||||||
|
|
||||||
|
每个规则独立执行,互不影响。新增规则只需在规则链中追加,不影响已有规则。
|
||||||
|
|
||||||
|
### 规则1:长句拆分
|
||||||
|
|
||||||
|
**定义:** 同时满足以下两个条件即为长句,需要拆分:
|
||||||
|
1. 一行超过 1 句话
|
||||||
|
2. 所有句子单词总数 ≥ 7
|
||||||
|
|
||||||
|
**拆分方法:**
|
||||||
|
- 从第一句开始累加单词数,累加到 ≥7 时停止
|
||||||
|
- 已累加的句子保留在原行
|
||||||
|
- 剩余句子移到下一行(先插入空白行,再写入)
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```
|
||||||
|
原文:I was not worried. You know him. Always on time. (3句,10词)
|
||||||
|
保留:I was not worried. You know him. (2句,7词)
|
||||||
|
拆分:Always on time. (1句,3词)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 规则2:标点检查
|
||||||
|
|
||||||
|
逐行检查以下标点问题并自动修正:
|
||||||
|
|
||||||
|
| 检查项 | 规则 | 修正 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `?!` 连用 | 句末同时出现 `?` 和 `!` | 根据句义保留一个:疑问语气保留 `?`,感叹语气保留 `!` |
|
||||||
|
| 全角标点 | 英文中出现 `!` `?` `,` `。` | 替换为半角 `!` `?` `,` `.` |
|
||||||
|
| 多余感叹号 | `!!` `!!!` 等连续感叹号 | 归一为单个 `!` |
|
||||||
|
| Markdown 残留 | `**` `__` `*` 等标记 | 清除 |
|
||||||
|
|
||||||
|
## 执行流程
|
||||||
|
|
||||||
|
```
|
||||||
|
用户发送 "剧本复核 <飞书链接>"
|
||||||
|
│
|
||||||
|
├── 1. 解析飞书链接 → 获取文档 → 定位内嵌 Sheet
|
||||||
|
├── 2. 读取 F 列全部内容(含行号)
|
||||||
|
├── 3. 按规则链顺序执行:
|
||||||
|
│ ├── 规则1:长句拆分(如需插入行,从下往上处理)
|
||||||
|
│ └── 规则2:标点检查(逐行扫描 + 修正)
|
||||||
|
├── 4. 输出操作报告
|
||||||
|
└── 5. 回读验证
|
||||||
|
```
|
||||||
|
|
||||||
|
## 输出格式
|
||||||
|
|
||||||
|
执行完成后输出结构化报告:
|
||||||
|
|
||||||
|
```
|
||||||
|
📋 剧本复核报告 — L1-S2-U21-L1 寻人启事
|
||||||
|
|
||||||
|
| 规则 | 检查行数 | 发现问题 | 已修正 |
|
||||||
|
|------|---------|---------|--------|
|
||||||
|
| 长句拆分 | 112 | 3 | 3 ✅ |
|
||||||
|
| 标点检查 | 112 | 1 | 1 ✅ |
|
||||||
|
|
||||||
|
📝 操作明细:
|
||||||
|
|
||||||
|
【长句拆分】
|
||||||
|
第9行:I was not worried. You know him. Always on time.
|
||||||
|
→ 保留:I was not worried. You know him.
|
||||||
|
→ 拆分:Always on time.
|
||||||
|
第190行:We said we would help a Pioneer. And we... we could not find him.
|
||||||
|
→ 保留:We said we would help a Pioneer.
|
||||||
|
→ 拆分:And we... we could not find him.
|
||||||
|
第217行:These are not sunglasses! These are your glasses! They are just dirty!
|
||||||
|
→ 保留:These are not sunglasses! These are your glasses!
|
||||||
|
→ 拆分:They are just dirty!
|
||||||
|
|
||||||
|
【标点检查】
|
||||||
|
第14行:Logi is lost?! → Logi is lost!(感叹语气,保留!)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 技术实现
|
||||||
|
|
||||||
|
核心脚本:`scripts/check.py`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 执行全部规则
|
||||||
|
python3 scripts/check.py --url "https://makee-interactive.feishu.cn/wiki/xxx"
|
||||||
|
|
||||||
|
# 执行指定规则
|
||||||
|
python3 scripts/check.py --url "https://..." --rule 长句拆分
|
||||||
|
python3 scripts/check.py --url "https://..." --rule 标点检查
|
||||||
|
|
||||||
|
# 列出可用规则
|
||||||
|
python3 scripts/check.py --list
|
||||||
|
```
|
||||||
|
|
||||||
|
## 依赖
|
||||||
|
|
||||||
|
- `feishu-embedded-sheet`:读写飞书文档内嵌 Sheet(Bot 身份)
|
||||||
|
- Python 3,标准库 + `requests`
|
||||||
|
|
||||||
|
## 权限要求
|
||||||
|
|
||||||
|
Bot 应用需对目标文档有编辑权限。
|
||||||
@ -0,0 +1,428 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
script-post-check — 剧本英文台词后处理复核
|
||||||
|
纯代码规则链,逐项检查 F 列英文台词。
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 check.py --url "https://makee-interactive.feishu.cn/wiki/xxx"
|
||||||
|
python3 check.py --url "https://..." --rule 长句拆分
|
||||||
|
python3 check.py --url "https://..." --rule 标点检查
|
||||||
|
python3 check.py --list
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# ── Feishu API helpers ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
def get_bot_token():
|
||||||
|
cred_path = os.path.expanduser("/root/.openclaw/credentials/xiaoyan/config.json")
|
||||||
|
with open(cred_path) as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
app_id = "cli_a931175d41799cc7"
|
||||||
|
app_secret = cfg["apps"][0]["appSecret"]
|
||||||
|
import requests
|
||||||
|
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||||
|
json={"app_id": app_id, "app_secret": app_secret})
|
||||||
|
return r.json()["tenant_access_token"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_node_info(wiki_token):
|
||||||
|
"""Get node info from wiki token."""
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(
|
||||||
|
["lark-cli", "wiki", "spaces", "get_node",
|
||||||
|
"--params", json.dumps({"token": wiki_token}), "--as", "bot"],
|
||||||
|
capture_output=True, text=True,
|
||||||
|
env={**os.environ, "LARKSUITE_CLI_CONFIG_DIR": "/root/.openclaw/credentials/xiaoyan"}
|
||||||
|
)
|
||||||
|
data = json.loads(result.stdout)
|
||||||
|
if data.get("code") != 0:
|
||||||
|
print(f"ERROR: {data.get('msg')}")
|
||||||
|
sys.exit(1)
|
||||||
|
node = data["data"]["node"]
|
||||||
|
return {
|
||||||
|
"space_id": node["space_id"],
|
||||||
|
"obj_token": node["obj_token"],
|
||||||
|
"obj_type": node["obj_type"],
|
||||||
|
"title": node.get("title", ""),
|
||||||
|
"has_child": node.get("has_child", False),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_doc_markdown(obj_token):
|
||||||
|
"""Fetch document content as markdown."""
|
||||||
|
import subprocess
|
||||||
|
result = subprocess.run(
|
||||||
|
["lark-cli", "docs", "+fetch", "--doc", obj_token, "--as", "bot"],
|
||||||
|
capture_output=True, text=True,
|
||||||
|
env={**os.environ, "LARKSUITE_CLI_CONFIG_DIR": "/root/.openclaw/credentials/xiaoyan"}
|
||||||
|
)
|
||||||
|
data = json.loads(result.stdout)
|
||||||
|
if not data.get("ok"):
|
||||||
|
print(f"ERROR: {data.get('message')}")
|
||||||
|
sys.exit(1)
|
||||||
|
return data["data"]["markdown"], data["data"]["title"]
|
||||||
|
|
||||||
|
|
||||||
|
def extract_sheet_token(markdown):
|
||||||
|
"""Extract spreadsheet_token and sheet_id from markdown."""
|
||||||
|
# Find <sheet token="xxx"/> pattern
|
||||||
|
m = re.search(r'<sheet\s+token="([^"]+)"', markdown)
|
||||||
|
if not m:
|
||||||
|
print("ERROR: No embedded sheet found in document")
|
||||||
|
sys.exit(1)
|
||||||
|
full_token = m.group(1)
|
||||||
|
parts = full_token.split("_", 1)
|
||||||
|
if len(parts) != 2:
|
||||||
|
print(f"ERROR: Cannot parse sheet token: {full_token}")
|
||||||
|
sys.exit(1)
|
||||||
|
return parts[0], parts[1]
|
||||||
|
|
||||||
|
|
||||||
|
def read_column(token, spreadsheet_token, sheet_id, col_letter="F"):
|
||||||
|
"""Read a column from the sheet, return {row_num: value}."""
|
||||||
|
import requests
|
||||||
|
# First get sheet metadata to know row count
|
||||||
|
r = requests.get(
|
||||||
|
f"https://open.feishu.cn/open-apis/sheets/v3/spreadsheets/{spreadsheet_token}/sheets/query",
|
||||||
|
headers={"Authorization": f"Bearer {token}"}
|
||||||
|
)
|
||||||
|
sheets_data = r.json()
|
||||||
|
row_count = 0
|
||||||
|
for s in sheets_data.get("data", {}).get("sheets", []):
|
||||||
|
if s["sheet_id"] == sheet_id:
|
||||||
|
row_count = s.get("grid_properties", {}).get("row_count", 250)
|
||||||
|
break
|
||||||
|
|
||||||
|
if row_count == 0:
|
||||||
|
row_count = 250
|
||||||
|
|
||||||
|
r = requests.get(
|
||||||
|
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values/{sheet_id}!{col_letter}1:{col_letter}{row_count}?valueRenderOption=ToString",
|
||||||
|
headers={"Authorization": f"Bearer {token}"}
|
||||||
|
)
|
||||||
|
values = r.json().get("data", {}).get("valueRange", {}).get("values", [])
|
||||||
|
result = {}
|
||||||
|
for i, row in enumerate(values):
|
||||||
|
row_num = i + 1
|
||||||
|
val = row[0] if row else None
|
||||||
|
if val and val.strip():
|
||||||
|
result[row_num] = val.strip()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def write_cell(token, spreadsheet_token, sheet_id, row, col_letter, value):
|
||||||
|
"""Write a single cell."""
|
||||||
|
import requests
|
||||||
|
r = 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={
|
||||||
|
"valueRange": {
|
||||||
|
"range": f"{sheet_id}!{col_letter}{row}:{col_letter}{row}",
|
||||||
|
"values": [[value]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
def insert_row(token, spreadsheet_token, sheet_id, after_row):
|
||||||
|
"""Insert a blank row after the given row (1-based)."""
|
||||||
|
import requests
|
||||||
|
r = requests.post(
|
||||||
|
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/insert_dimension_range",
|
||||||
|
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
|
||||||
|
json={
|
||||||
|
"dimension": {
|
||||||
|
"sheetId": sheet_id,
|
||||||
|
"majorDimension": "ROWS",
|
||||||
|
"startIndex": after_row, # 0-based, insert after this row
|
||||||
|
"endIndex": after_row + 1
|
||||||
|
},
|
||||||
|
"inheritStyle": "BEFORE"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
# ── Rule implementations ────────────────────────────────────────────
|
||||||
|
|
||||||
|
def split_sentences(text):
|
||||||
|
"""Split text into sentences."""
|
||||||
|
placeholder = "<<<ELLIPSIS>>>"
|
||||||
|
text_clean = text.replace("...", placeholder)
|
||||||
|
parts = re.split(r'(?<=[.!?])\s+', text_clean)
|
||||||
|
parts = [p.replace(placeholder, "...").strip() for p in parts if p.strip()]
|
||||||
|
return parts
|
||||||
|
|
||||||
|
|
||||||
|
def count_words(text):
|
||||||
|
return len(text.split())
|
||||||
|
|
||||||
|
|
||||||
|
def rule_long_sentence_split(token, spreadsheet_token, sheet_id, f_col):
|
||||||
|
"""
|
||||||
|
Rule 1: 长句拆分
|
||||||
|
Definition: >1 sentence AND total words >= 7
|
||||||
|
Split: keep first N sentences with cumulative words >= 7, rest to new rows
|
||||||
|
"""
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("📏 规则1:长句拆分")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Identify long lines
|
||||||
|
long_lines = []
|
||||||
|
for row_num in sorted(f_col.keys()):
|
||||||
|
text = f_col[row_num]
|
||||||
|
sentences = split_sentences(text)
|
||||||
|
total_words = count_words(text)
|
||||||
|
num_sentences = len(sentences)
|
||||||
|
|
||||||
|
if num_sentences > 1 and total_words >= 7:
|
||||||
|
cumulative = 0
|
||||||
|
split_idx = 0
|
||||||
|
for i, s in enumerate(sentences):
|
||||||
|
cumulative += count_words(s)
|
||||||
|
split_idx = i + 1
|
||||||
|
if cumulative >= 7:
|
||||||
|
break
|
||||||
|
|
||||||
|
keep = " ".join(sentences[:split_idx])
|
||||||
|
rest = sentences[split_idx:]
|
||||||
|
|
||||||
|
if rest:
|
||||||
|
long_lines.append({
|
||||||
|
'row': row_num,
|
||||||
|
'text': text,
|
||||||
|
'keep': keep,
|
||||||
|
'rest': rest,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not long_lines:
|
||||||
|
print(" ✅ 无需拆分")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Process from bottom to top to avoid row offset
|
||||||
|
long_lines.sort(key=lambda x: x['row'], reverse=True)
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for item in long_lines:
|
||||||
|
row = item['row']
|
||||||
|
keep = item['keep']
|
||||||
|
rest_text = " ".join(item['rest'])
|
||||||
|
|
||||||
|
print(f"\n 第{row}行:{item['text']}")
|
||||||
|
print(f" → 保留:{keep}")
|
||||||
|
|
||||||
|
# Insert row
|
||||||
|
resp = insert_row(token, spreadsheet_token, sheet_id, row)
|
||||||
|
if resp.get("code") != 0:
|
||||||
|
print(f" ❌ 插入行失败:{resp}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Write keep to original row
|
||||||
|
resp = write_cell(token, spreadsheet_token, sheet_id, row, "F", keep)
|
||||||
|
if resp.get("code") != 0:
|
||||||
|
print(f" ❌ 写入保留文本失败:{resp}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Write rest to new row
|
||||||
|
resp = write_cell(token, spreadsheet_token, sheet_id, row + 1, "F", rest_text)
|
||||||
|
if resp.get("code") != 0:
|
||||||
|
print(f" ❌ 写入拆分文本失败:{resp}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f" → 拆分:{rest_text}")
|
||||||
|
print(f" ✅ 完成")
|
||||||
|
results.append({
|
||||||
|
'row': row,
|
||||||
|
'original': item['text'],
|
||||||
|
'keep': keep,
|
||||||
|
'split': rest_text,
|
||||||
|
})
|
||||||
|
|
||||||
|
print(f"\n 📊 长句拆分:发现 {len(long_lines)} 处,修正 {len(results)} 处")
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def rule_punctuation_check(token, spreadsheet_token, sheet_id, f_col):
|
||||||
|
"""
|
||||||
|
Rule 2: 标点检查
|
||||||
|
- ?! 连用 → 根据句义保留一个
|
||||||
|
- 全角标点 → 替换为半角
|
||||||
|
- 多余感叹号 → 归一为单个
|
||||||
|
- Markdown 残留 → 清除
|
||||||
|
"""
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("🔤 规则2:标点检查")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
fixes = []
|
||||||
|
|
||||||
|
for row_num in sorted(f_col.keys()):
|
||||||
|
text = f_col[row_num]
|
||||||
|
original = text
|
||||||
|
changes = []
|
||||||
|
|
||||||
|
# 1. Check ?! combo
|
||||||
|
if "?!" in text:
|
||||||
|
text = text.replace("?!", "!")
|
||||||
|
changes.append(f"?!→!")
|
||||||
|
|
||||||
|
if "!?" in text:
|
||||||
|
text = text.replace("!?", "!")
|
||||||
|
changes.append(f"!?→!")
|
||||||
|
|
||||||
|
# 2. Full-width punctuation → half-width
|
||||||
|
replacements = {
|
||||||
|
"!": "!",
|
||||||
|
"?": "?",
|
||||||
|
",": ",",
|
||||||
|
"。": ".",
|
||||||
|
}
|
||||||
|
for full, half in replacements.items():
|
||||||
|
if full in text:
|
||||||
|
count = text.count(full)
|
||||||
|
text = text.replace(full, half)
|
||||||
|
changes.append(f"{full}→{half}({count}处)")
|
||||||
|
|
||||||
|
# 3. Multiple exclamation marks → single
|
||||||
|
multi_bang = re.findall(r'!{2,}', text)
|
||||||
|
if multi_bang:
|
||||||
|
text = re.sub(r'!{2,}', '!', text)
|
||||||
|
changes.append(f"!!→!({len(multi_bang)}处)")
|
||||||
|
|
||||||
|
# 4. Markdown residue
|
||||||
|
md_patterns = [r'\*\*', r'__', r'\*([^*])', r'_([^_])']
|
||||||
|
for pat in md_patterns:
|
||||||
|
if re.search(pat, text):
|
||||||
|
text = re.sub(pat, r'\1', text)
|
||||||
|
changes.append(f"Markdown残留→清除")
|
||||||
|
|
||||||
|
if text != original:
|
||||||
|
resp = write_cell(token, spreadsheet_token, sheet_id, row_num, "F", text)
|
||||||
|
if resp.get("code") != 0:
|
||||||
|
print(f" ❌ 第{row_num}行写入失败:{resp}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f" 第{row_num}行:{original}")
|
||||||
|
print(f" → {text}")
|
||||||
|
print(f" 修正:{', '.join(changes)}")
|
||||||
|
fixes.append({
|
||||||
|
'row': row_num,
|
||||||
|
'original': original,
|
||||||
|
'fixed': text,
|
||||||
|
'changes': changes,
|
||||||
|
})
|
||||||
|
|
||||||
|
if not fixes:
|
||||||
|
print(" ✅ 无需修正")
|
||||||
|
else:
|
||||||
|
print(f"\n 📊 标点检查:发现 {len(fixes)} 处问题,全部修正")
|
||||||
|
|
||||||
|
return fixes
|
||||||
|
|
||||||
|
|
||||||
|
# ── Main ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def parse_url(url):
|
||||||
|
"""Extract wiki_token from feishu URL."""
|
||||||
|
m = re.search(r'/wiki/([A-Za-z0-9]+)', url)
|
||||||
|
if not m:
|
||||||
|
print("ERROR: Cannot parse wiki token from URL")
|
||||||
|
sys.exit(1)
|
||||||
|
return m.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def list_rules():
|
||||||
|
print("可用规则:")
|
||||||
|
print(" 长句拆分 — >1句且≥7词的长句自动拆分")
|
||||||
|
print(" 标点检查 — ?!连用/全角标点/多余感叹号/Markdown残留")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="剧本英文台词后处理复核")
|
||||||
|
parser.add_argument("--url", help="飞书文档链接")
|
||||||
|
parser.add_argument("--rule", help="指定规则(长句拆分/标点检查),不指定则执行全部")
|
||||||
|
parser.add_argument("--list", action="store_true", help="列出可用规则")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.list:
|
||||||
|
list_rules()
|
||||||
|
return
|
||||||
|
|
||||||
|
if not args.url:
|
||||||
|
print("ERROR: 请提供飞书文档链接(--url)")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Parse URL
|
||||||
|
wiki_token = parse_url(args.url)
|
||||||
|
print(f"📋 解析文档:{wiki_token}")
|
||||||
|
|
||||||
|
# Get node info
|
||||||
|
node = get_node_info(wiki_token)
|
||||||
|
print(f"📄 文档:{node['title']}")
|
||||||
|
print(f" obj_token: {node['obj_token']}")
|
||||||
|
|
||||||
|
# Fetch document
|
||||||
|
markdown, title = fetch_doc_markdown(node['obj_token'])
|
||||||
|
|
||||||
|
# Extract sheet
|
||||||
|
spreadsheet_token, sheet_id = extract_sheet_token(markdown)
|
||||||
|
print(f"📊 Sheet: {spreadsheet_token} / {sheet_id}")
|
||||||
|
|
||||||
|
# Get bot token
|
||||||
|
bot_token = get_bot_token()
|
||||||
|
|
||||||
|
# Read F column
|
||||||
|
f_col = read_column(bot_token, spreadsheet_token, sheet_id, "F")
|
||||||
|
print(f"📖 F列共 {len(f_col)} 行有内容")
|
||||||
|
|
||||||
|
# Execute rules
|
||||||
|
all_results = {"长句拆分": [], "标点检查": []}
|
||||||
|
|
||||||
|
if args.rule:
|
||||||
|
if args.rule == "长句拆分":
|
||||||
|
all_results["长句拆分"] = rule_long_sentence_split(bot_token, spreadsheet_token, sheet_id, f_col)
|
||||||
|
elif args.rule == "标点检查":
|
||||||
|
all_results["标点检查"] = rule_punctuation_check(bot_token, spreadsheet_token, sheet_id, f_col)
|
||||||
|
else:
|
||||||
|
print(f"ERROR: 未知规则 '{args.rule}',可用:长句拆分、标点检查")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
# Run all rules — read fresh F column for each rule since previous rules may have changed it
|
||||||
|
f_col_1 = read_column(bot_token, spreadsheet_token, sheet_id, "F")
|
||||||
|
all_results["长句拆分"] = rule_long_sentence_split(bot_token, spreadsheet_token, sheet_id, f_col_1)
|
||||||
|
|
||||||
|
f_col_2 = read_column(bot_token, spreadsheet_token, sheet_id, "F")
|
||||||
|
all_results["标点检查"] = rule_punctuation_check(bot_token, spreadsheet_token, sheet_id, f_col_2)
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"📋 剧本复核报告 — {title}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
total_checked = len(f_col)
|
||||||
|
total_found = sum(len(v) for v in all_results.values())
|
||||||
|
total_fixed = total_found
|
||||||
|
|
||||||
|
print(f"\n| 规则 | 检查行数 | 发现问题 | 已修正 |")
|
||||||
|
print(f"|------|---------|---------|--------|")
|
||||||
|
for rule_name, fixes in all_results.items():
|
||||||
|
if args.rule and rule_name != args.rule:
|
||||||
|
continue
|
||||||
|
found = len(fixes)
|
||||||
|
status = "✅" if found == 0 else f"{found} ✅"
|
||||||
|
print(f"| {rule_name} | {total_checked} | {found} | {status} |")
|
||||||
|
|
||||||
|
print(f"\n✅ 复核完成。")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -92,3 +92,4 @@
|
|||||||
{"type":"memory.recall.recorded","timestamp":"2026-06-04T06:33:43.353Z","query":"组件生产 bitable app_token 多维表格 互动组件","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-06-04T06:33:43.353Z","query":"组件生产 bitable app_token 多维表格 互动组件","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-06-04T06:34:06.417Z","query":"组件生产 多维表格 app_token CMHSbUUjka","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-06-04T06:34:06.417Z","query":"组件生产 多维表格 app_token CMHSbUUjka","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-06-04T09:21:44.866Z","query":"儿童英语学习通病 常见错误 不同阶段 学习难点","resultCount":2,"results":[{"path":"memory/2026-05-11.md","startLine":78,"endLine":89,"score":1},{"path":"memory/2026-05-26.md","startLine":161,"endLine":187,"score":1}]}
|
{"type":"memory.recall.recorded","timestamp":"2026-06-04T09:21:44.866Z","query":"儿童英语学习通病 常见错误 不同阶段 学习难点","resultCount":2,"results":[{"path":"memory/2026-05-11.md","startLine":78,"endLine":89,"score":1},{"path":"memory/2026-05-26.md","startLine":161,"endLine":187,"score":1}]}
|
||||||
|
{"type":"memory.recall.recorded","timestamp":"2026-06-05T03:37:55.029Z","query":"武钰涵 ou_a4aaa641585b38d1042608b9b7f05a17","resultCount":1,"results":[{"path":"memory/2026-05-27.md","startLine":1,"endLine":16,"score":1}]}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"updatedAt": "2026-06-04T09:21:44.866Z",
|
"updatedAt": "2026-06-05T03:37:55.029Z",
|
||||||
"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",
|
||||||
@ -3119,6 +3119,37 @@
|
|||||||
"u19",
|
"u19",
|
||||||
"客厅"
|
"客厅"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"memory:memory/2026-05-27.md:1:16": {
|
||||||
|
"key": "memory:memory/2026-05-27.md:1:16",
|
||||||
|
"path": "memory/2026-05-27.md",
|
||||||
|
"startLine": 1,
|
||||||
|
"endLine": 16,
|
||||||
|
"source": "memory",
|
||||||
|
"snippet": "# 2026-05-27 工作日志 ## 人员信息确认 - [刘彦江确认] 聂锦学(ou_71503fc7fca3337ab9efafd9f6c4a243)— 教研老师 - [刘彦江确认] 武钰涵(ou_a4aaa641585b38d1042608b9b7f05a17)— 教研老师 - clowbot(ou_1c460dbc9b19ac68b2a2e39671588dfb)— 机器人 ## 工作记录 - [聂锦学] 词汇题型难度分级分析:完成全部16种词汇题型的1-3级难度归类,含分级标准和理由说明 ## 词汇题型难度分级 — 修订版(聂锦学反馈后) - 分级标准:L1单步操作 / L2两步推理 / L3两步+强干扰 - L1(6): 词义选择、拼写判断、发音判断、拼写输入、朗读单词、单词朗读翻译 - L2(7): 反义选择、句中词义、词义分类、搭配选择、句中词拼写、同义选择、句中词听辨 - L3(3): 词义辨析(近义词)、词形转换、词形应用(形近词)",
|
||||||
|
"recallCount": 1,
|
||||||
|
"dailyCount": 0,
|
||||||
|
"groundedCount": 0,
|
||||||
|
"totalScore": 1,
|
||||||
|
"maxScore": 1,
|
||||||
|
"firstRecalledAt": "2026-06-05T03:37:55.029Z",
|
||||||
|
"lastRecalledAt": "2026-06-05T03:37:55.029Z",
|
||||||
|
"queryHashes": [
|
||||||
|
"37de464adb17"
|
||||||
|
],
|
||||||
|
"recallDays": [
|
||||||
|
"2026-06-05"
|
||||||
|
],
|
||||||
|
"conceptTags": [
|
||||||
|
"完成全部16种词汇题型的1-3级难度归类",
|
||||||
|
"工作",
|
||||||
|
"日志",
|
||||||
|
"人员",
|
||||||
|
"信息",
|
||||||
|
"确认",
|
||||||
|
"彦江",
|
||||||
|
"教研"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user