Files
ChatAIBot/tests/test_sd_prompt.py
T
2026-06-02 15:03:39 +03:00

244 lines
9.1 KiB
Python

"""Unit tests for layered Anima prompt assembly (no LLM)."""
import os
import sys
from unittest.mock import patch
import pytest
# Ensure project root on path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from services import sd_prompt as sp
@pytest.fixture
def anima():
with patch.object(sp, "_is_anima", return_value=True), patch.object(sp, "_is_pony", return_value=False):
yield
PERSONA_WOLF = {
"appearance_tags": "wolfgirl, white_hair, golden_eyes, wolf_ears, tail, big_breast",
"appearance_prose": "",
"lora_name": "",
}
PERSONA_CARRIE = {
"appearance_tags": "short_hair, brown_hair, blue_eyes, skinny",
"appearance_prose": "",
"lora_name": "",
}
def test_walking_scene_includes_action_tags_and_contextual_pov(anima):
scene = sp._sanitize_scene_fields({
"shot_type": "first_person_pov",
"pov_cue": "walking_together",
"viewer_body_visible": False,
"action_tags": "holding_hands, walking, smiling, looking_at_each_other",
"environment_tags": "outdoors, sunlight, golden_hour",
"scene_description": "She walks beside you, laughter in the warm afternoon light.",
})
hybrid = sp.build_positive_prompt_hybrid(scene, PERSONA_WOLF, "")
assert "walking" in hybrid
assert "smiling" in hybrid
assert "holding_hands" not in hybrid
assert "looking_at_each_other" not in hybrid
assert "outdoors" in hybrid
assert "threshold" not in hybrid.lower()
assert "POV: walking beside you" in hybrid
assert "someone" not in hybrid.lower()
assert "both " not in hybrid.lower()
def test_hybrid_differs_from_tags_only_when_prose_present(anima):
scene = {
"shot_type": "first_person_pov",
"pov_cue": "walking_together",
"viewer_body_visible": False,
"action_tags": "holding_hands, walking",
"environment_tags": "outdoors, sunlight",
"scene_description": "Shared laughter drifts through the golden afternoon.",
}
tags_only = sp.build_positive_prompt_tags_only(scene, PERSONA_WOLF, "")
hybrid = sp.build_positive_prompt_hybrid(scene, PERSONA_WOLF, "")
assert tags_only != hybrid
assert "Shared laughter" in hybrid
assert "Shared laughter" not in tags_only
def test_carrie_doorway_scene(anima):
scene = {
"shot_type": "first_person_pov",
"pov_cue": "doorway_invite",
"viewer_body_visible": False,
"action_tags": "arms_out, inviting_hug, smirk, looking_at_viewer",
"environment_tags": "doorway, apartment, night, indoors",
"scene_description": "She waits in the doorway with playful hunger in half-lidded eyes.",
}
outfit = "crop_top, ripped_jeans, black_jeans"
hybrid = sp.build_positive_prompt_hybrid(scene, PERSONA_CARRIE, outfit)
assert "arms_out" in hybrid
assert "doorway" in hybrid
assert "crop_top" in hybrid
assert "threshold" not in hybrid.lower()
assert "POV: she blocks the doorway" in hybrid
def test_pov_inferred_from_action_when_cue_missing(anima):
scene = {
"shot_type": "first_person_pov",
"action_tags": "holding_hands, walking, smiling",
"environment_tags": "outdoors, park",
"scene_description": "",
}
tags = sp.build_positive_prompt_tags_only(scene, PERSONA_WOLF, "")
assert "POV: walking beside you" in tags
def test_negative_includes_interaction_block_for_pov_contact(anima):
scene = {
"shot_type": "first_person_pov",
"viewer_body_visible": False,
"action_tags": "arms_out, hug, inviting_hug",
"environment_tags": "doorway",
}
neg = sp._negative_for_scene(scene)
assert "duplicate" in neg
assert "extra_person" in neg
assert "third person" in neg
def test_scene_should_generate_false():
assert sp._scene_should_generate({"should_generate": False}) is False
assert sp._scene_should_generate({"should_generate": True}) is True
assert sp._scene_should_generate({}) is True
def test_format_builder_user_block_illustrate_vs_context(anima):
messages = [
{"role": "assistant", "content": "Long old first_mes " + ("x" * 900)},
{"role": "user", "content": "Hi"},
{"role": "assistant", "content": "*walks holding your hand*"},
]
block = sp._format_builder_user_block(PERSONA_WOLF, messages, "[]")
assert "=== ILLUSTRATE" in block
assert "=== Context" in block
assert "*walks holding your hand*" in block
assert "Long old first_mes" in block
assert len(block.split("Long old first_mes")[1].split("assistant:")[0]) < 900
def test_bundle_from_scene_anima_uses_hybrid_as_tag_full(anima):
scene = {
"should_generate": True,
"shot_type": "first_person_pov",
"pov_cue": "face_to_face",
"action_tags": "smiling",
"environment_tags": "indoors",
"scene_description": "A warm smile greets you.",
}
with patch.object(sp, "anima_dual_enabled", return_value=False):
bundle = sp._bundle_from_scene(scene, PERSONA_WOLF, "")
assert "A warm smile" in bundle.tag_full
assert bundle.desc_full is None
def test_user_example_walking_llm_output_cleaned(anima):
"""Regression: LLM prose/sentence leakage and second-person refs."""
scene = sp._sanitize_scene_fields({
"shot_type": "first_person_pov",
"pov_cue": "walking_together",
"action_tags": (
"holding_hands, walking, smiling, looking_at_each_other, "
"A wolfgirl walks hand in hand with someone, both smiling and chatting"
),
"environment_tags": "outdoor, daylight, path",
"scene_description": (
"A wolfgirl walks hand in hand with someone, both smiling and chatting under the daylight."
),
})
persona = {**PERSONA_WOLF, "appearance_tags": PERSONA_WOLF["appearance_tags"] + ", pumped_up"}
tags_only = sp.build_positive_prompt_tags_only(scene, persona, "")
hybrid = sp.build_positive_prompt_hybrid(scene, persona, "")
assert "pumped_up" not in tags_only
assert "someone" not in hybrid.lower()
assert "both " not in hybrid.lower()
assert ". A wolfgirl walks" not in tags_only
assert tags_only != hybrid or not scene.get("scene_description")
def test_user_example_carrie_env_reconciled(anima):
scene = sp._sanitize_scene_fields({
"shot_type": "first_person_pov",
"pov_cue": "doorway_invite",
"action_tags": "arms_out, inviting_hug, smirk, half-lidded_eyes",
"environment_tags": "doorway, nighttime, outdoor",
"scene_description": (
"Carrie stands in her doorway at night, arms outstretched toward you with a mischievous smirk."
),
})
hybrid = sp.build_positive_prompt_hybrid(
scene, PERSONA_CARRIE, "crop_top, ripped_jeans, black_jeans, jeans"
)
assert "outdoor" not in hybrid.lower() or "doorway" in hybrid
assert ", jeans," not in f", {hybrid},"
assert "someone" not in hybrid.lower()
def test_long_first_mes_uses_final_beat(anima):
carrie_tail = (
"About an hour later...\n\n"
"Carrie stood at her front door, arms out, smirking. "
'"Come on, hug me. Now." It\'s getting cold out.'
)
long = ("She shops for clothes.\n\n" * 5) + carrie_tail
excerpt = sp._extract_illustrate_content(long)
assert "front door" in excerpt or "hug me" in excerpt
assert "shops for clothes" not in excerpt
def test_hybrid_gets_fallback_when_no_scene_description(anima):
scene = sp._sanitize_scene_fields({
"shot_type": "first_person_pov",
"pov_cue": "walking_together",
"action_tags": "walking, smiling",
"environment_tags": "outdoor, daylight",
"scene_description": "",
})
tags_only = sp.build_positive_prompt_tags_only(scene, PERSONA_WOLF, "")
hybrid = sp.build_positive_prompt_hybrid(scene, PERSONA_WOLF, "")
assert hybrid != tags_only
assert "afternoon" in hybrid.lower() or "laughter" in hybrid.lower()
def test_yuki_pov_drops_lifting_and_nose_rub(anima):
scene = sp._sanitize_scene_fields({
"shot_type": "first_person_pov",
"pov_cue": "face_to_face",
"action_tags": "arms_out, lifting, nose_rub, smiling",
"environment_tags": "indoors, warm_lighting",
"scene_description": "Her golden eyes soften with warmth toward the camera.",
})
hybrid = sp.build_positive_prompt_hybrid(scene, {**PERSONA_WOLF, "appearance_tags": "fox_girl, golden_eyes"}, "pink_sweater")
assert "lifting" not in hybrid
assert "nose_rub" not in hybrid
assert "golden" in hybrid.lower()
def test_bundle_tags_only_alt_when_dual_compare(anima):
scene = {
"shot_type": "first_person_pov",
"pov_cue": "dialogue_close",
"action_tags": "smiling",
"environment_tags": "indoors",
"scene_description": "Soft light on her face.",
}
with patch.object(sp, "anima_dual_enabled", return_value=True):
bundle = sp._bundle_from_scene(scene, PERSONA_WOLF, "")
assert bundle.desc_full is not None
assert bundle.desc_full != bundle.tag_full
assert "Soft light" in bundle.tag_full
assert "Soft light" not in bundle.desc_full.split(sp.NEGATIVE_PROMPT_SEPARATOR)[0]