fix(interface): 修复持久化问题
This commit is contained in:
@@ -124,21 +124,18 @@ graph LR
|
||||
Algodata[(algodata.json)]
|
||||
Schedule[(schedule.toml)]
|
||||
end
|
||||
|
||||
subgraph "运行时组装"
|
||||
Nucleon -->|内容| Atom
|
||||
Electron -->|状态| Atom
|
||||
Orbital -->|策略| Atom
|
||||
end
|
||||
|
||||
Payload --> Nucleon
|
||||
Common --> Nucleon
|
||||
Algodata --> Electron
|
||||
Schedule --> Orbital
|
||||
Payload -->|Repo| Nucleon
|
||||
Common -->|Repo| Nucleon
|
||||
Algodata -->|Repo| Electron
|
||||
Schedule -->|Repo| Orbital
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 调度反应器 (Reactor)
|
||||
|
||||
调度反应器是核心业务流程引擎, 采用三层嵌套的有限状态机设计 (基于 `transitions` 库).
|
||||
@@ -157,12 +154,12 @@ ______________________________________________________________________
|
||||
| **ExpanderState** | `exammode` | 考试模式 (正面答题) |
|
||||
| | `retronly` | 回溯模式 (仅识别) |
|
||||
|
||||
### 三层嵌套结构
|
||||
### 状态机嵌套结构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Router (全局路由器)"
|
||||
R[Router<br/>状态: unsure→quick_review→recognition→final_review→finished]
|
||||
R[Router<br/>状态: unsure→quick_review<br/>→recognition→final_review<br/>→finished]
|
||||
P1[Procession 队列1: 快速复习]
|
||||
P2[Procession 队列2: 新记忆]
|
||||
P3[Procession 队列3: 总复习]
|
||||
@@ -222,7 +219,7 @@ Router.__init__(atoms)
|
||||
└─ Algorithm.revisor(algodata, feedback)
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
评分累积机制: 原子在多谜题阶段的最终评分取所有谜题的最低评分 (`min_rate`), 确保严格评估.
|
||||
|
||||
## 算法系统
|
||||
|
||||
@@ -260,11 +257,9 @@ ______________________________________________________________________
|
||||
}
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 仓库系统 (Repo)
|
||||
|
||||
仓库是 TOML/JSON 文件目录, 无数据库依赖.
|
||||
仓库为 TOML/JSON 文件目录, 无数据库依赖.
|
||||
|
||||
### 目录结构
|
||||
|
||||
@@ -303,8 +298,6 @@ classDiagram
|
||||
- `_generate_particles_data()` 在初始化时自动将 payload 数据转换为 `Nucleon` 所需的格式.
|
||||
- 默认保存列表 `default_save_list = ["algodata"]`, 仅持久化算法状态.
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## Lict 集合
|
||||
|
||||
`Lict` 继承 `MutableSequence`, 同时维护列表和字典访问:
|
||||
@@ -320,8 +313,6 @@ lict.dicted_data # 纯字典导出
|
||||
|
||||
脏同步机制:修改列表时自动同步字典, 修改字典时自动同步列表. 用于 `payload` 和 `algodata` 的双模式访问需求.
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 配置系统 (ConfigDict)
|
||||
|
||||
`ConfigDict` 继承 `UserDict`, 是**单例模式**的 TOML 懒加载配置管理器.
|
||||
@@ -361,8 +352,6 @@ with ConfigContext(test_config):
|
||||
... # 临时使用测试配置
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 提供者系统 (Providers)
|
||||
|
||||
可插拔的后端实现, 通过 `providers/__init__.py` 中的字典注册.
|
||||
@@ -377,8 +366,6 @@ ______________________________________________________________________
|
||||
|
||||
选择方式:`services/*.toml` 中的 `provider` 字段.
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 谜题系统 (Puzzles)
|
||||
|
||||
谜题引擎用于在复习阶段生成评估视图:
|
||||
@@ -393,8 +380,6 @@ ______________________________________________________________________
|
||||
|
||||
谜题通过轨道策略 (Orbital)在 `Expander` 中按概率展开, 每个原子可产生多个谜题, 每个谜题独立评分.
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 服务层
|
||||
|
||||
| 服务 | 文件 | 说明 |
|
||||
@@ -412,8 +397,6 @@ ______________________________________________________________________
|
||||
|
||||
日志系统:每个模块通过 `get_logger(__name__)` 创建自己的日志器, 日志文件 10MB 轮转, 最多 5 个备份, 追加到 `heurams.log`.
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 复习全流程
|
||||
|
||||
```mermaid
|
||||
@@ -453,15 +436,3 @@ sequenceDiagram
|
||||
Router-->>UI: 完成 (finished)
|
||||
UI->>User: 显示总结
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## 关键设计决策
|
||||
|
||||
1. **无数据库** — 所有持久化基于 TOML/JSON 文件目录, 方便版本管理和手动编辑.
|
||||
2. **Lict 双模式访问** — payload 和 algodata 同时支持列表迭代和字典查找, 兼顾批处理和随机访问.
|
||||
3. **物理隐喻分离** — 内容 (Nucleon)、状态 (Electron)、策略 (Orbital) 三者正交, 可独立替换, 便于组合不同算法和内容类型.
|
||||
4. **transitions 状态机** — 使用 `transitions` 库实现 Router → Procession → Expander 三层嵌套状态机, 每个层次职责明确.
|
||||
5. **Evalizer eval 模板** — 使用 `eval()` 实现动态模板替换, 功能灵活但存在安全风险 (标记为待替换).
|
||||
6. **配置单例** — `ConfigDict` 以规范化路径为键实现单例, 避免多实例导致的配置不一致问题.
|
||||
7. **评分累积** — 原子在多谜题阶段的最终评分取所有谜题的最低评分 (`min_rate`), 确保严格评估.
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
```bash
|
||||
# 克隆仓库
|
||||
git clone https://git.pluv27.top/pluv/HeurAMS
|
||||
|
||||
cd HeurAMS
|
||||
|
||||
# 可能需要切换到 dev 分支
|
||||
@@ -60,7 +61,7 @@ git checkout dev
|
||||
## 首先要安装uv, 例如通过 pip 或者其他包管理器
|
||||
python3 -m pip install uv
|
||||
|
||||
uv sync # 同步开发运行环境
|
||||
uv sync --all-extras # 同步开发运行环境
|
||||
|
||||
uv run heurams # 验证包安装
|
||||
|
||||
|
||||
20
README.md
20
README.md
@@ -2,13 +2,14 @@
|
||||
|
||||
## 概述
|
||||
|
||||
"潜进" (HeurAMS: Heuristic Auxiliary Memorizing Scheduler, 启发式记忆辅助调度器) 是一个基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划, 也是一个开放, 优雅, 易于扩展的间隔重复调度器实验平台, 旨在帮助研究者更高效地进行前沿记忆算法的研究.
|
||||
"潜进" (HeurAMS: Heuristic Auxiliary Memorizing Scheduler, 启发式记忆辅助调度器) 是一种基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划,
|
||||
也是一种开放, 优雅, 易于扩展的间隔重复调度器实验平台, 旨在帮助研究者更高效地进行前沿记忆算法的研究.
|
||||
|
||||
## 项目结构
|
||||
|
||||
这个仓库是 "潜进" 的核心程序库在 python 语言下的实现\
|
||||
包含数据模型与框架, 并内置了基于 textual 框架的前端实现 (interface 子模块)\
|
||||
除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams` 库, 使用框架构建其他辅助记忆功能前端或其他应用程序
|
||||
除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams` 库或使用 `RPC` 与 `heurams` 程序库实例通讯, 使用框架构建其他辅助记忆功能前端或其他应用程序
|
||||
|
||||
## 特性
|
||||
|
||||
@@ -19,24 +20,24 @@
|
||||
- 软件开箱即用, 无需多加配置即可使用默认的 `SM-2` 算法进行学习
|
||||
- 此外, 算法模块是 "潜进" 内核 (heurams.kernel) 中的一等公民, 内核天然支持插拔各型算法
|
||||
- 无需安装繁杂的插件即可分单元集完成算法快速切换与调优, 研究者可以方便地修改算法模块以便捷地进行研究与测试
|
||||
- 内置 `SM-2` 简单间隔重复算法, 此算法亦用作 `Anki` 闪卡记忆软件的默认闪卡调度器
|
||||
- 默认使用 `SM-2` 简单间隔重复算法, 此算法亦用作 `Anki` 闪卡记忆软件的默认闪卡调度器
|
||||
- 还内置 `NSP-0` 筛选用非间隔重复算法以便快速筛选记忆内容, `FSRS` 先进间隔重复算法作为效率更高的调度器, 与 `SM-15M (移植自 sm.js 项目)` 复杂间隔重复算法(逆向工程)
|
||||
- 算法模块可以标记记忆项目, 也可以动态规划每个记忆单元的记忆间隔时间表, 动态跟踪记忆反馈数据, 以优化长期记忆保留率与稳定性
|
||||
- 得益于项目的模块化架构与单元集结构设计, 一个项目甚至可以与任意种算法共存并互通, 这对研究者及想探索/实验高效率方法的用户极其友好
|
||||
|
||||
### 多模态学习进程
|
||||
|
||||
与 `Anki` 的 SQLite `apkg` 包不同, 潜进项目坚持使用人类可读的文件夹组织单元集, 这带来了若干好处, 包括:
|
||||
与 Anki 的 SQLite `.apkg` 包不同, 我们坚持使用人类可读的文件夹组织单元集, 这带来了若干好处, 包括:
|
||||
|
||||
- 人类可读: 您可以用任意工具, 乃至一个记事本自由修改记忆载荷数据而无需打开软件
|
||||
- 元数据配置: 配置自由度极高, 可以任意组合, 重造, 乃至创造新内容
|
||||
- 测验, 算法与知识互相隔离: 您的记忆项目不再是单一的闪卡, 而是 `载荷(payload)` 和 `谜题(puzzle)` 通过 `元数据(typedef)` 抽象成的 `核子(nucleon)` 对象, 在程序内部和 `算法数据(algodata)` 抽象成的 `电子`, `调度设置(schedule)` 定义的 `轨道(orbital)` 共同有机组合成的运行时对象 `原子(atom)`! 这意味着一条知识不仅可以用若干不同的算法规划, 还可以用多种并行的谜题类型测验, 极大地提升您的学习效果和丰富度. 作为学习者, 您无需担忧这些概念复杂--仅需从云端下载单元集即可开箱即用上述特性!
|
||||
- 测验, 算法与知识互相隔离: 一条知识不再是单一的闪卡, 不仅可以用若干不同的算法规划, 还可以用多种并行的谜题类型测验, 极大地提升您的学习效果和丰富度. 作为学习者, 您无需担忧概念复杂--仅需从云端下载单元集即可开箱即用上述特性!
|
||||
- 多模态学习
|
||||
- 软件自身集成了文本转语音 (TTS) , 音频与语言模型 (LLM) 模块, 这些功能乃至功能本身都是可插拔, 可扩展, 可切换驱动的, 这为内容创建了极大的丰富度
|
||||
- 软件内置多种谜题类型, 包括选择题 (MCQ), 填空题 (Cloze) 与识别题 (Recognition), 您可在同一单元应用多种, 或是选择启用
|
||||
- 软件天然支持动态内容生成, 支持宏驱动的模板系统, 根据上下文乃至语言模型动态生成知识点的解析
|
||||
- 在间隔重复研究尚被 SuperMemo 系列独占的时代, Wozniak 就早已表示 "如果不能理解知识, 就无需记忆它". 今天, 我们依然相信理解是记忆的基石
|
||||
- 云同步与分享优化: 由于我们的记忆数据和单元集文件都是文本文件, 故可进行快速的增量同步而无需完整地上传所有文件, 并且设计天然支持分享内容的版本控制, 如果您想分享单文件, 我们也支持 .zip/.tar.gz/.tar.xz 导入与导出
|
||||
- 云同步与分享优化: 由于我们的记忆数据和单元集文件都是文本文件, 故可进行快速的增量同步而无需完整地上传所有文件, 并且设计天然支持分享内容的版本控制, 如果您想分享单文件, 我们也支持导出为压缩包或合并单文本文件以通过纯文本文件形式在 pastebin 等平台分享
|
||||
- 性能提升: 得益于现代且支持分块的文件组织结构, 潜进能在保持高自由度的同时仅使用 python 就能达到敏捷且低占用的用户体验
|
||||
|
||||
### 实用用户界面
|
||||
@@ -71,10 +72,10 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
|
||||
|
||||
#### 依赖组说明
|
||||
|
||||
由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面的命令会安装所有可选依赖, 以下是依赖组列表
|
||||
由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面提供的命令会安装所有可选依赖, 以下是依赖组列表
|
||||
|
||||
- 基础依赖: (只能驱动程序库)
|
||||
- tabulate: 终端表格
|
||||
- tabulate: 终端表格生成
|
||||
- toml: TOML 文件加载
|
||||
- transitions: 状态机依赖
|
||||
- `interface` 依赖组: (基本用户界面依赖)
|
||||
@@ -115,7 +116,8 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
|
||||
|
||||
### 项目本身
|
||||
|
||||
本项目基于 AGPL-3.0 许可证开源. 详见根目录下 [LICENSE](LICENSE) 文件.
|
||||
本项目基于 AGPL-3.0 许可证开放源代码.
|
||||
详见根目录下 [LICENSE](LICENSE) 文件.
|
||||
|
||||
### 第三方代码
|
||||
|
||||
|
||||
14
data/repo/chmgk/algodata.json
Normal file
14
data/repo/chmgk/algodata.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"临安春雨初霁": {
|
||||
"SM-2": {
|
||||
"efactor": 2.5,
|
||||
"real_rept": 2,
|
||||
"rept": 0,
|
||||
"interval": 1,
|
||||
"last_date": 20573,
|
||||
"next_date": 20574,
|
||||
"is_activated": 1,
|
||||
"last_modify": 1777521623.7446923
|
||||
}
|
||||
}
|
||||
}
|
||||
22
data/repo/chmgk/draft.txt
Normal file
22
data/repo/chmgk/draft.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
使用仪器分析分子:
|
||||
质谱仪 -> 质量特征, 测分子质量(最大质荷比)
|
||||
红外光谱 -> 化学键和官能团
|
||||
核磁共振氢谱 -> 氢原子的种类和数目
|
||||
X射线衍射 -> 复杂分子, 分析键长键角
|
||||
元素分析仪 -> 确定元素种类及比例, 写出实验式
|
||||
元素转换:
|
||||
C -> CO2
|
||||
S -> SO2
|
||||
H -> H2O
|
||||
N -> N2 (注意)
|
||||
Cl -> HCl
|
||||
|
||||
烷烃:
|
||||
可以燃烧, 火焰较明亮
|
||||
可以在光照下和卤素单质发生取代(卤素单质光照下生成自由基 发生自由基取代反应)
|
||||
可以高温分解为小的烷烃和烯烃
|
||||
不和酸性高锰酸钾, 酸碱反应, 不和Br2(CCl4)反应
|
||||
除 CH3Br 为气体外,多溴代物为液体("油状液滴"), CBr4是固体
|
||||
光照用紫外灯或强日光(太阳光直射),不能用普通白炽灯 uv含量低
|
||||
|
||||
|
||||
4
data/repo/chmgk/manifest.toml
Normal file
4
data/repo/chmgk/manifest.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
title = "高考化学"
|
||||
package = "chmgk"
|
||||
author = "__heurams__"
|
||||
desc = "高考古诗文 60 篇"
|
||||
5
data/repo/chmgk/payload.toml
Normal file
5
data/repo/chmgk/payload.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
["临安春雨初霁"]
|
||||
note = ['陆游〔宋代〕']
|
||||
content = "临安/春雨/初霁/"
|
||||
translation = "临安春雨初霁"
|
||||
keyword_note = { "临安" = "南宋都城, 今杭州", "霁" = "雨后或雪后转晴" }
|
||||
11
data/repo/chmgk/schedule.toml
Normal file
11
data/repo/chmgk/schedule.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
schedule = ["quick_review", "recognition", "final_review"]
|
||||
|
||||
[routes]
|
||||
quick_review = [["SelectMeaning", "1.0"], ["Recognition", "1.0"]]
|
||||
recognition = [["Recognition", "1.0"]]
|
||||
final_review = [["FillBlank", "1.0"], ["Recognition", "1.0"]]
|
||||
|
||||
[annotation]
|
||||
"quick_review" = "复习旧知"
|
||||
"recognition" = "新知识"
|
||||
"final_review" = "总复习"
|
||||
17
data/repo/chmgk/typedef.toml
Normal file
17
data/repo/chmgk/typedef.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[annotation]
|
||||
note = "笔记"
|
||||
keyword_note = "关键词翻译"
|
||||
translation = "语句翻译"
|
||||
delimiter = "分隔符"
|
||||
content = "内容"
|
||||
tts_text = "文本转语音文本"
|
||||
|
||||
[common]
|
||||
delimiter = "/"
|
||||
tts_text = "eval:payload['content'].replace('/', '')"
|
||||
|
||||
[common.puzzles] # 谜题定义
|
||||
# 我们称 "Recognition" 为 recognition 谜题的 alia
|
||||
"Recognition" = { __origin__ = "recognition", __hint__ = "", primary = "eval:payload['content']", secondary = ["eval:payload['keyword_note']", "eval:payload['note']"], top_dim = ["eval:payload['translation']"] }
|
||||
"SelectMeaning" = { __origin__ = "mcq", __hint__ = "eval:payload['content']", primary = "eval:payload['content']", mapping = "eval:payload['keyword_note']", jammer = "eval:list(payload['keyword_note'].values())", max_riddles_num = "eval:default['mcq']['max_riddles_num']", prefix = "选择正确项: " }
|
||||
"FillBlank" = { __origin__ = "cloze", __hint__ = "", text = "eval:payload['content']", delimiter = "eval:nucleon['delimiter']", min_denominator = "eval:default['cloze']['min_denominator']"}
|
||||
@@ -15,6 +15,7 @@ from heurams.context import config_var, rootdir
|
||||
from heurams.kernel.reactor import *
|
||||
from heurams.services.favorite_service import favorite_manager
|
||||
from heurams.services.logger import get_logger
|
||||
from heurams.services.attic import Attic
|
||||
|
||||
from .. import shim
|
||||
|
||||
@@ -136,8 +137,8 @@ class MemScreen(Screen):
|
||||
from heurams.interface.widgets.finished import Finished
|
||||
|
||||
if config_var.get()["interface"]["global"]["persist_to_file"]:
|
||||
self.save_func()
|
||||
container.mount(Finished(is_saved=["interface"]["global"]["persist_to_file"]))
|
||||
self.repo.persist_to_repodir()
|
||||
container.mount(Finished(is_saved=config_var.get()["interface"]["global"]["persist_to_file"]))
|
||||
|
||||
def on_button_pressed(self, event):
|
||||
event.stop()
|
||||
|
||||
Reference in New Issue
Block a user