Keep multiline beat prompts intact
This commit is contained in:
+20
-35
@@ -317,34 +317,25 @@ def expand_beats(paras, mode="auto"):
|
|||||||
(beats, note).
|
(beats, note).
|
||||||
|
|
||||||
Beats are separated by a BLANK line (or a '##' line). That is unambiguous, but
|
Beats are separated by a BLANK line (or a '##' line). That is unambiguous, but
|
||||||
it is also the single easiest thing to get wrong in a textarea: six beats typed
|
it is also easy to misread once a dedicated beat editor exists: inside the
|
||||||
on six consecutive lines are one paragraph, so they render as ONE shot with six
|
beat editor, one textbox is one beat, so plain newlines inside that textbox
|
||||||
actions crammed into it -- which reads as characters moving at triple speed, not
|
should stay inside the same beat rather than quietly creating new shots.
|
||||||
as a splitting problem.
|
|
||||||
|
|
||||||
mode:
|
mode:
|
||||||
'auto' -- blank lines first; any paragraph still holding more than one
|
'auto' -- preserve each paragraph as one beat.
|
||||||
content line is then split one beat per line, and says so.
|
'each line' -- every content line is its own beat, with directive lines
|
||||||
'each line' -- every content line is its own beat. Same result as 'auto'; kept
|
attaching to the beat they configure.
|
||||||
so the intent can be stated explicitly.
|
|
||||||
|
|
||||||
There is deliberately no strict blank-lines-only mode any more. It was the ONE
|
|
||||||
setting that could silently lose beats: six beats typed as two blocks of three
|
|
||||||
rendered as two shots, with no note to say why, because the split note is only
|
|
||||||
written when a paragraph is actually split. Nothing else on the node can change
|
|
||||||
the beat count, so removing that option removes the whole failure class. A
|
|
||||||
workflow that still stores 'blank line' falls through to 'auto' below.
|
|
||||||
|
|
||||||
Directive lines ('wardrobe:', 'seconds:', 'exit:' ...) are never beats of their
|
Directive lines ('wardrobe:', 'seconds:', 'exit:' ...) are never beats of their
|
||||||
own: they attach to the next content line, or to the previous beat if they
|
own: they attach to the next content line, or to the previous beat if they
|
||||||
trail the paragraph."""
|
trail the paragraph."""
|
||||||
# Any unrecognized mode means AUTO, never "do nothing". An earlier version fell
|
# Any unrecognized mode means AUTO, never "do nothing". Older workflows may
|
||||||
# through an if/elif with no else and silently DROPPED every multi-line paragraph
|
# still store removed values such as 'blank line'; those should preserve whole
|
||||||
# -- six beats arrived as two shots with four beats simply gone. A stale value on
|
# paragraphs instead of unexpectedly splitting every newline into a beat.
|
||||||
# this widget (including 'blank line' from a workflow saved before it was removed)
|
|
||||||
# is enough to trigger it, so the safe branch has to be the default.
|
|
||||||
if mode not in ("auto", "each line"):
|
if mode not in ("auto", "each line"):
|
||||||
mode = "auto"
|
mode = "auto"
|
||||||
|
if mode == "auto":
|
||||||
|
return [p.strip() for p in (paras or []) if str(p or "").strip()], ""
|
||||||
out, split_from = [], 0
|
out, split_from = [], 0
|
||||||
for p in paras:
|
for p in paras:
|
||||||
lines = [ln for ln in (p or "").splitlines() if ln.strip()]
|
lines = [ln for ln in (p or "").splitlines() if ln.strip()]
|
||||||
@@ -370,10 +361,9 @@ def expand_beats(paras, mode="auto"):
|
|||||||
else:
|
else:
|
||||||
out.append(NL.join(pending))
|
out.append(NL.join(pending))
|
||||||
note = ""
|
note = ""
|
||||||
if split_from and mode == "auto":
|
if split_from:
|
||||||
note = (f"{split_from} paragraph(s) held several lines and were split one beat per LINE "
|
note = (f"beat_split '{mode}' split {split_from} multi-line paragraph(s) into "
|
||||||
f"-> {len(out)} beats. Separate beats with a BLANK line (or a '##' line) to control "
|
f"{len(out)} beats")
|
||||||
f"this yourself")
|
|
||||||
return out, note
|
return out, note
|
||||||
|
|
||||||
|
|
||||||
@@ -6154,17 +6144,12 @@ class H3LongVideos:
|
|||||||
"EVERY ref-conditioned shot, so on a long chain it is several times "
|
"EVERY ref-conditioned shot, so on a long chain it is several times "
|
||||||
"slower. Neither ever upscales a small reference."}),
|
"slower. Neither ever upscales a small reference."}),
|
||||||
"beat_split": (["auto", "each line"], {"default": "auto",
|
"beat_split": (["auto", "each line"], {"default": "auto",
|
||||||
"tooltip": "How the prompt box becomes beats. Beats are meant to be separated by a "
|
"tooltip": "How the prompt box becomes beats. Beats are separated by a BLANK line "
|
||||||
"BLANK line (or a '##' line) -- but six beats typed on six consecutive "
|
"(or a '##' line). auto (default): each paragraph stays one beat, so "
|
||||||
"lines are ONE paragraph, so they would render as one shot with six actions "
|
"plain newlines inside a beat remain part of that beat. 'each line': every "
|
||||||
"crammed into it, which looks like everyone is moving at triple speed. "
|
"content line becomes its own beat, with directive lines (wardrobe:, "
|
||||||
"auto (default): blank lines first, then any paragraph still holding "
|
"seconds:, exit:, etc.) attaching to the beat they configure. Older "
|
||||||
"several lines is split one beat per LINE, and the info output says so. "
|
"removed values such as 'blank line' now behave like 'auto'."}),
|
||||||
"'each line': every line is its own beat -- same result, stated explicitly. "
|
|
||||||
"Neither can lose a beat. (The old strict 'blank line' option was REMOVED: "
|
|
||||||
"it was the only setting that could silently collapse beats, and a stored "
|
|
||||||
"value of it now reads as 'auto'.) Directive lines (wardrobe:, seconds:, exit:) "
|
|
||||||
"are never beats -- they attach to the beat that follows them."}),
|
|
||||||
"anchor_override": ("STRING", {"multiline": True, "forceInput": True, "default": "",
|
"anchor_override": ("STRING", {"multiline": True, "forceInput": True, "default": "",
|
||||||
"tooltip": "Set the persistent look explicitly instead of using the first paragraph. "
|
"tooltip": "Set the persistent look explicitly instead of using the first paragraph. "
|
||||||
"When this is filled in, EVERY paragraph of the prompt box is a beat/shot -- "
|
"When this is filled in, EVERY paragraph of the prompt box is a beat/shot -- "
|
||||||
|
|||||||
@@ -160,6 +160,45 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
"keyframe carry",
|
"keyframe carry",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_expand_beats_auto_preserves_multiline_paragraph_as_one_beat(self):
|
||||||
|
beats, note = self.module.expand_beats(
|
||||||
|
["wardrobe: Maya = red jacket\nMaya enters the room.\nShe sits at the table."],
|
||||||
|
"auto",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
beats,
|
||||||
|
["wardrobe: Maya = red jacket\nMaya enters the room.\nShe sits at the table."],
|
||||||
|
)
|
||||||
|
self.assertEqual(note, "")
|
||||||
|
|
||||||
|
def test_expand_beats_legacy_blank_line_value_falls_back_to_auto(self):
|
||||||
|
beats, note = self.module.expand_beats(
|
||||||
|
["Maya enters the room.\nShe sits at the table."],
|
||||||
|
"blank line",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
beats,
|
||||||
|
["Maya enters the room.\nShe sits at the table."],
|
||||||
|
)
|
||||||
|
self.assertEqual(note, "")
|
||||||
|
|
||||||
|
def test_expand_beats_each_line_still_splits_multiline_paragraphs(self):
|
||||||
|
beats, note = self.module.expand_beats(
|
||||||
|
["wardrobe: Maya = red jacket\nMaya enters the room.\nseconds: 8\nShe sits at the table."],
|
||||||
|
"each line",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
beats,
|
||||||
|
[
|
||||||
|
"wardrobe: Maya = red jacket\nMaya enters the room.",
|
||||||
|
"seconds: 8\nShe sits at the table.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self.assertIn("beat_split 'each line' split 1 multi-line paragraph(s) into 2 beats", note)
|
||||||
|
|
||||||
def test_timing_summary_reports_retry_and_bucket_totals(self):
|
def test_timing_summary_reports_retry_and_bucket_totals(self):
|
||||||
note = self.module._format_timing_note([
|
note = self.module._format_timing_note([
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user