进一步实现 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 (
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(), {})
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()
for item, attr in dictdata.items():
lst.append(Electron(hasher.hash(item), attr))
return lst
return lst

View File

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