mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-23 11:41:17 -03:00
Compare commits
5 Commits
34791c2ad7
...
17ba350153
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17ba350153 | ||
|
|
60175334b5 | ||
|
|
f65a01df00 | ||
|
|
430e24d70b | ||
|
|
14f0c48fdd |
@@ -21,7 +21,9 @@
|
||||
"stone9k",
|
||||
"Rosenthal",
|
||||
"Francisco Tatis",
|
||||
"JongWon Han",
|
||||
"runte3221",
|
||||
"FreelancerZ",
|
||||
"Fraser Cross",
|
||||
"Polymorphic Indeterminate",
|
||||
"Marc Whiffen",
|
||||
@@ -43,11 +45,13 @@
|
||||
"ClockDaemon",
|
||||
"KD",
|
||||
"Omnidex",
|
||||
"Tyler Trebuchon",
|
||||
"Release Cabrakan",
|
||||
"Tobi_Swagg",
|
||||
"SG",
|
||||
"James Dooley",
|
||||
"zenbound",
|
||||
"Buzzard",
|
||||
"jmack",
|
||||
"Andrew Wilson",
|
||||
"Greybush",
|
||||
@@ -57,7 +61,7 @@
|
||||
"Wolffen",
|
||||
"Ricky Carter",
|
||||
"James Todd",
|
||||
"JongWon Han",
|
||||
"Steven Pfeiffer",
|
||||
"VantAI",
|
||||
"Tim",
|
||||
"Lisster",
|
||||
@@ -65,7 +69,6 @@
|
||||
"Illrigger",
|
||||
"Tom Corrigan",
|
||||
"JackieWang",
|
||||
"FreelancerZ",
|
||||
"fnkylove",
|
||||
"Yushio",
|
||||
"Vik71it",
|
||||
@@ -73,6 +76,7 @@
|
||||
"Lilleman",
|
||||
"Robert Stacey",
|
||||
"PM",
|
||||
"Todd Keck",
|
||||
"Edgar Tejeda",
|
||||
"Jorge Hussni",
|
||||
"Liam MacDougal",
|
||||
@@ -91,7 +95,6 @@
|
||||
"Melville Parrish",
|
||||
"daniel dove",
|
||||
"Lustre",
|
||||
"Tyler Trebuchon",
|
||||
"JW Sin",
|
||||
"contrite831",
|
||||
"Alex",
|
||||
@@ -99,20 +102,19 @@
|
||||
"carozzz",
|
||||
"Marlon Daniels",
|
||||
"Starkselle",
|
||||
"Buzzard",
|
||||
"Aaron Bleuer",
|
||||
"LacesOut!",
|
||||
"greebles",
|
||||
"Adam Shaw",
|
||||
"Anthony Rizzo",
|
||||
"M Postkasse",
|
||||
"Gooohokrbe",
|
||||
"RedrockVP",
|
||||
"ASLPro3D",
|
||||
"Wicked Choices by ASLPro3D",
|
||||
"OldBones",
|
||||
"Jacob Hoehler",
|
||||
"FinalyFree",
|
||||
"Weasyl",
|
||||
"Steven Pfeiffer",
|
||||
"Timmy",
|
||||
"Johnny",
|
||||
"Cory Paza",
|
||||
@@ -126,7 +128,7 @@
|
||||
"corde",
|
||||
"Nick Walker",
|
||||
"Bishoujoker",
|
||||
"Todd Keck",
|
||||
"aai",
|
||||
"Briton Heilbrun",
|
||||
"Tori",
|
||||
"wildnut",
|
||||
@@ -153,12 +155,13 @@
|
||||
"JaxMax",
|
||||
"takyamtom",
|
||||
"Jwk0205",
|
||||
"Bro Xie",
|
||||
"batblue",
|
||||
"carey6409",
|
||||
"Olive",
|
||||
"太郎 ゲーム",
|
||||
"Some Guy Named Barry",
|
||||
"Cosmosis",
|
||||
"M Postkasse",
|
||||
"AELOX",
|
||||
"Nicfit23",
|
||||
"FloPro4Sho",
|
||||
@@ -172,13 +175,13 @@
|
||||
"Serge Bekenkamp",
|
||||
"Jimmy Ledbetter",
|
||||
"LeoZero",
|
||||
"Antonio Pontes",
|
||||
"ApathyJones",
|
||||
"Julian V",
|
||||
"Steven Owens",
|
||||
"nahinahi9",
|
||||
"Dustin Chen",
|
||||
"dan",
|
||||
"aai",
|
||||
"Mouthlessman",
|
||||
"otaku fra",
|
||||
"ViperC",
|
||||
@@ -199,15 +202,15 @@
|
||||
"Jon Sandman",
|
||||
"Ubivis",
|
||||
"CloudValley",
|
||||
"linnfrey",
|
||||
"IamAyam",
|
||||
"skaterb949",
|
||||
"Joboshy",
|
||||
"Bohemian Corporal",
|
||||
"Dan",
|
||||
"confiscated Zyra",
|
||||
"Bro Xie",
|
||||
"yer fey",
|
||||
"Error_Rule34_Not_found",
|
||||
"太郎 ゲーム",
|
||||
"Roslynd",
|
||||
"Tee Gee",
|
||||
"jinxedx",
|
||||
@@ -221,7 +224,7 @@
|
||||
"Magic Noob",
|
||||
"Pronredn",
|
||||
"DougPeterson",
|
||||
"Antonio Pontes",
|
||||
"Jeff",
|
||||
"Bruce",
|
||||
"lh qwe",
|
||||
"Kevin John Duck",
|
||||
@@ -249,19 +252,21 @@
|
||||
"地獄の禄",
|
||||
"MJG",
|
||||
"David LaVallee",
|
||||
"linnfrey",
|
||||
"ae",
|
||||
"Tr4shP4nda",
|
||||
"WRL_SPR",
|
||||
"capn",
|
||||
"Joseph",
|
||||
"Mirko Katzula",
|
||||
"dan",
|
||||
"Piccio08",
|
||||
"kumakichi",
|
||||
"cppbel",
|
||||
"奚明 刘",
|
||||
"Brian M",
|
||||
"Josef Lanzl",
|
||||
"Nerezza",
|
||||
"sanborondon",
|
||||
"Griffin Dahlberg",
|
||||
"준희 김",
|
||||
"Taylor Funk",
|
||||
"aezin",
|
||||
@@ -278,10 +283,11 @@
|
||||
"Noora",
|
||||
"Pierce McBride",
|
||||
"Mattssn",
|
||||
"Mikko Hemilä",
|
||||
"Jamie Ogletree",
|
||||
"a _",
|
||||
"Jeff",
|
||||
"James Coleman",
|
||||
"Martial",
|
||||
"Emil Andersson",
|
||||
"Ouro Boros",
|
||||
"Chad Idk",
|
||||
@@ -302,10 +308,6 @@
|
||||
"Nick “Loadstone” D",
|
||||
"Gamalonia",
|
||||
"momokai",
|
||||
"dan",
|
||||
"Piccio08",
|
||||
"kumakichi",
|
||||
"cppbel",
|
||||
"starbugx",
|
||||
"Moon Knight",
|
||||
"몽타주",
|
||||
@@ -337,6 +339,7 @@
|
||||
"Andrew",
|
||||
"Robert Wegemund",
|
||||
"Littlehuggy",
|
||||
"Gregory Kozhemiak",
|
||||
"Draven T",
|
||||
"mrjuan",
|
||||
"Brian Buie",
|
||||
@@ -350,7 +353,6 @@
|
||||
"Joshua Gray",
|
||||
"Morgandel",
|
||||
"Focuschannel",
|
||||
"Mikko Hemilä",
|
||||
"Noah",
|
||||
"Jacob McDaniel",
|
||||
"X",
|
||||
@@ -359,7 +361,6 @@
|
||||
"Artokun",
|
||||
"Michael Taylor",
|
||||
"Derek Baker",
|
||||
"Martial",
|
||||
"Anthony Faxlandez",
|
||||
"battu",
|
||||
"Michael Anthony Scott",
|
||||
@@ -367,8 +368,6 @@
|
||||
"Decx _",
|
||||
"Pat Hen",
|
||||
"Jordan Shaw",
|
||||
"Thesharingbrother",
|
||||
"ResidentDeviant",
|
||||
"四糸凜音",
|
||||
"Nihongasuki",
|
||||
"JC",
|
||||
@@ -412,11 +411,11 @@
|
||||
"Wolfe7D1",
|
||||
"blikkies",
|
||||
"Chris",
|
||||
"Gregory Kozhemiak",
|
||||
"elleshar666",
|
||||
"Shock Shockor",
|
||||
"ACTUALLY_the_Real_Willem_Dafoe",
|
||||
"Goldwaters",
|
||||
"Kauffy",
|
||||
"Zude",
|
||||
"John J Linehan",
|
||||
"Kyler",
|
||||
@@ -426,19 +425,21 @@
|
||||
"Justin Blaylock",
|
||||
"aRtFuL_DodGeR",
|
||||
"Vane Holzer",
|
||||
"psytrax",
|
||||
"hexxish",
|
||||
"notedfakes",
|
||||
"DarkSunset",
|
||||
"Nathan",
|
||||
"Billy Gladky",
|
||||
"NICHOLAS BAXLEY",
|
||||
"Michael Scott",
|
||||
"Probis",
|
||||
"Ed Wang",
|
||||
"Wes Sims",
|
||||
"ItsGeneralButtNaked",
|
||||
"SRDB",
|
||||
"g unit",
|
||||
"Distortik",
|
||||
"Filippo Ferrari",
|
||||
"Youguang",
|
||||
"Saya",
|
||||
"andrewzpong",
|
||||
@@ -456,6 +457,7 @@
|
||||
"emadsultan",
|
||||
"Pkrsky",
|
||||
"nanana",
|
||||
"FeralOpticsAI",
|
||||
"Pavlaki",
|
||||
"Doug+Rintoul",
|
||||
"Noor",
|
||||
@@ -483,7 +485,6 @@
|
||||
"Time Valentine",
|
||||
"Михал Михалыч",
|
||||
"Matt",
|
||||
"Kauffy",
|
||||
"Frogmilk",
|
||||
"SPJ",
|
||||
"Kyron Mahan",
|
||||
@@ -491,11 +492,11 @@
|
||||
"Nick Kage",
|
||||
"TBitz33",
|
||||
"Anonym dkjglfleeoeldldldlkf",
|
||||
"psytrax",
|
||||
"Cyrus Fett",
|
||||
"Ezokewn",
|
||||
"SendingRavens",
|
||||
"Xenon Xue",
|
||||
"JackJohnnyJim",
|
||||
"Edward Ten Eyck",
|
||||
"Michael Docherty",
|
||||
"Paul Hartsuyker",
|
||||
@@ -504,15 +505,14 @@
|
||||
"Solixer",
|
||||
"Jacob Winter",
|
||||
"Ryan Presley Ng",
|
||||
"Wes Sims",
|
||||
"jinksta187",
|
||||
"Donor4115",
|
||||
"Manu Thetug",
|
||||
"Karlanx",
|
||||
"Lyavph",
|
||||
"David",
|
||||
"Meilo",
|
||||
"operationancut",
|
||||
"Filippo Ferrari",
|
||||
"shinonomeiro",
|
||||
"Snille",
|
||||
"MaartenAlbers",
|
||||
@@ -531,6 +531,8 @@
|
||||
"Scott",
|
||||
"Muratoraccio",
|
||||
"D",
|
||||
"YassineKhaled",
|
||||
"Y",
|
||||
"MatteKey",
|
||||
"Flob",
|
||||
"ShiroSenpai",
|
||||
@@ -552,7 +554,6 @@
|
||||
"rsamerica",
|
||||
"sfasdfasfdsa",
|
||||
"Alan+Cano",
|
||||
"FeralOpticsAI",
|
||||
"generic404",
|
||||
"abattoirblues",
|
||||
"zounik",
|
||||
@@ -584,7 +585,6 @@
|
||||
"Sauv",
|
||||
"Steven",
|
||||
"CptNeo",
|
||||
"JackJohnnyJim",
|
||||
"TenaciousD",
|
||||
"Dmitry Ryzhov",
|
||||
"Khánh Đặng",
|
||||
@@ -599,7 +599,6 @@
|
||||
"Andrew Wilkinson",
|
||||
"Yavizu3d",
|
||||
"Maxim",
|
||||
"Karlanx",
|
||||
"Yves Poezevara",
|
||||
"Teriak47",
|
||||
"Just me",
|
||||
@@ -637,6 +636,7 @@
|
||||
"Captain_Swag",
|
||||
"obkircher",
|
||||
"gwyar",
|
||||
"ResidentDeviant",
|
||||
"D",
|
||||
"edgecase",
|
||||
"Neoxena",
|
||||
@@ -681,8 +681,6 @@
|
||||
"low9",
|
||||
"Winged",
|
||||
"you+halo9",
|
||||
"YassineKhaled",
|
||||
"YK12",
|
||||
"Somebody",
|
||||
"Somebody",
|
||||
"Crescent~San",
|
||||
@@ -697,6 +695,7 @@
|
||||
"Coeur+de+cochon",
|
||||
"Obsidian.Studios",
|
||||
"han b",
|
||||
"Zomba Mann",
|
||||
"Nico",
|
||||
"Maximilian Krischan",
|
||||
"Banana Joe",
|
||||
@@ -714,7 +713,6 @@
|
||||
"Ronan Delevacq",
|
||||
"karim ben brik",
|
||||
"Vinarus",
|
||||
"james",
|
||||
"Michael Zhu",
|
||||
"Nemisu",
|
||||
"Seraphy",
|
||||
@@ -743,9 +741,11 @@
|
||||
"dsffsdfsdfsdfsdfsdf",
|
||||
"somethingtosay8",
|
||||
"Jean-françois SEMA",
|
||||
"3zS4QNQ4",
|
||||
"Terminuz",
|
||||
"Kurt",
|
||||
"ivistorm",
|
||||
"Ivan Imes",
|
||||
"Faburizu",
|
||||
"Jack Lawfield",
|
||||
"jimyjomson",
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "Inhaltsbewertung für alle festlegen",
|
||||
"copyAll": "Alle Syntax kopieren",
|
||||
"refreshAll": "Alle Metadaten aktualisieren",
|
||||
"repairMetadata": "Metadaten der Auswahl reparieren",
|
||||
"checkUpdates": "Auswahl auf Updates prüfen",
|
||||
"moveAll": "Alle in Ordner verschieben",
|
||||
"autoOrganize": "Automatisch organisieren",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "Keine Rezepte ausgewählt",
|
||||
"repairBulkComplete": "Reparatur abgeschlossen: {repaired} repariert, {skipped} übersprungen (von {total})",
|
||||
"repairBulkSkipped": "Keine Reparatur für die {total} ausgewählten Rezepte erforderlich",
|
||||
"repairBulkFailed": "Reparatur der ausgewählten Rezepte fehlgeschlagen: {message}",
|
||||
"noMissingLorasInSelection": "Keine fehlenden LoRAs in ausgewählten Rezepten gefunden",
|
||||
"noLoraRootConfigured": "Kein LoRA-Stammverzeichnis konfiguriert. Bitte legen Sie ein Standard-LoRA-Stammverzeichnis in den Einstellungen fest."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "Set Content Rating for Selected",
|
||||
"copyAll": "Copy Selected Syntax",
|
||||
"refreshAll": "Refresh Selected Metadata",
|
||||
"repairMetadata": "Repair Metadata for Selected",
|
||||
"checkUpdates": "Check Updates for Selected",
|
||||
"moveAll": "Move Selected to Folder",
|
||||
"autoOrganize": "Auto-Organize Selected",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "No recipes selected",
|
||||
"repairBulkComplete": "Repair complete: {repaired} repaired, {skipped} skipped (of {total})",
|
||||
"repairBulkSkipped": "No repair needed for any of the {total} selected recipes",
|
||||
"repairBulkFailed": "Failed to repair selected recipes: {message}",
|
||||
"noMissingLorasInSelection": "No missing LoRAs found in selected recipes",
|
||||
"noLoraRootConfigured": "No LoRA root directory configured. Please set a default LoRA root in settings."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "Establecer clasificación de contenido para todos",
|
||||
"copyAll": "Copiar toda la sintaxis",
|
||||
"refreshAll": "Actualizar todos los metadatos",
|
||||
"repairMetadata": "Reparar metadatos de la selección",
|
||||
"checkUpdates": "Comprobar actualizaciones para la selección",
|
||||
"moveAll": "Mover todos a carpeta",
|
||||
"autoOrganize": "Auto-organizar seleccionados",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "No se han seleccionado recetas",
|
||||
"repairBulkComplete": "Reparación completa: {repaired} reparadas, {skipped} omitidas (de {total})",
|
||||
"repairBulkSkipped": "No se necesita reparación para ninguna de las {total} recetas seleccionadas",
|
||||
"repairBulkFailed": "Error al reparar las recetas seleccionadas: {message}",
|
||||
"noMissingLorasInSelection": "No se encontraron LoRAs faltantes en las recetas seleccionadas",
|
||||
"noLoraRootConfigured": "No se ha configurado el directorio raíz de LoRA. Por favor, establezca un directorio raíz de LoRA predeterminado en la configuración."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "Définir la classification du contenu pour tous",
|
||||
"copyAll": "Copier toute la syntaxe",
|
||||
"refreshAll": "Actualiser toutes les métadonnées",
|
||||
"repairMetadata": "Réparer les métadonnées de la sélection",
|
||||
"checkUpdates": "Vérifier les mises à jour pour la sélection",
|
||||
"moveAll": "Déplacer tout vers un dossier",
|
||||
"autoOrganize": "Auto-organiser la sélection",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "Aucune recette sélectionnée",
|
||||
"repairBulkComplete": "Réparation terminée : {repaired} réparée(s), {skipped} ignorée(s) (sur {total})",
|
||||
"repairBulkSkipped": "Aucune réparation nécessaire parmi les {total} recettes sélectionnées",
|
||||
"repairBulkFailed": "Échec de la réparation des recettes sélectionnées : {message}",
|
||||
"noMissingLorasInSelection": "Aucun LoRA manquant trouvé dans les recettes sélectionnées",
|
||||
"noLoraRootConfigured": "Aucun répertoire racine LoRA configuré. Veuillez définir un répertoire racine LoRA par défaut dans les paramètres."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "הגדר דירוג תוכן לכל המודלים",
|
||||
"copyAll": "העתק את כל התחבירים",
|
||||
"refreshAll": "רענן את כל המטא-דאטה",
|
||||
"repairMetadata": "תקן מטא-דאטה עבור הנבחרים",
|
||||
"checkUpdates": "בדוק עדכונים לבחירה",
|
||||
"moveAll": "העבר הכל לתיקייה",
|
||||
"autoOrganize": "ארגן אוטומטית נבחרים",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "לא נבחרו מתכונים",
|
||||
"repairBulkComplete": "התיקון הושלם: {repaired} תוקנו, {skipped} דולגו (מתוך {total})",
|
||||
"repairBulkSkipped": "אין צורך בתיקון עבור {total} המתכונים הנבחרים",
|
||||
"repairBulkFailed": "תיקון המתכונים הנבחרים נכשל: {message}",
|
||||
"noMissingLorasInSelection": "לא נמצאו LoRAs חסרים במתכונים שנבחרו",
|
||||
"noLoraRootConfigured": "תיקיית השורש של LoRA לא מוגדרת. אנא הגדר תיקיית שורש LoRA ברירת מחדל בהגדרות."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "すべてのモデルのコンテンツレーティングを設定",
|
||||
"copyAll": "すべての構文をコピー",
|
||||
"refreshAll": "すべてのメタデータを更新",
|
||||
"repairMetadata": "選択したレシピのメタデータを修復",
|
||||
"checkUpdates": "選択項目の更新を確認",
|
||||
"moveAll": "すべてをフォルダに移動",
|
||||
"autoOrganize": "自動整理を実行",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "レシピが選択されていません",
|
||||
"repairBulkComplete": "修復完了:{repaired} 件修復、{skipped} 件スキップ(合計 {total} 件)",
|
||||
"repairBulkSkipped": "選択した {total} 件のレシピは修復不要です",
|
||||
"repairBulkFailed": "選択したレシピの修復に失敗しました:{message}",
|
||||
"noMissingLorasInSelection": "選択したレシピに不足している LoRA が見つかりませんでした",
|
||||
"noLoraRootConfigured": "LoRA ルートディレクトリが設定されていません。設定でデフォルトの LoRA ルートを設定してください。"
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "모든 모델에 콘텐츠 등급 설정",
|
||||
"copyAll": "모든 문법 복사",
|
||||
"refreshAll": "모든 메타데이터 새로고침",
|
||||
"repairMetadata": "선택한 레시피 메타데이터 복구",
|
||||
"checkUpdates": "선택 항목 업데이트 확인",
|
||||
"moveAll": "모두 폴더로 이동",
|
||||
"autoOrganize": "자동 정리 선택",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "선택한 레시피가 없습니다",
|
||||
"repairBulkComplete": "복구 완료: {repaired}개 복구, {skipped}개 건너뜀 (총 {total}개)",
|
||||
"repairBulkSkipped": "선택한 {total}개 레시피는 복구가 필요하지 않습니다",
|
||||
"repairBulkFailed": "선택한 레시피 복구 실패: {message}",
|
||||
"noMissingLorasInSelection": "선택한 레시피에서 누락된 LoRA를 찾을 수 없습니다",
|
||||
"noLoraRootConfigured": "LoRA 루트 디렉토리가 구성되지 않았습니다. 설정에서 기본 LoRA 루트를 설정하세요."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "Установить рейтинг контента для всех",
|
||||
"copyAll": "Копировать весь синтаксис",
|
||||
"refreshAll": "Обновить все метаданные",
|
||||
"repairMetadata": "Восстановить метаданные для выбранных",
|
||||
"checkUpdates": "Проверить обновления для выбранных",
|
||||
"moveAll": "Переместить все в папку",
|
||||
"autoOrganize": "Автоматически организовать выбранные",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "Failed to browse directory: {message}",
|
||||
"batchImportDirectorySelected": "Directory selected: {path}",
|
||||
"noRecipesSelected": "Рецепты не выбраны",
|
||||
"repairBulkComplete": "Восстановление завершено: {repaired} восстановлено, {skipped} пропущено (из {total})",
|
||||
"repairBulkSkipped": "Ни один из {total} выбранных рецептов не требует восстановления",
|
||||
"repairBulkFailed": "Не удалось восстановить выбранные рецепты: {message}",
|
||||
"noMissingLorasInSelection": "В выбранных рецептах не найдены отсутствующие LoRAs",
|
||||
"noLoraRootConfigured": "Корневой каталог LoRA не настроен. Пожалуйста, установите корневой каталог LoRA по умолчанию в настройках."
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "为所选中设置内容评级",
|
||||
"copyAll": "复制所选中语法",
|
||||
"refreshAll": "刷新所选中元数据",
|
||||
"repairMetadata": "修复所选中元数据",
|
||||
"checkUpdates": "检查所选更新",
|
||||
"moveAll": "移动所选中到文件夹",
|
||||
"autoOrganize": "自动整理所选模型",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "浏览目录失败:{message}",
|
||||
"batchImportDirectorySelected": "已选择目录:{path}",
|
||||
"noRecipesSelected": "未选择任何配方",
|
||||
"repairBulkComplete": "修复完成:{repaired} 个已修复,{skipped} 个已跳过(共 {total} 个)",
|
||||
"repairBulkSkipped": "所选 {total} 个配方无需修复",
|
||||
"repairBulkFailed": "修复所选配方失败:{message}",
|
||||
"noMissingLorasInSelection": "在选定的配方中未找到缺失的 LoRAs",
|
||||
"noLoraRootConfigured": "未配置 LoRA 根目录。请在设置中设置默认的 LoRA 根目录。"
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@
|
||||
"setContentRating": "為全部設定內容分級",
|
||||
"copyAll": "複製全部語法",
|
||||
"refreshAll": "刷新全部 metadata",
|
||||
"repairMetadata": "修復所選中元數據",
|
||||
"checkUpdates": "檢查所選更新",
|
||||
"moveAll": "全部移動到資料夾",
|
||||
"autoOrganize": "自動整理所選模型",
|
||||
@@ -1693,6 +1694,9 @@
|
||||
"batchImportBrowseFailed": "瀏覽目錄失敗:{message}",
|
||||
"batchImportDirectorySelected": "已選擇目錄:{path}",
|
||||
"noRecipesSelected": "未選取任何食譜",
|
||||
"repairBulkComplete": "修復完成:{repaired} 個已修復,{skipped} 個已跳過(共 {total} 個)",
|
||||
"repairBulkSkipped": "所選 {total} 個配方無需修復",
|
||||
"repairBulkFailed": "修復所選配方失敗:{message}",
|
||||
"noMissingLorasInSelection": "在選取的食譜中未找到缺失的 LoRAs",
|
||||
"noLoraRootConfigured": "未配置 LoRA 根目錄。請在設定中設定預設的 LoRA 根目錄。"
|
||||
},
|
||||
|
||||
@@ -87,6 +87,7 @@ class RecipeHandlerSet:
|
||||
"repair_recipes": self.management.repair_recipes,
|
||||
"cancel_repair": self.management.cancel_repair,
|
||||
"repair_recipe": self.management.repair_recipe,
|
||||
"repair_recipes_bulk": self.management.repair_recipes_bulk,
|
||||
"get_repair_progress": self.management.get_repair_progress,
|
||||
"start_batch_import": self.batch_import.start_batch_import,
|
||||
"get_batch_import_progress": self.batch_import.get_batch_import_progress,
|
||||
@@ -706,6 +707,69 @@ class RecipeManagementHandler:
|
||||
self._logger.error("Error cancelling recipe repair: %s", exc, exc_info=True)
|
||||
return web.json_response({"success": False, "error": str(exc)}, status=500)
|
||||
|
||||
async def repair_recipes_bulk(self, request: web.Request) -> web.Response:
|
||||
"""Bulk repair metadata for multiple recipes by their IDs.
|
||||
|
||||
Accepts a JSON body with a "recipe_ids" array and iterates
|
||||
repair_recipe_by_id over each entry, collecting statistics.
|
||||
"""
|
||||
try:
|
||||
await self._ensure_dependencies_ready()
|
||||
recipe_scanner = self._recipe_scanner_getter()
|
||||
if recipe_scanner is None:
|
||||
return web.json_response(
|
||||
{"success": False, "error": "Recipe scanner unavailable"},
|
||||
status=503,
|
||||
)
|
||||
|
||||
data = await request.json()
|
||||
recipe_ids = data.get("recipe_ids", [])
|
||||
if not recipe_ids:
|
||||
return web.json_response(
|
||||
{"success": False, "error": "recipe_ids are required"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
total = len(recipe_ids)
|
||||
repaired = 0
|
||||
skipped = 0
|
||||
errors = 0
|
||||
recipes = []
|
||||
|
||||
for recipe_id in recipe_ids:
|
||||
try:
|
||||
result = await recipe_scanner.repair_recipe_by_id(recipe_id)
|
||||
if result.get("success"):
|
||||
repaired += result.get("repaired", 0)
|
||||
skipped += result.get("skipped", 0)
|
||||
if result.get("recipe"):
|
||||
recipes.append(result["recipe"])
|
||||
else:
|
||||
errors += 1
|
||||
except RecipeNotFoundError:
|
||||
skipped += 1
|
||||
except Exception as exc:
|
||||
self._logger.error(
|
||||
"Error repairing recipe %s: %s", recipe_id, exc
|
||||
)
|
||||
errors += 1
|
||||
|
||||
return web.json_response({
|
||||
"success": True,
|
||||
"total": total,
|
||||
"repaired": repaired,
|
||||
"skipped": skipped,
|
||||
"errors": errors,
|
||||
"recipes": recipes,
|
||||
})
|
||||
except Exception as exc:
|
||||
self._logger.error(
|
||||
"Error performing bulk repair: %s", exc, exc_info=True
|
||||
)
|
||||
return web.json_response(
|
||||
{"success": False, "error": str(exc)}, status=500
|
||||
)
|
||||
|
||||
async def repair_recipe(self, request: web.Request) -> web.Response:
|
||||
try:
|
||||
await self._ensure_dependencies_ready()
|
||||
|
||||
@@ -58,6 +58,7 @@ ROUTE_DEFINITIONS: tuple[RouteDefinition, ...] = (
|
||||
RouteDefinition("POST", "/api/lm/recipes/repair", "repair_recipes"),
|
||||
RouteDefinition("POST", "/api/lm/recipes/cancel-repair", "cancel_repair"),
|
||||
RouteDefinition("POST", "/api/lm/recipe/{recipe_id}/repair", "repair_recipe"),
|
||||
RouteDefinition("POST", "/api/lm/recipes/repair-bulk", "repair_recipes_bulk"),
|
||||
RouteDefinition("GET", "/api/lm/recipes/repair-progress", "get_repair_progress"),
|
||||
RouteDefinition("POST", "/api/lm/recipes/batch-import/start", "start_batch_import"),
|
||||
RouteDefinition(
|
||||
|
||||
@@ -65,7 +65,7 @@ class RecipeScanner:
|
||||
cls._instance._civitai_client = None # Will be lazily initialized
|
||||
return cls._instance
|
||||
|
||||
REPAIR_VERSION = 3
|
||||
REPAIR_VERSION = 4
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -292,6 +292,32 @@ class RecipeScanner:
|
||||
if recipe.get("repair_version", 0) >= self.REPAIR_VERSION:
|
||||
return False
|
||||
|
||||
# 1.5 Detect and clear corrupted checkpoint (LoRA data saved as checkpoint).
|
||||
# A checkpoint whose modelVersionId also appears in a LoRA entry is
|
||||
# definitely wrong — the CivitAI import code used to pick
|
||||
# modelVersionIds[0] as the checkpoint, which was often a LoRA.
|
||||
# Clearing it lets the enrichment flow re-resolve the correct
|
||||
# checkpoint from CivitAI image metadata.
|
||||
cp = recipe.get("checkpoint")
|
||||
lora_mvids = {
|
||||
l.get("modelVersionId")
|
||||
for l in recipe.get("loras", [])
|
||||
if l.get("modelVersionId")
|
||||
}
|
||||
if cp and cp.get("modelVersionId") and cp["modelVersionId"] in lora_mvids:
|
||||
cp_mvid = cp["modelVersionId"]
|
||||
logger.info(
|
||||
"Recipe %s: checkpoint modelVersionId %s matches a LoRA — "
|
||||
"clearing corrupted checkpoint and removing matching LoRA entry",
|
||||
recipe.get("id"),
|
||||
cp_mvid,
|
||||
)
|
||||
recipe["checkpoint"] = None
|
||||
recipe["loras"] = [
|
||||
l for l in recipe.get("loras", [])
|
||||
if l.get("modelVersionId") != cp_mvid
|
||||
]
|
||||
|
||||
# 2. Identification: Is repair needed?
|
||||
has_checkpoint = (
|
||||
"checkpoint" in recipe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-lora-manager"
|
||||
description = "Revolutionize your workflow with the ultimate LoRA companion for ComfyUI!"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = [
|
||||
"aiohttp",
|
||||
|
||||
@@ -15,6 +15,7 @@ const RECIPE_ENDPOINTS = {
|
||||
move: '/api/lm/recipe/move',
|
||||
moveBulk: '/api/lm/recipes/move-bulk',
|
||||
bulkDelete: '/api/lm/recipes/bulk-delete',
|
||||
repairBulk: '/api/lm/recipes/repair-bulk',
|
||||
};
|
||||
|
||||
const RECIPE_SIDEBAR_CONFIG = {
|
||||
@@ -557,6 +558,38 @@ export class RecipeSidebarApiClient {
|
||||
};
|
||||
}
|
||||
|
||||
async repairBulkModels(filePaths) {
|
||||
if (!filePaths || filePaths.length === 0) {
|
||||
throw new Error('No file paths provided');
|
||||
}
|
||||
|
||||
const recipeIds = filePaths
|
||||
.map((path) => extractRecipeId(path))
|
||||
.filter((id) => !!id);
|
||||
|
||||
if (recipeIds.length === 0) {
|
||||
throw new Error('No recipe IDs could be derived from file paths');
|
||||
}
|
||||
|
||||
const response = await fetch(this.apiConfig.endpoints.repairBulk, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
recipe_ids: recipeIds,
|
||||
}),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (!response.ok || !result.success) {
|
||||
throw new Error(result.error || 'Failed to repair recipes');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async bulkDeleteModels(filePaths) {
|
||||
if (!filePaths || filePaths.length === 0) {
|
||||
throw new Error('No file paths provided');
|
||||
|
||||
@@ -41,6 +41,11 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
const autoOrganizeItem = this.menu.querySelector('[data-action="auto-organize"]');
|
||||
const deleteAllItem = this.menu.querySelector('[data-action="delete-all"]');
|
||||
const downloadMissingLorasItem = this.menu.querySelector('[data-action="download-missing-loras"]');
|
||||
const repairMetadataItem = this.menu.querySelector('[data-action="repair-metadata"]');
|
||||
|
||||
if (repairMetadataItem) {
|
||||
repairMetadataItem.style.display = config.repairMetadata ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
if (sendToWorkflowAppendItem) {
|
||||
sendToWorkflowAppendItem.style.display = config.sendToWorkflow ? 'flex' : 'none';
|
||||
@@ -127,33 +132,38 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
const resumeMetadataRefreshItem = this.menu.querySelector('[data-action="resume-metadata-refresh"]');
|
||||
|
||||
if (skipMetadataRefreshItem && resumeMetadataRefreshItem) {
|
||||
const skipCount = this.countSkipStatus(true);
|
||||
const resumeCount = this.countSkipStatus(false);
|
||||
const totalCount = skipCount + resumeCount;
|
||||
|
||||
if (skipCount === totalCount) {
|
||||
if (!config.skipMetadataRefresh) {
|
||||
skipMetadataRefreshItem.style.display = 'none';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefresh'
|
||||
);
|
||||
} else if (resumeCount === totalCount) {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'none';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefresh'
|
||||
);
|
||||
} else {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefreshCount',
|
||||
{ count: resumeCount }
|
||||
);
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefreshCount',
|
||||
{ count: skipCount }
|
||||
);
|
||||
const skipCount = this.countSkipStatus(true);
|
||||
const resumeCount = this.countSkipStatus(false);
|
||||
const totalCount = skipCount + resumeCount;
|
||||
|
||||
if (skipCount === totalCount) {
|
||||
skipMetadataRefreshItem.style.display = 'none';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefresh'
|
||||
);
|
||||
} else if (resumeCount === totalCount) {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'none';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefresh'
|
||||
);
|
||||
} else {
|
||||
skipMetadataRefreshItem.style.display = 'flex';
|
||||
resumeMetadataRefreshItem.style.display = 'flex';
|
||||
skipMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.skipMetadataRefreshCount',
|
||||
{ count: resumeCount }
|
||||
);
|
||||
resumeMetadataRefreshItem.querySelector('span').textContent = translate(
|
||||
'loras.bulkOperations.resumeMetadataRefreshCount',
|
||||
{ count: skipCount }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +261,9 @@ export class BulkContextMenu extends BaseContextMenu {
|
||||
case 'delete-all':
|
||||
bulkManager.showBulkDeleteModal();
|
||||
break;
|
||||
case 'repair-metadata':
|
||||
bulkManager.repairSelectedRecipes();
|
||||
break;
|
||||
case 'set-favorite': {
|
||||
const allFavorited = this.countFavoritedInSelection() === state.selectedModels.size;
|
||||
bulkManager.setBulkFavorites(!allFavorited);
|
||||
|
||||
@@ -85,7 +85,8 @@ export class BulkManager {
|
||||
setContentRating: false,
|
||||
skipMetadataRefresh: false,
|
||||
setFavorite: true,
|
||||
unfavorite: true
|
||||
unfavorite: true,
|
||||
repairMetadata: true
|
||||
}
|
||||
};
|
||||
|
||||
@@ -656,6 +657,76 @@ export class BulkManager {
|
||||
}
|
||||
}
|
||||
|
||||
async repairSelectedRecipes() {
|
||||
if (state.selectedModels.size === 0) {
|
||||
showToast('toast.recipes.noRecipesSelected', {}, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.currentPageType !== 'recipes') {
|
||||
showToast('This operation is only available for recipes', {}, 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const apiClient = this.getActiveApiClient();
|
||||
const filePaths = Array.from(state.selectedModels);
|
||||
|
||||
if (typeof apiClient.repairBulkModels !== 'function') {
|
||||
showToast('Bulk repair is not supported for this model type', {}, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
state.loadingManager.showSimpleLoading('Repairing recipe metadata...');
|
||||
|
||||
const result = await apiClient.repairBulkModels(filePaths);
|
||||
|
||||
if (result.success) {
|
||||
const total = result.total || filePaths.length;
|
||||
const repaired = result.repaired || 0;
|
||||
const skipped = result.skipped || 0;
|
||||
|
||||
const recipes = result.recipes || [];
|
||||
for (const recipe of recipes) {
|
||||
if (recipe.file_path) {
|
||||
state.virtualScroller.updateSingleItem(
|
||||
recipe.file_path,
|
||||
recipe
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (repaired > 0) {
|
||||
showToast(
|
||||
'toast.recipes.repairBulkComplete',
|
||||
{ repaired, skipped, total },
|
||||
'success'
|
||||
);
|
||||
} else {
|
||||
showToast(
|
||||
'toast.recipes.repairBulkSkipped',
|
||||
{ total },
|
||||
'info'
|
||||
);
|
||||
}
|
||||
|
||||
this.clearSelection();
|
||||
} else {
|
||||
throw new Error(result.error || 'Bulk repair failed');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during bulk recipe repair:', error);
|
||||
showToast('toast.recipes.repairBulkFailed', { message: error.message }, 'error');
|
||||
} finally {
|
||||
if (state.loadingManager?.hide) {
|
||||
state.loadingManager.hide();
|
||||
}
|
||||
if (typeof state.loadingManager?.restoreProgressBar === 'function') {
|
||||
state.loadingManager.restoreProgressBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async refreshAllMetadata() {
|
||||
if (state.selectedModels.size === 0) {
|
||||
showToast('toast.models.noModelsSelected', {}, 'warning');
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
<div class="context-menu-item" data-action="check-updates">
|
||||
<i class="fas fa-bell"></i> <span>{{ t('loras.bulkOperations.checkUpdates') }}</span>
|
||||
</div>
|
||||
<div class="context-menu-item" data-action="repair-metadata">
|
||||
<i class="fas fa-tools"></i> <span>{{ t('loras.bulkOperations.repairMetadata') }}</span>
|
||||
</div>
|
||||
<div class="context-menu-item" data-action="skip-metadata-refresh">
|
||||
<i class="fas fa-ban"></i> <span>{{ t('loras.bulkOperations.skipMetadataRefresh') }}</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user