Compare commits

..

2 Commits

Author SHA1 Message Date
8b691d9db8 chore: 修改版本文本 2026-04-30 04:52:17 +08:00
2625632e9c fix(interface): 修复持久化问题 2026-04-30 04:45:05 +08:00
13 changed files with 1241 additions and 465 deletions

View File

@@ -124,21 +124,18 @@ graph LR
Algodata[(algodata.json)] Algodata[(algodata.json)]
Schedule[(schedule.toml)] Schedule[(schedule.toml)]
end end
subgraph "运行时组装" subgraph "运行时组装"
Nucleon -->|内容| Atom Nucleon -->|内容| Atom
Electron -->|状态| Atom Electron -->|状态| Atom
Orbital -->|策略| Atom Orbital -->|策略| Atom
end end
Payload --> Nucleon Payload -->|Repo| Nucleon
Common --> Nucleon Common -->|Repo| Nucleon
Algodata --> Electron Algodata -->|Repo| Electron
Schedule --> Orbital Schedule -->|Repo| Orbital
``` ```
______________________________________________________________________
## 调度反应器 (Reactor) ## 调度反应器 (Reactor)
调度反应器是核心业务流程引擎, 采用三层嵌套的有限状态机设计 (基于 `transitions` 库). 调度反应器是核心业务流程引擎, 采用三层嵌套的有限状态机设计 (基于 `transitions` 库).
@@ -157,12 +154,12 @@ ______________________________________________________________________
| **ExpanderState** | `exammode` | 考试模式 (正面答题) | | **ExpanderState** | `exammode` | 考试模式 (正面答题) |
| | `retronly` | 回溯模式 (仅识别) | | | `retronly` | 回溯模式 (仅识别) |
### 三层嵌套结构 ### 状态机嵌套结构
```mermaid ```mermaid
graph TB graph TB
subgraph "Router (全局路由器)" 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: 快速复习] P1[Procession 队列1: 快速复习]
P2[Procession 队列2: 新记忆] P2[Procession 队列2: 新记忆]
P3[Procession 队列3: 总复习] P3[Procession 队列3: 总复习]
@@ -222,7 +219,7 @@ Router.__init__(atoms)
└─ Algorithm.revisor(algodata, feedback) └─ Algorithm.revisor(algodata, feedback)
``` ```
______________________________________________________________________ 评分累积机制: 原子在多谜题阶段的最终评分取所有谜题的最低评分 (`min_rate`), 确保严格评估.
## 算法系统 ## 算法系统
@@ -260,11 +257,9 @@ ______________________________________________________________________
} }
``` ```
______________________________________________________________________
## 仓库系统 (Repo) ## 仓库系统 (Repo)
仓库 TOML/JSON 文件目录, 无数据库依赖. 仓库 TOML/JSON 文件目录, 无数据库依赖.
### 目录结构 ### 目录结构
@@ -303,8 +298,6 @@ classDiagram
- `_generate_particles_data()` 在初始化时自动将 payload 数据转换为 `Nucleon` 所需的格式. - `_generate_particles_data()` 在初始化时自动将 payload 数据转换为 `Nucleon` 所需的格式.
- 默认保存列表 `default_save_list = ["algodata"]`, 仅持久化算法状态. - 默认保存列表 `default_save_list = ["algodata"]`, 仅持久化算法状态.
______________________________________________________________________
## Lict 集合 ## Lict 集合
`Lict` 继承 `MutableSequence`, 同时维护列表和字典访问: `Lict` 继承 `MutableSequence`, 同时维护列表和字典访问:
@@ -320,8 +313,6 @@ lict.dicted_data # 纯字典导出
脏同步机制:修改列表时自动同步字典, 修改字典时自动同步列表. 用于 `payload``algodata` 的双模式访问需求. 脏同步机制:修改列表时自动同步字典, 修改字典时自动同步列表. 用于 `payload``algodata` 的双模式访问需求.
______________________________________________________________________
## 配置系统 (ConfigDict) ## 配置系统 (ConfigDict)
`ConfigDict` 继承 `UserDict`, 是**单例模式**的 TOML 懒加载配置管理器. `ConfigDict` 继承 `UserDict`, 是**单例模式**的 TOML 懒加载配置管理器.
@@ -361,8 +352,6 @@ with ConfigContext(test_config):
... # 临时使用测试配置 ... # 临时使用测试配置
``` ```
______________________________________________________________________
## 提供者系统 (Providers) ## 提供者系统 (Providers)
可插拔的后端实现, 通过 `providers/__init__.py` 中的字典注册. 可插拔的后端实现, 通过 `providers/__init__.py` 中的字典注册.
@@ -377,8 +366,6 @@ ______________________________________________________________________
选择方式:`services/*.toml` 中的 `provider` 字段. 选择方式:`services/*.toml` 中的 `provider` 字段.
______________________________________________________________________
## 谜题系统 (Puzzles) ## 谜题系统 (Puzzles)
谜题引擎用于在复习阶段生成评估视图: 谜题引擎用于在复习阶段生成评估视图:
@@ -393,8 +380,6 @@ ______________________________________________________________________
谜题通过轨道策略 (Orbital)在 `Expander` 中按概率展开, 每个原子可产生多个谜题, 每个谜题独立评分. 谜题通过轨道策略 (Orbital)在 `Expander` 中按概率展开, 每个原子可产生多个谜题, 每个谜题独立评分.
______________________________________________________________________
## 服务层 ## 服务层
| 服务 | 文件 | 说明 | | 服务 | 文件 | 说明 |
@@ -412,8 +397,6 @@ ______________________________________________________________________
日志系统:每个模块通过 `get_logger(__name__)` 创建自己的日志器, 日志文件 10MB 轮转, 最多 5 个备份, 追加到 `heurams.log`. 日志系统:每个模块通过 `get_logger(__name__)` 创建自己的日志器, 日志文件 10MB 轮转, 最多 5 个备份, 追加到 `heurams.log`.
______________________________________________________________________
## 复习全流程 ## 复习全流程
```mermaid ```mermaid
@@ -453,15 +436,3 @@ sequenceDiagram
Router-->>UI: 完成 (finished) Router-->>UI: 完成 (finished)
UI->>User: 显示总结 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`), 确保严格评估.

View File

@@ -50,6 +50,7 @@
```bash ```bash
# 克隆仓库 # 克隆仓库
git clone https://git.pluv27.top/pluv/HeurAMS git clone https://git.pluv27.top/pluv/HeurAMS
cd HeurAMS cd HeurAMS
# 可能需要切换到 dev 分支 # 可能需要切换到 dev 分支
@@ -60,7 +61,7 @@ git checkout dev
## 首先要安装uv, 例如通过 pip 或者其他包管理器 ## 首先要安装uv, 例如通过 pip 或者其他包管理器
python3 -m pip install uv python3 -m pip install uv
uv sync # 同步开发运行环境 uv sync --all-extras # 同步开发运行环境
uv run heurams # 验证包安装 uv run heurams # 验证包安装

View File

@@ -2,13 +2,14 @@
## 概述 ## 概述
"潜进" (HeurAMS: Heuristic Auxiliary Memorizing Scheduler, 启发式记忆辅助调度器) 是一基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划, 也是一个开放, 优雅, 易于扩展的间隔重复调度器实验平台, 旨在帮助研究者更高效地进行前沿记忆算法的研究. "潜进" (HeurAMS: Heuristic Auxiliary Memorizing Scheduler, 启发式记忆辅助调度器) 是一基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划,
也是一种开放, 优雅, 易于扩展的间隔重复调度器实验平台, 旨在帮助研究者更高效地进行前沿记忆算法的研究.
## 项目结构 ## 项目结构
这个仓库是 "潜进" 的核心程序库在 python 语言下的实现\ 这个仓库是 "潜进" 的核心程序库在 python 语言下的实现\
包含数据模型与框架, 并内置了基于 textual 框架的前端实现 (interface 子模块)\ 包含数据模型与框架, 并内置了基于 textual 框架的前端实现 (interface 子模块)\
除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams` 库, 使用框架构建其他辅助记忆功能前端或其他应用程序 除了通过内置前端进行学习外, 开发者也能在 python 环境中导入 `heurams`或使用 `RPC``heurams` 程序库实例通讯, 使用框架构建其他辅助记忆功能前端或其他应用程序
## 特性 ## 特性
@@ -19,24 +20,24 @@
- 软件开箱即用, 无需多加配置即可使用默认的 `SM-2` 算法进行学习 - 软件开箱即用, 无需多加配置即可使用默认的 `SM-2` 算法进行学习
- 此外, 算法模块是 "潜进" 内核 (heurams.kernel) 中的一等公民, 内核天然支持插拔各型算法 - 此外, 算法模块是 "潜进" 内核 (heurams.kernel) 中的一等公民, 内核天然支持插拔各型算法
- 无需安装繁杂的插件即可分单元集完成算法快速切换与调优, 研究者可以方便地修改算法模块以便捷地进行研究与测试 - 无需安装繁杂的插件即可分单元集完成算法快速切换与调优, 研究者可以方便地修改算法模块以便捷地进行研究与测试
- 内置 `SM-2` 简单间隔重复算法, 此算法亦用作 `Anki` 闪卡记忆软件的默认闪卡调度器 - 默认使用 `SM-2` 简单间隔重复算法, 此算法亦用作 `Anki` 闪卡记忆软件的默认闪卡调度器
- 还内置 `NSP-0` 筛选用非间隔重复算法以便快速筛选记忆内容, `FSRS` 先进间隔重复算法作为效率更高的调度器, 与 `SM-15M (移植自 sm.js 项目)` 复杂间隔重复算法(逆向工程) - 还内置 `NSP-0` 筛选用非间隔重复算法以便快速筛选记忆内容, `FSRS` 先进间隔重复算法作为效率更高的调度器, 与 `SM-15M (移植自 sm.js 项目)` 复杂间隔重复算法(逆向工程)
- 算法模块可以标记记忆项目, 也可以动态规划每个记忆单元的记忆间隔时间表, 动态跟踪记忆反馈数据, 以优化长期记忆保留率与稳定性 - 算法模块可以标记记忆项目, 也可以动态规划每个记忆单元的记忆间隔时间表, 动态跟踪记忆反馈数据, 以优化长期记忆保留率与稳定性
- 得益于项目的模块化架构与单元集结构设计, 一个项目甚至可以与任意种算法共存并互通, 这对研究者及想探索/实验高效率方法的用户极其友好 - 得益于项目的模块化架构与单元集结构设计, 一个项目甚至可以与任意种算法共存并互通, 这对研究者及想探索/实验高效率方法的用户极其友好
### 多模态学习进程 ### 多模态学习进程
`Anki` 的 SQLite `apkg` 包不同, 潜进项目坚持使用人类可读的文件夹组织单元集, 这带来了若干好处, 包括: 与 Anki 的 SQLite `.apkg` 包不同, 我们坚持使用人类可读的文件夹组织单元集, 这带来了若干好处, 包括:
- 人类可读: 您可以用任意工具, 乃至一个记事本自由修改记忆载荷数据而无需打开软件 - 人类可读: 您可以用任意工具, 乃至一个记事本自由修改记忆载荷数据而无需打开软件
- 元数据配置: 配置自由度极高, 可以任意组合, 重造, 乃至创造新内容 - 元数据配置: 配置自由度极高, 可以任意组合, 重造, 乃至创造新内容
- 测验, 算法与知识互相隔离: 您的记忆项目不再是单一的闪卡, 而是 `载荷(payload)``谜题(puzzle)` 通过 `元数据(typedef)` 抽象成的 `核子(nucleon)` 对象, 在程序内部和 `算法数据(algodata)` 抽象成的 `电子`, `调度设置(schedule)` 定义的 `轨道(orbital)` 共同有机组合成的运行时对象 `原子(atom)`! 这意味着一条知识不仅可以用若干不同的算法规划, 还可以用多种并行的谜题类型测验, 极大地提升您的学习效果和丰富度. 作为学习者, 您无需担忧这些概念复杂--仅需从云端下载单元集即可开箱即用上述特性! - 测验, 算法与知识互相隔离: 一条知识不再是单一的闪卡, 不仅可以用若干不同的算法规划, 还可以用多种并行的谜题类型测验, 极大地提升您的学习效果和丰富度. 作为学习者, 您无需担忧概念复杂--仅需从云端下载单元集即可开箱即用上述特性!
- 多模态学习 - 多模态学习
- 软件自身集成了文本转语音 (TTS) , 音频与语言模型 (LLM) 模块, 这些功能乃至功能本身都是可插拔, 可扩展, 可切换驱动的, 这为内容创建了极大的丰富度 - 软件自身集成了文本转语音 (TTS) , 音频与语言模型 (LLM) 模块, 这些功能乃至功能本身都是可插拔, 可扩展, 可切换驱动的, 这为内容创建了极大的丰富度
- 软件内置多种谜题类型, 包括选择题 (MCQ), 填空题 (Cloze) 与识别题 (Recognition), 您可在同一单元应用多种, 或是选择启用 - 软件内置多种谜题类型, 包括选择题 (MCQ), 填空题 (Cloze) 与识别题 (Recognition), 您可在同一单元应用多种, 或是选择启用
- 软件天然支持动态内容生成, 支持宏驱动的模板系统, 根据上下文乃至语言模型动态生成知识点的解析 - 软件天然支持动态内容生成, 支持宏驱动的模板系统, 根据上下文乃至语言模型动态生成知识点的解析
- 在间隔重复研究尚被 SuperMemo 系列独占的时代, Wozniak 就早已表示 "如果不能理解知识, 就无需记忆它". 今天, 我们依然相信理解是记忆的基石 - 在间隔重复研究尚被 SuperMemo 系列独占的时代, Wozniak 就早已表示 "如果不能理解知识, 就无需记忆它". 今天, 我们依然相信理解是记忆的基石
- 云同步与分享优化: 由于我们的记忆数据和单元集文件都是文本文件, 故可进行快速的增量同步而无需完整地上传所有文件, 并且设计天然支持分享内容的版本控制, 如果您想分享单文件, 我们也支持 .zip/.tar.gz/.tar.xz 导入与导出 - 云同步与分享优化: 由于我们的记忆数据和单元集文件都是文本文件, 故可进行快速的增量同步而无需完整地上传所有文件, 并且设计天然支持分享内容的版本控制, 如果您想分享单文件, 我们也支持导出为压缩包或合并单文本文件以通过纯文本文件形式在 pastebin 等平台分享
- 性能提升: 得益于现代且支持分块的文件组织结构, 潜进能在保持高自由度的同时仅使用 python 就能达到敏捷且低占用的用户体验 - 性能提升: 得益于现代且支持分块的文件组织结构, 潜进能在保持高自由度的同时仅使用 python 就能达到敏捷且低占用的用户体验
### 实用用户界面 ### 实用用户界面
@@ -71,10 +72,10 @@ python -m pip install heurams[all] -i https://pypi.pluv27.top/root/dev/+simple/
#### 依赖组说明 #### 依赖组说明
由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面的命令会安装所有可选依赖, 以下是依赖组列表 由于部分依赖只被少数功能需要, 所以我们把可选依赖分得比较细, 前面提供的命令会安装所有可选依赖, 以下是依赖组列表
- 基础依赖: (只能驱动程序库) - 基础依赖: (只能驱动程序库)
- tabulate: 终端表格 - tabulate: 终端表格生成
- toml: TOML 文件加载 - toml: TOML 文件加载
- transitions: 状态机依赖 - transitions: 状态机依赖
- `interface` 依赖组: (基本用户界面依赖) - `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) 文件.
### 第三方代码 ### 第三方代码

View 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
View File

@@ -0,0 +1,22 @@
使用仪器分析分子:
质谱仪 -> 质量特征, 测分子质量(最大质荷比)
红外光谱 -> 化学键和官能团
核磁共振氢谱 -> 氢原子的种类和数目
X射线衍射 -> 复杂分子, 分析键长键角
元素分析仪 -> 确定元素种类及比例, 写出实验式
元素转换:
C -> CO2
S -> SO2
H -> H2O
N -> N2 (注意)
Cl -> HCl
烷烃:
可以燃烧, 火焰较明亮
可以在光照下和卤素单质发生取代(卤素单质光照下生成自由基 发生自由基取代反应)
可以高温分解为小的烷烃和烯烃
不和酸性高锰酸钾, 酸碱反应, 不和Br2(CCl4)反应
除 CH3Br 为气体外,多溴代物为液体("油状液滴"), CBr4是固体
光照用紫外灯或强日光(太阳光直射),不能用普通白炽灯 uv含量低

View File

@@ -0,0 +1,4 @@
title = "高考化学"
package = "chmgk"
author = "__heurams__"
desc = "高考古诗文 60 篇"

View File

@@ -0,0 +1,5 @@
["临安春雨初霁"]
note = ['陆游〔宋代〕']
content = "临安/春雨/初霁/"
translation = "临安春雨初霁"
keyword_note = { "临安" = "南宋都城, 今杭州", "霁" = "雨后或雪后转晴" }

View 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" = "总复习"

View 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']"}

View File

@@ -80,7 +80,7 @@ class DashboardScreen(Screen):
from heurams.services.attic import Attic from heurams.services.attic import Attic
a = Attic("ana", {"totaltime": 0, "openpuzzles": 0, "puzzles_err": 0}) a = Attic("ana", {"totaltime": 0, "openpuzzles": 0, "puzzles_err": 0})
yield Label(f"版本 {version.ver} {version.stage.capitalize()}") # 版本信息 yield Label(f"版本 {version.ver}-{version.stage}") # 版本信息
yield Label( yield Label(
f"{round(a.data['totaltime'], 2)} 秒内处理了 {a.data['openpuzzles']} 个谜题, 正确率{'无法求解' if not a.data['openpuzzles'] else ' ' + str(round(100 * (1 - a.data['puzzles_err']/a.data['openpuzzles']), 2)) + '%'}, 平均速度{'无法求解' if not a.data['totaltime'] else ' ' + str(round(a.data['openpuzzles']/a.data['totaltime'], 2)) + ' 个每秒'}", f"{round(a.data['totaltime'], 2)} 秒内处理了 {a.data['openpuzzles']} 个谜题, 正确率{'无法求解' if not a.data['openpuzzles'] else ' ' + str(round(100 * (1 - a.data['puzzles_err']/a.data['openpuzzles']), 2)) + '%'}, 平均速度{'无法求解' if not a.data['totaltime'] else ' ' + str(round(a.data['openpuzzles']/a.data['totaltime'], 2)) + ' 个每秒'}",
id="analysis", id="analysis",

View File

@@ -15,6 +15,7 @@ from heurams.context import config_var, rootdir
from heurams.kernel.reactor import * from heurams.kernel.reactor import *
from heurams.services.favorite_service import favorite_manager from heurams.services.favorite_service import favorite_manager
from heurams.services.logger import get_logger from heurams.services.logger import get_logger
from heurams.services.attic import Attic
from .. import shim from .. import shim
@@ -136,8 +137,8 @@ class MemScreen(Screen):
from heurams.interface.widgets.finished import Finished from heurams.interface.widgets.finished import Finished
if config_var.get()["interface"]["global"]["persist_to_file"]: if config_var.get()["interface"]["global"]["persist_to_file"]:
self.save_func() self.repo.persist_to_repodir()
container.mount(Finished(is_saved=["interface"]["global"]["persist_to_file"])) container.mount(Finished(is_saved=config_var.get()["interface"]["global"]["persist_to_file"]))
def on_button_pressed(self, event): def on_button_pressed(self, event):
event.stop() event.stop()

View File

@@ -4,7 +4,7 @@ from heurams.services.logger import get_logger
logger = get_logger(__name__) logger = get_logger(__name__)
ver = "0.5.0" ver = "0.5.0"
stage = "prototype" stage = "rc.1"
codename = "fulcrum" codename = "fulcrum"
codename_cn = "支点" codename_cn = "支点"

1556
uv.lock generated

File diff suppressed because it is too large Load Diff