import pathlib import toml import time import auxiliary as aux class Electron: """电子: 记忆分析元数据及算法""" algorithm = "SM-2" # 暂时使用 SM-2 算法进行记忆拟合, 考虑 SM-15 替代 def __init__(self, content: str, metadata: dict): self.content = content self.metadata = metadata if metadata == {}: # print("NULL") self._default_init() def _default_init(self): defaults = { 'efactor': 2.5, # 易度系数, 越大越简单, 最大为5 'real_rept': 0, # (实际)重复次数 'rept': 0, # (有效)重复次数 'interval': 0, # 最佳间隔 'last_date': 0, # 上一次复习的时间戳 'next_date': 0, # 将要复习的时间戳 'is_activated': 0, # 激活状态 # *NOTE: 此处"时间戳"是以天为单位的整数, 即 UNIX 时间戳除以一天的秒数取整 'last_modify': time.time() # 最后修改时间戳(此处是UNIX时间戳) } self.metadata = defaults def activate(self): self.metadata['is_activated'] = 1 self.metadata['last_modify'] = time.time() def modify(self, var: str, value): if var in self.metadata: self.metadata[var] = value self.metadata['last_modify'] = time.time() else: print(f"警告: '{var}' 非已知元数据字段") def revisor(self, quality: int = 5, is_new_activation: bool = False): """SM-2 算法迭代决策机制实现 根据 quality(0 ~ 5) 进行参数迭代最佳间隔 quality 由主程序评估 Args: quality (int): 记忆保留率量化参数 """ print(f"REVISOR: {quality}, {is_new_activation}") if quality == -1: return -1 self.metadata['efactor'] = self.metadata['efactor'] + ( 0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02) ) self.metadata['efactor'] = max(1.3, self.metadata['efactor']) if quality < 3: # 若保留率低于 3,重置重复次数 self.metadata['rept'] = 0 self.metadata['interval'] = 0 # 设为0,以便下面重新计算 I(1) else: self.metadata['rept'] += 1 self.metadata['real_rept'] += 1 if is_new_activation: # 初次激活 self.metadata['rept'] = 0 self.metadata['efactor'] = 2.5 if self.metadata['rept'] == 0: # 刚被重置或初次激活后复习 self.metadata['interval'] = 1 # I(1) elif self.metadata['rept'] == 1: self.metadata['interval'] = 6 # I(2) 经验公式 else: self.metadata['interval'] = round( self.metadata['interval'] * self.metadata['efactor'] ) self.metadata['last_date'] = aux.get_daystamp() self.metadata['next_date'] = aux.get_daystamp() + self.metadata['interval'] self.metadata['last_modify'] = time.time() def __str__(self): return ( f"记忆单元预览 \n" f"内容: '{self.content}' \n" f"易度系数: {self.metadata['efactor']:.2f} \n" f"已经重复的次数: {self.metadata['rept']} \n" f"下次间隔: {self.metadata['interval']} 天 \n" f"下次复习日期时间戳: {self.metadata['next_date']}" ) def __eq__(self, other): if self.content == other.content: return True return False def __hash__(self): return hash(self.content) def __getitem__(self, key): if key == "content": return self.content if key in self.metadata: return self.metadata[key] else: raise KeyError(f"Key '{key}' not found in metadata.") def __setitem__(self, key, value): if key == "content": raise AttributeError("content 应为只读") self.metadata[key] = value self.metadata['last_modify'] = time.time() def __iter__(self): yield from self.metadata.keys() def __len__(self): return len(self.metadata) @staticmethod def placeholder(): return Electron("电子对象样例内容", {}) class Nucleon: """核子: 材料元数据""" def __init__(self, content: str, data: dict): self.metadata = data self.content = content def __getitem__(self, key): if key == "content": return self.content if key in self.metadata: return self.metadata[key] else: raise KeyError(f"Key '{key}' not found in metadata.") def __iter__(self): yield from self.metadata.keys() def __len__(self): return len(self.metadata) def __hash__(self): return hash(self.content) @staticmethod def placeholder(): return Nucleon("核子对象样例内容", {}) class NucleonUnion: """ 替代原有 NucleonFile 类, 支持复杂逻辑 Attributes: path (Path): 对应于 NucleonUnion 实例的文件路径。 name (str): 核联对象的显示名称,从文件名中派生。 nucleons (list): 内部核子对象的列表。 nucleons_dict (dict): 内部核子对象的字典,以核子内容作为键。 keydata (dict): 核子对象字典键名的翻译。 testdata (dict): 记忆测试项目的元数据。 Parameters: path (Path): 包含核子数据的文件路径。 """ def __init__(self, path): self.path = path self.name = path.name.replace(path.suffix, "") with open(path, 'r') as f: all = toml.load(f) lst = list() for i in all.keys(): if "data" in i: continue lst.append(Nucleon(i, all[i])) self.keydata = all["keydata"] self.testdata = all["testdata"] self.nucleons = lst self.nucleons_dict = {i.content: i for i in lst} def __len__(self): return len(self.nucleons) def save(self): with open(self.path, 'w') as f: tmp = {i.content: i.metadata for i in self.nucleons} toml.dump(tmp, f) class ElectronUnion: """取代原有 ElectronFile 类, 以支持复杂逻辑""" def __init__(self, path): self.path = path self.name = path.name.replace(path.suffix, "") with open(path, 'r') as f: all = toml.load(f) lst = list() for i in all.keys(): if i != "total": lst.append(Electron(i, all[i])) self.total = all.get("total", {"last_date": 0}) self.electrons = lst self.electrons_dict = {i.content: i for i in lst} def sync(self): """同步 electrons_dict 中新增对到 electrons 中""" self.electrons = self.electrons_dict.values() def save(self): # print(1) self.total["last_date"] = aux.get_daystamp() with open(self.path, 'w') as f: tmp = {i.content: i.metadata for i in self.electrons} tmp["total"] = self.total # print(tmp) toml.dump(tmp, f) """ class AtomicFile(): def __init__(self, path, type_="unknown"): self.path = path self.type_ = type_ if type_ == "nucleon": self.name, self.datalist = Nucleon.import_from_file(pathlib.Path(path)) if type_ == "electron": self.name, self.datalist = Electron.import_from_file(pathlib.Path(path)) def save(self): dictobj = {i.content: i.export_data() for i in self.datalist} print(dictobj) if self.type_ == "nucleon": Nucleon.save_to_file(dictobj, self.path) if self.type_ == "electron": Electron.save_to_file(dictobj, self.path) def get_full_content(self): if self.type_ == "nucleon": text = "" for i in self.datalist: text += i.content return text return "" def get_len(self): return len(self.datalist) """ class Atom: @staticmethod def placeholder(): return (Electron.placeholder(), Nucleon.placeholder(), {}) @staticmethod def advanced_placeholder(): return ( Electron("两只黄鹤鸣翠柳", {}), Nucleon( "两只黄鹤鸣翠柳", { "note": [], "translation": "臣子李密陈言:我因命运不好,小时候遭遇到了不幸", "keyword_note": { "险衅": "凶险祸患(这里指命运不好)", "夙": "早时,这里指年幼的时候", "闵": "通'悯',指可忧患的事", "凶": "不幸,指丧父" } } ), { "keydata": { "note": "笔记", "keyword_note": "关键词翻译", "translation": "语句翻译" }, "testdata": { "additional_inf": ["translation", "note", "keyword_note"], "fill_blank_test": ["translation"], "draw_card_test": ["keyword_note"] }, "is_new_activation": 0 } )