Archived
0
0

fix: 改进

This commit is contained in:
2025-12-16 03:28:29 +08:00
parent 5e4b0508eb
commit 5f2e8f6523
19 changed files with 1076 additions and 61 deletions

View File

@@ -117,6 +117,8 @@ class MemScreen(Screen):
return
else:
logger.debug(f"建立新队列 {self.procession.phase}")
else:
self.procession.append()
self.update_display()
self.load_puzzle()

View File

@@ -13,6 +13,9 @@ from textual.containers import ScrollableContainer
from textual.screen import Screen
from heurams.services.version import ver
import toml
from pathlib import Path
from heurams.context import config_var
class NucleonCreatorScreen(Screen):
@@ -39,7 +42,6 @@ class NucleonCreatorScreen(Screen):
except Exception as e:
templates.append(f"无描述模板 ({i.name})")
print(e)
print(templates)
return templates
def compose(self) -> ComposeResult:
@@ -50,7 +52,7 @@ class NucleonCreatorScreen(Screen):
"> 提示: 你可能注意到当选中文本框时底栏和操作按键绑定将被覆盖 \n只需选中(使用鼠标或 Tab)选择框即可恢复底栏功能"
)
yield Markdown("1. 键入单元集名称")
yield Input(placeholder="单元集名称")
yield Input(placeholder="单元集名称", id="name_input")
yield Markdown(
"> 单元集名称不应与现有单元集重复. \n> 新的单元集文件将创建在 ./nucleon/你输入的名称.toml"
)
@@ -61,12 +63,12 @@ class NucleonCreatorScreen(Screen):
古诗词模板单元集 ({ver})
英语词汇和短语模板单元集 ({ver})
"""
yield Select.from_values(LINES, prompt="选择类型")
yield Select.from_values(LINES, prompt="选择类型", id="template_select")
yield Markdown("> 新单元集的版本号将和主程序版本保持同步")
yield Label(f"\n")
yield Markdown("3. 输入常见附加元数据 (可选)")
yield Input(placeholder="作者")
yield Input(placeholder="内容描述")
yield Input(placeholder="作者", id="author_input")
yield Input(placeholder="内容描述", id="desc_input")
yield Button(
"新建空白单元集",
id="submit_button",
@@ -87,4 +89,81 @@ class NucleonCreatorScreen(Screen):
def on_button_pressed(self, event) -> None:
event.stop()
if event.button.id == "submit_button":
pass
# 获取输入值
name_input = self.query_one("#name_input")
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
# 验证
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")
return
# selected 是描述字符串,格式如 "描述 (filename.toml)"
# 提取文件名
import re
match = re.search(r'\(([^)]+)\)$', selected)
if not match:
self.notify("模板选择格式无效", severity="error")
return
template_filename = match.group(1)
template_path = template_dir / template_filename
if not template_path.exists():
self.notify(f"模板文件不存在: {template_filename}", severity="error")
return
# 加载模板
try:
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", {})
if author:
attribution["author"] = author
if desc:
attribution["desc"] = desc
attribution["name"] = name
# 可选: 设置版本
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:
toml.dump(template_data, f)
except Exception as e:
self.notify(f"保存单元集失败: {e}", severity="error")
return
self.notify(f"单元集 '{name}' 创建成功")
self.app.pop_screen()

View File

@@ -8,8 +8,19 @@ import heurams.kernel.puzzles as pz
from .base_puzzle_widget import BasePuzzleWidget
import copy
import random
from textual.containers import Container
from textual.message import Message
from heurams.services.logger import get_logger
from typing import TypedDict
logger = get_logger(__name__)
class Setting(TypedDict):
__origin__: str
__hint__: str
text: str
delimiter: str
min_denominator: str
class ClozePuzzle(BasePuzzleWidget):
@@ -36,52 +47,37 @@ class ClozePuzzle(BasePuzzleWidget):
self.inputlist = list()
self.hashtable = {}
self.alia = alia
self._work()
self._load()
self.hashmap = dict()
def _work(self):
cfg = self.atom.registry["orbital"]["puzzles"][self.alia]
def _load(self):
setting = self.atom.registry["orbital"]["puzzles"][self.alia]
self.puzzle = pz.ClozePuzzle(
text=cfg["content"],
delimiter=cfg["delimiter"],
min_denominator=cfg["min_denominator"],
text=setting["text"],
delimiter=setting["delimiter"],
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)
class RatingChanged(Message):
def __init__(self, atom: pt.Atom, rating: int, is_correct: bool) -> None:
self.atom = atom
self.rating = rating # 评分
self.is_correct = is_correct # 是否正确
super().__init__()
class InputChanged(Message):
"""输入变化消息"""
def __init__(self, current_input: list, max_length: int) -> None:
self.current_input = current_input # 当前输入
self.max_length = max_length # 最大长度
self.progress = len(current_input) / max_length # 进度
super().__init__()
def compose(self):
yield Label(self.puzzle.wording, id="sentence")
yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
for i in self.ans:
self.hashtable[str(hash(i))] = i
yield Button(i, id=f"{hash(i)}")
# 渲染当前问题的选项
with Container(id="btn-container"):
for i in self.ans:
self.hashmap[str(hash(i))] = i
btnid = f"sel000-{hash(i)}"
logger.debug(f"建立按钮 {btnid}")
yield Button(i, id=f"{btnid}")
yield Button("退格", id="delete")
def update_preview(self):
def update_display(self):
preview = self.query_one("#inputpreview")
preview.update(f"当前输入: {self.inputlist}") # type: ignore
self.post_message(
self.InputChanged(
current_input=self.inputlist.copy(), max_length=len(self.puzzle.answer)
)
)
def on_button_pressed(self, event: Button.Pressed) -> None:
button_id = event.button.id
@@ -89,22 +85,18 @@ class ClozePuzzle(BasePuzzleWidget):
if button_id == "delete":
if len(self.inputlist) > 0:
self.inputlist.pop()
self.update_preview()
self.update_display()
else:
answer_text = self.hashtable[button_id]
answer_text = self.hashmap[button_id[7:]] # type: ignore
self.inputlist.append(answer_text)
self.update_preview()
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.post_message(
self.RatingChanged(
atom=self.atom, rating=rating, is_correct=is_correct
)
)
self.screen.rating = rating # type: ignore
if not is_correct:
self.inputlist = []
self.update_preview()
self.update_display()

View File

@@ -79,7 +79,7 @@ class MCQPuzzle(BasePuzzleWidget):
yield Button("退格", id="delete")
def update_display(self):
def update_display(self, error = 0):
# 更新预览标签
preview = self.query_one("#inputpreview")
preview.update(f"当前输入: {self.inputlist}") # type: ignore

View File

@@ -74,12 +74,17 @@ class Atom:
# eval 环境设置
def eval_with_env(s: str):
# 初始化默认值
nucleon = self.registry["nucleon"]
default = {}
metadata = {}
try:
nucleon = self.registry["nucleon"]
default = config_var.get()["puzzles"]
metadata = nucleon.metadata
except:
ret = "尚未链接对象"
except Exception:
# 如果无法获取配置或元数据,使用空字典
logger.debug("无法获取配置或元数据,使用空字典")
pass
try:
eval_value = eval(s)
if isinstance(eval_value, (list, dict)):
@@ -110,8 +115,24 @@ class Atom:
return modifier(data[5:])
return data
traverse(self.registry["nucleon"], eval_with_env)
traverse(self.registry["orbital"], eval_with_env)
# 如果 nucleon 存在且有 do_eval 方法,调用它
nucleon = self.registry["nucleon"]
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'):
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):
traverse(orbital, eval_with_env)
logger.debug("orbital eval 完成")
logger.debug("Atom.do_eval 完成")
def persist(self, key):