fix: 改进

This commit is contained in:
2025-12-16 00:26:58 +08:00
parent ec5c8eb191
commit 5e4b0508eb
6 changed files with 70 additions and 62 deletions

View File

@@ -1,23 +1,22 @@
# 贡献指南 # 贡献指南
欢迎为潜进 (HeurAMS) 项目做出贡献!本项目是一个开源项目,我们鼓励社区成员参与改进。 欢迎为此项目做出贡献!
本项目是一个开源项目, 我们鼓励社区成员参与改进.
## 开发流程 ## 开发流程
1. **讨论功能**:在开始编写代码之前,建议先通过 Issue 讨论新功能或修复。 1. **分支划分**
2. **分支策略**
- `main` 分支:稳定版本 - `main` 分支:稳定版本
- `develop` 分支:开发版本 - `develop` 分支:开发版本
- 功能分支:从 `develop` 分支创建,命名格式为 `feature/描述``fix/描述` - 功能分支:从 `develop` 分支创建,命名格式为 `feature/描述``fix/描述`
3. **代码风格** 2. **代码风格**
- 使用 Black 格式化代码(如果配置) - 使用 Black 格式化代码
- 遵循 PEP 8 规范 - 遵循 PEP 8 规范
- 使用类型注解 - 添加适当的文档字符串
- 添加适当的文档字符串(中英文均可) 3. **提交消息**
4. **提交消息**
- 使用中文或英文撰写清晰的提交消息 - 使用中文或英文撰写清晰的提交消息
- 格式:`类型: 描述`,例如 `fix: 修复登录错误``feat: 添加新算法` - 格式:`类型: 描述`,例如 `fix: 修复登录错误``feat: 添加新算法`
5. **测试** 4. **测试**
- 为新功能添加单元测试 - 为新功能添加单元测试
- 确保所有测试通过 - 确保所有测试通过
- 运行 `pytest` 检查 - 运行 `pytest` 检查
@@ -40,29 +39,6 @@ pip install -r requirements.txt
pip install -e . pip install -e .
``` ```
## 提交更改
1. 确保代码通过测试:
```bash
python -m pytest tests/
```
2. 提交更改:
```bash
git add .
git commit -m "类型: 描述"
git push origin 分支名
```
3. 创建 Pull Request
- 在 GitHub 上创建 Pull Request将你的分支合并到 `develop`
- 描述更改内容和动机
- 链接相关 Issue如果有
## 行为准则
请保持友好、尊重的交流氛围。我们遵循 [贡献者公约](https://www.contributor-covenant.org/)。
## 许可证 ## 许可证
贡献者同意其贡献将在 AGPL-3.0 许可证下发布。 贡献者同意其贡献将在 AGPL-3.0 许可证下发布。

View File

@@ -66,7 +66,7 @@
### 启动应用 ### 启动应用
```bash ```bash
# 从项目根目录运行 # 在任一目录(建议是空目录或者包根目录, 将被用作存放数据)下运行
python -m heurams.interface python -m heurams.interface
``` ```

View File

@@ -23,7 +23,7 @@ logger = get_logger(__name__)
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", "朗读"),
] ]
@@ -46,6 +46,8 @@ class MemScreen(Screen):
self.procession: Procession = self.phaser.current_procession() # type: ignore self.procession: Procession = self.phaser.current_procession() # type: ignore
# logger.debug(self.phaser.state) # logger.debug(self.phaser.state)
# self.procession.forward(1) # self.procession.forward(1)
for i in atoms:
i.do_eval()
def on_mount(self): def on_mount(self):
self.load_puzzle() self.load_puzzle()
@@ -53,11 +55,10 @@ class MemScreen(Screen):
def puzzle_widget(self): def puzzle_widget(self):
try: try:
# logger.debug(self.phaser.state) logger.debug(self.phaser.state)
#logger.debug(self.procession.cursor) logger.debug(self.procession.cursor)
#logger.debug(self.procession.current_atom) logger.debug(self.procession.current_atom)
self.fission = Fission(self.procession.current_atom, self.phaser.state) self.fission = Fission(self.procession.current_atom, self.phaser.state)
# logger.debug(1)
puzzle_debug = next(self.fission.generate()) puzzle_debug = next(self.fission.generate())
#logger.debug(puzzle_debug) #logger.debug(puzzle_debug)
return shim.puzzle2widget[puzzle_debug["puzzle"]]( return shim.puzzle2widget[puzzle_debug["puzzle"]](
@@ -71,21 +72,33 @@ class MemScreen(Screen):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Header(show_clock=True) yield Header(show_clock=True)
with ScrollableContainer(): with ScrollableContainer():
with Center(): yield Label(self._get_progress_text(), id="progress")
yield Static(
f"当前进度: {self.procession.process()}/{self.procession.total_length()}"
)
# self.mount(self.current_widget()) # type: ignore # self.mount(self.current_widget()) # type: ignore
yield ScrollableContainer(id="puzzle-container") yield ScrollableContainer(id="puzzle-container")
# yield Button("重新学习此单元", id="re-recognize", variant="warning") # yield Button("重新学习此单元", id="re-recognize", variant="warning")
yield Footer() yield Footer()
def _get_progress_text(self):
return f"当前进度: {self.procession.process() + 1}/{self.procession.total_length()}"
def update_display(self):
progress_widget = self.query_one("#progress")
progress_widget.update(self._get_progress_text()) # type: ignore
def load_puzzle(self): def load_puzzle(self):
container = self.query_one("#puzzle-container") container = self.query_one("#puzzle-container")
for i in container.children: for i in container.children:
i.remove() i.remove()
container.mount(self.puzzle_widget()) container.mount(self.puzzle_widget())
def load_finished_widget(self):
container = self.query_one("#puzzle-container")
for i in container.children:
i.remove()
from heurams.interface.widgets.finished import Finished
container.mount(Finished())
def on_button_pressed(self, event): def on_button_pressed(self, event):
event.stop() event.stop()
@@ -98,7 +111,13 @@ class MemScreen(Screen):
ret = self.procession.forward(1) ret = self.procession.forward(1)
if ret == 0: if ret == 0:
self.procession = self.phaser.current_procession() # type: ignore self.procession = self.phaser.current_procession() # type: ignore
if self.procession == 0:
logger.debug(f"记忆进程结束")
self.load_finished_widget()
return
else:
logger.debug(f"建立新队列 {self.procession.phase}") logger.debug(f"建立新队列 {self.procession.phase}")
self.update_display()
self.load_puzzle() self.load_puzzle()
def action_play_voice(self): def action_play_voice(self):

View File

@@ -3,15 +3,16 @@ from textual.widgets import (
Label, Label,
Button, Button,
) )
from textual.containers import ScrollableContainer from textual.containers import ScrollableContainer, Container
from textual.widget import Widget from textual.widget import Widget
import heurams.kernel.particles as pt import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz import heurams.kernel.puzzles as pz
from .base_puzzle_widget import BasePuzzleWidget from .base_puzzle_widget import BasePuzzleWidget
from typing import TypedDict from typing import TypedDict
from bidict import bidict
from heurams.services.hasher import hash from heurams.services.hasher import hash
from heurams.services.logger import get_logger
logger = get_logger(__name__)
class Setting(TypedDict): class Setting(TypedDict):
__origin__: str __origin__: str
@@ -46,7 +47,8 @@ class MCQPuzzle(BasePuzzleWidget):
) )
self.inputlist = [] self.inputlist = []
self.alia = alia self.alia = alia
self.hashmap = bidict() self.hashmap = dict()
self.cursor = 0
self._load() self._load()
def _load(self): def _load(self):
@@ -57,18 +59,23 @@ class MCQPuzzle(BasePuzzleWidget):
self.puzzle.refresh() self.puzzle.refresh()
def compose(self): def compose(self):
self.atom.registry["nucleon"].do_eval()
setting: Setting = self.atom.registry["nucleon"].metadata["orbital"]["puzzles"][ setting: Setting = self.atom.registry["nucleon"].metadata["orbital"]["puzzles"][
self.alia self.alia
] ]
logger.debug(f"Puzzle Setting: {setting}")
yield Label(setting["primary"], id="sentence") yield Label(setting["primary"], id="sentence")
yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle") yield Label(self.puzzle.wording[len(self.inputlist)], id="puzzle")
yield Label(f"当前输入: {self.inputlist}", id="inputpreview") yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
# 渲染当前问题的选项 # 渲染当前问题的选项
current_options = self.puzzle.options[len(self.inputlist)] current_options = self.puzzle.options[len(self.inputlist)]
with Container(id="btn-container"):
for i in current_options: for i in current_options:
self.hashmap[str(hash(i))] = i self.hashmap[str(hash(i))] = i
yield Button(i, id=f"select-{hash(i)}") btnid = f"sel{str(self.cursor).zfill(3)}-{hash(i)}"
logger.debug(f"建立按钮 {btnid}")
yield Button(i, id=f"{btnid}")
yield Button("退格", id="delete") yield Button("退格", id="delete")
@@ -76,7 +83,7 @@ class MCQPuzzle(BasePuzzleWidget):
# 更新预览标签 # 更新预览标签
preview = self.query_one("#inputpreview") preview = self.query_one("#inputpreview")
preview.update(f"当前输入: {self.inputlist}") # type: ignore preview.update(f"当前输入: {self.inputlist}") # type: ignore
logger.debug("已经更新预览标签")
# 更新问题标签 # 更新问题标签
puzzle_label = self.query_one("#puzzle") puzzle_label = self.query_one("#puzzle")
current_question_index = len(self.inputlist) current_question_index = len(self.inputlist)
@@ -95,11 +102,11 @@ class MCQPuzzle(BasePuzzleWidget):
self.refresh_buttons() self.refresh_buttons()
self.update_display() self.update_display()
elif button_id.startswith("select"): # type: ignore elif button_id.startswith("sel"): # type: ignore
# 选项选择处理 # 选项选择处理
answer_text = self.hashmap[button_id[7:]] # type: ignore answer_text = self.hashmap[button_id[7:]] # type: ignore
self.inputlist.append(answer_text) self.inputlist.append(answer_text)
logger.debug(f"{self.inputlist}")
# 检查是否完成所有题目 # 检查是否完成所有题目
if len(self.inputlist) >= len(self.puzzle.answer): if len(self.inputlist) >= len(self.puzzle.answer):
is_correct = self.inputlist == self.puzzle.answer is_correct = self.inputlist == self.puzzle.answer
@@ -120,22 +127,26 @@ class MCQPuzzle(BasePuzzleWidget):
def refresh_buttons(self): def refresh_buttons(self):
"""刷新按钮显示(用于题目切换)""" """刷新按钮显示(用于题目切换)"""
# 移除所有选项按钮 # 移除所有选项按钮
logger.debug("刷新按钮")
self.cursor += 1
container = self.query_one("#btn-container")
buttons_to_remove = [ buttons_to_remove = [
child child
for child in self.children for child in container.children
if hasattr(child, "id") and child.id and child.id.startswith("select") if hasattr(child, "id") and child.id and child.id.startswith("sel")
] ]
for button in buttons_to_remove: for button in buttons_to_remove:
self.remove_child(button) # type: ignore logger.info(button)
container.remove_children("#"+button.id) # type: ignore
# 添加当前题目的选项按钮 # 添加当前题目的选项按钮
current_question_index = len(self.inputlist) current_question_index = len(self.inputlist)
if current_question_index < len(self.puzzle.options): if current_question_index < len(self.puzzle.options):
current_options = self.puzzle.options[current_question_index] current_options = self.puzzle.options[current_question_index]
for option in current_options: for option in current_options:
button_id = f"select-{hash(option)}" button_id = f"sel{str(self.cursor).zfill(3)}-{hash(option)}"
if button_id not in self.hashmap: if button_id not in self.hashmap:
self.hashmap[button_id] = option self.hashmap[button_id] = option
new_button = Button(option, id=button_id) new_button = Button(option, id=button_id)
self.mount(new_button) container.mount(new_button)

View File

@@ -64,7 +64,9 @@ class MCQPuzzle(BasePuzzle):
# 确保至少有4个干扰项 # 确保至少有4个干扰项
while len(self.jammer) < 4: while len(self.jammer) < 4:
self.jammer.append(" ") self.jammer.append(" " * (4 - len(self.jammer)))
unique_jammers = set(jammer + list(self.mapping.values()))
def _reset_puzzle_state(self) -> None: def _reset_puzzle_state(self) -> None:
"""重置谜题状态为初始值 """重置谜题状态为初始值
@@ -84,7 +86,7 @@ class MCQPuzzle(BasePuzzle):
Raises: Raises:
ValueError: 当mapping为空时不会抛出异常, 但会设置空谜题状态 ValueError: 当mapping为空时不会抛出异常, 但会设置空谜题状态
""" """
logger.debug("MCQPuzzle.refresh 开始mapping size=%d", len(self.mapping)) logger.debug("MCQPuzzle.refresh 开始, mapping size=%d", len(self.mapping))
if not self.mapping: if not self.mapping:
self._set_empty_puzzle() self._set_empty_puzzle()
return return

View File

@@ -6,14 +6,14 @@ logger = get_logger(__name__)
def get_md5(text): def get_md5(text):
logger.debug("计算MD5哈希输入长度: %d", len(text)) logger.debug(f"计算哈希, 输入`{text}`")
result = hashlib.md5(text.encode("utf-8")).hexdigest() result = hashlib.md5(text.encode("utf-8")).hexdigest()
logger.debug("MD5哈希结果: %s...", result[:8]) logger.debug("哈希结果: %s...", result[:8])
return result return result
def hash(text): def hash(text):
logger.debug("计算哈希,输入长度: %d", len(text)) logger.debug(f"计算哈希, 输入`{text}`")
result = hashlib.md5(text.encode("utf-8")).hexdigest() result = hashlib.md5(text.encode("utf-8")).hexdigest()
logger.debug("哈希结果: %s...", result[:8]) logger.debug("哈希结果: %s...", result[:8])
return result return result