feat: 开发 unifront 前端会话模块

This commit is contained in:
2026-04-21 16:52:04 +08:00
parent 9dd6733063
commit e65db69fc6
26 changed files with 191 additions and 73 deletions

View File

@@ -1271,7 +1271,7 @@ class SM:
self.ofm = OFM(self)
def _find_index_to_insert(self, item, r=None):
"""Binary search to find insertion index for sorted queue."""
"""Binary search to find insertion index for sorted procession."""
if r is None:
r = list(range(len(self.q)))
@@ -1290,7 +1290,7 @@ class SM:
return self._find_index_to_insert(item, r[i:])
def add_item(self, value):
"""Add a new item to the queue."""
"""Add a new item to the procession."""
item = Item(self, value)
index = self._find_index_to_insert(item)
self.q.insert(index, item)
@@ -1330,7 +1330,7 @@ class SM:
item.answer(grade, now)
def discard(self, item):
"""Remove item from queue."""
"""Remove item from procession."""
if item in self.q:
self.q.remove(item)

View File

@@ -7,8 +7,8 @@
orbital, 即轨道, 是定义队列式复习阶段流程的数据结构, 其实就是个字典, 至于为何不用typeddict, 因为懒.
orbital_example = {
"schedule": [列表 存储阶段(phases)名称]
"phases":{
"schedule": [列表 存储阶段(routes)名称]
"routes":{
阶段名称 = [["谜题(puzzle 现称 Puzzles 评估器)名称", "概率系数 可大于1(整数部分为重复次数) 注意使用字符串包裹(toml 规范)"], ...],
...
}

View File

@@ -6,7 +6,7 @@ from .nucleon import Nucleon
orbital_placeholder = {
"schedule": ["quick_review", "recognition", "final_review"],
"phases": {
"routes": {
"quick_review": [
["FillBlank", 1.0],
["SelectMeaning", 0.5],

View File

@@ -83,16 +83,16 @@ Router 的 __repr__ 定义了此对象"官方的显示"用作直观的调试.\
- current_atom: 当前记忆原子的引用
- atoms: 队列中所有原子列表
- cursor: 指针, 是当前原子在 atoms 列表中的索引
- phase: "阶段属性"
- route: "阶段属性"
> 注意区分 "Router" 和 "Phase", 其中 "Phase" 表示 "Router State".
> 注意区分 "Router" 和 "Route", 其中 "Route" 表示 "Router State".
- name\_: 阶段的命名
- state: 当前状态属性
### 初始化
接受一个 atoms 列表与 phase_state (RouterState Enum 类型)对象
接受一个 atoms 列表与 route_state (RouterState Enum 类型)对象
### 直接输出呈现形式
@@ -100,12 +100,12 @@ Router 的 __repr__ 定义了此对象"官方的显示"用作直观的调试.\
与 Router 不同, Procession 显示队列会对过长的 atom.ident 进行缩略(末尾 `>` 符号)
```text
| Type | Name | State | Progress | Queue | Current Atom |
| Type | Name | State | Progress | Procession | Current Atom |
| :--------- | :----- | :----- | :------- | :--------------------- | :---------------------------- |
| Procession | 新记忆 | active | 1 / 2 | ['秦孝公>', '君臣固>'] | 秦孝公据崤函之固, 拥雍州之地, |
```
| Type | Name | State | Progress | Queue | Current Atom |
| Type | Name | State | Progress | Procession | Current Atom |
| :--------- | :----- | :----- | :------- | :--------------------- | :---------------------------- |
| Procession | 新记忆 | active | 1 / 2 | ['秦孝公>', '君臣固>'] | 秦孝公据崤函之固, 拥雍州之地, |
@@ -166,7 +166,7 @@ Router 的 __repr__ 定义了此对象"官方的显示"用作直观的调试.\
### 初始化
接受 atom 对象和 phase 参数
接受 atom 对象和 route 参数
### 方法

View File

@@ -16,13 +16,13 @@ logger = get_logger(__name__)
class Expander(Machine):
"""单原子调度展开器"""
def __init__(self, atom: pt.Atom, phase=RouterState.RECOGNITION):
self.phase = phase
def __init__(self, atom: pt.Atom, route=RouterState.RECOGNITION):
self.route = route
self.cursor = 0
self.atom = atom
self.current_puzzle_inf: dict
# phase 为 RouterState 枚举实例, 需要获取其value
phase_value = phase.value
# route 为 RouterState 枚举实例, 需要获取其value
route_value = route.value
states = [
{"name": ExpanderState.EXAMMODE.value},
{"name": ExpanderState.RETRONLY.value},
@@ -35,7 +35,7 @@ class Expander(Machine):
"dest": ExpanderState.RETRONLY.value,
},
]
if phase == RouterState.FINISHED:
if route == RouterState.FINISHED:
Machine.__init__(
self,
states=states,
@@ -43,7 +43,7 @@ class Expander(Machine):
initial=ExpanderState.EXAMMODE.value,
)
return
orbital_schedule = atom.registry["orbital"]["phases"][phase_value] # type: ignore
orbital_schedule = atom.registry["orbital"]["routes"][route_value] # type: ignore
orbital_puzzles = atom.registry["nucleon"]["puzzles"]
self.puzzles_inf = list()
self.min_ratings = []
@@ -122,7 +122,9 @@ class Expander(Machine):
"Atom": truncate(self.atom.ident),
"State": self.state,
"Progress": f"{self.cursor + 1} / {len(self.puzzles_inf)}",
"Queue": list(map(lambda f: truncate(f["alia"]), self.puzzles_inf)),
"Procession": list(
map(lambda f: truncate(f["alia"]), self.puzzles_inf)
),
"Current Puzzle": f"{self.current_puzzle_inf['alia']}@{self.current_puzzle_inf['puzzle'].__name__}", # type: ignore
}
]

View File

@@ -13,11 +13,11 @@ logger = get_logger(__name__)
class Procession(Machine):
"""队列: 标识单次记忆流程"""
def __init__(self, atoms: list, phase_state: RouterState, name_: str = ""):
def __init__(self, atoms: list, route_state: RouterState, name_: str = ""):
logger.debug(
"Procession.__init__: 原子数量=%d, phase=%s, name='%s'",
"Procession.__init__: 原子数量=%d, route=%s, name='%s'",
len(atoms),
phase_state.value,
route_state.value,
name_,
)
self.current_atom: pt.Atom | None
@@ -25,7 +25,7 @@ class Procession(Machine):
self.current_atom = atoms[0] if atoms else None
self.cursor = 0
self.name_ = name_
self.phase = phase_state
self.route = route_state
states = [
{"name": ProcessionState.ACTIVE.value, "on_enter": "on_active"},
@@ -114,7 +114,7 @@ class Procession(Machine):
return empty
def get_expander(self):
return Expander(atom=self.current_atom, phase=self.phase) # type: ignore
return Expander(atom=self.current_atom, route=self.route) # type: ignore
def __repr__(self, style="pipe", ends="\n"):
from heurams.services.textproc import truncate
@@ -125,7 +125,7 @@ class Procession(Machine):
"Name": self.name_,
"State": self.state,
"Progress": f"{self.cursor + 1} / {len(self.atoms)}",
"Queue": list(map(lambda f: truncate(f.ident), self.atoms)),
"Procession": list(map(lambda f: truncate(f.ident), self.atoms)),
"Current Atom": self.current_atom.ident, # type: ignore
}
]

View File

@@ -11,10 +11,10 @@ logger = get_logger(__name__)
class Router(Machine):
"""全局调度阶段管理"""
"""全局调度阶段路由"""
def __init__(self, atoms: list[pt.Atom]) -> None:
logger.debug("Router.__init__: 原子数量=%d", len(atoms))
logger.debug(f"Router.__init__: 原子数量={len(atoms)}")
self.atoms = atoms
new_atoms = list()
@@ -26,9 +26,10 @@ class Router(Machine):
else:
old_atoms.append(i)
logger.debug("新原子数量=%d, 旧原子数量=%d", len(new_atoms), len(old_atoms))
logger.debug(f"新原子数量={len(new_atoms)}, 旧原子数量={len(old_atoms)}")
self.processions = list()
"""路由中的所有队列"""
# TODO: 改进为基于配置文件的可选复习阶段
if len(old_atoms):
self.processions.append(
@@ -116,15 +117,15 @@ class Router(Machine):
for i in self.processions:
i: Procession
if i.state != ProcessionState.FINISHED.value:
# if i.phase == RouterState.UNSURE: 此判断是不必要的 因为没有这种 Procession
if i.phase == RouterState.QUICK_REVIEW:
# if i.route == RouterState.UNSURE: 此判断是不必要的 因为没有这种 Procession
if i.route == RouterState.QUICK_REVIEW:
self.to_quick_review()
elif i.phase == RouterState.RECOGNITION:
elif i.route == RouterState.RECOGNITION:
self.to_recognition()
elif i.phase == RouterState.FINAL_REVIEW:
elif i.route == RouterState.FINAL_REVIEW:
self.to_final_review()
logger.debug("找到未完成的 Procession: phase=%s", i.phase)
logger.debug("找到未完成的 Procession: route=%s", i.route)
return i
# 所有Procession都已完成