refactor: core widget baseline is a values-only file, keyed by core id
The editor seeded its fixed core nodes from a saved graph dump. Replaced with a small file holding just the widget values the builder consumes — no free text, nothing user-typed, since every text field a run needs arrives from the project at generate time. Graph output verified identical against live object_info. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e1ae4acea9
commit
22607b0c14
@@ -18,3 +18,6 @@ refinements/
|
||||
|
||||
# Large local research docs
|
||||
*.pdf
|
||||
|
||||
# Never track saved ComfyUI workflow dumps — they carry whatever was typed in the graph.
|
||||
movie_editor/backend/reference/*.workflow.json
|
||||
|
||||
@@ -48,13 +48,6 @@ CORE: dict[str, str] = {
|
||||
"f2i": "LTXFloatToInt",
|
||||
}
|
||||
|
||||
# reference-workflow node id per core node (to seed widget values from the user's
|
||||
# real settings). Missing -> bare object_info / param defaults.
|
||||
REF_ID: dict[str, int] = {
|
||||
"studio": 5299, "cond": 5147, "sampler": 5333, "concat": 4528, "separate": 4845,
|
||||
"audiodec": 5021, "normaudio": 5314, "vhs": 5019, "saveref": 5328, "keyloader": 5303,
|
||||
"pos": 5012, "neg": 5256, "frames": 4988, "fps": 4989, "f2i": 5145,
|
||||
}
|
||||
|
||||
# core internal links: core_id -> {input_name: (src_core_id, output_index)}
|
||||
CORE_LINKS: dict[str, dict[str, tuple[str, int]]] = {
|
||||
@@ -314,19 +307,25 @@ def _widget_choices(node_def: Optional[dict]) -> dict:
|
||||
return out
|
||||
|
||||
|
||||
# ── reference workflow ────────────────────────────────────────────────────────
|
||||
# ── core widget baseline ──────────────────────────────────────────────────────
|
||||
|
||||
def load_reference() -> dict:
|
||||
"""Baseline widget values for the fixed core nodes, keyed by core id — the tuned
|
||||
settings (sigma schedules, sampler config, container format) the editor starts from
|
||||
before per-run params are applied.
|
||||
|
||||
Values only: no prompt text, and nothing user-typed. Every text field the run needs
|
||||
arrives from the project at generate time, so none of it belongs in a checked-in file.
|
||||
A missing/unreadable file just means each core node falls back to its object_info
|
||||
defaults.
|
||||
"""
|
||||
try:
|
||||
return json.loads((config.REFERENCE_DIR / "montage.workflow.json").read_text())
|
||||
data = json.loads((config.REFERENCE_DIR / "core_widgets.json").read_text())
|
||||
return data if isinstance(data, dict) else {}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def _ref_widgets(ref: dict) -> dict[int, Any]:
|
||||
return {n.get("id"): n.get("widgets_values") for n in (ref.get("nodes") or [])}
|
||||
|
||||
|
||||
# ── graph assembly ────────────────────────────────────────────────────────────
|
||||
|
||||
def _output_index(node_def: Optional[dict], out_name: str) -> int:
|
||||
@@ -352,7 +351,7 @@ def build(object_info: dict, models_config: dict, params: dict, media: dict | No
|
||||
# build (including the closures below), so every reference downstream is family-aware.
|
||||
family = family_of(models_config)
|
||||
CORE, CORE_LINKS, OPEN_PORTS = family_core(family)
|
||||
ref_wv = _ref_widgets(load_reference())
|
||||
ref_wv = load_reference()
|
||||
graph: dict[str, dict] = {}
|
||||
# `blocking` is the subset of problems that should stop generation (required inputs).
|
||||
report: dict[str, list] = {"wired": [], "auto_wired": [], "ambiguous": [], "unsatisfied": [], "blocking": []}
|
||||
@@ -375,7 +374,7 @@ def build(object_info: dict, models_config: dict, params: dict, media: dict | No
|
||||
for cid, cls in CORE.items():
|
||||
nd = object_info.get(cls)
|
||||
inputs = _widget_defaults(nd)
|
||||
inputs.update(extract_widgets(nd, ref_wv.get(REF_ID.get(cid))))
|
||||
inputs.update(extract_widgets(nd, ref_wv.get(cid)))
|
||||
for inp, (src, idx) in CORE_LINKS.get(cid, {}).items():
|
||||
inputs[inp] = [src, idx]
|
||||
protected_edges.add((cid, inp))
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"cond": [
|
||||
25
|
||||
],
|
||||
"f2i": [
|
||||
0
|
||||
],
|
||||
"fps": [
|
||||
30
|
||||
],
|
||||
"frames": [
|
||||
241,
|
||||
"fixed"
|
||||
],
|
||||
"keyloader": [
|
||||
"tf",
|
||||
"tf",
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"neg": [
|
||||
"underwater, diving, slow motion, still image, bad quality, subtitles, text, watermark, overlay, pc game, yelling, console game, childish, ugly, text, blur, logo, wordmark, static, low quality, noise, white noise, bleep, censoring, censor, bleeping, beep, beeping, newscast, interview, podcast, chinese, mutant, horror, 70's, film grain, comedy, stand-up "
|
||||
],
|
||||
"normaudio": [
|
||||
-30
|
||||
],
|
||||
"pos": [
|
||||
""
|
||||
],
|
||||
"sampler": [
|
||||
898993421681879,
|
||||
"randomize",
|
||||
97,
|
||||
16,
|
||||
1,
|
||||
8,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
0.25,
|
||||
true,
|
||||
0.01,
|
||||
0,
|
||||
0,
|
||||
0.025,
|
||||
0.05,
|
||||
"relative"
|
||||
],
|
||||
"saveref": [
|
||||
"my_style_v1"
|
||||
],
|
||||
"studio": [
|
||||
"Wrong details|loved",
|
||||
"{\"refinement_key\":\"\",\"overrides\":{\"refinement_key\":false,\"feedback_prompt\":false,\"user_intent_prompt\":false,\"negative_prompt\":false},\"scene_builder\":{\"mode\":\"Pass-through\",\"scene\":\"-None-\",\"scene_name\":\"\",\"aliases\":\"\",\"scene_positive\":\"\",\"scene_negative\":\"\"},\"refiner\":{\"mode\":\"Refine\",\"advisor_mode\":\"Off\",\"advisor_thinking\":false,\"prompt_repair\":false,\"im_feeling_lucky\":false,\"reset_session\":false,\"feedback_prompt\":\"\",\"user_intent_prompt_override\":\"\",\"negative_prompt\":\"\",\"temporal_style\":\"accelerate\",\"split_by_transitions\":true,\"split_transition_placement\":\"start\",\"reference_injection\":false,\"vision_conditioning\":false,\"value_guidance\":true,\"steer_mode\":\"both\",\"absolute_strength\":0.3,\"latent_value_guidance\":true,\"transition_contrast\":1.5,\"batch_variants\":1,\"batch_mode\":\"Interactive Guessing\",\"batch_learning\":true,\"guess_mode\":false,\"guess_direction\":\"up\",\"guess_range\":1.2,\"guess_freeze_seed\":false},\"advisor_llm\":{\"enabled\":false,\"model_path\":\"huihui-ai/Huihui-Qwen3-8B-abliterated-v2\",\"dtype\":\"bfloat16\"},\"loras\":[],\"loras_config\":{\"mode\":\"ltx2\",\"per_block\":false},\"samplers\":{\"high\":{\"type\":\"Normalizing\",\"sigmas\":\"1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0\",\"hybrid\":{\"eta\":1,\"eta_final\":1,\"normalize_strength\":1,\"normalize_start_sigma\":0.9,\"s_noise\":1,\"high_quality_pct\":0.5,\"correction_blend\":0.25,\"quality_sharpness\":0.3,\"motion_pulse_mode\":\"off\",\"motion_pulse_start_pct\":0.5,\"motion_pulse_count\":4,\"motion_pulse_spacing_pct\":0.22,\"motion_pulse_strength\":0.85,\"velocity_bias_mode\":\"capture\",\"velocity_bias_strength\":0.1,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"\",\"rescue_mode\":false,\"rescue_threshold\":0.7,\"rescue_strength\":0.15,\"velocity_aspect_bucket\":\"any\",\"variability\":0},\"distilled\":{\"order\":1,\"final_correction_steps\":3,\"ab2_ramp\":false,\"normalize_strength\":0.5,\"normalize_start_sigma\":0.9,\"s_noise\":0,\"velocity_bias_mode\":\"capture\",\"velocity_bias_strength\":0.1,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"\",\"rescue_mode\":false,\"rescue_threshold\":0.15,\"rescue_strength\":0.2},\"normalizing\":{\"normalize_strength\":0.5,\"normalize_start_sigma\":0.9,\"velocity_bias_mode\":\"capture_and_apply\",\"velocity_bias_strength\":0.1,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"\",\"rescue_mode\":false,\"rescue_threshold\":0.15,\"rescue_strength\":0.2},\"ksampler_name\":\"ddim\"},\"low\":{\"type\":\"Distilled Flow\",\"sigmas\":\"0.909375, 0.725, 0.421875, 0.0\",\"hybrid\":{\"eta\":1,\"eta_final\":1,\"normalize_strength\":0,\"normalize_start_sigma\":0.9,\"s_noise\":1,\"high_quality_pct\":0.35,\"correction_blend\":1,\"quality_sharpness\":0,\"motion_pulse_mode\":\"off\",\"motion_pulse_start_pct\":0.3,\"motion_pulse_count\":2,\"motion_pulse_spacing_pct\":0.22,\"motion_pulse_strength\":0.85,\"velocity_bias_mode\":\"off\",\"velocity_bias_strength\":0,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"default\",\"rescue_mode\":false,\"rescue_threshold\":0.15,\"rescue_strength\":0.2,\"velocity_aspect_bucket\":\"any\"},\"distilled\":{\"order\":1,\"final_correction_steps\":1,\"ab2_ramp\":false,\"normalize_strength\":0,\"normalize_start_sigma\":0.9,\"s_noise\":0,\"velocity_bias_mode\":\"off\",\"velocity_bias_strength\":0,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"default\",\"rescue_mode\":false,\"rescue_threshold\":0.15,\"rescue_strength\":0.2},\"normalizing\":{\"normalize_strength\":0.5,\"normalize_start_sigma\":0.9,\"velocity_bias_mode\":\"off\",\"velocity_bias_strength\":0,\"velocity_bias_source\":\"mean\",\"velocity_refinement_key\":\"default\",\"rescue_mode\":false,\"rescue_threshold\":0.15,\"rescue_strength\":0.2},\"ksampler_name\":\"euler\"}}}",
|
||||
"[]",
|
||||
null,
|
||||
"funpack_studio_open",
|
||||
"funpack_studio_open",
|
||||
"funpack_studio_batch"
|
||||
],
|
||||
"vhs": {
|
||||
"crf": 22,
|
||||
"filename_prefix": "result_%date:MM-dd_hh-mm-ss%",
|
||||
"format": "video/h265-mp4",
|
||||
"frame_rate": 30,
|
||||
"loop_count": 0,
|
||||
"pingpong": false,
|
||||
"pix_fmt": "yuv420p",
|
||||
"save_metadata": false,
|
||||
"save_output": false
|
||||
}
|
||||
}
|
||||
@@ -1235,7 +1235,7 @@ if web is not None and PromptServer is not None:
|
||||
"ok": True,
|
||||
"comfy_url": config.comfy_base_url(),
|
||||
"template_exists": config.TEMPLATE_PATH.is_file(),
|
||||
"reference_loaded": bool(builder.load_reference().get("nodes")),
|
||||
"reference_loaded": bool(builder.load_reference()),
|
||||
"configured_slots": len(nodes.load_models().get("slots", [])),
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user