From eaa38fb880acda5471629f0f7f087919a93d6c65 Mon Sep 17 00:00:00 2001 From: david-ajax Date: Wed, 31 Dec 2025 00:57:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=9B=E4=B8=80=E6=AD=A5=E6=94=B9?= =?UTF-8?q?=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {config => data/config}/config.toml | 12 +- data/repo/test/algodata.json | 1 + data/repo/test/manifest.toml | 3 + data/repo/test/payload.toml | 17 +++ data/repo/test/schedule.toml | 3 + data/repo/test/typedef.toml | 19 +++ data/template/blank.toml | 23 ---- pyproject.toml | 2 +- src/heurams/default/config/config.toml | 61 ---------- src/heurams/interface/screens/dashboard.py | 2 +- src/heurams/interface/screens/memorizor.py | 2 +- src/heurams/interface/shim.py | 2 +- src/heurams/interface/widgets/cloze_puzzle.py | 2 +- src/heurams/interface/widgets/mcq_puzzle.py | 2 +- src/heurams/kernel/algorithms/__init__.py | 5 +- src/heurams/kernel/algorithms/base.py | 12 +- src/heurams/kernel/algorithms/sm2.py | 2 +- .../{puzzles => evaluators}/__init__.py | 12 +- .../kernel/{puzzles => evaluators}/base.py | 2 +- .../kernel/{puzzles => evaluators}/cloze.py | 4 +- src/heurams/kernel/evaluators/guess.py | 11 ++ .../kernel/{puzzles => evaluators}/mcq.py | 4 +- .../{puzzles => evaluators}/recognition.py | 4 +- src/heurams/kernel/particles/__init__.py | 29 ----- src/heurams/kernel/particles/atom.py | 99 ++++------------ src/heurams/kernel/particles/electron.py | 111 +++++------------- src/heurams/kernel/particles/loader.py | 74 ------------ src/heurams/kernel/particles/nucleon.py | 74 ++++++------ src/heurams/kernel/particles/orbital.py | 30 ----- src/heurams/kernel/particles/probe.py | 62 ---------- src/heurams/kernel/reactor/fission.py | 2 +- src/heurams/kernel/repomgr/aux.py | 5 + src/heurams/kernel/repomgr/repo.py | 42 ++++--- src/heurams/services/version.py | 4 +- src/heurams/utils/README.md | 2 - src/heurams/utils/__init__.py | 0 src/heurams/utils/evalizor.py | 28 +++++ src/heurams/{kernel/repomgr => utils}/lict.py | 0 tests/kernel/algorithms/test_sm2.py | 2 +- tests/kernel/particles/test_electron.py | 2 +- tests/kernel/puzzles/test_base.py | 2 +- tests/kernel/puzzles/test_cloze.py | 2 +- tests/kernel/puzzles/test_mcq.py | 2 +- 43 files changed, 251 insertions(+), 528 deletions(-) rename {config => data/config}/config.toml (90%) create mode 100644 data/repo/test/algodata.json create mode 100644 data/repo/test/manifest.toml create mode 100644 data/repo/test/payload.toml create mode 100644 data/repo/test/schedule.toml create mode 100644 data/repo/test/typedef.toml delete mode 100644 data/template/blank.toml delete mode 100644 src/heurams/default/config/config.toml rename src/heurams/kernel/{puzzles => evaluators}/__init__.py (82%) rename src/heurams/kernel/{puzzles => evaluators}/base.py (95%) rename src/heurams/kernel/{puzzles => evaluators}/cloze.py (97%) create mode 100644 src/heurams/kernel/evaluators/guess.py rename src/heurams/kernel/{puzzles => evaluators}/mcq.py (99%) rename src/heurams/kernel/{puzzles => evaluators}/recognition.py (82%) delete mode 100644 src/heurams/kernel/particles/loader.py delete mode 100644 src/heurams/kernel/particles/orbital.py delete mode 100644 src/heurams/kernel/particles/probe.py create mode 100644 src/heurams/kernel/repomgr/aux.py delete mode 100644 src/heurams/utils/README.md create mode 100644 src/heurams/utils/__init__.py create mode 100644 src/heurams/utils/evalizor.py rename src/heurams/{kernel/repomgr => utils}/lict.py (100%) diff --git a/config/config.toml b/data/config/config.toml similarity index 90% rename from config/config.toml rename to data/config/config.toml index c7a3805..a3b3369 100644 --- a/config/config.toml +++ b/data/config/config.toml @@ -1,18 +1,18 @@ # [调试] 将更改保存到文件 -persist_to_file = 1 +#persist_to_file = 1 # [调试] 覆写时间, 设为 -1 以禁用 -daystamp_override = -1 -timestamp_override = -1 +#daystamp_override = -1 +#timestamp_override = -1 # [调试] 一键通过 -quick_pass = 1 +#quick_pass = 1 # 对于每个项目的默认新记忆原子数量 -scheduled_num = 8 +#scheduled_num = 8 # UTC 时间戳修正 仅用于 UNIX 日时间戳的生成修正, 单位为秒 -timezone_offset = +28800 # 中国标准时间 (UTC+8) +#timezone_offset = +28800 # 中国标准时间 (UTC+8) [interface] diff --git a/data/repo/test/algodata.json b/data/repo/test/algodata.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/data/repo/test/algodata.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/data/repo/test/manifest.toml b/data/repo/test/manifest.toml new file mode 100644 index 0000000..6e5f567 --- /dev/null +++ b/data/repo/test/manifest.toml @@ -0,0 +1,3 @@ +title = "测试单元: 过秦论" +author = "__heurams__" +desc = "高考古诗文: 过秦论" \ No newline at end of file diff --git a/data/repo/test/payload.toml b/data/repo/test/payload.toml new file mode 100644 index 0000000..d9a34db --- /dev/null +++ b/data/repo/test/payload.toml @@ -0,0 +1,17 @@ +["秦孝公据崤函之固, 拥雍州之地,"] +note = [] +content = "秦孝公/据/崤函/之固/, 拥/雍州/之地,/" +translation = "秦孝公占据着崤山和函谷关的险固地势,拥有雍州的土地," +keyword_note = {"据"="占据", "崤函"="崤山和函谷关", "雍州"="古代九州之一"} + +["君臣固守以窥周室,"] +note = [] +content = "君臣/固守/以窥/周室,/" +translation = "君臣牢固地守卫着,借以窥视周王室的权力," +keyword_note = {"窥"="窥视"} + +["有席卷天下, 包举宇内, 囊括四海之意, 并吞八荒之心."] +note = [] +content = "有/席卷/天下/, 包举/宇内/, 囊括/四海/之意/, 并吞/八荒/之心./" +translation = "有席卷天下,包办天宇之间,囊括四海的意图,并统天下的雄心。" +keyword_note = {"席卷"="像卷席子一样全部卷进去", "包举"="像打包一样全部拿走", "囊括"="像装口袋一样全部装进去", "八荒"="八方荒远之地"} \ No newline at end of file diff --git a/data/repo/test/schedule.toml b/data/repo/test/schedule.toml new file mode 100644 index 0000000..792ed3d --- /dev/null +++ b/data/repo/test/schedule.toml @@ -0,0 +1,3 @@ +quick_review = [["FillBlank", "1.0"], ["SelectMeaning", "0.5"], ["Recognition", "1.0"]] +recognition = [["Recognition", "1.0"]] +final_review = [["FillBlank", "0.7"], ["SelectMeaning", "0.7"], ["Recognition", "1.0"]] \ No newline at end of file diff --git a/data/repo/test/typedef.toml b/data/repo/test/typedef.toml new file mode 100644 index 0000000..d55cc86 --- /dev/null +++ b/data/repo/test/typedef.toml @@ -0,0 +1,19 @@ +["古文句"] + +[annotation] +note = "笔记" +keyword_note = "关键词翻译" +translation = "语句翻译" +delimiter = "分隔符" +content = "内容" +tts_text = "文本转语音文本" + +["common"] +delimiter = "/" +tts_text = "eval:payload['content'].replace('/', '')" + +["puzzles"] # 谜题定义 +# 我们称 "Recognition" 为 recognition 谜题的 alia +"Recognition" = { __origin__ = "recognition", __hint__ = "", primary = "eval:payload['content']", secondary = ["eval:payload['keyword_note']", "eval:payload['note']"], top_dim = ["eval:payload['translation']"] } +"SelectMeaning" = { __origin__ = "mcq", __hint__ = "eval:payload['content']", primary = "eval:payload['content']", mapping = "eval:payload['keyword_note']", jammer = "eval:list(payload['keyword_note'].values())", max_riddles_num = "eval:default['mcq']['max_riddles_num']", prefix = "选择正确项: " } +"FillBlank" = { __origin__ = "cloze", __hint__ = "", text = "eval:payload['content']", delimiter = "eval:metadata['formation']['delimiter']", min_denominator = "eval:default['cloze']['min_denominator']"} diff --git a/data/template/blank.toml b/data/template/blank.toml deleted file mode 100644 index 49933ec..0000000 --- a/data/template/blank.toml +++ /dev/null @@ -1,23 +0,0 @@ -# Nucleon 是 HeurAMS 软件项目使用的基于 TOML 的专有源文件格式, 版本 5 -# 建议使用的 MIME 类型: application/vnd.xyz.imwangzhiyu.heurams-nucleon.v5+toml - -[__metadata__] -[__metadata__.attribution] # 元信息 -desc = "带有宏支持的空白模板" - -[__metadata__.annotation] # 键批注 - -[__metadata__.formation] # 文件配置 -#delimiter = "/" -#tts_text = "eval:nucleon['content'].replace('/', '')" - -[__metadata__.orbital.puzzles] # 谜题定义 -# 我们称 "Recognition" 为 recognition 谜题的 alia -#"Recognition" = { __origin__ = "recognition", __hint__ = "", primary = "eval:nucleon['content']", secondary = ["eval:nucleon['keyword_note']", "eval:nucleon['note']"], top_dim = ["eval:nucleon['translation']"] } -#"SelectMeaning" = { __origin__ = "mcq", __hint__ = "eval:nucleon['content']", mapping = "eval:nucleon['keyword_note']", jammer = "eval:nucleon['keyword_note']", max_riddles_num = "eval:default['mcq']['max_riddles_num']", prefix = "选择正确项: " } -#"FillBlank" = { __origin__ = "cloze", __hint__ = "", text = "eval:nucleon['content']", delimiter = "eval:metadata['formation']['delimiter']", min_denominator = "eval:default['cloze']['min_denominator']"} - -[__metadata__.orbital.schedule] # 内置的推荐学习方案 -#quick_review = [["FillBlank", "1.0"], ["SelectMeaning", "0.5"], ["recognition", "1.0"]] -#recognition = [["Recognition", "1.0"]] -#final_review = [["FillBlank", "0.7"], ["SelectMeaning", "0.7"], ["recognition", "1.0"]] diff --git a/pyproject.toml b/pyproject.toml index 400baf1..ec50274 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "heurams" -version = "0.4.3" +version = "0.5.0" description = "Heuristic Assisted Memory Scheduler" license = {file = "LICENSE"} classifiers = [ diff --git a/src/heurams/default/config/config.toml b/src/heurams/default/config/config.toml deleted file mode 100644 index c7a3805..0000000 --- a/src/heurams/default/config/config.toml +++ /dev/null @@ -1,61 +0,0 @@ -# [调试] 将更改保存到文件 -persist_to_file = 1 - -# [调试] 覆写时间, 设为 -1 以禁用 -daystamp_override = -1 -timestamp_override = -1 - -# [调试] 一键通过 -quick_pass = 1 - -# 对于每个项目的默认新记忆原子数量 -scheduled_num = 8 - -# UTC 时间戳修正 仅用于 UNIX 日时间戳的生成修正, 单位为秒 -timezone_offset = +28800 # 中国标准时间 (UTC+8) - -[interface] - -[interface.memorizor] -autovoice = true # 自动语音播放, 仅限于 recognition 组件 - -[algorithm] -default = "SM-2" # 主要算法; 可选项: SM-2, SM-15M, FSRS - -[puzzles] # 谜题默认配置 - -[puzzles.mcq] -max_riddles_num = 2 - -[puzzles.cloze] -min_denominator = 3 - -[paths] # 相对于配置文件的 ".." (即工作目录) 而言 或绝对路径 -nucleon_dir = "./data/nucleon" -electron_dir = "./data/electron" -global_dir = "./data/global" # 全局数据路径, SM-15 等算法需要 -orbital_dir = "./data/orbital" -cache_dir = "./data/cache" -template_dir = "./data/template" - -[services] # 定义服务到提供者的映射 -audio = "playsound" # 可选项: playsound(通用), termux(仅用于支持 Android Termux), mpg123(TODO) -tts = "edgetts" # 可选项: edgetts -llm = "openai" # 可选项: openai -sync = "webdav" # 可选项: 留空, webdav - -[providers.tts.edgetts] # EdgeTTS 设置 -voice = "zh-CN-XiaoxiaoNeural" # 可选项: zh-CN-YunjianNeural (男声), zh-CN-XiaoxiaoNeural (女声) - -[providers.llm.openai] # 与 OpenAI 相容的语言模型接口服务设置 -url = "" -key = "" - -[providers.sync.webdav] # WebDAV 同步设置 -url = "" -username = "" -password = "" -remote_path = "/heurams/" -verify_ssl = true - -[sync] diff --git a/src/heurams/interface/screens/dashboard.py b/src/heurams/interface/screens/dashboard.py index 38b0d1d..daea1c0 100644 --- a/src/heurams/interface/screens/dashboard.py +++ b/src/heurams/interface/screens/dashboard.py @@ -61,7 +61,7 @@ class DashboardScreen(Screen): Returns: dict: 包含显示文本的字典,键为行号 """ - from heurams.kernel.particles.loader import load_electron, load_nucleon + from heurams.kernel.repository.particle_loader import load_electron, load_nucleon result = {} filestem = pathlib.Path(filename).stem diff --git a/src/heurams/interface/screens/memorizor.py b/src/heurams/interface/screens/memorizor.py index 9bf03f7..53bb5cf 100644 --- a/src/heurams/interface/screens/memorizor.py +++ b/src/heurams/interface/screens/memorizor.py @@ -8,7 +8,7 @@ from textual.screen import Screen from textual.widgets import Button, Footer, Header, Label, Static import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz +import heurams.kernel.evaluators as pz from heurams.context import config_var from heurams.kernel.reactor import * from heurams.services.logger import get_logger diff --git a/src/heurams/interface/shim.py b/src/heurams/interface/shim.py index a8165c8..6dbe361 100644 --- a/src/heurams/interface/shim.py +++ b/src/heurams/interface/shim.py @@ -5,7 +5,7 @@ from typing import TypedDict import heurams.interface.widgets as pzw import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz +import heurams.kernel.evaluators as pz staging = {} # 细粒度缓存区, 是 ident -> quality 的封装 diff --git a/src/heurams/interface/widgets/cloze_puzzle.py b/src/heurams/interface/widgets/cloze_puzzle.py index 9d8c001..5278969 100644 --- a/src/heurams/interface/widgets/cloze_puzzle.py +++ b/src/heurams/interface/widgets/cloze_puzzle.py @@ -8,7 +8,7 @@ from textual.widget import Widget from textual.widgets import Button, Label import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz +import heurams.kernel.evaluators as pz from heurams.services.logger import get_logger from .base_puzzle_widget import BasePuzzleWidget diff --git a/src/heurams/interface/widgets/mcq_puzzle.py b/src/heurams/interface/widgets/mcq_puzzle.py index e686b49..56820b6 100644 --- a/src/heurams/interface/widgets/mcq_puzzle.py +++ b/src/heurams/interface/widgets/mcq_puzzle.py @@ -6,7 +6,7 @@ from textual.widget import Widget from textual.widgets import Button, Label import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz +import heurams.kernel.evaluators as pz from heurams.services.hasher import hash from heurams.services.logger import get_logger diff --git a/src/heurams/kernel/algorithms/__init__.py b/src/heurams/kernel/algorithms/__init__.py index a6ebbeb..c1e6fa8 100644 --- a/src/heurams/kernel/algorithms/__init__.py +++ b/src/heurams/kernel/algorithms/__init__.py @@ -2,17 +2,20 @@ from heurams.services.logger import get_logger from .sm2 import SM2Algorithm from .sm15m import SM15MAlgorithm +from .base import BaseAlgorithm logger = get_logger(__name__) __all__ = [ "SM2Algorithm", + "BaseAlgorithm", + "SM15MAlgorithm", ] algorithms = { "SM-2": SM2Algorithm, "SM-15M": SM15MAlgorithm, - # "SM-15M": SM15MAlgorithm, + "Base": BaseAlgorithm, } logger.debug("算法模块初始化完成, 注册的算法: %s", list(algorithms.keys())) diff --git a/src/heurams/kernel/algorithms/base.py b/src/heurams/kernel/algorithms/base.py index b671c5b..3c0dbfb 100644 --- a/src/heurams/kernel/algorithms/base.py +++ b/src/heurams/kernel/algorithms/base.py @@ -10,7 +10,6 @@ class BaseAlgorithm: algo_name = "BaseAlgorithm" class AlgodataDict(TypedDict): - efactor: float real_rept: int rept: int interval: int @@ -52,7 +51,7 @@ class BaseAlgorithm: return 1 @classmethod - def rate(cls, algodata) -> str: + def get_rating(cls, algodata) -> str: """获取评分信息""" logger.debug( "BaseAlgorithm.rate 被调用, algodata keys: %s", @@ -68,3 +67,12 @@ class BaseAlgorithm: list(algodata.keys()) if algodata else [], ) return -1 + + @classmethod + def check_integrity(cls, algodata): + try: + cls.AlgodataDict(**algodata[cls.algo_name]) + return 1 + except: + return 0 + \ No newline at end of file diff --git a/src/heurams/kernel/algorithms/sm2.py b/src/heurams/kernel/algorithms/sm2.py index 6696784..0d848aa 100644 --- a/src/heurams/kernel/algorithms/sm2.py +++ b/src/heurams/kernel/algorithms/sm2.py @@ -116,7 +116,7 @@ class SM2Algorithm(BaseAlgorithm): return result @classmethod - def rate(cls, algodata): + def get_rating(cls, algodata): efactor = algodata[cls.algo_name]["efactor"] logger.debug("SM2.rate: efactor=%f", efactor) return str(efactor) diff --git a/src/heurams/kernel/puzzles/__init__.py b/src/heurams/kernel/evaluators/__init__.py similarity index 82% rename from src/heurams/kernel/puzzles/__init__.py rename to src/heurams/kernel/evaluators/__init__.py index 5300648..8dd3a86 100644 --- a/src/heurams/kernel/puzzles/__init__.py +++ b/src/heurams/kernel/evaluators/__init__.py @@ -1,20 +1,20 @@ """ -Puzzle 模块 - 谜题生成系统 +Evaluator 模块 - 生成评估模块 -提供多种类型的谜题生成器, 支持从字符串、字典等数据源导入题目 +提供多种类型的辅助评估生成器, 支持从字符串、字典等数据源导入题目 """ from heurams.services.logger import get_logger logger = get_logger(__name__) -from .base import BasePuzzle +from .base import BaseEvaluator from .cloze import ClozePuzzle from .mcq import MCQPuzzle from .recognition import RecognitionPuzzle __all__ = [ - "BasePuzzle", + "BaseEvaluator", "ClozePuzzle", "MCQPuzzle", "RecognitionPuzzle", @@ -24,12 +24,12 @@ puzzles = { "mcq": MCQPuzzle, "cloze": ClozePuzzle, "recognition": RecognitionPuzzle, - "base": BasePuzzle, + "base": BaseEvaluator, } @staticmethod -def create_by_dict(config_dict: dict) -> BasePuzzle: +def create_by_dict(config_dict: dict) -> BaseEvaluator: """ 根据配置字典创建谜题 diff --git a/src/heurams/kernel/puzzles/base.py b/src/heurams/kernel/evaluators/base.py similarity index 95% rename from src/heurams/kernel/puzzles/base.py rename to src/heurams/kernel/evaluators/base.py index 688d7c8..cbae148 100644 --- a/src/heurams/kernel/puzzles/base.py +++ b/src/heurams/kernel/evaluators/base.py @@ -4,7 +4,7 @@ from heurams.services.logger import get_logger logger = get_logger(__name__) -class BasePuzzle: +class BaseEvaluator: """谜题基类""" def refresh(self): diff --git a/src/heurams/kernel/puzzles/cloze.py b/src/heurams/kernel/evaluators/cloze.py similarity index 97% rename from src/heurams/kernel/puzzles/cloze.py rename to src/heurams/kernel/evaluators/cloze.py index 3522aaa..549a91f 100644 --- a/src/heurams/kernel/puzzles/cloze.py +++ b/src/heurams/kernel/evaluators/cloze.py @@ -2,12 +2,12 @@ import random from heurams.services.logger import get_logger -from .base import BasePuzzle +from .base import BaseEvaluator logger = get_logger(__name__) -class ClozePuzzle(BasePuzzle): +class ClozePuzzle(BaseEvaluator): """填空题谜题生成器 Args: diff --git a/src/heurams/kernel/evaluators/guess.py b/src/heurams/kernel/evaluators/guess.py new file mode 100644 index 0000000..6b30b3e --- /dev/null +++ b/src/heurams/kernel/evaluators/guess.py @@ -0,0 +1,11 @@ +import random + +from heurams.services.logger import get_logger + +from .base import BaseEvaluator + +logger = get_logger(__name__) + +class GuessEvaluator(BaseEvaluator): + def __init__(self): + super().__init__() \ No newline at end of file diff --git a/src/heurams/kernel/puzzles/mcq.py b/src/heurams/kernel/evaluators/mcq.py similarity index 99% rename from src/heurams/kernel/puzzles/mcq.py rename to src/heurams/kernel/evaluators/mcq.py index 1246a19..e17db67 100644 --- a/src/heurams/kernel/puzzles/mcq.py +++ b/src/heurams/kernel/evaluators/mcq.py @@ -4,12 +4,12 @@ from typing import Dict, List, Optional, Union from heurams.services.logger import get_logger -from .base import BasePuzzle +from .base import BaseEvaluator logger = get_logger(__name__) -class MCQPuzzle(BasePuzzle): +class MCQPuzzle(BaseEvaluator): """选择题谜题生成器 该类用于生成和管理选择题谜题, 支持多个题目同时生成, diff --git a/src/heurams/kernel/puzzles/recognition.py b/src/heurams/kernel/evaluators/recognition.py similarity index 82% rename from src/heurams/kernel/puzzles/recognition.py rename to src/heurams/kernel/evaluators/recognition.py index 964db3f..81712b0 100644 --- a/src/heurams/kernel/puzzles/recognition.py +++ b/src/heurams/kernel/evaluators/recognition.py @@ -3,12 +3,12 @@ import random from heurams.services.logger import get_logger -from .base import BasePuzzle +from .base import BaseEvaluator logger = get_logger(__name__) -class RecognitionPuzzle(BasePuzzle): +class RecognitionPuzzle(BaseEvaluator): """识别占位符""" def __init__(self) -> None: diff --git a/src/heurams/kernel/particles/__init__.py b/src/heurams/kernel/particles/__init__.py index 331bb16..e69de29 100644 --- a/src/heurams/kernel/particles/__init__.py +++ b/src/heurams/kernel/particles/__init__.py @@ -1,29 +0,0 @@ -""" -Particle 模块 - 粒子对象系统 - -提供闪卡所需对象, 使用物理学粒子的领域驱动设计 -""" - -from heurams.services.logger import get_logger - -logger = get_logger(__name__) -logger.debug("粒子模块已加载") - -from .atom import Atom, atom_registry -from .electron import Electron -from .loader import load_electron, load_nucleon -from .nucleon import Nucleon -from .orbital import Orbital -from .probe import probe_all, probe_by_filename - -__all__ = [ - "Electron", - "Nucleon", - "Orbital", - "Atom", - "probe_all", - "probe_by_filename", - "load_nucleon", - "load_electron", - "atom_registry", -] diff --git a/src/heurams/kernel/particles/atom.py b/src/heurams/kernel/particles/atom.py index dfb172c..68ce358 100644 --- a/src/heurams/kernel/particles/atom.py +++ b/src/heurams/kernel/particles/atom.py @@ -11,7 +11,6 @@ from heurams.services.logger import get_logger from .electron import Electron from .nucleon import Nucleon -from .orbital import Orbital logger = get_logger(__name__) @@ -19,19 +18,12 @@ logger = get_logger(__name__) class AtomRegister_runtime(TypedDict): locked: bool # 只读锁定标识符 min_rate: int # 最低评分 - newact: bool # 新激活 + new_activation: bool # 新激活 class AtomRegister(TypedDict): nucleon: Nucleon - nucleon_path: pathlib.Path - nucleon_fmt: str electron: Electron - electron_path: pathlib.Path - electron_fmt: str - orbital: Orbital - orbital_path: pathlib.Path - orbital_fmt: str runtime: AtomRegister_runtime @@ -44,50 +36,37 @@ class Atom: 以及关联路径 """ - def __init__(self, ident=""): - logger.debug("创建 Atom 实例, ident: '%s'", ident) - self.ident = ident - atom_registry[ident] = self - logger.debug("Atom 已注册到全局注册表, 当前注册表大小: %d", len(atom_registry)) - # self.is_evaled = False + default_runtime = { + "locked": False, + "min_rate": 0x3F3F3F3F, + "new_activation": False, + } + + def __init__(self, nucleon_obj = None, electron_obj = None, orbital_obj = None): self.registry: AtomRegister = { # type: ignore - "nucleon": None, - "nucleon_path": None, - "nucleon_fmt": "toml", - "electron": None, - "electron_path": None, - "electron_fmt": "json", - "orbital": None, - "orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置 - "orbital_fmt": "toml", - "runtime": {"locked": False, "min_rate": 0x3F3F3F3F, "newact": False}, + "ident": nucleon_obj["ident"], # type: ignore + "nucleon": nucleon_obj, + "electron": electron_obj, + "orbital": orbital_obj, + "runtime": dict(), } - logger.debug("Atom 初始化完成") - - def link(self, key, value): - logger.debug("Atom.link: key='%s', value type: %s", key, type(value).__name__) - if key in self.registry.keys(): - self.registry[key] = value - logger.debug("键 '%s' 已链接, 触发 do_eval", key) - if key == "electron": - if self.registry["electron"].is_activated() == 0: - self.registry["runtime"]["newact"] = True - else: - logger.error("尝试链接不受支持的键: '%s'", key) - raise ValueError("不受支持的原子元数据链接操作") + if self.registry["electron"].is_activated() == 0: + self.registry["runtime"]["new_activation"] = True + def init_runtime(self): + self.registry['runtime'] = AtomRegister_runtime(**self.default_runtime) + def do_eval(self): """ 执行并以结果替换当前单元的所有 eval 语句 TODO: 带有限制的 eval, 异步/多线程执行避免堵塞 """ - logger.debug("EVAL 开始") - # eval 环境设置 def eval_with_env(s: str): default = config_var.get()["puzzles"] - payload = self.registry["nucleon"].payload - metadata = self.registry["nucleon"].metadata + nucleon = self.registry["nucleon"] + payload = nucleon # 兼容历史遗留问题 + metadata = nucleon # 兼容历史遗留问题 eval_value = eval(s) if isinstance(eval_value, (int, float)): ret = str(eval_value) @@ -158,39 +137,11 @@ class Atom: logger.debug(f"允许总评分: {self.registry['runtime']['min_rate']}") self.registry["electron"].revisor( self.registry["runtime"]["min_rate"], - is_new_activation=self.registry["runtime"]["newact"], + is_new_activation=self.registry["runtime"]["new_activation"], ) else: logger.debug("禁止总评分") - def persist(self, key): - logger.debug("Atom.persist: key='%s'", key) - path: pathlib.Path | None = self.registry[key + "_path"] - if isinstance(path, pathlib.Path): - path = typing.cast(pathlib.Path, path) - logger.debug("持久化路径: %s, 格式: %s", path, self.registry[key + "_fmt"]) - path.parent.mkdir(parents=True, exist_ok=True) - if self.registry[key + "_fmt"] == "toml": - with open(path, "r+") as f: - f.seek(0) - f.truncate() - toml.dump(self.registry[key], f) - logger.debug("TOML 数据已保存到: %s", path) - elif self.registry[key + "_fmt"] == "json": - with open(path, "r+") as f: - origin = json.load(f) - f.seek(0) - f.truncate() - origin[self.ident] = self.registry[key].algodata - json.dump(origin, f, indent=2, ensure_ascii=False) - logger.debug("JSON 数据已保存到: %s", path) - else: - logger.error("不受支持的持久化格式: %s", self.registry[key + "_fmt"]) - raise KeyError("不受支持的持久化格式") - else: - logger.error("路径未初始化: %s_path", key) - raise TypeError("对未初始化的路径对象操作") - def __getitem__(self, key): logger.debug("Atom.__getitem__: key='%s'", key) if key in self.registry: @@ -211,9 +162,3 @@ class Atom: logger.error("不支持的键: '%s'", key) raise KeyError(f"不支持的键: {key}") - @staticmethod - def placeholder(): - return (Electron.placeholder(), Nucleon.placeholder(), {}) - - -atom_registry: bidict.bidict[str, Atom] = bidict.bidict() diff --git a/src/heurams/kernel/particles/electron.py b/src/heurams/kernel/particles/electron.py index cc5cdd6..b6de929 100644 --- a/src/heurams/kernel/particles/electron.py +++ b/src/heurams/kernel/particles/electron.py @@ -1,100 +1,71 @@ +from typing import TypedDict import heurams.services.timer as timer from heurams.context import config_var from heurams.kernel.algorithms import algorithms from heurams.services.logger import get_logger - +import heurams.kernel.algorithms as algolib +from copy import deepcopy logger = get_logger(__name__) +class QueryType(TypedDict): + is_due: bool + is_activated: bool + rating: int + nextdate: int + lastdate: int class Electron: - """电子: 记忆分析元数据及算法""" + """电子: 单算法支持的记忆数据包装""" def __init__(self, ident: str, algodata: dict = {}, algo_name: str = ""): """初始化电子对象 (记忆数据) Args: ident: 算法的唯一标识符, 用于区分不同的算法实例, 使用 algodata[ident] 获取 - algodata: 算法数据字典, 包含算法的各项参数和设置 - algo: 使用的算法模块标识 + algodata: 算法数据字典引用, 包含算法的各项参数和设置 + algo_name: 使用的算法模块标识 """ if algo_name == "": - algo_name = config_var.get()["algorithm"]["default"] - logger.debug( - "创建 Electron 实例, ident: '%s', algo_name: '%s', algodata: %s", - ident, - algo_name, - algodata, - ) + algo_name = "sm-2" self.algodata = algodata self.ident = ident - self.algo = algorithms[algo_name] - logger.debug("使用的算法类: %s", self.algo.__name__) + self.algo: algolib.BaseAlgorithm = algorithms[algo_name] + self.query = dict() - if self.algo.algo_name not in self.algodata.keys(): - self.algodata[self.algo.algo_name] = {} - logger.debug("算法键 '%s' 不存在, 已创建空字典", self.algo) - if not self.algodata[self.algo.algo_name]: - logger.debug( - f"算法数据为空, 使用默认值初始化{self.algodata[self.algo.algo_name]}" - ) - self._default_init(self.algo.defaults) - else: - logger.debug("算法数据已存在, 跳过默认初始化") - logger.debug( - "Electron 初始化完成, algodata keys: %s", list(self.algodata.keys()) - ) - - def _default_init(self, defaults: dict): - """默认初始化包装""" - logger.debug( - "Electron._default_init: 使用默认值, keys: %s", list(defaults.keys()) - ) - self.algodata[self.algo.algo_name] = defaults.copy() + if self.algo.check_integrity(self.algodata): + self.algodata[self.algo.algo_name] = deepcopy(self.algo.defaults) def activate(self): """激活此电子""" - logger.debug("Electron.activate: 激活 ident='%s'", self.ident) self.algodata[self.algo.algo_name]["is_activated"] = 1 self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp() - logger.debug("电子已激活, is_activated=1") - def modify(self, var: str, value): + def modify(self, key, value): """修改 algodata[algo] 中子字典数据""" - logger.debug("Electron.modify: var='%s', value=%s", var, value) - if var in self.algodata[self.algo.algo_name]: - self.algodata[self.algo.algo_name][var] = value + if key in self.algodata[self.algo.algo_name]: + self.algodata[self.algo.algo_name][key] = value self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp() - logger.debug("变量 '%s' 已修改, 更新 last_modify", var) else: - logger.warning("'%s' 非已知元数据字段", var) - print(f"警告: '{var}' 非已知元数据字段") + raise AttributeError("不存在的子键") def is_due(self): """是否应该复习""" - logger.debug("Electron.is_due: 检查 ident='%s'", self.ident) result = self.algo.is_due(self.algodata) - logger.debug("is_due 结果: %s", result) return result and self.is_activated() def is_activated(self): result = self.algodata[self.algo.algo_name]["is_activated"] - logger.debug("Electron.is_activated: ident='%s', 结果: %d", self.ident, result) return result - def get_rate(self): - "评价" + def get_rating(self): try: - logger.debug("Electron.rate: ident='%s'", self.ident) - result = self.algo.rate(self.algodata) - logger.debug("rate 结果: %s", result) + result = self.algo.get_rating(self.algodata) return result except: return 0 def nextdate(self) -> int: - logger.debug("Electron.nextdate: ident='%s'", self.ident) result = self.algo.nextdate(self.algodata) - logger.debug("nextdate 结果: %d", result) return result def revisor(self, quality: int = 5, is_new_activation: bool = False): @@ -104,32 +75,7 @@ class Electron: quality (int): 记忆保留率量化参数 (0-5) is_new_activation (bool): 是否为初次激活 """ - logger.debug( - "Electron.revisor: ident='%s', quality=%d, is_new_activation=%s", - self.ident, - quality, - is_new_activation, - ) self.algo.revisor(self.algodata, quality, is_new_activation) - logger.debug( - "revisor 完成, 更新后的 algodata: %s", self.algodata.get(self.algo, {}) - ) - - def __str__(self): - return ( - f"记忆单元预览 \n" - f"标识符: '{self.ident}' \n" - f"算法: {self.algo} \n" - f"易度系数: {self.algodata[self.algo.algo_name]['efactor']:.2f} \n" - f"已经重复的次数: {self.algodata[self.algo.algo_name]['rept']} \n" - f"下次间隔: {self.algodata[self.algo.algo_name]['interval']} 天 \n" - f"下次复习日期时间戳: {self.algodata[self.algo.algo_name]['next_date']}" - ) - - def __eq__(self, other): - if self.ident == other.ident: - return True - return False def __hash__(self): return hash(self.ident) @@ -151,8 +97,11 @@ class Electron: def __len__(self): """仅返回当前算法的配置数量""" return len(self.algodata[self.algo.algo_name]) - + @staticmethod - def placeholder(): - """生成一个电子占位符""" - return Electron("电子对象样例内容", {}) + def create_on_electonic_data(electronic_data: tuple, algo_name: str = ""): + _data = electronic_data + ident = _data[0] + algodata = _data[1] + ident = ident + return Electron(ident, algodata, algo_name) \ No newline at end of file diff --git a/src/heurams/kernel/particles/loader.py b/src/heurams/kernel/particles/loader.py deleted file mode 100644 index 825e7db..0000000 --- a/src/heurams/kernel/particles/loader.py +++ /dev/null @@ -1,74 +0,0 @@ -import json -import pathlib -from copy import deepcopy - -import toml - -import heurams.services.hasher as hasher -from heurams.services.logger import get_logger - -from .electron import Electron -from .nucleon import Nucleon - -logger = get_logger(__name__) - - -def load_nucleon(path: pathlib.Path, fmt="toml"): - logger.debug("load_nucleon: 加载文件 %s, 格式: %s", path, fmt) - with open(path, "r") as f: - dictdata = dict() - dictdata = toml.load(f) # type: ignore - logger.debug("TOML 解析成功, keys: %s", list(dictdata.keys())) - lst = list() - nested_data = dict() - # 修正 toml 解析器的不管嵌套行为 - for key, value in dictdata.items(): - if "__metadata__" in key: # 以免影响句号 - if "." in key: - parts = key.split(".") - current = nested_data - for part in parts[:-1]: - if part not in current: - current[part] = {} - current = current[part] - current[parts[-1]] = value - logger.debug("处理元数据键: %s", key) - else: - nested_data[key] = value - logger.debug("嵌套数据处理完成, keys: %s", list(nested_data.keys())) - # print(nested_data) - for item, attr in nested_data.items(): - if item == "__metadata__": - continue - logger.debug("处理项目: %s", item) - lst.append( - ( - Nucleon(item, attr, deepcopy(nested_data["__metadata__"])), - deepcopy(nested_data["__metadata__"]["orbital"]), - ) - ) - logger.debug("load_nucleon 完成, 加载了 %d 个 Nucleon 对象", len(lst)) - return lst - - -def load_electron(path: pathlib.Path, fmt="json") -> dict: - """从文件路径加载电子对象 - - Args: - path (pathlib.Path): 路径 - fmt (str): 文件格式(可选, 默认 json) - - Returns: - dict: 键名是电子对象名称, 值是电子对象 - """ - logger.debug("load_electron: 加载文件 %s, 格式: %s", path, fmt) - with open(path, "r") as f: - dictdata = dict() - dictdata = json.load(f) # type: ignore - logger.debug("JSON 解析成功, keys: %s", list(dictdata.keys())) - dic = dict() - for item, attr in dictdata.items(): - logger.debug("处理电子项目: %s, %s", item, attr) - dic[item] = Electron(item, attr) - logger.debug("load_electron 完成, 加载了 %d 个 Electron 对象", len(dic)) - return dic diff --git a/src/heurams/kernel/particles/nucleon.py b/src/heurams/kernel/particles/nucleon.py index 175661b..463020e 100644 --- a/src/heurams/kernel/particles/nucleon.py +++ b/src/heurams/kernel/particles/nucleon.py @@ -2,55 +2,55 @@ from heurams.services.logger import get_logger logger = get_logger(__name__) - class Nucleon: - """原子核: 材料元数据""" + """原子核: 带有运行时隔离的半只读材料元数据容器 + """ - def __init__(self, ident: str, payload: dict, metadata: dict = {}): - """初始化原子核 (记忆内容) - - Args: - ident: 唯一标识符 - payload: 记忆内容信息 - metadata: 可选元数据信息 - """ - logger.debug( - "创建 Nucleon 实例, ident: '%s', payload keys: %s, metadata keys: %s", - ident, - list(payload.keys()) if payload else [], - list(metadata.keys()) if metadata else [], - ) - self.metadata = metadata - self.payload = payload + def __init__(self, ident, payload, common): self.ident = ident - logger.debug("Nucleon 初始化完成") + self.payload = payload + self.common = common + self.rtlayer = dict() # 运行时层 def __getitem__(self, key): - logger.debug("Nucleon.__getitem__: key='%s'", key) if key == "ident": - logger.debug("返回 ident: '%s'", self.ident) return self.ident - if key in self.payload: - value = self.payload[key] - logger.debug( - "返回 payload['%s'], value type: %s", key, type(value).__name__ - ) - return value + merged = self.rtlayer | self.payload | self.common + return merged[key] + + def __setitem__(self, key, value): + if key == "ident": + raise AttributeError("ident 应为只读") else: - logger.error("键 '%s' 未在 payload 中找到", key) - raise KeyError(f"Key '{key}' not found in payload.") + self.rtlayer[key] = value + + def __delitem__(self, key): + raise AttributeError("Nucleon 包含的数据被设计为无法删除") def __iter__(self): - yield from self.payload.keys() + merged = self.rtlayer | self.payload | self.common + return iter(merged) + def __contains__(self, key): + return key in (self.rtlayer | self.payload | self.common) + + def get(self, key, default=None): + if key in self: + return self[key] + return default + def __len__(self): - return len(self.payload) + return len(self.rtlayer | self.payload | self.common) - def __hash__(self): - return hash(self.ident) + def __repr__(self): + return f"""RUNTIME:{repr(self.rtlayer)} + PAYLOAD:{repr(self.payload)} + COMMON:{repr(self.common)}""" @staticmethod - def placeholder(): - """生成一个占位原子核""" - logger.debug("创建 Nucleon 占位符") - return Nucleon("核子对象样例内容", {}) + def create_on_nucleonic_data(nucleonic_data: tuple): + _data = nucleonic_data + payload = _data[1][0] + common = _data[1][1] + ident = _data[0] #TODO:实现eval + return Nucleon(ident, payload, common) \ No newline at end of file diff --git a/src/heurams/kernel/particles/orbital.py b/src/heurams/kernel/particles/orbital.py deleted file mode 100644 index 58d996f..0000000 --- a/src/heurams/kernel/particles/orbital.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import TypedDict - -from heurams.services.logger import get_logger - -logger = get_logger(__name__) -logger.debug("Orbital 类型定义模块已加载") - - -class OrbitalSchedule(TypedDict): - quick_review: list - recognition: list - final_review: list - - -class Orbital(TypedDict): - schedule: OrbitalSchedule - puzzles: dict - - -"""一份示例 -["__metadata__.orbital.puzzles"] # 谜题定义 -"Recognition" = { __origin__ = "recognition", __hint__ = "", primary = "eval:nucleon['content']", secondery = ["eval:nucleon['keyword_note']", "eval:nucleon['note']"], top_dim = ["eval:nucleon['translation']"] } -"SelectMeaning" = { __origin__ = "mcq", __hint__ = "eval:nucleon['content']", jammer = "eval:nucleon['keyword_note']", max_riddles_num = "eval:default['mcq']['max_riddles_num']", prefix = "选择正确项: " } -"FillBlank" = { __origin__ = "cloze", __hint__ = "", text = "eval:nucleon['content']", delimiter = "eval:metadata['formation']['delimiter']", min_denominator = "eval:default['cloze']['min_denominator']"} - -["__metadata__.orbital.schedule"] # 内置的推荐学习方案 -quick_review = [["FillBlank", "1.0"], ["SelectMeaning", "0.5"], ["recognition", "1.0"]] -recognition = [["recognition", "1.0"]] -final_review = [["FillBlank", "0.7"], ["SelectMeaning", "0.7"], ["recognition", "1.0"]] -""" diff --git a/src/heurams/kernel/particles/probe.py b/src/heurams/kernel/particles/probe.py deleted file mode 100644 index 5eb18ef..0000000 --- a/src/heurams/kernel/particles/probe.py +++ /dev/null @@ -1,62 +0,0 @@ -import pathlib - -from heurams.context import config_var -from heurams.services.logger import get_logger - -logger = get_logger(__name__) - - -def probe_by_filename(filename): - """探测指定文件 (无扩展名) 的所有信息""" - logger.debug("probe_by_filename: 探测文件 '%s'", filename) - paths: dict = config_var.get().get("paths") - logger.debug("配置路径: %s", paths) - formats = ["toml", "json"] - result = {} - for item, attr in paths.items(): - for i in formats: - attr: pathlib.Path = pathlib.Path(attr) / filename + "." + i - if attr.exists(): - logger.debug("找到文件: %s", attr) - result[item.replace("_dir", "")] = str(attr) - else: - logger.debug("文件不存在: %s", attr) - logger.debug("probe_by_filename 结果: %s", result) - return result - - -def probe_all(is_stem=1): - """依据目录探测所有信息 - - Args: - is_stem (boolean): 是否**删除**文件扩展名 - - Returns: - dict: 有三项, 每一项的键名都是文件组类型, 值都是文件组列表, 只包含文件名 - """ - logger.debug("probe_all: 开始探测, is_stem=%d", is_stem) - paths: dict = config_var.get().get("paths") - logger.debug("配置路径: %s", paths) - result = {} - for item, attr in paths.items(): - attr: pathlib.Path = pathlib.Path(attr) - result[item.replace("_dir", "")] = list() - logger.debug("扫描目录: %s", attr) - file_count = 0 - for i in attr.iterdir(): - if not i.is_dir(): - file_count += 1 - if is_stem: - result[item.replace("_dir", "")].append(str(i.stem)) - else: - result[item.replace("_dir", "")].append(str(i.name)) - logger.debug("目录 %s 中找到 %d 个文件", attr, file_count) - logger.debug("probe_all 完成, 结果 keys: %s", list(result.keys())) - return result - - -if __name__ == "__main__": - import os - - print(os.getcwd()) - print(probe_all()) diff --git a/src/heurams/kernel/reactor/fission.py b/src/heurams/kernel/reactor/fission.py index 6de3576..e57b791 100644 --- a/src/heurams/kernel/reactor/fission.py +++ b/src/heurams/kernel/reactor/fission.py @@ -1,7 +1,7 @@ import random import heurams.kernel.particles as pt -import heurams.kernel.puzzles as puz +import heurams.kernel.evaluators as puz from heurams.services.logger import get_logger from .states import PhaserState diff --git a/src/heurams/kernel/repomgr/aux.py b/src/heurams/kernel/repomgr/aux.py new file mode 100644 index 0000000..3d0b41f --- /dev/null +++ b/src/heurams/kernel/repomgr/aux.py @@ -0,0 +1,5 @@ +from ...utils.lict import Lict + +def merge(x: Lict, y: Lict): + return Lict(list(x.values()) + list(y.values())) + diff --git a/src/heurams/kernel/repomgr/repo.py b/src/heurams/kernel/repomgr/repo.py index b48d6e3..5750db5 100644 --- a/src/heurams/kernel/repomgr/repo.py +++ b/src/heurams/kernel/repomgr/repo.py @@ -1,44 +1,56 @@ +from functools import reduce from pathlib import Path import heurams.kernel.particles as pt import toml import json -from .lict import Lict +from ...utils.lict import Lict from .refvar import RefVar class Repo(): file_mapping = { - "orbital": "orbital.toml", + "schedule": "schedule.toml", "payload": "payload.toml", "algodata": "algodata.json", "manifest": "manifest.toml", - "formation": "formation.toml", + "typedef": "typedef.toml", } type_mapping = { - "orbital": "dict", + "schedule": "dict", "payload": "lict", "algodata": "lict", "manifest": "dict", - "formation": "dict", + "typedef": "dict", } default_save_list = ["algodata"] - def __init__(self, orbital, payload, manifest, formation, algodata, source = None) -> None: - self.orbital: pt.Orbital = orbital - self.payload: Lict = payload + def __init__(self, schedule: dict, payload: Lict, manifest: dict, typedef: dict, algodata: Lict, source = None) -> None: + self.schedule: dict = schedule self.manifest: dict = manifest - self.formation: dict = formation + self.typedef: dict = typedef + self.payload: Lict = payload self.algodata: Lict = algodata self.source: Path | None = source # 若存在, 指向 repo 所在 dir self.database = { - "orbital": self.orbital, + "schedule": self.schedule, "payload": self.payload, "manifest": self.manifest, - "formation": self.formation, + "typedef": self.typedef, "algodata": self.algodata, "source": self.source, } + self.generate_particles_data() + + def generate_particles_data(self): + self.nucleonic_data_lict = Lict(list(map(self._attach(self.typedef), self.payload))) + self.electronic_data_lict = self.algodata + + @staticmethod + def _attach(value): + def inner(x): + return (x, value) + return inner def __len__(self): return len(self.payload) @@ -70,11 +82,11 @@ class Repo(): @classmethod def create_new_repo(cls, source = None): default_database = { - "orbital": {"puzzles": {}, "schedule": {}}, - "payload": [], - "algodata": [], + "schedule": {}, + "payload": Lict([]), + "algodata": Lict([]), "manifest": {}, - "formation": {"annotation": {}, "unified": {}}, + "typedef": {}, "source": source } return Repo(**default_database) diff --git a/src/heurams/services/version.py b/src/heurams/services/version.py index 0239b75..4f31e59 100644 --- a/src/heurams/services/version.py +++ b/src/heurams/services/version.py @@ -3,8 +3,8 @@ from heurams.services.logger import get_logger logger = get_logger(__name__) -ver = "0.4.3" +ver = "0.5.0" stage = "prototype" -codename = "fledge" # 雏鸟, 0.4.x 版本 +codename = "fulcrom" # 支点 logger.info("HeurAMS 版本: %s (%s), 阶段: %s", ver, codename, stage) diff --git a/src/heurams/utils/README.md b/src/heurams/utils/README.md deleted file mode 100644 index ec435c4..0000000 --- a/src/heurams/utils/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Utils - 实用工具 -脚本与部分分离式工具函数 \ No newline at end of file diff --git a/src/heurams/utils/__init__.py b/src/heurams/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/heurams/utils/evalizor.py b/src/heurams/utils/evalizor.py new file mode 100644 index 0000000..65176b5 --- /dev/null +++ b/src/heurams/utils/evalizor.py @@ -0,0 +1,28 @@ + +from typing import Any + + +class Evalizer(): + def __init__(self, environment: dict) -> None: + self.env = environment + + def __call__(self, *args: Any, **kwds: Any) -> Any: + + +def do_eval(self): + """ + 执行并以结果替换当前单元的所有 eval 语句 + TODO: 带有限制的 eval, 异步/多线程执行避免堵塞 + """ + + # eval 环境设置 + def eval_with_env(s: str): + default = config_var.get()["puzzles"] + payload = self.registry["nucleon"].payload + metadata = self.registry["nucleon"].metadata + eval_value = eval(s) + if isinstance(eval_value, (int, float)): + ret = str(eval_value) + else: + ret = eval_value + return ret \ No newline at end of file diff --git a/src/heurams/kernel/repomgr/lict.py b/src/heurams/utils/lict.py similarity index 100% rename from src/heurams/kernel/repomgr/lict.py rename to src/heurams/utils/lict.py diff --git a/tests/kernel/algorithms/test_sm2.py b/tests/kernel/algorithms/test_sm2.py index 9075715..ecc1a24 100644 --- a/tests/kernel/algorithms/test_sm2.py +++ b/tests/kernel/algorithms/test_sm2.py @@ -174,7 +174,7 @@ class TestSM2Algorithm(unittest.TestCase): def test_rate(self): """测试 rate 方法""" algodata = {SM2Algorithm.algo_name: {"efactor": 2.7}} - self.assertEqual(SM2Algorithm.rate(algodata), "2.7") + self.assertEqual(SM2Algorithm.get_rating(algodata), "2.7") def test_nextdate(self): """测试 nextdate 方法""" diff --git a/tests/kernel/particles/test_electron.py b/tests/kernel/particles/test_electron.py index 75c4552..7fe7e4e 100644 --- a/tests/kernel/particles/test_electron.py +++ b/tests/kernel/particles/test_electron.py @@ -98,7 +98,7 @@ class TestElectron(unittest.TestCase): electron = Electron("test_electron") with patch.object(electron.algo, "rate") as mock_rate: mock_rate.return_value = "good" - result = electron.get_rate() + result = electron.get_rating() mock_rate.assert_called_once_with(electron.algodata) self.assertEqual(result, "good") diff --git a/tests/kernel/puzzles/test_base.py b/tests/kernel/puzzles/test_base.py index 28b70f0..c5e4387 100644 --- a/tests/kernel/puzzles/test_base.py +++ b/tests/kernel/puzzles/test_base.py @@ -1,7 +1,7 @@ import unittest from unittest.mock import Mock -from heurams.kernel.puzzles.base import BasePuzzle +from heurams.kernel.evaluators.base import BasePuzzle class TestBasePuzzle(unittest.TestCase): diff --git a/tests/kernel/puzzles/test_cloze.py b/tests/kernel/puzzles/test_cloze.py index 4a51b5b..86696ee 100644 --- a/tests/kernel/puzzles/test_cloze.py +++ b/tests/kernel/puzzles/test_cloze.py @@ -1,7 +1,7 @@ import unittest from unittest.mock import MagicMock, patch -from heurams.kernel.puzzles.cloze import ClozePuzzle +from heurams.kernel.evaluators.cloze import ClozePuzzle class TestClozePuzzle(unittest.TestCase): diff --git a/tests/kernel/puzzles/test_mcq.py b/tests/kernel/puzzles/test_mcq.py index 61dc1a9..b64b329 100644 --- a/tests/kernel/puzzles/test_mcq.py +++ b/tests/kernel/puzzles/test_mcq.py @@ -1,7 +1,7 @@ import unittest from unittest.mock import MagicMock, call, patch -from heurams.kernel.puzzles.mcq import MCQPuzzle +from heurams.kernel.evaluators.mcq import MCQPuzzle class TestMCQPuzzle(unittest.TestCase):