From e5568ec02bee39e0ad7f06a6affe1d1c4b962bf8 Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Thu, 15 Oct 2026 18:22:38 +0300 Subject: [PATCH] fix: a text-encoder .gguf is refused when ComfyUI-GGUF is absent too; docs no longer overclaim Ready to generate, failure behaviour, rating thresholds, Export; Start shots hint shortened (attacker round 6) Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 10 +++++----- README.md | 2 +- app/ui/features/inspector/project.js | 2 +- docs/how-to-start.md | 14 +++++++------- modules/loaders/gguf_support.py | 5 +++++ modules/loaders/tests/test_gguf_support.py | 8 ++++++++ 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5037bba0..f9046b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,14 @@ ## [5.0.0] "Cunning Cranberry" - unreleased -A rewrite from scratch, not an update of 4.x. Same idea (a studio for video inside ComfyUI that learns from your ratings), new architecture: every feature is a module that announces itself, so a feature cannot be forgotten in the UI, a wire cannot be missed, and one failing module never stops the run. 4.x projects are not imported; see "Not carried over". +A rewrite from scratch, not an update of 4.x. Same idea (a studio for video inside ComfyUI that learns from your ratings), new architecture: every feature is a module that announces itself, so a feature cannot be forgotten in the UI, a wire cannot be missed, and a failing feature module is left out while the run carries on. 4.x projects are not imported; see "Not carried over". ### What it is - **A browser studio at `/funpack/`**: timeline with one clip per scene, Composer (story in one box, cut word, templates, `$variables`, shortcuts), properties, media bin, preview, takes, rating, Export, Render, project wizard and guided tour. - **Models & Pipeline**: the pipeline as cards. Pick files, swap or add nodes (any installed custom node), wire one node's output into another's input, import a ComfyUI workflow. The server refuses what would not build and says why. -- **Modules** (Settings ▸ Modules): each feature switches on or off on its own. A module that fails during a run is left out of it, the log says why, and it stays off until its code is repaired or you turn it back on. -- **Learning from ratings**: a Taste key remembers ratings; the guidance, steering and prompt modules that use them start acting after a few liked clips and say so when they need more. +- **Modules** (Settings ▸ Modules): each feature switches on or off on its own. A module that fails during a run is left out of it, the log says why, and it stays off until its code changes or you turn it back on. +- **Learning from ratings**: a Taste key remembers ratings; the guidance, steering and prompt modules that use them start acting once they have enough ratings (a few liked clips; some also need disliked ones) and say so when they need more. ### Models @@ -19,7 +19,7 @@ A rewrite from scratch, not an update of 4.x. Same idea (a studio for video insi ### Features -- **Proven**: prompt markup, empty latent, loaders (diffusion model, CLIP, VAE, LoRA, checkpoint, media), cut opening, decode, save video, anchor de-staticking (ALG), randomizer, DynaShift, first-step seed search, modifiers, sampler, detail. +- **Proven**: prompt markup, empty latent, second pass (the H3 preset for it is held back), loaders (diffusion model, CLIP, VAE, LoRA, checkpoint, media), cut opening, decode, save video, anchor de-staticking (ALG), randomizer, DynaShift, first-step seed search, modifiers, sampler, detail. - **Experimental**: shot camera, continuity, identity transfer, negative erase, prompt enhancer, Render, taste modules (slider, guidance, prompt nudge, attention, REINS, early guidance), shot memory, decisiveness, late-branch guidance, camera move, context windows, block influence, block repeat, phrase probe, shadow negative, momentum, velocity bias, video detail, temporal style, massive-activation steering, video-to-audio coupling. - **Prompt enhancer**: a language model rewrites each finished prompt. Has its own encoder pick (Composer ▸ Enhance ▸ Encoder), because H3's own encoder cannot write prose. Verified with Gemma 4. - **Auto Montage**: builds a new cut at the end of the timeline from your rendered clips; originals stay untouched, and the pieces are never regenerated or rated. @@ -36,7 +36,7 @@ A rewrite from scratch, not an update of 4.x. Same idea (a studio for video insi - **LTX 2.x is untested** (see Models). - **`.gguf` text encoders** work only for architectures ComfyUI-GGUF understands; others are refused with a message. Gemma 4 `.gguf` does not work; a loader for it may come later. -- **H3 start frame**: the scene picture sets the video's shape only; image-to-video from it is not implemented. +- **H3 start frame**: in the H3 preset the scene picture sets the video's shape only; a start frame is not part of it. - **H3 second pass** is held back: not offered until verified. - Turning some modules on switches the model compiler off for the run, which costs sampling time. diff --git a/README.md b/README.md index 014ecd0e..ee946472 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **FunPack is a browser studio for video inside ComfyUI: a timeline with one clip per scene, a Composer for prompts ($variables, templates, shortcuts), pipeline cards instead of graphs, and modules that learn from your ratings - all on the regular ComfyUI backend.** -v5 is a rewrite from scratch, not an update of 4.x: every feature is a module that announces itself, so one failing module never stops a run. Classic FunPack (4.x) lives on its own branch. +v5 is a rewrite from scratch, not an update of 4.x: every feature is a module that announces itself, so a failing feature module is left out while the run carries on. Classic FunPack (4.x) lives on its own branch.

Ko-fi  diff --git a/app/ui/features/inspector/project.js b/app/ui/features/inspector/project.js index ab80cf1a..c9d969fd 100644 --- a/app/ui/features/inspector/project.js +++ b/app/ui/features/inspector/project.js @@ -72,7 +72,7 @@ export function projectRows(p, slots, api) { ...custom(p, open), c.field.default({ label: "Final render size", hint: "The size of the exported video: the first clip's, the project's, or any rendered clip's own.", control: c.select.md({ label: "Final render size", options: sizes(open), value: open.export_size_from || "", onChange: (v) => p.setField("export_size_from", v) }) }), - c.field.default({ label: "Start shots", hint: "From an image: a scene is shaped by its picture, or the last frame of the clip before it; a model that can start from a picture opens with it (MiniMax H3 uses it for the shape only). From a prompt: every scene starts without a picture.", control: c.select.md({ label: "Start shots", options: STARTS, value: open.generation_mode === "t2v" ? "t2v" : "i2v", onChange: (v) => p.setField("generation_mode", v) }) })), + c.field.default({ label: "Start shots", hint: "From an image: a scene starts from its picture, or the last frame of the clip before it (MiniMax H3 uses it for the shape only). From a prompt: every scene starts without a picture.", control: c.select.md({ label: "Start shots", options: STARTS, value: open.generation_mode === "t2v" ? "t2v" : "i2v", onChange: (v) => p.setField("generation_mode", v) }) })), c.label.section({ text: "Prompt" }), card(c.field.default({ label: "Anchor", hint: "Put in front of every scene's prompt.", control: c.textarea.md({ label: "Anchor", value: p.anchor, rows: 2, onInput: (v) => p.setAnchor(v) }) }), c.field.default({ label: "Negative prompt", hint: "What to steer away from. A model that ignores negative prompts (MiniMax H3) uses it only with Shadow negative or Negative erase on.", control: c.textarea.md({ label: "Negative prompt", value: p.negative, rows: 2, onInput: (v) => p.setNegative(v) }) }), diff --git a/docs/how-to-start.md b/docs/how-to-start.md index 8d15fb7a..0c03dd0f 100644 --- a/docs/how-to-start.md +++ b/docs/how-to-start.md @@ -30,10 +30,10 @@ Start ComfyUI as usual and open `/funpack/` on the same address, for example `ht The model's pipeline starts empty: it needs your files. -1. Open **Settings ▸ Ready to generate?**. It lists everything still missing. -2. Open **Settings ▸ Models & Pipeline** and choose a file in each card marked with an orange dot (diffusion model, text encoder, VAE, and so on). +1. Open **Settings ▸ Ready to generate?**. It checks the machine: ffmpeg, GPU, model folders, node packs. +2. Open **Settings ▸ Models & Pipeline** and choose a file in each card marked with an orange dot (diffusion model, text encoder, VAE, and so on). Generate also names any file that is still missing. -Put model files where ComfyUI expects them (`models/diffusion_models`, `models/text_encoders`, `models/vae`, `models/loras`). When nothing is missing, Ready to generate? says so. +Put model files where ComfyUI expects them (`models/diffusion_models`, `models/text_encoders`, `models/vae`, `models/loras`). `.gguf` text encoders work only for architectures ComfyUI-GGUF understands; any other is refused with a message (Gemma 4 `.gguf` is one such case). Use the `.safetensors` file of the same model. @@ -51,15 +51,15 @@ Watch the Log window if nothing happens: any module that fails says why there, a ## 7. Cut, render, export -Trim and split clips on the timeline. **⚡ Auto Montage** builds a new cut at the end from your rendered clips; your originals stay as they are. **⧉ Render** joins the timeline into one file; **⤓ Export** saves the picked clip. +Trim and split clips on the timeline. **⚡ Auto Montage** builds a new cut at the end from your rendered clips; your originals stay as they are. **⧉ Render** joins the timeline into one file; **⤓ Export** downloads the picked clip (picture only: a clip whose sound was separated is silent there, Render mixes it). ## 8. Teach it your taste (optional) -Rate a result with **Rate scene…** (liked, disliked, bad image, bad composition). Set a **Taste key** (the ⚠ chip on the timeline points to it: **Settings ▸ Engine ▸ System**) so ratings are remembered. **Settings ▸ Refinement & Taste** lists, exports and deletes keys. Modules that learn from ratings start acting after a few liked clips and say so when they need more. +Rate a result with **Rate scene…** (liked, disliked, bad image, bad composition). Set a **Taste key** (the ⚠ chip on the timeline points to it: **Settings ▸ Engine ▸ System**) so ratings are remembered. **Settings ▸ Refinement & Taste** lists, exports and deletes keys. Modules that learn from ratings start acting once they have enough ratings (a few liked clips; some also need disliked ones) and say so when they need more. ## 9. Features marked experimental -**Settings ▸ Modules** switches each feature on or off. Several features are experimental: built and run, but not yet proven over many runs. If a module fails while generating, the run carries on without it, the Log says why, and the module stays off until its code is repaired or you turn it back on in Settings ▸ Modules. +**Settings ▸ Modules** switches each feature on or off. Several features are experimental: built and run, but not yet proven over many runs. If a module fails while generating, the run carries on without it, the Log says why, and the module stays off until its code changes or you turn it back on in Settings ▸ Modules. ## If something goes wrong @@ -70,5 +70,5 @@ Rate a result with **Rate scene…** (liked, disliked, bad image, bad compositio ## Known limits in 5.0 - LTX 2.x is untested (see above). -- On H3 the scene picture sets the video's shape only; using it as a start frame is not implemented. +- In the H3 preset the scene picture sets the video's shape only; a start frame is not part of it. - The H3 "second pass" preset is not offered yet: it has not been verified. diff --git a/modules/loaders/gguf_support.py b/modules/loaders/gguf_support.py index 5d0a6299..59b02351 100644 --- a/modules/loaders/gguf_support.py +++ b/modules/loaders/gguf_support.py @@ -240,6 +240,11 @@ def _load(path: str, clip: bool) -> tuple[dict, dict, str]: which = backend() if which is None: raise RuntimeError(UNAVAILABLE) + if clip and which != "pack": + # Only the pack maps llama.cpp's tensor names back to a text encoder's; the native reader would hand over + # a state dict that looks loaded and is the wrong model. + raise RuntimeError("a text-encoder .gguf needs the ComfyUI-GGUF node pack to be read, and it is not installed. " + "Install it, or use a .safetensors encoder of the same model.") if which == "pack": d = _pack_dir() try: diff --git a/modules/loaders/tests/test_gguf_support.py b/modules/loaders/tests/test_gguf_support.py index ee43f5ac..9b65c2ba 100644 --- a/modules/loaders/tests/test_gguf_support.py +++ b/modules/loaders/tests/test_gguf_support.py @@ -261,3 +261,11 @@ def test_a_text_encoder_gguf_the_pack_refuses_is_refused_not_loaded_as_the_wrong monkeypatch.setattr(gguf_support, "_load_native", lambda path: ({"w": "native"}, {}, "native")) with pytest.raises(RuntimeError, match="not supported"): gguf_support.load_clip_state_dict("/x.gguf") + + +def test_a_text_encoder_gguf_without_the_pack_is_refused_not_dequantized_blind(monkeypatch): + monkeypatch.setattr(gguf_support, "backend", lambda: "native") + monkeypatch.setattr(gguf_support, "_load_native", lambda path: ({"w": "native"}, {}, "native")) + with pytest.raises(RuntimeError, match="ComfyUI-GGUF"): + gguf_support.load_clip_state_dict("/x.gguf") + assert gguf_support.load_state_dict("/x.gguf")[0] == {"w": "native"} # a diffusion model still loads natively