fix: 完善

This commit is contained in:
2025-12-10 13:13:37 +08:00
parent e9582e1dc0
commit a8ae1bacf3
12 changed files with 62 additions and 40 deletions

View File

@@ -26,4 +26,13 @@ min_denominator = 3
nucleon_dir = "./data/nucleon" nucleon_dir = "./data/nucleon"
electron_dir = "./data/electron" electron_dir = "./data/electron"
orbital_dir = "./data/orbital" orbital_dir = "./data/orbital"
cache_dir = "./data/cache" cache_dir = "./data/cache"
[services] # 定义服务到提供者的映射
audio = "playsound" # 可选项: playsound(通用), termux(仅用于支持 Android Termux), mpg123(TODO)
tts = "edgetts" # 可选项: edgetts
llm = "openai" # 可选项: openai
[providers.llm.openai] # 与 OpenAI 相容的语言模型接口服务设置
url = ""
key = ""

View File

@@ -3,7 +3,7 @@ from heurams.context import rootdir, workdir, config_var
from textual.app import App from textual.app import App
from textual.widgets import Button from textual.widgets import Button
from .screens.dashboard import DashboardScreen from .screens.dashboard import DashboardScreen
from .screens.nucleon_creator import NucleonCreatorScreen from .screens.nucreator import NucleonCreatorScreen
from .screens.precache import PrecachingScreen from .screens.precache import PrecachingScreen
class HeurAMSApp(App): class HeurAMSApp(App):

View File

@@ -105,7 +105,7 @@ class DashboardScreen(Screen):
def on_button_pressed(self, event) -> None: def on_button_pressed(self, event) -> None:
if event.button.id == "new_nucleon_button": if event.button.id == "new_nucleon_button":
# 切换到创建单元 # 切换到创建单元
from .nucleon_creator import NucleonCreatorScreen from .nucreator import NucleonCreatorScreen
newscr = NucleonCreatorScreen() newscr = NucleonCreatorScreen()
self.app.push_screen(newscr) self.app.push_screen(newscr)
elif event.button.id == "precache_all_button": elif event.button.id == "precache_all_button":

View File

@@ -18,7 +18,7 @@ class AtomState(Enum):
class MemScreen(Screen): class MemScreen(Screen):
BINDINGS = [ BINDINGS = [
("q", "pop_screen", "返回"), ("q", "pop_screen", "返回"),
#("p", "prev", "上一个"), ("p", "prev", "复习上一个"),
("d", "toggle_dark", "改变色调"), ("d", "toggle_dark", "改变色调"),
("v", "play_voice", "朗读"), ("v", "play_voice", "朗读"),
] ]
@@ -58,6 +58,7 @@ class MemScreen(Screen):
def on_button_pressed(self, event): def on_button_pressed(self, event):
event.stop() event.stop()
if
def action_play_voice(self): def action_play_voice(self):
"""朗读当前内容""" """朗读当前内容"""

View File

@@ -12,8 +12,10 @@ from textual.widgets import (
from textual.containers import Container from textual.containers import Container
from textual.screen import Screen from textual.screen import Screen
from heurams.services.version import ver
class NucleonCreatorScreen(Screen): class NucleonCreatorScreen(Screen):
BINDINGS = [("q", "go_back", "返回"), ("escape", "quit_app", "退出")] BINDINGS = [("q", "go_back", "返回")]
def __init__(self) -> None: def __init__(self) -> None:
super().__init__(name=None, id=None, classes=None) super().__init__(name=None, id=None, classes=None)
@@ -21,30 +23,34 @@ class NucleonCreatorScreen(Screen):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Header(show_clock=True) yield Header(show_clock=True)
with Container(id="vice_container"): with Container(id="vice_container"):
yield Label(f"[b]新建空的单元集\n") yield Label(f"[b]空白单元集创建向导\n")
yield Markdown("> 提示: 你可能注意到当选中文本框时底栏和操作按键绑定将被覆盖 \n只需选中(使用鼠标或 Tab)选择框即可恢复底栏功能")
yield Markdown("1. 键入单元集名称") yield Markdown("1. 键入单元集名称")
yield Input(placeholder="单元集名称") yield Input(placeholder="单元集名称")
yield Markdown("> 单元集名称不应与现有单元集重复, 新的单元集文件将创建在 ./nucleon/你输入的名称.toml") yield Markdown("> 单元集名称不应与现有单元集重复. \n> 新的单元集文件将创建在 ./nucleon/你输入的名称.toml")
yield Label(f"\n") yield Label(f"\n")
yield Markdown("2. 选择单元集类型") yield Markdown("2. 选择单元集模板")
LINES = """ LINES = f"""带有宏支持的空白单元集 ({ver})
单一字符串 古诗词模板单元集 ({ver})
主字符串(带有附加属性) 英语词汇和短语模板单元集 ({ver})
动态单元集(使用宏)
""".splitlines() """.splitlines()
yield Select.from_values(LINES, prompt="选择类型") yield Select.from_values(LINES, prompt="选择类型")
yield Markdown("> 新单元集的版本号将和主程序版本保持同步")
yield Label(f"\n") yield Label(f"\n")
yield Markdown("3. 输入附加元数据 (可选)") yield Markdown("3. 输入常见附加元数据 (可选)")
yield Input(placeholder="作者") yield Input(placeholder="作者")
yield Input(placeholder="内容描述") yield Input(placeholder="内容描述")
yield Button( yield Button(
"新建空单元集", "新建空单元集",
id="submit_button", id="submit_button",
variant="primary", variant="primary",
classes="start-button", classes="start-button",
) )
yield Footer() yield Footer()
def on_mount(self):
self.query_one("#submit_button").focus()
def action_go_back(self): def action_go_back(self):
self.app.pop_screen() self.app.pop_screen()

View File

@@ -177,26 +177,16 @@ class PrecachingScreen(Screen):
nu = list() nu = list()
for file in nucleon_files: for file in nucleon_files:
try: try:
nu += pt.load_nucleon(file)[0] for i in pt.load_nucleon(file):
self.total = len(nu) nu.append(i[0])
except: except:
continue continue
self.total = len(nu)
self.processed = 0 for i in nu:
self.is_precaching = True i: pt.Nucleon
i.do_eval()
for file in nucleon_files: return self.precache_by_list(nu)
try:
nu += pt.load_nucleon(file)[0]
if not self.precache_by_list(nu):
break # 用户取消
except Exception as e:
print(f"处理文件失败 {file}: {e}")
continue
self.is_precaching = False
self.update_status("完成", "所有单元的音频已被预缓存", 100)
def on_button_pressed(self, event: Button.Pressed) -> None: def on_button_pressed(self, event: Button.Pressed) -> None:
event.stop() event.stop()
if event.button.id == "start_precache" and not self.is_precaching: if event.button.id == "start_precache" and not self.is_precaching:

View File

@@ -1,10 +1,13 @@
# 音频播放器, 必须基于文件操作 # 音频播放器, 必须基于文件操作
from .termux_audio import player as termux_player from . import termux_audio
from . import playsound_audio
__all__ = [ __all__ = [
"termux_player" "termux_audio",
"playsound_audio",
] ]
players = { providers = {
"termux": termux_player "termux": termux_audio,
"playsound": playsound_audio
} }

View File

@@ -2,3 +2,10 @@
基于 playsound 库的音频播放器, 在绝大多数 python 环境上提供音频服务 基于 playsound 库的音频播放器, 在绝大多数 python 环境上提供音频服务
注意: 在未配置 pulseaudio termux 不可用 注意: 在未配置 pulseaudio termux 不可用
""" """
import os
import pathlib
import playsound
def play_by_path(path: pathlib.Path):
playsound.playsound(str(path))

View File

@@ -0,0 +1,5 @@
from typing import Protocol
import pathlib
class PlayFunctionProtocol(Protocol):
def __call__(self, path: pathlib.Path) -> None: ...

View File

@@ -5,6 +5,7 @@
import os import os
import pathlib import pathlib
#from .protocol import PlayFunctionProtocol
def player(path: pathlib.Path): def play_by_path(path: pathlib.Path):
os.system(f"play-audio {path}") os.system(f"play-audio {path}")

View File

@@ -6,7 +6,7 @@ __all__ = [
"EdgeTTS", "EdgeTTS",
] ]
TTSs = { providers = {
"BaseTTS": BaseTTS, "basetts": BaseTTS,
"EdgeTTS": EdgeTTS, "edgetts": EdgeTTS,
} }