@melite/models-anima 0.1.4-alpha → 0.1.5-pre-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/lib/actions.js +14 -18
- package/lib/index.d.ts +2 -1
- package/lib/index.js +32 -0
- package/lib/promptTags.d.ts +9 -0
- package/lib/promptTags.js +49 -0
- package/package.json +2 -3
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Anima text-to-image family, a Cosmos-Predict2 anime and illustration diffusion lane with Danbooru-style prompting.
|
|
3
|
+
kind: package-library
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @melite/models-anima
|
|
7
|
+
|
|
8
|
+
The Anima family — anime and illustration text-to-image on the comfyui engine, built on the Cosmos-Predict2 base with Danbooru-style prompting. The package owns the declaration, the lane's weight facts, and the t2i action; the image-gen card binds the action and owns the compose surface around it.
|
|
9
|
+
|
|
10
|
+
The lane pins its weights in lane_inputs: unet `anima-base-v1.0.safetensors`, text encoder `qwen_3_06b_base.safetensors`, VAE `qwen_image_vae.safetensors`, clip type `stable_diffusion`, stock `EmptyLatentImage` latent. Three provisions rows download them (circlestone-labs/Anima, Qwen/Qwen3-0.6B-Base, Comfy-Org/Qwen-Image_ComfyUI). Defaults are 1024×1024, 30 steps, er_sde over simple, cfg 4; the recipes are draft (8 steps) and detailed (30 steps); the single F32 cell peaks at 20 GB. The prompt field is required — a draft without one refuses, because every image lane states what the picture is.
|
|
11
|
+
|
|
12
|
+
The family's action is t2i: the stock diffuse topology — CLIPTextEncode pair, EmptyLatentImage at card resolution, KSampler, decode and save under `<run>/gen`. The facts door reads the resolved lane_inputs into the closed T2IFacts shape; a drifted latent class refuses rather than silently rerouting. Anima boards no mods: loras, controlnets, and ip-adapter bags refuse loud, never silently drop.
|
|
13
|
+
|
|
14
|
+
## Declaration
|
|
15
|
+
|
|
16
|
+
`src/index.ts` declares the DECL and the `family-anima` plugin; `src/actions.ts` owns the t2i segment and its typed facts and params.
|
|
17
|
+
|
|
18
|
+
## Model Experience
|
|
19
|
+
|
|
20
|
+
#### What the model sees
|
|
21
|
+
|
|
22
|
+
None — the package contributes no model-visible input. The DECL serves the estate's model catalog (label, description, variants, defaults) and the image-gen card that boards the family; it registers no session events and writes no prompt segments.
|
|
23
|
+
|
|
24
|
+
#### Token effect
|
|
25
|
+
|
|
26
|
+
Zero-direct token effect — the package registers a model family and composes engine graphs; it writes no prompt text into any model request.
|
|
27
|
+
|
|
28
|
+
#### KV Cache effect
|
|
29
|
+
|
|
30
|
+
Independent — the package contributes no persistent prompt prefix, so registering or removing the family invalidates nothing cached.
|
|
31
|
+
|
|
32
|
+
## Known Limitations and Deferred Work
|
|
33
|
+
|
|
34
|
+
- **Required prompt** — the relations row makes prompt mandatory; a textless draft refuses at the family door instead of composing an undefined image.
|
|
35
|
+
- **F32 only** — one cell, 20 GB peak; no quantized variants ride the DECL.
|
|
36
|
+
- **No adapter flavor** — no loras or controlnets packs board the family; a stated adapter bag refuses loud, so adapter-driven styling is out of scope here.
|
package/lib/actions.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { loadTextPair, decodeSave, stackLoras, stackControlNets } from "@melite/comfyui-card-kit";
|
|
2
2
|
import { fireLoras, fireControlNets, refuseIPAdapterFiring } from "@melite/comfyui-card-kit/guard";
|
|
3
|
-
import {
|
|
3
|
+
import { parseDiffusionLaneFacts } from "@melite/comfyui-card-kit/facts";
|
|
4
4
|
import { diffusionParamRows } from "@melite/comfyui-card-kit/paramRows";
|
|
5
|
+
import { checkAnimaPromptTags } from "./promptTags.js";
|
|
5
6
|
/** The t2i facts door: the resolved lane_inputs parsed into the
|
|
6
7
|
* closed shape. A drifted latent class refuses here, never
|
|
7
8
|
* silently routes to another topology. `sampling_shift: 0` is
|
|
@@ -10,23 +11,11 @@ import { diffusionParamRows } from "@melite/comfyui-card-kit/paramRows";
|
|
|
10
11
|
* @param raw the resolved lane_inputs (family ⊕ variant)
|
|
11
12
|
* @returns the typed facts the segment factory reads */
|
|
12
13
|
export function parseT2IFacts(raw) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
const shift = raw.sampling_shift;
|
|
19
|
-
if (shift !== undefined && typeof shift !== "number") {
|
|
20
|
-
throw new Error(`anima t2i: lane_inputs.sampling_shift = ${JSON.stringify(shift)} — a number is required`);
|
|
21
|
-
}
|
|
22
|
-
return {
|
|
23
|
-
unet: text("unet"),
|
|
24
|
-
text_encoder: text("text_encoder"),
|
|
25
|
-
vae: text("vae"),
|
|
26
|
-
clip_type: text("clip_type"),
|
|
27
|
-
latent_node: node,
|
|
28
|
-
sampling_shift: shift,
|
|
29
|
-
};
|
|
14
|
+
// The checks + refusal prose live in the kit (J2 consolidation,
|
|
15
|
+
|
|
16
|
+
// family's own typed shape (the self-containment contract, B4).
|
|
17
|
+
const f = parseDiffusionLaneFacts(raw, "anima t2i", { key: "latent_node", node: "EmptyLatentImage" });
|
|
18
|
+
return { unet: f.unet, text_encoder: f.text_encoder, vae: f.vae, clip_type: f.clip_type, latent_node: f.node, sampling_shift: f.sampling_shift };
|
|
30
19
|
}
|
|
31
20
|
/** The text-to-image action: the stock diffuse topology — CLIP
|
|
32
21
|
* encoder pair (positive + negative), EmptyLatentImage at card
|
|
@@ -57,6 +46,13 @@ export const t2i = {
|
|
|
57
46
|
// vocabulary, mod-level owned; anima boards no pack, the picks
|
|
58
47
|
// are always empty — the call stays so a stated bag refuses).
|
|
59
48
|
unet = stackControlNets(g, unet, vae, fireControlNets(model, p));
|
|
49
|
+
// THE TAG-GRAMMAR DOOR (features/001 A4): the Danbooru grammar
|
|
50
|
+
// is mechanical — a malformed prompt refuses here with the
|
|
51
|
+
// fragment named, never reaches the encoder silently rewritten.
|
|
52
|
+
checkAnimaPromptTags("prompt", p.prompt);
|
|
53
|
+
if (p.negative_prompt !== undefined) {
|
|
54
|
+
checkAnimaPromptTags("negative_prompt", p.negative_prompt);
|
|
55
|
+
}
|
|
60
56
|
const pos = g.node("CLIPTextEncode", { clip, text: p.prompt });
|
|
61
57
|
const neg = g.node("CLIPTextEncode", { clip, text: p.negative_prompt ?? "" });
|
|
62
58
|
const latent = g.node(facts.latent_node, { batch_size: 1, width: p.width, height: p.height });
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Plugin } from "@deepseek-ai/cordis";
|
|
2
|
-
import type { ModelDecl } from
|
|
2
|
+
import type { ModelDecl } from '@melite/comfyui-card-kit/model-contract';
|
|
3
3
|
export declare const DECL: ModelDecl;
|
|
4
4
|
export declare const family: Plugin;
|
|
5
5
|
export { t2i, parseT2IFacts, type T2IFacts, type T2IParams } from "./actions.js";
|
|
6
|
+
export { family as default };
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.js
CHANGED
|
@@ -14,6 +14,11 @@ export const DECL = {
|
|
|
14
14
|
"cfg": 4
|
|
15
15
|
},
|
|
16
16
|
"genre": "image",
|
|
17
|
+
// MASK-C (the image-gen region gap — deliberate no-board): no
|
|
18
|
+
// mods key (absent ≡ boards nothing) — the anime T2I lane takes no
|
|
19
|
+
// region input upstream and no edit lane shares these weights.
|
|
20
|
+
// Serving the surface would promise what no lane builds; a stated
|
|
21
|
+
// mask refuses LOUD at admission like every undeclared key.
|
|
17
22
|
"variants": [
|
|
18
23
|
{
|
|
19
24
|
"id": "standard",
|
|
@@ -45,6 +50,14 @@ export const DECL = {
|
|
|
45
50
|
"wire_defaults": { "steps": 30 },
|
|
46
51
|
"cells": [],
|
|
47
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"id": "settled-negative",
|
|
55
|
+
"label": "Settled negative",
|
|
56
|
+
"hint": "Stamps the guide's settled negative set. TRIM RULE: the negative stays short — broadening a negative concept degrades quality, so this row is the whole set, never a base to widen.",
|
|
57
|
+
"group": "Recipe",
|
|
58
|
+
"wire_defaults": { "negative_prompt": "worst quality, low quality, score_1, score_2, score_3, artist name" },
|
|
59
|
+
"cells": [],
|
|
60
|
+
},
|
|
48
61
|
{
|
|
49
62
|
"id": "default",
|
|
50
63
|
"label": "Default",
|
|
@@ -69,6 +82,20 @@ export const DECL = {
|
|
|
69
82
|
"default": "default"
|
|
70
83
|
}
|
|
71
84
|
],
|
|
85
|
+
// THE LANE SURFACE (the edit-2511 precedent): exactly the knobs the
|
|
86
|
+
// create card serves — no reference seat (operator ruling,
|
|
87
|
+
|
|
88
|
+
"params": [
|
|
89
|
+
"prompt",
|
|
90
|
+
"negative_prompt",
|
|
91
|
+
"width",
|
|
92
|
+
"height",
|
|
93
|
+
"seed",
|
|
94
|
+
"steps",
|
|
95
|
+
"cfg",
|
|
96
|
+
"sampler",
|
|
97
|
+
"scheduler",
|
|
98
|
+
],
|
|
72
99
|
"lane_inputs": {
|
|
73
100
|
"clip_type": "stable_diffusion",
|
|
74
101
|
"latent_node": "EmptyLatentImage",
|
|
@@ -138,4 +165,9 @@ export const family = {
|
|
|
138
165
|
// segment the image-gen card binds. The card imports this beside
|
|
139
166
|
// the DECL — the family's whole offer, one face.
|
|
140
167
|
export { t2i, parseT2IFacts } from "./actions.js";
|
|
168
|
+
// The Loader-row face: DSH loads plugin rows by bare specifier and
|
|
169
|
+
// unwraps `exports.default ?? exports` (vendor/cordis_plugins/loader
|
|
170
|
+
// unwrapExports) — the default export IS the row-loadable plugin. The
|
|
171
|
+
// named `family` stays the library face (engine loadFamilies).
|
|
172
|
+
export { family as default };
|
|
141
173
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Refuse a prompt or negative that breaks the Danbooru tag
|
|
2
|
+
* grammar. Called from the t2i build before any node renders —
|
|
3
|
+
* a malformed grammar dies at compose time with the offending
|
|
4
|
+
* fragment named, never at the encoder.
|
|
5
|
+
* @param field the param seat being judged ("prompt" or "negative_prompt")
|
|
6
|
+
* @param text the raw param value
|
|
7
|
+
* @throws Error naming the refusal class and the offending fragment */
|
|
8
|
+
export declare function checkAnimaPromptTags(field: "prompt" | "negative_prompt", text: string): void;
|
|
9
|
+
//# sourceMappingURL=promptTags.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @melite/models-anima/src/promptTags — the Danbooru tag-grammar
|
|
2
|
+
|
|
3
|
+
// is mechanical, so the family REFUSES a prompt that breaks it —
|
|
4
|
+
// never silently rewrites (a rewritten prompt is a different
|
|
5
|
+
// picture, and the author never learns their tags are malformed).
|
|
6
|
+
// Three refusal classes, one door: missing space after a comma,
|
|
7
|
+
// doubled comma, underscore in a tag. The score-tag exception is
|
|
8
|
+
// the recipe's own rule (score_1..score_9 are the one legal
|
|
9
|
+
// underscore form — "spaces instead of underscores, except score
|
|
10
|
+
// tags").
|
|
11
|
+
/** An underscore-bearing token that is NOT a score tag
|
|
12
|
+
* (score_[0-9] with optional decimals) — the recipe's one legal
|
|
13
|
+
* underscore form. */
|
|
14
|
+
function isScoreTag(token) {
|
|
15
|
+
return /^score_[0-9](\.[0-9]+)?$/.test(token);
|
|
16
|
+
}
|
|
17
|
+
/** Refuse a prompt or negative that breaks the Danbooru tag
|
|
18
|
+
* grammar. Called from the t2i build before any node renders —
|
|
19
|
+
* a malformed grammar dies at compose time with the offending
|
|
20
|
+
* fragment named, never at the encoder.
|
|
21
|
+
* @param field the param seat being judged ("prompt" or "negative_prompt")
|
|
22
|
+
* @param text the raw param value
|
|
23
|
+
* @throws Error naming the refusal class and the offending fragment */
|
|
24
|
+
export function checkAnimaPromptTags(field, text) {
|
|
25
|
+
const segments = text.split(",");
|
|
26
|
+
for (let i = 0; i < segments.length; i += 1) {
|
|
27
|
+
const seg = segments[i];
|
|
28
|
+
// class 2 — doubled comma: an empty segment anywhere except a
|
|
29
|
+
// trailing one (a prompt ending in a single comma is the
|
|
30
|
+
// prefix convention, not a doubled separator).
|
|
31
|
+
if (seg.trim() === "" && i < segments.length - 1) {
|
|
32
|
+
throw new Error(`anima ${field}: doubled comma at segment ${i + 1} — one comma, one space, then the next tag (${JSON.stringify(text)})`);
|
|
33
|
+
}
|
|
34
|
+
// class 1 — missing space after a comma: the separator grammar
|
|
35
|
+
// is ", " (comma + space); a comma glued to the next tag
|
|
36
|
+
// refuses (the first segment has no comma in front of it).
|
|
37
|
+
if (i > 0 && seg !== "" && !seg.startsWith(" ")) {
|
|
38
|
+
throw new Error(`anima ${field}: missing space after comma before ${JSON.stringify(seg)} — the separator is comma + space (${JSON.stringify(text)})`);
|
|
39
|
+
}
|
|
40
|
+
// class 3 — underscore in a tag: Danbooru tags use spaces;
|
|
41
|
+
// the score tags are the exception, per the recipe.
|
|
42
|
+
for (const token of seg.trim().split(/\s+/)) {
|
|
43
|
+
if (token.includes("_") && !isScoreTag(token)) {
|
|
44
|
+
throw new Error(`anima ${field}: underscore in tag ${JSON.stringify(token)} — tags use spaces; only score tags (score_1..score_9) keep the underscore (${JSON.stringify(text)})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=promptTags.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melite/models-anima",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5-pre-alpha",
|
|
4
4
|
"license": "SSPL-1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"./package.json": "./package.json"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@melite/comfyui-
|
|
15
|
-
"@melite/comfyui-card-kit": "0.1.4-alpha"
|
|
14
|
+
"@melite/comfyui-card-kit": "0.1.5-pre-alpha"
|
|
16
15
|
},
|
|
17
16
|
"devDependencies": {
|
|
18
17
|
"@types/node": "^22.20.0",
|