You've already forked HeurAMS-legacy
format
This commit is contained in:
@@ -5,25 +5,25 @@
|
|||||||
|
|
||||||
## 开发流程
|
## 开发流程
|
||||||
|
|
||||||
1. **分支划分**:
|
1. **分支划分**:
|
||||||
- `main` 分支:稳定版本
|
- `main` 分支: 稳定版本
|
||||||
- `develop` 分支:开发版本
|
- `develop` 分支: 开发版本
|
||||||
- 功能分支:从 `develop` 分支创建,命名格式为 `feature/描述` 或 `fix/描述`
|
- 功能分支: 从 `develop` 分支创建, 命名格式为 `feature/描述` 或 `fix/描述`
|
||||||
2. **代码风格**:
|
2. **代码风格**:
|
||||||
- 请使用 Black 格式化代码
|
- 请使用 Black 格式化代码
|
||||||
- 遵循 PEP 8 规范
|
- 遵循 PEP 8 规范
|
||||||
- 添加适当的文档字符串
|
- 添加适当的文档字符串
|
||||||
3. **提交消息**:
|
3. **提交消息**:
|
||||||
- 使用中文或英文撰写清晰的提交消息
|
- 使用中文或英文撰写清晰的提交消息
|
||||||
- 格式:`类型: 描述`,例如 `fix: 修复登录错误` 或 `feat: 添加新算法`
|
- 格式: `类型: 描述`, 例如 `fix: 修复登录错误` 或 `feat: 添加新算法`
|
||||||
4. **测试**:
|
4. **测试**:
|
||||||
- 为新功能添加单元测试
|
- 为新功能添加单元测试
|
||||||
- 确保所有测试通过
|
- 确保所有测试通过
|
||||||
- 运行 `pytest` 检查
|
- 运行 `pytest` 检查
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
请参阅 README.md 中的项目结构部分,了解代码组织方式。
|
请参阅 README.md 中的项目结构部分, 了解代码组织方式.
|
||||||
|
|
||||||
## 设置开发环境
|
## 设置开发环境
|
||||||
|
|
||||||
@@ -41,4 +41,4 @@ pip install -e .
|
|||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
贡献者同意其贡献将在 AGPL-3.0 许可证下发布。
|
贡献者同意其贡献将在 AGPL-3.0 许可证下发布.
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -19,17 +19,17 @@
|
|||||||
## 特性
|
## 特性
|
||||||
|
|
||||||
### 间隔迭代算法
|
### 间隔迭代算法
|
||||||
> 许多出版物都广泛讨论了不同重复间隔对学习效果的影响。特别是,间隔效应被认为是一种普遍现象。间隔效应是指,如果重复的间隔是分散/稀疏的,而不是集中重复,那么学习任务的表现会更好。因此,有观点提出,学习中使用的最佳重复间隔是**最长的、但不会导致遗忘的间隔**。
|
> 许多出版物都广泛讨论了不同重复间隔对学习效果的影响. 特别是, 间隔效应被认为是一种普遍现象. 间隔效应是指, 如果重复的间隔是分散/稀疏的, 而不是集中重复, 那么学习任务的表现会更好. 因此, 有观点提出, 学习中使用的最佳重复间隔是**最长的、但不会导致遗忘的间隔**.
|
||||||
- 采用经实证的 SM-2 间隔迭代算法, 此算法亦用作 Anki 闪卡记忆软件的默认闪卡调度器
|
- 采用经实证的 SM-2 间隔迭代算法, 此算法亦用作 Anki 闪卡记忆软件的默认闪卡调度器
|
||||||
- 动态规划每个记忆单元的记忆间隔时间表
|
- 动态规划每个记忆单元的记忆间隔时间表
|
||||||
- 动态跟踪记忆反馈数据,优化长期记忆保留率与稳定性
|
- 动态跟踪记忆反馈数据, 优化长期记忆保留率与稳定性
|
||||||
|
|
||||||
### 学习进程优化
|
### 学习进程优化
|
||||||
- 逐字解析:支持逐字详细释义解析
|
- 逐字解析: 支持逐字详细释义解析
|
||||||
- 语法分析:接入生成式人工智能, 支持古文结构交互式解析
|
- 语法分析: 接入生成式人工智能, 支持古文结构交互式解析
|
||||||
- 自然语音:集成微软神经网络文本转语音 (TTS) 技术
|
- 自然语音: 集成微软神经网络文本转语音 (TTS) 技术
|
||||||
- 多种谜题类型:选择题 (MCQ)、填空题 (Cloze)、识别题 (Recognition)
|
- 多种谜题类型: 选择题 (MCQ)、填空题 (Cloze)、识别题 (Recognition)
|
||||||
- 动态内容生成:支持宏驱动的模板系统,根据上下文动态生成题目
|
- 动态内容生成: 支持宏驱动的模板系统, 根据上下文动态生成题目
|
||||||
|
|
||||||
### 实用用户界面
|
### 实用用户界面
|
||||||
- 响应式 Textual 框架构建的跨平台 TUI 界面
|
- 响应式 Textual 框架构建的跨平台 TUI 界面
|
||||||
@@ -37,27 +37,27 @@
|
|||||||
- 简洁直观的复习流程设计
|
- 简洁直观的复习流程设计
|
||||||
|
|
||||||
### 架构特性
|
### 架构特性
|
||||||
- 模块化设计:算法、谜题、服务提供者可插拔替换
|
- 模块化设计: 算法、谜题、服务提供者可插拔替换
|
||||||
- 上下文管理:使用 ContextVar 实现隐式依赖注入
|
- 上下文管理: 使用 ContextVar 实现隐式依赖注入
|
||||||
- 数据持久化:TOML 配置与内容,JSON 算法状态
|
- 数据持久化: TOML 配置与内容, JSON 算法状态
|
||||||
- 服务抽象:音频播放、TTS、LLM 通过 provider 架构支持多种后端
|
- 服务抽象: 音频播放、TTS、LLM 通过 provider 架构支持多种后端
|
||||||
- 完整日志系统:带轮转的日志记录,便于调试
|
- 完整日志系统: 带轮转的日志记录, 便于调试
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
### 从源码安装
|
### 从源码安装
|
||||||
1. 克隆仓库:
|
1. 克隆仓库:
|
||||||
```bash
|
```bash
|
||||||
git clone https://gitea.imwangzhiyu.xyz/ajax/heurams.git HeurAMS
|
git clone https://gitea.imwangzhiyu.xyz/ajax/heurams.git HeurAMS
|
||||||
cd HeurAMS
|
cd HeurAMS
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 安装依赖:
|
2. 安装依赖:
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 以开发模式安装包:
|
3. 以开发模式安装包:
|
||||||
```bash
|
```bash
|
||||||
pip install -e .
|
pip install -e .
|
||||||
```
|
```
|
||||||
@@ -71,7 +71,7 @@ python -m heurams.interface
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 数据目录结构
|
### 数据目录结构
|
||||||
应用会在工作目录下创建以下数据目录:
|
应用会在工作目录下创建以下数据目录:
|
||||||
- `data/nucleon/`: 记忆内容 (TOML 格式)
|
- `data/nucleon/`: 记忆内容 (TOML 格式)
|
||||||
- `data/electron/`: 算法状态 (JSON 格式)
|
- `data/electron/`: 算法状态 (JSON 格式)
|
||||||
- `data/orbital/`: 策略配置 (TOML 格式)
|
- `data/orbital/`: 策略配置 (TOML 格式)
|
||||||
@@ -82,13 +82,13 @@ python -m heurams.interface
|
|||||||
|
|
||||||
## 配置
|
## 配置
|
||||||
|
|
||||||
配置文件位于 `config/config.toml`(相对于工作目录)。如果不存在,会使用内置的默认配置。
|
配置文件位于 `config/config.toml`(相对于工作目录). 如果不存在, 会使用内置的默认配置.
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
### 架构图
|
### 架构图
|
||||||
|
|
||||||
以下 Mermaid 图展示了 HeurAMS 的主要组件及其关系:
|
以下 Mermaid 图展示了 HeurAMS 的主要组件及其关系:
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TB
|
graph TB
|
||||||
@@ -175,8 +175,8 @@ src/heurams/
|
|||||||
|
|
||||||
## 贡献
|
## 贡献
|
||||||
|
|
||||||
欢迎贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解贡献指南。
|
欢迎贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解贡献指南.
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
本项目基于 AGPL-3.0 许可证开源。详见 [LICENSE](LICENSE) 文件。
|
本项目基于 AGPL-3.0 许可证开源. 详见 [LICENSE](LICENSE) 文件.
|
||||||
@@ -32,359 +32,359 @@ final_review = [["FillBlank", "0.7"], ["SelectMeaning", "0.7"], ["recognition",
|
|||||||
["秦孝公据崤函之固, 拥雍州之地,"]
|
["秦孝公据崤函之固, 拥雍州之地,"]
|
||||||
note = []
|
note = []
|
||||||
content = "秦孝公/据/崤函/之固/, 拥/雍州/之地,/"
|
content = "秦孝公/据/崤函/之固/, 拥/雍州/之地,/"
|
||||||
translation = "秦孝公占据着崤山和函谷关的险固地势,拥有雍州的土地,"
|
translation = "秦孝公占据着崤山和函谷关的险固地势, 拥有雍州的土地, "
|
||||||
keyword_note = {"据"="占据", "崤函"="崤山和函谷关", "雍州"="古代九州之一"}
|
keyword_note = {"据"="占据", "崤函"="崤山和函谷关", "雍州"="古代九州之一"}
|
||||||
|
|
||||||
["君臣固守以窥周室,"]
|
["君臣固守以窥周室,"]
|
||||||
note = []
|
note = []
|
||||||
content = "君臣/固守/以窥/周室,/"
|
content = "君臣/固守/以窥/周室,/"
|
||||||
translation = "君臣牢固地守卫着,借以窥视周王室的权力,"
|
translation = "君臣牢固地守卫着, 借以窥视周王室的权力, "
|
||||||
keyword_note = {"窥"="窥视"}
|
keyword_note = {"窥"="窥视"}
|
||||||
|
|
||||||
["有席卷天下, 包举宇内, 囊括四海之意, 并吞八荒之心."]
|
["有席卷天下, 包举宇内, 囊括四海之意, 并吞八荒之心."]
|
||||||
note = []
|
note = []
|
||||||
content = "有/席卷/天下/, 包举/宇内/, 囊括/四海/之意/, 并吞/八荒/之心./"
|
content = "有/席卷/天下/, 包举/宇内/, 囊括/四海/之意/, 并吞/八荒/之心./"
|
||||||
translation = "有席卷天下,包办天宇之间,囊括四海的意图,并统天下的雄心。"
|
translation = "有席卷天下, 包办天宇之间, 囊括四海的意图, 并统天下的雄心. "
|
||||||
keyword_note = {"席卷"="像卷席子一样全部卷进去", "包举"="像打包一样全部拿走", "囊括"="像装口袋一样全部装进去", "八荒"="八方荒远之地"}
|
keyword_note = {"席卷"="像卷席子一样全部卷进去", "包举"="像打包一样全部拿走", "囊括"="像装口袋一样全部装进去", "八荒"="八方荒远之地"}
|
||||||
|
|
||||||
["当是时也, 商君佐之,"]
|
["当是时也, 商君佐之,"]
|
||||||
note = []
|
note = []
|
||||||
content = "当是时也/, 商君/佐之,/"
|
content = "当是时也/, 商君/佐之,/"
|
||||||
translation = "正当这时,商鞅辅佐他,"
|
translation = "正当这时, 商鞅辅佐他, "
|
||||||
keyword_note = {"商君"="商鞅"}
|
keyword_note = {"商君"="商鞅"}
|
||||||
|
|
||||||
["内立法度, 务耕织, 修守战之具,"]
|
["内立法度, 务耕织, 修守战之具,"]
|
||||||
note = []
|
note = []
|
||||||
content = "内/立法度/, 务/耕织/, 修/守战/之具,/"
|
content = "内/立法度/, 务/耕织/, 修/守战/之具,/"
|
||||||
translation = "对内建立法规制度,从事耕作纺织,修造防守和进攻的器械;"
|
translation = "对内建立法规制度, 从事耕作纺织, 修造防守和进攻的器械; "
|
||||||
keyword_note = {"法度"="法规制度", "务"="从事", "耕织"="耕作纺织", "守战之具"="防守和进攻的器械"}
|
keyword_note = {"法度"="法规制度", "务"="从事", "耕织"="耕作纺织", "守战之具"="防守和进攻的器械"}
|
||||||
|
|
||||||
["外连衡而斗诸侯."]
|
["外连衡而斗诸侯."]
|
||||||
note = []
|
note = []
|
||||||
content = "外/连衡/而斗/诸侯./"
|
content = "外/连衡/而斗/诸侯./"
|
||||||
translation = "对外实行连衡策略,使诸侯自相争斗。"
|
translation = "对外实行连衡策略, 使诸侯自相争斗. "
|
||||||
keyword_note = {"连衡"="连横策略", "斗"="使...相斗"}
|
keyword_note = {"连衡"="连横策略", "斗"="使...相斗"}
|
||||||
|
|
||||||
["于是秦人拱手而取西河之外."]
|
["于是秦人拱手而取西河之外."]
|
||||||
note = []
|
note = []
|
||||||
content = "于是/秦人/拱手/而取/西河/之外./"
|
content = "于是/秦人/拱手/而取/西河/之外./"
|
||||||
translation = "因此,秦人轻而易举地夺取了黄河以西的土地。"
|
translation = "因此, 秦人轻而易举地夺取了黄河以西的土地. "
|
||||||
keyword_note = {"拱手"="两手相合,形容毫不费力", "西河"="黄河以西地区"}
|
keyword_note = {"拱手"="两手相合, 形容毫不费力", "西河"="黄河以西地区"}
|
||||||
|
|
||||||
["孝公既没, 惠文、武、昭襄蒙故业, 因遗策,"]
|
["孝公既没, 惠文、武、昭襄蒙故业, 因遗策,"]
|
||||||
note = []
|
note = []
|
||||||
content = "孝公/既没/, 惠文/、武/、昭襄/蒙/故业/, 因/遗策,/"
|
content = "孝公/既没/, 惠文/、武/、昭襄/蒙/故业/, 因/遗策,/"
|
||||||
translation = "秦孝公死了以后,惠文王、武王、昭襄王承继先前的基业,沿袭前代的策略,"
|
translation = "秦孝公死了以后, 惠文王、武王、昭襄王承继先前的基业, 沿袭前代的策略, "
|
||||||
keyword_note = {"既没"="死后", "蒙"="承继", "故业"="先前的基业", "因"="沿袭", "遗策"="前代的策略"}
|
keyword_note = {"既没"="死后", "蒙"="承继", "故业"="先前的基业", "因"="沿袭", "遗策"="前代的策略"}
|
||||||
|
|
||||||
["南取汉中, 西举巴、蜀, 东割膏腴之地, 北收要害之郡."]
|
["南取汉中, 西举巴、蜀, 东割膏腴之地, 北收要害之郡."]
|
||||||
note = []
|
note = []
|
||||||
content = "南取/汉中/, 西举/巴/、蜀/, 东割/膏腴/之地/, 北收/要害/之郡./"
|
content = "南取/汉中/, 西举/巴/、蜀/, 东割/膏腴/之地/, 北收/要害/之郡./"
|
||||||
translation = "向南夺取汉中,向西攻取巴、蜀,向东割取肥沃的地区,向北占领非常重要的地区。"
|
translation = "向南夺取汉中, 向西攻取巴、蜀, 向东割取肥沃的地区, 向北占领非常重要的地区. "
|
||||||
keyword_note = {"膏腴"="肥沃", "要害"="非常重要"}
|
keyword_note = {"膏腴"="肥沃", "要害"="非常重要"}
|
||||||
|
|
||||||
["诸侯恐惧, 会盟而谋弱秦,"]
|
["诸侯恐惧, 会盟而谋弱秦,"]
|
||||||
note = []
|
note = []
|
||||||
content = "诸侯/恐惧/, 会盟/而谋/弱秦,/"
|
content = "诸侯/恐惧/, 会盟/而谋/弱秦,/"
|
||||||
translation = "诸侯恐慌害怕,集会结盟,商议削弱秦国。"
|
translation = "诸侯恐慌害怕, 集会结盟, 商议削弱秦国. "
|
||||||
keyword_note = {"会盟"="集会结盟", "弱秦"="削弱秦国"}
|
keyword_note = {"会盟"="集会结盟", "弱秦"="削弱秦国"}
|
||||||
|
|
||||||
["不爱珍器重宝肥饶之地, 以致天下之士,"]
|
["不爱珍器重宝肥饶之地, 以致天下之士,"]
|
||||||
note = []
|
note = []
|
||||||
content = "不爱/珍器/重宝/肥饶/之地/, 以致/天下/之士,/"
|
content = "不爱/珍器/重宝/肥饶/之地/, 以致/天下/之士,/"
|
||||||
translation = "不吝惜奇珍贵重的器物和肥沃富饶的土地,用来招纳天下的优秀人才,"
|
translation = "不吝惜奇珍贵重的器物和肥沃富饶的土地, 用来招纳天下的优秀人才, "
|
||||||
keyword_note = {"不爱"="不吝惜", "珍器重宝"="奇珍贵重的器物", "以致"="用来招纳"}
|
keyword_note = {"不爱"="不吝惜", "珍器重宝"="奇珍贵重的器物", "以致"="用来招纳"}
|
||||||
|
|
||||||
["合从缔交, 相与为一."]
|
["合从缔交, 相与为一."]
|
||||||
note = []
|
note = []
|
||||||
content = "合从/缔交/, 相与/为一./"
|
content = "合从/缔交/, 相与/为一./"
|
||||||
translation = "采用合纵的策略缔结盟约,互相援助,成为一体。"
|
translation = "采用合纵的策略缔结盟约, 互相援助, 成为一体. "
|
||||||
keyword_note = {"合从"="合纵策略", "缔交"="缔结盟约"}
|
keyword_note = {"合从"="合纵策略", "缔交"="缔结盟约"}
|
||||||
|
|
||||||
["当此之时, 齐有孟尝, 赵有平原, 楚有春申, 魏有信陵."]
|
["当此之时, 齐有孟尝, 赵有平原, 楚有春申, 魏有信陵."]
|
||||||
note = []
|
note = []
|
||||||
content = "当此/之时/, 齐有/孟尝/, 赵有/平原/, 楚有/春申/, 魏有/信陵./"
|
content = "当此/之时/, 齐有/孟尝/, 赵有/平原/, 楚有/春申/, 魏有/信陵./"
|
||||||
translation = "在这个时候,齐国有孟尝君,赵国有平原君,楚国有春申君,魏国有信陵君。"
|
translation = "在这个时候, 齐国有孟尝君, 赵国有平原君, 楚国有春申君, 魏国有信陵君. "
|
||||||
keyword_note = {"孟尝"="孟尝君田文", "平原"="平原君赵胜", "春申"="春申君黄歇", "信陵"="信陵君魏无忌"}
|
keyword_note = {"孟尝"="孟尝君田文", "平原"="平原君赵胜", "春申"="春申君黄歇", "信陵"="信陵君魏无忌"}
|
||||||
|
|
||||||
["此四君者, 皆明智而忠信, 宽厚而爱人, 尊贤而重士,"]
|
["此四君者, 皆明智而忠信, 宽厚而爱人, 尊贤而重士,"]
|
||||||
note = []
|
note = []
|
||||||
content = "此/四君/者/, 皆/明智/而/忠信/, 宽厚/而/爱人/, 尊贤/而/重士,/"
|
content = "此/四君/者/, 皆/明智/而/忠信/, 宽厚/而/爱人/, 尊贤/而/重士,/"
|
||||||
translation = "这四位封君,都见识英明有智谋,心地诚而讲信义,待人宽宏厚道而爱惜人民,尊重贤才而重用士人,"
|
translation = "这四位封君, 都见识英明有智谋, 心地诚而讲信义, 待人宽宏厚道而爱惜人民, 尊重贤才而重用士人, "
|
||||||
keyword_note = {"明智"="见识英明有智谋", "忠信"="心地诚而讲信义", "爱人"="爱惜人民", "尊贤"="尊重贤才", "重士"="重用士人"}
|
keyword_note = {"明智"="见识英明有智谋", "忠信"="心地诚而讲信义", "爱人"="爱惜人民", "尊贤"="尊重贤才", "重士"="重用士人"}
|
||||||
|
|
||||||
["约从离衡, 兼韩、魏、燕、楚、齐、赵、宋、卫、中山之众."]
|
["约从离衡, 兼韩、魏、燕、楚、齐、赵、宋、卫、中山之众."]
|
||||||
note = []
|
note = []
|
||||||
content = "约从/离衡/, 兼/韩/、魏/、燕/、楚/、齐/、赵/、宋/、卫/、中山/之众./"
|
content = "约从/离衡/, 兼/韩/、魏/、燕/、楚/、齐/、赵/、宋/、卫/、中山/之众./"
|
||||||
translation = "以合纵之约击破秦的连横之策,联合韩、魏、燕、楚、齐、赵、宋、卫、中山的部队。"
|
translation = "以合纵之约击破秦的连横之策, 联合韩、魏、燕、楚、齐、赵、宋、卫、中山的部队. "
|
||||||
keyword_note = {"约从"="采用合纵策略", "离衡"="破坏连横策略", "兼"="联合"}
|
keyword_note = {"约从"="采用合纵策略", "离衡"="破坏连横策略", "兼"="联合"}
|
||||||
|
|
||||||
["于是六国之士, 有甯越、徐尚、苏秦、杜赫之属为之谋,"]
|
["于是六国之士, 有甯越、徐尚、苏秦、杜赫之属为之谋,"]
|
||||||
note = []
|
note = []
|
||||||
content = "于是/六国/之士/, 有/甯越/、徐尚/、苏秦/、杜赫/之属/为之/谋,/"
|
content = "于是/六国/之士/, 有/甯越/、徐尚/、苏秦/、杜赫/之属/为之/谋,/"
|
||||||
translation = "在这时,六国的士人,有宁越、徐尚、苏秦、杜赫等人为他们出谋划策,"
|
translation = "在这时, 六国的士人, 有宁越、徐尚、苏秦、杜赫等人为他们出谋划策, "
|
||||||
keyword_note = {"之属"="等人", "为之谋"="为他们出谋划策"}
|
keyword_note = {"之属"="等人", "为之谋"="为他们出谋划策"}
|
||||||
|
|
||||||
["齐明、周最、陈轸、召滑、楼缓、翟景、苏厉、乐毅之徒通其意,"]
|
["齐明、周最、陈轸、召滑、楼缓、翟景、苏厉、乐毅之徒通其意,"]
|
||||||
note = []
|
note = []
|
||||||
content = "齐明/、周最/、陈轸/、召滑/、楼缓/、翟景/、苏厉/、乐毅/之徒/通其/意,/"
|
content = "齐明/、周最/、陈轸/、召滑/、楼缓/、翟景/、苏厉/、乐毅/之徒/通其/意,/"
|
||||||
translation = "齐明、周最、陈轸、召滑、楼缓、翟景、苏厉、乐毅等人沟通他们的意见,"
|
translation = "齐明、周最、陈轸、召滑、楼缓、翟景、苏厉、乐毅等人沟通他们的意见, "
|
||||||
keyword_note = {"之徒"="等人", "通其意"="沟通他们的意见"}
|
keyword_note = {"之徒"="等人", "通其意"="沟通他们的意见"}
|
||||||
|
|
||||||
["吴起、孙膑、带佗、倪良、王廖、田忌、廉颇、赵奢之伦制其兵."]
|
["吴起、孙膑、带佗、倪良、王廖、田忌、廉颇、赵奢之伦制其兵."]
|
||||||
note = []
|
note = []
|
||||||
content = "吴起/、孙膑/、带佗/、倪良/、王廖/、田忌/、廉颇/、赵奢/之伦/制其/兵./"
|
content = "吴起/、孙膑/、带佗/、倪良/、王廖/、田忌/、廉颇/、赵奢/之伦/制其/兵./"
|
||||||
translation = "吴起、孙膑、带佗、倪良、王廖、田忌、廉颇、赵奢等人统率他们的军队。"
|
translation = "吴起、孙膑、带佗、倪良、王廖、田忌、廉颇、赵奢等人统率他们的军队. "
|
||||||
keyword_note = {"之伦"="等人", "制其兵"="统率他们的军队"}
|
keyword_note = {"之伦"="等人", "制其兵"="统率他们的军队"}
|
||||||
|
|
||||||
["尝以十倍之地, 百万之众, 叩关而攻秦."]
|
["尝以十倍之地, 百万之众, 叩关而攻秦."]
|
||||||
note = []
|
note = []
|
||||||
content = "尝以/十倍/之地/, 百万/之众/, 叩关/而攻/秦./"
|
content = "尝以/十倍/之地/, 百万/之众/, 叩关/而攻/秦./"
|
||||||
translation = "他们曾经用十倍于秦的土地,上百万的军队,攻打函谷关来攻打秦国。"
|
translation = "他们曾经用十倍于秦的土地, 上百万的军队, 攻打函谷关来攻打秦国. "
|
||||||
keyword_note = {"尝"="曾经", "以"="用", "叩关"="攻打函谷关"}
|
keyword_note = {"尝"="曾经", "以"="用", "叩关"="攻打函谷关"}
|
||||||
|
|
||||||
["秦人开关延敌, 九国之师, 逡巡而不敢进."]
|
["秦人开关延敌, 九国之师, 逡巡而不敢进."]
|
||||||
note = []
|
note = []
|
||||||
content = "秦人/开关/延敌/, 九国/之师/, 逡巡/而不敢/进./"
|
content = "秦人/开关/延敌/, 九国/之师/, 逡巡/而不敢/进./"
|
||||||
translation = "秦人打开函谷关口迎战敌人,九国的军队有所顾虑徘徊不敢入关。"
|
translation = "秦人打开函谷关口迎战敌人, 九国的军队有所顾虑徘徊不敢入关. "
|
||||||
keyword_note = {"开关"="打开函谷关", "延敌"="迎战敌人", "九国"="九个国家", "逡巡"="有所顾虑徘徊"}
|
keyword_note = {"开关"="打开函谷关", "延敌"="迎战敌人", "九国"="九个国家", "逡巡"="有所顾虑徘徊"}
|
||||||
|
|
||||||
["秦无亡矢遗镞之费, 而天下诸侯已困矣."]
|
["秦无亡矢遗镞之费, 而天下诸侯已困矣."]
|
||||||
note = []
|
note = []
|
||||||
content = "秦/无/亡矢/遗镞/之费/, 而/天下/诸侯/已困/矣./"
|
content = "秦/无/亡矢/遗镞/之费/, 而/天下/诸侯/已困/矣./"
|
||||||
translation = "秦人没有一兵一卒的耗费,然而天下的诸侯就已窘迫不堪了。"
|
translation = "秦人没有一兵一卒的耗费, 然而天下的诸侯就已窘迫不堪了. "
|
||||||
keyword_note = {"亡矢"="丢失箭矢", "遗镞"="遗失箭头", "费"="耗费", "困"="窘迫不堪"}
|
keyword_note = {"亡矢"="丢失箭矢", "遗镞"="遗失箭头", "费"="耗费", "困"="窘迫不堪"}
|
||||||
|
|
||||||
["于是从散约败, 争割地而赂秦."]
|
["于是从散约败, 争割地而赂秦."]
|
||||||
note = []
|
note = []
|
||||||
content = "于是/从散/约败/, 争/割地/而赂/秦./"
|
content = "于是/从散/约败/, 争/割地/而赂/秦./"
|
||||||
translation = "因此,纵约失败了,各诸侯国争着割地来贿赂秦国。"
|
translation = "因此, 纵约失败了, 各诸侯国争着割地来贿赂秦国. "
|
||||||
keyword_note = {"从散"="纵约失败", "约败"="盟约破坏", "赂"="贿赂"}
|
keyword_note = {"从散"="纵约失败", "约败"="盟约破坏", "赂"="贿赂"}
|
||||||
|
|
||||||
["秦有余力而制其弊, 追亡逐北, 伏尸百万, 流血漂橹;"]
|
["秦有余力而制其弊, 追亡逐北, 伏尸百万, 流血漂橹;"]
|
||||||
note = []
|
note = []
|
||||||
content = "秦/有余力/而制/其弊/, 追亡/逐北/, 伏尸/百万/, 流血/漂橹; /"
|
content = "秦/有余力/而制/其弊/, 追亡/逐北/, 伏尸/百万/, 流血/漂橹; /"
|
||||||
translation = "秦有剩余的力量趁他们困乏而制服他们,追赶逃走的败兵,百万败兵横尸道路,流淌的血液可以漂浮盾牌;"
|
translation = "秦有剩余的力量趁他们困乏而制服他们, 追赶逃走的败兵, 百万败兵横尸道路, 流淌的血液可以漂浮盾牌; "
|
||||||
keyword_note = {"制其弊"="趁他们困乏而制服他们", "追亡"="追赶逃兵", "逐北"="追逐败兵", "伏尸"="横尸", "漂橹"="漂浮盾牌"}
|
keyword_note = {"制其弊"="趁他们困乏而制服他们", "追亡"="追赶逃兵", "逐北"="追逐败兵", "伏尸"="横尸", "漂橹"="漂浮盾牌"}
|
||||||
|
|
||||||
["因利乘便, 宰割天下, 分裂山河."]
|
["因利乘便, 宰割天下, 分裂山河."]
|
||||||
note = []
|
note = []
|
||||||
content = "因利/乘便/, 宰割/天下/, 分裂/山河./"
|
content = "因利/乘便/, 宰割/天下/, 分裂/山河./"
|
||||||
translation = "秦国凭借这便利的形势,割取天下的土地,重新划分山河的区域。"
|
translation = "秦国凭借这便利的形势, 割取天下的土地, 重新划分山河的区域. "
|
||||||
keyword_note = {"因利乘便"="凭借便利的形势", "宰割"="割取", "分裂"="划分"}
|
keyword_note = {"因利乘便"="凭借便利的形势", "宰割"="割取", "分裂"="划分"}
|
||||||
|
|
||||||
["强国请服, 弱国入朝."]
|
["强国请服, 弱国入朝."]
|
||||||
note = []
|
note = []
|
||||||
content = "强国/请服/, 弱国/入朝./"
|
content = "强国/请服/, 弱国/入朝./"
|
||||||
translation = "强国主动表示臣服,弱国入秦朝拜。"
|
translation = "强国主动表示臣服, 弱国入秦朝拜. "
|
||||||
keyword_note = {"请服"="请求臣服", "入朝"="入秦朝拜"}
|
keyword_note = {"请服"="请求臣服", "入朝"="入秦朝拜"}
|
||||||
|
|
||||||
["延及孝文王、庄襄王, 享国之日浅, 国家无事."]
|
["延及孝文王、庄襄王, 享国之日浅, 国家无事."]
|
||||||
note = []
|
note = []
|
||||||
content = "延及/孝文王/、庄襄王/, 享国/之日/浅/, 国家/无事./"
|
content = "延及/孝文王/、庄襄王/, 享国/之日/浅/, 国家/无事./"
|
||||||
translation = "延续到孝文王、庄襄王,统治的时间不长,秦国并没有什么大事发生。"
|
translation = "延续到孝文王、庄襄王, 统治的时间不长, 秦国并没有什么大事发生. "
|
||||||
keyword_note = {"延及"="延续到", "享国"="统治国家", "浅"="时间短", "无事"="没有大事发生"}
|
keyword_note = {"延及"="延续到", "享国"="统治国家", "浅"="时间短", "无事"="没有大事发生"}
|
||||||
|
|
||||||
["及至始皇, 奋六世之余烈, 振长策而御宇内,"]
|
["及至始皇, 奋六世之余烈, 振长策而御宇内,"]
|
||||||
note = []
|
note = []
|
||||||
content = "及至/始皇/, 奋/六世/之余烈/, 振/长策/而御/宇内,/"
|
content = "及至/始皇/, 奋/六世/之余烈/, 振/长策/而御/宇内,/"
|
||||||
translation = "到始皇的时候,发展六世遗留下来的功业,以武力来统治各国,"
|
translation = "到始皇的时候, 发展六世遗留下来的功业, 以武力来统治各国, "
|
||||||
keyword_note = {"奋"="发展", "余烈"="遗留下来的功业", "振长策"="挥动长鞭", "御宇内"="统治天下"}
|
keyword_note = {"奋"="发展", "余烈"="遗留下来的功业", "振长策"="挥动长鞭", "御宇内"="统治天下"}
|
||||||
|
|
||||||
["吞二周而亡诸侯, 履至尊而制六合,"]
|
["吞二周而亡诸侯, 履至尊而制六合,"]
|
||||||
note = []
|
note = []
|
||||||
content = "吞/二周/而亡/诸侯/, 履/至尊/而制/六合,/"
|
content = "吞/二周/而亡/诸侯/, 履/至尊/而制/六合,/"
|
||||||
translation = "将东周,西周和各诸侯国统统消灭,登上皇帝的宝座来统治天下,"
|
translation = "将东周, 西周和各诸侯国统统消灭, 登上皇帝的宝座来统治天下, "
|
||||||
keyword_note = {"吞"="吞并", "二周"="东周和西周", "履至尊"="登上皇位", "制六合"="统治天下"}
|
keyword_note = {"吞"="吞并", "二周"="东周和西周", "履至尊"="登上皇位", "制六合"="统治天下"}
|
||||||
|
|
||||||
["执敲扑而鞭笞天下, 威振四海."]
|
["执敲扑而鞭笞天下, 威振四海."]
|
||||||
note = []
|
note = []
|
||||||
content = "执/敲扑/而鞭笞/天下/, 威振/四海./"
|
content = "执/敲扑/而鞭笞/天下/, 威振/四海./"
|
||||||
translation = "用严酷的刑罚来奴役天下的百姓,威风震慑四海。"
|
translation = "用严酷的刑罚来奴役天下的百姓, 威风震慑四海. "
|
||||||
keyword_note = {"敲扑"="刑具", "鞭笞"="鞭打,奴役", "威振"="威风震慑"}
|
keyword_note = {"敲扑"="刑具", "鞭笞"="鞭打, 奴役", "威振"="威风震慑"}
|
||||||
|
|
||||||
["南取百越之地, 以为桂林、象郡;"]
|
["南取百越之地, 以为桂林、象郡;"]
|
||||||
note = []
|
note = []
|
||||||
content = "南取/百越/之地/, 以为/桂林/、象郡; /"
|
content = "南取/百越/之地/, 以为/桂林/、象郡; /"
|
||||||
translation = "秦始皇向南攻取百越的土地,把它划为桂林郡和象郡;"
|
translation = "秦始皇向南攻取百越的土地, 把它划为桂林郡和象郡; "
|
||||||
keyword_note = {"百越"="古代南方少数民族", "以为"="把它作为"}
|
keyword_note = {"百越"="古代南方少数民族", "以为"="把它作为"}
|
||||||
|
|
||||||
["百越之君, 俯首系颈, 委命下吏."]
|
["百越之君, 俯首系颈, 委命下吏."]
|
||||||
note = []
|
note = []
|
||||||
content = "百越/之君/, 俯首/系颈/, 委命/下吏./"
|
content = "百越/之君/, 俯首/系颈/, 委命/下吏./"
|
||||||
translation = "百越的君主低着头,颈上捆着绳子愿意服从投降,把性命交给司法官吏。"
|
translation = "百越的君主低着头, 颈上捆着绳子愿意服从投降, 把性命交给司法官吏. "
|
||||||
keyword_note = {"俯首"="低头", "系颈"="颈上捆着绳子", "委命"="把性命交给", "下吏"="司法官吏"}
|
keyword_note = {"俯首"="低头", "系颈"="颈上捆着绳子", "委命"="把性命交给", "下吏"="司法官吏"}
|
||||||
|
|
||||||
["乃使蒙恬北筑长城而守藩篱, 却匈奴七百余里;"]
|
["乃使蒙恬北筑长城而守藩篱, 却匈奴七百余里;"]
|
||||||
note = []
|
note = []
|
||||||
content = "乃使/蒙恬/北筑/长城/而守/藩篱/, 却/匈奴/七百/余里; /"
|
content = "乃使/蒙恬/北筑/长城/而守/藩篱/, 却/匈奴/七百/余里; /"
|
||||||
translation = "秦始皇于是又命令蒙恬在北方修筑长城,守卫边境,使匈奴退却七百多里;"
|
translation = "秦始皇于是又命令蒙恬在北方修筑长城, 守卫边境, 使匈奴退却七百多里; "
|
||||||
keyword_note = {"蒙恬"="秦朝名将", "藩篱"="边境", "却"="使...退却", "匈奴"="北方少数民族"}
|
keyword_note = {"蒙恬"="秦朝名将", "藩篱"="边境", "却"="使...退却", "匈奴"="北方少数民族"}
|
||||||
|
|
||||||
["胡人不敢南下而牧马, 士不敢弯弓而报怨."]
|
["胡人不敢南下而牧马, 士不敢弯弓而报怨."]
|
||||||
note = []
|
note = []
|
||||||
content = "胡人/不敢/南下/而牧马/, 士/不敢/弯弓/而报怨./"
|
content = "胡人/不敢/南下/而牧马/, 士/不敢/弯弓/而报怨./"
|
||||||
translation = "胡人不敢向下到南边来放牧,勇士不敢拉弓射箭来报仇。"
|
translation = "胡人不敢向下到南边来放牧, 勇士不敢拉弓射箭来报仇. "
|
||||||
keyword_note = {"胡人"="指匈奴人", "牧马"="放牧", "弯弓"="拉弓", "报怨"="报仇"}
|
keyword_note = {"胡人"="指匈奴人", "牧马"="放牧", "弯弓"="拉弓", "报怨"="报仇"}
|
||||||
|
|
||||||
["于是废先王之道, 焚百家之言, 以愚黔首;"]
|
["于是废先王之道, 焚百家之言, 以愚黔首;"]
|
||||||
note = []
|
note = []
|
||||||
content = "于是/废/先王/之道/, 焚/百家/之言/, 以愚/黔首; /"
|
content = "于是/废/先王/之道/, 焚/百家/之言/, 以愚/黔首; /"
|
||||||
translation = "秦始皇接着就废除古代帝王的治世之道,焚烧诸子百家的著作,来使百姓愚蠢;"
|
translation = "秦始皇接着就废除古代帝王的治世之道, 焚烧诸子百家的著作, 来使百姓愚蠢; "
|
||||||
keyword_note = {"先王"="古代帝王", "道"="治世之道", "百家之言"="诸子百家的著作", "愚"="使...愚蠢", "黔首"="百姓"}
|
keyword_note = {"先王"="古代帝王", "道"="治世之道", "百家之言"="诸子百家的著作", "愚"="使...愚蠢", "黔首"="百姓"}
|
||||||
|
|
||||||
["隳名城, 杀豪杰;"]
|
["隳名城, 杀豪杰;"]
|
||||||
note = []
|
note = []
|
||||||
content = "隳/名城/, 杀/豪杰; /"
|
content = "隳/名城/, 杀/豪杰; /"
|
||||||
translation = "毁坏高大的城墙,杀掉英雄豪杰;"
|
translation = "毁坏高大的城墙, 杀掉英雄豪杰; "
|
||||||
keyword_note = {"隳"="毁坏", "名城"="高大的城墙"}
|
keyword_note = {"隳"="毁坏", "名城"="高大的城墙"}
|
||||||
|
|
||||||
["收天下之兵, 聚之咸阳, 销锋镝, 铸以为金人十二, 以弱天下之民."]
|
["收天下之兵, 聚之咸阳, 销锋镝, 铸以为金人十二, 以弱天下之民."]
|
||||||
note = []
|
note = []
|
||||||
content = "收/天下/之兵/, 聚之/咸阳/, 销/锋镝/, 铸以为/金人/十二/, 以弱/天下/之民./"
|
content = "收/天下/之兵/, 聚之/咸阳/, 销/锋镝/, 铸以为/金人/十二/, 以弱/天下/之民./"
|
||||||
translation = "收缴天下的兵器,集中在咸阳,销毁兵刃和箭头,冶炼它们铸造十二个铜人,以便削弱百姓的反抗力量。"
|
translation = "收缴天下的兵器, 集中在咸阳, 销毁兵刃和箭头, 冶炼它们铸造十二个铜人, 以便削弱百姓的反抗力量. "
|
||||||
keyword_note = {"兵"="兵器", "销"="销毁", "锋镝"="兵刃和箭头", "铸以为"="铸造成为", "金人"="铜人", "弱"="削弱"}
|
keyword_note = {"兵"="兵器", "销"="销毁", "锋镝"="兵刃和箭头", "铸以为"="铸造成为", "金人"="铜人", "弱"="削弱"}
|
||||||
|
|
||||||
["然后践华为城, 因河为池,"]
|
["然后践华为城, 因河为池,"]
|
||||||
note = []
|
note = []
|
||||||
content = "然后/践华/为城/, 因河/为池,/"
|
content = "然后/践华/为城/, 因河/为池,/"
|
||||||
translation = "然后凭借华山为城墙,依据黄河为城池,"
|
translation = "然后凭借华山为城墙, 依据黄河为城池, "
|
||||||
keyword_note = {"践华"="凭借华山", "因河"="依据黄河", "为城"="作为城墙", "为池"="作为护城河"}
|
keyword_note = {"践华"="凭借华山", "因河"="依据黄河", "为城"="作为城墙", "为池"="作为护城河"}
|
||||||
|
|
||||||
["据亿丈之城, 临不测之渊, 以为固."]
|
["据亿丈之城, 临不测之渊, 以为固."]
|
||||||
note = []
|
note = []
|
||||||
content = "据/亿丈/之城/, 临/不测/之渊/, 以为/固./"
|
content = "据/亿丈/之城/, 临/不测/之渊/, 以为/固./"
|
||||||
translation = "凭借着高耸的华山,往下看着深不可测的黄河,认为这是险固的地方。"
|
translation = "凭借着高耸的华山, 往下看着深不可测的黄河, 认为这是险固的地方. "
|
||||||
keyword_note = {"亿丈"="形容极高", "不测"="深不可测", "渊"="深水", "固"="险固"}
|
keyword_note = {"亿丈"="形容极高", "不测"="深不可测", "渊"="深水", "固"="险固"}
|
||||||
|
|
||||||
["良将劲弩守要害之处, 信臣精卒陈利兵而谁何."]
|
["良将劲弩守要害之处, 信臣精卒陈利兵而谁何."]
|
||||||
note = []
|
note = []
|
||||||
content = "良将/劲弩/守/要害/之处/, 信臣/精卒/陈/利兵/而谁何./"
|
content = "良将/劲弩/守/要害/之处/, 信臣/精卒/陈/利兵/而谁何./"
|
||||||
translation = "好的将领手执强弩,守卫着要害的地方,可靠的官员和精锐的士卒,拿着锋利的兵器,盘问过往行人。"
|
translation = "好的将领手执强弩, 守卫着要害的地方, 可靠的官员和精锐的士卒, 拿着锋利的兵器, 盘问过往行人. "
|
||||||
keyword_note = {"劲弩"="强弩", "要害"="重要关键", "信臣"="可靠的官员", "精卒"="精锐的士卒", "陈"="陈列,拿着", "利兵"="锋利的兵器", "谁何"="盘问行人"}
|
keyword_note = {"劲弩"="强弩", "要害"="重要关键", "信臣"="可靠的官员", "精卒"="精锐的士卒", "陈"="陈列, 拿着", "利兵"="锋利的兵器", "谁何"="盘问行人"}
|
||||||
|
|
||||||
["天下已定, 始皇之心, 自以为关中之固, 金城千里, 子孙帝王万世之业也."]
|
["天下已定, 始皇之心, 自以为关中之固, 金城千里, 子孙帝王万世之业也."]
|
||||||
note = []
|
note = []
|
||||||
content = "天下/已定/, 始皇/之心/, 自以为/关中/之固/, 金城/千里/, 子孙/帝王/万世/之业/也./"
|
content = "天下/已定/, 始皇/之心/, 自以为/关中/之固/, 金城/千里/, 子孙/帝王/万世/之业/也./"
|
||||||
translation = "天下已经安定,始皇心里自己认为这关中的险固地势、方圆千里的坚固的城防,是子子孙孙称帝称王直至万代的基业。"
|
translation = "天下已经安定, 始皇心里自己认为这关中的险固地势、方圆千里的坚固的城防, 是子子孙孙称帝称王直至万代的基业. "
|
||||||
keyword_note = {"自以为"="自己认为", "关中"="函谷关以西地区", "固"="险固地势", "金城"="坚固的城池", "帝王"="称帝称王", "万世"="万代"}
|
keyword_note = {"自以为"="自己认为", "关中"="函谷关以西地区", "固"="险固地势", "金城"="坚固的城池", "帝王"="称帝称王", "万世"="万代"}
|
||||||
|
|
||||||
["始皇既没, 余威震于殊俗."]
|
["始皇既没, 余威震于殊俗."]
|
||||||
note = []
|
note = []
|
||||||
content = "始皇/既没/, 余威/震于/殊俗./"
|
content = "始皇/既没/, 余威/震于/殊俗./"
|
||||||
translation = "始皇去世之后,他的余威依然震慑着边远地区。"
|
translation = "始皇去世之后, 他的余威依然震慑着边远地区. "
|
||||||
keyword_note = {"既没"="死后", "余威"="剩余的威势", "震"="震慑", "殊俗"="不同的风俗,指边远地区"}
|
keyword_note = {"既没"="死后", "余威"="剩余的威势", "震"="震慑", "殊俗"="不同的风俗, 指边远地区"}
|
||||||
|
|
||||||
["然陈涉瓮牖绳枢之子, 氓隶之人, 而迁徙之徒也;"]
|
["然陈涉瓮牖绳枢之子, 氓隶之人, 而迁徙之徒也;"]
|
||||||
note = []
|
note = []
|
||||||
content = "然/陈涉/瓮牖/绳枢/之子/, 氓隶/之人/, 而/迁徙/之徒/也; /"
|
content = "然/陈涉/瓮牖/绳枢/之子/, 氓隶/之人/, 而/迁徙/之徒/也; /"
|
||||||
translation = "可是,陈涉不过是个破瓮做窗户、草绳做户枢的贫家子弟,是氓、隶一类的人,后来做了被迁谪戍边的卒子;"
|
translation = "可是, 陈涉不过是个破瓮做窗户、草绳做户枢的贫家子弟, 是氓、隶一类的人, 后来做了被迁谪戍边的卒子; "
|
||||||
keyword_note = {"瓮牖"="用破瓮做窗户", "绳枢"="用草绳系户枢", "氓隶"="平民和奴隶", "迁徙之徒"="被征发戍边的人"}
|
keyword_note = {"瓮牖"="用破瓮做窗户", "绳枢"="用草绳系户枢", "氓隶"="平民和奴隶", "迁徙之徒"="被征发戍边的人"}
|
||||||
|
|
||||||
["才能不及中人, 非有仲尼、墨翟之贤, 陶朱、猗顿之富;"]
|
["才能不及中人, 非有仲尼、墨翟之贤, 陶朱、猗顿之富;"]
|
||||||
note = []
|
note = []
|
||||||
content = "才能/不及/中人/, 非有/仲尼/、墨翟/之贤/, 陶朱/、猗顿/之富; /"
|
content = "才能/不及/中人/, 非有/仲尼/、墨翟/之贤/, 陶朱/、猗顿/之富; /"
|
||||||
translation = "才能不如普通人,并没有孔丘、墨翟那样的贤德,也不像陶朱、猗顿那样富有。"
|
translation = "才能不如普通人, 并没有孔丘、墨翟那样的贤德, 也不像陶朱、猗顿那样富有. "
|
||||||
keyword_note = {"中人"="普通人", "仲尼"="孔子", "墨翟"="墨子", "陶朱"="范蠡", "猗顿"="春秋时富商"}
|
keyword_note = {"中人"="普通人", "仲尼"="孔子", "墨翟"="墨子", "陶朱"="范蠡", "猗顿"="春秋时富商"}
|
||||||
|
|
||||||
["蹑足行伍之间, 而倔起阡陌之中,"]
|
["蹑足行伍之间, 而倔起阡陌之中,"]
|
||||||
note = []
|
note = []
|
||||||
content = "蹑足/行伍/之间/, 而/倔起/阡陌/之中,/"
|
content = "蹑足/行伍/之间/, 而/倔起/阡陌/之中,/"
|
||||||
translation = "他跻身于戍卒的队伍中,从田野间突然奋起发难,"
|
translation = "他跻身于戍卒的队伍中, 从田野间突然奋起发难, "
|
||||||
keyword_note = {"蹑足"="置身于", "行伍"="军队", "倔起"="突然奋起", "阡陌"="田野"}
|
keyword_note = {"蹑足"="置身于", "行伍"="军队", "倔起"="突然奋起", "阡陌"="田野"}
|
||||||
|
|
||||||
["率疲弊之卒, 将数百之众, 转而攻秦;"]
|
["率疲弊之卒, 将数百之众, 转而攻秦;"]
|
||||||
note = []
|
note = []
|
||||||
content = "率/疲弊/之卒/, 将/数百/之众/, 转而/攻秦; /"
|
content = "率/疲弊/之卒/, 将/数百/之众/, 转而/攻秦; /"
|
||||||
translation = "率领着疲惫无力的士兵,指挥着几百人的队伍,掉转头来进攻秦国;"
|
translation = "率领着疲惫无力的士兵, 指挥着几百人的队伍, 掉转头来进攻秦国; "
|
||||||
keyword_note = {"疲弊"="疲惫无力", "将"="率领"}
|
keyword_note = {"疲弊"="疲惫无力", "将"="率领"}
|
||||||
|
|
||||||
["斩木为兵, 揭竿为旗,"]
|
["斩木为兵, 揭竿为旗,"]
|
||||||
note = []
|
note = []
|
||||||
content = "斩木/为兵/, 揭竿/为旗,/"
|
content = "斩木/为兵/, 揭竿/为旗,/"
|
||||||
translation = "砍下树木作武器,举起竹竿当旗帜,"
|
translation = "砍下树木作武器, 举起竹竿当旗帜, "
|
||||||
keyword_note = {"斩木为兵"="砍树木作武器", "揭竿为旗"="举竹竿当旗帜"}
|
keyword_note = {"斩木为兵"="砍树木作武器", "揭竿为旗"="举竹竿当旗帜"}
|
||||||
|
|
||||||
["天下云集响应, 赢粮而景从."]
|
["天下云集响应, 赢粮而景从."]
|
||||||
note = []
|
note = []
|
||||||
content = "天下/云集/响应/, 赢粮/而景从./"
|
content = "天下/云集/响应/, 赢粮/而景从./"
|
||||||
translation = "天下豪杰像云一样聚集,回声似的应和他,许多人都背着粮食,如影随形。"
|
translation = "天下豪杰像云一样聚集, 回声似的应和他, 许多人都背着粮食, 如影随形. "
|
||||||
keyword_note = {"云集"="像云一样聚集", "响应"="像回声一样应和", "赢粮"="背着粮食", "景从"="如影随形"}
|
keyword_note = {"云集"="像云一样聚集", "响应"="像回声一样应和", "赢粮"="背着粮食", "景从"="如影随形"}
|
||||||
|
|
||||||
["山东豪俊遂并起而亡秦族矣."]
|
["山东豪俊遂并起而亡秦族矣."]
|
||||||
note = []
|
note = []
|
||||||
content = "山东/豪俊/遂/并起/而亡/秦族/矣./"
|
content = "山东/豪俊/遂/并起/而亡/秦族/矣./"
|
||||||
translation = "崤山以东的英雄豪杰于是一齐起事,消灭了秦的家族。"
|
translation = "崤山以东的英雄豪杰于是一齐起事, 消灭了秦的家族. "
|
||||||
keyword_note = {"山东"="崤山以东", "豪俊"="英雄豪杰", "并起"="一齐起事", "亡"="消灭", "秦族"="秦的家族"}
|
keyword_note = {"山东"="崤山以东", "豪俊"="英雄豪杰", "并起"="一齐起事", "亡"="消灭", "秦族"="秦的家族"}
|
||||||
|
|
||||||
["且夫天下非小弱也, 雍州之地, 崤函之固, 自若也."]
|
["且夫天下非小弱也, 雍州之地, 崤函之固, 自若也."]
|
||||||
note = []
|
note = []
|
||||||
content = "且夫/天下/非/小弱/也/, 雍州/之地/, 崤函/之固/, 自若/也./"
|
content = "且夫/天下/非/小弱/也/, 雍州/之地/, 崤函/之固/, 自若/也./"
|
||||||
translation = "况且那天下并没有缩小削弱,雍州的地势,崤山和函谷关的险固,是保持原来的样子。"
|
translation = "况且那天下并没有缩小削弱, 雍州的地势, 崤山和函谷关的险固, 是保持原来的样子. "
|
||||||
keyword_note = {"且夫"="况且", "小弱"="变小削弱", "自若"="保持原样"}
|
keyword_note = {"且夫"="况且", "小弱"="变小削弱", "自若"="保持原样"}
|
||||||
|
|
||||||
["陈涉之位, 非尊于齐、楚、燕、赵、韩、魏、宋、卫、中山之君也;"]
|
["陈涉之位, 非尊于齐、楚、燕、赵、韩、魏、宋、卫、中山之君也;"]
|
||||||
note = []
|
note = []
|
||||||
content = "陈涉/之位/, 非/尊于/齐/、楚/、燕/、赵/、韩/、魏/、宋/、卫/、中山/之君/也; /"
|
content = "陈涉/之位/, 非/尊于/齐/、楚/、燕/、赵/、韩/、魏/、宋/、卫/、中山/之君/也; /"
|
||||||
translation = "陈涉的地位,没有比齐、楚、燕、赵、韩、魏、宋、卫、中山的国君更加尊贵;"
|
translation = "陈涉的地位, 没有比齐、楚、燕、赵、韩、魏、宋、卫、中山的国君更加尊贵; "
|
||||||
keyword_note = {"尊于"="比...尊贵"}
|
keyword_note = {"尊于"="比...尊贵"}
|
||||||
|
|
||||||
["锄櫌棘矜, 非铦于钩戟长铩也;"]
|
["锄櫌棘矜, 非铦于钩戟长铩也;"]
|
||||||
note = []
|
note = []
|
||||||
content = "锄櫌/棘矜/, 非/铦于/钩戟/长铩/也; /"
|
content = "锄櫌/棘矜/, 非/铦于/钩戟/长铩/也; /"
|
||||||
translation = "锄头木棍也不比钩戟长矛更锋利;"
|
translation = "锄头木棍也不比钩戟长矛更锋利; "
|
||||||
keyword_note = {"锄櫌"="锄头", "棘矜"="木棍", "铦于"="比...锋利", "钩戟"="带钩的戟", "长铩"="长矛"}
|
keyword_note = {"锄櫌"="锄头", "棘矜"="木棍", "铦于"="比...锋利", "钩戟"="带钩的戟", "长铩"="长矛"}
|
||||||
|
|
||||||
["谪戍之众, 非抗于九国之师也;"]
|
["谪戍之众, 非抗于九国之师也;"]
|
||||||
note = []
|
note = []
|
||||||
content = "谪戍/之众/, 非/抗于/九国/之师/也; /"
|
content = "谪戍/之众/, 非/抗于/九国/之师/也; /"
|
||||||
translation = "那迁谪戍边的士兵也不能和九国部队抗衡;"
|
translation = "那迁谪戍边的士兵也不能和九国部队抗衡; "
|
||||||
keyword_note = {"谪戍"="被贬戍边", "抗于"="和...抗衡", "九国"="九个国家"}
|
keyword_note = {"谪戍"="被贬戍边", "抗于"="和...抗衡", "九国"="九个国家"}
|
||||||
|
|
||||||
["深谋远虑, 行军用兵之道, 非及乡时之士也."]
|
["深谋远虑, 行军用兵之道, 非及乡时之士也."]
|
||||||
note = []
|
note = []
|
||||||
content = "深谋/远虑/, 行军/用兵/之道/, 非及/乡时/之士/也./"
|
content = "深谋/远虑/, 行军/用兵/之道/, 非及/乡时/之士/也./"
|
||||||
translation = "深谋远虑,行军用兵的方法,也比不上先前九国的武将谋臣。"
|
translation = "深谋远虑, 行军用兵的方法, 也比不上先前九国的武将谋臣. "
|
||||||
keyword_note = {"深谋远虑"="深谋远虑", "行军用兵"="行军作战", "非及"="比不上", "乡时"="先前"}
|
keyword_note = {"深谋远虑"="深谋远虑", "行军用兵"="行军作战", "非及"="比不上", "乡时"="先前"}
|
||||||
|
|
||||||
["然而成败异变, 功业相反, 何也?"]
|
["然而成败异变, 功业相反, 何也?"]
|
||||||
note = []
|
note = []
|
||||||
content = "然而/成败/异变/, 功业/相反/, 何也?/"
|
content = "然而/成败/异变/, 功业/相反/, 何也?/"
|
||||||
translation = "可是条件好者失败而条件差者成功,功业完全相反,为什么呢?"
|
translation = "可是条件好者失败而条件差者成功, 功业完全相反, 为什么呢? "
|
||||||
keyword_note = {"成败异变"="成功失败发生变化", "功业相反"="功业完全相反"}
|
keyword_note = {"成败异变"="成功失败发生变化", "功业相反"="功业完全相反"}
|
||||||
|
|
||||||
["试使山东之国与陈涉度长絜大, 比权量力,"]
|
["试使山东之国与陈涉度长絜大, 比权量力,"]
|
||||||
note = []
|
note = []
|
||||||
content = "试使/山东/之国/与/陈涉/度长/絜大/, 比权/量力,/"
|
content = "试使/山东/之国/与/陈涉/度长/絜大/, 比权/量力,/"
|
||||||
translation = "假使拿东方诸侯国跟陈涉比一比长短大小,量一量权势力量,"
|
translation = "假使拿东方诸侯国跟陈涉比一比长短大小, 量一量权势力量, "
|
||||||
keyword_note = {"试使"="假使", "度长絜大"="衡量长短大小", "比权量力"="比较权势力量"}
|
keyword_note = {"试使"="假使", "度长絜大"="衡量长短大小", "比权量力"="比较权势力量"}
|
||||||
|
|
||||||
["则不可同年而语矣."]
|
["则不可同年而语矣."]
|
||||||
note = []
|
note = []
|
||||||
content = "则/不可/同年/而语/矣./"
|
content = "则/不可/同年/而语/矣./"
|
||||||
translation = "就更不能相提并论了。"
|
translation = "就更不能相提并论了. "
|
||||||
keyword_note = {"同年而语"="相提并论"}
|
keyword_note = {"同年而语"="相提并论"}
|
||||||
|
|
||||||
["然秦以区区之地, 致万乘之势, 序八州而朝同列, 百有余年矣;"]
|
["然秦以区区之地, 致万乘之势, 序八州而朝同列, 百有余年矣;"]
|
||||||
note = []
|
note = []
|
||||||
content = "然/秦/以/区区/之地/, 致/万乘/之势/, 序/八州/而朝/同列/, 百有/余年/矣; /"
|
content = "然/秦/以/区区/之地/, 致/万乘/之势/, 序/八州/而朝/同列/, 百有/余年/矣; /"
|
||||||
translation = "然而秦凭借着它的小小的地方,发展到兵车万乘的国势,管辖全国,使六国诸侯都来朝见,已经一百多年了;"
|
translation = "然而秦凭借着它的小小的地方, 发展到兵车万乘的国势, 管辖全国, 使六国诸侯都来朝见, 已经一百多年了; "
|
||||||
keyword_note = {"区区"="小小", "致"="达到", "万乘"="兵车万乘", "序八州"="管辖全国", "朝同列"="使同列来朝拜", "百有余年"="一百多年"}
|
keyword_note = {"区区"="小小", "致"="达到", "万乘"="兵车万乘", "序八州"="管辖全国", "朝同列"="使同列来朝拜", "百有余年"="一百多年"}
|
||||||
|
|
||||||
["然后以六合为家, 崤函为宫;"]
|
["然后以六合为家, 崤函为宫;"]
|
||||||
note = []
|
note = []
|
||||||
content = "然后/以/六合/为家/, 崤函/为宫; /"
|
content = "然后/以/六合/为家/, 崤函/为宫; /"
|
||||||
translation = "这之后把天下作为家业,用崤山、函谷关作为自己的内宫;"
|
translation = "这之后把天下作为家业, 用崤山、函谷关作为自己的内宫; "
|
||||||
keyword_note = {"六合为家"="把天下作为家业", "崤函为宫"="把崤山函谷关作为内宫"}
|
keyword_note = {"六合为家"="把天下作为家业", "崤函为宫"="把崤山函谷关作为内宫"}
|
||||||
|
|
||||||
["一夫作难而七庙隳, 身死人手, 为天下笑者, 何也?"]
|
["一夫作难而七庙隳, 身死人手, 为天下笑者, 何也?"]
|
||||||
note = []
|
note = []
|
||||||
content = "一夫/作难/而/七庙/隳/, 身死/人手/, 为/天下/笑者/, 何也?/"
|
content = "一夫/作难/而/七庙/隳/, 身死/人手/, 为/天下/笑者/, 何也?/"
|
||||||
translation = "陈涉一人起义国家就灭亡了,秦王子婴死在别人项羽手里,被天下人耻笑,这是为什么呢?"
|
translation = "陈涉一人起义国家就灭亡了, 秦王子婴死在别人项羽手里, 被天下人耻笑, 这是为什么呢? "
|
||||||
keyword_note = {"一夫作难"="一人起义", "七庙隳"="宗庙毁灭,国家灭亡", "身死人手"="死在别人手里", "为天下笑"="被天下人耻笑"}
|
keyword_note = {"一夫作难"="一人起义", "七庙隳"="宗庙毁灭, 国家灭亡", "身死人手"="死在别人手里", "为天下笑"="被天下人耻笑"}
|
||||||
|
|
||||||
["仁义不施而攻守之势异也."]
|
["仁义不施而攻守之势异也."]
|
||||||
note = []
|
note = []
|
||||||
content = "仁义/不施/而/攻守/之势/异也./"
|
content = "仁义/不施/而/攻守/之势/异也./"
|
||||||
translation = "就因为不施行仁政而使攻守的形势发生了变化啊。"
|
translation = "就因为不施行仁政而使攻守的形势发生了变化啊. "
|
||||||
keyword_note = {"仁义"="仁政", "不施"="不施行", "攻守之势"="进攻和防守的形势", "异"="发生变化"}
|
keyword_note = {"仁义"="仁政", "不施"="不施行", "攻守之势"="进攻和防守的形势", "异"="发生变化"}
|
||||||
@@ -27,10 +27,10 @@ try:
|
|||||||
"config_var", default=ConfigFile(workdir / "config" / "config.toml")
|
"config_var", default=ConfigFile(workdir / "config" / "config.toml")
|
||||||
) # 配置文件
|
) # 配置文件
|
||||||
print("已加载自定义用户配置")
|
print("已加载自定义用户配置")
|
||||||
logger.info("已加载自定义用户配置,路径: %s", workdir / "config" / "config.toml")
|
logger.info("已加载自定义用户配置, 路径: %s", workdir / "config" / "config.toml")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("未能加载自定义用户配置")
|
print("未能加载自定义用户配置")
|
||||||
logger.warning("未能加载自定义用户配置,错误: %s", e)
|
logger.warning("未能加载自定义用户配置, 错误: %s", e)
|
||||||
|
|
||||||
# runtime_var: ContextVar = ContextVar('runtime_var', default=dict()) # 运行时共享数据
|
# runtime_var: ContextVar = ContextVar('runtime_var', default=dict()) # 运行时共享数据
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class NucleonCreatorScreen(Screen):
|
|||||||
if selected is None:
|
if selected is None:
|
||||||
self.notify("请选择一个模板", severity="error")
|
self.notify("请选择一个模板", severity="error")
|
||||||
return
|
return
|
||||||
# selected 是描述字符串,格式如 "描述 (filename.toml)"
|
# selected 是描述字符串, 格式如 "描述 (filename.toml)"
|
||||||
# 提取文件名
|
# 提取文件名
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class BasicEvaluation(BasePuzzleWidget):
|
|||||||
yield Label(self.atom.registry["nucleon"]["content"], id="main")
|
yield Label(self.atom.registry["nucleon"]["content"], id="main")
|
||||||
|
|
||||||
# 显示评估说明(可选)
|
# 显示评估说明(可选)
|
||||||
yield Static("请评估你对这个内容的记忆程度:", classes="instruction")
|
yield Static("请评估你对这个内容的记忆程度: ", classes="instruction")
|
||||||
|
|
||||||
# 按钮容器
|
# 按钮容器
|
||||||
with ScrollableContainer(id="button_container"):
|
with ScrollableContainer(id="button_container"):
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ algorithms = {
|
|||||||
"supermemo2": SM2Algorithm,
|
"supermemo2": SM2Algorithm,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("算法模块初始化完成,注册的算法: %s", list(algorithms.keys()))
|
logger.debug("算法模块初始化完成, 注册的算法: %s", list(algorithms.keys()))
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class BaseAlgorithm:
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""迭代记忆数据"""
|
"""迭代记忆数据"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"BaseAlgorithm.revisor 被调用,algodata keys: %s, feedback: %d, is_new_activation: %s",
|
"BaseAlgorithm.revisor 被调用, algodata keys: %s, feedback: %d, is_new_activation: %s",
|
||||||
list(algodata.keys()) if algodata else [],
|
list(algodata.keys()) if algodata else [],
|
||||||
feedback,
|
feedback,
|
||||||
is_new_activation,
|
is_new_activation,
|
||||||
@@ -45,7 +45,7 @@ class BaseAlgorithm:
|
|||||||
def is_due(cls, algodata) -> int:
|
def is_due(cls, algodata) -> int:
|
||||||
"""是否应该复习"""
|
"""是否应该复习"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"BaseAlgorithm.is_due 被调用,algodata keys: %s",
|
"BaseAlgorithm.is_due 被调用, algodata keys: %s",
|
||||||
list(algodata.keys()) if algodata else [],
|
list(algodata.keys()) if algodata else [],
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
@@ -54,7 +54,7 @@ class BaseAlgorithm:
|
|||||||
def rate(cls, algodata) -> str:
|
def rate(cls, algodata) -> str:
|
||||||
"""获取评分信息"""
|
"""获取评分信息"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"BaseAlgorithm.rate 被调用,algodata keys: %s",
|
"BaseAlgorithm.rate 被调用, algodata keys: %s",
|
||||||
list(algodata.keys()) if algodata else [],
|
list(algodata.keys()) if algodata else [],
|
||||||
)
|
)
|
||||||
return ""
|
return ""
|
||||||
@@ -63,7 +63,7 @@ class BaseAlgorithm:
|
|||||||
def nextdate(cls, algodata) -> int:
|
def nextdate(cls, algodata) -> int:
|
||||||
"""获取下一次记忆时间戳"""
|
"""获取下一次记忆时间戳"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"BaseAlgorithm.nextdate 被调用,algodata keys: %s",
|
"BaseAlgorithm.nextdate 被调用, algodata keys: %s",
|
||||||
list(algodata.keys()) if algodata else [],
|
list(algodata.keys()) if algodata else [],
|
||||||
)
|
)
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ class SM2Algorithm(BaseAlgorithm):
|
|||||||
quality (int): 记忆保留率量化参数
|
quality (int): 记忆保留率量化参数
|
||||||
"""
|
"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"SM2.revisor 开始,feedback: %d, is_new_activation: %s",
|
"SM2.revisor 开始, feedback: %d, is_new_activation: %s",
|
||||||
feedback,
|
feedback,
|
||||||
is_new_activation,
|
is_new_activation,
|
||||||
)
|
)
|
||||||
|
|
||||||
if feedback == -1:
|
if feedback == -1:
|
||||||
logger.debug("feedback 为 -1,跳过更新")
|
logger.debug("feedback 为 -1, 跳过更新")
|
||||||
return
|
return
|
||||||
|
|
||||||
algodata[cls.algo_name]["efactor"] = algodata[cls.algo_name]["efactor"] + (
|
algodata[cls.algo_name]["efactor"] = algodata[cls.algo_name]["efactor"] + (
|
||||||
@@ -62,7 +62,7 @@ class SM2Algorithm(BaseAlgorithm):
|
|||||||
if feedback < 3:
|
if feedback < 3:
|
||||||
algodata[cls.algo_name]["rept"] = 0
|
algodata[cls.algo_name]["rept"] = 0
|
||||||
algodata[cls.algo_name]["interval"] = 0
|
algodata[cls.algo_name]["interval"] = 0
|
||||||
logger.debug("feedback < 3,重置 rept 和 interval")
|
logger.debug("feedback < 3, 重置 rept 和 interval")
|
||||||
else:
|
else:
|
||||||
algodata[cls.algo_name]["rept"] += 1
|
algodata[cls.algo_name]["rept"] += 1
|
||||||
logger.debug("递增 rept: %d", algodata[cls.algo_name]["rept"])
|
logger.debug("递增 rept: %d", algodata[cls.algo_name]["rept"])
|
||||||
@@ -73,20 +73,20 @@ class SM2Algorithm(BaseAlgorithm):
|
|||||||
if is_new_activation:
|
if is_new_activation:
|
||||||
algodata[cls.algo_name]["rept"] = 0
|
algodata[cls.algo_name]["rept"] = 0
|
||||||
algodata[cls.algo_name]["efactor"] = 2.5
|
algodata[cls.algo_name]["efactor"] = 2.5
|
||||||
logger.debug("新激活,重置 rept 和 efactor")
|
logger.debug("新激活, 重置 rept 和 efactor")
|
||||||
|
|
||||||
if algodata[cls.algo_name]["rept"] == 0:
|
if algodata[cls.algo_name]["rept"] == 0:
|
||||||
algodata[cls.algo_name]["interval"] = 1
|
algodata[cls.algo_name]["interval"] = 1
|
||||||
logger.debug("rept=0,设置 interval=1")
|
logger.debug("rept=0, 设置 interval=1")
|
||||||
elif algodata[cls.algo_name]["rept"] == 1:
|
elif algodata[cls.algo_name]["rept"] == 1:
|
||||||
algodata[cls.algo_name]["interval"] = 6
|
algodata[cls.algo_name]["interval"] = 6
|
||||||
logger.debug("rept=1,设置 interval=6")
|
logger.debug("rept=1, 设置 interval=6")
|
||||||
else:
|
else:
|
||||||
algodata[cls.algo_name]["interval"] = round(
|
algodata[cls.algo_name]["interval"] = round(
|
||||||
algodata[cls.algo_name]["interval"] * algodata[cls.algo_name]["efactor"]
|
algodata[cls.algo_name]["interval"] * algodata[cls.algo_name]["efactor"]
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"rept>1,计算 interval: %d", algodata[cls.algo_name]["interval"]
|
"rept>1, 计算 interval: %d", algodata[cls.algo_name]["interval"]
|
||||||
)
|
)
|
||||||
|
|
||||||
algodata[cls.algo_name]["last_date"] = timer.get_daystamp()
|
algodata[cls.algo_name]["last_date"] = timer.get_daystamp()
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ class Atom:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ident=""):
|
def __init__(self, ident=""):
|
||||||
logger.debug("创建 Atom 实例,ident: '%s'", ident)
|
logger.debug("创建 Atom 实例, ident: '%s'", ident)
|
||||||
self.ident = ident
|
self.ident = ident
|
||||||
atom_registry[ident] = self
|
atom_registry[ident] = self
|
||||||
logger.debug("Atom 已注册到全局注册表,当前注册表大小: %d", len(atom_registry))
|
logger.debug("Atom 已注册到全局注册表, 当前注册表大小: %d", len(atom_registry))
|
||||||
# self.is_evaled = False
|
# self.is_evaled = False
|
||||||
self.registry: AtomRegister = { # type: ignore
|
self.registry: AtomRegister = { # type: ignore
|
||||||
"nucleon": None,
|
"nucleon": None,
|
||||||
@@ -65,7 +65,7 @@ class Atom:
|
|||||||
logger.debug("Atom.link: key='%s', value type: %s", key, type(value).__name__)
|
logger.debug("Atom.link: key='%s', value type: %s", key, type(value).__name__)
|
||||||
if key in self.registry.keys():
|
if key in self.registry.keys():
|
||||||
self.registry[key] = value
|
self.registry[key] = value
|
||||||
logger.debug("键 '%s' 已链接,触发 do_eval", key)
|
logger.debug("键 '%s' 已链接, 触发 do_eval", key)
|
||||||
self.do_eval()
|
self.do_eval()
|
||||||
else:
|
else:
|
||||||
logger.error("尝试链接不受支持的键: '%s'", key)
|
logger.error("尝试链接不受支持的键: '%s'", key)
|
||||||
@@ -120,8 +120,8 @@ class Atom:
|
|||||||
default = config_var.get()["puzzles"]
|
default = config_var.get()["puzzles"]
|
||||||
metadata = nucleon.metadata
|
metadata = nucleon.metadata
|
||||||
except Exception:
|
except Exception:
|
||||||
# 如果无法获取配置或元数据,使用空字典
|
# 如果无法获取配置或元数据, 使用空字典
|
||||||
logger.debug("无法获取配置或元数据,使用空字典")
|
logger.debug("无法获取配置或元数据, 使用空字典")
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
eval_value = eval(s)
|
eval_value = eval(s)
|
||||||
@@ -157,19 +157,19 @@ class Atom:
|
|||||||
return modifier(data[5:])
|
return modifier(data[5:])
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# 如果 nucleon 存在且有 do_eval 方法,调用它
|
# 如果 nucleon 存在且有 do_eval 方法, 调用它
|
||||||
nucleon = self.registry["nucleon"]
|
nucleon = self.registry["nucleon"]
|
||||||
if nucleon is not None and hasattr(nucleon, "do_eval"):
|
if nucleon is not None and hasattr(nucleon, "do_eval"):
|
||||||
nucleon.do_eval()
|
nucleon.do_eval()
|
||||||
logger.debug("已调用 nucleon.do_eval")
|
logger.debug("已调用 nucleon.do_eval")
|
||||||
|
|
||||||
# 如果 electron 存在且其 algodata 包含 eval 字符串,遍历它
|
# 如果 electron 存在且其 algodata 包含 eval 字符串, 遍历它
|
||||||
electron = self.registry["electron"]
|
electron = self.registry["electron"]
|
||||||
if electron is not None and hasattr(electron, "algodata"):
|
if electron is not None and hasattr(electron, "algodata"):
|
||||||
traverse(electron.algodata, eval_with_env)
|
traverse(electron.algodata, eval_with_env)
|
||||||
logger.debug("已处理 electron algodata eval")
|
logger.debug("已处理 electron algodata eval")
|
||||||
|
|
||||||
# 如果 orbital 存在且是字典,遍历它
|
# 如果 orbital 存在且是字典, 遍历它
|
||||||
orbital = self.registry["orbital"]
|
orbital = self.registry["orbital"]
|
||||||
if orbital is not None and isinstance(orbital, dict):
|
if orbital is not None and isinstance(orbital, dict):
|
||||||
traverse(orbital, eval_with_env)
|
traverse(orbital, eval_with_env)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Electron:
|
|||||||
algo: 使用的算法模块标识
|
algo: 使用的算法模块标识
|
||||||
"""
|
"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"创建 Electron 实例,ident: '%s', algo_name: '%s'", ident, algo_name
|
"创建 Electron 实例, ident: '%s', algo_name: '%s'", ident, algo_name
|
||||||
)
|
)
|
||||||
self.algodata = algodata
|
self.algodata = algodata
|
||||||
self.ident = ident
|
self.ident = ident
|
||||||
@@ -27,20 +27,20 @@ class Electron:
|
|||||||
|
|
||||||
if self.algo not in self.algodata.keys():
|
if self.algo not in self.algodata.keys():
|
||||||
self.algodata[self.algo.algo_name] = {}
|
self.algodata[self.algo.algo_name] = {}
|
||||||
logger.debug("算法键 '%s' 不存在,已创建空字典", self.algo)
|
logger.debug("算法键 '%s' 不存在, 已创建空字典", self.algo)
|
||||||
if not self.algodata[self.algo.algo_name]:
|
if not self.algodata[self.algo.algo_name]:
|
||||||
logger.debug("算法数据为空,使用默认值初始化")
|
logger.debug("算法数据为空, 使用默认值初始化")
|
||||||
self._default_init(self.algo.defaults)
|
self._default_init(self.algo.defaults)
|
||||||
else:
|
else:
|
||||||
logger.debug("算法数据已存在,跳过默认初始化")
|
logger.debug("算法数据已存在, 跳过默认初始化")
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Electron 初始化完成,algodata keys: %s", list(self.algodata.keys())
|
"Electron 初始化完成, algodata keys: %s", list(self.algodata.keys())
|
||||||
)
|
)
|
||||||
|
|
||||||
def _default_init(self, defaults: dict):
|
def _default_init(self, defaults: dict):
|
||||||
"""默认初始化包装"""
|
"""默认初始化包装"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Electron._default_init: 使用默认值,keys: %s", list(defaults.keys())
|
"Electron._default_init: 使用默认值, keys: %s", list(defaults.keys())
|
||||||
)
|
)
|
||||||
self.algodata[self.algo.algo_name] = defaults.copy()
|
self.algodata[self.algo.algo_name] = defaults.copy()
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class Electron:
|
|||||||
logger.debug("Electron.activate: 激活 ident='%s'", self.ident)
|
logger.debug("Electron.activate: 激活 ident='%s'", self.ident)
|
||||||
self.algodata[self.algo.algo_name]["is_activated"] = 1
|
self.algodata[self.algo.algo_name]["is_activated"] = 1
|
||||||
self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp()
|
self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp()
|
||||||
logger.debug("电子已激活,is_activated=1")
|
logger.debug("电子已激活, is_activated=1")
|
||||||
|
|
||||||
def modify(self, var: str, value):
|
def modify(self, var: str, value):
|
||||||
"""修改 algodata[algo] 中子字典数据"""
|
"""修改 algodata[algo] 中子字典数据"""
|
||||||
@@ -57,7 +57,7 @@ class Electron:
|
|||||||
if var in self.algodata[self.algo.algo_name]:
|
if var in self.algodata[self.algo.algo_name]:
|
||||||
self.algodata[self.algo.algo_name][var] = value
|
self.algodata[self.algo.algo_name][var] = value
|
||||||
self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp()
|
self.algodata[self.algo.algo_name]["last_modify"] = timer.get_timestamp()
|
||||||
logger.debug("变量 '%s' 已修改,更新 last_modify", var)
|
logger.debug("变量 '%s' 已修改, 更新 last_modify", var)
|
||||||
else:
|
else:
|
||||||
logger.warning("'%s' 非已知元数据字段", var)
|
logger.warning("'%s' 非已知元数据字段", var)
|
||||||
print(f"警告: '{var}' 非已知元数据字段")
|
print(f"警告: '{var}' 非已知元数据字段")
|
||||||
@@ -74,7 +74,7 @@ class Electron:
|
|||||||
logger.debug("Electron.is_activated: ident='%s', 结果: %d", self.ident, result)
|
logger.debug("Electron.is_activated: ident='%s', 结果: %d", self.ident, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def rate(self):
|
def get_rate(self):
|
||||||
"评价"
|
"评价"
|
||||||
logger.debug("Electron.rate: ident='%s'", self.ident)
|
logger.debug("Electron.rate: ident='%s'", self.ident)
|
||||||
result = self.algo.rate(self.algodata)
|
result = self.algo.rate(self.algodata)
|
||||||
@@ -102,7 +102,7 @@ class Electron:
|
|||||||
)
|
)
|
||||||
self.algo.revisor(self.algodata, quality, is_new_activation)
|
self.algo.revisor(self.algodata, quality, is_new_activation)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"revisor 完成,更新后的 algodata: %s", self.algodata.get(self.algo, {})
|
"revisor 完成, 更新后的 algodata: %s", self.algodata.get(self.algo, {})
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def load_nucleon(path: pathlib.Path, fmt="toml"):
|
|||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
dictdata = dict()
|
dictdata = dict()
|
||||||
dictdata = toml.load(f) # type: ignore
|
dictdata = toml.load(f) # type: ignore
|
||||||
logger.debug("TOML 解析成功,keys: %s", list(dictdata.keys()))
|
logger.debug("TOML 解析成功, keys: %s", list(dictdata.keys()))
|
||||||
lst = list()
|
lst = list()
|
||||||
nested_data = dict()
|
nested_data = dict()
|
||||||
# 修正 toml 解析器的不管嵌套行为
|
# 修正 toml 解析器的不管嵌套行为
|
||||||
@@ -32,7 +32,7 @@ def load_nucleon(path: pathlib.Path, fmt="toml"):
|
|||||||
logger.debug("处理元数据键: %s", key)
|
logger.debug("处理元数据键: %s", key)
|
||||||
else:
|
else:
|
||||||
nested_data[key] = value
|
nested_data[key] = value
|
||||||
logger.debug("嵌套数据处理完成,keys: %s", list(nested_data.keys()))
|
logger.debug("嵌套数据处理完成, keys: %s", list(nested_data.keys()))
|
||||||
# print(nested_data)
|
# print(nested_data)
|
||||||
for item, attr in nested_data.items():
|
for item, attr in nested_data.items():
|
||||||
if item == "__metadata__":
|
if item == "__metadata__":
|
||||||
@@ -44,7 +44,7 @@ def load_nucleon(path: pathlib.Path, fmt="toml"):
|
|||||||
deepcopy(nested_data["__metadata__"]["orbital"]),
|
deepcopy(nested_data["__metadata__"]["orbital"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logger.debug("load_nucleon 完成,加载了 %d 个 Nucleon 对象", len(lst))
|
logger.debug("load_nucleon 完成, 加载了 %d 个 Nucleon 对象", len(lst))
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
|
||||||
@@ -62,10 +62,10 @@ def load_electron(path: pathlib.Path, fmt="json") -> dict:
|
|||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
dictdata = dict()
|
dictdata = dict()
|
||||||
dictdata = json.load(f) # type: ignore
|
dictdata = json.load(f) # type: ignore
|
||||||
logger.debug("JSON 解析成功,keys: %s", list(dictdata.keys()))
|
logger.debug("JSON 解析成功, keys: %s", list(dictdata.keys()))
|
||||||
dic = dict()
|
dic = dict()
|
||||||
for item, attr in dictdata.items():
|
for item, attr in dictdata.items():
|
||||||
logger.debug("处理电子项目: %s", item)
|
logger.debug("处理电子项目: %s", item)
|
||||||
dic[item] = Electron(item, attr)
|
dic[item] = Electron(item, attr)
|
||||||
logger.debug("load_electron 完成,加载了 %d 个 Electron 对象", len(dic))
|
logger.debug("load_electron 完成, 加载了 %d 个 Electron 对象", len(dic))
|
||||||
return dic
|
return dic
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Nucleon:
|
|||||||
metadata: 可选元数据信息
|
metadata: 可选元数据信息
|
||||||
"""
|
"""
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"创建 Nucleon 实例,ident: '%s', payload keys: %s, metadata keys: %s",
|
"创建 Nucleon 实例, ident: '%s', payload keys: %s, metadata keys: %s",
|
||||||
ident,
|
ident,
|
||||||
list(payload.keys()) if payload else [],
|
list(payload.keys()) if payload else [],
|
||||||
list(metadata.keys()) if metadata else [],
|
list(metadata.keys()) if metadata else [],
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def probe_all(is_stem=1):
|
|||||||
Returns:
|
Returns:
|
||||||
dict: 有三项, 每一项的键名都是文件组类型, 值都是文件组列表, 只包含文件名
|
dict: 有三项, 每一项的键名都是文件组类型, 值都是文件组列表, 只包含文件名
|
||||||
"""
|
"""
|
||||||
logger.debug("probe_all: 开始探测,is_stem=%d", is_stem)
|
logger.debug("probe_all: 开始探测, is_stem=%d", is_stem)
|
||||||
paths: dict = config_var.get().get("paths")
|
paths: dict = config_var.get().get("paths")
|
||||||
logger.debug("配置路径: %s", paths)
|
logger.debug("配置路径: %s", paths)
|
||||||
result = {}
|
result = {}
|
||||||
@@ -50,7 +50,7 @@ def probe_all(is_stem=1):
|
|||||||
else:
|
else:
|
||||||
result[item.replace("_dir", "")].append(str(i.name))
|
result[item.replace("_dir", "")].append(str(i.name))
|
||||||
logger.debug("目录 %s 中找到 %d 个文件", attr, file_count)
|
logger.debug("目录 %s 中找到 %d 个文件", attr, file_count)
|
||||||
logger.debug("probe_all 完成,结果 keys: %s", list(result.keys()))
|
logger.debug("probe_all 完成, 结果 keys: %s", list(result.keys()))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Puzzle 模块 - 谜题生成系统
|
Puzzle 模块 - 谜题生成系统
|
||||||
|
|
||||||
提供多种类型的谜题生成器,支持从字符串、字典等数据源导入题目
|
提供多种类型的谜题生成器, 支持从字符串、字典等数据源导入题目
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from heurams.services.logger import get_logger
|
from heurams.services.logger import get_logger
|
||||||
@@ -34,7 +34,7 @@ def create_by_dict(config_dict: dict) -> BasePuzzle:
|
|||||||
根据配置字典创建谜题
|
根据配置字典创建谜题
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config_dict: 配置字典,包含谜题类型和参数
|
config_dict: 配置字典, 包含谜题类型和参数
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BasePuzzle: 谜题实例
|
BasePuzzle: 谜题实例
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ClozePuzzle(BasePuzzle):
|
|||||||
answer.append(words[index])
|
answer.append(words[index])
|
||||||
self.answer = answer
|
self.answer = answer
|
||||||
self.wording = "".join(blanked_words)
|
self.wording = "".join(blanked_words)
|
||||||
logger.debug("ClozePuzzle.refresh 完成,生成 %d 个填空", len(answer))
|
logger.debug("ClozePuzzle.refresh 完成, 生成 %d 个填空", len(answer))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
logger.debug("ClozePuzzle.__str__ 被调用")
|
logger.debug("ClozePuzzle.__str__ 被调用")
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class Phaser:
|
|||||||
logger.debug("创建新记忆 Procession")
|
logger.debug("创建新记忆 Procession")
|
||||||
self.processions.append(Procession(atoms, PhaserState.FINAL_REVIEW, "总体复习"))
|
self.processions.append(Procession(atoms, PhaserState.FINAL_REVIEW, "总体复习"))
|
||||||
logger.debug("创建总体复习 Procession")
|
logger.debug("创建总体复习 Procession")
|
||||||
logger.debug("Phaser 初始化完成,processions 数量=%d", len(self.processions))
|
logger.debug("Phaser 初始化完成, processions 数量=%d", len(self.processions))
|
||||||
|
|
||||||
def current_procession(self):
|
def current_procession(self):
|
||||||
logger.debug("Phaser.current_procession 被调用")
|
logger.debug("Phaser.current_procession 被调用")
|
||||||
@@ -46,5 +46,5 @@ class Phaser:
|
|||||||
logger.debug("找到未完成的 Procession: phase=%s", i.phase)
|
logger.debug("找到未完成的 Procession: phase=%s", i.phase)
|
||||||
return i
|
return i
|
||||||
self.state = PhaserState.FINISHED
|
self.state = PhaserState.FINISHED
|
||||||
logger.debug("所有 Procession 已完成,状态设置为 FINISHED")
|
logger.debug("所有 Procession 已完成, 状态设置为 FINISHED")
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Procession:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.phase = phase
|
self.phase = phase
|
||||||
self.state: ProcessionState = ProcessionState.RUNNING
|
self.state: ProcessionState = ProcessionState.RUNNING
|
||||||
logger.debug("Procession 初始化完成,队列长度=%d", len(self.queue))
|
logger.debug("Procession 初始化完成, 队列长度=%d", len(self.queue))
|
||||||
|
|
||||||
def forward(self, step=1):
|
def forward(self, step=1):
|
||||||
logger.debug("Procession.forward: step=%d, 当前 cursor=%d", step, self.cursor)
|
logger.debug("Procession.forward: step=%d, 当前 cursor=%d", step, self.cursor)
|
||||||
@@ -49,7 +49,7 @@ class Procession:
|
|||||||
logger.debug("Procession.append: atom=%s", atom.ident if atom else "None")
|
logger.debug("Procession.append: atom=%s", atom.ident if atom else "None")
|
||||||
if self.queue[len(self.queue) - 1] != atom or len(self) <= 1:
|
if self.queue[len(self.queue) - 1] != atom or len(self) <= 1:
|
||||||
self.queue.append(atom)
|
self.queue.append(atom)
|
||||||
logger.debug("原子已追加到队列,新队列长度=%d", len(self.queue))
|
logger.debug("原子已追加到队列, 新队列长度=%d", len(self.queue))
|
||||||
else:
|
else:
|
||||||
logger.debug("原子未追加(重复或队列长度<=1)")
|
logger.debug("原子未追加(重复或队列长度<=1)")
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ class BaseTTS:
|
|||||||
def convert(cls, text: str, path: pathlib.Path | str = "") -> pathlib.Path:
|
def convert(cls, text: str, path: pathlib.Path | str = "") -> pathlib.Path:
|
||||||
"""path 是可选参数, 不填则自动返回生成文件路径"""
|
"""path 是可选参数, 不填则自动返回生成文件路径"""
|
||||||
logger.debug("BaseTTS.convert: text length=%d, path=%s", len(text), path)
|
logger.debug("BaseTTS.convert: text length=%d, path=%s", len(text), path)
|
||||||
logger.warning("BaseTTS.convert 是基类方法,未实现具体功能")
|
logger.warning("BaseTTS.convert 是基类方法, 未实现具体功能")
|
||||||
return path # type: ignore
|
return path # type: ignore
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class EdgeTTS(BaseTTS):
|
|||||||
text,
|
text,
|
||||||
"zh-CN-YunjianNeural",
|
"zh-CN-YunjianNeural",
|
||||||
)
|
)
|
||||||
logger.debug("EdgeTTS 通信对象创建成功,正在保存音频")
|
logger.debug("EdgeTTS 通信对象创建成功, 正在保存音频")
|
||||||
communicate.save_sync(str(path))
|
communicate.save_sync(str(path))
|
||||||
logger.debug("EdgeTTS 音频已保存到: %s", path)
|
logger.debug("EdgeTTS 音频已保存到: %s", path)
|
||||||
return path # type: ignore
|
return path # type: ignore
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
play_by_path: Callable = prov[config_var.get()["services"]["audio"]].play_by_path
|
play_by_path: Callable = prov[config_var.get()["services"]["audio"]].play_by_path
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"音频服务初始化完成,使用 provider: %s", config_var.get()["services"]["audio"]
|
"音频服务初始化完成, 使用 provider: %s", config_var.get()["services"]["audio"]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class ConfigFile:
|
|||||||
self.logger.debug("配置文件已保存: %s", save_path)
|
self.logger.debug("配置文件已保存: %s", save_path)
|
||||||
|
|
||||||
def get(self, key: str, default: typing.Any = None) -> typing.Any:
|
def get(self, key: str, default: typing.Any = None) -> typing.Any:
|
||||||
"""获取配置值,如果不存在返回默认值"""
|
"""获取配置值, 如果不存在返回默认值"""
|
||||||
return self.data.get(key, default)
|
return self.data.get(key, default)
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> typing.Any:
|
def __getitem__(self, key: str) -> typing.Any:
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ def setup_logging(
|
|||||||
app_logger.setLevel(log_level) # 保持DEBUG级别
|
app_logger.setLevel(log_level) # 保持DEBUG级别
|
||||||
app_logger.addHandler(file_handler)
|
app_logger.addHandler(file_handler)
|
||||||
|
|
||||||
# 禁止传播到root logger,避免双重记录
|
# 禁止传播到root logger, 避免双重记录
|
||||||
app_logger.propagate = False
|
app_logger.propagate = False
|
||||||
|
|
||||||
# 设置第三方库的日志级别为WARNING,避免调试信息干扰
|
# 设置第三方库的日志级别为WARNING, 避免调试信息干扰
|
||||||
third_party_loggers = [
|
third_party_loggers = [
|
||||||
"markdown_it",
|
"markdown_it",
|
||||||
"markdown_it.rules_block",
|
"markdown_it.rules_block",
|
||||||
@@ -101,7 +101,7 @@ def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|||||||
if name is None:
|
if name is None:
|
||||||
return logging.getLogger()
|
return logging.getLogger()
|
||||||
|
|
||||||
# 确保使用 heurams 作为前缀,继承应用logger的配置
|
# 确保使用 heurams 作为前缀, 继承应用logger的配置
|
||||||
if not name.startswith("heurams") and name != "":
|
if not name.startswith("heurams") and name != "":
|
||||||
logger_name = f"heurams.{name}"
|
logger_name = f"heurams.{name}"
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ logger = get_logger(__name__)
|
|||||||
|
|
||||||
convert: Callable = TTSs[config_var.get().get("tts_provider")]
|
convert: Callable = TTSs[config_var.get().get("tts_provider")]
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"TTS服务初始化完成,使用 provider: %s", config_var.get().get("tts_provider")
|
"TTS服务初始化完成, 使用 provider: %s", config_var.get().get("tts_provider")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
DashboardScreen 的测试,包括单元测试和 pilot 测试。
|
DashboardScreen 的测试, 包括单元测试和 pilot 测试.
|
||||||
"""
|
"""
|
||||||
import unittest
|
import unittest
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -16,15 +16,15 @@ from heurams.interface.screens.dashboard import DashboardScreen
|
|||||||
|
|
||||||
|
|
||||||
class TestDashboardScreenUnit(unittest.TestCase):
|
class TestDashboardScreenUnit(unittest.TestCase):
|
||||||
"""DashboardScreen 的单元测试(不启动完整应用)。"""
|
"""DashboardScreen 的单元测试(不启动完整应用). """
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""在每个测试之前运行,设置临时目录和配置。"""
|
"""在每个测试之前运行, 设置临时目录和配置. """
|
||||||
# 创建临时目录用于测试数据
|
# 创建临时目录用于测试数据
|
||||||
self.temp_dir = tempfile.TemporaryDirectory()
|
self.temp_dir = tempfile.TemporaryDirectory()
|
||||||
self.temp_path = pathlib.Path(self.temp_dir.name)
|
self.temp_path = pathlib.Path(self.temp_dir.name)
|
||||||
|
|
||||||
# 创建默认配置,并修改路径指向临时目录
|
# 创建默认配置, 并修改路径指向临时目录
|
||||||
default_config_path = (
|
default_config_path = (
|
||||||
pathlib.Path(__file__).parent.parent.parent
|
pathlib.Path(__file__).parent.parent.parent
|
||||||
/ "src/heurams/default/config/config.toml"
|
/ "src/heurams/default/config/config.toml"
|
||||||
@@ -36,7 +36,7 @@ class TestDashboardScreenUnit(unittest.TestCase):
|
|||||||
config_data["paths"]["electron_dir"] = str(self.temp_path / "electron")
|
config_data["paths"]["electron_dir"] = str(self.temp_path / "electron")
|
||||||
config_data["paths"]["orbital_dir"] = str(self.temp_path / "orbital")
|
config_data["paths"]["orbital_dir"] = str(self.temp_path / "orbital")
|
||||||
config_data["paths"]["cache_dir"] = str(self.temp_path / "cache")
|
config_data["paths"]["cache_dir"] = str(self.temp_path / "cache")
|
||||||
# 禁用快速通过,避免测试干扰
|
# 禁用快速通过, 避免测试干扰
|
||||||
config_data["quick_pass"] = 0
|
config_data["quick_pass"] = 0
|
||||||
# 禁用时间覆盖
|
# 禁用时间覆盖
|
||||||
config_data["daystamp_override"] = -1
|
config_data["daystamp_override"] = -1
|
||||||
@@ -53,12 +53,12 @@ class TestDashboardScreenUnit(unittest.TestCase):
|
|||||||
self.config_ctx.__enter__()
|
self.config_ctx.__enter__()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""在每个测试之后清理。"""
|
"""在每个测试之后清理. """
|
||||||
self.config_ctx.__exit__(None, None, None)
|
self.config_ctx.__exit__(None, None, None)
|
||||||
self.temp_dir.cleanup()
|
self.temp_dir.cleanup()
|
||||||
|
|
||||||
def test_compose(self):
|
def test_compose(self):
|
||||||
"""测试 compose 方法返回正确的部件。"""
|
"""测试 compose 方法返回正确的部件. """
|
||||||
screen = DashboardScreen()
|
screen = DashboardScreen()
|
||||||
# 手动调用 compose 并收集部件
|
# 手动调用 compose 并收集部件
|
||||||
from textual.app import ComposeResult
|
from textual.app import ComposeResult
|
||||||
@@ -77,14 +77,14 @@ class TestDashboardScreenUnit(unittest.TestCase):
|
|||||||
|
|
||||||
container_present = any(isinstance(w, ScrollableContainer) for w in widgets)
|
container_present = any(isinstance(w, ScrollableContainer) for w in widgets)
|
||||||
self.assertTrue(container_present)
|
self.assertTrue(container_present)
|
||||||
# 使用 query_one 查找 union-list,即使屏幕未挂载也可能有效
|
# 使用 query_one 查找 union-list, 即使屏幕未挂载也可能有效
|
||||||
list_view = screen.query_one("#union-list")
|
list_view = screen.query_one("#union-list")
|
||||||
self.assertIsNotNone(list_view)
|
self.assertIsNotNone(list_view)
|
||||||
self.assertEqual(list_view.id, "union-list")
|
self.assertEqual(list_view.id, "union-list")
|
||||||
self.assertEqual(list_view.__class__.__name__, "ListView")
|
self.assertEqual(list_view.__class__.__name__, "ListView")
|
||||||
|
|
||||||
def test_item_desc_generator(self):
|
def test_item_desc_generator(self):
|
||||||
"""测试 item_desc_generator 函数。"""
|
"""测试 item_desc_generator 函数. """
|
||||||
screen = DashboardScreen()
|
screen = DashboardScreen()
|
||||||
# 模拟一个文件名
|
# 模拟一个文件名
|
||||||
filename = "test.toml"
|
filename = "test.toml"
|
||||||
@@ -94,16 +94,16 @@ class TestDashboardScreenUnit(unittest.TestCase):
|
|||||||
self.assertIn(1, result)
|
self.assertIn(1, result)
|
||||||
# 检查内容
|
# 检查内容
|
||||||
self.assertIn("test.toml", result[0])
|
self.assertIn("test.toml", result[0])
|
||||||
# 由于 electron 文件不存在,应显示“尚未激活”
|
# 由于 electron 文件不存在, 应显示“尚未激活”
|
||||||
self.assertIn("尚未激活", result[1])
|
self.assertIn("尚未激活", result[1])
|
||||||
|
|
||||||
|
|
||||||
@unittest.skip("Pilot 测试需要进一步配置,暂不运行")
|
@unittest.skip("Pilot 测试需要进一步配置, 暂不运行")
|
||||||
class TestDashboardScreenPilot(unittest.TestCase):
|
class TestDashboardScreenPilot(unittest.TestCase):
|
||||||
"""使用 Textual Pilot 的集成测试。"""
|
"""使用 Textual Pilot 的集成测试. """
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""配置临时目录和配置。"""
|
"""配置临时目录和配置. """
|
||||||
self.temp_dir = tempfile.TemporaryDirectory()
|
self.temp_dir = tempfile.TemporaryDirectory()
|
||||||
self.temp_path = pathlib.Path(self.temp_dir.name)
|
self.temp_path = pathlib.Path(self.temp_dir.name)
|
||||||
|
|
||||||
@@ -134,11 +134,11 @@ class TestDashboardScreenPilot(unittest.TestCase):
|
|||||||
self.temp_dir.cleanup()
|
self.temp_dir.cleanup()
|
||||||
|
|
||||||
def test_dashboard_loads_with_pilot(self):
|
def test_dashboard_loads_with_pilot(self):
|
||||||
"""使用 Pilot 测试 DashboardScreen 加载。"""
|
"""使用 Pilot 测试 DashboardScreen 加载. """
|
||||||
with patch("heurams.interface.__main__.environment_check"):
|
with patch("heurams.interface.__main__.environment_check"):
|
||||||
app = HeurAMSApp()
|
app = HeurAMSApp()
|
||||||
# 注意:Pilot 在 Textual 6.9.0 中的用法可能不同
|
# 注意: Pilot 在 Textual 6.9.0 中的用法可能不同
|
||||||
# 以下为示例代码,可能需要调整
|
# 以下为示例代码, 可能需要调整
|
||||||
pilot = Pilot(app)
|
pilot = Pilot(app)
|
||||||
# 等待应用启动
|
# 等待应用启动
|
||||||
pilot.pause()
|
pilot.pause()
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class TestSM2Algorithm(unittest.TestCase):
|
|||||||
self.assertEqual(defaults["last_date"], 0)
|
self.assertEqual(defaults["last_date"], 0)
|
||||||
self.assertEqual(defaults["next_date"], 0)
|
self.assertEqual(defaults["next_date"], 0)
|
||||||
self.assertEqual(defaults["is_activated"], 0)
|
self.assertEqual(defaults["is_activated"], 0)
|
||||||
# last_modify 是动态的,仅检查存在性
|
# last_modify 是动态的, 仅检查存在性
|
||||||
self.assertIn("last_modify", defaults)
|
self.assertIn("last_modify", defaults)
|
||||||
|
|
||||||
def test_revisor_feedback_minus_one(self):
|
def test_revisor_feedback_minus_one(self):
|
||||||
@@ -129,12 +129,12 @@ class TestSM2Algorithm(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SM2Algorithm.revisor(algodata, feedback=4)
|
SM2Algorithm.revisor(algodata, feedback=4)
|
||||||
# rept 从 0 递增到 1,因此 interval 应为 6
|
# rept 从 0 递增到 1, 因此 interval 应为 6
|
||||||
self.assertEqual(algodata[SM2Algorithm.algo_name]["interval"], 6)
|
self.assertEqual(algodata[SM2Algorithm.algo_name]["interval"], 6)
|
||||||
|
|
||||||
# 现在 rept=1,再次调用 revisor 递增到 2
|
# 现在 rept=1, 再次调用 revisor 递增到 2
|
||||||
SM2Algorithm.revisor(algodata, feedback=4)
|
SM2Algorithm.revisor(algodata, feedback=4)
|
||||||
# rept=2,interval = round(6 * 2.5) = 15
|
# rept=2, interval = round(6 * 2.5) = 15
|
||||||
self.assertEqual(algodata[SM2Algorithm.algo_name]["interval"], 15)
|
self.assertEqual(algodata[SM2Algorithm.algo_name]["interval"], 15)
|
||||||
|
|
||||||
# 单独测试 rept=1 的情况
|
# 单独测试 rept=1 的情况
|
||||||
@@ -147,7 +147,7 @@ class TestSM2Algorithm(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SM2Algorithm.revisor(algodata2, feedback=4)
|
SM2Algorithm.revisor(algodata2, feedback=4)
|
||||||
# rept 递增到 2,interval = round(0 * 2.5) = 0
|
# rept 递增到 2, interval = round(0 * 2.5) = 0
|
||||||
self.assertEqual(algodata2[SM2Algorithm.algo_name]["interval"], 0)
|
self.assertEqual(algodata2[SM2Algorithm.algo_name]["interval"], 0)
|
||||||
|
|
||||||
def test_revisor_updates_dates(self):
|
def test_revisor_updates_dates(self):
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class TestElectron(unittest.TestCase):
|
|||||||
defaults = electron.algo.defaults
|
defaults = electron.algo.defaults
|
||||||
for key, value in defaults.items():
|
for key, value in defaults.items():
|
||||||
if key == "last_modify":
|
if key == "last_modify":
|
||||||
# last_modify 是动态的,只检查存在性
|
# last_modify 是动态的, 只检查存在性
|
||||||
self.assertIn(key, electron.algodata[electron.algo])
|
self.assertIn(key, electron.algodata[electron.algo])
|
||||||
elif key == "is_activated":
|
elif key == "is_activated":
|
||||||
# TODO: 调查为什么 is_activated 是 1
|
# TODO: 调查为什么 is_activated 是 1
|
||||||
@@ -45,7 +45,7 @@ class TestElectron(unittest.TestCase):
|
|||||||
electron = Electron("test_electron", algodata=algodata)
|
electron = Electron("test_electron", algodata=algodata)
|
||||||
self.assertEqual(electron.algodata[electron.algo]["efactor"], 2.5)
|
self.assertEqual(electron.algodata[electron.algo]["efactor"], 2.5)
|
||||||
self.assertEqual(electron.algodata[electron.algo]["interval"], 1)
|
self.assertEqual(electron.algodata[electron.algo]["interval"], 1)
|
||||||
# 其他字段可能不存在,因为未提供默认初始化
|
# 其他字段可能不存在, 因为未提供默认初始化
|
||||||
# 检查 real_rept 不存在
|
# 检查 real_rept 不存在
|
||||||
self.assertNotIn("real_rept", electron.algodata[electron.algo])
|
self.assertNotIn("real_rept", electron.algodata[electron.algo])
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class TestElectron(unittest.TestCase):
|
|||||||
electron = Electron("test_electron")
|
electron = Electron("test_electron")
|
||||||
with patch.object(electron.algo, "rate") as mock_rate:
|
with patch.object(electron.algo, "rate") as mock_rate:
|
||||||
mock_rate.return_value = "good"
|
mock_rate.return_value = "good"
|
||||||
result = electron.rate()
|
result = electron.get_rate()
|
||||||
mock_rate.assert_called_once_with(electron.algodata)
|
mock_rate.assert_called_once_with(electron.algodata)
|
||||||
self.assertEqual(result, "good")
|
self.assertEqual(result, "good")
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class TestClozePuzzle(unittest.TestCase):
|
|||||||
# 检查 wording 和 answer
|
# 检查 wording 和 answer
|
||||||
self.assertNotEqual(puzzle.wording, "填空题 - 尚未刷新谜题")
|
self.assertNotEqual(puzzle.wording, "填空题 - 尚未刷新谜题")
|
||||||
self.assertNotEqual(puzzle.answer, ["填空题 - 尚未刷新谜题"])
|
self.assertNotEqual(puzzle.answer, ["填空题 - 尚未刷新谜题"])
|
||||||
# 根据模拟,应该有两个填空
|
# 根据模拟, 应该有两个填空
|
||||||
self.assertEqual(len(puzzle.answer), 2)
|
self.assertEqual(len(puzzle.answer), 2)
|
||||||
self.assertEqual(puzzle.answer, ["hello", "test"])
|
self.assertEqual(puzzle.answer, ["hello", "test"])
|
||||||
# wording 应包含下划线
|
# wording 应包含下划线
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ class TestMCQPuzzle(unittest.TestCase):
|
|||||||
def test_init_jammer_ensures_minimum(self):
|
def test_init_jammer_ensures_minimum(self):
|
||||||
"""测试干扰项至少保证 4 个"""
|
"""测试干扰项至少保证 4 个"""
|
||||||
puzzle = MCQPuzzle({}, [])
|
puzzle = MCQPuzzle({}, [])
|
||||||
# 正确答案为空,干扰项为空,应填充空格
|
# 正确答案为空, 干扰项为空, 应填充空格
|
||||||
self.assertEqual(len(puzzle.jammer), 4)
|
self.assertEqual(len(puzzle.jammer), 4)
|
||||||
self.assertEqual(set(puzzle.jammer), {" "}) # 三个空格?实际上循环填充空格
|
self.assertEqual(set(puzzle.jammer), {" "}) # 三个空格? 实际上循环填充空格
|
||||||
|
|
||||||
@patch("random.sample")
|
@patch("random.sample")
|
||||||
@patch("random.shuffle")
|
@patch("random.shuffle")
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class TestPhaser(unittest.TestCase):
|
|||||||
atoms = [self.atom_old, self.atom_new, self.atom_old]
|
atoms = [self.atom_old, self.atom_new, self.atom_old]
|
||||||
phaser = Phaser(atoms)
|
phaser = Phaser(atoms)
|
||||||
|
|
||||||
# 应该创建两个 Procession:一个用于旧原子,一个用于新原子,以及一个总体复习
|
# 应该创建两个 Procession: 一个用于旧原子, 一个用于新原子, 以及一个总体复习
|
||||||
self.assertEqual(self.mock_procession_class.call_count, 3)
|
self.assertEqual(self.mock_procession_class.call_count, 3)
|
||||||
|
|
||||||
# 检查调用参数
|
# 检查调用参数
|
||||||
@@ -52,7 +52,7 @@ class TestPhaser(unittest.TestCase):
|
|||||||
atoms = [self.atom_old, self.atom_old]
|
atoms = [self.atom_old, self.atom_old]
|
||||||
phaser = Phaser(atoms)
|
phaser = Phaser(atoms)
|
||||||
|
|
||||||
# 应该创建两个 Procession:一个初始复习,一个总体复习
|
# 应该创建两个 Procession: 一个初始复习, 一个总体复习
|
||||||
self.assertEqual(self.mock_procession_class.call_count, 2)
|
self.assertEqual(self.mock_procession_class.call_count, 2)
|
||||||
calls = self.mock_procession_class.call_args_list
|
calls = self.mock_procession_class.call_args_list
|
||||||
self.assertEqual(calls[0][0][0], atoms)
|
self.assertEqual(calls[0][0][0], atoms)
|
||||||
|
|||||||
Reference in New Issue
Block a user