Archived
0
0
This commit is contained in:
2025-12-17 20:52:11 +08:00
parent 8da8354609
commit 38f720aa7b
30 changed files with 181 additions and 181 deletions

View File

@@ -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 许可证下发布.

View File

@@ -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) 文件.

View File

@@ -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 = {"仁义"="仁政", "不施"="不施行", "攻守之势"="进攻和防守的形势", "异"="发生变化"}

View File

@@ -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()) # 运行时共享数据

View File

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

View File

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

View File

@@ -12,4 +12,4 @@ algorithms = {
"supermemo2": SM2Algorithm, "supermemo2": SM2Algorithm,
} }
logger.debug("算法模块初始化完成注册的算法: %s", list(algorithms.keys())) logger.debug("算法模块初始化完成, 注册的算法: %s", list(algorithms.keys()))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: 谜题实例

View File

@@ -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__ 被调用")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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=2interval = 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 递增到 2interval = 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):

View File

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

View File

@@ -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 应包含下划线

View File

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

View File

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