tree.py 6.2 KB
Newer Older
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
1 2 3 4 5 6 7
from genericpath import exists
import json
import os
import uuid
import sys
import re

M
Mars Liu 已提交
8
id_set = set()
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

def load_json(p):
    with open(p, 'r') as f:
        return json.loads(f.read())


def dump_json(p, j, exist_ok=False, override=False):
    if os.path.exists(p):
        if exist_ok:
            if not override:
                return
        else:
            print(f"{p} already exist")
            sys.exit(0)

    with open(p, 'w') as f:
        f.write(json.dumps(j, indent=2, ensure_ascii=False))


def parse_no_name(d):
    p = r'(\d+)\.(.*)'
    m = re.search(p, d)

    try:
        no = int(m.group(1))
        dir_name = m.group(2)
    except:
        sys.exit(0)

    return no, dir_name

M
Mars Liu 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
def check_export(base, cfg):
    flag = False
    exports = []
    for export in cfg.get('export', []):
        ecfg_path = os.path.join(base, export)
        if os.path.exists(ecfg_path):
            exports.append(export)
        else:
            flag = True
    if flag:
        cfg["export"] = exports
    return flag

CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
53 54 55 56 57

def gen_tree(data_path):
    root = {}

    def gen_node_id():
M
Mars Liu 已提交
58 59
        # return ''.join(str(uuid.uuid5(uuid.NAMESPACE_URL, 'skill_tree')).split('-'))
        return "c-" + uuid.uuid4().hex
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
60 61 62 63 64 65 66 67 68

    def list_dir(p):
        v = os.listdir(p)
        v.sort()
        for no_name in v:
            no_dir = os.path.join(p, no_name)
            if os.path.isdir(no_dir):
                yield no_dir, no_name

M
Mars Liu 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    def ensure_id_helper(node):
        flag = False

        if (node.get('node_id') is None) or node.get('node_id') in id_set:
            node['node_id'] = gen_node_id()   
            flag = True

        id_set.add(node['node_id'])

        if 'children' in node:
            for c in node["children"]:
                flag = flag or ensure_id_helper(list(c.values())[0])
    
        return flag

    def ensure_node_id(cfg):
        return ensure_id_helper(cfg)

    def ensure_title_helper(node, cfg_path, title=""):
        flag = False

        if node.get('title') is None:
            if cfg_path:
                node['title'] = re.sub("^[0-9]{1,3}\.", "", os.path.split(os.path.dirname(cfg_path))[-1])
            else:
                node['title'] = title
            flag = True

        if 'children' in node:
            for c in node["children"]:
                flag = flag or ensure_title_helper(list(c.values())[0], None, list(c.keys())[0])
    
        return flag

    def ensure_title(cfg, cfg_path):
        return ensure_title_helper(cfg, cfg_path)
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118

    def make_node(name, node_id, keywords, children=None):
        node = {}
        node_children = children or []
        node[name] = {
            'node_id': node_id,
            'keywords': keywords,
            'children': node_children
        }
        return node, node_children

    # 根节点
    cfg_path = os.path.join(data_path, 'config.json')
    cfg = load_json(cfg_path)
M
Mars Liu 已提交
119 120 121 122 123 124
    if ensure_node_id(cfg):
        dump_json(cfg_path, cfg)
        
    if ensure_title(cfg, cfg_path):
        cfg["title"] = "C"
        dump_json(cfg_path, cfg, exist_ok=True, override=True)
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
125 126 127 128 129 130 131 132 133 134 135
    tree_node = {
        "node_id": cfg['node_id'],
        "keywords": cfg['keywords'],
        "children": []
    }
    root[cfg['tree_name']] = tree_node

    # 难度节点
    for level_no_dir, level_no_name in list_dir(data_path):
        print(level_no_dir)
        no, level_name = parse_no_name(level_no_name)
M
Mars Liu 已提交
136 137 138 139 140 141
        level_path = os.path.join(level_no_dir, 'config.json')
        level_cfg = load_json(level_path)
        if ensure_node_id(level_cfg) or check_export(level_no_dir, level_cfg):
            dump_json(level_path, level_cfg, exist_ok=True, override=True)
        if ensure_title(level_cfg, level_path):
            dump_json(level_path, level_cfg, exist_ok=True, override=True)
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
142 143

        level_node, level_node_children = make_node(
M
Mars Liu 已提交
144
            level_name, level_cfg['node_id'], level_cfg['keywords'])
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
145 146 147 148 149
        tree_node['children'].append(level_node)

        # 章节点
        for chapter_no_dir, chapter_no_name in list_dir(level_no_dir):
            no, chapter_name = parse_no_name(chapter_no_name)
M
Mars Liu 已提交
150 151 152 153 154 155
            chapter_path = os.path.join(chapter_no_dir, 'config.json')
            chapter_cfg = load_json(chapter_path)
            if ensure_node_id(chapter_cfg) or check_export(chapter_no_dir, chapter_cfg):
                dump_json(chapter_path, chapter_cfg, exist_ok=True, override=True)
            if ensure_title(chapter_cfg, chapter_path):
                dump_json(chapter_path, chapter_cfg, exist_ok=True, override=True) 
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
156 157

            chapter_node, chapter_node_children = make_node(
M
Mars Liu 已提交
158
                chapter_name, chapter_cfg['node_id'], chapter_cfg['keywords'])
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
159 160 161 162 163
            level_node_children.append(chapter_node)

            # 知识点
            for section_no_dir, section_no_name in list_dir(chapter_no_dir):
                no, section_name = parse_no_name(section_no_name)
M
Mars Liu 已提交
164 165 166
                sec_path = os.path.join(section_no_dir, 'config.json')
                sec_cfg = load_json(sec_path)
                flag = ensure_node_id(sec_cfg) or check_export(section_no_dir, sec_cfg)
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
167 168

                section_node, section_node_children = make_node(
M
Mars Liu 已提交
169
                    section_name, sec_cfg['node_id'], sec_cfg['keywords'], sec_cfg.get('children', []))
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
170 171 172
                chapter_node_children.append(section_node)

                # 确保习题分配了习题ID
M
Mars Liu 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
                
                for export in sec_cfg.get("export", []):
                    ecfg_path = os.path.join(section_no_dir, export)
                    ecfg = load_json(ecfg_path)

                    if (ecfg.get('exercise_id') is None) or (ecfg.get('exercise_id') in id_set):
                        ecfg['exercise_id'] = uuid.uuid4().hex     
                        dump_json(ecfg_path, ecfg, exist_ok=True, override=True)
                        
                    id_set.add(ecfg['exercise_id'])

                if flag:
                    dump_json(sec_path, sec_cfg, exist_ok=True, override=True)

                if ensure_title(sec_cfg, sec_path):
                    dump_json(sec_path, sec_cfg, exist_ok=True, override=True) 
CSDN-Ada助手's avatar
CSDN-Ada助手 已提交
189 190 191 192

    # 保存技能树骨架
    tree_path = os.path.join(data_path, 'tree.json')
    dump_json(tree_path, root, exist_ok=True, override=True)