You've already forked HeurAMS-Legacy
fix
This commit is contained in:
@@ -2,5 +2,6 @@ print("欢迎使用 HeurAMS 及其组件!")
|
||||
|
||||
# 补充日志记录
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
logger.info("欢迎使用 HeurAMS 及其组件!")
|
||||
|
||||
@@ -8,6 +8,7 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class HeurAMSApp(App):
|
||||
TITLE = "潜进"
|
||||
CSS_PATH = "css/main.tcss"
|
||||
@@ -37,8 +38,10 @@ class HeurAMSApp(App):
|
||||
print("DO NOTHING")
|
||||
self.refresh()
|
||||
|
||||
|
||||
def environment_check():
|
||||
from pathlib import Path
|
||||
|
||||
logger.debug("检查环境路径")
|
||||
|
||||
for i in config_var.get()["paths"].values():
|
||||
|
||||
@@ -34,12 +34,12 @@ class AboutScreen(Screen):
|
||||
|
||||
开发人员:
|
||||
|
||||
- [@pluvium27](https://github.com/pluvium27) (Wang Zhiyu)
|
||||
- Wang Zhiyu([@pluvium27](https://github.com/pluvium27)): 项目作者
|
||||
|
||||
特别感谢:
|
||||
|
||||
- [Piotr A. Woźniak](https://supermemo.guru/wiki/Piotr_Wozniak): SuperMemo-2 算法
|
||||
- [Thoughts Memo](https://www.zhihu.com/people/L.M.Sherlock): 文献参考
|
||||
- [Piotr A. Woźniak](https://supermemo.guru/wiki/Piotr_Wozniak): SuperMemo-2 算法
|
||||
- [Thoughts Memo](https://www.zhihu.com/people/L.M.Sherlock): 文献参考
|
||||
|
||||
# 参与贡献
|
||||
|
||||
@@ -47,7 +47,7 @@ class AboutScreen(Screen):
|
||||
|
||||
通过我们协力开发的软件为所有人谋取福祉.
|
||||
|
||||
此项目不是 KDE 软件, 但上述工作不可避免地让我们确立了和 KDE 宣言相同的下列价值观:
|
||||
上述工作不可避免地让我们确立了下列价值观 (取自 KDE 宣言):
|
||||
|
||||
- 开放治理 确保更多人能参与我们的领导和决策进程;
|
||||
|
||||
@@ -68,8 +68,13 @@ class AboutScreen(Screen):
|
||||
我们的共同目标是为人人带来高品质的辅助记忆 & 学习软件.
|
||||
|
||||
不管您来自何方, 我们都欢迎您加入社区并做出贡献.
|
||||
|
||||
"""
|
||||
|
||||
# """
|
||||
# 学术数据
|
||||
|
||||
# "潜进" 的用户数据可用于科学方面的研究, 我们将在未来版本添加学术数据的收集和展示平台
|
||||
# """
|
||||
yield Markdown(about_text, classes="about-markdown")
|
||||
|
||||
yield Button(
|
||||
|
||||
@@ -24,8 +24,10 @@ import pathlib
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class DashboardScreen(Screen):
|
||||
SUB_TITLE = "仪表盘"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
yield ScrollableContainer(
|
||||
@@ -71,6 +73,7 @@ class DashboardScreen(Screen):
|
||||
nextdate = 0x3F3F3F3F
|
||||
for i in electron_dict.values():
|
||||
i: pt.Electron
|
||||
logger.debug(i, i.is_due())
|
||||
if i.is_due():
|
||||
is_due = 1
|
||||
if i.is_activated():
|
||||
|
||||
@@ -18,8 +18,10 @@ class AtomState(Enum):
|
||||
FAILED = auto()
|
||||
NORMAL = auto()
|
||||
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class MemScreen(Screen):
|
||||
BINDINGS = [
|
||||
("q", "pop_screen", "返回"),
|
||||
@@ -45,6 +47,7 @@ class MemScreen(Screen):
|
||||
self.phaser = Phaser(atoms)
|
||||
# logger.debug(self.phaser.state)
|
||||
self.procession: Procession = self.phaser.current_procession() # type: ignore
|
||||
self.atom: pt.Atom = self.procession.current_atom
|
||||
# logger.debug(self.phaser.state)
|
||||
# self.procession.forward(1)
|
||||
for i in atoms:
|
||||
@@ -58,12 +61,12 @@ class MemScreen(Screen):
|
||||
try:
|
||||
logger.debug(self.phaser.state)
|
||||
logger.debug(self.procession.cursor)
|
||||
logger.debug(self.procession.current_atom)
|
||||
self.fission = Fission(self.procession.current_atom, self.phaser.state)
|
||||
logger.debug(self.atom)
|
||||
self.fission = Fission(self.atom, self.phaser.state)
|
||||
puzzle_debug = next(self.fission.generate())
|
||||
#logger.debug(puzzle_debug)
|
||||
# logger.debug(puzzle_debug)
|
||||
return shim.puzzle2widget[puzzle_debug["puzzle"]](
|
||||
atom=self.procession.current_atom, alia=puzzle_debug["alia"]
|
||||
atom=self.atom, alia=puzzle_debug["alia"]
|
||||
)
|
||||
except (KeyError, StopIteration, AttributeError) as e:
|
||||
logger.debug(f"调度展开出错: {e}")
|
||||
@@ -74,7 +77,7 @@ class MemScreen(Screen):
|
||||
yield Header(show_clock=True)
|
||||
with ScrollableContainer():
|
||||
yield Label(self._get_progress_text(), id="progress")
|
||||
|
||||
|
||||
# self.mount(self.current_widget()) # type: ignore
|
||||
yield ScrollableContainer(id="puzzle-container")
|
||||
# yield Button("重新学习此单元", id="re-recognize", variant="warning")
|
||||
@@ -85,7 +88,7 @@ class MemScreen(Screen):
|
||||
|
||||
def update_display(self):
|
||||
progress_widget = self.query_one("#progress")
|
||||
progress_widget.update(self._get_progress_text()) # type: ignore
|
||||
progress_widget.update(self._get_progress_text()) # type: ignore
|
||||
|
||||
def load_puzzle(self):
|
||||
container = self.query_one("#puzzle-container")
|
||||
@@ -98,6 +101,7 @@ class MemScreen(Screen):
|
||||
for i in container.children:
|
||||
i.remove()
|
||||
from heurams.interface.widgets.finished import Finished
|
||||
|
||||
container.mount(Finished())
|
||||
|
||||
def on_button_pressed(self, event):
|
||||
@@ -108,11 +112,12 @@ class MemScreen(Screen):
|
||||
return
|
||||
forwards = 1 if new_rating >= 4 else 0
|
||||
self.rating = -1
|
||||
logger.debug(f"试图前进: {"允许" if forwards else "禁止"}")
|
||||
if forwards:
|
||||
ret = self.procession.forward(1)
|
||||
if ret == 0:
|
||||
if ret == 0: # 若结束了此次队列
|
||||
self.procession = self.phaser.current_procession() # type: ignore
|
||||
if self.procession == 0:
|
||||
if self.procession == 0: # 若所有队列都结束了
|
||||
logger.debug(f"记忆进程结束")
|
||||
for i in self.atoms:
|
||||
i: pt.Atom
|
||||
@@ -121,10 +126,10 @@ class MemScreen(Screen):
|
||||
return
|
||||
else:
|
||||
logger.debug(f"建立新队列 {self.procession.phase}")
|
||||
else:
|
||||
self.load_puzzle()
|
||||
else: # 若不通过
|
||||
self.procession.append()
|
||||
self.update_display()
|
||||
self.load_puzzle()
|
||||
|
||||
def action_play_voice(self):
|
||||
"""朗读当前内容"""
|
||||
|
||||
@@ -94,28 +94,28 @@ class NucleonCreatorScreen(Screen):
|
||||
template_select = self.query_one("#template_select")
|
||||
author_input = self.query_one("#author_input")
|
||||
desc_input = self.query_one("#desc_input")
|
||||
|
||||
name = name_input.value.strip() # type: ignore
|
||||
author = author_input.value.strip() # type: ignore
|
||||
desc = desc_input.value.strip() # type: ignore
|
||||
selected = template_select.value # type: ignore
|
||||
|
||||
|
||||
name = name_input.value.strip() # type: ignore
|
||||
author = author_input.value.strip() # type: ignore
|
||||
desc = desc_input.value.strip() # type: ignore
|
||||
selected = template_select.value # type: ignore
|
||||
|
||||
# 验证
|
||||
if not name:
|
||||
self.notify("单元集名称不能为空", severity="error")
|
||||
return
|
||||
|
||||
|
||||
# 获取配置路径
|
||||
config = config_var.get()
|
||||
nucleon_dir = Path(config["paths"]["nucleon_dir"])
|
||||
template_dir = Path(config["paths"]["template_dir"])
|
||||
|
||||
|
||||
# 检查文件是否已存在
|
||||
nucleon_path = nucleon_dir / f"{name}.toml"
|
||||
if nucleon_path.exists():
|
||||
self.notify(f"单元集 '{name}' 已存在", severity="error")
|
||||
return
|
||||
|
||||
|
||||
# 确定模板文件
|
||||
if selected is None:
|
||||
self.notify("请选择一个模板", severity="error")
|
||||
@@ -123,7 +123,8 @@ class NucleonCreatorScreen(Screen):
|
||||
# selected 是描述字符串,格式如 "描述 (filename.toml)"
|
||||
# 提取文件名
|
||||
import re
|
||||
match = re.search(r'\(([^)]+)\)$', selected)
|
||||
|
||||
match = re.search(r"\(([^)]+)\)$", selected)
|
||||
if not match:
|
||||
self.notify("模板选择格式无效", severity="error")
|
||||
return
|
||||
@@ -132,15 +133,15 @@ class NucleonCreatorScreen(Screen):
|
||||
if not template_path.exists():
|
||||
self.notify(f"模板文件不存在: {template_filename}", severity="error")
|
||||
return
|
||||
|
||||
|
||||
# 加载模板
|
||||
try:
|
||||
with open(template_path, 'r', encoding='utf-8') as f:
|
||||
with open(template_path, "r", encoding="utf-8") as f:
|
||||
template_data = toml.load(f)
|
||||
except Exception as e:
|
||||
self.notify(f"加载模板失败: {e}", severity="error")
|
||||
return
|
||||
|
||||
|
||||
# 更新元数据
|
||||
metadata = template_data.get("__metadata__", {})
|
||||
attribution = metadata.get("attribution", {})
|
||||
@@ -153,17 +154,17 @@ class NucleonCreatorScreen(Screen):
|
||||
attribution["version"] = ver
|
||||
metadata["attribution"] = attribution
|
||||
template_data["__metadata__"] = metadata
|
||||
|
||||
|
||||
# 确保 nucleon_dir 存在
|
||||
nucleon_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
# 写入新文件
|
||||
try:
|
||||
with open(nucleon_path, 'w', encoding='utf-8') as f:
|
||||
with open(nucleon_path, "w", encoding="utf-8") as f:
|
||||
toml.dump(template_data, f)
|
||||
except Exception as e:
|
||||
self.notify(f"保存单元集失败: {e}", severity="error")
|
||||
return
|
||||
|
||||
|
||||
self.notify(f"单元集 '{name}' 创建成功")
|
||||
self.app.pop_screen()
|
||||
|
||||
@@ -19,7 +19,7 @@ from heurams.context import *
|
||||
class PreparationScreen(Screen):
|
||||
|
||||
SUB_TITLE = "准备记忆集"
|
||||
|
||||
|
||||
BINDINGS = [
|
||||
("q", "go_back", "返回"),
|
||||
("p", "precache", "预缓存音频"),
|
||||
@@ -70,7 +70,6 @@ class PreparationScreen(Screen):
|
||||
def action_go_back(self):
|
||||
self.app.pop_screen()
|
||||
|
||||
|
||||
def action_precache(self):
|
||||
from ..screens.precache import PrecachingScreen
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Iterable
|
||||
from textual.app import ComposeResult
|
||||
from textual.widget import Widget
|
||||
import heurams.kernel.particles as pt
|
||||
|
||||
@@ -22,3 +24,9 @@ class BasePuzzleWidget(Widget):
|
||||
markup=markup
|
||||
)
|
||||
self.atom = atom
|
||||
|
||||
def compose(self) -> Iterable[Widget]:
|
||||
return super().compose()
|
||||
|
||||
def handler(self, rating) -> None:
|
||||
pass
|
||||
@@ -15,12 +15,14 @@ from typing import TypedDict
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class Setting(TypedDict):
|
||||
__origin__: str
|
||||
__hint__: str
|
||||
text: str
|
||||
delimiter: str
|
||||
min_denominator: str
|
||||
min_denominator: str
|
||||
|
||||
|
||||
class ClozePuzzle(BasePuzzleWidget):
|
||||
|
||||
@@ -58,7 +60,7 @@ class ClozePuzzle(BasePuzzleWidget):
|
||||
min_denominator=int(setting["min_denominator"]),
|
||||
)
|
||||
self.puzzle.refresh()
|
||||
self.ans = copy.copy(self.puzzle.answer) # 乱序
|
||||
self.ans = copy.copy(self.puzzle.answer) # 乱序
|
||||
random.shuffle(self.ans)
|
||||
|
||||
def compose(self):
|
||||
@@ -78,7 +80,6 @@ class ClozePuzzle(BasePuzzleWidget):
|
||||
preview = self.query_one("#inputpreview")
|
||||
preview.update(f"当前输入: {self.inputlist}") # type: ignore
|
||||
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
button_id = event.button.id
|
||||
|
||||
@@ -87,16 +88,22 @@ class ClozePuzzle(BasePuzzleWidget):
|
||||
self.inputlist.pop()
|
||||
self.update_display()
|
||||
else:
|
||||
answer_text = self.hashmap[button_id[7:]] # type: ignore
|
||||
answer_text = self.hashmap[button_id[7:]] # type: ignore
|
||||
self.inputlist.append(answer_text)
|
||||
self.update_display()
|
||||
|
||||
if len(self.inputlist) >= len(self.puzzle.answer):
|
||||
is_correct = self.inputlist == self.puzzle.answer
|
||||
rating = 4 if is_correct else 2
|
||||
|
||||
self.screen.rating = rating # type: ignore
|
||||
self.handler(rating)
|
||||
self.screen.rating = rating # type: ignore
|
||||
|
||||
if not is_correct:
|
||||
self.inputlist = []
|
||||
self.update_display()
|
||||
|
||||
def handler(self, rating):
|
||||
if self.atom.lock():
|
||||
pass
|
||||
else:
|
||||
self.atom.minimize(rating)
|
||||
@@ -14,6 +14,7 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class Setting(TypedDict):
|
||||
__origin__: str
|
||||
__hint__: str
|
||||
@@ -49,6 +50,7 @@ class MCQPuzzle(BasePuzzleWidget):
|
||||
self.alia = alia
|
||||
self.hashmap = dict()
|
||||
self.cursor = 0
|
||||
self.atom = atom
|
||||
self._load()
|
||||
|
||||
def _load(self):
|
||||
@@ -79,7 +81,7 @@ class MCQPuzzle(BasePuzzleWidget):
|
||||
|
||||
yield Button("退格", id="delete")
|
||||
|
||||
def update_display(self, error = 0):
|
||||
def update_display(self, error=0):
|
||||
# 更新预览标签
|
||||
preview = self.query_one("#inputpreview")
|
||||
preview.update(f"当前输入: {self.inputlist}") # type: ignore
|
||||
@@ -113,7 +115,7 @@ class MCQPuzzle(BasePuzzleWidget):
|
||||
rating = 4 if is_correct else 2
|
||||
|
||||
self.screen.rating = rating # type: ignore
|
||||
|
||||
self.handler(rating)
|
||||
# 重置输入(如果回答错误)
|
||||
if not is_correct:
|
||||
self.inputlist = []
|
||||
@@ -138,7 +140,7 @@ class MCQPuzzle(BasePuzzleWidget):
|
||||
|
||||
for button in buttons_to_remove:
|
||||
logger.info(button)
|
||||
container.remove_children("#"+button.id) # type: ignore
|
||||
container.remove_children("#" + button.id) # type: ignore
|
||||
|
||||
# 添加当前题目的选项按钮
|
||||
current_question_index = len(self.inputlist)
|
||||
@@ -150,3 +152,10 @@ class MCQPuzzle(BasePuzzleWidget):
|
||||
self.hashmap[button_id] = option
|
||||
new_button = Button(option, id=button_id)
|
||||
container.mount(new_button)
|
||||
|
||||
def handler(self, rating):
|
||||
if self.atom.lock():
|
||||
pass
|
||||
else:
|
||||
self.atom.minimize(rating)
|
||||
|
||||
@@ -13,7 +13,9 @@ import re
|
||||
from .base_puzzle_widget import BasePuzzleWidget
|
||||
from typing import TypedDict, List
|
||||
from textual.message import Message
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
class RecognitionConfig(TypedDict):
|
||||
__origin__: str
|
||||
@@ -100,3 +102,11 @@ class Recognition(BasePuzzleWidget):
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
if event.button.id == "ok":
|
||||
self.screen.rating = 5 # type: ignore
|
||||
self.handler(5)
|
||||
|
||||
def handler(self, rating):
|
||||
if not self.atom.registry["electron"].is_activated() and not self.atom.registry["runtime"]["locked"]:
|
||||
self.atom.registry["electron"].activate()
|
||||
logger.debug(f"激活原子 {self.atom}")
|
||||
self.atom.lock(1)
|
||||
self.atom.minimize(5)
|
||||
|
||||
@@ -33,27 +33,37 @@ class BaseAlgorithm:
|
||||
cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False
|
||||
) -> None:
|
||||
"""迭代记忆数据"""
|
||||
logger.debug("BaseAlgorithm.revisor 被调用,algodata keys: %s, feedback: %d, is_new_activation: %s",
|
||||
list(algodata.keys()) if algodata else [], feedback, is_new_activation)
|
||||
logger.debug(
|
||||
"BaseAlgorithm.revisor 被调用,algodata keys: %s, feedback: %d, is_new_activation: %s",
|
||||
list(algodata.keys()) if algodata else [],
|
||||
feedback,
|
||||
is_new_activation,
|
||||
)
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def is_due(cls, algodata) -> int:
|
||||
"""是否应该复习"""
|
||||
logger.debug("BaseAlgorithm.is_due 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [])
|
||||
logger.debug(
|
||||
"BaseAlgorithm.is_due 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [],
|
||||
)
|
||||
return 1
|
||||
|
||||
@classmethod
|
||||
def rate(cls, algodata) -> str:
|
||||
"""获取评分信息"""
|
||||
logger.debug("BaseAlgorithm.rate 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [])
|
||||
logger.debug(
|
||||
"BaseAlgorithm.rate 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [],
|
||||
)
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
def nextdate(cls, algodata) -> int:
|
||||
"""获取下一次记忆时间戳"""
|
||||
logger.debug("BaseAlgorithm.nextdate 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [])
|
||||
logger.debug(
|
||||
"BaseAlgorithm.nextdate 被调用,algodata keys: %s",
|
||||
list(algodata.keys()) if algodata else [],
|
||||
)
|
||||
return -1
|
||||
|
||||
@@ -41,8 +41,12 @@ class SM2Algorithm(BaseAlgorithm):
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数
|
||||
"""
|
||||
logger.debug("SM2.revisor 开始,feedback: %d, is_new_activation: %s", feedback, is_new_activation)
|
||||
|
||||
logger.debug(
|
||||
"SM2.revisor 开始,feedback: %d, is_new_activation: %s",
|
||||
feedback,
|
||||
is_new_activation,
|
||||
)
|
||||
|
||||
if feedback == -1:
|
||||
logger.debug("feedback 为 -1,跳过更新")
|
||||
return
|
||||
@@ -81,24 +85,32 @@ class SM2Algorithm(BaseAlgorithm):
|
||||
algodata[cls.algo_name]["interval"] = round(
|
||||
algodata[cls.algo_name]["interval"] * algodata[cls.algo_name]["efactor"]
|
||||
)
|
||||
logger.debug("rept>1,计算 interval: %d", algodata[cls.algo_name]["interval"])
|
||||
logger.debug(
|
||||
"rept>1,计算 interval: %d", algodata[cls.algo_name]["interval"]
|
||||
)
|
||||
|
||||
algodata[cls.algo_name]["last_date"] = timer.get_daystamp()
|
||||
algodata[cls.algo_name]["next_date"] = (
|
||||
timer.get_daystamp() + algodata[cls.algo_name]["interval"]
|
||||
)
|
||||
algodata[cls.algo_name]["last_modify"] = timer.get_timestamp()
|
||||
|
||||
logger.debug("更新日期: last_date=%d, next_date=%d, last_modify=%f",
|
||||
algodata[cls.algo_name]["last_date"],
|
||||
algodata[cls.algo_name]["next_date"],
|
||||
algodata[cls.algo_name]["last_modify"])
|
||||
|
||||
logger.debug(
|
||||
"更新日期: last_date=%d, next_date=%d, last_modify=%f",
|
||||
algodata[cls.algo_name]["last_date"],
|
||||
algodata[cls.algo_name]["next_date"],
|
||||
algodata[cls.algo_name]["last_modify"],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def is_due(cls, algodata):
|
||||
result = algodata[cls.algo_name]["next_date"] <= timer.get_daystamp()
|
||||
logger.debug("SM2.is_due: next_date=%d, current_daystamp=%d, result=%s",
|
||||
algodata[cls.algo_name]["next_date"], timer.get_daystamp(), result)
|
||||
logger.debug(
|
||||
"SM2.is_due: next_date=%d, current_daystamp=%d, result=%s",
|
||||
algodata[cls.algo_name]["next_date"],
|
||||
timer.get_daystamp(),
|
||||
result,
|
||||
)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -5,6 +5,7 @@ Particle 模块 - 粒子对象系统
|
||||
"""
|
||||
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
logger.debug("粒子模块已加载")
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
class AtomRegister_runtime(TypedDict):
|
||||
locked: bool # 只读锁定标识符
|
||||
min_rate: int # 最低评分
|
||||
|
||||
class AtomRegister(TypedDict):
|
||||
nucleon: Nucleon
|
||||
@@ -23,7 +26,7 @@ class AtomRegister(TypedDict):
|
||||
orbital: Orbital
|
||||
orbital_path: pathlib.Path
|
||||
orbital_fmt: str
|
||||
runtime: dict
|
||||
runtime: AtomRegister_runtime
|
||||
|
||||
|
||||
class Atom:
|
||||
@@ -51,6 +54,7 @@ class Atom:
|
||||
"orbital": None,
|
||||
"orbital_path": None, # 允许设置为 None, 此时使用 nucleon 文件内的推荐配置
|
||||
"orbital_fmt": "toml",
|
||||
"runtime": {"locked": False, "min_rate": 0x3f3f3f3f}
|
||||
}
|
||||
self.do_eval()
|
||||
logger.debug("Atom 初始化完成")
|
||||
@@ -65,6 +69,38 @@ class Atom:
|
||||
logger.error("尝试链接不受支持的键: '%s'", key)
|
||||
raise ValueError("不受支持的原子元数据链接操作")
|
||||
|
||||
def minimize(self, rating):
|
||||
"""效果等同于 self.registry['runtime']['min_rate'] = min(rating, self.registry['runtime']['min_rate'])
|
||||
|
||||
Args:
|
||||
rating (int): 评分
|
||||
"""
|
||||
self.registry['runtime']['min_rate'] = min(rating, self.registry['runtime']['min_rate'])
|
||||
|
||||
def lock(self, locked = -1):
|
||||
"""锁定, 效果等同于 self.registry['runtime']['locked'] = locked 或者返回是否锁定
|
||||
"""
|
||||
if locked == 1:
|
||||
self.registry['runtime']['locked'] = True
|
||||
return 1
|
||||
elif locked == 0:
|
||||
self.registry['runtime']['locked'] = False
|
||||
return 1
|
||||
elif locked == -1:
|
||||
return self.registry['runtime']["locked"]
|
||||
return 0
|
||||
|
||||
def revise(self):
|
||||
"""执行最终评分
|
||||
PuzzleWidget 的 handler 除了测试, 严禁直接执行 Electron 的 revisor 函数, 否则造成逻辑混乱
|
||||
"""
|
||||
if self.registry["runtime"]["locked"]:
|
||||
logger.debug(f"允许总评分: {self.registry['runtime']['min_rate']}")
|
||||
self.registry["electron"].revisor(self.registry['runtime']["min_rate"])
|
||||
else:
|
||||
logger.debug("禁止总评分")
|
||||
|
||||
|
||||
def do_eval(self):
|
||||
"""
|
||||
执行并以结果替换当前单元的所有 eval 语句
|
||||
@@ -85,13 +121,17 @@ class Atom:
|
||||
# 如果无法获取配置或元数据,使用空字典
|
||||
logger.debug("无法获取配置或元数据,使用空字典")
|
||||
pass
|
||||
try:
|
||||
try:
|
||||
eval_value = eval(s)
|
||||
if isinstance(eval_value, (list, dict)):
|
||||
ret = eval_value
|
||||
else:
|
||||
ret = str(eval_value)
|
||||
logger.debug("eval 执行成功: '%s' -> '%s'", s, str(ret)[:50] + '...' if len(ret) > 50 else ret)
|
||||
logger.debug(
|
||||
"eval 执行成功: '%s' -> '%s'",
|
||||
s,
|
||||
str(ret)[:50] + "..." if len(ret) > 50 else ret,
|
||||
)
|
||||
except Exception as e:
|
||||
ret = f"此 eval 实例发生错误: {e}"
|
||||
logger.warning("eval 执行错误: '%s' -> %s", s, e)
|
||||
@@ -117,16 +157,16 @@ class Atom:
|
||||
|
||||
# 如果 nucleon 存在且有 do_eval 方法,调用它
|
||||
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()
|
||||
logger.debug("已调用 nucleon.do_eval")
|
||||
|
||||
|
||||
# 如果 electron 存在且其 algodata 包含 eval 字符串,遍历它
|
||||
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)
|
||||
logger.debug("已处理 electron algodata eval")
|
||||
|
||||
|
||||
# 如果 orbital 存在且是字典,遍历它
|
||||
orbital = self.registry["orbital"]
|
||||
if orbital is not None and isinstance(orbital, dict):
|
||||
@@ -173,7 +213,9 @@ class Atom:
|
||||
raise KeyError(f"不支持的键: {key}")
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
logger.debug("Atom.__setitem__: key='%s', value type: %s", key, type(value).__name__)
|
||||
logger.debug(
|
||||
"Atom.__setitem__: key='%s', value type: %s", key, type(value).__name__
|
||||
)
|
||||
if key in self.registry:
|
||||
self.registry[key] = value
|
||||
logger.debug("键 '%s' 已设置", key)
|
||||
|
||||
@@ -17,7 +17,9 @@ class Electron:
|
||||
algodata: 算法数据字典, 包含算法的各项参数和设置
|
||||
algo: 使用的算法模块标识
|
||||
"""
|
||||
logger.debug("创建 Electron 实例,ident: '%s', algo_name: '%s'", ident, algo_name)
|
||||
logger.debug(
|
||||
"创建 Electron 实例,ident: '%s', algo_name: '%s'", ident, algo_name
|
||||
)
|
||||
self.algodata = algodata
|
||||
self.ident = ident
|
||||
self.algo = algorithms[algo_name]
|
||||
@@ -31,11 +33,15 @@ class Electron:
|
||||
self._default_init(self.algo.defaults)
|
||||
else:
|
||||
logger.debug("算法数据已存在,跳过默认初始化")
|
||||
logger.debug("Electron 初始化完成,algodata keys: %s", list(self.algodata.keys()))
|
||||
logger.debug(
|
||||
"Electron 初始化完成,algodata keys: %s", list(self.algodata.keys())
|
||||
)
|
||||
|
||||
def _default_init(self, defaults: dict):
|
||||
"""默认初始化包装"""
|
||||
logger.debug("Electron._default_init: 使用默认值,keys: %s", list(defaults.keys()))
|
||||
logger.debug(
|
||||
"Electron._default_init: 使用默认值,keys: %s", list(defaults.keys())
|
||||
)
|
||||
self.algodata[self.algo.algo_name] = defaults.copy()
|
||||
|
||||
def activate(self):
|
||||
@@ -88,10 +94,16 @@ class Electron:
|
||||
quality (int): 记忆保留率量化参数 (0-5)
|
||||
is_new_activation (bool): 是否为初次激活
|
||||
"""
|
||||
logger.debug("Electron.revisor: ident='%s', quality=%d, is_new_activation=%s",
|
||||
self.ident, quality, is_new_activation)
|
||||
logger.debug(
|
||||
"Electron.revisor: ident='%s', quality=%d, is_new_activation=%s",
|
||||
self.ident,
|
||||
quality,
|
||||
is_new_activation,
|
||||
)
|
||||
self.algo.revisor(self.algodata, quality, is_new_activation)
|
||||
logger.debug("revisor 完成,更新后的 algodata: %s", self.algodata.get(self.algo, {}))
|
||||
logger.debug(
|
||||
"revisor 完成,更新后的 algodata: %s", self.algodata.get(self.algo, {})
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
|
||||
@@ -40,9 +40,7 @@ def load_nucleon(path: pathlib.Path, fmt="toml"):
|
||||
logger.debug("处理项目: %s", item)
|
||||
lst.append(
|
||||
(
|
||||
Nucleon(
|
||||
item, attr, deepcopy(nested_data["__metadata__"])
|
||||
),
|
||||
Nucleon(item, attr, deepcopy(nested_data["__metadata__"])),
|
||||
deepcopy(nested_data["__metadata__"]["orbital"]),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -14,8 +14,12 @@ class Nucleon:
|
||||
payload: 记忆内容信息
|
||||
metadata: 可选元数据信息
|
||||
"""
|
||||
logger.debug("创建 Nucleon 实例,ident: '%s', payload keys: %s, metadata keys: %s",
|
||||
ident, list(payload.keys()) if payload else [], list(metadata.keys()) if metadata else [])
|
||||
logger.debug(
|
||||
"创建 Nucleon 实例,ident: '%s', payload keys: %s, metadata keys: %s",
|
||||
ident,
|
||||
list(payload.keys()) if payload else [],
|
||||
list(metadata.keys()) if metadata else [],
|
||||
)
|
||||
self.metadata = metadata
|
||||
self.payload = payload
|
||||
self.ident = ident
|
||||
@@ -28,7 +32,9 @@ class Nucleon:
|
||||
return self.ident
|
||||
if key in self.payload:
|
||||
value = self.payload[key]
|
||||
logger.debug("返回 payload['%s'], value type: %s", key, type(value).__name__)
|
||||
logger.debug(
|
||||
"返回 payload['%s'], value type: %s", key, type(value).__name__
|
||||
)
|
||||
return value
|
||||
else:
|
||||
logger.error("键 '%s' 未在 payload 中找到", key)
|
||||
@@ -59,7 +65,11 @@ class Nucleon:
|
||||
ret = str(eval_value)
|
||||
else:
|
||||
ret = eval_value
|
||||
logger.debug("eval 执行成功: '%s' -> '%s'", s, str(ret)[:50] + '...' if len(ret) > 50 else ret)
|
||||
logger.debug(
|
||||
"eval 执行成功: '%s' -> '%s'",
|
||||
s,
|
||||
str(ret)[:50] + "..." if len(ret) > 50 else ret,
|
||||
)
|
||||
except Exception as e:
|
||||
ret = f"此 eval 实例发生错误: {e}"
|
||||
logger.warning("eval 执行错误: '%s' -> %s", s, e)
|
||||
|
||||
@@ -5,6 +5,7 @@ Puzzle 模块 - 谜题生成系统
|
||||
"""
|
||||
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
from .base import BasePuzzle
|
||||
@@ -41,7 +42,9 @@ def create_by_dict(config_dict: dict) -> BasePuzzle:
|
||||
Raises:
|
||||
ValueError: 当配置无效时抛出
|
||||
"""
|
||||
logger.debug("puzzles.create_by_dict: config_dict keys=%s", list(config_dict.keys()))
|
||||
logger.debug(
|
||||
"puzzles.create_by_dict: config_dict keys=%s", list(config_dict.keys())
|
||||
)
|
||||
puzzle_type = config_dict.get("type")
|
||||
|
||||
if puzzle_type == "cloze":
|
||||
|
||||
@@ -14,8 +14,12 @@ class ClozePuzzle(BasePuzzle):
|
||||
"""
|
||||
|
||||
def __init__(self, text: str, min_denominator: int, delimiter: str = "/"):
|
||||
logger.debug("ClozePuzzle.__init__: text length=%d, min_denominator=%d, delimiter='%s'",
|
||||
len(text), min_denominator, delimiter)
|
||||
logger.debug(
|
||||
"ClozePuzzle.__init__: text length=%d, min_denominator=%d, delimiter='%s'",
|
||||
len(text),
|
||||
min_denominator,
|
||||
delimiter,
|
||||
)
|
||||
self.text = text
|
||||
self.min_denominator = min_denominator
|
||||
self.wording = "填空题 - 尚未刷新谜题"
|
||||
|
||||
@@ -6,6 +6,7 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class MCQPuzzle(BasePuzzle):
|
||||
"""选择题谜题生成器
|
||||
|
||||
@@ -37,7 +38,12 @@ class MCQPuzzle(BasePuzzle):
|
||||
max_riddles_num: 每次生成的最大题目数量, 范围限制在1-5之间
|
||||
prefix: 题目前缀文本, 会显示在每个题目之前
|
||||
"""
|
||||
logger.debug("MCQPuzzle.__init__: mapping size=%d, jammer size=%d, max_riddles_num=%d", len(mapping), len(jammer), max_riddles_num)
|
||||
logger.debug(
|
||||
"MCQPuzzle.__init__: mapping size=%d, jammer size=%d, max_riddles_num=%d",
|
||||
len(mapping),
|
||||
len(jammer),
|
||||
max_riddles_num,
|
||||
)
|
||||
self.prefix = prefix
|
||||
self.mapping = mapping
|
||||
self.max_riddles_num = max(1, min(max_riddles_num, 5))
|
||||
|
||||
@@ -11,7 +11,7 @@ class Fission:
|
||||
def __init__(self, atom: pt.Atom, phase=PhaserState.RECOGNITION):
|
||||
self.logger = get_logger(__name__)
|
||||
self.atom = atom
|
||||
#print(f"{phase.value}")
|
||||
# print(f"{phase.value}")
|
||||
self.orbital_schedule = atom.registry["orbital"]["schedule"][phase.value] # type: ignore
|
||||
self.orbital_puzzles = atom.registry["orbital"]["puzzles"]
|
||||
# print(self.orbital_schedule)
|
||||
@@ -38,7 +38,6 @@ class Fission:
|
||||
)
|
||||
print(f"ok:{item}")
|
||||
self.logger.debug(f"orbital 项处理完成: {item}")
|
||||
|
||||
|
||||
def generate(self):
|
||||
yield from self.puzzles
|
||||
|
||||
@@ -9,8 +9,12 @@ class Procession:
|
||||
"""队列: 标识单次记忆流程"""
|
||||
|
||||
def __init__(self, atoms: list, phase: PhaserState, name: str = ""):
|
||||
logger.debug("Procession.__init__: 原子数量=%d, phase=%s, name='%s'",
|
||||
len(atoms), phase.value, name)
|
||||
logger.debug(
|
||||
"Procession.__init__: 原子数量=%d, phase=%s, name='%s'",
|
||||
len(atoms),
|
||||
phase.value,
|
||||
name,
|
||||
)
|
||||
self.atoms = atoms
|
||||
self.queue = atoms.copy()
|
||||
self.current_atom = atoms[0]
|
||||
|
||||
@@ -16,4 +16,5 @@ class ProcessionState(Enum):
|
||||
RUNNING = auto()
|
||||
FINISHED = auto()
|
||||
|
||||
|
||||
logger.debug("状态枚举定义已加载")
|
||||
|
||||
@@ -2,4 +2,4 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
logger.debug("LLM 基类模块已加载")
|
||||
logger.debug("LLM 基类模块已加载")
|
||||
|
||||
@@ -2,4 +2,4 @@ from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
logger.debug("OpenAI provider 模块已加载(未实现)")
|
||||
logger.debug("OpenAI provider 模块已加载(未实现)")
|
||||
|
||||
@@ -7,4 +7,6 @@ from heurams.services.logger import get_logger
|
||||
logger = get_logger(__name__)
|
||||
|
||||
play_by_path: Callable = prov[config_var.get()["services"]["audio"]].play_by_path
|
||||
logger.debug("音频服务初始化完成,使用 provider: %s", config_var.get()["services"]["audio"])
|
||||
logger.debug(
|
||||
"音频服务初始化完成,使用 provider: %s", config_var.get()["services"]["audio"]
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ def setup_logging(
|
||||
filename=log_path,
|
||||
maxBytes=max_bytes,
|
||||
backupCount=backup_count,
|
||||
encoding='utf-8'
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
file_handler.setLevel(log_level)
|
||||
@@ -58,7 +58,7 @@ def setup_logging(
|
||||
# 配置root logger - 设置为 WARNING 级别(只记录重要信息)
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.WARNING) # 这里改为 WARNING
|
||||
|
||||
|
||||
# 移除所有现有handler
|
||||
for handler in root_logger.handlers[:]:
|
||||
root_logger.removeHandler(handler)
|
||||
@@ -67,22 +67,22 @@ def setup_logging(
|
||||
app_logger = logging.getLogger("heurams")
|
||||
app_logger.setLevel(log_level) # 保持DEBUG级别
|
||||
app_logger.addHandler(file_handler)
|
||||
|
||||
|
||||
# 禁止传播到root logger,避免双重记录
|
||||
app_logger.propagate = False
|
||||
|
||||
|
||||
# 设置第三方库的日志级别为WARNING,避免调试信息干扰
|
||||
third_party_loggers = [
|
||||
"markdown_it",
|
||||
"markdown_it.rules_block",
|
||||
"markdown_it.rules_core",
|
||||
"markdown_it.rules_core",
|
||||
"markdown_it.rules_inline",
|
||||
"asyncio",
|
||||
]
|
||||
|
||||
|
||||
for logger_name in third_party_loggers:
|
||||
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
||||
|
||||
|
||||
# 记录日志系统初始化
|
||||
app_logger.info("日志系统已初始化, 日志文件: %s", log_path)
|
||||
|
||||
@@ -100,7 +100,7 @@ def get_logger(name: Optional[str] = None) -> logging.Logger:
|
||||
"""
|
||||
if name is None:
|
||||
return logging.getLogger()
|
||||
|
||||
|
||||
# 确保使用 heurams 作为前缀,继承应用logger的配置
|
||||
if not name.startswith("heurams") and name != "":
|
||||
logger_name = f"heurams.{name}"
|
||||
@@ -142,7 +142,7 @@ def critical(msg: str, *args, **kwargs) -> None:
|
||||
|
||||
|
||||
def exception(msg: str, *args, **kwargs) -> None:
|
||||
"""记录异常信息 (ERROR级别) """
|
||||
"""记录异常信息 (ERROR级别)"""
|
||||
get_logger().exception(msg, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -152,4 +152,4 @@ setup_logging()
|
||||
|
||||
# 模块级别的logger实例
|
||||
logger = get_logger(__name__)
|
||||
logger.info("HeurAMS日志服务模块已加载")
|
||||
logger.info("HeurAMS日志服务模块已加载")
|
||||
|
||||
@@ -7,4 +7,6 @@ from heurams.services.logger import get_logger
|
||||
logger = get_logger(__name__)
|
||||
|
||||
convert: Callable = TTSs[config_var.get().get("tts_provider")]
|
||||
logger.debug("TTS服务初始化完成,使用 provider: %s", config_var.get().get("tts_provider"))
|
||||
logger.debug(
|
||||
"TTS服务初始化完成,使用 provider: %s", config_var.get().get("tts_provider")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user