实现 Recognition 部件

This commit is contained in:
2025-11-08 13:23:15 +08:00
parent 92f9903307
commit 330846a4a5
8 changed files with 108 additions and 54 deletions

View File

@@ -10,10 +10,10 @@ def clear():
staging = dict() staging = dict()
def deploy_to_electron(): def deploy_to_electron():
for atom_ident, quality in staging.items(): for atom_ident, quality in staging.items():
if pt.atom_registry[atom_ident].register['electron'].is_activated: if pt.atom_registry[atom_ident].registry['electron'].is_activated:
pt.atom_registry[atom_ident].register['electron'].revisor(quality=quality) pt.atom_registry[atom_ident].registry['electron'].revisor(quality=quality)
else: else:
pt.atom_registry[atom_ident].register['electron'].revisor(quality=quality, is_new_activation=True) pt.atom_registry[atom_ident].registry['electron'].revisor(quality=quality, is_new_activation=True)
clear() clear()
puzzle2widget = { puzzle2widget = {
pz.RecognitionPuzzle: pzw.Recognition, pz.RecognitionPuzzle: pzw.Recognition,

View File

@@ -25,7 +25,7 @@ class BasicEvaluation(BasePuzzleWidget):
} }
def compose(self): def compose(self):
yield Label(self.atom.register["nucleon"]["content"], id="main") yield Label(self.atom.registry["nucleon"]["content"], id="main")
with Container(id="button_container"): with Container(id="button_container"):
btn = {} btn = {}
btn["5"] = Button( btn["5"] = Button(

View File

@@ -23,7 +23,7 @@ class ClozePuzzle(BasePuzzleWidget):
self._work() self._work()
def _work(self): def _work(self):
self.puzzle = pz.ClozePuzzle(text=self.atom.register["nucleon"]["content"], min_denominator=2) self.puzzle = pz.ClozePuzzle(text=self.atom.registry["nucleon"]["content"], min_denominator=2)
self.puzzle.refresh() self.puzzle.refresh()
self.ans = copy.copy(self.puzzle.answer) self.ans = copy.copy(self.puzzle.answer)
random.shuffle(self.ans) random.shuffle(self.ans)

View File

@@ -24,56 +24,72 @@ import copy
from .base_puzzle_widget import BasePuzzleWidget from .base_puzzle_widget import BasePuzzleWidget
from heurams.context import config_var from heurams.context import config_var
from .. import shim from .. import shim
from typing import TypedDict, List
class RecognitionConfig(TypedDict):
__origin__: str
__hint__: str
primary: str
secondary: List[str]
top_dim: List[str]
class Recognition(BasePuzzleWidget): class Recognition(BasePuzzleWidget):
def __init__(self, *children: Widget, atom: pt.Atom, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
rate_mapping = {
"ok": 5
}
def __init__(self, *children: Widget, atom: pt.Atom, alia: str = "", name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
if alia == "":
alia = "Recognition"
self.alia = alia
def compose(self): def compose(self):
with Center(): cfg: RecognitionConfig = self.atom.registry["orbital"]["puzzles"][self.alia]
yield Static(f"[dim]{self.atom.register['nucleon']['translation']}[/]") delim = self.atom.registry['nucleon'].metadata["formation"]["delimiter"]
yield Label(f"")
s = str(self.atom.register['nucleon']["content"])
replace_dict = { replace_dict = {
", ": ",", ", ": ",",
". ": ".", ". ": ".",
"; ": ";", "; ": ";",
": ": ":", ": ": ":",
"/,": ",", f"{delim},": ",",
"./": ".", f".{delim}": ".",
"/;": ";", f"{delim};": ";",
";/": ";", f";{delim}": ";",
":/": ":", f":{delim}": ":",
} }
nucleon = self.atom.registry['nucleon']
metadata = self.atom.registry['nucleon'].metadata
primary = nucleon[cfg["primary"]]
with Center():
yield Static(f"[dim]{nucleon[cfg["top_dim"]]}[/]")
yield Label(f"")
for old, new in replace_dict.items(): for old, new in replace_dict.items():
s = s.replace(old, new) primary = primary.replace(old, new)
result = re.split(r"(?<=[,;:|])", s.replace("/", " ")) primary_splited = re.split(r"(?<=[,;:|])", cfg['primary'])
for i in result: for item in primary_splited:
with Center(): with Center():
yield Label( yield Label(
f"[b][b]{i.replace('/', ' ')}[/][/]", f"[b][b]{item.replace(delim, ' ')}[/][/]",
id="sentence" + str(hash(i)), id="sentence" + str(hash(item)),
) )
# 处理orbital/展示配置
for i in
# eval 环境设置
nucleon = self.atom.register['nucleon']
default = config_var.get()["puzzles"]
metadata = nucleon.metadata
for item in nucleon[cfg["secondary"]]:
if isinstance(item, list):
for j in item:
yield Markdown(f"### {metadata["annotation"][item]}: {j}")
continue
if isinstance(item, Dict):
total = ""
for j, k in item.items(): # type: ignore
total += f"> **{j}**: {k} \n"
yield Markdown(total)
if isinstance(item, str):
yield Markdown(item)
for i in self.atom.register["orbital"] ["testdata"]["additional_inf"]:
if self.atom.register['nucleon'][i]:
if isinstance(self.atom.register['nucleon'][i], list):
for j in self.atom.register['nucleon'][i]:
yield Markdown(f"### {self.atom.register["orbital"] ['keydata'][i]}: {j}")
continue
if isinstance(self.atom.register['nucleon'][i], Dict):
t = ""
for j, k in self.atom.register['nucleon'][i].items(): # type: ignore
t += f"> **{j}**: {k} \n"
yield Markdown(t, id="tran")
with Center(): with Center():
yield Button("我已知晓", id="ok") yield Button("我已知晓", id="ok")

View File

@@ -7,6 +7,7 @@ import typing
import toml import toml
import json import json
import bidict import bidict
from heurams.context import config_var
class AtomRegister(TypedDict): class AtomRegister(TypedDict):
nucleon: Nucleon nucleon: Nucleon
@@ -32,7 +33,8 @@ class Atom():
def __init__(self, ident = ""): def __init__(self, ident = ""):
self.ident = ident self.ident = ident
atom_registry[ident] = self atom_registry[ident] = self
self.register: AtomRegister = { # type: ignore # self.is_evaled = False
self.registry: AtomRegister = { # type: ignore
"nucleon": None, "nucleon": None,
"nucleon_path": None, "nucleon_path": None,
"nucleon_fmt": "toml", "nucleon_fmt": "toml",
@@ -43,37 +45,73 @@ class Atom():
"orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置 "orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置
"orbital_fmt": "toml", "orbital_fmt": "toml",
} }
self.do_eval()
def link(self, key, value): def link(self, key, value):
if key in self.register.keys(): if key in self.registry.keys():
self.register[key] = value self.registry[key] = value
self.do_eval()
else: else:
raise ValueError("不受支持的原子元数据链接操作") raise ValueError("不受支持的原子元数据链接操作")
def do_eval(self):
"""
执行并以结果替换当前单元的所有 eval 语句
TODO: 带有限制的 eval, 异步/多线程执行避免堵塞
"""
# eval 环境设置
def eval_with_env(s: str):
nucleon = self.registry['nucleon']
default = config_var.get()["puzzles"]
metadata = nucleon.metadata
try:
ret = str(eval(s))
except:
ret = "此 eval 实例发生错误"
return ret
def traverse(data, modifier):
if isinstance(data, dict):
for key, value in data.items():
data[key] = traverse(value, modifier)
return data
elif isinstance(data, list):
for i, item in enumerate(data):
data[i] = traverse(item, modifier)
return data
elif isinstance(data, tuple):
return tuple(traverse(item, modifier) for item in data)
else:
return modifier(data)
traverse(self.registry["nucleon"], eval_with_env)
traverse(self.registry["orbital"], eval_with_env)
def persist(self, key): def persist(self, key):
path: pathlib.Path | None = self.register[key + "_path"] path: pathlib.Path | None = self.registry[key + "_path"]
if isinstance(path, pathlib.Path): if isinstance(path, pathlib.Path):
path = typing.cast(pathlib.Path, path) path = typing.cast(pathlib.Path, path)
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
if self.register[key + "_fmt"] == "toml": if self.registry[key + "_fmt"] == "toml":
with open(path, "w") as f: with open(path, "w") as f:
toml.dump(self.register[key], f) toml.dump(self.registry[key], f)
elif self.register[key + "_fmt"] == "json": elif self.registry[key + "_fmt"] == "json":
with open(path, "w") as f: with open(path, "w") as f:
json.dump(self.register[key], f) json.dump(self.registry[key], f)
else: else:
raise KeyError("不受支持的持久化格式") raise KeyError("不受支持的持久化格式")
else: else:
raise TypeError("对未初始化的路径对象操作") raise TypeError("对未初始化的路径对象操作")
def __getitem__(self, key): def __getitem__(self, key):
if key in self.register: if key in self.registry:
return self.register[key] return self.registry[key]
raise KeyError(f"不支持的键: {key}") raise KeyError(f"不支持的键: {key}")
def __setitem__(self, key, value): def __setitem__(self, key, value):
if key in self.register: if key in self.registry:
self.register[key] = value self.registry[key] = value
else: else:
raise KeyError(f"不支持的键: {key}") raise KeyError(f"不支持的键: {key}")

View File

@@ -7,7 +7,7 @@ class Fission():
"""裂变器: 单原子调度展开器""" """裂变器: 单原子调度展开器"""
def __init__(self, atom: pt.Atom, phase = PhaserState.RECOGNITION): def __init__(self, atom: pt.Atom, phase = PhaserState.RECOGNITION):
self.atom = atom self.atom = atom
self.orbital = atom.register["orbital"][phase.value] self.orbital = atom.registry["orbital"][phase.value]
print(self.orbital) print(self.orbital)
self.puzzles = list() self.puzzles = list()
for item, possibility in self.orbital: # type: ignore for item, possibility in self.orbital: # type: ignore

View File

@@ -11,7 +11,7 @@ class Phaser():
old_atoms = list() old_atoms = list()
self.state = PhaserState.UNSURE self.state = PhaserState.UNSURE
for i in atoms: for i in atoms:
if not i.register["electron"].is_activated(): if not i.registry["electron"].is_activated():
new_atoms.append(i) new_atoms.append(i)
else: else:
old_atoms.append(i) old_atoms.append(i)

View File

@@ -153,7 +153,7 @@ class TestAtom:
atom = Atom("test_atom") atom = Atom("test_atom")
assert atom.ident == "test_atom" assert atom.ident == "test_atom"
assert isinstance(atom.register, dict) assert isinstance(atom.registry, dict)
def test_atom_link(self): def test_atom_link(self):
"""Test Atom linking components.""" """Test Atom linking components."""