10 Commits

Author SHA1 Message Date
39459a0f6e 更新版本号 2025-08-21 13:30:59 +08:00
cccf7189e3 自动播放机制 2025-08-21 13:30:30 +08:00
2c51f2cea3 改动 2025-08-21 06:28:22 +08:00
2ad014fcd8 更新文件树 2025-08-16 07:33:42 +08:00
4ad289d02d 改进部署组件 2025-08-14 11:16:43 +08:00
28ccfdd227 删除运行时文件 2025-08-14 11:13:11 +08:00
f83d5c934d 增加若干元数据 2025-08-14 11:12:33 +08:00
4f9eb3b7d1 重命名文件 2025-08-12 19:10:14 +08:00
c44a38f3c8 更新自述文件 2025-08-09 22:44:02 +08:00
f760e7f0fa 预缓存实用程序改动 2025-08-09 08:41:40 +08:00
67 changed files with 50 additions and 40 deletions

2
.playsound.py Normal file
View File

@@ -0,0 +1,2 @@
def playsound(p):
print(p)

View File

@@ -1,9 +1,9 @@
# 潜进 (HeurAMS) - 实验型辅助记忆程序 # 潜进 (HeurAMS) - 启发式辅助记忆程序
> 形人而我无形,**则我专而敌分** > 形人而我无形,**则我专而敌分**
## 概述 ## 概述
"潜进" (HeurAMS, 中文含义: 启发式辅助记忆软件) 是为习题册, 古诗词, 及其他问答/记忆/理解型知识设计的辅助记忆软件, 提供动态规划的优化记忆方案 "潜进" (HeurAMS) 是为习题册, 古诗词, 及其他问答/记忆/理解型知识设计的辅助记忆软件, 提供动态规划的优化记忆方案
## 技术集成与特性 ## 技术集成与特性
@@ -68,4 +68,4 @@ graph TD
## 系统要求 ## 系统要求
- 平台支持Windows / macOS / Linux / Android (需要 Termux 或 Linux) (终端或浏览器) - 平台支持Windows / macOS / Linux / Android (需要 Termux 或 Linux) (终端或浏览器)
- 网络连接:可预缓存语音文件, 需联网使用大模型服务功能 - 网络连接:可预缓存语音文件, 需联网使用大模型服务功能

View File

@@ -2,6 +2,9 @@ import time
import pathlib import pathlib
import toml import toml
import typing import typing
import playsound
import threading
import edge_tts as tts
class ConfigFile: class ConfigFile:
def __init__(self, path: str): def __init__(self, path: str):
@@ -34,6 +37,17 @@ class ConfigFile:
"""获取配置值,如果不存在返回默认值""" """获取配置值,如果不存在返回默认值"""
return self.data.get(key, default) return self.data.get(key, default)
def action_play_voice(content):
def play():
communicate = tts.Communicate(
content,
"zh-CN-YunjianNeural",
)
communicate.save_sync(
f"./cache/voice/{content}"
)
playsound()
threading.Thread(target=play).start()
def get_daystamp() -> int: def get_daystamp() -> int:
"""获取当前日戳(以天为单位的整数时间戳)""" """获取当前日戳(以天为单位的整数时间戳)"""

View File

@@ -188,6 +188,7 @@ class FillBlank(Composition):
yield Button("退格", id=self.regid(f"delete")) yield Button("退格", id=self.regid(f"delete"))
def handler(self, event, type_): def handler(self, event, type_):
# TODO: 改动:在线错误纠正
if type_ == "button": if type_ == "button":
if self.recid(event.button.id) == "delete": if self.recid(event.button.id) == "delete":
if len(self.inputlist) > 0: if len(self.inputlist) > 0:
@@ -279,7 +280,7 @@ class TestScreen(Screen):
class AppLauncher(App): class AppLauncher(App):
CSS_PATH = "styles.tcss" CSS_PATH = "styles.css"
TITLE = "测试布局" TITLE = "测试布局"
BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")] BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")]
SCREENS = { SCREENS = {
@@ -293,4 +294,4 @@ class AppLauncher(App):
if __name__ == "__main__": if __name__ == "__main__":
app = AppLauncher() app = AppLauncher()
app.run() app.run()

19
main.py
View File

@@ -22,18 +22,7 @@ import auxiliary as aux
import compositions as compo import compositions as compo
import builtins import builtins
# Hook python 的 open() 函数, 使用 utf-8 (兼容 Windows 万年 GBK) ver = "0.3.1"
_original_open = builtins.open
def _open(*args, **kwargs):
if "encoding" not in kwargs:
kwargs["encoding"] = "utf-8"
return _original_open(*args, **kwargs)
builtins.open = _open
ver = "0.3.0"
config = aux.ConfigFile("config.toml") config = aux.ConfigFile("config.toml")
@@ -62,6 +51,8 @@ class MemScreen(Screen):
self.compo = next(self.reactor.current_appar) self.compo = next(self.reactor.current_appar)
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
if type(self.compo).__name__ == "Recognition":
self.action_play_voice()
yield Header(show_clock=True) yield Header(show_clock=True)
with Center(): with Center():
yield Static( yield Static(
@@ -116,8 +107,10 @@ class MemScreen(Screen):
def refresh_ui(self): def refresh_ui(self):
self.call_later(self.recompose) self.call_later(self.recompose)
print(type(self.compo).__name__)
def action_play_voice(self): def action_play_voice(self):
print("VOICE")
def play(): def play():
cache_dir = pathlib.Path(f"./cache/voice/") cache_dir = pathlib.Path(f"./cache/voice/")
cache_dir.mkdir(parents=True, exist_ok=True) cache_dir.mkdir(parents=True, exist_ok=True)
@@ -250,7 +243,7 @@ class FileSelectorScreen(Screen):
class AppLauncher(App): class AppLauncher(App):
CSS_PATH = "styles.tcss" CSS_PATH = "styles.css"
TITLE = "潜进 - 辅助记忆程序" TITLE = "潜进 - 辅助记忆程序"
BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")] BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")]
SCREENS = { SCREENS = {

0
nucleon_todo/书愤.toml Normal file
View File

View File

View File

0
nucleon_todo/劝学.toml Normal file
View File

View File

0
nucleon_todo/客至.toml Normal file
View File

View File

View File

View File

0
nucleon_todo/师说.toml Normal file
View File

View File

View File

View File

View File

View File

View File

View File

0
nucleon_todo/无衣.toml Normal file
View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

0
nucleon_todo/登高.toml Normal file
View File

View File

View File

0
nucleon_todo/礼运.toml Normal file
View File

0
nucleon_todo/离骚.toml Normal file
View File

View File

View File

View File

View File

View File

0
nucleon_todo/蜀相.toml Normal file
View File

View File

0
nucleon_todo/论语.toml Normal file
View File

View File

View File

View File

View File

0
nucleon_todo/锦瑟.toml Normal file
View File

View File

View File

View File

0
nucleon_todo/静女.toml Normal file
View File

View File

View File

View File

@@ -21,8 +21,8 @@ def proc_file(path: Path):
c = 0 c = 0
for i in nu.nucleons: for i in nu.nucleons:
c += 1 c += 1
print(f"预缓存 [{nu.name}] ({c}/{len(nu)}): {i['content']}") print(f"预缓存 [{nu.name}] ({c}/{len(nu)}): {i['content'].replace('/', '')}")
precache(i['content']) precache(i['content'].replace('/', ''))
def walk(path_str: str): def walk(path_str: str):
@@ -49,4 +49,4 @@ if __name__ == "__main__":
walk("./nucleon") walk("./nucleon")
elif choice == "C": elif choice == "C":
shutil.rmtree("./cache/voice", ignore_errors=True) shutil.rmtree("./cache/voice", ignore_errors=True)
print("缓存已清空") print("缓存已清空")

View File

@@ -0,0 +1,17 @@
function getStartUrl() {
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
params.delete("delay");
return url.pathname + "?" + params.toString();
}
async function refresh() {
const ping_url = document.body.dataset.pingurl;
if (ping_url) {
await fetch(ping_url, {
method: "GET",
mode: "no-cors",
});
}
window.location.href = getStartUrl();
}

View File

@@ -4,6 +4,7 @@
<link rel="stylesheet" href="{{ config.static.url }}css/xterm.css" /> <link rel="stylesheet" href="{{ config.static.url }}css/xterm.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto%20Mono"/> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto%20Mono"/>
<script src="{{ config.static.url }}js/textual.js"></script> <script src="{{ config.static.url }}js/textual.js"></script>
<script src="{{ config.static.url }}js/script.js"></script>
<style> <style>
body { body {
background: #000000; background: #000000;
@@ -99,24 +100,6 @@
z-index: 5; z-index: 5;
} }
</style> </style>
<script>
function getStartUrl() {
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
params.delete("delay");
return url.pathname + "?" + params.toString();
}
async function refresh() {
const ping_url = document.body.dataset.pingurl;
if (ping_url) {
await fetch(ping_url, {
method: "GET",
mode: "no-cors",
});
}
window.location.href = getStartUrl();
}
</script>
</head> </head>
<body data-pingurl="{{ ping_url }}"> <body data-pingurl="{{ ping_url }}">
<div class="dialog-container intro-dialog"> <div class="dialog-container intro-dialog">
@@ -145,4 +128,4 @@
data-font-size="{{ font_size }}" data-font-size="{{ font_size }}"
></div> ></div>
</body> </body>
</html> </html>