Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4d5eee89d | ||
|
|
fa4d87ee77 | ||
|
|
3cb5a41cc8 | ||
|
|
16a325b798 | ||
|
|
e3171940fb |
+11
-19
@@ -235,16 +235,7 @@ class Downloader:
|
||||
|
||||
def _check_new_csv_from_hf_dataset(self, dataset_meta: dict, now_utc: datetime, force_check: bool = False):
|
||||
"""Checks HuggingFace for file updates and updates metadata."""
|
||||
perform_hf_check = True
|
||||
if not force_check and dataset_meta.get("last_remote_check_timestamp"):
|
||||
try:
|
||||
last_check_dt = datetime.fromisoformat(dataset_meta["last_remote_check_timestamp"])
|
||||
if now_utc - last_check_dt < timedelta(days=7):
|
||||
perform_hf_check = False
|
||||
except (ValueError, KeyError, TypeError):
|
||||
print(
|
||||
"[Autocomplete-Plus] Invalid or missing timestamp for last_remote_check_timestamp. Will perform remote check."
|
||||
)
|
||||
perform_hf_check = force_check
|
||||
|
||||
if perform_hf_check:
|
||||
huggingface_dataset_id = dataset_meta["hf_dataset_id"]
|
||||
@@ -303,15 +294,16 @@ class Downloader:
|
||||
return f"File {file_name} is missing or empty locally."
|
||||
|
||||
# Check if the last modified date on HuggingFace is newer than the last download date
|
||||
try:
|
||||
last_download_dt = datetime.fromisoformat(file_meta_entry["last_download"])
|
||||
hf_modified_dt = datetime.fromisoformat(file_meta_entry["last_modified_on_hf"])
|
||||
if hf_modified_dt > last_download_dt:
|
||||
return f"Remote file {file_name} is newer (HF: {last_download_dt}, Local Download: {hf_modified_dt})."
|
||||
except (ValueError, TypeError):
|
||||
file_meta_entry["last_download"] = None
|
||||
file_meta_entry["last_modified_on_hf"] = None
|
||||
return f"Invalid timestamp format for {file_name}. Forcing download to ensure integrity."
|
||||
# Temporarily comment out until changes to remote files can be detected
|
||||
# try:
|
||||
# last_download_dt = datetime.fromisoformat(file_meta_entry["last_download"])
|
||||
# hf_modified_dt = datetime.fromisoformat(file_meta_entry["last_modified_on_hf"])
|
||||
# if hf_modified_dt > last_download_dt:
|
||||
# return f"Remote file {file_name} is newer (HF: {hf_modified_dt}, Local Download: {last_download_dt})."
|
||||
# except (ValueError, TypeError):
|
||||
# file_meta_entry["last_download"] = None
|
||||
# file_meta_entry["last_modified_on_hf"] = None
|
||||
# return f"Invalid timestamp format for {file_name}. Forcing download to ensure integrity."
|
||||
|
||||
# If the file is missing or empty, but the last download timestamp exists, we need to retry.
|
||||
if not check_file_valid(local_file_path) and file_meta_entry.get("last_download") is not None:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-autocomplete-plus"
|
||||
description = "Autocomplete and Related Tag display for ComfyUI"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = ["",]
|
||||
|
||||
|
||||
+26
-23
@@ -154,6 +154,7 @@ async function loadTags(csvUrl, siteName) {
|
||||
}
|
||||
const csvText = await response.text();
|
||||
const lines = csvText.split('\n').filter(line => line.trim().length > 0);
|
||||
const totalLines = lines.length;
|
||||
|
||||
const startIndex = lines[0].toLowerCase().startsWith(TAGS_CSV_HEADER) ? 1 : 0;
|
||||
|
||||
@@ -183,8 +184,18 @@ async function loadTags(csvUrl, siteName) {
|
||||
updateMaxTagLength(tag.length);
|
||||
|
||||
autoCompleteData[siteName].sortedTags.push(tagData);
|
||||
} else {
|
||||
console.warn(`[Autocomplete-Plus] Invalid CSV format in line ${i + 1} of ${csvUrl}: ${line}. Expected ${TAGS_CSV_HEADER_COLUMNS.length} columns, but got ${columns.length}.`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the tag and its alias in the maps
|
||||
// Sort by count in descending order
|
||||
autoCompleteData[siteName].sortedTags.sort((a, b) => b.count - a.count);
|
||||
|
||||
// Build maps as before, but ensure not to overwrite if already processed from extra files
|
||||
autoCompleteData[siteName].sortedTags.forEach(tagData => {
|
||||
if (!autoCompleteData[siteName].tagMap.has(tagData.tag)) {
|
||||
autoCompleteData[siteName].tagMap.set(tagData.tag, tagData);
|
||||
if (tagData.alias && Array.isArray(tagData.alias)) {
|
||||
tagData.alias.forEach(alias => {
|
||||
@@ -193,11 +204,8 @@ async function loadTags(csvUrl, siteName) {
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn(`[Autocomplete-Plus] Invalid CSV format in line ${i + 1} of ${csvUrl}: ${line}. Expected ${TAGS_CSV_HEADER_COLUMNS.length} columns, but got ${columns.length}.`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[Autocomplete-Plus] Failed to fetch or process tags from ${csvUrl}:`, error);
|
||||
@@ -268,17 +276,17 @@ async function loadCooccurrence(csvUrl, siteName) {
|
||||
|
||||
const startIndex = lines[0].startsWith('tag_a,tag_b,count') ? 1 : 0;
|
||||
|
||||
await processCooccurrenceInChunks(lines, startIndex, autoCompleteData[siteName].cooccurrenceMap, csvUrl, siteName);
|
||||
await processInChunks(lines, startIndex, autoCompleteData[siteName].cooccurrenceMap, csvUrl, siteName);
|
||||
} catch (error) {
|
||||
console.error(`[Autocomplete-Plus] Failed to fetch or process cooccurrence data from ${csvUrl}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Co-Occurrence CSV data in chunks to avoid blocking the UI.
|
||||
* Process CSV data in chunks to avoid blocking the UI.
|
||||
* Modifies the targetMap directly.
|
||||
*/
|
||||
function processCooccurrenceInChunks(lines, startIndex, targetMap, csvUrl, siteName) {
|
||||
function processInChunks(lines, startIndex, targetMap, csvUrl, siteName) {
|
||||
return new Promise((resolve) => {
|
||||
const CHUNK_SIZE = 10000;
|
||||
let i = startIndex;
|
||||
@@ -289,7 +297,7 @@ function processCooccurrenceInChunks(lines, startIndex, targetMap, csvUrl, siteN
|
||||
|
||||
for (; i < endIndex; i++) {
|
||||
const line = lines[i];
|
||||
const columns = line.split(",");
|
||||
const columns = parseCSVLine(line);
|
||||
|
||||
if (columns.length >= 3) {
|
||||
const tagA = columns[0].trim();
|
||||
@@ -299,19 +307,17 @@ function processCooccurrenceInChunks(lines, startIndex, targetMap, csvUrl, siteN
|
||||
if (!tagA || !tagB || isNaN(count)) continue;
|
||||
|
||||
// Add tagA -> tagB relationship
|
||||
let subMapA = targetMap.get(tagA);
|
||||
if (!subMapA) {
|
||||
subMapA = new Map();
|
||||
targetMap.set(tagA, subMapA);
|
||||
if (!targetMap.has(tagA)) {
|
||||
targetMap.set(tagA, new Map());
|
||||
}
|
||||
subMapA.set(tagB, count);
|
||||
targetMap.get(tagA).set(tagB, count);
|
||||
|
||||
let subMapB = targetMap.get(tagB);
|
||||
if (!subMapB) {
|
||||
subMapB = new Map();
|
||||
targetMap.set(tagB, subMapB);
|
||||
|
||||
// Add tagB -> tagA relationship (bidirectional)
|
||||
if (!targetMap.has(tagB)) {
|
||||
targetMap.set(tagB, new Map());
|
||||
}
|
||||
subMapB.set(tagA, count);
|
||||
targetMap.get(tagB).set(tagA, count);
|
||||
|
||||
pairCount++;
|
||||
}
|
||||
@@ -444,9 +450,6 @@ async function initializeDataFromCSV(csvListData, source) {
|
||||
await Promise.all([
|
||||
Promise.all(tagsLoadPromiseFactories.map(factory => factory()))
|
||||
.then(() => {
|
||||
// Sort by count in descending order
|
||||
autoCompleteData[source].sortedTags.sort((a, b) => b.count - a.count);
|
||||
|
||||
// Build FlexSearch index after tags are loaded
|
||||
return buildFlexSearchIndex(source);
|
||||
})
|
||||
@@ -543,7 +546,7 @@ async function loadLoras() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all data sources in parallel.
|
||||
* Load all data sources asynchronously.
|
||||
*/
|
||||
export async function loadDataAsync() {
|
||||
return Promise.all([
|
||||
|
||||
+34
-33
@@ -190,40 +190,41 @@ async function addExtraSettings() {
|
||||
}
|
||||
|
||||
// Add extra setting for checking new CSV updates
|
||||
app.ui.settings.addSetting({
|
||||
id: id + ".check_new_csv",
|
||||
defaultValue: null,
|
||||
name: "Check CSV updates",
|
||||
category: [name, "Misc", "Check new CSV"],
|
||||
type: () => {
|
||||
const lastCheckSpan = $el("span", {
|
||||
textContent: lastCheckTimeText,
|
||||
className: "text-sm text-gray-500",
|
||||
style: {
|
||||
marginRight: "16px"
|
||||
}
|
||||
});
|
||||
// Note: Temporarily comment out until changes to remote files can be detected
|
||||
// app.ui.settings.addSetting({
|
||||
// id: id + ".check_new_csv",
|
||||
// defaultValue: null,
|
||||
// name: "Check CSV updates",
|
||||
// category: [name, "Misc", "Check new CSV"],
|
||||
// type: () => {
|
||||
// const lastCheckSpan = $el("span", {
|
||||
// textContent: lastCheckTimeText,
|
||||
// className: "text-sm text-gray-500",
|
||||
// style: {
|
||||
// marginRight: "16px"
|
||||
// }
|
||||
// });
|
||||
|
||||
const checkButton = $el("button", {
|
||||
textContent: "Check now",
|
||||
className: "p-button p-component p-button-primary",
|
||||
onclick: async () => {
|
||||
await performUpdateCheck(checkButton, lastCheckSpan);
|
||||
}
|
||||
});
|
||||
// const checkButton = $el("button", {
|
||||
// textContent: "Check now",
|
||||
// className: "p-button p-component p-button-primary",
|
||||
// onclick: async () => {
|
||||
// await performUpdateCheck(checkButton, lastCheckSpan);
|
||||
// }
|
||||
// });
|
||||
|
||||
return $el("div", {
|
||||
className: "flex-row items-center gap-2",
|
||||
}, [
|
||||
$el("div", {
|
||||
className: "p-component",
|
||||
}, [
|
||||
lastCheckSpan,
|
||||
checkButton,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
});
|
||||
// return $el("div", {
|
||||
// className: "flex-row items-center gap-2",
|
||||
// }, [
|
||||
// $el("div", {
|
||||
// className: "p-component",
|
||||
// }, [
|
||||
// lastCheckSpan,
|
||||
// checkButton,
|
||||
// ]),
|
||||
// ]);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +241,7 @@ app.registerExtension({
|
||||
let rootPath = import.meta.url.replace("js/main.js", "");
|
||||
loadCSS(rootPath + "css/autocomplete-plus.css"); // Load CSS for autocomplete
|
||||
|
||||
loadDataAsync();
|
||||
await loadDataAsync();
|
||||
},
|
||||
|
||||
// One the Settings Screen, displays reverse order in same category
|
||||
|
||||
Reference in New Issue
Block a user