feat(kernel): 状态机改进
This commit is contained in:
56
examples/data/config/config.toml
Normal file
56
examples/data/config/config.toml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# [调试] 将更改保存到文件
|
||||||
|
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] # 相对于配置文件的 ".." (即工作目录) 而言 或绝对路径
|
||||||
|
data = "./data"
|
||||||
|
|
||||||
|
[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]
|
||||||
14
examples/jiebatest.py
Normal file
14
examples/jiebatest.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# encoding=utf-8
|
||||||
|
import jieba
|
||||||
|
|
||||||
|
#jieba.enable_paddle()# 启动paddle模式。 0.40版之后开始支持,早期版本不支持
|
||||||
|
strs=["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]
|
||||||
|
#for str in strs:
|
||||||
|
# seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
|
||||||
|
# print("Paddle Mode: " + '/'.join(list(seg_list)))
|
||||||
|
|
||||||
|
seg_list = jieba.cut("秦孝公据崤函之固, 拥雍州之地", cut_all=False)
|
||||||
|
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
|
||||||
|
|
||||||
|
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
|
||||||
|
print(", ".join(seg_list))
|
||||||
@@ -5,8 +5,9 @@ repo = repolib.Repo.create_from_repodir(Path('./test_repo'))
|
|||||||
for i in repo.ident_index:
|
for i in repo.ident_index:
|
||||||
n = pt.Nucleon.create_on_nucleonic_data(nucleonic_data=repo.nucleonic_data_lict.get_itemic_unit(i))
|
n = pt.Nucleon.create_on_nucleonic_data(nucleonic_data=repo.nucleonic_data_lict.get_itemic_unit(i))
|
||||||
e = pt.Electron.create_on_electonic_data(electronic_data=repo.electronic_data_lict.get_itemic_unit(i))
|
e = pt.Electron.create_on_electonic_data(electronic_data=repo.electronic_data_lict.get_itemic_unit(i))
|
||||||
|
a = pt.Atom(n, e, repo.orbitic_data)
|
||||||
e.activate()
|
e.activate()
|
||||||
e.revisor(5, True)
|
e.revisor(5, True)
|
||||||
print(repr(n))
|
print(repr(a))
|
||||||
print(repr(e))
|
#print(repr(e))
|
||||||
print(repo)
|
#print(repo)
|
||||||
@@ -38,7 +38,7 @@ class HeurAMSApp(App):
|
|||||||
("d", "toggle_dark", "切换色调"),
|
("d", "toggle_dark", "切换色调"),
|
||||||
("1", "app.push_screen('dashboard')", "仪表盘"),
|
("1", "app.push_screen('dashboard')", "仪表盘"),
|
||||||
("2", "app.push_screen('precache_all')", "缓存管理器"),
|
("2", "app.push_screen('precache_all')", "缓存管理器"),
|
||||||
("3", "app.push_screen('nucleon_creator')", "创建新仓库"),
|
("3", "app.push_screen('repo_creator')", "创建新仓库"),
|
||||||
# ("4", "app.push_screen('synctool')", "同步工具"),
|
# ("4", "app.push_screen('synctool')", "同步工具"),
|
||||||
("0", "app.push_screen('about')", "版本信息"),
|
("0", "app.push_screen('about')", "版本信息"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class AboutScreen(Screen):
|
|||||||
|
|
||||||
版本 {version.ver} {version.stage.capitalize()}
|
版本 {version.ver} {version.stage.capitalize()}
|
||||||
|
|
||||||
开发代号: {version.codename.capitalize()}
|
开发代号: {version.codename.capitalize()} {version.codename_cn}
|
||||||
|
|
||||||
一个基于启发式算法的开放源代码记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划.
|
一个基于启发式算法的开放源代码记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划.
|
||||||
|
|
||||||
|
|||||||
@@ -146,26 +146,6 @@ class DashboardScreen(Screen):
|
|||||||
# 跳转到准备屏幕
|
# 跳转到准备屏幕
|
||||||
self.app.push_screen(PreparationScreen(selected_repo, self.repostat[self.title2dirname[selected_repotitle]]))
|
self.app.push_screen(PreparationScreen(selected_repo, self.repostat[self.title2dirname[selected_repotitle]]))
|
||||||
|
|
||||||
def on_button_pressed(self, event) -> None:
|
|
||||||
"""处理按钮点击事件"""
|
|
||||||
button_id = event.button.id
|
|
||||||
|
|
||||||
if button_id == "new_nucleon_button":
|
|
||||||
from .repocreator import RepoCreatorScreen
|
|
||||||
|
|
||||||
new_screen = RepoCreatorScreen()
|
|
||||||
self.app.push_screen(new_screen)
|
|
||||||
|
|
||||||
elif button_id == "precache_all_button":
|
|
||||||
from .precache import PrecachingScreen
|
|
||||||
|
|
||||||
precache_screen = PrecachingScreen()
|
|
||||||
self.app.push_screen(precache_screen)
|
|
||||||
|
|
||||||
elif button_id == "about_button":
|
|
||||||
about_screen = AboutScreen()
|
|
||||||
self.app.push_screen(about_screen)
|
|
||||||
|
|
||||||
def action_quit_app(self) -> None:
|
def action_quit_app(self) -> None:
|
||||||
"""退出应用程序"""
|
"""退出应用程序"""
|
||||||
self.app.exit()
|
self.app.exit()
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ class MemScreen(Screen):
|
|||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(name, id, classes)
|
super().__init__(name, id, classes)
|
||||||
self.atoms = atoms
|
self.atoms = atoms
|
||||||
for i in self.atoms:
|
|
||||||
i.do_eval()
|
|
||||||
self.phaser = Phaser(atoms)
|
self.phaser = Phaser(atoms)
|
||||||
# logger.debug(self.phaser.state)
|
# logger.debug(self.phaser.state)
|
||||||
self.procession: Procession = self.phaser.current_procession() # type: ignore
|
self.procession: Procession = self.phaser.current_procession() # type: ignore
|
||||||
|
|||||||
@@ -38,12 +38,6 @@ class PrecachingScreen(Screen):
|
|||||||
self.precache_worker = None
|
self.precache_worker = None
|
||||||
self.cancel_flag = 0
|
self.cancel_flag = 0
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
for i in nucleons:
|
|
||||||
i: pt.Nucleon
|
|
||||||
atom = pt.Atom()
|
|
||||||
atom.link("nucleon", i)
|
|
||||||
atom.do_eval()
|
|
||||||
# print("完成 EVAL")
|
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
yield Header(show_clock=True)
|
yield Header(show_clock=True)
|
||||||
@@ -94,7 +88,7 @@ class PrecachingScreen(Screen):
|
|||||||
"""预缓存单段文本的音频"""
|
"""预缓存单段文本的音频"""
|
||||||
from heurams.context import config_var, rootdir, workdir
|
from heurams.context import config_var, rootdir, workdir
|
||||||
|
|
||||||
cache_dir = pathlib.Path(config_var.get()["paths"]["cache_dir"])
|
cache_dir = pathlib.Path(config_var.get()["paths"]["data"]) / 'cache'
|
||||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||||
cache_file = cache_dir / f"{hasher.get_md5(text)}.wav"
|
cache_file = cache_dir / f"{hasher.get_md5(text)}.wav"
|
||||||
if not cache_file.exists():
|
if not cache_file.exists():
|
||||||
@@ -110,10 +104,8 @@ class PrecachingScreen(Screen):
|
|||||||
|
|
||||||
def precache_by_nucleon(self, nucleon: pt.Nucleon):
|
def precache_by_nucleon(self, nucleon: pt.Nucleon):
|
||||||
"""依据 Nucleon 缓存"""
|
"""依据 Nucleon 缓存"""
|
||||||
# print(nucleon.metadata['formation']['tts_text'])
|
ret = self.precache_by_text(nucleon["tts_text"])
|
||||||
ret = self.precache_by_text(nucleon.metadata["formation"]["tts_text"])
|
|
||||||
return ret
|
return ret
|
||||||
# print(f"TTS 缓存: {nucleon.metadata['formation']['tts_text']}")
|
|
||||||
|
|
||||||
def precache_by_list(self, nucleons: list):
|
def precache_by_list(self, nucleons: list):
|
||||||
"""依据 Nucleons 列表缓存"""
|
"""依据 Nucleons 列表缓存"""
|
||||||
@@ -122,7 +114,7 @@ class PrecachingScreen(Screen):
|
|||||||
worker = get_current_worker()
|
worker = get_current_worker()
|
||||||
if worker and worker.is_cancelled: # 函数在worker中执行且已被取消
|
if worker and worker.is_cancelled: # 函数在worker中执行且已被取消
|
||||||
return False
|
return False
|
||||||
text = nucleon.metadata["formation"]["tts_text"]
|
text = nucleon["tts_text"]
|
||||||
# self.current_item = text[:30] + "..." if len(text) > 50 else text
|
# self.current_item = text[:30] + "..." if len(text) > 50 else text
|
||||||
# print(text)
|
# print(text)
|
||||||
self.processed += 1
|
self.processed += 1
|
||||||
@@ -152,38 +144,26 @@ class PrecachingScreen(Screen):
|
|||||||
# print(f"返回 {ret}")
|
# print(f"返回 {ret}")
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def precache_by_filepath(self, path: pathlib.Path):
|
|
||||||
"""预缓存单个文件的所有内容"""
|
|
||||||
lst = list()
|
|
||||||
for i in pt.load_nucleon(path):
|
|
||||||
lst.append(i[0])
|
|
||||||
return self.precache_by_list(lst)
|
|
||||||
|
|
||||||
def precache_all_files(self):
|
def precache_all_files(self):
|
||||||
"""预缓存所有文件"""
|
"""预缓存所有文件"""
|
||||||
from heurams.context import config_var, rootdir, workdir
|
from heurams.context import config_var, rootdir, workdir
|
||||||
|
from heurams.kernel.repolib import Repo
|
||||||
|
|
||||||
nucleon_path = pathlib.Path(config_var.get()["paths"]["nucleon_dir"])
|
repo_path = pathlib.Path(config_var.get()["paths"]["data"]) / 'repo'
|
||||||
nucleon_files = [
|
repo_dirs = Repo.probe_vaild_repos_in_dir(repo_path)
|
||||||
f for f in nucleon_path.iterdir() if f.suffix == ".toml"
|
repos = map(Repo.create_from_repodir, repo_dirs)
|
||||||
] # TODO: 解耦合
|
|
||||||
|
|
||||||
# 计算总项目数
|
# 计算总项目数
|
||||||
self.total = 0
|
self.total = 0
|
||||||
nu = list()
|
nucleon_list = list()
|
||||||
for file in nucleon_files:
|
for repo in repos:
|
||||||
try:
|
try:
|
||||||
for i in pt.load_nucleon(file):
|
for i in repo.ident_index:
|
||||||
nu.append(i[0])
|
nucleon_list.append(pt.Nucleon.create_on_nucleonic_data(repo.nucleonic_data_lict.get_itemic_unit(i)))
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
self.total = len(nu)
|
self.total = len(nucleon_list)
|
||||||
for i in nu:
|
return self.precache_by_list(nucleon_list)
|
||||||
i: pt.Nucleon
|
|
||||||
atom = pt.Atom()
|
|
||||||
atom.link("nucleon", i)
|
|
||||||
atom.do_eval()
|
|
||||||
return self.precache_by_list(nu)
|
|
||||||
|
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
event.stop()
|
event.stop()
|
||||||
@@ -221,7 +201,7 @@ class PrecachingScreen(Screen):
|
|||||||
from heurams.context import config_var, rootdir, workdir
|
from heurams.context import config_var, rootdir, workdir
|
||||||
|
|
||||||
shutil.rmtree(
|
shutil.rmtree(
|
||||||
f"{config_var.get()["paths"]["cache_dir"]}", ignore_errors=True
|
f"{config_var.get()["paths"]["data"]}/'cache'", ignore_errors=True
|
||||||
)
|
)
|
||||||
self.update_status("已清空", "音频缓存已清空", 0)
|
self.update_status("已清空", "音频缓存已清空", 0)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -84,9 +84,9 @@ class PreparationScreen(Screen):
|
|||||||
from ..screens.precache import PrecachingScreen
|
from ..screens.precache import PrecachingScreen
|
||||||
|
|
||||||
lst = list()
|
lst = list()
|
||||||
for i in self.nucleons_with_orbital:
|
for i in self.repo.ident_index:
|
||||||
lst.append(i[0])
|
lst.append(pt.Nucleon.create_on_nucleonic_data(self.repo.nucleonic_data_lict.get_itemic_unit(i)))
|
||||||
precache_screen = PrecachingScreen(lst)
|
precache_screen = PrecachingScreen(nucleons=lst, desc=self.repo.manifest["title"])
|
||||||
self.app.push_screen(precache_screen)
|
self.app.push_screen(precache_screen)
|
||||||
|
|
||||||
def action_quit_app(self):
|
def action_quit_app(self):
|
||||||
@@ -97,38 +97,27 @@ class PreparationScreen(Screen):
|
|||||||
logger.debug("按下按钮")
|
logger.debug("按下按钮")
|
||||||
if event.button.id == "start_memorizing_button":
|
if event.button.id == "start_memorizing_button":
|
||||||
atoms = list()
|
atoms = list()
|
||||||
for nucleon, orbital in self.nucleons_with_orbital:
|
for i in self.repo.ident_index:
|
||||||
atom = pt.Atom(nucleon.ident)
|
n = pt.Nucleon.create_on_nucleonic_data(nucleonic_data=self.repo.nucleonic_data_lict.get_itemic_unit(i))
|
||||||
atom.link("nucleon", nucleon)
|
e = pt.Electron.create_on_electonic_data(electronic_data=self.repo.electronic_data_lict.get_itemic_unit(i))
|
||||||
try:
|
a = pt.Atom(n, e, self.repo.orbitic_data)
|
||||||
atom.link("electron", self.electrons[nucleon.ident])
|
atoms.append(a)
|
||||||
except KeyError:
|
|
||||||
atom.link("electron", pt.Electron(nucleon.ident))
|
|
||||||
atom.link("orbital", orbital)
|
|
||||||
atom.link("nucleon_fmt", "toml")
|
|
||||||
atom.link("electron_fmt", "json")
|
|
||||||
atom.link("orbital_fmt", "toml")
|
|
||||||
atom.link("nucleon_path", self.nucleon_file)
|
|
||||||
atom.link("electron_path", self.electron_file)
|
|
||||||
atom.link("orbital_path", None)
|
|
||||||
atoms.append(atom)
|
|
||||||
atoms_to_provide = list()
|
atoms_to_provide = list()
|
||||||
left_new = self.scheduled_num
|
left_new = self.scheduled_num
|
||||||
for i in atoms:
|
for i in atoms:
|
||||||
i: pt.Atom
|
i: pt.Atom
|
||||||
if i.registry["electron"].is_due():
|
if i.registry['electron'].is_activated():
|
||||||
atoms_to_provide.append(i)
|
if i.registry["electron"].is_due():
|
||||||
|
atoms_to_provide.append(i)
|
||||||
else:
|
else:
|
||||||
if i.registry["electron"].is_activated():
|
left_new -= 1
|
||||||
pass
|
if left_new >= 0:
|
||||||
else:
|
atoms_to_provide.append(i)
|
||||||
left_new -= 1
|
|
||||||
if left_new >= 0:
|
|
||||||
atoms_to_provide.append(i)
|
|
||||||
logger.debug(f"ATP: {atoms_to_provide}")
|
|
||||||
from .memoqueue import MemScreen
|
from .memoqueue import MemScreen
|
||||||
|
|
||||||
memscreen = MemScreen(atoms_to_provide)
|
memscreen = MemScreen(atoms_to_provide)
|
||||||
self.app.push_screen(memscreen)
|
self.app.push_screen(memscreen)
|
||||||
|
|
||||||
elif event.button.id == "precache_button":
|
elif event.button.id == "precache_button":
|
||||||
self.action_precache()
|
self.action_precache()
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import json
|
|
||||||
import pathlib
|
|
||||||
import typing
|
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
|
|
||||||
import toml
|
|
||||||
|
|
||||||
from heurams.services.logger import get_logger
|
from heurams.services.logger import get_logger
|
||||||
|
|
||||||
@@ -22,6 +18,7 @@ class AtomRegister_runtime(TypedDict):
|
|||||||
class AtomRegister(TypedDict):
|
class AtomRegister(TypedDict):
|
||||||
nucleon: Nucleon
|
nucleon: Nucleon
|
||||||
electron: Electron
|
electron: Electron
|
||||||
|
orbital: dict
|
||||||
runtime: AtomRegister_runtime
|
runtime: AtomRegister_runtime
|
||||||
|
|
||||||
|
|
||||||
@@ -99,3 +96,8 @@ class Atom:
|
|||||||
if key == "ident":
|
if key == "ident":
|
||||||
raise AttributeError("应为只读")
|
raise AttributeError("应为只读")
|
||||||
self.registry[key] = value
|
self.registry[key] = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
from pprint import pformat
|
||||||
|
s = pformat(self.registry, indent=4)
|
||||||
|
return s
|
||||||
|
|||||||
@@ -13,12 +13,15 @@ class Nucleon:
|
|||||||
self.ident = ident
|
self.ident = ident
|
||||||
env = {"payload": payload}
|
env = {"payload": payload}
|
||||||
self.evalizer = Evalizer(environment=env)
|
self.evalizer = Evalizer(environment=env)
|
||||||
self.data = self.evalizer(deepcopy((payload | common)))
|
self.data: dict = self.evalizer(deepcopy((payload | common))) # type: ignore
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if key == "ident":
|
if isinstance(key, str):
|
||||||
return self.ident
|
if key == "ident":
|
||||||
return self.data[key]
|
return self.ident
|
||||||
|
return self.data[key]
|
||||||
|
else:
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
raise AttributeError("应为只读")
|
raise AttributeError("应为只读")
|
||||||
|
|||||||
1
src/heurams/kernel/reactor/README.md
Normal file
1
src/heurams/kernel/reactor/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Reactor - 记忆过程状态机模块
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from heurams.services.logger import get_logger
|
||||||
|
|
||||||
|
from .fission import Fission
|
||||||
|
from .phaser import Phaser
|
||||||
|
from .procession import Procession
|
||||||
|
from .states import PhaserState, ProcessionState
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
__all__ = ["PhaserState", "ProcessionState", "Procession", "Fission", "Phaser"]
|
||||||
|
|
||||||
|
logger.debug("反应堆模块已加载")
|
||||||
49
src/heurams/kernel/reactor/fission.py
Normal file
49
src/heurams/kernel/reactor/fission.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
import heurams.kernel.evaluators as puz
|
||||||
|
import heurams.kernel.particles as pt
|
||||||
|
from heurams.services.logger import get_logger
|
||||||
|
|
||||||
|
from .states import PhaserState
|
||||||
|
|
||||||
|
|
||||||
|
class Fission:
|
||||||
|
"""裂变器: 单原子调度展开器"""
|
||||||
|
|
||||||
|
def __init__(self, atom: pt.Atom, phase_state=PhaserState.RECOGNITION):
|
||||||
|
self.logger = get_logger(__name__)
|
||||||
|
self.atom = atom
|
||||||
|
|
||||||
|
#NOTE: phase 为 PhaserState 枚举实例,需要获取其value
|
||||||
|
phase_value = phase_state.value if isinstance(phase_state, PhaserState) else phase_state
|
||||||
|
|
||||||
|
self.orbital_schedule = atom.registry["orbital"]["schedule"][phase_value] # type: ignore
|
||||||
|
self.orbital_puzzles = atom.registry["orbital"]["puzzles"]
|
||||||
|
|
||||||
|
self.puzzles = list()
|
||||||
|
for item, possibility in self.orbital_schedule: # type: ignore
|
||||||
|
self.logger.debug(f"开始处理 orbital 项: {item}")
|
||||||
|
if not isinstance(possibility, float):
|
||||||
|
possibility = float(possibility)
|
||||||
|
|
||||||
|
while possibility > 1:
|
||||||
|
self.puzzles.append(
|
||||||
|
{
|
||||||
|
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||||
|
"alia": item,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
possibility -= 1
|
||||||
|
|
||||||
|
if random.random() <= possibility:
|
||||||
|
self.puzzles.append(
|
||||||
|
{
|
||||||
|
"puzzle": puz.puzzles[self.orbital_puzzles[item]["__origin__"]],
|
||||||
|
"alia": item,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.logger.debug(f"orbital 项处理完成: {item}")
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
yield from self.puzzles
|
||||||
@@ -1,24 +1,117 @@
|
|||||||
from enum import Enum
|
import heurams.kernel.particles as pt
|
||||||
from typing import Any, Sequence, Type
|
from heurams.services.logger import get_logger
|
||||||
from transitions import Machine, State, Event, EventData
|
from transitions import Machine
|
||||||
|
|
||||||
|
from .procession import Procession
|
||||||
|
from .states import PhaserState, ProcessionState
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Phaser(Machine):
|
class Phaser(Machine):
|
||||||
def __init__(self, schedule: list):
|
"""全局调度阶段管理器"""
|
||||||
state_words = ["init"] + schedule.copy()
|
|
||||||
state_objects = list()
|
|
||||||
for name in state_words:
|
|
||||||
state_objects.append(State(
|
|
||||||
name=name,
|
|
||||||
on_enter=["on_enter"]
|
|
||||||
))
|
|
||||||
Machine.__init__(self, states=state_objects, initial="init", send_event=True)
|
|
||||||
self.add_ordered_transitions(loop=False)
|
|
||||||
|
|
||||||
def on_enter(self, event_data: EventData):
|
def __init__(self, atoms: list[pt.Atom]) -> None:
|
||||||
print(event_data.transition.source, "->", event_data.transition.dest) # type: ignore
|
logger.debug("Phaser.__init__: 原子数量=%d", len(atoms))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
new_atoms = list()
|
||||||
p = Phaser(["a", "b"])
|
old_atoms = list()
|
||||||
p.next_state()
|
|
||||||
p.next_state()
|
for i in atoms:
|
||||||
print(p.state)
|
if not i.registry["electron"].is_activated():
|
||||||
|
new_atoms.append(i)
|
||||||
|
else:
|
||||||
|
old_atoms.append(i)
|
||||||
|
|
||||||
|
logger.debug("新原子数量=%d, 旧原子数量=%d", len(new_atoms), len(old_atoms))
|
||||||
|
|
||||||
|
self.processions = list()
|
||||||
|
#TODO: 改进为基于配置文件的可变复习阶段管理
|
||||||
|
if len(old_atoms):
|
||||||
|
self.processions.append(
|
||||||
|
Procession(old_atoms, PhaserState.QUICK_REVIEW, "初始复习")
|
||||||
|
)
|
||||||
|
logger.debug("创建初始复习 Procession")
|
||||||
|
|
||||||
|
if len(new_atoms):
|
||||||
|
self.processions.append(
|
||||||
|
Procession(new_atoms, PhaserState.RECOGNITION, "新记忆")
|
||||||
|
)
|
||||||
|
logger.debug("创建新记忆 Procession")
|
||||||
|
|
||||||
|
self.processions.append(Procession(atoms, PhaserState.FINAL_REVIEW, "总体复习"))
|
||||||
|
logger.debug("创建总体复习 Procession")
|
||||||
|
logger.debug("Phaser 初始化完成, processions 数量=%d", len(self.processions))
|
||||||
|
|
||||||
|
# 设置transitions状态机
|
||||||
|
states = [
|
||||||
|
{'name': PhaserState.UNSURE.value, 'on_enter': 'on_unsure'},
|
||||||
|
{'name': PhaserState.QUICK_REVIEW.value, 'on_enter': 'on_quick_review'},
|
||||||
|
{'name': PhaserState.RECOGNITION.value, 'on_enter': 'on_recognition'},
|
||||||
|
{'name': PhaserState.FINAL_REVIEW.value, 'on_enter': 'on_final_review'},
|
||||||
|
{'name': PhaserState.FINISHED.value, 'on_enter': 'on_finished'}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions = [
|
||||||
|
{'trigger': 'to_unsure', 'source': '*', 'dest': PhaserState.UNSURE.value},
|
||||||
|
{'trigger': 'to_quick_review', 'source': '*', 'dest': PhaserState.QUICK_REVIEW.value},
|
||||||
|
{'trigger': 'to_recognition', 'source': '*', 'dest': PhaserState.RECOGNITION.value},
|
||||||
|
{'trigger': 'to_final_review', 'source': '*', 'dest': PhaserState.FINAL_REVIEW.value},
|
||||||
|
{'trigger': 'to_finished', 'source': '*', 'dest': PhaserState.FINISHED.value}
|
||||||
|
]
|
||||||
|
|
||||||
|
Machine.__init__(self, states=states, transitions=transitions,
|
||||||
|
initial=PhaserState.UNSURE.value)
|
||||||
|
|
||||||
|
self.to_unsure()
|
||||||
|
|
||||||
|
def on_unsure(self):
|
||||||
|
"""进入UNSURE状态时的回调"""
|
||||||
|
logger.debug("Phaser 进入 UNSURE 状态")
|
||||||
|
|
||||||
|
def on_quick_review(self):
|
||||||
|
"""进入QUICK_REVIEW状态时的回调"""
|
||||||
|
logger.debug("Phaser 进入 QUICK_REVIEW 状态")
|
||||||
|
|
||||||
|
def on_recognition(self):
|
||||||
|
"""进入RECOGNITION状态时的回调"""
|
||||||
|
logger.debug("Phaser 进入 RECOGNITION 状态")
|
||||||
|
|
||||||
|
def on_final_review(self):
|
||||||
|
"""进入FINAL_REVIEW状态时的回调"""
|
||||||
|
logger.debug("Phaser 进入 FINAL_REVIEW 状态")
|
||||||
|
|
||||||
|
def on_finished(self):
|
||||||
|
"""进入FINISHED状态时的回调"""
|
||||||
|
logger.debug("Phaser 进入 FINISHED 状态")
|
||||||
|
|
||||||
|
def current_procession(self):
|
||||||
|
logger.debug("Phaser.current_procession 被调用")
|
||||||
|
for i in self.processions:
|
||||||
|
i: Procession
|
||||||
|
if i.state != ProcessionState.FINISHED.value:
|
||||||
|
# 根据当前procession的phase更新Phaser状态
|
||||||
|
if i.phase == PhaserState.QUICK_REVIEW:
|
||||||
|
self.to_quick_review()
|
||||||
|
elif i.phase == PhaserState.RECOGNITION:
|
||||||
|
self.to_recognition()
|
||||||
|
elif i.phase == PhaserState.FINAL_REVIEW:
|
||||||
|
self.to_final_review()
|
||||||
|
|
||||||
|
logger.debug("找到未完成的 Procession: phase=%s", i.phase)
|
||||||
|
return i
|
||||||
|
|
||||||
|
# 所有Procession都已完成
|
||||||
|
self.to_finished()
|
||||||
|
logger.debug("所有 Procession 已完成, 状态设置为 FINISHED")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""获取当前状态值"""
|
||||||
|
current_state = self.get_model_state(self)
|
||||||
|
# 将字符串状态转换为PhaserState枚举
|
||||||
|
for phase in PhaserState:
|
||||||
|
if phase.value == current_state:
|
||||||
|
return phase
|
||||||
|
return PhaserState.UNSURE
|
||||||
@@ -1,24 +1,112 @@
|
|||||||
from enum import Enum
|
import heurams.kernel.particles as pt
|
||||||
from typing import Any, Sequence, Type
|
from heurams.services.logger import get_logger
|
||||||
from transitions import Machine, State, Event, EventData
|
from transitions import Machine
|
||||||
|
|
||||||
class Phaser(Machine):
|
from .states import PhaserState, ProcessionState
|
||||||
def __init__(self, schedule: list):
|
|
||||||
state_words = ["init"] + schedule.copy()
|
|
||||||
state_objects = list()
|
|
||||||
for name in state_words:
|
|
||||||
state_objects.append(State(
|
|
||||||
name=name,
|
|
||||||
on_enter=["on_enter"]
|
|
||||||
))
|
|
||||||
Machine.__init__(self, states=state_objects, initial="init", send_event=True)
|
|
||||||
self.add_ordered_transitions(loop=False)
|
|
||||||
|
|
||||||
def on_enter(self, event_data: EventData):
|
logger = get_logger(__name__)
|
||||||
print(event_data.transition.source, "->", event_data.transition.dest) # type: ignore
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
p = Phaser(["a", "b"])
|
class Procession(Machine):
|
||||||
p.next_state()
|
"""队列: 标识单次记忆流程"""
|
||||||
p.next_state()
|
|
||||||
print(p.state)
|
def __init__(self, atoms: list, phase_state: PhaserState, name: str = ""):
|
||||||
|
logger.debug(
|
||||||
|
"Procession.__init__: 原子数量=%d, phase=%s, name='%s'",
|
||||||
|
len(atoms),
|
||||||
|
phase_state.value,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 初始化原子队列
|
||||||
|
self.atoms = atoms
|
||||||
|
self.queue = atoms.copy()
|
||||||
|
self.current_atom = atoms[0] if atoms else None
|
||||||
|
self.cursor = 0
|
||||||
|
self.name = name
|
||||||
|
self.phase = phase_state
|
||||||
|
|
||||||
|
# 设置transitions状态机
|
||||||
|
states = [{'name': ProcessionState.RUNNING.value, 'on_enter': 'on_running'},
|
||||||
|
{'name': ProcessionState.FINISHED.value, 'on_enter': 'on_finished'}]
|
||||||
|
|
||||||
|
transitions = [
|
||||||
|
{'trigger': 'finish', 'source': ProcessionState.RUNNING.value, 'dest': ProcessionState.FINISHED.value},
|
||||||
|
{'trigger': 'restart', 'source': ProcessionState.FINISHED.value, 'dest': ProcessionState.RUNNING.value}
|
||||||
|
]
|
||||||
|
|
||||||
|
Machine.__init__(self, states=states, transitions=transitions,
|
||||||
|
initial=ProcessionState.RUNNING.value)
|
||||||
|
|
||||||
|
logger.debug("Procession 初始化完成, 队列长度=%d", len(self.queue))
|
||||||
|
|
||||||
|
def on_running(self):
|
||||||
|
"""进入RUNNING状态时的回调"""
|
||||||
|
logger.debug("Procession 进入 RUNNING 状态")
|
||||||
|
|
||||||
|
def on_finished(self):
|
||||||
|
"""进入FINISHED状态时的回调"""
|
||||||
|
logger.debug("Procession 进入 FINISHED 状态")
|
||||||
|
|
||||||
|
def forward(self, step=1):
|
||||||
|
logger.debug("Procession.forward: step=%d, 当前 cursor=%d", step, self.cursor)
|
||||||
|
self.cursor += step
|
||||||
|
|
||||||
|
if self.cursor >= len(self.queue):
|
||||||
|
if self.state != ProcessionState.FINISHED.value:
|
||||||
|
self.finish() # 触发状态转换
|
||||||
|
logger.debug("Procession 已完成")
|
||||||
|
else:
|
||||||
|
if self.state != ProcessionState.RUNNING.value:
|
||||||
|
self.restart() # 确保在RUNNING状态
|
||||||
|
self.current_atom = self.queue[self.cursor]
|
||||||
|
logger.debug("cursor 更新为: %d", self.cursor)
|
||||||
|
logger.debug("当前原子更新为: %s", self.current_atom.ident if self.current_atom else "None")
|
||||||
|
return 1 # 成功
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def append(self, atom=None):
|
||||||
|
if atom is None:
|
||||||
|
atom = self.current_atom
|
||||||
|
logger.debug("Procession.append: atom=%s", atom.ident if atom else "None")
|
||||||
|
|
||||||
|
if not self.queue or self.queue[-1] != atom or len(self) <= 1:
|
||||||
|
self.queue.append(atom)
|
||||||
|
logger.debug("原子已追加到队列, 新队列长度=%d", len(self.queue))
|
||||||
|
else:
|
||||||
|
logger.debug("原子未追加(重复或队列长度<=1)")
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
if not self.queue:
|
||||||
|
return 0
|
||||||
|
length = len(self.queue) - self.cursor
|
||||||
|
logger.debug("Procession.__len__: 剩余长度=%d", length)
|
||||||
|
return length
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
logger.debug("Procession.process: cursor=%d", self.cursor)
|
||||||
|
return self.cursor
|
||||||
|
|
||||||
|
def total_length(self):
|
||||||
|
total = len(self.queue)
|
||||||
|
logger.debug("Procession.total_length: %d", total)
|
||||||
|
return total
|
||||||
|
|
||||||
|
def is_empty(self):
|
||||||
|
empty = len(self.queue) == 0
|
||||||
|
logger.debug("Procession.is_empty: %s", empty)
|
||||||
|
return empty
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""获取当前状态值"""
|
||||||
|
return self.get_model_state(self)
|
||||||
|
|
||||||
|
@state.setter
|
||||||
|
def state(self, value):
|
||||||
|
"""设置状态值"""
|
||||||
|
if value == ProcessionState.RUNNING.value:
|
||||||
|
self.restart()
|
||||||
|
elif value == ProcessionState.FINISHED.value:
|
||||||
|
self.finish()
|
||||||
21
src/heurams/kernel/reactor/states.py
Normal file
21
src/heurams/kernel/reactor/states.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
from heurams.services.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PhaserState(Enum):
|
||||||
|
UNSURE = "unsure"
|
||||||
|
QUICK_REVIEW = "quick_review"
|
||||||
|
RECOGNITION = "recognition"
|
||||||
|
FINAL_REVIEW = "final_review"
|
||||||
|
FINISHED = "finished"
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessionState(Enum):
|
||||||
|
RUNNING = "running"
|
||||||
|
FINISHED = "finished"
|
||||||
|
|
||||||
|
|
||||||
|
logger.debug("状态枚举定义已加载")
|
||||||
@@ -5,6 +5,7 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
ver = "0.5.0"
|
ver = "0.5.0"
|
||||||
stage = "prototype"
|
stage = "prototype"
|
||||||
codename = "fulcrom" # 支点
|
codename = "fulcrom"
|
||||||
|
codename_cn = "支点"
|
||||||
|
|
||||||
logger.info("HeurAMS 版本: %s (%s), 阶段: %s", ver, codename, stage)
|
logger.info("HeurAMS 版本: %s (%s), 阶段: %s", ver, codename, stage)
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ class Lict(UserList): # TODO: 优化同步(惰性同步), 当前性能为 O(n)
|
|||||||
else:
|
else:
|
||||||
return super().__getitem__(i)
|
return super().__getitem__(i)
|
||||||
|
|
||||||
def get_itemic_unit(self, i):
|
def get_itemic_unit(self, ident):
|
||||||
return (i, self.dicted_data[i])
|
return (ident, self.dicted_data[ident])
|
||||||
|
|
||||||
def __setitem__(self, i, item):
|
def __setitem__(self, i, item):
|
||||||
if isinstance(i, str):
|
if isinstance(i, str):
|
||||||
|
|||||||
Reference in New Issue
Block a user