test(workspace): concept fixture carries the concept inspector facts

This commit is contained in:
Vito Sansevero
2026-10-19 22:48:39 -07:00
parent 383b724369
commit 720231f7ba
2 changed files with 161 additions and 30 deletions
+77 -30
View File
@@ -24,10 +24,15 @@ from uuid import UUID, uuid5
from PIL import Image, ImageDraw
from PIL.PngImagePlugin import PngInfo
from tests.browser.workspace_history_fixture import _snapshot
from utils.execution_contexts import ContextBundle, RecipeContext
from utils.execution_contexts import (
ContextBundle,
PromptSnapshot,
RecipeContext,
TextEvidence,
)
from utils.execution_history_events import make_finish, make_start
from utils.execution_outputs import OutputBundle, OutputReference, snapshot_output_roots
from utils.pair_execution import EXECUTION_KEY
if TYPE_CHECKING:
from py.api import PromptManagerAPI
@@ -147,6 +152,8 @@ CONCEPT_DIMENSIONS = (
)
CONCEPT_IMAGE_ROUNDS = 4
CONCEPT_RUN_COUNT = 4
# The concept's Model fact (app.js:408).
CONCEPT_MODEL = "illustrative-model.safetensors"
MAX_EXTRA_IMAGES = 120
SESSION = "5c1f9a7e-3f0b-4a55-9d0e-2b8c4f6a7d10"
_TABLES = (
@@ -180,48 +187,91 @@ def concept_filename(prompt: ConceptPrompt, round_index: int) -> str:
def _graph(positive: str, negative: str, seed: int) -> dict:
"""A ComfyUI API prompt with one sampler, so the seed is unambiguous."""
"""A ComfyUI API prompt with the concept's facts (app.js:406-408).
The recipe is a Prompt Manager pair node, so with its embedded execution record
the inspector reports both roles as execution evidence, which the panel badges
"Execution recorded" (D21). One sampler keeps the seed unambiguous.
"""
return {
"1": {"class_type": "CLIPTextEncode", "inputs": {"text": positive}},
"2": {"class_type": "CLIPTextEncode", "inputs": {"text": negative}},
"1": {
"class_type": "PromptManagerPair",
"inputs": {"text": positive, "negative_text": negative, "clip": ["2", 1]},
},
"2": {
"class_type": "CheckpointLoaderSimple",
"inputs": {"ckpt_name": CONCEPT_MODEL},
},
"3": {
"class_type": "KSampler",
"inputs": {
"model": ["2", 0],
"positive": ["1", 0],
"negative": ["2", 0],
"negative": ["1", 1],
"seed": seed,
"steps": 28,
"cfg": 6.5,
"sampler_name": "euler",
"scheduler": "normal",
"sampler_name": "dpmpp_2m",
"scheduler": "karras",
},
},
"4": {"class_type": "SaveImage", "inputs": {"images": ["3", 0]}},
}
def _write_png(
path: Path, prompt: ConceptPrompt, size: tuple[int, int], graph: dict
) -> None:
"""An original flat artwork in the prompt's concept palette."""
width, height = size
def _execution_record(positive: str, negative: str) -> dict:
"""The pair node's embedded execution evidence (utils/pair_execution.py)."""
record = {
"text": positive,
"negative_text": negative,
"positive_text": positive,
"negative_effective_text": negative,
"prepend_text": "",
"append_text": "",
}
return {"version": 1, "nodes": {"1": {"records": [record]}}}
def _snapshot(text: str) -> PromptSnapshot:
"""A recorded prompt snapshot whose raw and effective texts are ``text``."""
def known(value: str) -> TextEvidence:
return TextEvidence(value, "recorded", "runtime_return", None)
return PromptSnapshot(known(text), known(text), known(""), known(""))
def write_concept_png(path: Path, prompt_index: int, round_index: int) -> dict:
"""Write the concept's sample image ``round_index`` of prompt ``prompt_index``.
Returns its facts: variant, negative, seed and dimensions.
"""
prompt = CONCEPT_PROMPTS[prompt_index]
index = round_index * len(CONCEPT_PROMPTS) + prompt_index
variant = round_index % len(prompt.negatives)
negative = prompt.negatives[variant][1]
seed = concept_seed(prompt_index, round_index)
width, height = size = CONCEPT_DIMENSIONS[index % len(CONCEPT_DIMENSIONS)]
sky, ground, light = prompt.color
info = PngInfo()
info.add_text("prompt", json.dumps(graph))
info.add_text("prompt", json.dumps(_graph(prompt.positive, negative, seed)))
info.add_text(
EXECUTION_KEY, json.dumps(_execution_record(prompt.positive, negative))
)
with Image.new("RGB", size, sky) as image:
draw = ImageDraw.Draw(image)
draw.rectangle((0, height * 2 // 3, width, height), fill=ground)
radius = min(width, height) // 9
draw.ellipse(
(
width * 2 // 3,
height // 6,
width * 2 // 3 + radius,
height // 6 + radius,
),
fill=light,
)
left, top = width * 2 // 3, height // 6
draw.ellipse((left, top, left + radius, top + radius), fill=light)
image.save(path, pnginfo=info)
return {
"variant": variant,
"negative": negative,
"seed": seed,
"width": width,
"height": height,
}
def _clear(api: PromptManagerAPI, root: Path) -> None:
@@ -315,13 +365,10 @@ def seed_workspace_concept(
index = round_index * len(CONCEPT_PROMPTS) + prompt_index
if index >= total:
break
variant = round_index % len(prompt.negatives)
seed = concept_seed(prompt_index, round_index)
name = concept_filename(prompt, round_index)
path = folder / name
negative = prompt.negatives[variant][1]
size = CONCEPT_DIMENSIONS[index % len(CONCEPT_DIMENSIONS)]
_write_png(path, prompt, size, _graph(prompt.positive, negative, seed))
facts = write_concept_png(path, prompt_index, round_index)
variant, negative, seed = facts["variant"], facts["negative"], facts["seed"]
# The concept lists images newest first in this order.
stamp = now - 60 - index * 60
os.utime(path, (stamp, stamp))
@@ -353,8 +400,8 @@ def seed_workspace_concept(
"prompt": prompt.id,
"variant": variant,
"seed": seed,
"width": size[0],
"height": size[1],
"width": facts["width"],
"height": facts["height"],
}
)
with db.model.get_connection() as conn:
+84
View File
@@ -0,0 +1,84 @@
"""The concept fixture files carry the concept inspector facts (app.js:400-414)."""
import json
import tempfile
import unittest
from pathlib import Path
from PIL import Image
try:
from tests.open_handles import assert_closed
except ImportError: # discovered with tests/ as the top-level directory
from open_handles import assert_closed
from tests.browser.workspace_concept_fixture import (
CONCEPT_MODEL,
CONCEPT_PROMPTS,
write_concept_png,
)
from utils.prompt_inspector import inspect_prompt_evidence, read_inspection_file
class TestWorkspaceConceptFixture(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.addCleanup(assert_closed, self, self.tmp.name)
def write(self, prompt_index, round_index):
prompt = CONCEPT_PROMPTS[prompt_index]
path = Path(self.tmp.name) / f"{prompt.id}_{round_index + 1:05}.png"
image = write_concept_png(path, prompt_index, round_index)
return path, image
def test_each_image_carries_execution_evidence_and_the_concept_facts(self):
for prompt_index, round_index in ((0, 0), (0, 2), (3, 1), (5, 3)):
with self.subTest(prompt=prompt_index, round=round_index):
prompt = CONCEPT_PROMPTS[prompt_index]
path, image = self.write(prompt_index, round_index)
negative = prompt.negatives[round_index % len(prompt.negatives)][1]
inspection = read_inspection_file(path)
evidence = inspect_prompt_evidence(inspection.metadata)
# D21: "execution" is the source the panel badges "Execution recorded".
self.assertEqual(
evidence["prompts"]["positive"],
{
"status": "resolved",
"text": prompt.positive,
"source": "execution",
},
)
self.assertEqual(evidence["prompts"]["negative"]["text"], negative)
self.assertEqual(evidence["prompts"]["negative"]["source"], "execution")
graph = json.loads(inspection.metadata["prompt"])
sampler = next(
node["inputs"]
for node in graph.values()
if node["class_type"] == "KSampler"
)
self.assertEqual(
sampler["seed"], 42001 + prompt_index * 100 + round_index
)
self.assertEqual(sampler["seed"], image["seed"])
self.assertEqual(
(sampler["sampler_name"], sampler["scheduler"]),
("dpmpp_2m", "karras"),
)
self.assertEqual((sampler["steps"], sampler["cfg"]), (28, 6.5))
loader = graph[sampler["model"][0]]
self.assertEqual(loader["class_type"], "CheckpointLoaderSimple")
self.assertEqual(loader["inputs"]["ckpt_name"], CONCEPT_MODEL)
self.assertEqual(CONCEPT_MODEL, "illustrative-model.safetensors")
with Image.open(path) as source:
self.assertEqual(source.size, (image["width"], image["height"]))
def test_concept_dimensions_follow_the_prompt_index(self):
expected = [(1536, 1152), (1024, 1536), (1280, 1280)]
for prompt_index, size in enumerate(expected):
_, image = self.write(prompt_index, 1)
self.assertEqual((image["width"], image["height"]), size)
if __name__ == "__main__":
unittest.main()