ai_member_xiaoyan/scripts/update_l2_difficulty_skills.py

194 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""批量更新 L2 和共用题型 SKILL.md 中的难度对应关系表"""
import os
import re
BASE = "/root/.openclaw/workspace-xiaoyan/business_production/单元挑战/skills/unit_challenge/questions"
# New L2 8-stage difficulty table
L2_NEW_TABLE = """## 难度对应关系(与教研标准对齐)
| 难度等级 | 对应L2阶段Unit范围 | 对标说明 | 难度描述 |
|------|---------|---------|------|
"""
# Store the A/B/C/D rows with the new mapping - 通用声明式,实际难度描述(最后一列)保留原样
L2_NEW_HEADER = "| 难度等级 | 对应L2阶段Unit范围 | 对标说明 | 难度描述 |"
# Maps for old->new grade columns
L2_GRADE_MAP = {
"A级": "| A级 | U1-U12阶段1-2 | Flyers入门→基础 |",
"B级": "| B级 | U13-U24阶段3-4 | Flyers达标→KET入门 |",
"C级": "| C级 | U25-U36阶段5-6 | KET基础→强化 |",
"D级": "| D级 | U37-U48阶段7-8 | KET高位→达标 |",
}
def update_l2_exclusive(filepath):
"""Update L2专属题型: replace entire difficulty table with 8-stage version"""
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
original = content
# ---- Part 1: Replace the difficulty table ----
# Find the section from "## 难度对应关系" to next heading/separator
pattern = r'(## 难度对应关系.*?\n)\| 难度等级 \|.*?\n\|[-|\s]*\n((?:\| [ABCD]级 \|.*?\n)+)'
def replace_table(match):
section_title = match.group(1)
old_rows = match.group(2)
new_rows = []
for old_row in old_rows.strip().split('\n'):
# Extract the last column (难度描述) from old row
parts = old_row.split('|')
if len(parts) >= 4:
desc = parts[-2].strip() if len(parts) > 4 else parts[-1].strip()
# Determine which grade
for grade, new_prefix in L2_GRADE_MAP.items():
if grade in old_row:
new_rows.append(f"{new_prefix} {desc} |")
break
else:
new_rows.append(old_row)
return section_title + L2_NEW_HEADER + '\n' + '\n'.join(new_rows) + '\n'
content = re.sub(pattern, replace_table, content, flags=re.DOTALL)
# ---- Part 2: Update config field description for 难度等级 ----
# Pattern: | 难度等级 | ✅ | `A级` / `...` / `...` | ... |
# Replace with new references
def replace_config(match):
full_line = match.group(0)
# Replace old stage/cambridge refs with new ones
new_line = re.sub(
r'`[ABCD]级` / `(?:L[12])(?:第)?[\d-]+阶段` / `(?:Starters|Movers|Flyers)[\s\d-]*`',
lambda m: m.group(0).replace(
m.group(0),
re.sub(
r'`([ABCD]级)` / `.*?` / `.*?`',
lambda g: {
'A级': '`A级` / `U1-U12阶段1-2` / `Flyers入门→基础`',
'B级': '`B级` / `U13-U24阶段3-4` / `Flyers达标→KET入门`',
'C级': '`C级` / `U25-U36阶段5-6` / `KET基础→强化`',
'D级': '`D级` / `U37-U48阶段7-8` / `KET高位→达标`',
}[g.group(1)],
m.group(0)
)
),
full_line
)
# Also update the note column
new_line = new_line.replace('难度等级或对应阶段', '难度等级L2用Unit范围')
return new_line
content = re.sub(
r'\| 难度等级 \| ✅ \|.*?\|.*?\|',
replace_config,
content
)
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def update_common(filepath):
"""Update L1&L2共用题型: add L2 dimension after L1 table"""
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
original = content
# Check if already has L2 dimension
if 'L2 维度' in content or 'L2阶段Unit范围' in content:
return False
# Find end of L1 difficulty table (## 难度对应关系 ... through last D级 row)
pattern = r'(## 难度对应关系.*?\n(?:\| .*?\n)*)'
def add_l2_dimension(match):
table_block = match.group(1)
l2_note = (
"\n> **L2 难度维度(对标 Flyers/KET每2阶段为1个难度等级**\n"
"> - A级 = U1-U12阶段1-2Flyers入门→Flyers基础\n"
"> - B级 = U13-U24阶段3-4Flyers达标→KET入门\n"
"> - C级 = U25-U36阶段5-6KET基础→KET强化\n"
"> - D级 = U37-U48阶段7-8KET高位→KET达标\n"
)
return table_block + l2_note
content = re.sub(pattern, add_l2_dimension, content, flags=re.DOTALL)
# Also update config row if it references Starters/Movers
content = re.sub(
r'\| 难度等级 \| ✅ \|.*?\| 难度等级或对应阶段 \|',
lambda m: m.group(0).replace('难度等级或对应阶段', '难度等级L1用Starters/MoversL2用Unit范围'),
content
)
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def main():
L2_FILES = [
"listening/L2/listening_short_conversation/SKILL.md",
"listening/L2/listening_long_conversation/SKILL.md",
"listening/L2/listening_form_fill/SKILL.md",
"listening/L2/listening-choicePic/SKILL.md",
"listening/L2/listening_info_match/SKILL.md",
"reading/reading_info_match/SKILL.md",
"reading/reading_paragraph_match/SKILL.md",
"reading/reading_long_passage/SKILL.md",
"reading/reading_cloze/SKILL.md",
"reading/reading_open_fill/SKILL.md",
"writing/writing_email_reply/SKILL.md",
"writing/writing_picture_writing/SKILL.md",
"speaking/L2/speaking_topic_discussion/SKILL.md",
]
COMMON_FILES = [
"reading/common/reading_pic_qa/SKILL.md",
"reading/common/reading_pic_judge/SKILL.md",
"speaking/common/speaking_daily_qa/SKILL.md",
"writing/common/writing_pic_qa/SKILL.md",
]
updated = 0
print("=== L2 专属题型 ===")
for rel_path in L2_FILES:
full = os.path.join(BASE, rel_path)
if not os.path.exists(full):
print(f" [MISS] {rel_path}")
continue
if update_l2_exclusive(full):
print(f" [OK] {rel_path}")
updated += 1
else:
print(f" [NO CHANGE] {rel_path}")
print("\n=== L1&L2 共用题型 ===")
for rel_path in COMMON_FILES:
full = os.path.join(BASE, rel_path)
if not os.path.exists(full):
print(f" [MISS] {rel_path}")
continue
if update_common(full):
print(f" [OK] {rel_path}")
updated += 1
else:
print(f" [NO CHANGE] {rel_path}")
print(f"\n=== Done: {updated} files updated ===")
if __name__ == '__main__':
main()