Added cache and use of model metadata in json file. (First load will be slow.)

This commit is contained in:
Christian Bastian
2024-09-12 01:42:13 -04:00
parent fa5e7dfcdc
commit 408f5887cd
2 changed files with 302 additions and 240 deletions

View File

@@ -244,56 +244,63 @@ def get_def_headers(url=""):
return def_headers return def_headers
def civitai_get_model_version_info_by_hash(sha256_hash): def hash_file(path, buffer_size=1024*1024):
url_api_hash = r"https://civitai.com/api/v1/model-versions/by-hash/" + sha256_hash sha256 = hashlib.sha256()
hash_response = requests.get(url_api_hash) with open(path, 'rb') as f:
if hash_response.status_code != 200: while True:
return {} data = f.read(buffer_size)
return hash_response.json() if not data: break
sha256.update(data)
def civitai_get_model_info_by_model_id(model_id): return sha256.hexdigest()
url_api_model = r"https://civitai.com/api/v1/models/" + str(model_id)
model_response = requests.get(url_api_model)
if model_response.status_code != 200:
return {}
return model_response.json()
def search_web_for_model_info(sha256_hash): class Civitai:
model_info = civitai_get_model_version_info_by_hash(sha256_hash) @staticmethod
if len(model_info) > 0: return model_info def search_by_hash(sha256_hash):
url_api_hash = r"https://civitai.com/api/v1/model-versions/by-hash/" + sha256_hash
hash_response = requests.get(url_api_hash)
if hash_response.status_code != 200:
return {}
return hash_response.json() # model version info
# TODO: search other websites @staticmethod
def search_by_model_id(model_id):
url_api_model = r"https://civitai.com/api/v1/models/" + str(model_id)
model_response = requests.get(url_api_model)
if model_response.status_code != 200:
return {}
return model_response.json() # model group info
return {} @staticmethod
def get_model_url(model_version_info):
if len(model_version_info) == 0: return ""
model_id = model_version_info.get("modelId")
if model_id is None:
# there can be incomplete model info, so don't throw just in case
return ""
url = f"https://civitai.com/models/{model_id}"
version_id = model_version_info.get("id")
if version_id is not None:
url += f"?modelVersionId={version_id}"
return url
@staticmethod
def search_notes(model_version_info):
model_id = model_version_info.get("modelId")
model_version_id = model_version_info.get("id")
def search_web_for_model_url(sha256_hash): assert(model_id is not None)
model_info = civitai_get_model_version_info_by_hash(sha256_hash) assert(model_version_id is not None)
if len(model_info) > 0:
model_id = model_info["modelId"]
version_id = model_info["id"]
return f"https://civitai.com/models/{model_id}?modelVersionId={version_id}"
# TODO: search other websites
return ""
def search_web_for_model_notes(sha256_hash):
model_info = civitai_get_model_version_info_by_hash(sha256_hash)
model_info = civitai_get_model_info_by_model_id(model_info["modelId"])
if len(model_info) > 0:
model_description = model_info.get("description", "")
model_version_description = "" model_version_description = ""
model_trigger_words = [] model_trigger_words = []
model_info = Civitai.search_by_model_id(model_id)
model_description = model_info.get("description", "")
for model_version in model_info["modelVersions"]: for model_version in model_info["modelVersions"]:
for files in model_version["files"]: if model_version["id"] == model_version_id:
if files["hashes"]["SHA256"].lower() == sha256_hash.lower(): model_version_description = model_version.get("description", "")
model_version_description = model_version.get("description", "") model_trigger_words = model_version.get("trainedWords", [])
model_trigger_words = model_version.get("trainedWords", "") break
break
if model_version_description != "": break
notes = "" notes = ""
if len(model_trigger_words) > 0: if len(model_trigger_words) > 0:
@@ -313,24 +320,76 @@ def search_web_for_model_notes(sha256_hash):
notes += markdownify.markdownify(model_version_description) notes += markdownify.markdownify(model_version_description)
if model_description != "": if model_description != "":
if len(notes) > 0: notes += "\n\n" if len(notes) > 0: notes += "\n\n"
notes += "# " + model_info.get("name", str(model_info["id"])) + "\n\n" notes += "# " + model_info.get("name", str(model_id)) + "\n\n"
notes += markdownify.markdownify(model_description) notes += markdownify.markdownify(model_description)
notes = notes.strip() return notes.strip()
class ModelInfo:
@staticmethod
def search_by_hash(sha256_hash):
model_info = Civitai.search_by_hash(sha256_hash)
if len(model_info) > 0: return model_info
# TODO: search other websites
return {}
@staticmethod
def try_load_cached(model_path):
model_info_path = os.path.splitext(model_path)[0] + model_info_extension
if os.path.isfile(model_info_path):
with open(model_info_path, "r", encoding="utf-8") as f:
model_info = json.load(f)
return model_info
return {}
@staticmethod
def get_hash(model_info):
model_info = Civitai.get_hash(model_info)
if len(model_info) > 0: return model_info
# TODO: search other websites
return {}
@staticmethod
def search_info(model_path, cache=True, use_cached=True):
model_info = ModelInfo.try_load_cached(model_path)
if use_cached and len(model_info) > 0:
return model_info
sha256_hash = hash_file(model_path)
model_info = ModelInfo.search_by_hash(sha256_hash)
if cache and len(model_info) > 0:
model_info_path = os.path.splitext(model_path)[0] + model_info_extension
with open(model_info_path, "w", encoding="utf-8") as f:
json.dump(model_info, f, indent=4)
print("Saved file: " + model_info_path)
return model_info
@staticmethod
def get_url(model_info):
if len(model_info) == 0: return ""
model_url = Civitai.get_model_url(model_info)
if model_url != "": return model_url
# TODO: huggingface has <user>/<model> formats
# TODO: support other websites
return ""
@staticmethod
def search_notes(model_path):
notes = ""
model_info = ModelInfo.search_info(model_path, cache=True, use_cached=True) # assume cached is correct; re-download elsewhere
if len(model_info) > 0:
notes = Civitai.search_notes(model_info)
# TODO: support other websites
return notes return notes
# TODO: search other websites # TODO: search other websites
return "" return ""
def hash_file(path, buffer_size=1024*1024):
sha256 = hashlib.sha256()
with open(path, 'rb') as f:
while True:
data = f.read(buffer_size)
if not data: break
sha256.update(data)
return sha256.hexdigest()
@server.PromptServer.instance.routes.get("/model-manager/timestamp") @server.PromptServer.instance.routes.get("/model-manager/timestamp")
@@ -979,7 +1038,7 @@ def bytes_to_size(total_bytes):
@server.PromptServer.instance.routes.get("/model-manager/model/info/{path}") @server.PromptServer.instance.routes.get("/model-manager/model/info/{path}")
async def get_model_info(request): async def get_model_metadata(request):
result = { "success": False } result = { "success": False }
model_path = request.match_info["path"] model_path = request.match_info["path"]
@@ -993,16 +1052,16 @@ async def get_model_info(request):
result["alert"] = "Invalid model path!" result["alert"] = "Invalid model path!"
return web.json_response(result) return web.json_response(result)
info = {} data = {}
comfyui_directory, name = os.path.split(model_path) comfyui_directory, name = os.path.split(model_path)
info["File Name"] = name data["File Name"] = name
info["File Directory"] = comfyui_directory data["File Directory"] = comfyui_directory
info["File Size"] = bytes_to_size(os.path.getsize(abs_path)) data["File Size"] = bytes_to_size(os.path.getsize(abs_path))
stats = pathlib.Path(abs_path).stat() stats = pathlib.Path(abs_path).stat()
date_format = "%Y-%m-%d %H:%M:%S" date_format = "%Y-%m-%d %H:%M:%S"
date_modified = datetime.fromtimestamp(stats.st_mtime).strftime(date_format) date_modified = datetime.fromtimestamp(stats.st_mtime).strftime(date_format)
#info["Date Modified"] = date_modified #data["Date Modified"] = date_modified
#info["Date Created"] = datetime.fromtimestamp(stats.st_ctime).strftime(date_format) #data["Date Created"] = datetime.fromtimestamp(stats.st_ctime).strftime(date_format)
model_extensions = folder_paths_get_supported_pt_extensions(model_type) model_extensions = folder_paths_get_supported_pt_extensions(model_type)
abs_name , _ = split_valid_ext(abs_path, model_extensions) abs_name , _ = split_valid_ext(abs_path, model_extensions)
@@ -1012,7 +1071,7 @@ async def get_model_info(request):
if os.path.isfile(maybe_preview): if os.path.isfile(maybe_preview):
preview_path, _ = split_valid_ext(model_path, model_extensions) preview_path, _ = split_valid_ext(model_path, model_extensions)
preview_modified = pathlib.Path(maybe_preview).stat().st_mtime_ns preview_modified = pathlib.Path(maybe_preview).stat().st_mtime_ns
info["Preview"] = { data["Preview"] = {
"path": preview_path + extension, "path": preview_path + extension,
"dateModified": str(preview_modified), "dateModified": str(preview_modified),
} }
@@ -1021,27 +1080,27 @@ async def get_model_info(request):
header = get_safetensor_header(abs_path) header = get_safetensor_header(abs_path)
metadata = header.get("__metadata__", None) metadata = header.get("__metadata__", None)
if metadata is not None and info.get("Preview", None) is None: if metadata is not None and data.get("Preview", None) is None:
thumbnail = metadata.get("modelspec.thumbnail") thumbnail = metadata.get("modelspec.thumbnail")
if thumbnail is not None: if thumbnail is not None:
i0 = thumbnail.find("/") + 1 i0 = thumbnail.find("/") + 1
i1 = thumbnail.find(";", i0) i1 = thumbnail.find(";", i0)
thumbnail_extension = "." + thumbnail[i0:i1] thumbnail_extension = "." + thumbnail[i0:i1]
if thumbnail_extension in image_extensions: if thumbnail_extension in image_extensions:
info["Preview"] = { data["Preview"] = {
"path": request.query["path"] + thumbnail_extension, "path": request.query["path"] + thumbnail_extension,
"dateModified": date_modified, "dateModified": date_modified,
} }
if metadata is not None: if metadata is not None:
info["Base Training Model"] = metadata.get("ss_sd_model_name", "") data["Base Training Model"] = metadata.get("ss_sd_model_name", "")
info["Base Model Version"] = metadata.get("ss_base_model_version", "") data["Base Model Version"] = metadata.get("ss_base_model_version", "")
info["Network Dimension"] = metadata.get("ss_network_dim", "") data["Network Dimension"] = metadata.get("ss_network_dim", "")
info["Network Alpha"] = metadata.get("ss_network_alpha", "") data["Network Alpha"] = metadata.get("ss_network_alpha", "")
if metadata is not None: if metadata is not None:
training_comment = metadata.get("ss_training_comment", "") training_comment = metadata.get("ss_training_comment", "")
info["Description"] = ( data["Description"] = (
metadata.get("modelspec.description", "") + metadata.get("modelspec.description", "") +
"\n\n" + "\n\n" +
metadata.get("modelspec.usage_hint", "") + metadata.get("modelspec.usage_hint", "") +
@@ -1076,7 +1135,7 @@ async def get_model_info(request):
resolutions[str(x) + "x" + str(y)] = count resolutions[str(x) + "x" + str(y)] = count
resolutions = list(resolutions.items()) resolutions = list(resolutions.items())
resolutions.sort(key=lambda x: x[1], reverse=True) resolutions.sort(key=lambda x: x[1], reverse=True)
info["Bucket Resolutions"] = resolutions data["Bucket Resolutions"] = resolutions
tags = None tags = None
if metadata is not None: if metadata is not None:
@@ -1091,7 +1150,7 @@ async def get_model_info(request):
tags.sort(key=lambda x: x[1], reverse=True) tags.sort(key=lambda x: x[1], reverse=True)
result["success"] = True result["success"] = True
result["info"] = info result["info"] = data
if metadata is not None: if metadata is not None:
result["metadata"] = metadata result["metadata"] = metadata
if tags is not None: if tags is not None:
@@ -1099,8 +1158,9 @@ async def get_model_info(request):
result["notes"] = notes result["notes"] = notes
return web.json_response(result) return web.json_response(result)
@server.PromptServer.instance.routes.get("/model-manager/model/web-url") @server.PromptServer.instance.routes.get("/model-manager/model/web-url")
async def get_model_info(request): async def get_model_web_url(request):
result = { "success": False } result = { "success": False }
model_path = request.query.get("path", None) model_path = request.query.get("path", None)
@@ -1114,9 +1174,14 @@ async def get_model_info(request):
result["alert"] = "Invalid model path!" result["alert"] = "Invalid model path!"
return web.json_response(result) return web.json_response(result)
sha256_hash = hash_file(abs_path) model_info = ModelInfo.search_info(abs_path)
web_url = search_web_for_model_url(sha256_hash) if len(model_info) == 0:
result["alert"] = "Unable to find model info!"
return web.json_response(result)
web_url = ModelInfo.get_url(model_info)
if web_url != "":
result["success"] = True
return web.json_response({ "url": web_url }) return web.json_response({ "url": web_url })
@@ -1164,18 +1229,7 @@ async def download_model(request):
return web.json_response(result) return web.json_response(result)
# download model info # download model info
sha256_hash = formdata.get("sha256", None) _ = ModelInfo.search_info(file_name, cache=True) # save json
if sha256_hash is not None:
model_info = search_web_for_model_info(sha256_hash)
if len(model_info) > 0:
info_path = os.path.splitext(file_name)[0] + ".json"
try:
with open(info_path, "w", encoding="utf-8") as f:
json.dump(model_info, f, indent=4)
print("Saved file: " + info_path)
except ValueError as e:
print(e, file=sys.stderr, flush=True)
result["alert"] = "Failed to save model info!\n\n" + str(e) # TODO: >1 alert? concat?
# save image as model preview # save image as model preview
image = formdata.get("image") image = formdata.get("image")
@@ -1379,8 +1433,7 @@ async def try_download_notes(request):
result["alert"] = "Notes already exist!" result["alert"] = "Notes already exist!"
return web.json_response(result) return web.json_response(result)
sha256_hash = hash_file(abs_path) notes = ModelInfo.search_notes(abs_path)
notes = search_web_for_model_notes(sha256_hash)
if not notes.isspace() and notes != "": if not notes.isspace() and notes != "":
try: try:
with open(notes_path, "w", encoding="utf-8") as f: with open(notes_path, "w", encoding="utf-8") as f:

View File

@@ -2370,9 +2370,9 @@ class ModelInfo {
[this.elements.tabButtons, this.elements.tabContents] = GenerateTabGroup([ [this.elements.tabButtons, this.elements.tabContents] = GenerateTabGroup([
{ name: "Overview", icon: "information-box-outline", tabContent: this.element }, { name: "Overview", icon: "information-box-outline", tabContent: this.element },
{ name: "Metadata", icon: "file-document-outline", tabContent: $el("div", ["Metadata"]) },
{ name: "Tags", icon: "tag-outline", tabContent: $el("div", ["Tags"]) },
{ name: "Notes", icon: "pencil-outline", tabContent: $el("div", ["Notes"]) }, { name: "Notes", icon: "pencil-outline", tabContent: $el("div", ["Notes"]) },
{ name: "Tags", icon: "tag-outline", tabContent: $el("div", ["Tags"]) },
{ name: "Metadata", icon: "file-document-outline", tabContent: $el("div", ["Metadata"]) },
]); ]);
} }
@@ -2457,7 +2457,7 @@ class ModelInfo {
result["info"], result["info"],
result["metadata"], result["metadata"],
result["tags"], result["tags"],
result["notes"] result["notes"],
]; ];
}) })
.catch((err) => { .catch((err) => {
@@ -2642,33 +2642,137 @@ class ModelInfo {
infoHtml.append.apply(infoHtml, innerHtml); infoHtml.append.apply(infoHtml, innerHtml);
// TODO: set default value of dropdown and value to model type? // TODO: set default value of dropdown and value to model type?
/** @type {HTMLDivElement} */ //
const metadataElement = this.elements.tabContents[1]; // TODO: remove magic value // NOTES
const isMetadata = typeof metadata === 'object' && metadata !== null && Object.keys(metadata).length > 0; //
metadataElement.innerHTML = "";
metadataElement.append.apply(metadataElement, [ const saveIcon = "content-save";
$el("h1", ["Metadata"]), const savingIcon = "cloud-upload-outline";
$el("div", (() => {
const tableRows = []; const saveNotesButton = new ComfyButton({
if (isMetadata) { icon: saveIcon,
for (const [key, value] of Object.entries(metadata)) { tooltip: "Save note",
if (value === undefined || value === null) { classList: "comfyui-button icon-button",
continue; action: async (e) => {
} const [button, icon, span] = comfyButtonDisambiguate(e.target);
if (value !== "") { button.disabled = true;
tableRows.push($el("tr", [ const saved = await this.trySave(false);
$el("th.model-metadata-key", [key]), comfyButtonAlert(e.target, saved);
$el("th.model-metadata-value", [value]), button.disabled = false;
])); },
} }).element;
}
const downloadNotesButton = new ComfyButton({
icon: "earth-arrow-down",
tooltip: "Attempt to download model info from the internet.",
classList: "comfyui-button icon-button",
action: async (e) => {
if (this.#savedNotesValue !== "") {
const overwriteNoteConfirmation = window.confirm("Overwrite note?");
if (!overwriteNoteConfirmation) {
comfyButtonAlert(e.target, false, "mdi-check-bold", "mdi-close-thick");
return;
} }
return $el("table.model-metadata", tableRows); }
})(),
), const [button, icon, span] = comfyButtonDisambiguate(e.target);
]); button.disabled = true;
const metadataButton = this.elements.tabButtons[1]; // TODO: remove magic value const [success, downloadedNotesValue] = await comfyRequest(
metadataButton.style.display = isMetadata ? "" : "none"; `/model-manager/notes/download?path=${path}&overwrite=True`,
{
method: "POST",
body: {},
}
).then((data) => {
const success = data["success"];
const message = data["alert"];
if (message !== undefined) {
window.alert(message);
}
return [success, data["notes"]];
}).catch((err) => {
return [false, ""];
});
if (success) {
this.#savedNotesValue = downloadedNotesValue;
this.elements.notes.value = downloadedNotesValue;
}
comfyButtonAlert(e.target, success, "mdi-check-bold", "mdi-close-thick");
button.disabled = false;
},
}).element;
const saveDebounce = debounce(async() => {
const saveIconClass = "mdi-" + saveIcon;
const savingIconClass = "mdi-" + savingIcon;
const iconElement = saveNotesButton.getElementsByTagName("i")[0];
iconElement.classList.remove(saveIconClass);
iconElement.classList.add(savingIconClass);
const saved = await this.trySave(false);
iconElement.classList.remove(savingIconClass);
iconElement.classList.add(saveIconClass);
}, 1000);
/** @type {HTMLDivElement} */
const notesElement = this.elements.tabContents[1]; // TODO: remove magic value
notesElement.innerHTML = "";
notesElement.append.apply(notesElement,
(() => {
const notes = $el("textarea.comfy-multiline-input", {
name: "model notes",
value: noteText,
oninput: (e) => {
if (this.#settingsElements["model-info-autosave-notes"].checked) {
saveDebounce();
}
},
});
if (navigator.userAgent.includes("Mac")) {
new KeyComboListener(
["MetaLeft", "KeyS"],
saveDebounce,
notes,
);
new KeyComboListener(
["MetaRight", "KeyS"],
saveDebounce,
notes,
);
}
else {
new KeyComboListener(
["ControlLeft", "KeyS"],
saveDebounce,
notes,
);
new KeyComboListener(
["ControlRight", "KeyS"],
saveDebounce,
notes,
);
}
this.elements.notes = notes;
this.#savedNotesValue = noteText;
return [
$el("div.row", {
style: { "align-items": "center" },
}, [
$el("h1", ["Notes"]),
saveNotesButton,
downloadNotesButton,
]),
$el("div", {
style: { "display": "flex", "height": "100%", "min-height": "60px" },
}, notes),
];
})()
);
//
// Tags
//
/** @type {HTMLDivElement} */ /** @type {HTMLDivElement} */
const tagsElement = this.elements.tabContents[2]; // TODO: remove magic value const tagsElement = this.elements.tabContents[2]; // TODO: remove magic value
@@ -2762,129 +2866,37 @@ class ModelInfo {
const tagButton = this.elements.tabButtons[2]; // TODO: remove magic value const tagButton = this.elements.tabButtons[2]; // TODO: remove magic value
tagButton.style.display = isTags ? "" : "none"; tagButton.style.display = isTags ? "" : "none";
const saveIcon = "content-save"; //
const savingIcon = "cloud-upload-outline"; // Metadata
//
const saveNotesButton = new ComfyButton({
icon: saveIcon,
tooltip: "Save note",
classList: "comfyui-button icon-button",
action: async (e) => {
const [button, icon, span] = comfyButtonDisambiguate(e.target);
button.disabled = true;
const saved = await this.trySave(false);
comfyButtonAlert(e.target, saved);
button.disabled = false;
},
}).element;
const downloadNotesButton = new ComfyButton({
icon: "earth-arrow-down",
tooltip: "Attempt to download model info from the internet.",
classList: "comfyui-button icon-button",
action: async (e) => {
if (this.#savedNotesValue !== "") {
const overwriteNoteConfirmation = window.confirm("Overwrite note?");
if (!overwriteNoteConfirmation) {
comfyButtonAlert(e.target, false, "mdi-check-bold", "mdi-close-thick");
return;
}
}
const [button, icon, span] = comfyButtonDisambiguate(e.target);
button.disabled = true;
const [success, downloadedNotesValue] = await comfyRequest(
`/model-manager/notes/download?path=${path}&overwrite=True`,
{
method: "POST",
body: {},
}
).then((data) => {
const success = data["success"];
const message = data["alert"];
if (message !== undefined) {
window.alert(message);
}
return [success, data["notes"]];
}).catch((err) => {
return [false, ""];
});
if (success) {
this.#savedNotesValue = downloadedNotesValue;
this.elements.notes.value = downloadedNotesValue;
}
comfyButtonAlert(e.target, success, "mdi-check-bold", "mdi-close-thick");
button.disabled = false;
},
}).element;
const saveDebounce = debounce(async() => {
const saveIconClass = "mdi-" + saveIcon;
const savingIconClass = "mdi-" + savingIcon;
const iconElement = saveNotesButton.getElementsByTagName("i")[0];
iconElement.classList.remove(saveIconClass);
iconElement.classList.add(savingIconClass);
const saved = await this.trySave(false);
iconElement.classList.remove(savingIconClass);
iconElement.classList.add(saveIconClass);
}, 1000);
/** @type {HTMLDivElement} */ /** @type {HTMLDivElement} */
const notesElement = this.elements.tabContents[3]; // TODO: remove magic value const metadataElement = this.elements.tabContents[3]; // TODO: remove magic value
notesElement.innerHTML = ""; const isMetadata = typeof metadata === 'object' && metadata !== null && Object.keys(metadata).length > 0;
notesElement.append.apply(notesElement, metadataElement.innerHTML = "";
(() => { metadataElement.append.apply(metadataElement, [
const notes = $el("textarea.comfy-multiline-input", { $el("h1", ["Metadata"]),
name: "model notes", $el("div", (() => {
value: noteText, const tableRows = [];
oninput: (e) => { if (isMetadata) {
if (this.#settingsElements["model-info-autosave-notes"].checked) { for (const [key, value] of Object.entries(metadata)) {
saveDebounce(); if (value === undefined || value === null) {
continue;
}
if (value !== "") {
tableRows.push($el("tr", [
$el("th.model-metadata-key", [key]),
$el("th.model-metadata-value", [value]),
]));
}
} }
}, }
}); return $el("table.model-metadata", tableRows);
})(),
if (navigator.userAgent.includes("Mac")) { ),
new KeyComboListener( ]);
["MetaLeft", "KeyS"], const metadataButton = this.elements.tabButtons[3]; // TODO: remove magic value
saveDebounce, metadataButton.style.display = isMetadata ? "" : "none";
notes,
);
new KeyComboListener(
["MetaRight", "KeyS"],
saveDebounce,
notes,
);
}
else {
new KeyComboListener(
["ControlLeft", "KeyS"],
saveDebounce,
notes,
);
new KeyComboListener(
["ControlRight", "KeyS"],
saveDebounce,
notes,
);
}
this.elements.notes = notes;
this.#savedNotesValue = noteText;
return [
$el("div.row", {
style: { "align-items": "center" },
}, [
$el("h1", ["Notes"]),
saveNotesButton,
downloadNotesButton,
]),
$el("div", {
style: { "display": "flex", "height": "100%", "min-height": "60px" },
}, notes),
];
})()
);
} }
static UniformTagSampling(tagsAndCounts, sampleCount, frequencyThreshold = 0) { static UniformTagSampling(tagsAndCounts, sampleCount, frequencyThreshold = 0) {
@@ -3333,7 +3345,6 @@ async function getModelInfos(urlText) {
"fp": file["fp"], "fp": file["fp"],
"quant": file["size"], "quant": file["size"],
"fileFormat": file["format"], "fileFormat": file["format"],
"sha256": file["hashes"]["SHA256"],
}, },
}); });
}); });
@@ -3354,7 +3365,6 @@ async function getModelInfos(urlText) {
const infos = hfInfo["modelFiles"].map((file) => { const infos = hfInfo["modelFiles"].map((file) => {
const indexSep = file.lastIndexOf("/"); const indexSep = file.lastIndexOf("/");
const filename = file.substring(indexSep + 1); const filename = file.substring(indexSep + 1);
// TODO: get sha256 of each HuggingFace model file
return { return {
"images": hfInfo["images"], "images": hfInfo["images"],
"fileName": filename, "fileName": filename,
@@ -3657,7 +3667,6 @@ class DownloadView {
formData.append("download", info["downloadUrl"]); formData.append("download", info["downloadUrl"]);
formData.append("path", pathDirectory); formData.append("path", pathDirectory);
formData.append("name", modelName); formData.append("name", modelName);
formData.append("sha256", info["details"]["sha256"]);
const image = await downloadPreviewSelect.getImage(); const image = await downloadPreviewSelect.getImage();
formData.append("image", image === PREVIEW_NONE_URI ? "" : image); formData.append("image", image === PREVIEW_NONE_URI ? "" : image);
formData.append("overwrite", this.elements.overwrite.checked); formData.append("overwrite", this.elements.overwrite.checked);