@nodaro/prompts 1.11.0 → 1.13.0
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/dist/index.cjs +627 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +726 -33
- package/dist/index.d.ts +726 -33
- package/dist/index.js +598 -179
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/entity-convergence-image.test.ts.snap +19 -0
- package/src/__tests__/animal-getters-parity.test.ts +82 -0
- package/src/__tests__/assemble-image-input-cap.test.ts +236 -0
- package/src/__tests__/assemble-image-input.test.ts +100 -19
- package/src/__tests__/assemble-video-input-cap.test.ts +442 -0
- package/src/__tests__/assemble-video-input.test.ts +167 -33
- package/src/__tests__/direction-hint-token-safety.test.ts +21 -0
- package/src/__tests__/entity-convergence-image.test.ts +374 -0
- package/src/__tests__/location-convergence-image.test.ts +29 -1
- package/src/__tests__/location-default-role-image.test.ts +166 -0
- package/src/__tests__/mention-splice-spacing.test.ts +257 -0
- package/src/__tests__/prompt-style-section.test.ts +345 -0
- package/src/__tests__/read-node-subject.test.ts +140 -0
- package/src/__tests__/style-section-boundary.test.ts +179 -0
- package/src/__tests__/subject-fold.test.ts +251 -0
- package/src/__tests__/subject-registry.test.ts +312 -0
- package/src/assemble-image-input.ts +169 -41
- package/src/assemble-video-input.ts +200 -25
- package/src/direction-registry.ts +116 -28
- package/src/hint-shedding.ts +87 -0
- package/src/index.ts +3 -0
- package/src/parameter-prompt-hint.ts +8 -7
- package/src/picker-catalogs.ts +14 -7
- package/src/prompt-builder.ts +628 -88
- package/src/prompt-hint-join.ts +9 -0
- package/src/prompt-style-section.ts +256 -0
- package/src/read-node-direction.ts +60 -1
- package/src/subject-registry.ts +464 -0
- package/src/video-reference-resolver.ts +5 -2
package/dist/index.cjs
CHANGED
|
@@ -9241,7 +9241,7 @@ function objectOptions(arr, phrase) {
|
|
|
9241
9241
|
label: e.label,
|
|
9242
9242
|
description: e.description,
|
|
9243
9243
|
category: e.subcategory,
|
|
9244
|
-
promptHint: phrase(e
|
|
9244
|
+
promptHint: phrase(e),
|
|
9245
9245
|
// Object entities have no `promptHint` field of their own (it is
|
|
9246
9246
|
// synthesized above), so the term cannot come from `resolveTerm`'s
|
|
9247
9247
|
// empty-hint rule: an authored `term` wins, and otherwise the label IS the
|
|
@@ -9573,7 +9573,7 @@ var SINGLE_CATALOGS = [
|
|
|
9573
9573
|
defaultValue: "dog-golden-retriever",
|
|
9574
9574
|
categoryOrder: shared.ANIMAL_SUBCATEGORY_ORDER,
|
|
9575
9575
|
categoryLabels: shared.ANIMAL_SUBCATEGORY_LABELS,
|
|
9576
|
-
options: objectOptions(shared.ANIMALS, (
|
|
9576
|
+
options: objectOptions(shared.ANIMALS, (e) => shared.getAnimalPromptHint(e.id))
|
|
9577
9577
|
},
|
|
9578
9578
|
{
|
|
9579
9579
|
nodeType: "vehicle",
|
|
@@ -9584,7 +9584,7 @@ var SINGLE_CATALOGS = [
|
|
|
9584
9584
|
defaultValue: "sedan",
|
|
9585
9585
|
categoryOrder: shared.VEHICLE_SUBCATEGORY_ORDER,
|
|
9586
9586
|
categoryLabels: shared.VEHICLE_SUBCATEGORY_LABELS,
|
|
9587
|
-
options: objectOptions(shared.VEHICLES, (
|
|
9587
|
+
options: objectOptions(shared.VEHICLES, (e) => `featuring a ${e.label.toLowerCase()}, ${e.description}`)
|
|
9588
9588
|
},
|
|
9589
9589
|
{
|
|
9590
9590
|
nodeType: "weapon",
|
|
@@ -9595,7 +9595,7 @@ var SINGLE_CATALOGS = [
|
|
|
9595
9595
|
defaultValue: "katana",
|
|
9596
9596
|
categoryOrder: shared.WEAPON_SUBCATEGORY_ORDER,
|
|
9597
9597
|
categoryLabels: shared.WEAPON_SUBCATEGORY_LABELS,
|
|
9598
|
-
options: objectOptions(shared.WEAPONS, (
|
|
9598
|
+
options: objectOptions(shared.WEAPONS, (e) => `with a ${e.label.toLowerCase()}, ${e.description}`)
|
|
9599
9599
|
},
|
|
9600
9600
|
{
|
|
9601
9601
|
nodeType: "furniture",
|
|
@@ -9606,7 +9606,7 @@ var SINGLE_CATALOGS = [
|
|
|
9606
9606
|
defaultValue: "sofa",
|
|
9607
9607
|
categoryOrder: shared.FURNITURE_SUBCATEGORY_ORDER,
|
|
9608
9608
|
categoryLabels: shared.FURNITURE_SUBCATEGORY_LABELS,
|
|
9609
|
-
options: objectOptions(shared.FURNITURE, (
|
|
9609
|
+
options: objectOptions(shared.FURNITURE, (e) => `including a ${e.label.toLowerCase()}, ${e.description}`)
|
|
9610
9610
|
},
|
|
9611
9611
|
{
|
|
9612
9612
|
nodeType: "held-prop",
|
|
@@ -9974,13 +9974,16 @@ function resolveBaseHint(type, data, mode = "full") {
|
|
|
9974
9974
|
return withCustomText(data, byMode(mode, getLoopSubjectPromptHint, getLoopSubjectTerm)(asStr(data.loopSubject)));
|
|
9975
9975
|
case "material":
|
|
9976
9976
|
return withCustomText(data, buildMaterialHints(data.material, mode));
|
|
9977
|
-
|
|
9978
|
-
|
|
9977
|
+
// Animal is the one Object-entity catalog whose phrasing has a single
|
|
9978
|
+
// owner: `@nodaro/shared`'s `getAnimalPromptHint` / `getAnimalTerm`, which
|
|
9979
|
+
// the picker-catalog funnel calls too. Both getters already return "" on a
|
|
9980
|
+
// miss, so the entry lookup and the `animal ? … : ""` guard are the
|
|
9981
|
+
// getters' job now, not this switch's.
|
|
9982
|
+
case "animal":
|
|
9979
9983
|
return withCustomText(
|
|
9980
9984
|
data,
|
|
9981
|
-
|
|
9985
|
+
byMode(mode, shared.getAnimalPromptHint, shared.getAnimalTerm)(asStr(data.animal))
|
|
9982
9986
|
);
|
|
9983
|
-
}
|
|
9984
9987
|
case "vehicle": {
|
|
9985
9988
|
const vehicle = shared.getVehicle(asStr(data.vehicle));
|
|
9986
9989
|
return withCustomText(
|
|
@@ -10214,6 +10217,218 @@ function applyTemplate(template, vars) {
|
|
|
10214
10217
|
template
|
|
10215
10218
|
);
|
|
10216
10219
|
}
|
|
10220
|
+
|
|
10221
|
+
// src/prompt-hint-join.ts
|
|
10222
|
+
var PROMPT_HINT_SEPARATOR = ". ";
|
|
10223
|
+
function joinPromptHints(userPrompt, hints) {
|
|
10224
|
+
if (hints.length === 0) return userPrompt;
|
|
10225
|
+
return [userPrompt.trim(), ...hints].filter((p) => p.length > 0).join(PROMPT_HINT_SEPARATOR);
|
|
10226
|
+
}
|
|
10227
|
+
|
|
10228
|
+
// src/direction-registry.ts
|
|
10229
|
+
var perId = (full, compact) => (ids, mode) => {
|
|
10230
|
+
const out = [];
|
|
10231
|
+
for (const id of ids) {
|
|
10232
|
+
const frag = mode === "compact" ? compact(id) : full(id);
|
|
10233
|
+
if (frag.length > 0) out.push(frag);
|
|
10234
|
+
}
|
|
10235
|
+
return out;
|
|
10236
|
+
};
|
|
10237
|
+
var viaListBuilder = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
|
|
10238
|
+
var viaStringBuilder = (build) => (ids, mode) => {
|
|
10239
|
+
const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
|
|
10240
|
+
return s.length > 0 ? [s] : [];
|
|
10241
|
+
};
|
|
10242
|
+
var viaMood = (ids, mode) => buildMoodHints({ mood: ids.length === 1 ? ids[0] : [...ids] }, mode).filter(
|
|
10243
|
+
(s) => s.length > 0
|
|
10244
|
+
);
|
|
10245
|
+
var framing = perId(getFramingPromptHint, getFramingTerm);
|
|
10246
|
+
var lighting = perId(getLightingPromptHint, getLightingTerm);
|
|
10247
|
+
var exposure = perId(getExposurePromptHint, getExposureTerm);
|
|
10248
|
+
var temporal = perId(getTemporalPromptHint, getTemporalTerm);
|
|
10249
|
+
var DIRECTION_FIELDS = [
|
|
10250
|
+
{ key: "cameraMotion", surface: "video", family: "motion", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },
|
|
10251
|
+
// Composition (the Framing catalog, one row per category).
|
|
10252
|
+
{ key: "shotSize", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10253
|
+
{ key: "angle", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10254
|
+
{ key: "coverage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10255
|
+
{ key: "composition", surface: "both", family: "look", maxPicks: 2, render: framing },
|
|
10256
|
+
{ key: "vantage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10257
|
+
{ key: "pose", surface: "both", family: "look", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },
|
|
10258
|
+
{ key: "compositionEffect", surface: "both", family: "look", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },
|
|
10259
|
+
// Camera.
|
|
10260
|
+
{ key: "cameraFormat", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },
|
|
10261
|
+
{ key: "lens", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
10262
|
+
// Exposure (stills only — a video's exposure rides its own temporal levers).
|
|
10263
|
+
{ key: "aperture", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10264
|
+
{ key: "shutterSpeed", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10265
|
+
{ key: "isoValue", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10266
|
+
// Light (the Lighting catalog, one row per category).
|
|
10267
|
+
{ key: "timeOfDay", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10268
|
+
{ key: "lightingStyle", surface: "both", family: "look", maxPicks: 2, render: lighting },
|
|
10269
|
+
{ key: "lightingDirection", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10270
|
+
{ key: "lightingRatio", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10271
|
+
{ key: "colorTemperature", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10272
|
+
{ key: "colorLook", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getColorLookPromptHint, getColorLookTerm) },
|
|
10273
|
+
{ key: "atmosphere", surface: "both", family: "look", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },
|
|
10274
|
+
{ key: "postProcess", surface: "image", family: "look", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },
|
|
10275
|
+
// Style.
|
|
10276
|
+
{ key: "style", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getStylePromptHint, getStyleTerm) },
|
|
10277
|
+
{ key: "mood", surface: "both", family: "look", maxPicks: 2, render: viaMood },
|
|
10278
|
+
{ key: "aesthetic", surface: "both", family: "look", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },
|
|
10279
|
+
{ key: "photoGenre", surface: "image", family: "look", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },
|
|
10280
|
+
{ key: "photographer", surface: "image", family: "look", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },
|
|
10281
|
+
{ key: "renderQuality", surface: "image", family: "look", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },
|
|
10282
|
+
// Scene.
|
|
10283
|
+
{ key: "setting", surface: "both", family: "look", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },
|
|
10284
|
+
{ key: "era", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },
|
|
10285
|
+
{ key: "backdrop", surface: "both", family: "look", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },
|
|
10286
|
+
// Motion & time.
|
|
10287
|
+
{ key: "actionFx", surface: "video", family: "motion", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },
|
|
10288
|
+
{ key: "temporalSpeed", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10289
|
+
{ key: "temporalFreeze", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10290
|
+
{ key: "temporalDirection", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10291
|
+
{ key: "temporalShutter", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10292
|
+
{ key: "transition", surface: "video", family: "motion", maxPicks: 2, render: perId(getTransitionPromptHint, getTransitionTerm) },
|
|
10293
|
+
{ key: "loopSubject", surface: "video", family: "motion", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },
|
|
10294
|
+
// ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact
|
|
10295
|
+
// `composePromptText` order, so every pre-registry caller is byte-identical.
|
|
10296
|
+
{ key: "framingId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10297
|
+
{ key: "framingAngleId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10298
|
+
{ key: "lightingId", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10299
|
+
{ key: "lensId", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
10300
|
+
{ key: "cameraFormatId", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) }
|
|
10301
|
+
];
|
|
10302
|
+
var DIRECTION_SPECS = DIRECTION_FIELDS;
|
|
10303
|
+
var DIRECTION_KEYS = DIRECTION_FIELDS.map((f) => f.key);
|
|
10304
|
+
var FILM_STYLE_KEYS = DIRECTION_SPECS.filter(
|
|
10305
|
+
(f) => f.styleGroup === "film"
|
|
10306
|
+
).map((f) => f.key);
|
|
10307
|
+
var IMAGE_HINT_MODE_DEFAULT = "full";
|
|
10308
|
+
var VIDEO_HINT_MODE_DEFAULT = { look: "full", motion: "compact" };
|
|
10309
|
+
function modeForFamily(mode, family) {
|
|
10310
|
+
return typeof mode === "string" ? mode : family === "motion" ? mode.motion : mode.look;
|
|
10311
|
+
}
|
|
10312
|
+
var DIRECTION_ARRAY_CEILING = 8;
|
|
10313
|
+
var DIRECTION_ID_MAX_CHARS = 100;
|
|
10314
|
+
function normalizeDirectionIds(value, maxPicks) {
|
|
10315
|
+
const ids = [];
|
|
10316
|
+
if (typeof value === "string") {
|
|
10317
|
+
if (value) ids.push(value);
|
|
10318
|
+
} else if (Array.isArray(value)) {
|
|
10319
|
+
for (const v of value) {
|
|
10320
|
+
if (ids.length >= maxPicks) break;
|
|
10321
|
+
if (typeof v === "string" && v && !ids.includes(v)) ids.push(v);
|
|
10322
|
+
}
|
|
10323
|
+
}
|
|
10324
|
+
return ids.slice(0, maxPicks);
|
|
10325
|
+
}
|
|
10326
|
+
function directionFieldsForSurface(surface) {
|
|
10327
|
+
return DIRECTION_SPECS.filter((f) => f.surface === "both" || f.surface === surface);
|
|
10328
|
+
}
|
|
10329
|
+
function renderDirectionHintClauses(direction, opts) {
|
|
10330
|
+
if (!direction) return [];
|
|
10331
|
+
const mode = opts.mode ?? "full";
|
|
10332
|
+
const out = [];
|
|
10333
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10334
|
+
for (const spec of DIRECTION_SPECS) {
|
|
10335
|
+
if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
|
|
10336
|
+
const ids = normalizeDirectionIds(
|
|
10337
|
+
direction[spec.key],
|
|
10338
|
+
spec.maxPicks
|
|
10339
|
+
);
|
|
10340
|
+
if (ids.length === 0) continue;
|
|
10341
|
+
for (const hint of spec.render(ids, modeForFamily(mode, spec.family))) {
|
|
10342
|
+
if (hint.length > 0 && !seen.has(hint)) {
|
|
10343
|
+
seen.add(hint);
|
|
10344
|
+
out.push({
|
|
10345
|
+
key: spec.key,
|
|
10346
|
+
family: spec.family,
|
|
10347
|
+
...spec.styleGroup !== void 0 ? { styleGroup: spec.styleGroup } : {},
|
|
10348
|
+
text: hint
|
|
10349
|
+
});
|
|
10350
|
+
}
|
|
10351
|
+
}
|
|
10352
|
+
}
|
|
10353
|
+
return out;
|
|
10354
|
+
}
|
|
10355
|
+
function renderDirectionHints(direction, opts) {
|
|
10356
|
+
return renderDirectionHintClauses(direction, opts).map((c) => c.text);
|
|
10357
|
+
}
|
|
10358
|
+
|
|
10359
|
+
// src/prompt-style-section.ts
|
|
10360
|
+
var STYLE_SECTION_HEADER = "[style]:";
|
|
10361
|
+
var STYLE_SECTION_GAP = "\n\n";
|
|
10362
|
+
var STYLE_SECTION_OPENING = `${STYLE_SECTION_GAP}${STYLE_SECTION_HEADER}
|
|
10363
|
+
`;
|
|
10364
|
+
function splitStyleSection(prompt) {
|
|
10365
|
+
const at = prompt.lastIndexOf(STYLE_SECTION_OPENING);
|
|
10366
|
+
if (at >= 0) {
|
|
10367
|
+
return { body: prompt.slice(0, at), section: prompt.slice(at + STYLE_SECTION_GAP.length) };
|
|
10368
|
+
}
|
|
10369
|
+
return prompt.startsWith(`${STYLE_SECTION_HEADER}
|
|
10370
|
+
`) ? { body: "", section: prompt } : { body: prompt, section: "" };
|
|
10371
|
+
}
|
|
10372
|
+
function insertBeforeStyleSection(prompt, lines) {
|
|
10373
|
+
if (lines.length === 0) return prompt;
|
|
10374
|
+
const block = lines.join("\n");
|
|
10375
|
+
const { body, section } = splitStyleSection(prompt);
|
|
10376
|
+
if (section.length === 0) return `${prompt}
|
|
10377
|
+
${block}`;
|
|
10378
|
+
return `${body.length > 0 ? `${body}
|
|
10379
|
+
${block}` : block}${STYLE_SECTION_GAP}${section}`;
|
|
10380
|
+
}
|
|
10381
|
+
function endsInsideStyleSection(prompt) {
|
|
10382
|
+
const at = prompt.lastIndexOf(STYLE_SECTION_GAP);
|
|
10383
|
+
const lastBlock = at >= 0 ? prompt.slice(at + STYLE_SECTION_GAP.length) : prompt;
|
|
10384
|
+
return lastBlock.startsWith(`${STYLE_SECTION_HEADER}
|
|
10385
|
+
`);
|
|
10386
|
+
}
|
|
10387
|
+
function styleSlotFor(row) {
|
|
10388
|
+
if (row.family === "motion") return "body";
|
|
10389
|
+
return row.styleGroup === "film" ? "film" : "scene";
|
|
10390
|
+
}
|
|
10391
|
+
function asBodyClauses(texts) {
|
|
10392
|
+
return texts.map((text) => ({ text, slot: "body" }));
|
|
10393
|
+
}
|
|
10394
|
+
function partitionStyleClauses(direction, opts) {
|
|
10395
|
+
return renderDirectionHintClauses(direction, opts).map((clause) => ({
|
|
10396
|
+
text: clause.text,
|
|
10397
|
+
slot: styleSlotFor(clause)
|
|
10398
|
+
}));
|
|
10399
|
+
}
|
|
10400
|
+
function styleSectionFromClauses(clauses) {
|
|
10401
|
+
const line = (slot) => clauses.filter((c) => c.slot === slot).map((c) => c.text).join(PROMPT_HINT_SEPARATOR);
|
|
10402
|
+
const lines = [line("film"), line("scene")].filter((l) => l.length > 0);
|
|
10403
|
+
return lines.length === 0 ? "" : `${STYLE_SECTION_HEADER}
|
|
10404
|
+
${lines.join("\n")}`;
|
|
10405
|
+
}
|
|
10406
|
+
function renderStyleSection(direction, opts) {
|
|
10407
|
+
return styleSectionFromClauses(partitionStyleClauses(direction, opts));
|
|
10408
|
+
}
|
|
10409
|
+
function composeSectionedPrompt(userPrompt, clauses, structuredFragment) {
|
|
10410
|
+
const bodyHints = [
|
|
10411
|
+
...clauses.filter((c) => c.slot === "body").map((c) => c.text),
|
|
10412
|
+
structuredFragment
|
|
10413
|
+
].filter((p) => p.length > 0);
|
|
10414
|
+
const section = styleSectionFromClauses(clauses);
|
|
10415
|
+
if (section.length === 0) {
|
|
10416
|
+
return bodyHints.length === 0 ? userPrompt : joinPromptHints(userPrompt ?? "", bodyHints);
|
|
10417
|
+
}
|
|
10418
|
+
const body = bodyHints.length > 0 ? joinPromptHints(userPrompt ?? "", bodyHints) : (userPrompt ?? "").trim();
|
|
10419
|
+
return body.length > 0 ? `${body}${STYLE_SECTION_GAP}${section}` : section;
|
|
10420
|
+
}
|
|
10421
|
+
function sectionedClauseCosts(userPrompt, clauses, structuredFragment) {
|
|
10422
|
+
const lengthAt = (kept) => composeSectionedPrompt(userPrompt, clauses.slice(0, kept), structuredFragment)?.length ?? 0;
|
|
10423
|
+
const costs = [];
|
|
10424
|
+
let below = lengthAt(0);
|
|
10425
|
+
for (let i = 0; i < clauses.length; i++) {
|
|
10426
|
+
const at = lengthAt(i + 1);
|
|
10427
|
+
costs.push(at - below);
|
|
10428
|
+
below = at;
|
|
10429
|
+
}
|
|
10430
|
+
return costs;
|
|
10431
|
+
}
|
|
10217
10432
|
function composeIdentityDescPart(subject, canonicalDesc, elementInjection) {
|
|
10218
10433
|
const parts = [];
|
|
10219
10434
|
const c = canonicalDesc?.trim();
|
|
@@ -10284,6 +10499,11 @@ ${resolvedPrompt}`;
|
|
|
10284
10499
|
}
|
|
10285
10500
|
return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs };
|
|
10286
10501
|
}
|
|
10502
|
+
function spliceMentionPhrase(prompt, offset, tokenLength, phrase) {
|
|
10503
|
+
const before = prompt.slice(0, offset).replace(/(?<=\S)[^\S\r\n]{2,}$/, " ");
|
|
10504
|
+
const after = prompt.slice(offset + tokenLength).replace(/^[^\S\r\n]{2,}/, " ");
|
|
10505
|
+
return before + phrase + after;
|
|
10506
|
+
}
|
|
10287
10507
|
function resolveCharacterMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
10288
10508
|
const bySlug = /* @__PURE__ */ new Map();
|
|
10289
10509
|
const byVariant = /* @__PURE__ */ new Map();
|
|
@@ -10322,7 +10542,7 @@ function resolveCharacterMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10322
10542
|
let resolvedPrompt = prompt;
|
|
10323
10543
|
for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
|
|
10324
10544
|
const phrase = shared.roleToPhrase(m.role, bindingFor(m.url));
|
|
10325
|
-
resolvedPrompt = resolvedPrompt
|
|
10545
|
+
resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
|
|
10326
10546
|
}
|
|
10327
10547
|
const lockLines = [];
|
|
10328
10548
|
const elementDirectives = [];
|
|
@@ -10353,16 +10573,21 @@ function locationModeDirective(mode) {
|
|
|
10353
10573
|
}
|
|
10354
10574
|
}
|
|
10355
10575
|
function locationModeToRole(mode) {
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10576
|
+
return roleBearingLocationMode(mode) ?? shared.defaultRoleForSource("wired-location");
|
|
10577
|
+
}
|
|
10578
|
+
function roleBearingLocationMode(mode) {
|
|
10579
|
+
const m = mode?.trim();
|
|
10580
|
+
if (!m) return null;
|
|
10581
|
+
return shared.REFERENCE_ROLE_PRESETS["wired-location"].includes(m) ? m : null;
|
|
10582
|
+
}
|
|
10583
|
+
function resolveLocationRole(tokenRole, tokenUsageMode, ref) {
|
|
10584
|
+
const explicitRole = tokenRole?.trim();
|
|
10585
|
+
if (explicitRole) return shared.normalizeRoleSlug(explicitRole);
|
|
10586
|
+
const modeRole = roleBearingLocationMode(tokenUsageMode);
|
|
10587
|
+
if (modeRole) return modeRole;
|
|
10588
|
+
const nodeRole = ref.defaultRole?.trim();
|
|
10589
|
+
if (nodeRole) return shared.normalizeRoleSlug(nodeRole);
|
|
10590
|
+
return locationModeToRole(ref.defaultUsageMode ?? shared.DEFAULT_LOCATION_USAGE_MODE);
|
|
10366
10591
|
}
|
|
10367
10592
|
function resolveLocationMentions(prompt, tokens, refs) {
|
|
10368
10593
|
const bySlug = /* @__PURE__ */ new Map();
|
|
@@ -10444,8 +10669,7 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10444
10669
|
mentionedLocationSlugs.add(t.locationSlug);
|
|
10445
10670
|
refByUrl.set(match.url, match);
|
|
10446
10671
|
if (t.lock !== void 0) lockOverrideByUrl.set(match.url, t.lock);
|
|
10447
|
-
const
|
|
10448
|
-
const role = t.role ? shared.normalizeRoleSlug(t.role) : locationModeToRole(mode);
|
|
10672
|
+
const role = resolveLocationRole(t.role, t.usageMode, match);
|
|
10449
10673
|
matched.push({ token: t.token, offset: t.offset, url: match.url, role });
|
|
10450
10674
|
}
|
|
10451
10675
|
const slotByUrl = /* @__PURE__ */ new Map();
|
|
@@ -10459,7 +10683,7 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10459
10683
|
let resolvedPrompt = prompt;
|
|
10460
10684
|
for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
|
|
10461
10685
|
const phrase = shared.roleToPhrase(m.role, bindingFor(m.url));
|
|
10462
|
-
resolvedPrompt = resolvedPrompt
|
|
10686
|
+
resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
|
|
10463
10687
|
}
|
|
10464
10688
|
const lockLines = [];
|
|
10465
10689
|
const elementDirectives = [];
|
|
@@ -10508,7 +10732,7 @@ function resolveImageMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10508
10732
|
let resolvedPrompt = prompt;
|
|
10509
10733
|
for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
|
|
10510
10734
|
const phrase = shared.roleToPhrase(m.role, bindingFor(m.url));
|
|
10511
|
-
resolvedPrompt = resolvedPrompt
|
|
10735
|
+
resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
|
|
10512
10736
|
}
|
|
10513
10737
|
const lockLines = [];
|
|
10514
10738
|
const elementDirectives = [];
|
|
@@ -10526,6 +10750,60 @@ function resolveImageMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
|
10526
10750
|
}
|
|
10527
10751
|
return { prompt: resolvedPrompt, additionalUrls, lockLines, elementDirectives };
|
|
10528
10752
|
}
|
|
10753
|
+
function resolveEntityMentionsHybrid(prompt, tokens, refs, existingUrls) {
|
|
10754
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
10755
|
+
for (const source of ["wired-creature", "wired-object"]) {
|
|
10756
|
+
for (const r of refs) {
|
|
10757
|
+
if (r.source !== source) continue;
|
|
10758
|
+
const slug = shared.entityMentionSlugForRef(r);
|
|
10759
|
+
if (!slug) continue;
|
|
10760
|
+
if (!bySlug.has(slug)) bySlug.set(slug, r);
|
|
10761
|
+
}
|
|
10762
|
+
}
|
|
10763
|
+
const additionalUrls = [];
|
|
10764
|
+
const mentionedUrls = /* @__PURE__ */ new Set();
|
|
10765
|
+
const refByUrl = /* @__PURE__ */ new Map();
|
|
10766
|
+
const lockOverrideByUrl = /* @__PURE__ */ new Map();
|
|
10767
|
+
const matched = [];
|
|
10768
|
+
for (const t of tokens) {
|
|
10769
|
+
const match = bySlug.get(t.entitySlug);
|
|
10770
|
+
if (!match || !match.url) continue;
|
|
10771
|
+
additionalUrls.push(match.url);
|
|
10772
|
+
mentionedUrls.add(match.url);
|
|
10773
|
+
refByUrl.set(match.url, match);
|
|
10774
|
+
if (t.lock !== void 0) lockOverrideByUrl.set(match.url, t.lock);
|
|
10775
|
+
const role = (t.role ?? "").trim() || shared.resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source);
|
|
10776
|
+
matched.push({ token: t.token, offset: t.offset, url: match.url, role });
|
|
10777
|
+
}
|
|
10778
|
+
const slotByUrl = /* @__PURE__ */ new Map();
|
|
10779
|
+
for (const u of [...existingUrls, ...additionalUrls]) {
|
|
10780
|
+
if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1);
|
|
10781
|
+
}
|
|
10782
|
+
const bindingFor = (url2) => {
|
|
10783
|
+
const slot = slotByUrl.get(url2);
|
|
10784
|
+
return slot ? `reference image ${slotToLetter(slot)}` : "the reference image";
|
|
10785
|
+
};
|
|
10786
|
+
let resolvedPrompt = prompt;
|
|
10787
|
+
for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
|
|
10788
|
+
const phrase = shared.roleToPhrase(m.role, bindingFor(m.url));
|
|
10789
|
+
resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
|
|
10790
|
+
}
|
|
10791
|
+
const lockLines = [];
|
|
10792
|
+
const elementDirectives = [];
|
|
10793
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
10794
|
+
for (const m of matched) {
|
|
10795
|
+
if (seenUrls.has(m.url)) continue;
|
|
10796
|
+
seenUrls.add(m.url);
|
|
10797
|
+
const ref = refByUrl.get(m.url);
|
|
10798
|
+
if (!ref) continue;
|
|
10799
|
+
const binding = bindingFor(m.url);
|
|
10800
|
+
const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
|
|
10801
|
+
if (lock) lockLines.push(lock);
|
|
10802
|
+
const inject = ref.elementInjection?.trim();
|
|
10803
|
+
if (inject) elementDirectives.push(inject);
|
|
10804
|
+
}
|
|
10805
|
+
return { prompt: resolvedPrompt, additionalUrls, mentionedUrls, lockLines, elementDirectives };
|
|
10806
|
+
}
|
|
10529
10807
|
function buildCanonicalFallback(refs, mentionedSlugs, startIndex) {
|
|
10530
10808
|
const directiveLines = [];
|
|
10531
10809
|
const urls = [];
|
|
@@ -10684,7 +10962,7 @@ function renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, covere
|
|
|
10684
10962
|
if (!slot) continue;
|
|
10685
10963
|
seenUrls.add(r.url);
|
|
10686
10964
|
const binding = `reference image ${slotToLetter(slot)}`;
|
|
10687
|
-
phrases.push(shared.roleToPhrase(
|
|
10965
|
+
phrases.push(shared.roleToPhrase(resolveLocationRole(null, null, r), binding));
|
|
10688
10966
|
const lock = buildIdentityLockLine(r, binding);
|
|
10689
10967
|
if (lock) lockLines.push(lock);
|
|
10690
10968
|
const inject = r.elementInjection?.trim();
|
|
@@ -10840,9 +11118,29 @@ function reconcileBodySegments(body, bodySegments) {
|
|
|
10840
11118
|
}
|
|
10841
11119
|
return [{ text: body, origin: "user" }];
|
|
10842
11120
|
}
|
|
11121
|
+
function controlSuffixes(body, styleLine, avoidLine) {
|
|
11122
|
+
const separator = (text) => endsInsideStyleSection(text) ? STYLE_SECTION_GAP : "\n";
|
|
11123
|
+
const styleSuffix = styleLine ? `${separator(body)}${styleLine}` : "";
|
|
11124
|
+
const avoidSuffix = avoidLine ? `${separator(body + styleSuffix)}${avoidLine}` : "";
|
|
11125
|
+
return { styleSuffix, avoidSuffix };
|
|
11126
|
+
}
|
|
10843
11127
|
function buildImagePrompt(config2) {
|
|
10844
11128
|
return buildImagePromptInternal(config2);
|
|
10845
11129
|
}
|
|
11130
|
+
function buildImagePromptWithOverflow(config2) {
|
|
11131
|
+
const marks = newAssemblyMarks();
|
|
11132
|
+
const result = buildImagePromptInternal(config2, marks);
|
|
11133
|
+
return { ...result, overflowChars: marks.overflowChars };
|
|
11134
|
+
}
|
|
11135
|
+
function newAssemblyMarks() {
|
|
11136
|
+
return {
|
|
11137
|
+
directivesPrefix: "",
|
|
11138
|
+
bodyBeforeSuffixes: "",
|
|
11139
|
+
styleSuffix: "",
|
|
11140
|
+
avoidSuffix: "",
|
|
11141
|
+
overflowChars: 0
|
|
11142
|
+
};
|
|
11143
|
+
}
|
|
10846
11144
|
function buildImagePromptInternal(config2, marks) {
|
|
10847
11145
|
let {
|
|
10848
11146
|
provider,
|
|
@@ -10864,6 +11162,7 @@ function buildImagePromptInternal(config2, marks) {
|
|
|
10864
11162
|
const suppressedCanonicalLocationIds = config2.suppressedCanonicalLocationIds ?? [];
|
|
10865
11163
|
const isHybrid = config2.referenceFormat === "hybrid";
|
|
10866
11164
|
let hybridBodyConverged = false;
|
|
11165
|
+
const mentionedEntityUrls = /* @__PURE__ */ new Set();
|
|
10867
11166
|
if (config2.skipCharacterMentions) {
|
|
10868
11167
|
config2 = {
|
|
10869
11168
|
...config2,
|
|
@@ -10910,7 +11209,9 @@ function buildImagePromptInternal(config2, marks) {
|
|
|
10910
11209
|
);
|
|
10911
11210
|
const knownImageSlugs = shared.knownImageSlugsFromRefs(connectedReferences);
|
|
10912
11211
|
const hasImageMentionTokens = isHybrid && knownImageSlugs.length > 0 && shared.findImageMentionTokens(config2.prompt, knownImageSlugs).length > 0;
|
|
10913
|
-
|
|
11212
|
+
const knownEntitySlugs = shared.knownEntitySlugsFromRefs(connectedReferences);
|
|
11213
|
+
const hasEntityMentionTokens = isHybrid && knownEntitySlugs.length > 0 && shared.findEntityMentionTokens(config2.prompt, knownEntitySlugs).length > 0;
|
|
11214
|
+
if (knownCharacterSlugs.length > 0 || hasExtraRefs || knownLocationSlugs.length > 0 || hasImageMentionTokens || hasEntityMentionTokens) {
|
|
10914
11215
|
const mentionTokens = knownCharacterSlugs.length > 0 ? shared.findCharacterMentionTokens(config2.prompt, knownCharacterSlugs) : [];
|
|
10915
11216
|
let hybridLockLines = [];
|
|
10916
11217
|
let hybridElementDirectives = [];
|
|
@@ -10982,6 +11283,25 @@ function buildImagePromptInternal(config2, marks) {
|
|
|
10982
11283
|
if (hi.additionalUrls.length > 0) hybridBodyConverged = true;
|
|
10983
11284
|
}
|
|
10984
11285
|
}
|
|
11286
|
+
let hybridEntityLockLines = [];
|
|
11287
|
+
let hybridEntityElementDirectives = [];
|
|
11288
|
+
if (hasEntityMentionTokens) {
|
|
11289
|
+
const entityTokens = shared.findEntityMentionTokens(resolved.prompt, knownEntitySlugs);
|
|
11290
|
+
if (entityTokens.length > 0) {
|
|
11291
|
+
const he = resolveEntityMentionsHybrid(
|
|
11292
|
+
resolved.prompt,
|
|
11293
|
+
entityTokens,
|
|
11294
|
+
connectedReferences,
|
|
11295
|
+
[...referenceImageUrls || [], ...resolved.additionalUrls]
|
|
11296
|
+
);
|
|
11297
|
+
resolved.prompt = he.prompt;
|
|
11298
|
+
resolved.additionalUrls = [...resolved.additionalUrls, ...he.additionalUrls];
|
|
11299
|
+
hybridEntityLockLines = he.lockLines;
|
|
11300
|
+
hybridEntityElementDirectives = he.elementDirectives;
|
|
11301
|
+
for (const u of he.mentionedUrls) mentionedEntityUrls.add(u);
|
|
11302
|
+
if (he.additionalUrls.length > 0) hybridBodyConverged = true;
|
|
11303
|
+
}
|
|
11304
|
+
}
|
|
10985
11305
|
const prefixDedupedLength = [
|
|
10986
11306
|
...referenceImageUrls || [],
|
|
10987
11307
|
...resolved.additionalUrls
|
|
@@ -11063,6 +11383,7 @@ ${promptForNext}`;
|
|
|
11063
11383
|
...hybridLockLines,
|
|
11064
11384
|
...hybridLocationLockLines,
|
|
11065
11385
|
...hybridImageLockLines,
|
|
11386
|
+
...hybridEntityLockLines,
|
|
11066
11387
|
...canonical.lockLines,
|
|
11067
11388
|
...extrasRendered.lockLines
|
|
11068
11389
|
])];
|
|
@@ -11070,6 +11391,7 @@ ${promptForNext}`;
|
|
|
11070
11391
|
...hybridElementDirectives,
|
|
11071
11392
|
...hybridLocationElementDirectives,
|
|
11072
11393
|
...hybridImageElementDirectives,
|
|
11394
|
+
...hybridEntityElementDirectives,
|
|
11073
11395
|
...canonical.phrases,
|
|
11074
11396
|
...canonical.elementDirectives,
|
|
11075
11397
|
...extrasRendered.bodyLines,
|
|
@@ -11078,9 +11400,7 @@ ${promptForNext}`;
|
|
|
11078
11400
|
const lockBlock = allLockLines.length > 0 ? `${allLockLines.join("\n")}
|
|
11079
11401
|
|
|
11080
11402
|
` : "";
|
|
11081
|
-
|
|
11082
|
-
${trailingLines.join("\n")}` : "";
|
|
11083
|
-
promptForNext = `${lockBlock}${promptForNext}${trailingBlock}`;
|
|
11403
|
+
promptForNext = `${lockBlock}${insertBeforeStyleSection(promptForNext, trailingLines)}`;
|
|
11084
11404
|
}
|
|
11085
11405
|
config2 = {
|
|
11086
11406
|
...config2,
|
|
@@ -11116,7 +11436,8 @@ ${trailingLines.join("\n")}` : "";
|
|
|
11116
11436
|
if (coveredUrl) tokenCoveredUrls.add(coveredUrl);
|
|
11117
11437
|
}
|
|
11118
11438
|
const locCanon = renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, tokenCoveredUrls);
|
|
11119
|
-
const
|
|
11439
|
+
const objCoveredUrls = mentionedEntityUrls.size > 0 ? /* @__PURE__ */ new Set([...tokenCoveredUrls, ...mentionedEntityUrls]) : tokenCoveredUrls;
|
|
11440
|
+
const objCanon = renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, objCoveredUrls);
|
|
11120
11441
|
const canonLockLines = [...locCanon.lockLines, ...objCanon.lockLines];
|
|
11121
11442
|
const canonLockBlock = canonLockLines.length > 0 ? `${canonLockLines.join("\n")}
|
|
11122
11443
|
|
|
@@ -11127,9 +11448,7 @@ ${trailingLines.join("\n")}` : "";
|
|
|
11127
11448
|
...locCanon.elementDirectives,
|
|
11128
11449
|
...objCanon.elementDirectives
|
|
11129
11450
|
];
|
|
11130
|
-
const
|
|
11131
|
-
${canonTrailingLines.join("\n")}` : "";
|
|
11132
|
-
const composedScene = `${canonLockBlock}${scene}${canonTrailingBlock}`;
|
|
11451
|
+
const composedScene = `${canonLockBlock}${insertBeforeStyleSection(scene, canonTrailingLines)}`;
|
|
11133
11452
|
prompt2 = config2.referenceLockSnippet ? `${config2.referenceLockSnippet}
|
|
11134
11453
|
${composedScene}` : composedScene;
|
|
11135
11454
|
if (marks) marks.directivesPrefix = "";
|
|
@@ -11155,31 +11474,33 @@ ${directives}`;
|
|
|
11155
11474
|
}
|
|
11156
11475
|
}
|
|
11157
11476
|
const styleText2 = style?.trim();
|
|
11158
|
-
const
|
|
11159
|
-
Style: ${getStylePromptHint(styleText2) || styleText2}` : "";
|
|
11477
|
+
const styleLine2 = styleText2 ? `Style: ${getStylePromptHint(styleText2) || styleText2}` : "";
|
|
11160
11478
|
const negPrompt2 = negativePrompt?.trim();
|
|
11161
11479
|
let nativeNegativePrompt2;
|
|
11162
|
-
let
|
|
11480
|
+
let avoidLine2 = "";
|
|
11163
11481
|
if (negPrompt2) {
|
|
11164
11482
|
if (shared.NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {
|
|
11165
11483
|
nativeNegativePrompt2 = negPrompt2.slice(0, shared.getMaxNegativePromptChars(provider));
|
|
11166
11484
|
} else {
|
|
11167
|
-
|
|
11168
|
-
Avoid: ${negPrompt2}`;
|
|
11485
|
+
avoidLine2 = `Avoid: ${negPrompt2}`;
|
|
11169
11486
|
}
|
|
11170
11487
|
}
|
|
11171
|
-
if (marks) {
|
|
11172
|
-
marks.styleSuffix = styleSuffix2;
|
|
11173
|
-
marks.avoidSuffix = avoidSuffix2;
|
|
11174
|
-
}
|
|
11175
11488
|
const maxLen2 = shared.getMaxImagePromptChars(provider);
|
|
11176
|
-
const
|
|
11489
|
+
const preCut2 = controlSuffixes(prompt2, styleLine2, avoidLine2);
|
|
11490
|
+
const reserved2 = preCut2.styleSuffix.length + preCut2.avoidSuffix.length;
|
|
11177
11491
|
if (prompt2.length + reserved2 > maxLen2) {
|
|
11492
|
+
if (marks) marks.overflowChars += prompt2.length + reserved2 - maxLen2;
|
|
11178
11493
|
prompt2 = prompt2.slice(0, Math.max(0, maxLen2 - reserved2 - 3)) + "...";
|
|
11179
11494
|
}
|
|
11495
|
+
const { styleSuffix: styleSuffix2, avoidSuffix: avoidSuffix2 } = controlSuffixes(prompt2, styleLine2, avoidLine2);
|
|
11496
|
+
if (marks) {
|
|
11497
|
+
marks.styleSuffix = styleSuffix2;
|
|
11498
|
+
marks.avoidSuffix = avoidSuffix2;
|
|
11499
|
+
}
|
|
11180
11500
|
if (marks) marks.bodyBeforeSuffixes = prompt2.slice(marks.directivesPrefix.length);
|
|
11181
11501
|
prompt2 = prompt2 + styleSuffix2 + avoidSuffix2;
|
|
11182
11502
|
if (prompt2.length > maxLen2) {
|
|
11503
|
+
if (marks) marks.overflowChars += prompt2.length - maxLen2;
|
|
11183
11504
|
prompt2 = prompt2.slice(0, maxLen2 - 3) + "...";
|
|
11184
11505
|
}
|
|
11185
11506
|
if (!isHybrid) {
|
|
@@ -11227,37 +11548,41 @@ Avoid: ${negPrompt2}`;
|
|
|
11227
11548
|
let prompt = config2.prompt;
|
|
11228
11549
|
if (charDescs.length > 0) {
|
|
11229
11550
|
const wrapperTemplate = resolveTemplate("generate-image-wrapper", userTemplates, flowTemplates);
|
|
11230
|
-
|
|
11231
|
-
|
|
11551
|
+
const { body, section } = splitStyleSection(prompt);
|
|
11552
|
+
const wrapped = applyTemplate(wrapperTemplate, {
|
|
11553
|
+
userPrompt: body,
|
|
11232
11554
|
assetDescriptions: charDescs.join(" ")
|
|
11233
11555
|
});
|
|
11556
|
+
prompt = section.length > 0 ? `${wrapped}${STYLE_SECTION_GAP}${section}` : wrapped;
|
|
11234
11557
|
}
|
|
11235
11558
|
const styleText = style?.trim();
|
|
11236
|
-
const
|
|
11237
|
-
Style: ${getStylePromptHint(styleText) || styleText}` : "";
|
|
11559
|
+
const styleLine = styleText ? `Style: ${getStylePromptHint(styleText) || styleText}` : "";
|
|
11238
11560
|
const negPrompt = negativePrompt?.trim();
|
|
11239
11561
|
let nativeNegativePrompt;
|
|
11240
|
-
let
|
|
11562
|
+
let avoidLine = "";
|
|
11241
11563
|
if (negPrompt) {
|
|
11242
11564
|
if (shared.NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {
|
|
11243
11565
|
nativeNegativePrompt = negPrompt.slice(0, shared.getMaxNegativePromptChars(provider));
|
|
11244
11566
|
} else {
|
|
11245
|
-
|
|
11246
|
-
Avoid: ${negPrompt}`;
|
|
11567
|
+
avoidLine = `Avoid: ${negPrompt}`;
|
|
11247
11568
|
}
|
|
11248
11569
|
}
|
|
11249
|
-
if (marks) {
|
|
11250
|
-
marks.styleSuffix = styleSuffix;
|
|
11251
|
-
marks.avoidSuffix = avoidSuffix;
|
|
11252
|
-
}
|
|
11253
11570
|
const maxLen = shared.getMaxImagePromptChars(provider);
|
|
11254
|
-
const
|
|
11571
|
+
const preCut = controlSuffixes(prompt, styleLine, avoidLine);
|
|
11572
|
+
const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length;
|
|
11255
11573
|
if (prompt.length + reserved > maxLen) {
|
|
11574
|
+
if (marks) marks.overflowChars += prompt.length + reserved - maxLen;
|
|
11256
11575
|
prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + "...";
|
|
11257
11576
|
}
|
|
11577
|
+
const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine);
|
|
11578
|
+
if (marks) {
|
|
11579
|
+
marks.styleSuffix = styleSuffix;
|
|
11580
|
+
marks.avoidSuffix = avoidSuffix;
|
|
11581
|
+
}
|
|
11258
11582
|
if (marks) marks.bodyBeforeSuffixes = prompt;
|
|
11259
11583
|
prompt = prompt + styleSuffix + avoidSuffix;
|
|
11260
11584
|
if (prompt.length > maxLen) {
|
|
11585
|
+
if (marks) marks.overflowChars += prompt.length - maxLen;
|
|
11261
11586
|
prompt = prompt.slice(0, maxLen - 3) + "...";
|
|
11262
11587
|
}
|
|
11263
11588
|
const allRefs = referenceImageUrls.length > 0 ? referenceImageUrls : ancestorRefs;
|
|
@@ -11267,12 +11592,7 @@ Avoid: ${negPrompt}`;
|
|
|
11267
11592
|
return { prompt, nativeNegativePrompt, referenceImageUrls: refsToSend };
|
|
11268
11593
|
}
|
|
11269
11594
|
function buildImagePromptSegments(config2, bodySegments) {
|
|
11270
|
-
const marks =
|
|
11271
|
-
directivesPrefix: "",
|
|
11272
|
-
bodyBeforeSuffixes: "",
|
|
11273
|
-
styleSuffix: "",
|
|
11274
|
-
avoidSuffix: ""
|
|
11275
|
-
};
|
|
11595
|
+
const marks = newAssemblyMarks();
|
|
11276
11596
|
const result = buildImagePromptInternal(config2, marks);
|
|
11277
11597
|
let segments = [
|
|
11278
11598
|
...marks.directivesPrefix ? [{ text: marks.directivesPrefix, origin: "mention" }] : [],
|
|
@@ -11462,19 +11782,35 @@ function hybridRolePhrase(label, letter) {
|
|
|
11462
11782
|
return `the ${label} from reference image ${letter}`;
|
|
11463
11783
|
}
|
|
11464
11784
|
function expandImageRefTokensHybrid(prompt, refs, finalIndexByUrl) {
|
|
11465
|
-
|
|
11466
|
-
|
|
11785
|
+
const splices = [];
|
|
11786
|
+
for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {
|
|
11787
|
+
const n = parseInt(m[1], 10);
|
|
11467
11788
|
const ref = refs[n - 1];
|
|
11468
11789
|
const finalIdx = ref?.url ? finalIndexByUrl.get(ref.url) : void 0;
|
|
11469
|
-
if (!finalIdx)
|
|
11470
|
-
|
|
11471
|
-
|
|
11790
|
+
if (!finalIdx) continue;
|
|
11791
|
+
splices.push({
|
|
11792
|
+
offset: m.index ?? 0,
|
|
11793
|
+
length: m[0].length,
|
|
11794
|
+
phrase: hybridRolePhrase((m[2] ?? "").trim(), slotToLetter(finalIdx))
|
|
11795
|
+
});
|
|
11796
|
+
}
|
|
11797
|
+
let resolved = prompt;
|
|
11798
|
+
for (let i = splices.length - 1; i >= 0; i--) {
|
|
11799
|
+
const s = splices[i];
|
|
11800
|
+
resolved = spliceMentionPhrase(resolved, s.offset, s.length, s.phrase);
|
|
11801
|
+
}
|
|
11802
|
+
return resolved;
|
|
11472
11803
|
}
|
|
11473
11804
|
function capitalizeLineInitial(line) {
|
|
11474
11805
|
return line.replace(/[a-zA-Z]/, (c) => c.toUpperCase());
|
|
11475
11806
|
}
|
|
11476
11807
|
function buildHybridScene(prompt, refs, finalIndexByUrl) {
|
|
11477
|
-
|
|
11808
|
+
const lines = prompt.split("\n");
|
|
11809
|
+
const sectionAt = lines.indexOf(STYLE_SECTION_HEADER);
|
|
11810
|
+
return lines.map((line, i) => {
|
|
11811
|
+
const expanded = expandImageRefTokensHybrid(line, refs, finalIndexByUrl);
|
|
11812
|
+
return sectionAt >= 0 && i >= sectionAt ? expanded : capitalizeLineInitial(expanded);
|
|
11813
|
+
}).join("\n");
|
|
11478
11814
|
}
|
|
11479
11815
|
function buildIdentityDirectives(prompt, refs, meta3 = [], suppressedCanonicalLocationIds) {
|
|
11480
11816
|
return collectIdentities(prompt, refs, meta3).map((id) => buildIdentityDirective(id, suppressedCanonicalLocationIds)).filter((s) => s.length > 0).join("\n");
|
|
@@ -11692,9 +12028,16 @@ function renderLens(l) {
|
|
|
11692
12028
|
if (l.aperture) bits.push(`f/${l.aperture}`);
|
|
11693
12029
|
return bits.length > 0 ? `Lens: ${bits.join(", ")}.` : "";
|
|
11694
12030
|
}
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
12031
|
+
var viaFragmentBuilder = (build) => (subject, mode) => {
|
|
12032
|
+
const clause = build(subject, mode).filter((s) => s.length > 0).join(", ");
|
|
12033
|
+
return clause.length > 0 ? [clause] : [];
|
|
12034
|
+
};
|
|
12035
|
+
var viaListBuilder2 = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
|
|
12036
|
+
var viaStringBuilder2 = (build) => (ids, mode) => {
|
|
12037
|
+
const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
|
|
12038
|
+
return s.length > 0 ? [s] : [];
|
|
12039
|
+
};
|
|
12040
|
+
var perId2 = (full, compact) => (ids, mode) => {
|
|
11698
12041
|
const out = [];
|
|
11699
12042
|
for (const id of ids) {
|
|
11700
12043
|
const frag = mode === "compact" ? compact(id) : full(id);
|
|
@@ -11702,80 +12045,45 @@ var perId = (full, compact) => (ids, mode) => {
|
|
|
11702
12045
|
}
|
|
11703
12046
|
return out;
|
|
11704
12047
|
};
|
|
11705
|
-
var
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
}
|
|
11710
|
-
|
|
11711
|
-
(s) => s.length > 0
|
|
11712
|
-
);
|
|
11713
|
-
var framing = perId(getFramingPromptHint, getFramingTerm);
|
|
11714
|
-
var lighting = perId(getLightingPromptHint, getLightingTerm);
|
|
11715
|
-
var exposure = perId(getExposurePromptHint, getExposureTerm);
|
|
11716
|
-
var temporal = perId(getTemporalPromptHint, getTemporalTerm);
|
|
11717
|
-
var DIRECTION_FIELDS = [
|
|
11718
|
-
{ key: "cameraMotion", surface: "video", family: "motion", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },
|
|
11719
|
-
// Composition (the Framing catalog, one row per category).
|
|
11720
|
-
{ key: "shotSize", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11721
|
-
{ key: "angle", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11722
|
-
{ key: "coverage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11723
|
-
{ key: "composition", surface: "both", family: "look", maxPicks: 2, render: framing },
|
|
11724
|
-
{ key: "vantage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11725
|
-
{ key: "pose", surface: "both", family: "look", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },
|
|
11726
|
-
{ key: "compositionEffect", surface: "both", family: "look", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },
|
|
11727
|
-
// Camera.
|
|
11728
|
-
{ key: "cameraFormat", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },
|
|
11729
|
-
{ key: "lens", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
11730
|
-
// Exposure (stills only — a video's exposure rides its own temporal levers).
|
|
11731
|
-
{ key: "aperture", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11732
|
-
{ key: "shutterSpeed", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11733
|
-
{ key: "isoValue", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11734
|
-
// Light (the Lighting catalog, one row per category).
|
|
11735
|
-
{ key: "timeOfDay", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11736
|
-
{ key: "lightingStyle", surface: "both", family: "look", maxPicks: 2, render: lighting },
|
|
11737
|
-
{ key: "lightingDirection", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11738
|
-
{ key: "lightingRatio", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11739
|
-
{ key: "colorTemperature", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11740
|
-
{ key: "colorLook", surface: "both", family: "look", maxPicks: 1, render: perId(getColorLookPromptHint, getColorLookTerm) },
|
|
11741
|
-
{ key: "atmosphere", surface: "both", family: "look", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },
|
|
11742
|
-
{ key: "postProcess", surface: "image", family: "look", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },
|
|
11743
|
-
// Style.
|
|
11744
|
-
{ key: "style", surface: "both", family: "look", maxPicks: 1, render: perId(getStylePromptHint, getStyleTerm) },
|
|
11745
|
-
{ key: "mood", surface: "both", family: "look", maxPicks: 2, render: viaMood },
|
|
11746
|
-
{ key: "aesthetic", surface: "both", family: "look", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },
|
|
11747
|
-
{ key: "photoGenre", surface: "image", family: "look", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },
|
|
11748
|
-
{ key: "photographer", surface: "image", family: "look", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },
|
|
11749
|
-
{ key: "renderQuality", surface: "image", family: "look", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },
|
|
11750
|
-
// Scene.
|
|
11751
|
-
{ key: "setting", surface: "both", family: "look", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },
|
|
11752
|
-
{ key: "era", surface: "both", family: "look", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },
|
|
11753
|
-
{ key: "backdrop", surface: "both", family: "look", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },
|
|
11754
|
-
// Motion & time.
|
|
11755
|
-
{ key: "actionFx", surface: "video", family: "motion", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },
|
|
11756
|
-
{ key: "temporalSpeed", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11757
|
-
{ key: "temporalFreeze", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11758
|
-
{ key: "temporalDirection", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11759
|
-
{ key: "temporalShutter", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11760
|
-
{ key: "transition", surface: "video", family: "motion", maxPicks: 2, render: perId(getTransitionPromptHint, getTransitionTerm) },
|
|
11761
|
-
{ key: "loopSubject", surface: "video", family: "motion", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },
|
|
11762
|
-
// ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact
|
|
11763
|
-
// `composePromptText` order, so every pre-registry caller is byte-identical.
|
|
11764
|
-
{ key: "framingId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11765
|
-
{ key: "framingAngleId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11766
|
-
{ key: "lightingId", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11767
|
-
{ key: "lensId", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
11768
|
-
{ key: "cameraFormatId", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) }
|
|
12048
|
+
var SUBJECT_FIELDS = [
|
|
12049
|
+
{ key: "person", kind: "group", surface: "both", render: viaFragmentBuilder(buildPersonHints) },
|
|
12050
|
+
{ key: "styling", kind: "group", surface: "both", render: viaFragmentBuilder(buildStylingHints) },
|
|
12051
|
+
{ key: "heldProp", kind: "ids", surface: "both", maxPicks: 2, render: viaListBuilder2(buildHeldPropHints) },
|
|
12052
|
+
{ key: "material", kind: "ids", surface: "both", maxPicks: 2, render: viaStringBuilder2(buildMaterialHints) },
|
|
12053
|
+
{ key: "animal", kind: "ids", surface: "both", maxPicks: 1, render: perId2(shared.getAnimalPromptHint, shared.getAnimalTerm) }
|
|
11769
12054
|
];
|
|
11770
|
-
var
|
|
11771
|
-
var
|
|
11772
|
-
var
|
|
11773
|
-
|
|
11774
|
-
|
|
12055
|
+
var SUBJECT_FOLD_KEYS = SUBJECT_FIELDS.map((f) => f.key);
|
|
12056
|
+
var IDS_ROWS = SUBJECT_FIELDS.filter((f) => f.kind === "ids");
|
|
12057
|
+
var SUBJECT_CUSTOM_AGE_KEY = "customAge";
|
|
12058
|
+
var CUSTOM_AGE_MIN = 0;
|
|
12059
|
+
var CUSTOM_AGE_MAX = 120;
|
|
12060
|
+
var SUBJECT_KEYS = [
|
|
12061
|
+
...PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]),
|
|
12062
|
+
SUBJECT_CUSTOM_AGE_KEY,
|
|
12063
|
+
...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),
|
|
12064
|
+
...IDS_ROWS.map((f) => f.key)
|
|
12065
|
+
];
|
|
12066
|
+
function getRegisteredSubjectKeys() {
|
|
12067
|
+
const fieldByDimension = getRegisteredPersonFieldByDimension();
|
|
12068
|
+
const personFields = [];
|
|
12069
|
+
for (const dimension of getRegisteredPersonDimensionOrder()) {
|
|
12070
|
+
const field = fieldByDimension[dimension];
|
|
12071
|
+
if (field) personFields.push(field);
|
|
12072
|
+
}
|
|
12073
|
+
return [
|
|
12074
|
+
...personFields,
|
|
12075
|
+
SUBJECT_CUSTOM_AGE_KEY,
|
|
12076
|
+
...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),
|
|
12077
|
+
...IDS_ROWS.map((f) => f.key)
|
|
12078
|
+
];
|
|
11775
12079
|
}
|
|
11776
|
-
var
|
|
11777
|
-
var
|
|
11778
|
-
|
|
12080
|
+
var SUBJECT_IMAGE_HINT_MODE_DEFAULT = "full";
|
|
12081
|
+
var SUBJECT_VIDEO_HINT_MODE_DEFAULT = "compact";
|
|
12082
|
+
var SUBJECT_ARRAY_CEILING = DIRECTION_ARRAY_CEILING;
|
|
12083
|
+
var SUBJECT_ID_MAX_CHARS = DIRECTION_ID_MAX_CHARS;
|
|
12084
|
+
var MAX_SUBJECT_KEYS = 128;
|
|
12085
|
+
var SUBJECT_KEY_MAX_CHARS = 64;
|
|
12086
|
+
function normalizeIds(value, maxPicks) {
|
|
11779
12087
|
const ids = [];
|
|
11780
12088
|
if (typeof value === "string") {
|
|
11781
12089
|
if (value) ids.push(value);
|
|
@@ -11787,22 +12095,54 @@ function normalizeDirectionIds(value, maxPicks) {
|
|
|
11787
12095
|
}
|
|
11788
12096
|
return ids.slice(0, maxPicks);
|
|
11789
12097
|
}
|
|
11790
|
-
function
|
|
11791
|
-
|
|
12098
|
+
function limitByField() {
|
|
12099
|
+
const out = /* @__PURE__ */ new Map();
|
|
12100
|
+
const personFieldByDimension = getRegisteredPersonFieldByDimension();
|
|
12101
|
+
for (const dimension of getRegisteredPersonDimensionOrder()) {
|
|
12102
|
+
const field = personFieldByDimension[dimension];
|
|
12103
|
+
if (field) out.set(field, getPersonDimensionLimit(dimension));
|
|
12104
|
+
}
|
|
12105
|
+
for (const dimension of STYLING_DIMENSION_ORDER) {
|
|
12106
|
+
out.set(
|
|
12107
|
+
STYLING_FIELD_BY_DIMENSION[dimension],
|
|
12108
|
+
getStylingDimensionLimit(dimension)
|
|
12109
|
+
);
|
|
12110
|
+
}
|
|
12111
|
+
for (const row of IDS_ROWS) out.set(row.key, row.maxPicks);
|
|
12112
|
+
return out;
|
|
11792
12113
|
}
|
|
11793
|
-
function
|
|
11794
|
-
if (!
|
|
12114
|
+
function normalizeSubjectFields(subject) {
|
|
12115
|
+
if (!subject || typeof subject !== "object" || Array.isArray(subject)) return void 0;
|
|
12116
|
+
const src = subject;
|
|
12117
|
+
const limits = limitByField();
|
|
12118
|
+
const out = {};
|
|
12119
|
+
const rawAge = src[SUBJECT_CUSTOM_AGE_KEY];
|
|
12120
|
+
if (typeof rawAge === "number" && Number.isFinite(rawAge)) {
|
|
12121
|
+
out[SUBJECT_CUSTOM_AGE_KEY] = Math.max(
|
|
12122
|
+
CUSTOM_AGE_MIN,
|
|
12123
|
+
Math.min(CUSTOM_AGE_MAX, Math.round(rawAge))
|
|
12124
|
+
);
|
|
12125
|
+
}
|
|
12126
|
+
for (const [field, limit] of limits) {
|
|
12127
|
+
const ids = normalizeIds(src[field], limit);
|
|
12128
|
+
if (ids.length === 0) continue;
|
|
12129
|
+
out[field] = ids.length === 1 ? ids[0] : ids;
|
|
12130
|
+
}
|
|
12131
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
12132
|
+
}
|
|
12133
|
+
function subjectFieldsForSurface(surface) {
|
|
12134
|
+
return SUBJECT_FIELDS.filter((f) => f.surface === "both" || f.surface === surface);
|
|
12135
|
+
}
|
|
12136
|
+
function renderSubjectHints(subject, opts) {
|
|
12137
|
+
const bag = normalizeSubjectFields(subject);
|
|
12138
|
+
if (!bag) return [];
|
|
11795
12139
|
const mode = opts.mode ?? "full";
|
|
11796
12140
|
const out = [];
|
|
11797
12141
|
const seen = /* @__PURE__ */ new Set();
|
|
11798
|
-
for (const spec of
|
|
12142
|
+
for (const spec of SUBJECT_FIELDS) {
|
|
11799
12143
|
if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
|
|
11800
|
-
const
|
|
11801
|
-
|
|
11802
|
-
spec.maxPicks
|
|
11803
|
-
);
|
|
11804
|
-
if (ids.length === 0) continue;
|
|
11805
|
-
for (const hint of spec.render(ids, modeForFamily(mode, spec.family))) {
|
|
12144
|
+
const hints = spec.kind === "group" ? spec.render(bag, mode) : spec.render(normalizeIds(bag[spec.key], spec.maxPicks), mode);
|
|
12145
|
+
for (const hint of hints) {
|
|
11806
12146
|
if (hint.length > 0 && !seen.has(hint)) {
|
|
11807
12147
|
seen.add(hint);
|
|
11808
12148
|
out.push(hint);
|
|
@@ -11812,11 +12152,15 @@ function renderDirectionHints(direction, opts) {
|
|
|
11812
12152
|
return out;
|
|
11813
12153
|
}
|
|
11814
12154
|
|
|
11815
|
-
// src/
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
12155
|
+
// src/hint-shedding.ts
|
|
12156
|
+
function keepableDirectionHints(hintClauses, kept, deficit, clauseCosts) {
|
|
12157
|
+
let remaining = deficit;
|
|
12158
|
+
let next = kept;
|
|
12159
|
+
while (next > 0 && remaining > 0) {
|
|
12160
|
+
next -= 1;
|
|
12161
|
+
remaining -= clauseCosts?.[next] ?? hintClauses[next].length + PROMPT_HINT_SEPARATOR.length;
|
|
12162
|
+
}
|
|
12163
|
+
return next;
|
|
11820
12164
|
}
|
|
11821
12165
|
|
|
11822
12166
|
// src/ref-binding.ts
|
|
@@ -12168,9 +12512,7 @@ function resolveVideoReferenceCore(args) {
|
|
|
12168
12512
|
const lockBlock = lockLines.length > 0 ? `${lockLines.join("\n")}
|
|
12169
12513
|
|
|
12170
12514
|
` : "";
|
|
12171
|
-
|
|
12172
|
-
${trailingLines.join("\n")}` : "";
|
|
12173
|
-
finalPrompt = `${lockBlock}${finalPrompt}${trailingBlock}`;
|
|
12515
|
+
finalPrompt = `${lockBlock}${insertBeforeStyleSection(finalPrompt, trailingLines)}`;
|
|
12174
12516
|
} else {
|
|
12175
12517
|
const allFallbackLines = [...fallbackDirectiveLines, ...extraDirectiveLines];
|
|
12176
12518
|
if (allFallbackLines.length > 0) {
|
|
@@ -12404,17 +12746,34 @@ function assembleSunoInput(input) {
|
|
|
12404
12746
|
}
|
|
12405
12747
|
|
|
12406
12748
|
// src/assemble-image-input.ts
|
|
12407
|
-
function
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12749
|
+
function renderImageHintPieces(subject, direction, structured) {
|
|
12750
|
+
return {
|
|
12751
|
+
hintClauses: [
|
|
12752
|
+
...asBodyClauses(
|
|
12753
|
+
renderSubjectHints(subject, {
|
|
12754
|
+
surface: "image",
|
|
12755
|
+
mode: SUBJECT_IMAGE_HINT_MODE_DEFAULT
|
|
12756
|
+
})
|
|
12757
|
+
),
|
|
12758
|
+
...partitionStyleClauses(direction, {
|
|
12759
|
+
surface: "image",
|
|
12760
|
+
mode: IMAGE_HINT_MODE_DEFAULT
|
|
12761
|
+
})
|
|
12762
|
+
].filter((c) => c.text.length > 0),
|
|
12763
|
+
structuredFragment: structured ? renderStructuredFields(structured) : ""
|
|
12764
|
+
};
|
|
12765
|
+
}
|
|
12766
|
+
function composePromptText(userPrompt, pieces, keptHintClauses) {
|
|
12767
|
+
return composeSectionedPrompt(
|
|
12768
|
+
userPrompt,
|
|
12769
|
+
pieces.hintClauses.slice(0, keptHintClauses),
|
|
12770
|
+
pieces.structuredFragment
|
|
12771
|
+
);
|
|
12413
12772
|
}
|
|
12414
12773
|
function assembleImageInput(input) {
|
|
12415
|
-
const
|
|
12416
|
-
const
|
|
12417
|
-
prompt,
|
|
12774
|
+
const pieces = renderImageHintPieces(input.subject, input.direction, input.structured);
|
|
12775
|
+
const assembleWith = (keptHintClauses) => buildImagePromptWithOverflow({
|
|
12776
|
+
prompt: composePromptText(input.userPrompt, pieces, keptHintClauses),
|
|
12418
12777
|
provider: input.provider,
|
|
12419
12778
|
...input.connectedReferences !== void 0 ? { connectedReferences: input.connectedReferences } : {},
|
|
12420
12779
|
// Manual uploads / direct refs ride the builder's reference-URL channel so
|
|
@@ -12437,6 +12796,21 @@ function assembleImageInput(input) {
|
|
|
12437
12796
|
...input.sourceNodeIdById !== void 0 ? { sourceNodeIdById: input.sourceNodeIdById } : {},
|
|
12438
12797
|
...input.skipCharacterMentions !== void 0 ? { skipCharacterMentions: input.skipCharacterMentions } : {}
|
|
12439
12798
|
});
|
|
12799
|
+
let kept = pieces.hintClauses.length;
|
|
12800
|
+
let fitted = assembleWith(kept);
|
|
12801
|
+
if (fitted.overflowChars > 0) {
|
|
12802
|
+
const costs = sectionedClauseCosts(
|
|
12803
|
+
input.userPrompt,
|
|
12804
|
+
pieces.hintClauses,
|
|
12805
|
+
pieces.structuredFragment
|
|
12806
|
+
);
|
|
12807
|
+
const texts = pieces.hintClauses.map((c) => c.text);
|
|
12808
|
+
while (fitted.overflowChars > 0 && kept > 0) {
|
|
12809
|
+
kept = keepableDirectionHints(texts, kept, fitted.overflowChars, costs);
|
|
12810
|
+
fitted = assembleWith(kept);
|
|
12811
|
+
}
|
|
12812
|
+
}
|
|
12813
|
+
const { overflowChars, ...result } = fitted;
|
|
12440
12814
|
if (input.throwOnEmpty && !result.prompt.trim()) {
|
|
12441
12815
|
throw new Error(
|
|
12442
12816
|
"No prompt \u2014 type one, bind a character, or pick a cinematography direction"
|
|
@@ -12447,15 +12821,35 @@ function assembleImageInput(input) {
|
|
|
12447
12821
|
|
|
12448
12822
|
// src/assemble-video-input.ts
|
|
12449
12823
|
function composeVideoPromptText(userPrompt, direction, structured, opts) {
|
|
12450
|
-
const
|
|
12451
|
-
...
|
|
12824
|
+
const hintClauses = [
|
|
12825
|
+
...asBodyClauses(
|
|
12826
|
+
renderSubjectHints(opts?.subject, {
|
|
12827
|
+
surface: "video",
|
|
12828
|
+
mode: opts?.subjectHintMode ?? SUBJECT_VIDEO_HINT_MODE_DEFAULT
|
|
12829
|
+
})
|
|
12830
|
+
),
|
|
12831
|
+
...partitionStyleClauses(direction, {
|
|
12452
12832
|
surface: "video",
|
|
12453
12833
|
mode: opts?.hintMode ?? VIDEO_HINT_MODE_DEFAULT
|
|
12454
|
-
})
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12834
|
+
})
|
|
12835
|
+
].filter((c) => c.text.length > 0);
|
|
12836
|
+
const structuredFragment = structured ? renderStructuredFields(structured) : "";
|
|
12837
|
+
const composeWith = (kept2) => composeSectionedPrompt(userPrompt, hintClauses.slice(0, kept2), structuredFragment);
|
|
12838
|
+
const cap = opts?.cap;
|
|
12839
|
+
if (cap === void 0) return composeWith(hintClauses.length);
|
|
12840
|
+
const frame = opts?.frame ?? ((body2) => body2);
|
|
12841
|
+
let kept = hintClauses.length;
|
|
12842
|
+
let body = composeWith(kept);
|
|
12843
|
+
let framedLength = frame(body)?.length ?? 0;
|
|
12844
|
+
if (framedLength <= cap) return body;
|
|
12845
|
+
const costs = sectionedClauseCosts(userPrompt, hintClauses, structuredFragment);
|
|
12846
|
+
const texts = hintClauses.map((c) => c.text);
|
|
12847
|
+
while (framedLength > cap && kept > 0) {
|
|
12848
|
+
kept = keepableDirectionHints(texts, kept, framedLength - cap, costs);
|
|
12849
|
+
body = composeWith(kept);
|
|
12850
|
+
framedLength = frame(body)?.length ?? 0;
|
|
12851
|
+
}
|
|
12852
|
+
return body;
|
|
12459
12853
|
}
|
|
12460
12854
|
|
|
12461
12855
|
// src/read-node-direction.ts
|
|
@@ -12480,6 +12874,31 @@ function readDirectionFields(value) {
|
|
|
12480
12874
|
}
|
|
12481
12875
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
12482
12876
|
}
|
|
12877
|
+
function readSubjectFields(value) {
|
|
12878
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
12879
|
+
const src = value;
|
|
12880
|
+
const out = {};
|
|
12881
|
+
for (const key of getRegisteredSubjectKeys()) {
|
|
12882
|
+
const v = src[key];
|
|
12883
|
+
if (key === SUBJECT_CUSTOM_AGE_KEY) {
|
|
12884
|
+
if (typeof v === "number" && Number.isFinite(v)) out[key] = v;
|
|
12885
|
+
continue;
|
|
12886
|
+
}
|
|
12887
|
+
if (typeof v === "string") {
|
|
12888
|
+
if (v.length > 0 && v.length <= SUBJECT_ID_MAX_CHARS) out[key] = v;
|
|
12889
|
+
} else if (Array.isArray(v)) {
|
|
12890
|
+
const kept = [];
|
|
12891
|
+
for (const x of v) {
|
|
12892
|
+
if (kept.length >= SUBJECT_ARRAY_CEILING) break;
|
|
12893
|
+
if (typeof x === "string" && x.length > 0 && x.length <= SUBJECT_ID_MAX_CHARS) {
|
|
12894
|
+
kept.push(x);
|
|
12895
|
+
}
|
|
12896
|
+
}
|
|
12897
|
+
if (kept.length > 0) out[key] = kept;
|
|
12898
|
+
}
|
|
12899
|
+
}
|
|
12900
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
12901
|
+
}
|
|
12483
12902
|
var GENDERS = ["man", "woman", "child", "non-binary"];
|
|
12484
12903
|
var MAX_STRUCTURED_VALUE_CHARS = 200;
|
|
12485
12904
|
var PERSON_FIELDS2 = {
|
|
@@ -33804,6 +34223,7 @@ exports.EXPOSURE_SETTINGS = EXPOSURE_SETTINGS;
|
|
|
33804
34223
|
exports.FACTORY_PRESETS = FACTORY_PRESETS;
|
|
33805
34224
|
exports.FACTORY_SNIPPETS = FACTORY_SNIPPETS;
|
|
33806
34225
|
exports.FILM_STILL_PREFIX = FILM_STILL_PREFIX;
|
|
34226
|
+
exports.FILM_STYLE_KEYS = FILM_STYLE_KEYS;
|
|
33807
34227
|
exports.FRAMINGS = FRAMINGS;
|
|
33808
34228
|
exports.FRAMING_CATEGORY_LABELS = FRAMING_CATEGORY_LABELS;
|
|
33809
34229
|
exports.FRAMING_CATEGORY_ORDER = FRAMING_CATEGORY_ORDER;
|
|
@@ -33839,6 +34259,7 @@ exports.MATERIAL_IDS = MATERIAL_IDS;
|
|
|
33839
34259
|
exports.MAX_SELECTED_BY_DIMENSION = MAX_SELECTED_BY_DIMENSION;
|
|
33840
34260
|
exports.MAX_SELECTED_BY_FRAMING_CATEGORY = MAX_SELECTED_BY_FRAMING_CATEGORY;
|
|
33841
34261
|
exports.MAX_SELECTED_BY_STYLING_DIMENSION = MAX_SELECTED_BY_STYLING_DIMENSION;
|
|
34262
|
+
exports.MAX_SUBJECT_KEYS = MAX_SUBJECT_KEYS;
|
|
33842
34263
|
exports.MOODS = MOODS;
|
|
33843
34264
|
exports.MOOD_CATEGORY_LABELS = MOOD_CATEGORY_LABELS;
|
|
33844
34265
|
exports.MOOD_CATEGORY_ORDER = MOOD_CATEGORY_ORDER;
|
|
@@ -33913,11 +34334,22 @@ exports.SNIPPET_MEDIA_VALUES = SNIPPET_MEDIA_VALUES;
|
|
|
33913
34334
|
exports.STYLES = STYLES;
|
|
33914
34335
|
exports.STYLE_IDS = STYLE_IDS;
|
|
33915
34336
|
exports.STYLE_PRESETS = STYLE_PRESETS;
|
|
34337
|
+
exports.STYLE_SECTION_GAP = STYLE_SECTION_GAP;
|
|
34338
|
+
exports.STYLE_SECTION_HEADER = STYLE_SECTION_HEADER;
|
|
33916
34339
|
exports.STYLINGS = STYLINGS;
|
|
33917
34340
|
exports.STYLING_DIMENSION_LABELS = STYLING_DIMENSION_LABELS;
|
|
33918
34341
|
exports.STYLING_DIMENSION_ORDER = STYLING_DIMENSION_ORDER;
|
|
33919
34342
|
exports.STYLING_FIELD_BY_DIMENSION = STYLING_FIELD_BY_DIMENSION;
|
|
33920
34343
|
exports.STYLING_IDS = STYLING_IDS;
|
|
34344
|
+
exports.SUBJECT_ARRAY_CEILING = SUBJECT_ARRAY_CEILING;
|
|
34345
|
+
exports.SUBJECT_CUSTOM_AGE_KEY = SUBJECT_CUSTOM_AGE_KEY;
|
|
34346
|
+
exports.SUBJECT_FIELDS = SUBJECT_FIELDS;
|
|
34347
|
+
exports.SUBJECT_FOLD_KEYS = SUBJECT_FOLD_KEYS;
|
|
34348
|
+
exports.SUBJECT_ID_MAX_CHARS = SUBJECT_ID_MAX_CHARS;
|
|
34349
|
+
exports.SUBJECT_IMAGE_HINT_MODE_DEFAULT = SUBJECT_IMAGE_HINT_MODE_DEFAULT;
|
|
34350
|
+
exports.SUBJECT_KEYS = SUBJECT_KEYS;
|
|
34351
|
+
exports.SUBJECT_KEY_MAX_CHARS = SUBJECT_KEY_MAX_CHARS;
|
|
34352
|
+
exports.SUBJECT_VIDEO_HINT_MODE_DEFAULT = SUBJECT_VIDEO_HINT_MODE_DEFAULT;
|
|
33921
34353
|
exports.TEMPORALS = TEMPORALS;
|
|
33922
34354
|
exports.TEMPORAL_CATEGORY_LABELS = TEMPORAL_CATEGORY_LABELS;
|
|
33923
34355
|
exports.TEMPORAL_CATEGORY_ORDER = TEMPORAL_CATEGORY_ORDER;
|
|
@@ -33956,6 +34388,7 @@ exports.applyPickerJson = applyPickerJson;
|
|
|
33956
34388
|
exports.applyPromptAffixes = applyPromptAffixes;
|
|
33957
34389
|
exports.applyReferenceOrderToVideo = applyReferenceOrderToVideo;
|
|
33958
34390
|
exports.applyTemplate = applyTemplate;
|
|
34391
|
+
exports.asBodyClauses = asBodyClauses;
|
|
33959
34392
|
exports.assembleImageInput = assembleImageInput;
|
|
33960
34393
|
exports.assembleSunoInput = assembleSunoInput;
|
|
33961
34394
|
exports.buildActionFxHints = buildActionFxHints;
|
|
@@ -33978,6 +34411,7 @@ exports.buildIdentityDirectives = buildIdentityDirectives;
|
|
|
33978
34411
|
exports.buildIdentityLockLine = buildIdentityLockLine;
|
|
33979
34412
|
exports.buildImagePrompt = buildImagePrompt;
|
|
33980
34413
|
exports.buildImagePromptSegments = buildImagePromptSegments;
|
|
34414
|
+
exports.buildImagePromptWithOverflow = buildImagePromptWithOverflow;
|
|
33981
34415
|
exports.buildInstrumentationHints = buildInstrumentationHints;
|
|
33982
34416
|
exports.buildInstrumentationTerms = buildInstrumentationTerms;
|
|
33983
34417
|
exports.buildLightingHints = buildLightingHints;
|
|
@@ -34028,6 +34462,7 @@ exports.composeCameraMotionTermFromConnections = composeCameraMotionTermFromConn
|
|
|
34028
34462
|
exports.composeCharacterFxHintFromConnections = composeCharacterFxHintFromConnections;
|
|
34029
34463
|
exports.composeNegative = composeNegative;
|
|
34030
34464
|
exports.composePickerCatalogs = composePickerCatalogs;
|
|
34465
|
+
exports.composeSectionedPrompt = composeSectionedPrompt;
|
|
34031
34466
|
exports.composeSoundHintFromConnections = composeSoundHintFromConnections;
|
|
34032
34467
|
exports.composeTransitionHintFromConnections = composeTransitionHintFromConnections;
|
|
34033
34468
|
exports.composeVideoPromptText = composeVideoPromptText;
|
|
@@ -34036,6 +34471,7 @@ exports.computeNodePrompt = computeNodePrompt;
|
|
|
34036
34471
|
exports.computePackSidecarCoverage = computePackSidecarCoverage;
|
|
34037
34472
|
exports.deriveTerm = deriveTerm;
|
|
34038
34473
|
exports.directionFieldsForSurface = directionFieldsForSurface;
|
|
34474
|
+
exports.endsInsideStyleSection = endsInsideStyleSection;
|
|
34039
34475
|
exports.expandImagePositionRefs = expandImagePositionRefs;
|
|
34040
34476
|
exports.expandImageRefTokens = expandImageRefTokens;
|
|
34041
34477
|
exports.filmStillPrefix = filmStillPrefix;
|
|
@@ -34168,6 +34604,7 @@ exports.getRegisteredPersonDimensionLabels = getRegisteredPersonDimensionLabels;
|
|
|
34168
34604
|
exports.getRegisteredPersonDimensionOrder = getRegisteredPersonDimensionOrder;
|
|
34169
34605
|
exports.getRegisteredPersonFieldByDimension = getRegisteredPersonFieldByDimension;
|
|
34170
34606
|
exports.getRegisteredPickerCatalogs = getRegisteredPickerCatalogs;
|
|
34607
|
+
exports.getRegisteredSubjectKeys = getRegisteredSubjectKeys;
|
|
34171
34608
|
exports.getRenderQuality = getRenderQuality;
|
|
34172
34609
|
exports.getRenderQualityLabel = getRenderQualityLabel;
|
|
34173
34610
|
exports.getRenderQualityPromptHint = getRenderQualityPromptHint;
|
|
@@ -34221,6 +34658,7 @@ exports.getWardrobePromptHint = getWardrobePromptHint;
|
|
|
34221
34658
|
exports.groupFactoryPresets = groupFactoryPresets;
|
|
34222
34659
|
exports.hasUpstreamCharacter = hasUpstreamCharacter;
|
|
34223
34660
|
exports.identityRefsSentence = identityRefsSentence;
|
|
34661
|
+
exports.insertBeforeStyleSection = insertBeforeStyleSection;
|
|
34224
34662
|
exports.isAnalyzablePicker = isAnalyzablePicker;
|
|
34225
34663
|
exports.isInstrumentalVocal = isInstrumentalVocal;
|
|
34226
34664
|
exports.isSuspiciousDerivedTerm = isSuspiciousDerivedTerm;
|
|
@@ -34228,12 +34666,15 @@ exports.isVantageFraming = isVantageFraming;
|
|
|
34228
34666
|
exports.isWizardSupported = isWizardSupported;
|
|
34229
34667
|
exports.joinPromptHints = joinPromptHints;
|
|
34230
34668
|
exports.joinPromptParts = joinPromptParts;
|
|
34669
|
+
exports.keepableDirectionHints = keepableDirectionHints;
|
|
34231
34670
|
exports.listPickerCatalogs = listPickerCatalogs;
|
|
34232
34671
|
exports.migratePersonValue = migratePersonValue;
|
|
34233
34672
|
exports.modeForFamily = modeForFamily;
|
|
34234
34673
|
exports.nodeHasInlinePrompt = nodeHasInlinePrompt;
|
|
34235
34674
|
exports.nodeHasPromptField = nodeHasPromptField;
|
|
34236
34675
|
exports.nodeSupportsPromptAffixes = nodeSupportsPromptAffixes;
|
|
34676
|
+
exports.normalizeSubjectFields = normalizeSubjectFields;
|
|
34677
|
+
exports.partitionStyleClauses = partitionStyleClauses;
|
|
34237
34678
|
exports.personPacksVersion = personPacksVersion;
|
|
34238
34679
|
exports.pickerFanoutTargets = pickerFanoutTargets;
|
|
34239
34680
|
exports.projectAllCatalogs = projectAllCatalogs;
|
|
@@ -34244,11 +34685,15 @@ exports.promptFieldCarriesAffixes = promptFieldCarriesAffixes;
|
|
|
34244
34685
|
exports.promptPartSeparator = promptPartSeparator;
|
|
34245
34686
|
exports.readDirectionFields = readDirectionFields;
|
|
34246
34687
|
exports.readStructuredFields = readStructuredFields;
|
|
34688
|
+
exports.readSubjectFields = readSubjectFields;
|
|
34247
34689
|
exports.referenceRulesBlock = referenceRulesBlock;
|
|
34248
34690
|
exports.registerCatalogPack = registerCatalogPack;
|
|
34249
34691
|
exports.registerPersonPack = registerPersonPack;
|
|
34692
|
+
exports.renderDirectionHintClauses = renderDirectionHintClauses;
|
|
34250
34693
|
exports.renderDirectionHints = renderDirectionHints;
|
|
34251
34694
|
exports.renderStructuredFields = renderStructuredFields;
|
|
34695
|
+
exports.renderStyleSection = renderStyleSection;
|
|
34696
|
+
exports.renderSubjectHints = renderSubjectHints;
|
|
34252
34697
|
exports.resetCatalogPacks = resetCatalogPacks;
|
|
34253
34698
|
exports.resetPersonPacks = resetPersonPacks;
|
|
34254
34699
|
exports.resolveBrandInput = resolveBrandInput;
|
|
@@ -34263,6 +34708,11 @@ exports.resolveTemplate = resolveTemplate;
|
|
|
34263
34708
|
exports.resolveTerm = resolveTerm;
|
|
34264
34709
|
exports.resolveVeoI2vInputs = resolveVeoI2vInputs;
|
|
34265
34710
|
exports.resolveVideoReferenceCore = resolveVideoReferenceCore;
|
|
34711
|
+
exports.sectionedClauseCosts = sectionedClauseCosts;
|
|
34712
|
+
exports.splitStyleSection = splitStyleSection;
|
|
34713
|
+
exports.styleSectionFromClauses = styleSectionFromClauses;
|
|
34714
|
+
exports.styleSlotFor = styleSlotFor;
|
|
34715
|
+
exports.subjectFieldsForSurface = subjectFieldsForSurface;
|
|
34266
34716
|
exports.summarizePickerCatalogs = summarizePickerCatalogs;
|
|
34267
34717
|
exports.toIdentityLockMode = toIdentityLockMode;
|
|
34268
34718
|
exports.truncateForField = truncateForField;
|