Merge 0f6ab9c1de into 83082a51c4
This commit is contained in:
commit
ba95b07f7e
|
|
@ -170,6 +170,19 @@ def is_previewable(media_type: str, item: dict) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def is_text_preview(media_type: str, item: dict) -> bool:
|
||||
"""
|
||||
Check if a previewable output item is textual rather than visual media.
|
||||
|
||||
Saved text files (SaveText's .txt/.md/.json) are real outputs but must not
|
||||
outrank visual media when picking the job preview.
|
||||
"""
|
||||
if media_type == 'text':
|
||||
return True
|
||||
filename = item.get('filename', '').lower()
|
||||
return any(filename.endswith(ext) for ext in TEXT_EXTENSIONS)
|
||||
|
||||
|
||||
def normalize_queue_item(item: tuple, status: str) -> dict:
|
||||
"""Convert queue item tuple to unified job dict.
|
||||
|
||||
|
|
@ -259,8 +272,13 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
|
|||
Returns (outputs_count, preview_output).
|
||||
|
||||
Preview priority (matching frontend):
|
||||
1. type="output" with previewable media
|
||||
2. Any previewable media
|
||||
1. type="output" visual media (saved images/video/audio/3d)
|
||||
2. any other previewable visual media (e.g. temp/preview images)
|
||||
3. saved text file (e.g. SaveText's .txt/.md/.json)
|
||||
4. raw text (only when the job produced nothing else previewable)
|
||||
|
||||
Text is kept in its own slots so node/execution order can't let a text
|
||||
output mask a visual one (e.g. a text node that runs before an image).
|
||||
|
||||
Text content entries (strings under 'text') are preview-only metadata,
|
||||
matching the frontend's METADATA_KEYS: they can serve as the fallback
|
||||
|
|
@ -269,6 +287,8 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
|
|||
count = 0
|
||||
preview_output = None
|
||||
fallback_preview = None
|
||||
text_file_fallback = None
|
||||
text_fallback = None
|
||||
|
||||
for node_id, node_outputs in outputs.items():
|
||||
if not isinstance(node_outputs, dict):
|
||||
|
|
@ -296,8 +316,8 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
|
|||
'nodeId': node_id,
|
||||
'mediaType': media_type
|
||||
}
|
||||
if fallback_preview is None:
|
||||
fallback_preview = enriched
|
||||
if text_fallback is None:
|
||||
text_fallback = enriched
|
||||
continue
|
||||
# normalize_output_item returned a dict (e.g. 3D file)
|
||||
item = normalized
|
||||
|
|
@ -314,12 +334,15 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
|
|||
}
|
||||
if 'mediaType' not in item:
|
||||
enriched['mediaType'] = media_type
|
||||
if item.get('type') == 'output':
|
||||
if is_text_preview(media_type, item):
|
||||
if text_file_fallback is None:
|
||||
text_file_fallback = enriched
|
||||
elif item.get('type') == 'output':
|
||||
preview_output = enriched
|
||||
elif fallback_preview is None:
|
||||
fallback_preview = enriched
|
||||
|
||||
return count, preview_output or fallback_preview
|
||||
return count, preview_output or fallback_preview or text_file_fallback or text_fallback
|
||||
|
||||
|
||||
def apply_sorting(jobs: list[dict], sort_by: str, sort_order: str) -> list[dict]:
|
||||
|
|
|
|||
|
|
@ -280,6 +280,86 @@ class TestGetOutputsSummary:
|
|||
assert preview['filename'] == 'model.glb'
|
||||
assert preview['mediaType'] == '3d'
|
||||
|
||||
def test_media_preview_preferred_over_text(self):
|
||||
"""A visual output wins the preview even when a text node is iterated
|
||||
first (regression: text could mask a later temp/preview image)."""
|
||||
outputs = {
|
||||
'text_node': {'text': ['a caption']},
|
||||
'image_node': {'images': [{'filename': 'preview.png', 'type': 'temp'}]},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
# Text is preview-only metadata and not counted; only the image counts.
|
||||
assert count == 1
|
||||
assert preview['filename'] == 'preview.png'
|
||||
assert preview['mediaType'] == 'images'
|
||||
|
||||
def test_text_used_as_preview_when_no_media(self):
|
||||
"""Text is the preview only when the job produced no media output."""
|
||||
outputs = {
|
||||
'text_node': {'text': ['hello world']},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
assert count == 0 # text entries are not counted as outputs
|
||||
assert preview['mediaType'] == 'text'
|
||||
assert preview['content'] == 'hello world'
|
||||
|
||||
def test_media_preview_preferred_over_saved_text_file(self):
|
||||
"""A visual output wins the preview over a saved text file (SaveText),
|
||||
even a temp/preview image iterated after the text node."""
|
||||
outputs = {
|
||||
'save_text': {
|
||||
'text': ['the text'],
|
||||
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
|
||||
},
|
||||
'preview_image': {'images': [{'filename': 'preview.png', 'type': 'temp'}]},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
assert count == 2 # the .txt file and the image; raw text is metadata
|
||||
assert preview['filename'] == 'preview.png'
|
||||
assert preview['mediaType'] == 'images'
|
||||
|
||||
def test_saved_media_preferred_over_saved_text_file(self):
|
||||
outputs = {
|
||||
'save_text': {
|
||||
'text': ['the text'],
|
||||
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
|
||||
},
|
||||
'save_image': {'images': [{'filename': 'result.png', 'type': 'output'}]},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
assert count == 2
|
||||
assert preview['filename'] == 'result.png'
|
||||
|
||||
def test_mime_format_file_preferred_over_saved_text_file(self):
|
||||
"""Custom-node outputs previewable via MIME format (e.g. VHS videos
|
||||
under arbitrary keys) rank as visual media, above saved text files."""
|
||||
outputs = {
|
||||
'save_text': {
|
||||
'files': [{'filename': 'notes.md', 'subfolder': '', 'type': 'output'}],
|
||||
},
|
||||
'video_node': {
|
||||
'files': [{'filename': 'clip.webm', 'format': 'video/webm', 'type': 'output'}],
|
||||
},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
assert count == 2
|
||||
assert preview['filename'] == 'clip.webm'
|
||||
|
||||
|
||||
def test_saved_text_file_preferred_over_raw_text(self):
|
||||
"""With no media in the job, the saved text file (a real, counted
|
||||
output) is the preview rather than the raw text metadata."""
|
||||
outputs = {
|
||||
'save_text': {
|
||||
'text': ['the text'],
|
||||
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
|
||||
},
|
||||
}
|
||||
count, preview = get_outputs_summary(outputs)
|
||||
assert count == 1
|
||||
assert preview['filename'] == 'ComfyUI_00001.txt'
|
||||
assert preview['mediaType'] == 'files'
|
||||
|
||||
|
||||
class TestHas3DExtension:
|
||||
"""Unit tests for has_3d_extension()"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue