From d1a1fa193fa5d71ebcf3485481e61f3408d40689 Mon Sep 17 00:00:00 2001 From: pluvium27 Date: Mon, 20 Apr 2026 01:44:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=AF=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8=E5=92=8C=E9=85=8D=E7=BD=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E8=BF=9B=E8=A1=8C=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/config/config.toml | 65 +- data/config/data/config/config.toml | 0 data/config/global.toml | 7 + data/config/interface/global.toml | 6 + data/config/interface/puzzles/cloze.toml | 1 + data/config/interface/puzzles/mcq.toml | 1 + data/config/interface/screens/memoqueue.toml | 1 + .../config/interface/widgets/recognition.toml | 1 + data/config/providers/tts/edgetts.toml | 24 + data/config/services/audio.toml | 8 + data/config/services/llm.toml | 5 + data/config/services/sync.toml | 6 + data/config/services/timer.toml | 3 + data/config/services/tts.toml | 6 + data/repo/cngk-t/algodata.json | 1438 ++++++++--------- src/heurams/context.py | 8 +- src/heurams/interface/__init__.py | 12 + src/heurams/interface/__main__.py | 2 +- src/heurams/interface/screens/dashboard.py | 6 +- src/heurams/interface/screens/favmgr.py | 2 +- src/heurams/interface/screens/memoqueue.py | 14 +- src/heurams/interface/screens/precache.py | 6 +- src/heurams/interface/screens/preparation.py | 6 +- src/heurams/interface/widgets/recognition.py | 2 +- src/heurams/kernel/algorithms/__init__.py | 6 +- .../kernel/algorithms/{fast0.py => nsp0.py} | 14 +- src/heurams/kernel/algorithms/sm15m.py | 2 +- src/heurams/kernel/particles/nucleon.py | 4 +- src/heurams/services/audio_service.py | 4 +- src/heurams/services/config copy.py | 127 ++ src/heurams/services/config.py | 181 +-- src/heurams/services/epath.py | 30 + src/heurams/services/exceptions.py | 4 + src/heurams/services/favorite_service.py | 2 +- src/heurams/services/timer.py | 6 +- src/heurams/services/tts_service.py | 4 +- 36 files changed, 1097 insertions(+), 917 deletions(-) delete mode 100644 data/config/data/config/config.toml create mode 100644 data/config/global.toml create mode 100644 data/config/interface/global.toml create mode 100644 data/config/interface/puzzles/cloze.toml create mode 100644 data/config/interface/puzzles/mcq.toml create mode 100644 data/config/interface/screens/memoqueue.toml create mode 100644 data/config/interface/widgets/recognition.toml create mode 100644 data/config/providers/tts/edgetts.toml create mode 100644 data/config/services/audio.toml create mode 100644 data/config/services/llm.toml create mode 100644 data/config/services/sync.toml create mode 100644 data/config/services/timer.toml create mode 100644 data/config/services/tts.toml rename src/heurams/kernel/algorithms/{fast0.py => nsp0.py} (86%) create mode 100644 src/heurams/services/config copy.py create mode 100644 src/heurams/services/epath.py create mode 100644 src/heurams/services/exceptions.py diff --git a/data/config/config.toml b/data/config/config.toml index 10f3d05..d737df1 100644 --- a/data/config/config.toml +++ b/data/config/config.toml @@ -1,32 +1,31 @@ -# [调试] 将更改保存到文件 persist_to_file = 1 - -# [调试] 覆写时间, 设为 -1 以禁用 daystamp_override = -1 timestamp_override = -1 - -# [调试] 一键通过 quick_pass = true - -# [调试] 自动化测试模式(仅用于测试完整性) -auto_pass = true - -# 对于每个项目的默认新记忆原子数量 -scheduled_num = 100 - -# UTC 时间戳修正 仅用于 UNIX 日时间戳的生成修正, 单位为秒 -timezone_offset = +28800 # 中国标准时间 (UTC+8) - -[interface] - -[interface.memorizor] -autovoice = true # 自动语音播放, 仅限于 recognition 组件 +auto_pass = false +scheduled_num = 420 +timezone_offset = 28800 [algorithm] -# default = "SM-2" # 主要算法; 可选项: SM-2, SM-15M, FSRS, FAST-0 -default = 'FAST-0' +default = "FAST-0" -[puzzles] # 谜题默认配置 +[paths] +data = "./data" +cache = "./data/cache" +config = "./data/config" +global = "./data/global" +repo = "./data/repo" + +[services] +audio = "playsound" +tts = "edgetts" +llm = "openai" +sync = "webdav" + +[sync] + +[interface.memorizor] +autovoice = true [puzzles.mcq] max_riddles_num = 2 @@ -34,30 +33,16 @@ max_riddles_num = 2 [puzzles.cloze] min_denominator = 3 -[paths] # 相对于配置文件的 ".." (即工作目录) 而言 或绝对路径 -data = "./data" -cache = "./data/cache" -config = "./data/config" -global = "./data/global" -repo = "./data/repo" -[services] # 定义服务到提供者的映射 -audio = "playsound" # 可选项: playsound(通用), termux(仅用于支持 Android Termux), mpg123(TODO) -tts = "edgetts" # 可选项: edgetts -llm = "openai" # 可选项: openai -sync = "webdav" # 可选项: 留空, webdav +[providers.tts.edgetts] +voice = "zh-CN-XiaoxiaoNeural" -[providers.tts.edgetts] # EdgeTTS 设置 -voice = "zh-CN-XiaoxiaoNeural" # 可选项: zh-CN-YunjianNeural (男声), zh-CN-XiaoxiaoNeural (女声) - -[providers.llm.openai] # 与 OpenAI 相容的语言模型接口服务设置 +[providers.llm.openai] url = "" key = "" -[providers.sync.webdav] # WebDAV 同步设置 +[providers.sync.webdav] url = "" username = "" password = "" remote_path = "/heurams/" verify_ssl = true - -[sync] diff --git a/data/config/data/config/config.toml b/data/config/data/config/config.toml deleted file mode 100644 index e69de29..0000000 diff --git a/data/config/global.toml b/data/config/global.toml new file mode 100644 index 0000000..74fc3ed --- /dev/null +++ b/data/config/global.toml @@ -0,0 +1,7 @@ +enable_built_in_interface = true + +[paths] +data = "./data" +cache = "./data/cache" +config = "./data/config" +repo = "./data/repo" diff --git a/data/config/interface/global.toml b/data/config/interface/global.toml new file mode 100644 index 0000000..ddf073e --- /dev/null +++ b/data/config/interface/global.toml @@ -0,0 +1,6 @@ +persist_to_file = true +quick_pass = true +auto_pass = false +scheduled_num = 420 +algorithm = "NSP-0" +_algorithm_candidate = [ "SM-2", "SM-15M", "FSRS", "NSP-0", "None",] diff --git a/data/config/interface/puzzles/cloze.toml b/data/config/interface/puzzles/cloze.toml new file mode 100644 index 0000000..74f917b --- /dev/null +++ b/data/config/interface/puzzles/cloze.toml @@ -0,0 +1 @@ +min_denominator = 3 diff --git a/data/config/interface/puzzles/mcq.toml b/data/config/interface/puzzles/mcq.toml new file mode 100644 index 0000000..b72b3dd --- /dev/null +++ b/data/config/interface/puzzles/mcq.toml @@ -0,0 +1 @@ +max_riddles_num = 2 diff --git a/data/config/interface/screens/memoqueue.toml b/data/config/interface/screens/memoqueue.toml new file mode 100644 index 0000000..cf80dfb --- /dev/null +++ b/data/config/interface/screens/memoqueue.toml @@ -0,0 +1 @@ +autovoice = true diff --git a/data/config/interface/widgets/recognition.toml b/data/config/interface/widgets/recognition.toml new file mode 100644 index 0000000..cf80dfb --- /dev/null +++ b/data/config/interface/widgets/recognition.toml @@ -0,0 +1 @@ +autovoice = true diff --git a/data/config/providers/tts/edgetts.toml b/data/config/providers/tts/edgetts.toml new file mode 100644 index 0000000..1ada64f --- /dev/null +++ b/data/config/providers/tts/edgetts.toml @@ -0,0 +1,24 @@ +voice = "zh-CN-XiaoxiaoNeural" + +[_voice_candidate] +zh-CN-XiaoxiaoNeural = "晓晓: 中文温柔女声" +zh-CN-XiaoyiNeural = "晓伊: 中文甜美女声" +zh-CN-XiaochenNeural = "晓辰: 中文知性女声" +zh-CN-XiaohanNeural = "晓涵: 中文优雅女声" +zh-CN-XiaomengNeural = "晓梦: 中文梦幻女声" +zh-CN-XiaomoNeural = "晓墨: 中文文艺女声" +zh-CN-XiaoqiuNeural = "晓秋: 中文成熟女声" +zh-CN-XiaoruiNeural = "晓睿: 中文智慧女声" +zh-CN-XiaoshuangNeural = "晓双: 中文活泼女声" +zh-CN-XiaoxuanNeural = "晓萱: 中文清新女声" +zh-CN-XiaoyanNeural = "晓颜: 中文柔美女声" +zh-CN-XiaoyouNeural = "晓悠: 中文悠扬女声" +zh-CN-XiaozhenNeural = "晓甄: 中文端庄女声" +zh-CN-YunxiNeural = "云希: 中文清朗男声" +zh-CN-YunyangNeural = "云扬: 中文阳光男声" +zh-CN-YunjianNeural = "云健: 中文稳重男声" +zh-CN-YunfengNeural = "云枫: 中文磁性男声" +zh-CN-YunhaoNeural = "云皓: 中文豪迈男声" +zh-CN-YunxiaNeural = "云夏: 中文热情男声" +zh-CN-YunyeNeural = "云野: 中文野性男声" +zh-CN-YunzeNeural = "云泽: 中文深沉男声" diff --git a/data/config/services/audio.toml b/data/config/services/audio.toml new file mode 100644 index 0000000..d1722d7 --- /dev/null +++ b/data/config/services/audio.toml @@ -0,0 +1,8 @@ +provider = "playsound" + +[_provider_candidate] +playsound = "python 跨平台音频系统" +termux = "Android Termux 音频系统" +mpg123 = "通用音频系统, 依赖系统 mpg123" +pulseaudio = "高级音频路由系统" +none = "不使用音频" diff --git a/data/config/services/llm.toml b/data/config/services/llm.toml new file mode 100644 index 0000000..5e9e971 --- /dev/null +++ b/data/config/services/llm.toml @@ -0,0 +1,5 @@ +provider = "openai" + +[_provider_candidate] +openai = "OpenAI 风格 API, 同时支持与其相容的模型服务 (如 deepseek)" +none = "不使用语言大模型" diff --git a/data/config/services/sync.toml b/data/config/services/sync.toml new file mode 100644 index 0000000..da9c57c --- /dev/null +++ b/data/config/services/sync.toml @@ -0,0 +1,6 @@ +provider = "webdav" + +[_provider_candidate] +webdav = "WebDAV 兼容网络文件系统 (包括 webdavs)" +official = "官方同步服务器" +none = "不使用同步服务器" diff --git a/data/config/services/timer.toml b/data/config/services/timer.toml new file mode 100644 index 0000000..69d414d --- /dev/null +++ b/data/config/services/timer.toml @@ -0,0 +1,3 @@ +daystamp_override = -1 +timestamp_override = -1 +timezone_offset = 28800 diff --git a/data/config/services/tts.toml b/data/config/services/tts.toml new file mode 100644 index 0000000..d2bf261 --- /dev/null +++ b/data/config/services/tts.toml @@ -0,0 +1,6 @@ +provider = "edgetts" + +[_provider_candidate] +edgetts = "微软神经网络语音合成, 依赖微软网络服务" +espeak = "低保真度本地语音合成" +none = "不使用文本转语音" diff --git a/data/repo/cngk-t/algodata.json b/data/repo/cngk-t/algodata.json index 27df993..300550e 100644 --- a/data/repo/cngk-t/algodata.json +++ b/data/repo/cngk-t/algodata.json @@ -2,1441 +2,1441 @@ "临安春雨初霁": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4164822 + "last_modify": 1776577784.6136827 } }, "世味年来薄似纱, 谁令骑马客京华.": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4167655 + "last_modify": 1776577784.6139746 } }, "小楼一夜听春雨, 深巷明朝卖杏花.": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.417041 + "last_modify": 1776577784.6142678 } }, "矮纸斜行闲作草, 晴窗细乳戏分茶.": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4173286 + "last_modify": 1776577784.6145742 } }, "素衣莫起风尘叹, 犹及清明可到家.": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4176028 + "last_modify": 1776577784.6149702 } }, "书愤": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4178832 + "last_modify": 1776577784.6153867 } }, "早岁那知世事艰, 中原北望气如山": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.418158 + "last_modify": 1776577784.6157937 } }, "楼船夜雪瓜洲渡, 铁马秋风大散关": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.41845 + "last_modify": 1776577784.616204 } }, "塞上长城空自许, 镜中衰鬓已先斑": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.418725 + "last_modify": 1776577784.6166213 } }, "出师一表真名世, 千载谁堪伯仲间": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4190054 + "last_modify": 1776577784.6170292 } }, "五代史伶官传序": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4192874 + "last_modify": 1776577784.6174061 } }, "呜呼! 盛衰之理, 虽曰天命, 岂非人事哉!": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4195747 + "last_modify": 1776577784.6177616 } }, "原庄宗之所以得天下, 与其所以失之者, 可以知之矣": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4198568 + "last_modify": 1776577784.6181145 } }, "世言晋王之将终也, 以三矢赐庄宗而告之曰:": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4201329 + "last_modify": 1776577784.618471 } }, "梁, 吾仇也; 燕王, 吾所立; 契丹与吾约为兄弟; 而皆背晋以归梁": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4204254 + "last_modify": 1776577784.6188185 } }, "此三者, 吾遗恨也. 与尔三矢, 尔其无忘乃父之志!": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4207032 + "last_modify": 1776577784.619165 } }, "庄宗受而藏之于庙. 其后用兵, 则遣从事以一少牢告庙, 请其矢, 盛以锦囊, 负而前驱, 及凯旋而纳之": { "SM-2": { - "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "efactor": 2.2199999999999998, + "real_rept": 4, + "rept": 2, + "interval": 13, + "last_date": 20562, + "next_date": 20575, "is_activated": 1, - "last_modify": 1776527873.420987 + "last_modify": 1776577784.6195261 } }, "方其系燕父子以组, 函梁君臣之首, 入于太庙, 还矢先王, 而告以成功, 其意气之盛, 可谓壮哉!": { "SM-2": { - "efactor": 2.5, - "real_rept": 2, + "efactor": 1.8599999999999997, + "real_rept": 4, "rept": 0, "interval": 1, - "last_date": 20561, - "next_date": 20562, + "last_date": 20562, + "next_date": 20563, "is_activated": 1, - "last_modify": 1776527873.4212651 + "last_modify": 1776577784.6198707 } }, "及仇雠已灭, 天下已定, 一夫夜呼, 乱者四应, 仓皇东出, 未及见贼而士卒离散, 君臣相顾, 不知所归": { "SM-2": { - "efactor": 2.5, - "real_rept": 2, + "efactor": 1.3, + "real_rept": 6, "rept": 0, "interval": 1, - "last_date": 20561, - "next_date": 20562, + "last_date": 20562, + "next_date": 20563, "is_activated": 1, - "last_modify": 1776527873.4215648 + "last_modify": 1776577784.6579466 } }, "至于誓天断发, 泣下沾襟, 何其衰也!": { "SM-2": { "efactor": 2.5, - "real_rept": 2, - "rept": 0, - "interval": 1, - "last_date": 20561, - "next_date": 20562, + "real_rept": 4, + "rept": 2, + "interval": 15, + "last_date": 20562, + "next_date": 20577, "is_activated": 1, - "last_modify": 1776527873.4218438 + "last_modify": 1776577784.6205814 } }, "岂得之难而失之易欤? 抑本其成败之迹, 而皆自于人欤?": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6209705 } }, "《书》曰: 满招损, 谦得益.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6213555 } }, "忧劳可以兴国, 逸豫可以亡身, 自然之理也": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.621733 } }, "故方其盛也, 举天下之豪杰, 莫能与之争;": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6221194 } }, "及其衰也, 数十伶人困之, 而身死国灭, 为天下笑": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6225028 } }, "夫祸患常积于忽微, 而智勇多困于所溺, 岂独伶人也哉?": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6228793 } }, "六国论": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.623255 } }, "六国破灭, 非兵不利, 战不善, 弊在赂秦.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6236465 } }, "赂秦而力亏, 破灭之道也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6240213 } }, "或曰: 六国互丧, 率赂秦耶?": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6244063 } }, "曰: 不赂者以赂者丧.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.624782 } }, "盖失强援, 不能独完.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6251616 } }, "故曰: 弊在赂秦也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6255794 } }, "秦以攻取之外, 小则获邑, 大则得城.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6259894 } }, "较秦之所得, 与战胜而得者, 其实百倍;": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6264102 } }, "诸侯之所亡, 与战败而亡者, 其实亦百倍.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.626829 } }, "则秦之所大欲, 诸侯之所大患, 固不在战矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6272392 } }, "思厥先祖父, 暴霜露, 斩荆棘, 以有尺寸之地.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6276643 } }, "子孙视之不甚惜, 举以予人, 如弃草芥.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.628089 } }, "今日割五城, 明日割十城, 然后得一夕安寝.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6285114 } }, "起视四境, 而秦兵又至矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6289263 } }, "然则诸侯之地有限, 暴秦之欲无厌, 奉之弥繁, 侵之愈急.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6293442 } }, "故不战而强弱胜负已判矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.629762 } }, "至于颠覆, 理固宜然.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.630174 } }, "古人云: “以地事秦, 犹抱薪救火, 薪不尽, 火不灭.”": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.630577 } }, "此言得之.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6308808 } }, "齐人未尝赂秦, 终继五国迁灭, 何哉?": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6311781 } }, "与嬴而不助五国也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.63148 } }, "五国既丧, 齐亦不免矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.631776 } }, "燕赵之君, 始有远略, 能守其土, 义不赂秦.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6320646 } }, "是故燕虽小国而后亡, 斯用兵之效也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6323593 } }, "至丹以荆卿为计, 始速祸焉.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6326425 } }, "赵尝五战于秦, 二败而三胜.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6329288 } }, "后秦击赵者再, 李牧连却之.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6332211 } }, "洎牧以谗诛, 邯郸为郡, 惜其用武而不终也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6336164 } }, "且燕赵处秦革灭殆尽之际, 可谓智力孤危, 战败而亡, 诚不得已.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.633949 } }, "向使三国各爱其地, 齐人勿附于秦, 刺客不行, 良将犹在,": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6342893 } }, "则胜负之数, 存亡之理, 当与秦相较, 或未易量.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6346242 } }, "呜呼! 以赂秦之地封天下之谋臣, 以事秦之心礼天下之奇才, 并力西向,": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.634954 } }, "则吾恐秦人食之不得下咽也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6352873 } }, "悲夫! 有如此之势, 而为秦人积威之所劫, 日削月割, 以趋于亡.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6356177 } }, "为国者无使为积威之所劫哉!": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6359751 } }, "夫六国与秦皆诸侯, 其势弱于秦, 而犹有可以不赂而胜之之势.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 4, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6582904 } }, "苟以天下之大, 下而从六国破亡之故事, 是又在六国下矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6367347 } }, "劝学": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.637102 } }, "君子曰: 学不可以已.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6374843 } }, "青, 取之于蓝, 而青于蓝; 冰, 水为之, 而寒于水.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6378508 } }, "木直中绳, 𫐓以为轮, 其曲中规.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6382143 } }, "虽有槁暴, 不复挺者, 𫐓使之然也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6385686 } }, "故木受绳则直, 金就砺则利, 君子博学而日参省乎己, 则知明而行无过矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.638898 } }, "吾尝终日而思矣, 不如须臾之所学也; 吾尝跂而望矣, 不如登高之博见也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6393514 } }, "登高而招, 臂非加长也, 而见者远; 顺风而呼, 声非加疾也, 而闻者彰.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6398017 } }, "假舆马者, 非利足也, 而致千里; 假舟楫者, 非能水也, 而绝江河.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6402524 } }, "君子生非异也, 善假于物也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6406782 } }, "积土成山, 风雨兴焉; 积水成渊, 蛟龙生焉; 积善成德, 而神明自得, 圣心备焉.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6410484 } }, "故不积跬步, 无以至千里; 不积小流, 无以成江海.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6414237 } }, "骐骥一跃, 不能十步; 驽马十驾, 功在不舍.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.641818 } }, "锲而舍之, 朽木不折; 锲而不舍, 金石可镂.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 4, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6586235 } }, "蚓无爪牙之利, 筋骨之强, 上食埃土, 下饮黄泉, 用心一也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.642687 } }, "蟹六跪而二螯, 非蛇鳝之穴无可寄托者, 用心躁也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6429799 } }, "声声慢·寻寻觅觅": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6432714 } }, "寻寻觅觅, 冷冷清清, 凄凄惨惨戚戚. 乍暖还寒时候, 最难将息. 三杯两盏淡酒, 怎敌他、晚来风急! 雁过也, 正伤心, 却是旧时相识.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6436827 } }, "满地黄花堆积, 憔悴损, 如今有谁堪摘? 守着窗儿, 独自怎生得黑? 梧桐更兼细雨, 到黄昏、点点滴滴. 这次第, 怎一个愁字了得!": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 4, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6589534 } }, "大道之行也": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6444263 } }, "大道之行也, 天下为公.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6447709 } }, "选贤与能, 讲信修睦.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6451163 } }, "故人不独亲其亲, 不独子其子.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6454694 } }, "使老有所终, 壮有所用, 幼有所长.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6458526 } }, "矜寡孤独废疾者皆有所养.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6462154 } }, "男有分, 女有归.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6465893 } }, "货恶其弃于地也, 不必藏于己; 力恶其不出于身也, 不必为己.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6469772 } }, "是故谋闭不兴, 盗窃乱贼而不作.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.647417 } }, "故外户而不闭, 是谓大同.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6477902 } }, "客至": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.64818 } }, "舍南舍北皆春水, 但见群鸥日日来.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.648559 } }, "花径不曾缘客扫, 蓬门今始为君开.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6489382 } }, "盘飧市远无兼味, 樽酒家贫只旧醅.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6493144 } }, "肯与邻翁相对饮, 隔篱呼取尽余杯.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6496823 } }, "将进酒": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6500533 } }, "君不见, 黄河之水天上来, 奔流到海不复回.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6504254 } }, "君不见, 高堂明镜悲白发, 朝如青丝暮成雪!": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6507947 } }, "人生得意须尽欢, 莫使金樽空对月.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6511571 } }, "天生我材必有用, 千金散尽还复来.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.651622 } }, "烹羊宰牛且为乐, 会须一饮三百杯.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6520529 } }, "岑夫子, 丹丘生, 将进酒, 杯莫停.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6524749 } }, "与君歌一曲, 请君为我倾耳听.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6528883 } }, "钟鼓馔玉不足贵, 但愿长醉不复醒.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6533206 } }, "古来圣贤皆寂寞, 惟有饮者留其名.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6536992 } }, "陈王昔时宴平乐, 斗酒十千恣欢谑.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6540747 } }, "主人何为言少钱, 径须沽取对君酌.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6545231 } }, "五花马、千金裘, 呼儿将出换美酒, 与尔同销万古愁!": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6548157 } }, "屈原列传": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6551015 } }, "屈平疾王听之不聪也, 谗谄之蔽明也, 邪曲之害公也, 方正之不容也, 故忧愁幽思而作《离骚》.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6554022 } }, "离骚者, 犹离忧也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6556945 } }, "夫天者, 人之始也; 父母者, 人之本也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6559892 } }, "人穷则反本, 故劳苦倦极, 未尝不呼天也; 疾痛惨怛, 未尝不呼父母也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.656302 } }, "屈平正道直行, 竭忠尽智以事其君, 谗人间之, 可谓穷矣.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6566348 } }, "信而见疑, 忠而被谤, 能无怨乎?": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.656969 } }, "屈平之作《离骚》, 盖自怨生也.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.6573117 } }, "《国风》好色而不淫, 《小雅》怨诽而不乱.": { "SM-2": { "efactor": 2.5, - "real_rept": 0, + "real_rept": 2, "rept": 0, - "interval": 0, - "last_date": 0, - "next_date": 0, - "is_activated": 0, - "last_modify": 1776527865.8334022 + "interval": 1, + "last_date": 20562, + "next_date": 20563, + "is_activated": 1, + "last_modify": 1776577784.657641 } }, "若《离骚》者, 可谓兼之矣.": { diff --git a/src/heurams/context.py b/src/heurams/context.py index c4c7af8..bd30f6a 100644 --- a/src/heurams/context.py +++ b/src/heurams/context.py @@ -6,7 +6,7 @@ import pathlib from contextvars import ContextVar -from heurams.services.config import ConfigFile +from heurams.services.config import ConfigDict from heurams.services.logger import get_logger # 默认数据目录, 以包目录下的 data 为准 @@ -24,9 +24,9 @@ logger.debug(f"工作目录: {workdir}") (workdir / "data" / "config").mkdir(parents=True, exist_ok=True) -config_var: ContextVar[ConfigFile].get = ContextVar( +config_var: ContextVar[ConfigDict].get = ContextVar( "config_var", - default=ConfigFile(workdir / "data" / "config" / "config.toml"), + default=ConfigDict(workdir / "data" / "config"), ) """配置对象的全局引用对象.""" @@ -41,7 +41,7 @@ class ConfigContext: >>> get_daystamp() # 恢复原配置 """ - def __init__(self, config_provider: ConfigFile): + def __init__(self, config_provider: ConfigDict): self.config_provider = config_provider self._token = None diff --git a/src/heurams/interface/__init__.py b/src/heurams/interface/__init__.py index f02130e..faf1895 100644 --- a/src/heurams/interface/__init__.py +++ b/src/heurams/interface/__init__.py @@ -59,3 +59,15 @@ class HeurAMSApp(App): def action_do_nothing(self): self.refresh() + + # 移除烦人的 "rich traceback" + # Textual 官方不会管这破事, 写 Rich 写入脑了导致的 + # 不知道哪来的自信改标准库的 traceback + # https://github.com/Textualize/textual/discussions/6255 + def _fatal_error(self): + self._close_messages_no_wait() + raise self._exception + + def panic(self, *args): + self._close_messages_no_wait() + raise self._exception \ No newline at end of file diff --git a/src/heurams/interface/__main__.py b/src/heurams/interface/__main__.py index 3600fe7..209f0a3 100644 --- a/src/heurams/interface/__main__.py +++ b/src/heurams/interface/__main__.py @@ -10,7 +10,7 @@ def environment_check(): logger.debug("检查环境路径") subdir = ["cache/voice", "repo", "global", "config"] for i in subdir: - i = Path(config_var.get()["paths"]["data"]) / i + i = Path(config_var.get()["global"]["paths"]["data"]) / i if not i.exists(): logger.info("创建目录: %s", i) print(f"创建 {i}") diff --git a/src/heurams/interface/screens/dashboard.py b/src/heurams/interface/screens/dashboard.py index 6b6ea10..30889bf 100644 --- a/src/heurams/interface/screens/dashboard.py +++ b/src/heurams/interface/screens/dashboard.py @@ -58,8 +58,8 @@ class DashboardScreen(Screen): Label( f"当前 UNIX 日时间戳: {timer.get_daystamp()}" ), - Label(f"应用时区修正: UTC+{config_var.get()['timezone_offset'] / 3600}"), - Label(f"全局算法设置: {config_var.get()['algorithm']['default']}: {algorithms[config_var.get()['algorithm']['default']].desc}"), + Label(f"应用时区修正: UTC+{config_var.get()['services']['timer']['timezone_offset'] / 3600}"), + Label(f"全局算法设置: {config_var.get()['interface']['global']['algorithm']}: {algorithms[config_var.get()['interface']['global']['algorithm']].desc}"), classes="column infview", ), Vertical( @@ -78,7 +78,7 @@ class DashboardScreen(Screen): def _load_data(self): self.repo_dirs = Repo.probe_valid_repos_in_dir( - Path(config_var.get()["paths"]["data"]) / "repo" + Path(config_var.get()['global']["paths"]["data"]) / "repo" ) for repo_dir in self.repo_dirs: repo = Repo.create_from_repodir(repo_dir) diff --git a/src/heurams/interface/screens/favmgr.py b/src/heurams/interface/screens/favmgr.py index b90a957..4635cd4 100644 --- a/src/heurams/interface/screens/favmgr.py +++ b/src/heurams/interface/screens/favmgr.py @@ -115,7 +115,7 @@ class FavoriteManagerScreen(Screen): def _get_repo_info(self, repo_path: str, fav: FavoriteItem) -> Optional[dict]: """获取仓库信息(标题、原子内容预览)""" try: - data_repo = Path(config_var.get()["paths"]["data"]) / "repo" + data_repo = Path(config_var.get()['global']["paths"]["data"]) / "repo" repo_dir = data_repo / repo_path if not repo_dir.exists(): logger.warning("仓库目录不存在: %s", repo_dir) diff --git a/src/heurams/interface/screens/memoqueue.py b/src/heurams/interface/screens/memoqueue.py index afab256..1d7c877 100644 --- a/src/heurams/interface/screens/memoqueue.py +++ b/src/heurams/interface/screens/memoqueue.py @@ -38,7 +38,7 @@ class MemScreen(Screen): ("0,1,2,3", "app.push_screen('about')", ""), ] - if config_var.get()["quick_pass"]: + if config_var.get()['interface']['global']["quick_pass"]: BINDINGS.append(("k", "quick_pass", "正确应答")) BINDINGS.append(("f", "quick_fail", "错误应答")) rating = reactive(-1) @@ -93,7 +93,7 @@ class MemScreen(Screen): if self.repo is not None: fav_status = "已收藏" if self._is_current_atom_favorited() else "未收藏" s += f"收藏: {fav_status}\n" - if config_var.get().get("debug_topline", 0): + '''if config_var.get().get("debug_topline", 0): try: alia = self.fission.get_current_puzzle_inf()["alia"] # type: ignore s += f"谜题: {alia}\n" @@ -113,7 +113,7 @@ class MemScreen(Screen): stat = self.fission.__repr__("simple", "") s += f"{stat}\n" except Exception as e: - s = str(e) + s = str(e)''' s += f"进度: {self.procession.process() + 1}/{self.procession.total_length()}" return s @@ -139,9 +139,9 @@ class MemScreen(Screen): i.remove() from heurams.interface.widgets.finished import Finished - if config_var.get().get("persist_to_file", 0): + if config_var.get()['interface']['global']["persist_to_file"]: self.save_func() - container.mount(Finished(is_saved=config_var.get().get("persist_to_file", 0))) + container.mount(Finished(is_saved=['interface']['global']["persist_to_file"])) def on_button_pressed(self, event): event.stop() @@ -156,7 +156,7 @@ class MemScreen(Screen): from heurams.services.audio_service import play_by_path from heurams.services.hasher import get_md5 - path = Path(config_var.get()["paths"]["data"]) / "cache" / "voice" + path = Path(config_var.get()['global']["paths"]["data"]) / "cache" / "voice" path = path / f"{get_md5(self.atom.registry['nucleon']["tts_text"])}.wav" if path.exists(): play_by_path(path) @@ -226,7 +226,7 @@ class MemScreen(Screen): return "" # self.repo.source 是 Path 对象,指向仓库目录 repo_full_path = self.repo.source - data_repo_path = Path(config_var.get()["paths"]["data"]) / "repo" + data_repo_path = Path(config_var.get()['global']["paths"]["data"]) / "repo" try: rel_path = repo_full_path.relative_to(data_repo_path) return str(rel_path) diff --git a/src/heurams/interface/screens/precache.py b/src/heurams/interface/screens/precache.py index 422f738..4b3d055 100644 --- a/src/heurams/interface/screens/precache.py +++ b/src/heurams/interface/screens/precache.py @@ -13,7 +13,7 @@ import heurams.services.hasher as hasher from heurams.context import * # 兼容性缓存路径:优先使用 paths.cache,否则使用 data/cache -paths = config_var.get()["paths"] +paths = config_var.get()['global']["paths"] cache_dir = pathlib.Path(paths.get("cache", paths["data"] + "/cache")) / "voice" @@ -61,7 +61,7 @@ class PrecachingScreen(Screen): """获取所有仓库的总单元数""" from heurams.context import config_var from heurams.kernel.repolib import Repo - repo_path = pathlib.Path(config_var.get()["paths"]["data"]) / "repo" + repo_path = pathlib.Path(config_var.get()['global']["paths"]["data"]) / "repo" repo_dirs = Repo.probe_valid_repos_in_dir(repo_path) repos = map(Repo.create_from_repodir, repo_dirs) total = 0 @@ -230,7 +230,7 @@ class PrecachingScreen(Screen): from heurams.context import config_var, rootdir, workdir from heurams.kernel.repolib import Repo - repo_path = pathlib.Path(config_var.get()["paths"]["data"]) / "repo" + repo_path = pathlib.Path(config_var.get()['global']["paths"]["data"]) / "repo" repo_dirs = Repo.probe_valid_repos_in_dir(repo_path) repos = map(Repo.create_from_repodir, repo_dirs) diff --git a/src/heurams/interface/screens/preparation.py b/src/heurams/interface/screens/preparation.py index 3ae7459..3a151a8 100644 --- a/src/heurams/interface/screens/preparation.py +++ b/src/heurams/interface/screens/preparation.py @@ -28,7 +28,7 @@ class PreparationScreen(Screen): ("0,1,2,3", "app.push_screen('about')", ""), ] - scheduled_num = reactive(config_var.get()["scheduled_num"]) + scheduled_num = reactive(config_var.get()['interface']['global']["scheduled_num"]) def __init__(self, repo: Repo, repostat: dict) -> None: super().__init__(name=None, id=None, classes=None) @@ -41,7 +41,7 @@ class PreparationScreen(Screen): with ScrollableContainer(id="vice_container"): yield Label(f"准备就绪: [b]{self.repostat['title']}[/b]\n") yield Label( - f"仓库路径: {config_var.get()['paths']['data']}/repo/[b]{self.repostat['dirname']}[/b]" + f"仓库路径: {config_var.get()['global']['paths']['data']}/repo/[b]{self.repostat['dirname']}[/b]" ) yield Label(f"\n单元数量: {len(self.repo)}\n") yield Label(f"最小记忆分组: {self.scheduled_num}\n", id="schnum_label") @@ -130,7 +130,7 @@ class PreparationScreen(Screen): def launch(repo, app, scheduled_num): if scheduled_num == -1: - scheduled_num = config_var.get()["scheduled_num"] + scheduled_num = config_var.get()['interface']['global']["scheduled_num"] atoms = list() for i in repo.ident_index: n = pt.Nucleon.create_on_nucleonic_data( diff --git a/src/heurams/interface/widgets/recognition.py b/src/heurams/interface/widgets/recognition.py index 67f6091..0162519 100644 --- a/src/heurams/interface/widgets/recognition.py +++ b/src/heurams/interface/widgets/recognition.py @@ -51,7 +51,7 @@ class Recognition(BasePuzzleWidget): def compose(self): from heurams.context import config_var - autovoice = config_var.get()["interface"]["memorizor"]["autovoice"] + autovoice = config_var.get()["interface"]["widgets"]["autovoice"] if autovoice: self.screen.action_play_voice() # type: ignore cfg: RecognitionConfig = self.atom.registry["nucleon"]["puzzles"][self.alia] diff --git a/src/heurams/kernel/algorithms/__init__.py b/src/heurams/kernel/algorithms/__init__.py index 5114ed8..2161012 100644 --- a/src/heurams/kernel/algorithms/__init__.py +++ b/src/heurams/kernel/algorithms/__init__.py @@ -1,18 +1,18 @@ from .base import BaseAlgorithm from .sm2 import SM2Algorithm from .sm15m import SM15MAlgorithm -from .fast0 import FAST0Algorithm +from .nsp0 import NSP0Algorithm __all__ = [ "SM2Algorithm", "BaseAlgorithm", "SM15MAlgorithm", - "FAST0Algorithm", + "NSP0Algorithm", ] algorithms = { "SM-2": SM2Algorithm, - "FAST-0": FAST0Algorithm, + "NSP-0": NSP0Algorithm, "SM-15M": SM15MAlgorithm, "Base": BaseAlgorithm, } diff --git a/src/heurams/kernel/algorithms/fast0.py b/src/heurams/kernel/algorithms/nsp0.py similarity index 86% rename from src/heurams/kernel/algorithms/fast0.py rename to src/heurams/kernel/algorithms/nsp0.py index 4548b17..752a833 100644 --- a/src/heurams/kernel/algorithms/fast0.py +++ b/src/heurams/kernel/algorithms/nsp0.py @@ -8,8 +8,8 @@ from .base import BaseAlgorithm logger = get_logger(__name__) -class FAST0Algorithm(BaseAlgorithm): - algo_name = "FAST-0" +class NSP0Algorithm(BaseAlgorithm): + algo_name = "NSP-0" desc = '快速筛选用特殊调度器' class AlgodataDict(TypedDict): real_rept: int @@ -36,7 +36,7 @@ class FAST0Algorithm(BaseAlgorithm): def revisor( cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False ): - """FAST-0 算法迭代决策机制实现 + """NSP-0 算法迭代决策机制实现 根据 quality(0 ~ 5) 进行参数迭代最佳间隔 quality 由主程序评估 @@ -44,7 +44,7 @@ class FAST0Algorithm(BaseAlgorithm): quality (int): 记忆保留率量化参数 """ logger.debug( - "FAST0.revisor 开始, feedback: %d, is_new_activation: %s", + "NSP0.revisor 开始, feedback: %d, is_new_activation: %s", feedback, is_new_activation, ) @@ -71,7 +71,7 @@ class FAST0Algorithm(BaseAlgorithm): def is_due(cls, algodata): result = algodata[cls.algo_name]["next_date"] <= timer.get_daystamp() logger.debug( - "FAST0.is_due: next_date=%d, current_daystamp=%d, result=%s", + "NSP0.is_due: next_date=%d, current_daystamp=%d, result=%s", algodata[cls.algo_name]["next_date"], timer.get_daystamp(), result, @@ -81,11 +81,11 @@ class FAST0Algorithm(BaseAlgorithm): @classmethod def get_rating(cls, algodata): efactor = algodata[cls.algo_name]["efactor"] - logger.debug("FAST0.rate: efactor=%f", efactor) + logger.debug("NSP0.rate: efactor=%f", efactor) return str(efactor) @classmethod def nextdate(cls, algodata) -> int: next_date = algodata[cls.algo_name]["next_date"] - logger.debug("FAST0.nextdate: %d", next_date) + logger.debug("NSP0.nextdate: %d", next_date) return next_date diff --git a/src/heurams/kernel/algorithms/sm15m.py b/src/heurams/kernel/algorithms/sm15m.py index a909d58..83fa9e8 100644 --- a/src/heurams/kernel/algorithms/sm15m.py +++ b/src/heurams/kernel/algorithms/sm15m.py @@ -27,7 +27,7 @@ from heurams.kernel.algorithms.sm15m_calc import ( # 全局状态文件路径 _GLOBAL_STATE_FILE = os.path.expanduser( - pathlib.Path(config_var.get()["paths"]["data"]) + pathlib.Path(config_var.get()['global']["paths"]["data"]) / "global" / "sm15m_global_state.json" ) diff --git a/src/heurams/kernel/particles/nucleon.py b/src/heurams/kernel/particles/nucleon.py index 9015be7..17affdb 100644 --- a/src/heurams/kernel/particles/nucleon.py +++ b/src/heurams/kernel/particles/nucleon.py @@ -19,14 +19,14 @@ class Nucleon: data_safe['puzzles'] = {} env = { "payload": data_safe, - "default": config_var.get()["puzzles"], + "default": config_var.get()['interface']["puzzles"], "nucleon": data_safe, } self.evalizer = Evalizer(environment=env) data_safe = self.evalizer(deepcopy(data_safe)) env = { "payload": data_safe, - "default": config_var.get()["puzzles"], + "default": config_var.get()['interface']["puzzles"], "nucleon": data_safe, } self.evalizer = Evalizer(environment=env) diff --git a/src/heurams/services/audio_service.py b/src/heurams/services/audio_service.py index 7693156..4eefd11 100644 --- a/src/heurams/services/audio_service.py +++ b/src/heurams/services/audio_service.py @@ -7,7 +7,7 @@ from heurams.services.logger import get_logger 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"]['provider']].play_by_path logger.debug( - "音频服务初始化完成, 使用 Provider: %s", config_var.get()["services"]["audio"] + "音频服务初始化完成, 使用 Provider: %s", config_var.get()["services"]["audio"]['provider'] ) diff --git a/src/heurams/services/config copy.py b/src/heurams/services/config copy.py new file mode 100644 index 0000000..e0c6b12 --- /dev/null +++ b/src/heurams/services/config copy.py @@ -0,0 +1,127 @@ +"""配置文件服务""" +import pathlib +import typing + +import toml + +from heurams.services.logger import get_logger + +default_config = { + "persist_to_file": 1, # 将更改保存到文件 + "daystamp_override": -1, # 覆写时间, 设为 -1 以禁用 + "timestamp_override": -1, # 覆写时间, 设为 -1 以禁用 + "quick_pass": 1, # 启用用于测试的快速通过 + "scheduled_num": 8, # 对于每个项目的默认新记忆原子数量 + "timezone_offset": 28800, # UTC 时间戳修正 仅用于 UNIX 日时间戳的生成修正, 单位为秒 + # 28800 是中国标准时间 (UTC+8) + + "interface": { + "memorizor": { + "autovoice": True # 自动语音播放, 仅限于 recognition 组件 + } + }, + + "algorithm": { + "default": "SM-2" # 主要算法 + # 可选项: SM-2, SM-15M, FSRS + }, + + "puzzles": { # 谜题默认配置 + "mcq": { + "max_riddles_num": 2 + }, + "cloze": { + "min_denominator": 3 + } + }, + + "paths": { # 相对于配置文件的 ".." (即工作目录) 而言 或绝对路径 + "data": "./data" + }, + + "services": { # 定义服务到提供者的映射 + "audio": "playsound", # 可选项: playsound(通用), termux(仅用于 Android Termux), mpg123(TODO) + "tts": "edgetts", # 可选项: edgetts + "llm": "openai", # 可选项: openai + "sync": "webdav" # 可选项: 留空, webdav + }, + + "providers": { + "tts": { + "edgetts": { # EdgeTTS 设置 + "voice": "zh-CN-XiaoxiaoNeural" # 可选项: zh-CN-YunjianNeural (男声), zh-CN-XiaoxiaoNeural (女声) + } + }, + "llm": { + "openai": { # 与 OpenAI 相容的语言模型接口服务设置 + "url": "", + "key": "" + } + }, + "sync": { + "webdav": { # WebDAV 同步设置 + "url": "", + "username": "", + "password": "", + "remote_path": "/heurams/", + "verify_ssl": True + } + } + }, +} + +class ConfigFile: + def __init__(self, path: pathlib.Path): + self.logger = get_logger(__name__) + self.path = path + self.data = dict() + if not self.path.exists(): + self.path.touch() + self.logger.debug("创建配置文件: %s", self.path) + self.data = default_config + self.valid_configfile = 1 + # 考虑到可能临时编辑格式错误, 所以不覆写格式错误的配置文件, 而是提示损坏并使用默认配置 + self._load() + + def _load(self): + """从文件加载配置数据""" + with open(self.path, "r") as f: + try: + self.data = toml.load(f) + self.logger.debug("配置文件加载成功: %s", self.path) + except toml.TomlDecodeError as e: + print(f"{e}") + self.logger.error("TOML解析错误: %s", e) + self.data = default_config + self.valid_configfile = 0 + + def modify(self, key: str, value: typing.Any): + """修改配置值并保存""" + self.data[key] = value + self.logger.debug("修改配置项: %s = %s", key, value) + self.save() + + def save(self, path: typing.Union[str, pathlib.Path] = ""): + """保存配置到文件""" + if self.valid_configfile: + save_path = pathlib.Path(path) if path else self.path + with open(save_path, "w") as f: + toml.dump(self.data, f) + self.logger.debug("配置文件已保存: %s", save_path) + else: + pass + + def get(self, key: str, default: typing.Any = None) -> typing.Any: + """获取配置值, 如果不存在返回默认值""" + return self.data.get(key, default) + + def __getitem__(self, key: str) -> typing.Any: + return self.data[key] + + def __setitem__(self, key: str, value: typing.Any): + self.data[key] = value + self.save() + + def __contains__(self, key: str) -> bool: + """支持 in 语法""" + return key in self.data diff --git a/src/heurams/services/config.py b/src/heurams/services/config.py index e0c6b12..7755bb3 100644 --- a/src/heurams/services/config.py +++ b/src/heurams/services/config.py @@ -1,127 +1,80 @@ -"""配置文件服务""" import pathlib import typing import toml +from collections import UserDict +import atexit from heurams.services.logger import get_logger +from heurams.services.exceptions import WTFException -default_config = { - "persist_to_file": 1, # 将更改保存到文件 - "daystamp_override": -1, # 覆写时间, 设为 -1 以禁用 - "timestamp_override": -1, # 覆写时间, 设为 -1 以禁用 - "quick_pass": 1, # 启用用于测试的快速通过 - "scheduled_num": 8, # 对于每个项目的默认新记忆原子数量 - "timezone_offset": 28800, # UTC 时间戳修正 仅用于 UNIX 日时间戳的生成修正, 单位为秒 - # 28800 是中国标准时间 (UTC+8) - - "interface": { - "memorizor": { - "autovoice": True # 自动语音播放, 仅限于 recognition 组件 - } - }, - - "algorithm": { - "default": "SM-2" # 主要算法 - # 可选项: SM-2, SM-15M, FSRS - }, - - "puzzles": { # 谜题默认配置 - "mcq": { - "max_riddles_num": 2 - }, - "cloze": { - "min_denominator": 3 - } - }, - - "paths": { # 相对于配置文件的 ".." (即工作目录) 而言 或绝对路径 - "data": "./data" - }, - - "services": { # 定义服务到提供者的映射 - "audio": "playsound", # 可选项: playsound(通用), termux(仅用于 Android Termux), mpg123(TODO) - "tts": "edgetts", # 可选项: edgetts - "llm": "openai", # 可选项: openai - "sync": "webdav" # 可选项: 留空, webdav - }, - - "providers": { - "tts": { - "edgetts": { # EdgeTTS 设置 - "voice": "zh-CN-XiaoxiaoNeural" # 可选项: zh-CN-YunjianNeural (男声), zh-CN-XiaoxiaoNeural (女声) - } - }, - "llm": { - "openai": { # 与 OpenAI 相容的语言模型接口服务设置 - "url": "", - "key": "" - } - }, - "sync": { - "webdav": { # WebDAV 同步设置 - "url": "", - "username": "", - "password": "", - "remote_path": "/heurams/", - "verify_ssl": True - } - } - }, -} - -class ConfigFile: - def __init__(self, path: pathlib.Path): +# 我们的流程是: 找到文件名: 返回文件名里头的数据; 找不到: 继续查索引; 所以 self.data 除了存本级各种索引球用没得 +# 递归就是这么吊 +class ConfigDict(UserDict): # 舒服了 + def __init__(self, config_path: pathlib.Path, dict = None): # 需要自己把自己提起来 + if dict: + raise WTFException("不要放默认值...") + super().__init__(dict) self.logger = get_logger(__name__) - self.path = path - self.data = dict() - if not self.path.exists(): - self.path.touch() - self.logger.debug("创建配置文件: %s", self.path) - self.data = default_config - self.valid_configfile = 1 - # 考虑到可能临时编辑格式错误, 所以不覆写格式错误的配置文件, 而是提示损坏并使用默认配置 - self._load() - - def _load(self): - """从文件加载配置数据""" - with open(self.path, "r") as f: - try: - self.data = toml.load(f) - self.logger.debug("配置文件加载成功: %s", self.path) - except toml.TomlDecodeError as e: - print(f"{e}") - self.logger.error("TOML解析错误: %s", e) - self.data = default_config - self.valid_configfile = 0 - - def modify(self, key: str, value: typing.Any): - """修改配置值并保存""" - self.data[key] = value - self.logger.debug("修改配置项: %s = %s", key, value) - self.save() - - def save(self, path: typing.Union[str, pathlib.Path] = ""): - """保存配置到文件""" - if self.valid_configfile: - save_path = pathlib.Path(path) if path else self.path - with open(save_path, "w") as f: - toml.dump(self.data, f) - self.logger.debug("配置文件已保存: %s", save_path) + self.path = config_path + self.is_dir = self.path.is_dir() + if self.is_dir: + self.update_index() # 狗儿要唱狗儿歌 else: - pass + with open(self.path, 'r+') as f: #TODO: 给这个做缓存 + try: + self.data = toml.load(f) + except: + self.data = {} + self.persist = lambda: False # 不修改错误的配置文件 + + def __getitem__(self, key): + # 我们实现了先进的懒狗加载 + value = super().__getitem__(key) + if isinstance(value, pathlib.Path): + return ConfigDict(value) + return value - def get(self, key: str, default: typing.Any = None) -> typing.Any: - """获取配置值, 如果不存在返回默认值""" - return self.data.get(key, default) + def converter(self, s): + if (self.path / s).exists: + return self.path / s + return self.path / s+'.toml' - def __getitem__(self, key: str) -> typing.Any: - return self.data[key] + def __contains__(self, key): + if isinstance(key, str): + key = self.converter(key) + return super().__contains__(key) - def __setitem__(self, key: str, value: typing.Any): - self.data[key] = value - self.save() + def __setitem__(self, key, value): + if isinstance(key, str): + key = self.converter(key) + origvalue = super().__getitem__(key) # 所以你不该访问不存在的对象 + if isinstance(origvalue, ConfigDict): + if origvalue.path.is_dir(): + raise WTFException("你怎么能变更目录配置的内容呢?!") + else: + # 对文件, 我们允许这种覆写存在 + # 但是不准变类型 + origvalue.data = value + super().__setitem__(key, value) - def __contains__(self, key: str) -> bool: - """支持 in 语法""" - return key in self.data + def update_index(self): # 如果有人没事干在config里面创建指向config的符号链接 这玩意会崩溃 但是不要修复: 需要这个符号链接特性 + for i in self.path.iterdir(): + if i.is_dir(): + self.data[i.name] = i + else: + if i.suffix == '.toml': + self.data[i.stem] = i + else: + self.logger.log(f"配置目录中有无效的文件 {i.stem}") # what's up bro + + def persist(self): + if self.is_dir: + raise WTFException("不准这样浪费性能...") + + with open(self.path, 'w+') as f: + toml.dump(self.data, f) + + def __del__(self): + if not self.is_dir: + self.persist() # 不准循环引用, 懂了吧 \ No newline at end of file diff --git a/src/heurams/services/epath.py b/src/heurams/services/epath.py new file mode 100644 index 0000000..e95d6ee --- /dev/null +++ b/src/heurams/services/epath.py @@ -0,0 +1,30 @@ +def epath(dct, path: str = '', default=None, parents=False): + if not path: + return dct + + path = path.rstrip('/') + target = dct + + for i in path.split('/'): + # 处理字典键 + if isinstance(target, dict) and i in target: + target = target[i] + # 处理列表索引 + elif i.startswith('[') and i.endswith(']') and isinstance(target, (list, tuple)): + idx = int(i[1:-1]) + if 0 <= idx < len(target): + target = target[idx] + elif parents: + while len(target) <= idx: + target.append(None) + target[idx] = {} + target = target[idx] + else: + return default + elif parents: + target[i] = {} + target = target[i] + else: + return default + + return target \ No newline at end of file diff --git a/src/heurams/services/exceptions.py b/src/heurams/services/exceptions.py new file mode 100644 index 0000000..3708473 --- /dev/null +++ b/src/heurams/services/exceptions.py @@ -0,0 +1,4 @@ +from heurams.services.logger import get_logger + +class WTFException(Exception): + pass \ No newline at end of file diff --git a/src/heurams/services/favorite_service.py b/src/heurams/services/favorite_service.py index a925a34..e0939e4 100644 --- a/src/heurams/services/favorite_service.py +++ b/src/heurams/services/favorite_service.py @@ -63,7 +63,7 @@ class FavoriteManager: def _get_file_path(self) -> Path: """获取收藏文件路径""" - config_path = Path(config_var.get()["paths"]["data"]) + config_path = Path(config_var.get()['global']["paths"]["data"]) fav_path = config_path / "global" / "favorites.json" fav_path.parent.mkdir(parents=True, exist_ok=True) return fav_path diff --git a/src/heurams/services/timer.py b/src/heurams/services/timer.py index 91bd55a..ec52336 100644 --- a/src/heurams/services/timer.py +++ b/src/heurams/services/timer.py @@ -9,12 +9,12 @@ logger = get_logger(__name__) def get_daystamp() -> int: """获取当前日戳(以天为单位的整数时间戳)""" - time_override = config_var.get().get("daystamp_override", -1) + time_override = config_var.get()['services']["timer"]["daystamp_override"] if time_override != -1: logger.debug("使用覆盖的日戳: %d", time_override) return int(time_override) - result = int((time.time() + config_var.get().get("timezone_offset")) // (24 * 3600)) + result = int((time.time() + config_var.get()['services']["timer"]["timezone_offset"]) // (24 * 3600)) logger.debug("计算日戳: %d", result) return result @@ -22,7 +22,7 @@ def get_daystamp() -> int: def get_timestamp() -> float: """获取 UNIX 时间戳""" # 搞这个类的原因是要支持可复现操作 - time_override = config_var.get().get("timestamp_override", -1) + time_override = config_var.get()['services']["timer"]["timestamp_override"] if time_override != -1: logger.debug("使用覆盖的时间戳: %f", time_override) return float(time_override) diff --git a/src/heurams/services/tts_service.py b/src/heurams/services/tts_service.py index 0c582f5..71d4524 100644 --- a/src/heurams/services/tts_service.py +++ b/src/heurams/services/tts_service.py @@ -7,7 +7,7 @@ from heurams.services.logger import get_logger logger = get_logger(__name__) -convertor: Callable = prov[config_var.get()["services"]["tts"]].convert +convertor: Callable = prov[config_var.get()['services']["tts"]["provider"]].convert logger.debug( - "TTS 服务初始化完成, 使用 provider: %s", config_var.get()["services"]["tts"] + "TTS 服务初始化完成, 使用 provider: %s", config_var.get()['services']["tts"]["provider"] )