style: 格式化代码

This commit is contained in:
2026-05-07 19:48:07 +08:00
parent fcda88488b
commit 048e74ad7f
19 changed files with 164 additions and 132 deletions

View File

@@ -11,4 +11,4 @@ for _finder, _name, _ispkg in pkgutil.iter_modules(__path__):
continue
importlib.import_module(f".{_name}", __package__)
algorithms = BaseAlgorithm.get_registry()
algorithms = BaseAlgorithm.get_registry()

View File

@@ -7,6 +7,7 @@ logger = get_logger(__name__)
_registry: dict[str, type["BaseAlgorithm"]] = {}
class BaseAlgorithm:
algo_name = "BaseAlgorithm"
desc = "算法基类"

View File

@@ -3,7 +3,7 @@ FSRS 算法模块 — 基于 py-fsrs 的现代间隔重复调度器
基于: https://github.com/open-spaced-repetition/py-fsrs
"""
import json
import os
import pathlib
from datetime import datetime, timezone, timedelta
@@ -20,9 +20,10 @@ from .base import BaseAlgorithm
logger = get_logger(__name__)
# 全局 Scheduler 状态文件路径
_SCHEDULER_STATE_FILE = pathlib.Path(
config_var.get()["global"]["paths"]["misc"]
) / "fsrs_scheduler_state.json"
_SCHEDULER_STATE_FILE = (
pathlib.Path(config_var.get()["global"]["paths"]["misc"])
/ "fsrs_scheduler_state.json"
)
def _get_global_scheduler():
@@ -78,10 +79,10 @@ class FSRSAlgorithm(BaseAlgorithm):
class AlgodataDict(TypedDict):
# FSRS 特有字段
fsrs_state: int # State 枚举值: 1=Learning, 2=Review, 3=Relearning
fsrs_step: int # 当前学习步进索引, -1 表示 None (Review 状态)
fsrs_state: int # State 枚举值: 1=Learning, 2=Review, 3=Relearning
fsrs_step: int # 当前学习步进索引, -1 表示 None (Review 状态)
fsrs_stability: float # 稳定性(秒), 0.0 表示尚未计算
fsrs_difficulty: float # 难度 [1.0, 10.0], 0.0 表示尚未计算
fsrs_difficulty: float # 难度 [1.0, 10.0], 0.0 表示尚未计算
# 标准 BaseAlgorithm 兼容字段
real_rept: int
rept: int
@@ -92,7 +93,7 @@ class FSRSAlgorithm(BaseAlgorithm):
last_modify: float
defaults = {
"fsrs_state": 1, # State.Learning
"fsrs_state": 1, # State.Learning
"fsrs_step": 0,
"fsrs_stability": 0.0,
"fsrs_difficulty": 0.0,
@@ -136,9 +137,7 @@ class FSRSAlgorithm(BaseAlgorithm):
# last_review
last_date = data.get("last_date", 0)
card.last_review = (
_daystamp_to_datetime(last_date) if last_date > 0 else None
)
card.last_review = _daystamp_to_datetime(last_date) if last_date > 0 else None
return card
@@ -160,9 +159,7 @@ class FSRSAlgorithm(BaseAlgorithm):
if card.last_review
else data.get("last_date", 0)
)
data["next_date"] = (
_datetime_to_daystamp(card.due) if card.due else 0
)
data["next_date"] = _datetime_to_daystamp(card.due) if card.due else 0
data["interval"] = max(0, data["next_date"] - data["last_date"])
data["last_modify"] = get_timestamp()
return algodata
@@ -209,8 +206,7 @@ class FSRSAlgorithm(BaseAlgorithm):
algodata[cls.algo_name]["rept"] += 1
logger.debug(
"FSRS.revisor 完成: stability=%s, difficulty=%s, state=%s, "
"next_date=%d",
"FSRS.revisor 完成: stability=%s, difficulty=%s, state=%s, " "next_date=%d",
card.stability,
card.difficulty,
card.state,

View File

@@ -4,6 +4,7 @@ SM-15M — 基于 sm.js 的间隔重复算法
基于: https://github.com/slaypni/sm.js
原始 CoffeeScript (c) 2014 Kazuaki Tanida, MIT 许可证
"""
import datetime
import json
import math
@@ -19,7 +20,6 @@ from heurams.services.timer import (
get_timestamp_ms,
daystamp_to_datetime,
datetime_to_daystamp,
get_now_datetime,
)
from .base import BaseAlgorithm
@@ -111,7 +111,7 @@ def power_law_model(a, b):
"""y = a * x^b"""
def y_func(x):
return a * (x ** b)
return a * (x**b)
def x_func(y):
if a == 0 or b == 0:
@@ -134,7 +134,7 @@ def fixed_point_power_law_regression(points, fixed_point):
sum_sqX = sum(x * x for x in X)
b = sumXY / sum_sqX if sum_sqX else 0
return power_law_model(q / (p ** b), b)
return power_law_model(q / (p**b), b)
# ============================================================================
@@ -161,7 +161,7 @@ class FI_G:
def _register_point(self, fi, grade):
self.points.append([fi, grade + self.GRADE_OFFSET])
if len(self.points) > self.MAX_POINTS_COUNT:
self.points = self.points[-self.MAX_POINTS_COUNT:]
self.points = self.points[-self.MAX_POINTS_COUNT :]
self._graph = None
def update(self, grade, item, now):
@@ -203,7 +203,7 @@ class ForgettingCurve:
is_remembered = grade >= THRESHOLD_RECALL
self.points.append([uf, self.REMEMBERED if is_remembered else self.FORGOTTEN])
if len(self.points) > self.MAX_POINTS_COUNT:
self.points = self.points[-self.MAX_POINTS_COUNT:]
self.points = self.points[-self.MAX_POINTS_COUNT :]
self._curve = None
def retention(self, uf):
@@ -253,9 +253,9 @@ class ForgettingCurves:
pts = []
for i in range(21):
v = MIN_AF + NOTCH_AF * i
y = math.exp(
-1.0 / (10 + 1 * (a + 1)) * (i - a ** 0.6)
) * (self.REMEMBERED - self.sm.requested_fi)
y = math.exp(-1.0 / (10 + 1 * (a + 1)) * (i - a**0.6)) * (
self.REMEMBERED - self.sm.requested_fi
)
pts.append([v, min(self.REMEMBERED, y)])
partial = [[0, self.REMEMBERED]] + pts
row.append(ForgettingCurve(partial))
@@ -427,7 +427,9 @@ class Item:
now = datetime.datetime.now()
af_idx = self.lapse if self.repetition == 0 else self.af_index()
of_val = self.sm.ofm.of(self.repetition, af_idx)
self.of = max(1.0, (of_val - 1) * (self.interval(now) / self.optimum_interval) + 1)
self.of = max(
1.0, (of_val - 1) * (self.interval(now) / self.optimum_interval) + 1
)
self.optimum_interval = round(self.optimum_interval * self.of)
self.previous_date = now
self.due_date = now + datetime.timedelta(milliseconds=self.optimum_interval)
@@ -443,7 +445,7 @@ class Item:
estimated_af = max(MIN_AF, min(MAX_AF, corrected_uf))
self._afs.append(estimated_af)
if len(self._afs) > self.MAX_AFS_COUNT:
self._afs = self._afs[-self.MAX_AFS_COUNT:]
self._afs = self._afs[-self.MAX_AFS_COUNT :]
wsum = sum(af * (i + 1) for i, af in enumerate(self._afs))
wtotal = sum(range(1, len(self._afs) + 1))
self.af(wsum / wtotal if wtotal else estimated_af)
@@ -600,7 +602,10 @@ class SM:
# Global state management
# ============================================================================
_GLOBAL_STATE_FILE = pathlib.Path(config_var.get()["global"]["paths"]["misc"]) / "sm15m_global_state.json"
_GLOBAL_STATE_FILE = (
pathlib.Path(config_var.get()["global"]["paths"]["misc"])
/ "sm15m_global_state.json"
)
def _get_global_sm():
@@ -702,7 +707,8 @@ class SM15MAlgorithm(BaseAlgorithm):
last_date = data.get("last_date", 0)
item.previous_date = (
daystamp_to_datetime(last_date).replace(tzinfo=None)
if last_date > 0 else None
if last_date > 0
else None
)
next_date_ms = data.get("next_date_ms", 0)
@@ -743,9 +749,7 @@ class SM15MAlgorithm(BaseAlgorithm):
data["last_date"] = datetime_to_daystamp(item.previous_date)
data["next_date_ms"] = int(item.due_date.timestamp() * 1000)
data["next_date"] = datetime_to_daystamp(item.due_date)
data["interval"] = max(
0, data["next_date"] - (data.get("last_date", 0) or 0)
)
data["interval"] = max(0, data["next_date"] - (data.get("last_date", 0) or 0))
data["last_modify"] = get_timestamp()
return algodata