docs: 修改文档

This commit is contained in:
2026-05-07 13:26:22 +08:00
parent c2496c1bb5
commit 1975474c94
16 changed files with 464 additions and 57 deletions

View File

@@ -24,7 +24,7 @@ logger.debug(f"工作目录: {workdir}")
(workdir / "data" / "config").mkdir(parents=True, exist_ok=True)
config_var: ContextVar[ConfigDict].get = ContextVar(
config_var: ContextVar[ConfigDict] = ContextVar(
"config_var",
default=ConfigDict(workdir / "data" / "config"),
)

View File

@@ -85,7 +85,7 @@ class FavoriteManagerScreen(Screen):
def _encode_favorite_key(self, repo_path: str, ident: str) -> str:
"""编码仓库路径和标识符为安全的按钮 ID 部分"""
# 使用 \x00 分隔两部分然后进行 base64 编码
# 使用 \x00 分隔两部分, 然后进行 base64 编码
combined = f"{repo_path}\x00{ident}"
encoded = base64.urlsafe_b64encode(combined.encode()).decode()
# 去掉填充的等号
@@ -114,7 +114,7 @@ class FavoriteManagerScreen(Screen):
# 创建安全的按钮 ID
button_key = self._encode_favorite_key(fav.repo_path, fav.ident)
# 创建列表项包含移除按钮
# 创建列表项, 包含移除按钮
container = Horizontal(
Label(display_text, classes="favorite-content"),
Button("移除", id=f"remove-{button_key}", variant="error", flat=True, classes="favorite-item-btn"),

View File

@@ -237,14 +237,14 @@ class MemScreen(Screen):
"""获取仓库相对路径(相对于 data/repo"""
if self.repo is None:
return ""
# self.repo.source 是 Path 对象指向仓库目录
# self.repo.source 是 Path 对象, 指向仓库目录
repo_full_path = self.repo.source
data_repo_path = Path(config_var.get()["global"]["paths"]["data"]) / "repo"
try:
rel_path = repo_full_path.relative_to(data_repo_path)
return str(rel_path)
except ValueError:
# 如果不在 data/repo 下则返回完整路径(字符串形式)
# 如果不在 data/repo 下, 则返回完整路径(字符串形式)
return str(repo_full_path)
def _is_current_atom_favorited(self) -> bool:

View File

@@ -14,7 +14,7 @@ import heurams.kernel.particles as pt
import heurams.services.hasher as hasher
from heurams.context import *
# 兼容性缓存路径:优先使用 paths.cache否则使用 data/cache
# 兼容性缓存路径:优先使用 paths.cache, 否则使用 data/cache
paths = config_var.get()["global"]["paths"]
cache_dir = pathlib.Path(paths.get("cache", paths["data"] + "/cache")) / "voice"
@@ -55,7 +55,7 @@ class PrecachingScreen(Screen):
self.precache_worker = None
self.cancel_flag = 0
self.desc = desc
# 不再需要缓存配置保留配置读取以兼容
# 不再需要缓存配置, 保留配置读取以兼容
self.cache_stats = {
"total_size": 0,
"file_count": 0,

View File

@@ -130,7 +130,7 @@ class SyncScreen(Screen):
log_widget = self.query_one("#log_output")
log_widget.update("\n".join(self.log_messages)) # type: ignore
except Exception:
pass # 如果组件未就绪忽略错误
pass # 如果组件未就绪, 忽略错误
def on_button_pressed(self, event: Button.Pressed) -> None:
"""处理按钮点击事件"""
@@ -150,7 +150,7 @@ class SyncScreen(Screen):
def test_connection(self):
"""测试 WebDAV 服务器连接"""
if not self.sync_service:
self.log_message("同步服务未初始化请检查配置", is_error=True)
self.log_message("同步服务未初始化, 请检查配置", is_error=True)
self.update_status("❌ 同步服务未初始化")
return
@@ -172,7 +172,7 @@ class SyncScreen(Screen):
def start_sync(self):
"""开始同步"""
if not self.sync_service:
self.log_message("同步服务未初始化无法开始同步", is_error=True)
self.log_message("同步服务未初始化, 无法开始同步", is_error=True)
return
if self.is_syncing:

View File

@@ -26,13 +26,13 @@ _SCHEDULER_STATE_FILE = pathlib.Path(
def _get_global_scheduler():
"""获取全局 FSRS Scheduler 实例从文件加载或创建新的"""
"""获取全局 FSRS Scheduler 实例, 从文件加载或创建新的"""
if os.path.exists(_SCHEDULER_STATE_FILE):
try:
with open(_SCHEDULER_STATE_FILE, "r", encoding="utf-8") as f:
return Scheduler.from_json(f.read())
except Exception:
logger.warning("FSRS Scheduler 状态文件加载失败创建新实例")
logger.warning("FSRS Scheduler 状态文件加载失败, 创建新实例")
return Scheduler()
@@ -80,7 +80,7 @@ class FSRSAlgorithm(BaseAlgorithm):
# FSRS 特有字段
fsrs_state: int # State 枚举值: 1=Learning, 2=Review, 3=Relearning
fsrs_step: int # 当前学习步进索引, -1 表示 None (Review 状态)
fsrs_stability: float # 稳定性(秒)0.0 表示尚未计算
fsrs_stability: float # 稳定性(秒), 0.0 表示尚未计算
fsrs_difficulty: float # 难度 [1.0, 10.0], 0.0 表示尚未计算
# 标准 BaseAlgorithm 兼容字段
real_rept: int
@@ -194,7 +194,7 @@ class FSRSAlgorithm(BaseAlgorithm):
if is_new_activation:
card = Card()
logger.debug("新激活创建新 Card")
logger.debug("新激活, 创建新 Card")
else:
card = cls._algodata_to_card(algodata)

View File

@@ -611,7 +611,7 @@ def _get_global_sm():
with open(_GLOBAL_STATE_FILE, "r", encoding="utf-8") as f:
return SM.load(json.load(f))
except Exception:
logger.warning("SM-15M 全局状态文件加载失败创建新实例")
logger.warning("SM-15M 全局状态文件加载失败, 创建新实例")
sm = SM()
_save_global_sm(sm)
return sm
@@ -646,7 +646,7 @@ class SM15MAlgorithm(BaseAlgorithm):
# 毫秒精度(子日排程)
last_date_ms: int
next_date_ms: int
# BaseAlgorithm 兼容(天精度向后兼容)
# BaseAlgorithm 兼容(天精度, 向后兼容)
real_rept: int
rept: int
interval: int
@@ -694,7 +694,7 @@ class SM15MAlgorithm(BaseAlgorithm):
opt_days * 24 * 60 * 60 * 1000 if opt_days > 0 else sm.interval_base
)
# 毫秒精度优先退化至天精度
# 毫秒精度优先, 退化至天精度
last_date_ms = data.get("last_date_ms", 0)
if last_date_ms:
item.previous_date = datetime.datetime(1970, 1, 1) + datetime.timedelta(

View File

@@ -26,14 +26,14 @@ class BaseLLM:
"""发送聊天消息并获取响应
Args:
messages: 消息列表每个消息为 {"role": "user"|"assistant"|"system", "content": "消息内容"}
**kwargs: 其他参数如 temperature, max_tokens 等
messages: 消息列表, 每个消息为 {"role": "user"|"assistant"|"system", "content": "消息内容"}
**kwargs: 其他参数, 如 temperature, max_tokens 等
Returns:
模型返回的文本响应
"""
logger.debug("BaseLLM.chat: messages=%d, kwargs=%s", len(messages), kwargs)
logger.warning("BaseLLM.chat 是基类方法未实现具体功能")
logger.warning("BaseLLM.chat 是基类方法, 未实现具体功能")
await asyncio.sleep(0) # 避免未使用异步的警告
return "BaseLLM 未实现具体功能"
@@ -50,6 +50,6 @@ class BaseLLM:
logger.debug(
"BaseLLM.chat_stream: messages=%d, kwargs=%s", len(messages), kwargs
)
logger.warning("BaseLLM.chat_stream 是基类方法未实现具体功能")
logger.warning("BaseLLM.chat_stream 是基类方法, 未实现具体功能")
await asyncio.sleep(0)
yield "BaseLLM 未实现流式功能"

View File

@@ -27,8 +27,8 @@ class OpenAILLM(BaseLLM):
try:
from openai import AsyncOpenAI
except ImportError:
logger.error("未安装 openai 库请运行: pip install openai")
raise ImportError("未安装 openai 库请运行: pip install openai")
logger.error("未安装 openai 库, 请运行: pip install openai")
raise ImportError("未安装 openai 库, 请运行: pip install openai")
self._client = AsyncOpenAI(
api_key=self.api_key if self.api_key else None,
@@ -49,7 +49,7 @@ class OpenAILLM(BaseLLM):
"max_tokens": kwargs.get("max_tokens", 1000),
}
# 合并参数优先使用传入的 kwargs
# 合并参数, 优先使用传入的 kwargs
request_kwargs = {**default_kwargs, **kwargs}
request_kwargs["messages"] = messages

View File

@@ -10,7 +10,7 @@ from heurams.services.exceptions import WTFException
logger = get_logger(__name__)
class ConfigDict(UserDict): # 舒服了
class ConfigDict(UserDict):
_instances = {} # 必须使用单例模式, 不然有严重的多实例导致的配置无法持久化问题
def __new__(cls, config_path: pathlib.Path, dict=None):

View File

@@ -73,7 +73,7 @@ class FavoriteManager:
with open(self._file_path, "r", encoding="utf-8") as f:
data = json.load(f)
self._favorites = [FavoriteItem.from_dict(item) for item in data]
logger.debug("收藏列表加载成功%d", len(self._favorites))
logger.debug("收藏列表加载成功, %d", len(self._favorites))
except Exception as e:
logger.error("加载收藏列表失败: %s", e)
self._favorites = []
@@ -86,7 +86,7 @@ class FavoriteManager:
data = [item.to_dict() for item in self._favorites]
with open(self._file_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
logger.debug("收藏列表保存成功%d", len(self._favorites))
logger.debug("收藏列表保存成功, %d", len(self._favorites))
except Exception as e:
logger.error("保存收藏列表失败: %s", e)

View File

@@ -6,9 +6,9 @@
转换规则:
1. `ident` 列用作 TOML 的 section 标题(`[ident]`)
2. 若某行的 `ident` 为空则自动按顺序生成标识符例如 `idx_1`、`idx_2` 等
2. 若某行的 `ident` 为空, 则自动按顺序生成标识符, 例如 `idx_1`、`idx_2` 等
3. 所有其他列(除 `ident` 外)都作为该 section 下的键值对
4. 所有列都是可选的但 `ident` 为空时会自动生成
4. 所有列都是可选的, 但 `ident` 为空时会自动生成
示例 CSV:
```csv
@@ -61,8 +61,8 @@ meaning = "狗发出的声音"
补充说明:
- 自动生成的标识符使用 `idx_` 前缀加数字序列
- 生成序列基于原始 CSV 中 `ident` 为空的行出现的顺序
- 所有值都保留为字符串类型符合 TOML 字符串格式要求
- 如果 CSV 包含更多列它们也会以相同方式转换为键值对
- 所有值都保留为字符串类型, 符合 TOML 字符串格式要求
- 如果 CSV 包含更多列, 它们也会以相同方式转换为键值对
- 支持 `-r` 参数指定随机种子来打乱 section 顺序
"""
@@ -79,8 +79,8 @@ def csv_to_toml(csv_path, toml_path=None, random_seed=None):
Args:
csv_path (str): 输入CSV文件路径
toml_path (str): 输出TOML文件路径默认为相同目录下同名文件
random_seed (int): 随机种子用于打乱section顺序None表示不打乱
toml_path (str): 输出TOML文件路径, 默认为相同目录下同名文件
random_seed (int): 随机种子, 用于打乱section顺序, None表示不打乱
"""
# 检查CSV文件是否存在
csv_file = Path(csv_path)
@@ -108,7 +108,7 @@ def csv_to_toml(csv_path, toml_path=None, random_seed=None):
print("错误: CSV文件为空或格式不正确")
sys.exit(1)
# 如果指定了随机种子设置随机种子并打乱行顺序
# 如果指定了随机种子, 设置随机种子并打乱行顺序
if random_seed is not None:
random.seed(random_seed)
random.shuffle(rows)
@@ -119,7 +119,7 @@ def csv_to_toml(csv_path, toml_path=None, random_seed=None):
idx_counter = 1
for row in rows:
# 处理ident列为空时生成自动标识符
# 处理ident列, 为空时生成自动标识符
ident = row.get("ident", "").strip()
if not ident:
ident = f"idx_{idx_counter}"
@@ -155,7 +155,7 @@ def csv_to_toml(csv_path, toml_path=None, random_seed=None):
def main():
"""主函数"""
parser = argparse.ArgumentParser(
description="将CSV文件转换为TOML格式支持随机打乱section顺序",
description="将CSV文件转换为TOML格式, 支持随机打乱section顺序",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
@@ -168,10 +168,10 @@ def main():
parser.add_argument("csv_path", help="输入的CSV文件路径")
parser.add_argument(
"toml_path", nargs="?", help="输出的TOML文件路径默认为CSV同名文件"
"toml_path", nargs="?", help="输出的TOML文件路径, 默认为CSV同名文件"
)
parser.add_argument(
"-r", "--random-seed", type=int, help="随机种子用于打乱TOML section的顺序"
"-r", "--random-seed", type=int, help="随机种子, 用于打乱TOML section的顺序"
)
args = parser.parse_args()