改进
This commit is contained in:
22
src/heurams/interface/main.py
Normal file
22
src/heurams/interface/main.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Button, Header, Label, Footer
|
||||
|
||||
class HeurAMSApp(App):
|
||||
#CSS_PATH = "question02.tcss"
|
||||
TITLE = "潜进"
|
||||
SUB_TITLE = "启发式辅助记忆调度器"
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock = True)
|
||||
|
||||
yield Footer(show_command_palette = True)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
self.exit(event.button.id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = HeurAMSApp()
|
||||
app.run()
|
||||
25
src/heurams/interface/widgets/fileexpr.py
Normal file
25
src/heurams/interface/widgets/fileexpr.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from textual.widget import Widget
|
||||
|
||||
class FileSelector(Widget):
|
||||
def __init__(self, *children: Widget, name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
|
||||
super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
|
||||
def a(self):
|
||||
file_list_widget = self.query_one("#file-list", ListView)
|
||||
nucleon_path = pathlib.Path("./nucleon")
|
||||
nucleon_files = sorted(
|
||||
[f for f in nucleon_path.iterdir() if f.suffix == ".toml"],
|
||||
key=lambda f: Glimpse(pt.NucleonUnion(f)).next_date,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
if nucleon_files:
|
||||
for file in nucleon_files:
|
||||
text = self.item_desc_generator(pathlib.Path(file))
|
||||
file_list_widget.append(ListItem(
|
||||
Label(text[0] + '\n' + text[1]),
|
||||
))
|
||||
else:
|
||||
file_list_widget.append(
|
||||
ListItem(Static("在 ./nucleon/ 中未找到任何内容源数据文件.\n请放置文件后重启应用.\n或者新建空的单元集."))
|
||||
)
|
||||
file_list_widget.disabled = True
|
||||
@@ -0,0 +1,9 @@
|
||||
from .sm2 import SM2Algorithm
|
||||
|
||||
__all__ = [
|
||||
'SM2Algorithm',
|
||||
]
|
||||
|
||||
registry = {
|
||||
"SM-2": SM2Algorithm,
|
||||
}
|
||||
@@ -1,66 +1,72 @@
|
||||
import heurams.services.timer as timer
|
||||
from typing import TypedDict
|
||||
|
||||
algo_name = "SM-2"
|
||||
class SM2Algorithm:
|
||||
algo_name = "SM-2"
|
||||
|
||||
class AlgodataDict(TypedDict):
|
||||
efactor: float
|
||||
real_rept: int
|
||||
rept: int
|
||||
interval: int
|
||||
last_date: int
|
||||
next_date: int
|
||||
is_activated: int
|
||||
last_modify: float
|
||||
class AlgodataDict(TypedDict):
|
||||
efactor: float
|
||||
real_rept: int
|
||||
rept: int
|
||||
interval: int
|
||||
last_date: int
|
||||
next_date: int
|
||||
is_activated: int
|
||||
last_modify: float
|
||||
|
||||
defaults = {
|
||||
'efactor': 2.5,
|
||||
'real_rept': 0,
|
||||
'rept': 0,
|
||||
'interval': 0,
|
||||
'last_date': 0,
|
||||
'next_date': 0,
|
||||
'is_activated': 0,
|
||||
'last_modify': timer.get_timestamp()
|
||||
}
|
||||
defaults = {
|
||||
'efactor': 2.5,
|
||||
'real_rept': 0,
|
||||
'rept': 0,
|
||||
'interval': 0,
|
||||
'last_date': 0,
|
||||
'next_date': 0,
|
||||
'is_activated': 0,
|
||||
'last_modify': timer.get_timestamp()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def revisor(cls, algodata: dict, feedback: int = 5, is_new_activation: bool = False):
|
||||
"""SM-2 算法迭代决策机制实现
|
||||
根据 quality(0 ~ 5) 进行参数迭代最佳间隔
|
||||
quality 由主程序评估
|
||||
|
||||
def revisor(algodata: dict, feedback: int = 5, is_new_activation: bool = False):
|
||||
"""SM-2 算法迭代决策机制实现
|
||||
根据 quality(0 ~ 5) 进行参数迭代最佳间隔
|
||||
quality 由主程序评估
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数
|
||||
"""
|
||||
if feedback == -1:
|
||||
return
|
||||
|
||||
Args:
|
||||
quality (int): 记忆保留率量化参数
|
||||
"""
|
||||
if feedback == -1:
|
||||
return
|
||||
|
||||
algodata[algo_name]['efactor'] = algodata[algo_name]['efactor'] + (
|
||||
0.1 - (5 - feedback) * (0.08 + (5 - feedback) * 0.02)
|
||||
)
|
||||
algodata[algo_name]['efactor'] = max(1.3, algodata[algo_name]['efactor'])
|
||||
|
||||
if feedback < 3:
|
||||
algodata[algo_name]['rept'] = 0
|
||||
algodata[algo_name]['interval'] = 0
|
||||
else:
|
||||
algodata[algo_name]['rept'] += 1
|
||||
|
||||
algodata[algo_name]['real_rept'] += 1
|
||||
|
||||
if is_new_activation:
|
||||
algodata[algo_name]['rept'] = 0
|
||||
algodata[algo_name]['efactor'] = 2.5
|
||||
|
||||
if algodata[algo_name]['rept'] == 0:
|
||||
algodata[algo_name]['interval'] = 1
|
||||
elif algodata[algo_name]['rept'] == 1:
|
||||
algodata[algo_name]['interval'] = 6
|
||||
else:
|
||||
algodata[algo_name]['interval'] = round(
|
||||
algodata[algo_name]['interval'] * algodata[algo_name]['efactor']
|
||||
algodata[cls.algo_name]['efactor'] = algodata[cls.algo_name]['efactor'] + (
|
||||
0.1 - (5 - feedback) * (0.08 + (5 - feedback) * 0.02)
|
||||
)
|
||||
algodata[cls.algo_name]['efactor'] = max(1.3, algodata[cls.algo_name]['efactor'])
|
||||
|
||||
algodata[algo_name]['last_date'] = timer.get_daystamp()
|
||||
algodata[algo_name]['next_date'] = timer.get_daystamp() + algodata[algo_name]['interval']
|
||||
algodata[algo_name]['last_modify'] = timer.get_timestamp()
|
||||
if feedback < 3:
|
||||
algodata[cls.algo_name]['rept'] = 0
|
||||
algodata[cls.algo_name]['interval'] = 0
|
||||
else:
|
||||
algodata[cls.algo_name]['rept'] += 1
|
||||
|
||||
algodata[cls.algo_name]['real_rept'] += 1
|
||||
|
||||
if is_new_activation:
|
||||
algodata[cls.algo_name]['rept'] = 0
|
||||
algodata[cls.algo_name]['efactor'] = 2.5
|
||||
|
||||
if algodata[cls.algo_name]['rept'] == 0:
|
||||
algodata[cls.algo_name]['interval'] = 1
|
||||
elif algodata[cls.algo_name]['rept'] == 1:
|
||||
algodata[cls.algo_name]['interval'] = 6
|
||||
else:
|
||||
algodata[cls.algo_name]['interval'] = round(
|
||||
algodata[cls.algo_name]['interval'] * algodata[cls.algo_name]['efactor']
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
@classmethod
|
||||
def is_due(cls, algodata):
|
||||
return (algodata[cls.algo_name]['next_date'] <= timer.get_daystamp())
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
Puzzle 模块 - 谜题生成系统
|
||||
|
||||
提供多种类型的谜题生成器,支持从字符串、字典等数据源导入题目
|
||||
"""
|
||||
|
||||
from .base import BasePuzzle
|
||||
from .cloze import ClozePuzzle
|
||||
from .mcq import MCQPuzzle
|
||||
from .factory import PuzzleFactory
|
||||
from .loader import PuzzleLoader
|
||||
|
||||
__all__ = [
|
||||
'BasePuzzle',
|
||||
'ClozePuzzle',
|
||||
'MCQPuzzle',
|
||||
'PuzzleFactory',
|
||||
'PuzzleLoader',
|
||||
]
|
||||
77
src/heurams/kernel/puzzles/factory.py
Normal file
77
src/heurams/kernel/puzzles/factory.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
谜题工厂类 - 统一创建各种类型的谜题
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Union, Any
|
||||
from .base import BasePuzzle
|
||||
from .cloze import ClozePuzzle
|
||||
from .mcq import MCQPuzzle
|
||||
|
||||
class PuzzleFactory:
|
||||
"""谜题工厂,根据配置创建不同类型的谜题"""
|
||||
|
||||
@staticmethod
|
||||
def create_cloze(text: str, min_denominator: int = 7) -> ClozePuzzle:
|
||||
"""
|
||||
创建填空题谜题
|
||||
|
||||
Args:
|
||||
text: 原始字符串,使用 "/" 分割句子
|
||||
min_denominator: 最小概率倒数,控制填空数量
|
||||
|
||||
Returns:
|
||||
ClozePuzzle: 填空题实例
|
||||
"""
|
||||
return ClozePuzzle(text, min_denominator)
|
||||
|
||||
@staticmethod
|
||||
def create_mcq(
|
||||
mapping: Dict[str, str],
|
||||
jammer: List[str],
|
||||
max_riddles_num: int = 2,
|
||||
prefix: str = ""
|
||||
) -> MCQPuzzle:
|
||||
"""
|
||||
创建选择题谜题
|
||||
|
||||
Args:
|
||||
mapping: 题目-答案映射字典
|
||||
jammer: 干扰项列表
|
||||
max_riddles_num: 最大题目数量
|
||||
prefix: 题目前缀
|
||||
|
||||
Returns:
|
||||
MCQPuzzle: 选择题实例
|
||||
"""
|
||||
return MCQPuzzle(mapping, jammer, max_riddles_num, prefix)
|
||||
|
||||
@staticmethod
|
||||
def from_config(config: Dict[str, Any]) -> BasePuzzle:
|
||||
"""
|
||||
根据配置字典创建谜题
|
||||
|
||||
Args:
|
||||
config: 配置字典,包含谜题类型和参数
|
||||
|
||||
Returns:
|
||||
BasePuzzle: 谜题实例
|
||||
|
||||
Raises:
|
||||
ValueError: 当配置无效时抛出
|
||||
"""
|
||||
puzzle_type = config.get('type')
|
||||
|
||||
if puzzle_type == 'cloze':
|
||||
return PuzzleFactory.create_cloze(
|
||||
text=config['text'],
|
||||
min_denominator=config.get('min_denominator', 7)
|
||||
)
|
||||
elif puzzle_type == 'mcq':
|
||||
return PuzzleFactory.create_mcq(
|
||||
mapping=config['mapping'],
|
||||
jammer=config.get('jammer', []),
|
||||
max_riddles_num=config.get('max_riddles_num', 2),
|
||||
prefix=config.get('prefix', '')
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"未知的谜题类型: {puzzle_type}")
|
||||
154
src/heurams/kernel/puzzles/loader.py
Normal file
154
src/heurams/kernel/puzzles/loader.py
Normal file
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
谜题加载器 - 从多种数据源加载谜题配置
|
||||
"""
|
||||
|
||||
import json
|
||||
import yaml
|
||||
import re
|
||||
from typing import Dict, List, Union, Any
|
||||
from pathlib import Path
|
||||
from .factory import PuzzleFactory
|
||||
|
||||
|
||||
class PuzzleLoader:
|
||||
"""谜题加载器,支持从多种格式加载谜题配置"""
|
||||
|
||||
@staticmethod
|
||||
def from_json(file_path: Union[str, Path]) -> Dict[str, Any]:
|
||||
"""
|
||||
从JSON文件加载谜题配置
|
||||
|
||||
Args:
|
||||
file_path: JSON文件路径
|
||||
|
||||
Returns:
|
||||
Dict: 谜题配置字典
|
||||
"""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
@staticmethod
|
||||
def from_yaml(file_path: Union[str, Path]) -> Dict[str, Any]:
|
||||
"""
|
||||
从YAML文件加载谜题配置
|
||||
|
||||
Args:
|
||||
file_path: YAML文件路径
|
||||
|
||||
Returns:
|
||||
Dict: 谜题配置字典
|
||||
"""
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
@staticmethod
|
||||
def from_text(text: str, puzzle_type: str = 'cloze', **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
从纯文本字符串创建谜题配置
|
||||
|
||||
Args:
|
||||
text: 原始文本
|
||||
puzzle_type: 谜题类型 ('cloze' 或 'mcq')
|
||||
**kwargs: 其他参数
|
||||
|
||||
Returns:
|
||||
Dict: 谜题配置字典
|
||||
"""
|
||||
config = {'type': puzzle_type}
|
||||
|
||||
if puzzle_type == 'cloze':
|
||||
config['text'] = text
|
||||
config.update(kwargs)
|
||||
elif puzzle_type == 'mcq':
|
||||
# 从文本解析选择题配置
|
||||
config.update(PuzzleLoader._parse_mcq_from_text(text, **kwargs))
|
||||
else:
|
||||
raise ValueError(f"不支持的谜题类型: {puzzle_type}")
|
||||
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def _parse_mcq_from_text(text: str, **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
从文本解析选择题配置
|
||||
|
||||
Args:
|
||||
text: 原始文本
|
||||
**kwargs: 其他参数
|
||||
|
||||
Returns:
|
||||
Dict: 选择题配置
|
||||
"""
|
||||
# 简单的解析逻辑:每行一个题目,格式为 "题目:答案"
|
||||
mapping = {}
|
||||
lines = text.strip().split('\n')
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if ':' in line:
|
||||
question, answer = line.split(':', 1)
|
||||
mapping[question.strip()] = answer.strip()
|
||||
|
||||
return {
|
||||
'mapping': mapping,
|
||||
'jammer': kwargs.get('jammer', []),
|
||||
'max_riddles_num': kwargs.get('max_riddles_num', 2),
|
||||
'prefix': kwargs.get('prefix', '')
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_csv(file_path: Union[str, Path], **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
从CSV文件加载选择题配置
|
||||
|
||||
Args:
|
||||
file_path: CSV文件路径
|
||||
**kwargs: 其他参数
|
||||
|
||||
Returns:
|
||||
Dict: 选择题配置
|
||||
"""
|
||||
import csv
|
||||
mapping = {}
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
if len(row) >= 2:
|
||||
mapping[row[0].strip()] = row[1].strip()
|
||||
|
||||
return {
|
||||
'type': 'mcq',
|
||||
'mapping': mapping,
|
||||
'jammer': kwargs.get('jammer', []),
|
||||
'max_riddles_num': kwargs.get('max_riddles_num', 2),
|
||||
'prefix': kwargs.get('prefix', '')
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def load_puzzles_from_directory(directory: Union[str, Path]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
从目录批量加载谜题配置
|
||||
|
||||
Args:
|
||||
directory: 目录路径
|
||||
|
||||
Returns:
|
||||
List[Dict]: 谜题配置列表
|
||||
"""
|
||||
puzzles = []
|
||||
dir_path = Path(directory)
|
||||
|
||||
# 加载JSON文件
|
||||
for json_file in dir_path.glob('*.json'):
|
||||
puzzles.append(PuzzleLoader.from_json(json_file))
|
||||
|
||||
# 加载YAML文件
|
||||
for yaml_file in dir_path.glob('*.yaml'):
|
||||
puzzles.append(PuzzleLoader.from_yaml(yaml_file))
|
||||
|
||||
# 加载CSV文件
|
||||
for csv_file in dir_path.glob('*.csv'):
|
||||
puzzles.append(PuzzleLoader.from_csv(csv_file))
|
||||
|
||||
return puzzles
|
||||
Reference in New Issue
Block a user