From 4eaff186851286448dc0377c58a4018564c1f833 Mon Sep 17 00:00:00 2001 From: david-ajax Date: Tue, 4 Nov 2025 00:07:40 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E4=B8=80=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=20interface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heurams/interface/shim.py | 14 +++++ src/heurams/interface/widgets/base_puzzle.py | 60 ------------------- .../interface/widgets/base_puzzle_widget.py | 28 +++++++++ src/heurams/interface/widgets/basic_puzzle.py | 51 ++++++++++++++++ src/heurams/interface/widgets/cloze_puzzle.py | 43 +++++-------- src/heurams/interface/widgets/finished.py | 8 +-- src/heurams/interface/widgets/mcq_puzzle.py | 31 +++++----- src/heurams/interface/widgets/placeholder.py | 16 ++--- src/heurams/interface/widgets/recognition.py | 19 +++--- src/heurams/kernel/particles/__init__.py | 3 +- src/heurams/kernel/particles/atom.py | 7 ++- src/heurams/kernel/particles/loader.py | 2 +- src/heurams/services/version.py | 3 +- 13 files changed, 153 insertions(+), 132 deletions(-) create mode 100644 src/heurams/interface/shim.py delete mode 100644 src/heurams/interface/widgets/base_puzzle.py create mode 100644 src/heurams/interface/widgets/base_puzzle_widget.py create mode 100644 src/heurams/interface/widgets/basic_puzzle.py diff --git a/src/heurams/interface/shim.py b/src/heurams/interface/shim.py new file mode 100644 index 0000000..b107dff --- /dev/null +++ b/src/heurams/interface/shim.py @@ -0,0 +1,14 @@ +"""Kernel 操作辅助函数库""" +import heurams.kernel.particles as pt +staging = {} # 细粒度缓存区, 是 ident -> quality 的封装 +def report_to_staging(atom: pt.Atom, quality): + staging[atom.ident] = min(quality, staging[atom.ident]) +def clear(): + staging = dict() +def deploy_to_electron(): + for atom_ident, quality in staging.items(): + if pt.atom_registry[atom_ident].register['electron'].is_activated: + pt.atom_registry[atom_ident].register['electron'].revisor(quality=quality) + else: + pt.atom_registry[atom_ident].register['electron'].revisor(quality=quality, is_new_activation=True) + clear() \ No newline at end of file diff --git a/src/heurams/interface/widgets/base_puzzle.py b/src/heurams/interface/widgets/base_puzzle.py deleted file mode 100644 index b658b7c..0000000 --- a/src/heurams/interface/widgets/base_puzzle.py +++ /dev/null @@ -1,60 +0,0 @@ -from textual.app import App, ComposeResult -from textual.events import Event -from textual.widgets import ( - Collapsible, - Header, - Footer, - Markdown, - ListView, - ListItem, - Label, - Static, - Button, -) -from textual.containers import Container, Horizontal, Center -from textual.screen import Screen -from textual.widget import Widget -import uuid -from typing import Tuple, Dict -import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz -import re -import random -import copy - - -class BasicEvaluation(Composition): - def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): - super().__init__(screen, reactor, atom) - - def compose(self): - yield Label(self.atom[1]["content"], id="sentence") - with Container(id="button_container"): - btn = {} - btn["5"] = Button( - "完美回想", variant="success", id=self.regid("feedback5"), classes="choice" - ) - btn["4"] = Button( - "犹豫后正确", variant="success", id=self.regid("feedback4"), classes="choice" - ) - btn["3"] = Button( - "困难地正确", variant="warning", id=self.regid("feedback3"), classes="choice" - ) - btn["2"] = Button( - "错误但熟悉", variant="warning", id=self.regid("feedback2"), classes="choice" - ) - btn["1"] = Button( - "错误且不熟", variant="error", id=self.regid("feedback1"), classes="choice" - ) - btn["0"] = Button( - "完全空白", variant="error", id=self.regid("feedback0"), classes="choice" - ) - yield Horizontal(btn["5"], btn["4"]) - yield Horizontal(btn["3"], btn["2"]) - yield Horizontal(btn["1"], btn["0"]) - - def handler(self, event, type_): - if "feedback" in event.button.id: - assess = int(self.recid(event.button.id)[8:9]) - ret = self.reactor.report(self.atom, assess) - return ret \ No newline at end of file diff --git a/src/heurams/interface/widgets/base_puzzle_widget.py b/src/heurams/interface/widgets/base_puzzle_widget.py new file mode 100644 index 0000000..3787857 --- /dev/null +++ b/src/heurams/interface/widgets/base_puzzle_widget.py @@ -0,0 +1,28 @@ +from textual.app import App, ComposeResult +from textual.events import Event +from textual.widgets import ( + Collapsible, + Header, + Footer, + Markdown, + ListView, + ListItem, + Label, + Static, + Button, +) +from textual.containers import Container, Horizontal, Center +from textual.screen import Screen +from textual.widget import Widget +import uuid +from typing import Tuple, Dict +import heurams.kernel.particles as pt +import heurams.kernel.puzzles as pz +import re +import random +import copy + +class BasePuzzleWidget(Widget): + 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, name=name, id=id, classes=classes, disabled=disabled, markup=markup) + self.atom = atom \ No newline at end of file diff --git a/src/heurams/interface/widgets/basic_puzzle.py b/src/heurams/interface/widgets/basic_puzzle.py new file mode 100644 index 0000000..75db2e0 --- /dev/null +++ b/src/heurams/interface/widgets/basic_puzzle.py @@ -0,0 +1,51 @@ +from textual.widgets import ( + Markdown, + Label, + Static, + Button, +) +from textual.containers import Container, Horizontal, Center +from textual.screen import Screen +from textual.widget import Widget +import heurams.kernel.particles as pt +import heurams.kernel.puzzles as pz +from .base_puzzle_widget import BasePuzzleWidget + +class BasicEvaluation(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) + + feedback_mapping = { + "feedback_5": 5, + "feedback_4": 4, + "feedback_3": 3, + "feedback_2": 2, + "feedback_1": 1, + "feedback_0": 0, + } + + def compose(self): + yield Label(self.atom.register["nucleon"]["content"], id="main") + with Container(id="button_container"): + btn = {} + btn["5"] = Button( + "完美回想", variant="success", id="feedback_5", classes="choice" + ) + btn["4"] = Button( + "犹豫后正确", variant="success", id="feedback_4", classes="choice" + ) + btn["3"] = Button( + "困难地正确", variant="warning", id="feedback_3", classes="choice" + ) + btn["2"] = Button( + "错误但熟悉", variant="warning", id="feedback_2", classes="choice" + ) + btn["1"] = Button( + "错误且不熟", variant="error", id="feedback_1", classes="choice" + ) + btn["0"] = Button( + "完全空白", variant="error", id="feedback_0", classes="choice" + ) + yield Horizontal(btn["5"], btn["4"]) + yield Horizontal(btn["3"], btn["2"]) + yield Horizontal(btn["1"], btn["0"]) \ No newline at end of file diff --git a/src/heurams/interface/widgets/cloze_puzzle.py b/src/heurams/interface/widgets/cloze_puzzle.py index 1a2773b..8302110 100644 --- a/src/heurams/interface/widgets/cloze_puzzle.py +++ b/src/heurams/interface/widgets/cloze_puzzle.py @@ -1,12 +1,5 @@ -from textual.app import App, ComposeResult -from textual.events import Event from textual.widgets import ( - Collapsible, - Header, - Footer, Markdown, - ListView, - ListItem, Label, Static, Button, @@ -14,56 +7,52 @@ from textual.widgets import ( from textual.containers import Container, Horizontal, Center from textual.screen import Screen from textual.widget import Widget -import uuid -from typing import Tuple, Dict import heurams.kernel.particles as pt import heurams.kernel.puzzles as pz -import re -import random +from .base_puzzle_widget import BasePuzzleWidget import copy +import random +from .. import shim +class ClozePuzzle(BasePuzzleWidget): -class FillBlank(Composition): - def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra:Dict = {}): - super().__init__(screen, reactor, atom) - self.extra = extra - self.inputlist = [] + 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) + self.inputlist = list() self.hashtable = {} self._work() def _work(self): - self.puzzle = pz.BlankPuzzle(self.atom[1]["content"], 2) + self.puzzle = pz.ClozePuzzle(text=self.atom.register["nucleon"]["content"], min_denominator=2) self.puzzle.refresh() self.ans = copy.copy(self.puzzle.answer) random.shuffle(self.ans) def compose(self): - if self.extra.get("feedback_msg"): - yield Label("反馈提示:" + self.extra["feedback_msg"]) - yield Label(self.puzzle.wording, id=self.regid("sentence")) - yield Label(f"当前输入: {self.inputlist}", id=self.regid("inputpreview")) + yield Label(self.puzzle.wording, id="sentence") + yield Label(f"当前输入: {self.inputlist}", id="inputpreview") for i in self.ans: self.hashtable[str(hash(i))] = i - yield Button(i, id=self.regid(f"select{hash(i)}")) - yield Button("退格", id=self.regid(f"delete")) + yield Button(i, id=f"{hash(i)}") + yield Button("退格", id=f"delete") def handler(self, event, type_): # TODO: 改动:在线错误纠正 if type_ == "button": - if self.recid(event.button.id) == "delete": + if event.button.id == "delete": if len(self.inputlist) > 0: self.inputlist.pop() else: return 1 else: - self.inputlist.append(self.hashtable[self.recid(event.button.id)[6:]]) + self.inputlist.append(self.hashtable[event.button.id[6:]]) if len(self.inputlist) < len(self.puzzle.answer): return 1 else: if self.inputlist == self.puzzle.answer: - self.reactor.report(self.atom, 4) + shim.report_to_staging(self.atom, 4) return 0 else: self.inputlist = [] - self.reactor.report(self.atom, 2) + shim.report_to_staging(self.atom, 2) return 2 \ No newline at end of file diff --git a/src/heurams/interface/widgets/finished.py b/src/heurams/interface/widgets/finished.py index fe9aae9..3df3d15 100644 --- a/src/heurams/interface/widgets/finished.py +++ b/src/heurams/interface/widgets/finished.py @@ -22,9 +22,9 @@ import re import random import copy -class Finished(Composition): - def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): - super().__init__(screen, reactor, atom) +class Finished(Widget): + def __init__(self, *children: Widget, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None: + super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup) def compose(self): - yield Label("本次记忆进程结束", id=self.regid("msg")) + yield Label("本次记忆进程结束, 下次再会!", id="finished_msg") diff --git a/src/heurams/interface/widgets/mcq_puzzle.py b/src/heurams/interface/widgets/mcq_puzzle.py index d074af5..e5f72ac 100644 --- a/src/heurams/interface/widgets/mcq_puzzle.py +++ b/src/heurams/interface/widgets/mcq_puzzle.py @@ -14,18 +14,17 @@ from textual.widgets import ( from textual.containers import Container, Horizontal, Center from textual.screen import Screen from textual.widget import Widget -import uuid from typing import Tuple, Dict import heurams.kernel.particles as pt import heurams.kernel.puzzles as pz -import re -import random +from .base_puzzle_widget import BasePuzzleWidget import copy +import random +from .. import shim - -class DrawCard(Composition): - def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): - super().__init__(screen, reactor, atom) +class DrawCard(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) self.inputlist = [] self.hashtable = {} self._work() @@ -35,30 +34,30 @@ class DrawCard(Composition): self.puzzle.refresh() def compose(self): - yield Label(self.atom[1].content.replace("/",""), id=self.regid("sentence")) - yield Label(self.puzzle.wording[len(self.inputlist)], id=self.regid("puzzle")) - yield Label(f"当前输入: {self.inputlist}", id=self.regid("inputpreview")) + yield Label(self.atom[1].content.replace("/",""), id="sentence") + yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle") + yield Label(f"当前输入: {self.inputlist}", id="inputpreview") for i in self.puzzle.options[len(self.inputlist)]: self.hashtable[str(hash(i))] = i - yield Button(i, id=self.regid(f"select{hash(i)}")) - yield Button("退格", id=self.regid(f"delete")) + yield Button(i, id=f"select{hash(i)}") + yield Button("退格", id=f"delete") def handler(self, event, type_): if type_ == "button": - if self.recid(event.button.id) == "delete": + if event.button.id == "delete": if len(self.inputlist) > 0: self.inputlist.pop() else: return 1 else: - self.inputlist.append(self.hashtable[self.recid(event.button.id)[6:]]) + self.inputlist.append(self.hashtable[event.button.id[6:]]) if len(self.inputlist) < len(self.puzzle.answer): return 1 else: if self.inputlist == self.puzzle.answer: - self.reactor.report(self.atom, 4) + shim.report_to_staging(self.atom, 4) return 0 else: self.inputlist = [] - self.reactor.report(self.atom, 2) + shim.report_to_staging(self.atom, 2) return 2 \ No newline at end of file diff --git a/src/heurams/interface/widgets/placeholder.py b/src/heurams/interface/widgets/placeholder.py index 77f166c..7fb97ba 100644 --- a/src/heurams/interface/widgets/placeholder.py +++ b/src/heurams/interface/widgets/placeholder.py @@ -11,20 +11,12 @@ from textual.widgets import ( Static, Button, ) -from textual.containers import Container, Horizontal, Center -from textual.screen import Screen from textual.widget import Widget -import uuid -from typing import Tuple, Dict -import heurams.kernel.particles as pt -import heurams.kernel.puzzles as pz -import re -import random -import copy -class Placeholder(Composition): - def __init__(self, screen: Screen, extra = {}): - self.screen = screen + +class Placeholder(Widget): + def __init__(self, *children: Widget, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None: + super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup) def compose(self): yield Label("示例标签", id="testlabel") diff --git a/src/heurams/interface/widgets/recognition.py b/src/heurams/interface/widgets/recognition.py index 44c666b..886749d 100644 --- a/src/heurams/interface/widgets/recognition.py +++ b/src/heurams/interface/widgets/recognition.py @@ -21,10 +21,12 @@ import heurams.kernel.puzzles as pz import re import random import copy +from .base_puzzle_widget import BasePuzzleWidget +from .. import shim -class Recognition(Composition): - def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): - super().__init__(screen, reactor, atom) +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) def compose(self): with Center(): @@ -49,7 +51,7 @@ class Recognition(Composition): with Center(): yield Label( f"[b][b]{i.replace('/', ' ')}[/][/]", - id=self.regid("sentence" + str(hash(i))), + id="sentence" + str(hash(i)), ) for i in self.atom[2]["testdata"]["additional_inf"]: if self.atom[1][i]: @@ -60,15 +62,14 @@ class Recognition(Composition): if isinstance(self.atom[1][i], Dict): t = "" for j, k in self.atom[1][i].items(): # type: ignore - # 弱智的 Pylance 类型推导 t += f"> **{j}**: {k} \n" - yield Markdown(t, id=self.regid("tran")) + yield Markdown(t, id="tran") with Center(): - yield Button("我已知晓", id=self.regid("ok")) + yield Button("我已知晓", id="ok") def handler(self, event, type_): if type_ == "button": - if event.button.id == self.getid("ok"): - self.reactor.report(self.atom, 5) + if event.button.id == "ok": + shim.report_to_staging(self.atom, 5) return 0 return -1 diff --git a/src/heurams/kernel/particles/__init__.py b/src/heurams/kernel/particles/__init__.py index d8fd87c..8e26462 100644 --- a/src/heurams/kernel/particles/__init__.py +++ b/src/heurams/kernel/particles/__init__.py @@ -1,7 +1,7 @@ from .electron import Electron from .nucleon import Nucleon from .orbital import Orbital -from .atom import Atom +from .atom import Atom, atom_registry from .probe import probe_all, probe_by_filename from .loader import load_nucleon, load_electron @@ -14,4 +14,5 @@ __all__ = [ "probe_by_filename", "load_nucleon", "load_electron", + "atom_registry", ] \ No newline at end of file diff --git a/src/heurams/kernel/particles/atom.py b/src/heurams/kernel/particles/atom.py index 6215990..51daa20 100644 --- a/src/heurams/kernel/particles/atom.py +++ b/src/heurams/kernel/particles/atom.py @@ -6,6 +6,7 @@ import pathlib import typing import toml import json +import bidict class AtomRegister(TypedDict): nucleon: Nucleon @@ -17,6 +18,7 @@ class AtomRegister(TypedDict): orbital: Orbital orbital_path: pathlib.Path orbital_fmt: str + runtime: dict class Atom(): """ @@ -29,6 +31,7 @@ class Atom(): def __init__(self, ident = ""): self.ident = ident + atom_registry[ident] = self self.register: AtomRegister = { # type: ignore "nucleon": None, "nucleon_path": None, @@ -76,4 +79,6 @@ class Atom(): @staticmethod def placeholder(): - return (Electron.placeholder(), Nucleon.placeholder(), {}) \ No newline at end of file + return (Electron.placeholder(), Nucleon.placeholder(), {}) + +atom_registry: bidict.bidict[str, Atom] = bidict.bidict() diff --git a/src/heurams/kernel/particles/loader.py b/src/heurams/kernel/particles/loader.py index 42aba06..743db61 100644 --- a/src/heurams/kernel/particles/loader.py +++ b/src/heurams/kernel/particles/loader.py @@ -23,4 +23,4 @@ def load_electron(path: pathlib.Path, fmt = "json"): lst = list() for item, attr in dictdata.items(): lst.append(Electron(hasher.hash(item), attr)) - return lst \ No newline at end of file + return lst diff --git a/src/heurams/services/version.py b/src/heurams/services/version.py index aa3214e..285ea0c 100644 --- a/src/heurams/services/version.py +++ b/src/heurams/services/version.py @@ -1,4 +1,5 @@ # 版本控制集成服务 ver = "0.4.0" -stage = "prototype" \ No newline at end of file +stage = "prototype" +codename = "fledge" # 雏鸟, 0.4.x 版本 \ No newline at end of file