]> acesimba.cloud Git - study-mountion.git/commitdiff
新增重点词修订脚本(按 Excel 回填 is_key)
authorstudyhill <studyhill@local>
Sat, 29 Aug 2026 11:40:28 +0000 (19:40 +0800)
committerstudyhill <studyhill@local>
Sat, 29 Aug 2026 11:40:28 +0000 (19:40 +0800)
从修订版 Excel 读回 wid → 是否重点词,更新 lessons.payload 的 is_key。
与导入脚本不同:只改 payload,不重建课程,因此进度、完成记录、复习队列、
每日任务全部保留。默认预演,需显式 --apply 才写库。

本次采用人工修订版词表:每组 10 个、74 组共 740 个重点词,
较原自动选取翻转 916 处(新增 458 / 取消 458)。

backend/imports/apply_key_revision.py [new file with mode: 0644]

diff --git a/backend/imports/apply_key_revision.py b/backend/imports/apply_key_revision.py
new file mode 100644 (file)
index 0000000..b755784
--- /dev/null
@@ -0,0 +1,109 @@
+"""按修订版 Excel 更新 lessons.payload 里的重点词(is_key)标记。
+
+与 ielts_vocab.py 的区别:本脚本**只改 payload,不重建课程**,
+因此 course_progress / lesson_completions / review_queue / daily_tasks 全部原样保留。
+
+用法:
+    python3 imports/apply_key_revision.py --xlsx <修订版.xlsx>            # 预演
+    python3 imports/apply_key_revision.py --xlsx <修订版.xlsx> --apply    # 落库
+"""
+
+import argparse
+import json
+import os
+import sys
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+import db  # noqa: E402
+
+DEFAULT_XLSX = "/home/Codebuddy-web/data/pastes/雅思词汇真经-分组词汇表_重点词修订版 (1).xlsx"
+SHEET = "分组词汇表"
+C_WID, C_IS_KEY = 5, 10  # 列索引:单词ID / 重点词
+
+
+def load_revision(xlsx_path):
+    """返回 {wid: is_key}。以单词ID 为键,避免跨章重名混淆。"""
+    import openpyxl
+
+    wb = openpyxl.load_workbook(xlsx_path, data_only=True)
+    if SHEET not in wb.sheetnames:
+        raise SystemExit(f"找不到 sheet「{SHEET}」,现有:{wb.sheetnames}")
+    ws = wb[SHEET]
+
+    mapping = {}
+    for r in ws.iter_rows(min_row=2, values_only=True):
+        if r[C_WID] is None:
+            continue
+        mapping[str(r[C_WID]).strip()] = str(r[C_IS_KEY]).strip() == "是"
+    return mapping
+
+
+def apply(xlsx_path, do_apply=False):
+    revision = load_revision(xlsx_path)
+
+    conn = db.get_conn()
+    lessons = conn.execute("SELECT id, lesson_no, payload FROM lessons ORDER BY lesson_no").fetchall()
+
+    matched = 0      # Excel 里能对应上的词条数
+    changed = 0      # 实际翻转标记的词条数
+    lessons_touched = 0
+    unknown = set()
+
+    for lesson in lessons:
+        payload = json.loads(lesson["payload"])
+        dirty = False
+        for w in payload.get("words", []):
+            wid = str(w.get("wid") or "").strip()
+            if wid not in revision:
+                unknown.add(wid)
+                continue
+            matched += 1
+            if bool(w.get("is_key")) != revision[wid]:
+                w["is_key"] = revision[wid]
+                changed += 1
+                dirty = True
+        if dirty:
+            lessons_touched += 1
+            if do_apply:
+                conn.execute(
+                    "UPDATE lessons SET payload=?, updated_at=? WHERE id=?",
+                    (json.dumps(payload, ensure_ascii=False), db.now(), lesson["id"]),
+                )
+
+    if do_apply:
+        conn.commit()
+    conn.close()
+
+    return {
+        "revised_total": len(revision),
+        "revised_keys": sum(1 for v in revision.values() if v),
+        "matched": matched,
+        "changed": changed,
+        "lessons_touched": lessons_touched,
+        "unknown": unknown,
+    }
+
+
+def main():
+    ap = argparse.ArgumentParser()
+    ap.add_argument("--xlsx", default=DEFAULT_XLSX)
+    ap.add_argument("--apply", action="store_true", help="真正写库,缺省为预演")
+    args = ap.parse_args()
+
+    if not os.path.exists(args.xlsx):
+        raise SystemExit(f"找不到文件:{args.xlsx}")
+
+    db.init_db()
+    info = apply(args.xlsx, do_apply=args.apply)
+
+    print(f"修订版:{info['revised_total']} 词,其中重点词 {info['revised_keys']}")
+    print(f"匹配上:{info['matched']} 词")
+    print(f"需翻转:{info['changed']} 词,涉及 {info['lessons_touched']} 个课时")
+    if info["unknown"]:
+        print(f"!! 库中有 {len(info['unknown'])} 个词在修订版里找不到:{list(info['unknown'])[:5]}")
+    print("预演完成(未写库)" if not args.apply else "已写入数据库")
+
+
+if __name__ == "__main__":
+    main()