* feat(cache): 节点缓存键纳入 CSV 文件签名 ComfyUI 默认只按输入参数判断缓存是否命中。两个节点读的都是外部 CSV, 参数不变而文件被替换时缓存会一直返回旧结果,用户换了数据却看不到变化。 把 CSV 的「路径 + 修改时间 + 大小」作为 IS_CHANGED 的返回值纳入缓存键: 文件一变就重算;文件与参数都不变时指纹稳定,缓存行为与 5.0.0 一致。 路径被防护拒绝时返回稳定哨兵而不抛异常,避免打断 ComfyUI 的缓存判断。 * perf(character): 派生索引随记录缓存,单次执行 62.6ms -> 26.7ms 角色节点每次执行都在 3.4 万条记录上重建 record_map / names / 作品筛选下标, CSV 没变时完全是重复劳动。把三者收进 CharacterIndex,与记录共用同一套 文件签名缓存(路径 + 列 + mtime + size),CSV 一变就重建。 顺带修掉作品下拉菜单的失效问题:菜单改为按默认 CSV 的文件签名缓存, 换 CSV 后自动重建,不再需要重启 ComfyUI。 实测(本机 7 次中位数):generate_characters 62.62ms -> 26.69ms(-57%)。 4 个 seed 下 prompt / characters_json / tested_count 逐字节一致。 剩余约 24ms 在 select_artists 的排除过滤里;改动它会改变 RNG 消耗顺序、 破坏同 seed 的可复现性,故本次不动。 * docs(db): 修正 generation_lock 的持锁范围说明 原文写「调用方应在进入本上下文之前完成抽样、权重计算、提示词拼装等纯 CPU 工作」, 但 RollingArtist 的重试循环必须待在事务里(命中已测组合要重新抽样), 实际持锁时长等于一次完整生成。文档与实现互相矛盾,读代码的人会误判并发行为。 改为如实描述:持锁时长由调用方决定,两种调用方式各自的代价是什么, 以及为什么不能简单把抽样挪到锁外(冲突只会推迟到写入时才被 INSERT OR IGNORE 吞掉)。 同时修正 __init__ 里「不覆盖事务内的业务计算」这句同样有歧义的注释。 纯注释改动,无代码行为变化。 * docs: 5.1.0 变更记录与 README 缓存/性能说明(T-04) * docs: 归档 v5.1.0 迭代计划至 docs/iteration * chore(release): 5.1.0
156 lines
3.8 KiB
Python
156 lines
3.8 KiB
Python
"""RollingArtist / RollingCharacter 核心实现(不依赖 ComfyUI,可独立导入与测试)。
|
|
|
|
模块划分:
|
|
- ``constants``: 路径、权重步长、规模阈值、记录类型标记与日志器
|
|
- ``params``: 节点入参的容错转换(两个节点共用)
|
|
- ``artists``: 艺术家 CSV 解析 / 加载缓存 / 索引化抽样
|
|
- ``characters``: 角色数据解析(trigger 拆解)、作品筛选、外观标签合并
|
|
- ``weights``: 权重分配、提示词构建解析、去重键
|
|
- ``db``: SQLite 记录库(已测记录)
|
|
- ``storage``: 旧版 CSV 读取与备份(供导入与留底使用)
|
|
- ``startup``: 启动期清理默认运行期文件(由 prestartup_script.py 调用)
|
|
"""
|
|
|
|
from .artists import (
|
|
ArtistRepository,
|
|
available_names,
|
|
clear_repositories,
|
|
compute_top_count,
|
|
get_artist_repository,
|
|
get_repository,
|
|
normalize_column_spec,
|
|
parse_artist_rows,
|
|
resolve_layout,
|
|
select_artists,
|
|
split_names,
|
|
)
|
|
from .characters import (
|
|
COPYRIGHT_ANY,
|
|
CharacterIndex,
|
|
CharacterRecord,
|
|
build_character_prompt,
|
|
build_payload,
|
|
build_records,
|
|
clear_records_cache,
|
|
copyright_options,
|
|
filter_by_copyright,
|
|
load_index,
|
|
load_records,
|
|
parse_copyright_filter,
|
|
split_core_tags,
|
|
split_tags,
|
|
unique_tags,
|
|
)
|
|
from .constants import (
|
|
DEFAULT_ARTIST_CSV,
|
|
DEFAULT_CHARACTER_CSV,
|
|
DEFAULT_CHARACTER_DB,
|
|
DEFAULT_DB,
|
|
DEFAULT_TESTED_CSV,
|
|
KIND_ARTIST,
|
|
KIND_CHARACTER,
|
|
LEGACY_BACKUP_SUFFIX,
|
|
LOGGER,
|
|
NODE_DIR,
|
|
WEIGHT_STEP,
|
|
)
|
|
from .db import RollingArtistDB, close_all_dbs, get_db, resolve_db_path
|
|
from .params import as_bool, as_float, as_int, as_text
|
|
from .paths import (
|
|
PathNotAllowedError,
|
|
check_csv_path,
|
|
check_db_path,
|
|
check_path,
|
|
forbidden_roots,
|
|
is_path_guard_disabled,
|
|
)
|
|
from .startup import cleanup_default_runtime_files, default_runtime_files
|
|
from .storage import backup_file, file_fingerprint, parse_tested_row, read_rows
|
|
from .weights import (
|
|
DEDUP_MODES,
|
|
WEIGHT_CURVES,
|
|
build_prompt,
|
|
dedup_key,
|
|
escape_key_part,
|
|
generate_weights,
|
|
normalize_dedup_mode,
|
|
normalize_weight_curve,
|
|
parse_prompt,
|
|
)
|
|
|
|
__all__ = [
|
|
# artists
|
|
"ArtistRepository",
|
|
"available_names",
|
|
"clear_repositories",
|
|
"compute_top_count",
|
|
"get_artist_repository",
|
|
"get_repository",
|
|
"normalize_column_spec",
|
|
"parse_artist_rows",
|
|
"resolve_layout",
|
|
"select_artists",
|
|
"split_names",
|
|
# characters
|
|
"COPYRIGHT_ANY",
|
|
"CharacterIndex",
|
|
"CharacterRecord",
|
|
"build_character_prompt",
|
|
"build_payload",
|
|
"build_records",
|
|
"clear_records_cache",
|
|
"copyright_options",
|
|
"filter_by_copyright",
|
|
"load_index",
|
|
"load_records",
|
|
"parse_copyright_filter",
|
|
"split_core_tags",
|
|
"split_tags",
|
|
"unique_tags",
|
|
# constants
|
|
"DEFAULT_ARTIST_CSV",
|
|
"DEFAULT_CHARACTER_CSV",
|
|
"DEFAULT_CHARACTER_DB",
|
|
"DEFAULT_DB",
|
|
"DEFAULT_TESTED_CSV",
|
|
"KIND_ARTIST",
|
|
"KIND_CHARACTER",
|
|
"LEGACY_BACKUP_SUFFIX",
|
|
"LOGGER",
|
|
"NODE_DIR",
|
|
"WEIGHT_STEP",
|
|
# db
|
|
"RollingArtistDB",
|
|
"close_all_dbs",
|
|
"get_db",
|
|
"resolve_db_path",
|
|
# params / startup
|
|
"as_bool",
|
|
"as_float",
|
|
"as_int",
|
|
"as_text",
|
|
"cleanup_default_runtime_files",
|
|
"default_runtime_files",
|
|
# paths
|
|
"PathNotAllowedError",
|
|
"check_csv_path",
|
|
"check_db_path",
|
|
"check_path",
|
|
"forbidden_roots",
|
|
"is_path_guard_disabled",
|
|
"backup_file",
|
|
"file_fingerprint",
|
|
"parse_tested_row",
|
|
"read_rows",
|
|
# weights
|
|
"DEDUP_MODES",
|
|
"WEIGHT_CURVES",
|
|
"build_prompt",
|
|
"dedup_key",
|
|
"escape_key_part",
|
|
"generate_weights",
|
|
"normalize_dedup_mode",
|
|
"normalize_weight_curve",
|
|
"parse_prompt",
|
|
]
|