Skip to content

Commit 27d0a4b

Browse files
committed
Thumbnail option for gallery/queue images
1 parent eb02561 commit 27d0a4b

File tree

9 files changed

+174
-74
lines changed

9 files changed

+174
-74
lines changed

src/lib/components/ComfyQueue.svelte

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
1-
<script lang="ts" context="module">
2-
export type QueueUIEntryStatus = QueueEntryStatus | "pending" | "running";
3-
4-
export type QueueUIEntry = {
5-
entry: QueueEntry,
6-
message: string,
7-
submessage: string,
8-
date?: string,
9-
status: QueueUIEntryStatus,
10-
images?: string[], // URLs
11-
details?: string, // shown in a tooltip on hover
12-
error?: WorkflowError
13-
}
14-
</script>
15-
161
<script lang="ts">
172
import queueState, { type CompletedQueueEntry, type QueueEntry, type QueueEntryStatus } from "$lib/stores/queueState";
183
import ProgressBar from "./ProgressBar.svelte";
194
import SystemStatsBar from "./SystemStatsBar.svelte";
205
import Spinner from "./Spinner.svelte";
216
import PromptDisplay from "./PromptDisplay.svelte";
227
import { List, ListUl, Grid } from "svelte-bootstrap-icons";
23-
import { convertComfyOutputToComfyURL, convertFilenameToComfyURL, getNodeInfo, truncateString } from "$lib/utils"
8+
import { getNodeInfo, type ComfyImageLocation } from "$lib/utils"
249
import type { Writable } from "svelte/store";
2510
import type { QueueItemType } from "$lib/api";
2611
import { Button } from "@gradio/button";
@@ -31,7 +16,7 @@
3116
import ComfyQueueListDisplay from "./ComfyQueueListDisplay.svelte";
3217
import ComfyQueueGridDisplay from "./ComfyQueueGridDisplay.svelte";
3318
import { WORKFLOWS_VIEW } from "./ComfyBoxWorkflowsView.svelte";
34-
import uiQueueState from "$lib/stores/uiQueueState";
19+
import uiQueueState, { type QueueUIEntry } from "$lib/stores/uiQueueState";
3520
3621
export let app: ComfyApp;
3722
@@ -125,7 +110,7 @@
125110
let showModal = false;
126111
let expandAll = false;
127112
let selectedPrompt = null;
128-
let selectedImages = [];
113+
let selectedImages: ComfyImageLocation[] = [];
129114
function showPrompt(entry: QueueUIEntry) {
130115
if (entry.error != null) {
131116
showModal = false;

src/lib/components/ComfyQueueGridDisplay.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import type { QueueItemType } from "$lib/api";
3-
import { showLightbox } from "$lib/utils";
3+
import { convertComfyOutputToComfyURL, showLightbox } from "$lib/utils";
44
import type { QueueUIEntry } from "./ComfyQueue.svelte";
55
import queueState from "$lib/stores/queueState";
66
@@ -19,7 +19,7 @@
1919
allEntries = []
2020
for (const entry of entries) {
2121
for (const image of entry.images) {
22-
allEntries.push([entry, image]);
22+
allEntries.push([entry, convertComfyOutputToComfyURL(image, true)]);
2323
}
2424
}
2525
allImages = allEntries.map(p => p[1]);
@@ -56,6 +56,7 @@
5656
<img class="grid-entry-image"
5757
on:click={(e) => handleClick(e, entry, i)}
5858
src={image}
59+
loading="lazy"
5960
alt="thumbnail" />
6061
</div>
6162
{/each}
@@ -130,6 +131,8 @@
130131
.grid-entry-image {
131132
aspect-ratio: 1 / 1;
132133
object-fit: cover;
134+
width: 100%;
135+
max-width: unset;
133136
134137
&:hover {
135138
cursor: pointer;

src/lib/components/ComfyQueueListDisplay.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import type { QueueItemType } from "$lib/api";
3-
import { showLightbox, truncateString } from "$lib/utils";
4-
import type { QueueUIEntry } from "./ComfyQueue.svelte";
3+
import { convertComfyOutputToComfyURL, showLightbox, truncateString } from "$lib/utils";
54
import queueState from "$lib/stores/queueState";
5+
import type { QueueUIEntry } from "$lib/stores/uiQueueState";
66
77
export let entries: QueueUIEntry[] = [];
88
export let showPrompt: (entry: QueueUIEntry) => void;
@@ -39,11 +39,13 @@
3939
<div class="list-entry-images"
4040
style="--cols: {Math.ceil(Math.sqrt(Math.min(entry.images.length, 4)))}" >
4141
{#each entry.images.slice(0, 4) as image, i}
42+
{@const imageURL = convertComfyOutputToComfyURL(image, true)}
4243
<div>
4344
<!-- svelte-ignore a11y-click-events-have-key-events -->
4445
<img class="list-entry-image"
4546
on:click={(e) => showLightbox(entry.images, i, e)}
46-
src={image}
47+
src={imageURL}
48+
loading="lazy"
4749
alt="thumbnail" />
4850
</div>
4951
{/each}

src/lib/components/PromptDisplay.svelte

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Gallery from "$lib/components/gradio/gallery/Gallery.svelte";
99
import { ImageViewer } from "$lib/ImageViewer";
1010
import type { Styles } from "@gradio/utils";
11-
import { comfyFileToComfyBoxMetadata, comfyURLToComfyFile, countNewLines } from "$lib/utils";
11+
import { comfyFileToComfyBoxMetadata, comfyURLToComfyFile, countNewLines, type ComfyImageLocation, convertComfyOutputToComfyURL } from "$lib/utils";
1212
import ReceiveOutputTargets from "./modal/ReceiveOutputTargets.svelte";
1313
import workflowState, { type ComfyBoxWorkflow, type WorkflowReceiveOutputTargets } from "$lib/stores/workflowState";
1414
import type { ComfyReceiveOutputNode } from "$lib/nodes/actions";
@@ -17,7 +17,7 @@
1717
const splitLength = 50;
1818
1919
export let prompt: SerializedPromptInputsAll;
20-
export let images: string[] = []; // list of image URLs to ComfyUI's /view? endpoint
20+
export let images: ComfyImageLocation[] = [];
2121
export let isMobile: boolean = false;
2222
export let expandAll: boolean = false;
2323
export let closeModal: () => void;
@@ -36,10 +36,7 @@
3636
let litegraphType = "(none)"
3737
3838
$: if (images.length > 0) {
39-
// since the image links come from gradio, have to parse the URL for the
40-
// ComfyImageLocation params
41-
comfyBoxImages = images.map(comfyURLToComfyFile)
42-
.map(comfyFileToComfyBoxMetadata);
39+
comfyBoxImages = images.map(comfyFileToComfyBoxMetadata);
4340
}
4441
else {
4542
comfyBoxImages = []
@@ -199,7 +196,7 @@
199196
<div class="image-container">
200197
<Block>
201198
<Gallery
202-
value={images}
199+
value={images.map(convertComfyOutputToComfyURL)}
203200
label=""
204201
show_label={false}
205202
style={galleryStyle}

src/lib/stores/configDefs.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,36 @@ const defNotifications: ConfigDefEnum<"notifications", NotificationState> = {
119119
}
120120
};
121121

122+
export enum OutputThumbnailsMode {
123+
Auto,
124+
AlwaysThumbnail,
125+
AlwaysFullSize
126+
}
127+
128+
const defOutputThumbnails: ConfigDefEnum<"outputThumbnails", OutputThumbnailsMode> = {
129+
name: "outputThumbnails",
130+
type: "enum",
131+
defaultValue: OutputThumbnailsMode.Auto,
132+
category: "ui",
133+
description: "If enabled, send back smaller sized output image thumbnails for gallery/queue/history. Enable if you have slow network or are using Colab.",
134+
options: {
135+
values: [
136+
{
137+
value: OutputThumbnailsMode.Auto,
138+
label: "Autodetect"
139+
},
140+
{
141+
value: OutputThumbnailsMode.AlwaysThumbnail,
142+
label: "Always use thumbnails"
143+
},
144+
{
145+
value: OutputThumbnailsMode.AlwaysFullSize,
146+
label: "Always use full size"
147+
},
148+
]
149+
}
150+
};
151+
122152
const defAlwaysStripUserState: ConfigDefBoolean<"alwaysStripUserState"> = {
123153
name: "alwaysStripUserState",
124154
type: "boolean",
@@ -207,6 +237,7 @@ export const CONFIG_DEFS = [
207237
defComfyUIHostname,
208238
defComfyUIPort,
209239
defNotifications,
240+
defOutputThumbnails,
210241
defAlwaysStripUserState,
211242
defPromptForWorkflowName,
212243
defConfirmWhenUnloadingUnsavedChanges,

src/lib/stores/uiQueueState.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { PromptID, QueueItemType } from '$lib/api';
2+
import type { ComfyImageLocation } from "$lib/utils";
23
import { get, writable } from 'svelte/store';
34
import type { Readable, Writable } from 'svelte/store';
4-
import queueState, { type CompletedQueueEntry, type QueueEntry } from './queueState';
5+
import queueState, { QueueEntryStatus, type CompletedQueueEntry, type QueueEntry } from './queueState';
56
import type { WorkflowError } from './workflowState';
67
import { convertComfyOutputToComfyURL } from '$lib/utils';
78

@@ -13,7 +14,7 @@ export type QueueUIEntry = {
1314
submessage: string,
1415
date?: string,
1516
status: QueueUIEntryStatus,
16-
images?: string[], // URLs
17+
images?: ComfyImageLocation[], // URLs
1718
details?: string, // shown in a tooltip on hover
1819
error?: WorkflowError
1920
}
@@ -94,13 +95,12 @@ function convertPendingEntry(entry: QueueEntry, status: QueueUIEntryStatus): Que
9495

9596
const thumbnails = entry.extraData?.thumbnails
9697
if (thumbnails) {
97-
result.images = thumbnails.map(convertComfyOutputToComfyURL);
98+
result.images = [...thumbnails]
9899
}
99100

100101
const outputs = Object.values(entry.outputs)
101102
.filter(o => o.images)
102103
.flatMap(o => o.images)
103-
.map(convertComfyOutputToComfyURL);
104104
if (outputs) {
105105
result.images = result.images.concat(outputs)
106106
}
@@ -114,7 +114,6 @@ function convertCompletedEntry(entry: CompletedQueueEntry): QueueUIEntry {
114114
const images = Object.values(entry.entry.outputs)
115115
.filter(o => o.images)
116116
.flatMap(o => o.images)
117-
.map(convertComfyOutputToComfyURL);
118117
result.images = images
119118

120119
if (entry.message)
@@ -132,6 +131,8 @@ function updateFromQueue(queuePending: QueueEntry[], queueRunning: QueueEntry[])
132131
// newest entries appear at the top
133132
s.queuedEntries = queuePending.map((e) => convertPendingEntry(e, "pending")).reverse();
134133
s.runningEntries = queueRunning.map((e) => convertPendingEntry(e, "running")).reverse();
134+
s.queuedEntries.sort((a, b) => a.entry.number - b.entry.number)
135+
s.runningEntries.sort((a, b) => a.entry.number - b.entry.number)
135136
s.queueUIEntries = s.queuedEntries.concat(s.runningEntries);
136137
console.warn("[ComfyQueue] BUILDQUEUE", s.queuedEntries.length, s.runningEntries.length)
137138
return s;

0 commit comments

Comments
 (0)