进一步实现 interface

This commit is contained in:
2025-11-04 00:07:40 +08:00
parent 0e08fb3a41
commit 4eaff18685
13 changed files with 153 additions and 132 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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"])

View File

@@ -1,12 +1,5 @@
from textual.app import App, ComposeResult
from textual.events import Event
from textual.widgets import ( from textual.widgets import (
Collapsible,
Header,
Footer,
Markdown, Markdown,
ListView,
ListItem,
Label, Label,
Static, Static,
Button, Button,
@@ -14,56 +7,52 @@ from textual.widgets import (
from textual.containers import Container, Horizontal, Center from textual.containers import Container, Horizontal, Center
from textual.screen import Screen from textual.screen import Screen
from textual.widget import Widget from textual.widget import Widget
import uuid
from typing import Tuple, Dict
import heurams.kernel.particles as pt import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz import heurams.kernel.puzzles as pz
import re from .base_puzzle_widget import BasePuzzleWidget
import random
import copy import copy
import random
from .. import shim
class ClozePuzzle(BasePuzzleWidget):
class FillBlank(Composition): 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:
def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra:Dict = {}): super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
super().__init__(screen, reactor, atom) self.inputlist = list()
self.extra = extra
self.inputlist = []
self.hashtable = {} self.hashtable = {}
self._work() self._work()
def _work(self): 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.puzzle.refresh()
self.ans = copy.copy(self.puzzle.answer) self.ans = copy.copy(self.puzzle.answer)
random.shuffle(self.ans) random.shuffle(self.ans)
def compose(self): def compose(self):
if self.extra.get("feedback_msg"): yield Label(self.puzzle.wording, id="sentence")
yield Label("反馈提示:" + self.extra["feedback_msg"]) yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
yield Label(self.puzzle.wording, id=self.regid("sentence"))
yield Label(f"当前输入: {self.inputlist}", id=self.regid("inputpreview"))
for i in self.ans: for i in self.ans:
self.hashtable[str(hash(i))] = i self.hashtable[str(hash(i))] = i
yield Button(i, id=self.regid(f"select{hash(i)}")) yield Button(i, id=f"{hash(i)}")
yield Button("退格", id=self.regid(f"delete")) yield Button("退格", id=f"delete")
def handler(self, event, type_): def handler(self, event, type_):
# TODO: 改动:在线错误纠正 # TODO: 改动:在线错误纠正
if type_ == "button": if type_ == "button":
if self.recid(event.button.id) == "delete": if event.button.id == "delete":
if len(self.inputlist) > 0: if len(self.inputlist) > 0:
self.inputlist.pop() self.inputlist.pop()
else: else:
return 1 return 1
else: 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): if len(self.inputlist) < len(self.puzzle.answer):
return 1 return 1
else: else:
if self.inputlist == self.puzzle.answer: if self.inputlist == self.puzzle.answer:
self.reactor.report(self.atom, 4) shim.report_to_staging(self.atom, 4)
return 0 return 0
else: else:
self.inputlist = [] self.inputlist = []
self.reactor.report(self.atom, 2) shim.report_to_staging(self.atom, 2)
return 2 return 2

View File

@@ -22,9 +22,9 @@ import re
import random import random
import copy import copy
class Finished(Composition): class Finished(Widget):
def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): 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__(screen, reactor, atom) super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
def compose(self): def compose(self):
yield Label("本次记忆进程结束", id=self.regid("msg")) yield Label("本次记忆进程结束, 下次再会!", id="finished_msg")

View File

@@ -14,18 +14,17 @@ from textual.widgets import (
from textual.containers import Container, Horizontal, Center from textual.containers import Container, Horizontal, Center
from textual.screen import Screen from textual.screen import Screen
from textual.widget import Widget from textual.widget import Widget
import uuid
from typing import Tuple, Dict from typing import Tuple, Dict
import heurams.kernel.particles as pt import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz import heurams.kernel.puzzles as pz
import re from .base_puzzle_widget import BasePuzzleWidget
import random
import copy import copy
import random
from .. import shim
class DrawCard(BasePuzzleWidget):
class DrawCard(Composition): 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:
def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
super().__init__(screen, reactor, atom)
self.inputlist = [] self.inputlist = []
self.hashtable = {} self.hashtable = {}
self._work() self._work()
@@ -35,30 +34,30 @@ class DrawCard(Composition):
self.puzzle.refresh() self.puzzle.refresh()
def compose(self): def compose(self):
yield Label(self.atom[1].content.replace("/",""), id=self.regid("sentence")) yield Label(self.atom[1].content.replace("/",""), id="sentence")
yield Label(self.puzzle.wording[len(self.inputlist)], id=self.regid("puzzle")) yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle")
yield Label(f"当前输入: {self.inputlist}", id=self.regid("inputpreview")) yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
for i in self.puzzle.options[len(self.inputlist)]: for i in self.puzzle.options[len(self.inputlist)]:
self.hashtable[str(hash(i))] = i self.hashtable[str(hash(i))] = i
yield Button(i, id=self.regid(f"select{hash(i)}")) yield Button(i, id=f"select{hash(i)}")
yield Button("退格", id=self.regid(f"delete")) yield Button("退格", id=f"delete")
def handler(self, event, type_): def handler(self, event, type_):
if type_ == "button": if type_ == "button":
if self.recid(event.button.id) == "delete": if event.button.id == "delete":
if len(self.inputlist) > 0: if len(self.inputlist) > 0:
self.inputlist.pop() self.inputlist.pop()
else: else:
return 1 return 1
else: 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): if len(self.inputlist) < len(self.puzzle.answer):
return 1 return 1
else: else:
if self.inputlist == self.puzzle.answer: if self.inputlist == self.puzzle.answer:
self.reactor.report(self.atom, 4) shim.report_to_staging(self.atom, 4)
return 0 return 0
else: else:
self.inputlist = [] self.inputlist = []
self.reactor.report(self.atom, 2) shim.report_to_staging(self.atom, 2)
return 2 return 2

View File

@@ -11,20 +11,12 @@ from textual.widgets import (
Static, Static,
Button, Button,
) )
from textual.containers import Container, Horizontal, Center
from textual.screen import Screen
from textual.widget import Widget 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 = {}): class Placeholder(Widget):
self.screen = screen 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): def compose(self):
yield Label("示例标签", id="testlabel") yield Label("示例标签", id="testlabel")

View File

@@ -21,10 +21,12 @@ import heurams.kernel.puzzles as pz
import re import re
import random import random
import copy import copy
from .base_puzzle_widget import BasePuzzleWidget
from .. import shim
class Recognition(Composition): class Recognition(BasePuzzleWidget):
def __init__(self, screen: Screen, reactor, atom: Tuple[pt.Electron, pt.Nucleon, Dict], extra = {}): 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__(screen, reactor, atom) super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
def compose(self): def compose(self):
with Center(): with Center():
@@ -49,7 +51,7 @@ class Recognition(Composition):
with Center(): with Center():
yield Label( yield Label(
f"[b][b]{i.replace('/', ' ')}[/][/]", 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"]: for i in self.atom[2]["testdata"]["additional_inf"]:
if self.atom[1][i]: if self.atom[1][i]:
@@ -60,15 +62,14 @@ class Recognition(Composition):
if isinstance(self.atom[1][i], Dict): if isinstance(self.atom[1][i], Dict):
t = "" t = ""
for j, k in self.atom[1][i].items(): # type: ignore for j, k in self.atom[1][i].items(): # type: ignore
# 弱智的 Pylance 类型推导
t += f"> **{j}**: {k} \n" t += f"> **{j}**: {k} \n"
yield Markdown(t, id=self.regid("tran")) yield Markdown(t, id="tran")
with Center(): with Center():
yield Button("我已知晓", id=self.regid("ok")) yield Button("我已知晓", id="ok")
def handler(self, event, type_): def handler(self, event, type_):
if type_ == "button": if type_ == "button":
if event.button.id == self.getid("ok"): if event.button.id == "ok":
self.reactor.report(self.atom, 5) shim.report_to_staging(self.atom, 5)
return 0 return 0
return -1 return -1

View File

@@ -1,7 +1,7 @@
from .electron import Electron from .electron import Electron
from .nucleon import Nucleon from .nucleon import Nucleon
from .orbital import Orbital from .orbital import Orbital
from .atom import Atom from .atom import Atom, atom_registry
from .probe import probe_all, probe_by_filename from .probe import probe_all, probe_by_filename
from .loader import load_nucleon, load_electron from .loader import load_nucleon, load_electron
@@ -14,4 +14,5 @@ __all__ = [
"probe_by_filename", "probe_by_filename",
"load_nucleon", "load_nucleon",
"load_electron", "load_electron",
"atom_registry",
] ]

View File

@@ -6,6 +6,7 @@ import pathlib
import typing import typing
import toml import toml
import json import json
import bidict
class AtomRegister(TypedDict): class AtomRegister(TypedDict):
nucleon: Nucleon nucleon: Nucleon
@@ -17,6 +18,7 @@ class AtomRegister(TypedDict):
orbital: Orbital orbital: Orbital
orbital_path: pathlib.Path orbital_path: pathlib.Path
orbital_fmt: str orbital_fmt: str
runtime: dict
class Atom(): class Atom():
""" """
@@ -29,6 +31,7 @@ class Atom():
def __init__(self, ident = ""): def __init__(self, ident = ""):
self.ident = ident self.ident = ident
atom_registry[ident] = self
self.register: AtomRegister = { # type: ignore self.register: AtomRegister = { # type: ignore
"nucleon": None, "nucleon": None,
"nucleon_path": None, "nucleon_path": None,
@@ -76,4 +79,6 @@ class Atom():
@staticmethod @staticmethod
def placeholder(): def placeholder():
return (Electron.placeholder(), Nucleon.placeholder(), {}) return (Electron.placeholder(), Nucleon.placeholder(), {})
atom_registry: bidict.bidict[str, Atom] = bidict.bidict()

View File

@@ -23,4 +23,4 @@ def load_electron(path: pathlib.Path, fmt = "json"):
lst = list() lst = list()
for item, attr in dictdata.items(): for item, attr in dictdata.items():
lst.append(Electron(hasher.hash(item), attr)) lst.append(Electron(hasher.hash(item), attr))
return lst return lst

View File

@@ -1,4 +1,5 @@
# 版本控制集成服务 # 版本控制集成服务
ver = "0.4.0" ver = "0.4.0"
stage = "prototype" stage = "prototype"
codename = "fledge" # 雏鸟, 0.4.x 版本