sorting optimization 3

This commit is contained in:
JasonHoku
2026-02-18 17:10:10 -08:00
parent 470078ab72
commit 820ff09df8
4 changed files with 26 additions and 19 deletions
+3 -1
View File
@@ -422,6 +422,7 @@ def run_generation_loop(
pending_batch = []
current_job = 0
total_generated = 0
gen_index_offset = len(existing_data.get("items", [])) # Sequential index for deterministic sort ordering
skipped_count = 0
job_durations = []
eta_start_time = time.time()
@@ -1020,7 +1021,8 @@ def run_generation_loop(
meta = create_image_metadata(
conf, w, h, duration, current_seed, batch_idx,
actual_positive_prompt, actual_negative_prompt
actual_positive_prompt, actual_negative_prompt,
gen_index=gen_index_offset + total_generated
)
if pos_hash or neg_hash:
meta["conditioning_pos_hash"] = pos_hash
+9 -5
View File
@@ -141,10 +141,10 @@ def save_image_to_disk(image, output_dir, filename):
return filepath
def create_image_metadata(config, width, height, duration, seed, batch_idx, actual_positive_prompt, actual_negative_prompt):
def create_image_metadata(config, width, height, duration, seed, batch_idx, actual_positive_prompt, actual_negative_prompt, gen_index=None):
"""
Create metadata dictionary for an image.
Args:
config: Configuration dictionary
width: Image width
@@ -154,7 +154,8 @@ def create_image_metadata(config, width, height, duration, seed, batch_idx, actu
batch_idx: Batch index
actual_positive_prompt: Final positive prompt (with triggers)
actual_negative_prompt: Final negative prompt
gen_index: Sequential generation index for deterministic sort ordering (optional, backwards-compatible)
Returns:
dict: Metadata dictionary
"""
@@ -178,7 +179,7 @@ def create_image_metadata(config, width, height, duration, seed, batch_idx, actu
if meta.get("attention_mode") == "default":
meta.pop("attention_mode", None)
meta.update({
update_dict = {
"width": width,
"height": height,
"duration": duration,
@@ -186,7 +187,10 @@ def create_image_metadata(config, width, height, duration, seed, batch_idx, actu
"batch_idx": batch_idx,
"positive": actual_positive_prompt,
"negative": actual_negative_prompt
})
}
if gen_index is not None:
update_dict["gen_index"] = gen_index
meta.update(update_dict)
return meta
+10 -9
View File
@@ -12,7 +12,7 @@ const ASYNC_PIPELINE_THRESHOLD = 500;
// current sort/filter, used for "Go To Card #" and the #N tag on cards.
function refreshIndices() {
if (!activeData) return;
const sorted = activeData.slice().sort((a, b) => a.id - b.id);
const sorted = activeData.slice().sort((a, b) => (a.gen_index ?? a.id) - (b.gen_index ?? b.id));
idToIndexMap = new Map(sorted.map((item, index) => [item.id, index + 1]));
}
@@ -167,8 +167,8 @@ function setSecondarySort(id) {
// Unified Comparison Helper
function compareItems(a, b, sortKey) {
switch (sortKey) {
case 'newest': return b.id - a.id;
case 'oldest': return a.id - b.id;
case 'newest': return (b.gen_index ?? b.id) - (a.gen_index ?? a.id);
case 'oldest': return (a.gen_index ?? a.id) - (b.gen_index ?? b.id);
case 'fastest': return a.duration - b.duration;
case 'favorited': return (b.favorited ? 1 : 0) - (a.favorited ? 1 : 0);
case 'cfg': return a.cfg - b.cfg;
@@ -199,9 +199,9 @@ function runMultiSort(list) {
res = compareItems(a, b, currentSecondarySort);
}
// 3. Fallback to ID (Stable sort)
// 3. Fallback to gen_index/ID (Stable sort, backwards-compatible)
if (res === 0) {
return a.id - b.id;
return (a.gen_index ?? a.id) - (b.gen_index ?? b.id);
}
return res;
});
@@ -313,10 +313,11 @@ function executePipeline() {
});
// Apply sorting
// Fast path: for oldest/newest with no secondary sort, items from activeData.filter()
// are already in ID order — just reverse for newest
// Fast path: for oldest/newest with no secondary sort, activeData is stored newest-first
// (items are inserted/unshifted at position 0), so processedData after filter() is also newest-first.
// For 'oldest' we reverse; for 'newest' it's already correct.
if ((currentSort === 'oldest' || currentSort === 'newest') && currentSecondarySort === 'none') {
if (currentSort === 'newest') {
if (currentSort === 'oldest') {
processedData.reverse();
}
} else {
@@ -402,7 +403,7 @@ function binaryInsert(arr, item) {
cmp = compareItems(arr[mid], item, currentSecondarySort);
}
if (cmp === 0) {
cmp = arr[mid].id - item.id; // Stable sort fallback
cmp = (arr[mid].gen_index ?? arr[mid].id) - (item.gen_index ?? item.id); // Stable sort fallback
}
if (cmp <= 0) {
low = mid + 1;
+4 -4
View File
@@ -242,7 +242,7 @@ function renderVisibleItems(forcePositionUpdate = false) {
itemsToShow.forEach((data, offsetIndex) => {
const globalIndex = visibleRange.start + offsetIndex;
const displayNumber = globalIndex + 1; // 1-based position in current sorted view
const genOrderNumber = idToIndexMap.get(data.id) || (globalIndex + 1); // Generation order number (backwards-compatible)
const row = Math.floor(globalIndex / columnsCount);
const col = globalIndex % columnsCount;
@@ -259,9 +259,9 @@ function renderVisibleItems(forcePositionUpdate = false) {
card.style.width = `${itemWidth - 10}px`;
card.style.zIndex = globalIndex;
// Update card number to reflect sorted position
// Update card number to reflect generation order
const indexTag = card.querySelector('.index-tag');
if (indexTag) indexTag.textContent = `#${displayNumber}`;
if (indexTag) indexTag.textContent = `#${genOrderNumber}`;
nodeMap.set(data.id, card);
fragment.appendChild(card);
@@ -286,7 +286,7 @@ function renderVisibleItems(forcePositionUpdate = false) {
// Update card number when position changes (sort/filter changed)
const indexTag = card.querySelector('.index-tag');
if (indexTag) indexTag.textContent = `#${displayNumber}`;
if (indexTag) indexTag.textContent = `#${genOrderNumber}`;
}
}
});