From bb2e653c1f2b424b93402d85a7245c44b717aa8d Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sun, 1 Oct 2023 11:17:34 +0100 Subject: [PATCH] Add editing notes --- py/model_info.py | 36 ++++++++++++++ web/js/common/modelInfoDialog.css | 8 ++++ web/js/common/modelInfoDialog.js | 80 +++++++++++++++++++++++++++---- 3 files changed, 115 insertions(+), 9 deletions(-) diff --git a/py/model_info.py b/py/model_info.py index 0fba0d0..b9b4daf 100644 --- a/py/model_info.py +++ b/py/model_info.py @@ -23,6 +23,42 @@ def get_metadata(filepath): return header_json["__metadata__"] if "__metadata__" in header_json else None +@PromptServer.instance.routes.post("/pysssss/metadata/notes/{name}") +async def save_notes(request): + name = request.match_info["name"] + pos = name.index("/") + type = name[0:pos] + name = name[pos+1:] + + file_path = None + if type == "embeddings": + name = name.lower() + files = folder_paths.get_filename_list(type) + for f in files: + lower_f = f.lower() + if lower_f == name: + file_path = folder_paths.get_full_path(type, f) + else: + n = os.path.splitext(f)[0].lower() + if n == name: + file_path = folder_paths.get_full_path(type, f) + + if file_path is not None: + break + else: + file_path = folder_paths.get_full_path( + type, name) + if not file_path: + return web.Response(status=404) + + file_no_ext = os.path.splitext(file_path)[0] + info_file = file_no_ext + ".txt" + with open(info_file, "w") as f: + f.write(await request.text()) + + return web.Response(status=200) + + @PromptServer.instance.routes.get("/pysssss/metadata/{name}") async def load_metadata(request): name = request.match_info["name"] diff --git a/web/js/common/modelInfoDialog.css b/web/js/common/modelInfoDialog.css index 92bcb67..7c9718d 100644 --- a/web/js/common/modelInfoDialog.css +++ b/web/js/common/modelInfoDialog.css @@ -94,3 +94,11 @@ bottom: 10px; right: 10px; } +.pysssss-model-notes { + background-color: rgba(0, 0, 0, 0.25); + padding: 5px; + margin-top: 5px; +} +.pysssss-model-notes:empty { + display: none; +} diff --git a/web/js/common/modelInfoDialog.js b/web/js/common/modelInfoDialog.js index cab47c8..9a8c989 100644 --- a/web/js/common/modelInfoDialog.js +++ b/web/js/common/modelInfoDialog.js @@ -33,6 +33,10 @@ export class ModelInfoDialog extends ComfyDialog { return this.metadata["pysssss.notes"]; } + set customNotes(v) { + this.metadata["pysssss.notes"] = v; + } + get hash() { return this.metadata["pysssss.sha256"]; } @@ -41,7 +45,7 @@ export class ModelInfoDialog extends ComfyDialog { this.type = type; const req = api.fetchApi("/pysssss/metadata/" + encodeURIComponent(`${type}/${value}`)); - this.info = $el("div"); + this.info = $el("div", { style: { flex: "auto" } }); this.img = $el("img", { style: { display: "none" } }); this.imgWrapper = $el("div.pysssss-preview", [this.img]); this.main = $el("main", { style: { display: "flex" } }, [this.info, this.imgWrapper]); @@ -81,7 +85,9 @@ export class ModelInfoDialog extends ComfyDialog { } getNoteInfo() { - if (this.customNotes) { + function parseNote() { + if (!this.customNotes) return []; + let notes = []; // Extract links from notes const r = new RegExp("(\\bhttps?:\\/\\/[^\\s]+)", "g"); @@ -119,14 +125,70 @@ export class ModelInfoDialog extends ComfyDialog { end = fin; } while (m); - return $el("span", notes); - } else { - let last = this.name.lastIndexOf("."); - if (last === -1) { - last = this.name.length; - } - return `Add custom notes in ${this.name.substring(0, last) + ".txt"}`; + return notes; } + + let textarea; + let notesContainer; + const editText = "✏️ Edit"; + const edit = $el("a", { + textContent: editText, + href: "#", + style: { + float: "right", + color: "greenyellow", + textDecoration: "none", + }, + onclick: async (e) => { + e.preventDefault(); + + if (textarea) { + this.customNotes = textarea.value; + + const resp = await api.fetchApi( + "/pysssss/metadata/notes/" + encodeURIComponent(`${this.type}/${this.name}`), + { + method: "POST", + body: this.customNotes, + } + ); + + if (resp.status !== 200) { + console.error(resp); + alert(`Error saving notes (${req.status}) ${req.statusText}`); + return; + } + + e.target.textContent = editText; + textarea.remove(); + textarea = null; + + notesContainer.replaceChildren(...parseNote.call(this)); + } else { + e.target.textContent = "💾 Save"; + textarea = $el("textarea", { + style: { + width: "100%", + minWidth: "200px", + minHeight: "50px", + }, + textContent: this.customNotes, + }); + e.target.after(textarea); + notesContainer.replaceChildren(); + textarea.style.height = Math.min(textarea.scrollHeight, 300) + "px"; + } + }, + }); + + notesContainer = $el("div.pysssss-model-notes", parseNote.call(this)); + return $el( + "div", + { + style: { display: "contents" }, + }, + [edit, notesContainer] + ); } addInfo() {