mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-06 22:10:14 -03:00
Compare commits
3 Commits
703a6a4ea0
...
402d8b07cf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
402d8b07cf | ||
|
|
3e303ab316 | ||
|
|
e9e8c31ad1 |
@@ -11,8 +11,8 @@
|
|||||||
"Insomnia Art Designs",
|
"Insomnia Art Designs",
|
||||||
"2018cfh",
|
"2018cfh",
|
||||||
"Arlecchino Shion",
|
"Arlecchino Shion",
|
||||||
"Rob Williams",
|
|
||||||
"Charles Blakemore",
|
"Charles Blakemore",
|
||||||
|
"Rob Williams",
|
||||||
"W+K+White",
|
"W+K+White",
|
||||||
"$MetaSamsara",
|
"$MetaSamsara",
|
||||||
"wackop",
|
"wackop",
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
"stone9k",
|
"stone9k",
|
||||||
"Rosenthal",
|
"Rosenthal",
|
||||||
"Francisco Tatis",
|
"Francisco Tatis",
|
||||||
|
"JongWon Han",
|
||||||
|
"FreelancerZ",
|
||||||
"Polymorphic Indeterminate",
|
"Polymorphic Indeterminate",
|
||||||
"Skalabananen",
|
"Skalabananen",
|
||||||
"Marc Whiffen",
|
"Marc Whiffen",
|
||||||
@@ -38,24 +40,32 @@
|
|||||||
"Estragon",
|
"Estragon",
|
||||||
"J\\B/ 8r0wns0n",
|
"J\\B/ 8r0wns0n",
|
||||||
"ClockDaemon",
|
"ClockDaemon",
|
||||||
|
"KD",
|
||||||
|
"Omnidex",
|
||||||
|
"Tyler Trebuchon",
|
||||||
|
"Release Cabrakan",
|
||||||
"Tobi_Swagg",
|
"Tobi_Swagg",
|
||||||
"SG",
|
"SG",
|
||||||
|
"James Dooley",
|
||||||
"zenbound",
|
"zenbound",
|
||||||
|
"Buzzard",
|
||||||
"jmack",
|
"jmack",
|
||||||
"Andrew Wilson",
|
"Andrew Wilson",
|
||||||
"Greybush",
|
"Greybush",
|
||||||
|
"Mark Corneglio",
|
||||||
"Ricky Carter",
|
"Ricky Carter",
|
||||||
"James Todd",
|
"James Todd",
|
||||||
"JongWon Han",
|
"Steven Pfeiffer",
|
||||||
"VantAI",
|
"VantAI",
|
||||||
"レプサイ",
|
"レプサイ",
|
||||||
|
"Lisster",
|
||||||
"Michael Wong",
|
"Michael Wong",
|
||||||
"runte3221",
|
"runte3221",
|
||||||
"Illrigger",
|
"Illrigger",
|
||||||
"Tom Corrigan",
|
"Tom Corrigan",
|
||||||
"JackieWang",
|
"JackieWang",
|
||||||
"FreelancerZ",
|
|
||||||
"fnkylove",
|
"fnkylove",
|
||||||
|
"Yushio",
|
||||||
"Vik71it",
|
"Vik71it",
|
||||||
"Echo",
|
"Echo",
|
||||||
"Lilleman",
|
"Lilleman",
|
||||||
@@ -65,50 +75,48 @@
|
|||||||
"Fraser Cross",
|
"Fraser Cross",
|
||||||
"Liam MacDougal",
|
"Liam MacDougal",
|
||||||
"Sterilized",
|
"Sterilized",
|
||||||
|
"BadassArabianMofo",
|
||||||
"JORGE+LUIZ+HUSSNI+MESSIAS",
|
"JORGE+LUIZ+HUSSNI+MESSIAS",
|
||||||
"quarz",
|
"quarz",
|
||||||
"Greg",
|
"Greg",
|
||||||
|
"jean jahren",
|
||||||
"JSST",
|
"JSST",
|
||||||
"Snaggwort",
|
"Snaggwort",
|
||||||
|
"lmsupporter",
|
||||||
"Takkan",
|
"Takkan",
|
||||||
"wfpearl",
|
"wfpearl",
|
||||||
"Matt+J",
|
"Matt+J",
|
||||||
"Baekdoosixt",
|
"Baekdoosixt",
|
||||||
"Jonathan Ross",
|
"Jonathan Ross",
|
||||||
"KD",
|
"Jack B Nimble",
|
||||||
"Omnidex",
|
|
||||||
"Nazono_hito",
|
"Nazono_hito",
|
||||||
"Melville Parrish",
|
"Melville Parrish",
|
||||||
"daniel dove",
|
"daniel dove",
|
||||||
"Lustre",
|
"Lustre",
|
||||||
"Tyler Trebuchon",
|
|
||||||
"Release Cabrakan",
|
|
||||||
"JW Sin",
|
"JW Sin",
|
||||||
"Alex",
|
"Alex",
|
||||||
"bh",
|
"bh",
|
||||||
"carozzz",
|
"carozzz",
|
||||||
"Marlon Daniels",
|
"Marlon Daniels",
|
||||||
"James Dooley",
|
"Starkselle",
|
||||||
"Buzzard",
|
|
||||||
"Aaron Bleuer",
|
"Aaron Bleuer",
|
||||||
"LacesOut!",
|
"LacesOut!",
|
||||||
|
"greebles",
|
||||||
"Adam Shaw",
|
"Adam Shaw",
|
||||||
"Mark Corneglio",
|
|
||||||
"SarcasticHashtag",
|
"SarcasticHashtag",
|
||||||
"Anthony Rizzo",
|
"Anthony Rizzo",
|
||||||
"iamresist",
|
"iamresist",
|
||||||
|
"M Postkasse",
|
||||||
"RedrockVP",
|
"RedrockVP",
|
||||||
"Wolffen",
|
"Wolffen",
|
||||||
"Wicked Choices by ASLPro3D",
|
"Wicked Choices by ASLPro3D",
|
||||||
"Jacob Hoehler",
|
"Jacob Hoehler",
|
||||||
"FinalyFree",
|
"FinalyFree",
|
||||||
"Weasyl",
|
"Weasyl",
|
||||||
"Steven Pfeiffer",
|
|
||||||
"Timmy",
|
"Timmy",
|
||||||
"Johnny",
|
"Johnny",
|
||||||
"Cory Paza",
|
"Cory Paza",
|
||||||
"Tak",
|
"Tak",
|
||||||
"Lisster",
|
|
||||||
"Big Red",
|
"Big Red",
|
||||||
"whudunit",
|
"whudunit",
|
||||||
"Luc Job",
|
"Luc Job",
|
||||||
@@ -116,37 +124,36 @@
|
|||||||
"Philip Hempel",
|
"Philip Hempel",
|
||||||
"corde",
|
"corde",
|
||||||
"nwalker94",
|
"nwalker94",
|
||||||
"Yushio",
|
|
||||||
"Bishoujoker",
|
"Bishoujoker",
|
||||||
|
"aai",
|
||||||
"Todd Keck",
|
"Todd Keck",
|
||||||
"Briton Heilbrun",
|
"Briton Heilbrun",
|
||||||
"Tori",
|
"Tori",
|
||||||
"wildnut",
|
"wildnut",
|
||||||
"Aleksander Wujczyk",
|
"Aleksander Wujczyk",
|
||||||
"AM Kuro",
|
"AM Kuro",
|
||||||
"BadassArabianMofo",
|
|
||||||
"Pascal Dahle",
|
"Pascal Dahle",
|
||||||
"Sangheili460",
|
"Sangheili460",
|
||||||
"MagnaInsomnia",
|
"MagnaInsomnia",
|
||||||
"Akira_HentAI",
|
"Akira_HentAI",
|
||||||
"Karl P.",
|
"Karl P.",
|
||||||
"lmsupporter",
|
|
||||||
"andrew.tappan",
|
"andrew.tappan",
|
||||||
"N/A",
|
"N/A",
|
||||||
|
"The Spawn",
|
||||||
"graysock",
|
"graysock",
|
||||||
"Greenmoustache",
|
"Greenmoustache",
|
||||||
"zounic",
|
"zounic",
|
||||||
"fancypants",
|
"fancypants",
|
||||||
"Eldithor",
|
"Digital",
|
||||||
"Jack B Nimble",
|
|
||||||
"JaxMax",
|
"JaxMax",
|
||||||
"contrite831",
|
"contrite831",
|
||||||
"Jwk0205",
|
"Jwk0205",
|
||||||
"Starkselle",
|
"Bro Xie",
|
||||||
|
"batblue",
|
||||||
|
"carey6409",
|
||||||
"Olive",
|
"Olive",
|
||||||
"greebles",
|
"太郎 ゲーム",
|
||||||
"Some Guy Named Barry",
|
"Some Guy Named Barry",
|
||||||
"M Postkasse",
|
|
||||||
"AELOX",
|
"AELOX",
|
||||||
"Gooohokrbe",
|
"Gooohokrbe",
|
||||||
"Nicfit23",
|
"Nicfit23",
|
||||||
@@ -162,12 +169,12 @@
|
|||||||
"Serge Bekenkamp",
|
"Serge Bekenkamp",
|
||||||
"Jimmy Ledbetter",
|
"Jimmy Ledbetter",
|
||||||
"LeoZero",
|
"LeoZero",
|
||||||
|
"Antonio Pontes",
|
||||||
|
"nahinahi9",
|
||||||
"Dustin Chen",
|
"Dustin Chen",
|
||||||
"dan",
|
"dan",
|
||||||
"aai",
|
|
||||||
"Mouthlessman",
|
"Mouthlessman",
|
||||||
"otaku fra",
|
"otaku fra",
|
||||||
"jean jahren",
|
|
||||||
"MiraiKuriyamaSy",
|
"MiraiKuriyamaSy",
|
||||||
"Ran C",
|
"Ran C",
|
||||||
"ViperC",
|
"ViperC",
|
||||||
@@ -176,7 +183,6 @@
|
|||||||
"Adam Taylor",
|
"Adam Taylor",
|
||||||
"AbstractAss",
|
"AbstractAss",
|
||||||
"Weird_With_A_Beard",
|
"Weird_With_A_Beard",
|
||||||
"The Spawn",
|
|
||||||
"Pozadine1",
|
"Pozadine1",
|
||||||
"Qarob",
|
"Qarob",
|
||||||
"AIGooner",
|
"AIGooner",
|
||||||
@@ -187,18 +193,16 @@
|
|||||||
"Hasturkun",
|
"Hasturkun",
|
||||||
"Jon Sandman",
|
"Jon Sandman",
|
||||||
"Ubivis",
|
"Ubivis",
|
||||||
|
"CloudValley",
|
||||||
|
"linnfrey",
|
||||||
"Jackthemind",
|
"Jackthemind",
|
||||||
|
"griffin+dahlberg",
|
||||||
"Joboshy",
|
"Joboshy",
|
||||||
"Digital",
|
|
||||||
"takyamtom",
|
"takyamtom",
|
||||||
"Bohemian Corporal",
|
"Bohemian Corporal",
|
||||||
"Dan",
|
"Dan",
|
||||||
"Bro Xie",
|
|
||||||
"yer fey",
|
"yer fey",
|
||||||
"batblue",
|
|
||||||
"Error_Rule34_Not_found",
|
"Error_Rule34_Not_found",
|
||||||
"carey6409",
|
|
||||||
"太郎 ゲーム",
|
|
||||||
"Roslynd",
|
"Roslynd",
|
||||||
"jinxedx",
|
"jinxedx",
|
||||||
"Neco28",
|
"Neco28",
|
||||||
@@ -210,22 +214,21 @@
|
|||||||
"Frank Nitty",
|
"Frank Nitty",
|
||||||
"Magic Noob",
|
"Magic Noob",
|
||||||
"DougPeterson",
|
"DougPeterson",
|
||||||
"Antonio Pontes",
|
|
||||||
"ApathyJones",
|
"ApathyJones",
|
||||||
|
"Jeff",
|
||||||
"Bruce",
|
"Bruce",
|
||||||
"Julian V",
|
|
||||||
"Steven Owens",
|
"Steven Owens",
|
||||||
"nahinahi9",
|
|
||||||
"Kevin John Duck",
|
"Kevin John Duck",
|
||||||
"Kevin Christopher",
|
"Kevin Christopher",
|
||||||
"Blackfish95",
|
"Blackfish95",
|
||||||
|
"dd",
|
||||||
"Paul Kroll",
|
"Paul Kroll",
|
||||||
"Bas Imagineer",
|
"Bas Imagineer",
|
||||||
"John Statham",
|
"John Statham",
|
||||||
"yuxz69",
|
"yuxz69",
|
||||||
"esthe",
|
"esthe",
|
||||||
|
"AlexDuKaNa",
|
||||||
"decoy",
|
"decoy",
|
||||||
"CloudValley",
|
|
||||||
"thesoftwaredruid",
|
"thesoftwaredruid",
|
||||||
"wundershark",
|
"wundershark",
|
||||||
"mr_dinosaur",
|
"mr_dinosaur",
|
||||||
@@ -233,15 +236,20 @@
|
|||||||
"Ray Wing",
|
"Ray Wing",
|
||||||
"Ranzitho",
|
"Ranzitho",
|
||||||
"Gus",
|
"Gus",
|
||||||
|
"地獄の禄",
|
||||||
"MJG",
|
"MJG",
|
||||||
"David LaVallee",
|
"David LaVallee",
|
||||||
"linnfrey",
|
|
||||||
"ae",
|
"ae",
|
||||||
"Tr4shP4nda",
|
"Tr4shP4nda",
|
||||||
"capn",
|
"capn",
|
||||||
"Joseph",
|
"Joseph",
|
||||||
|
"Mirko Katzula",
|
||||||
|
"dan",
|
||||||
|
"Piccio08",
|
||||||
|
"kumakichi",
|
||||||
|
"cppbel",
|
||||||
"IamAyam",
|
"IamAyam",
|
||||||
"skaterb949",
|
"jeaness",
|
||||||
"Brian M",
|
"Brian M",
|
||||||
"Josef Lanzl",
|
"Josef Lanzl",
|
||||||
"Nerezza",
|
"Nerezza",
|
||||||
@@ -261,37 +269,32 @@
|
|||||||
"Eris3D",
|
"Eris3D",
|
||||||
"Max Marklund",
|
"Max Marklund",
|
||||||
"m",
|
"m",
|
||||||
|
"Pierce McBride",
|
||||||
"Pronredn",
|
"Pronredn",
|
||||||
|
"Mikko Hemilä",
|
||||||
"Jamie Ogletree",
|
"Jamie Ogletree",
|
||||||
"a _",
|
"a _",
|
||||||
"Jeff",
|
|
||||||
"lh qwe",
|
"lh qwe",
|
||||||
"James Coleman",
|
"James Coleman",
|
||||||
|
"Martial",
|
||||||
"conner",
|
"conner",
|
||||||
"Ouro Boros",
|
"Ouro Boros",
|
||||||
"Chad Idk",
|
"Chad Idk",
|
||||||
"dd",
|
|
||||||
"Princess Bright Eyes",
|
"Princess Bright Eyes",
|
||||||
"Yuji Kaneko",
|
"Yuji Kaneko",
|
||||||
"Dušan Ryban",
|
"Dušan Ryban",
|
||||||
"Felipe dos Santos",
|
"Felipe dos Santos",
|
||||||
|
"Rops Alot",
|
||||||
"Sam",
|
"Sam",
|
||||||
"sjon kreutz",
|
"sjon kreutz",
|
||||||
"Ace Ventura",
|
"Ace Ventura",
|
||||||
"Douglas Gaspar",
|
"Douglas Gaspar",
|
||||||
"Metryman55",
|
"Metryman55",
|
||||||
"AlexDuKaNa",
|
|
||||||
"George",
|
"George",
|
||||||
"dw",
|
"dw",
|
||||||
"地獄の禄",
|
|
||||||
"Gamalonia",
|
"Gamalonia",
|
||||||
"WRL_SPR",
|
"WRL_SPR",
|
||||||
"momokai",
|
"momokai",
|
||||||
"Mirko Katzula",
|
|
||||||
"dan",
|
|
||||||
"Piccio08",
|
|
||||||
"kumakichi",
|
|
||||||
"cppbel",
|
|
||||||
"Moon Knight",
|
"Moon Knight",
|
||||||
"몽타주",
|
"몽타주",
|
||||||
"Kland",
|
"Kland",
|
||||||
@@ -313,12 +316,15 @@
|
|||||||
"kyoumei",
|
"kyoumei",
|
||||||
"RadStorm04",
|
"RadStorm04",
|
||||||
"JohnDoe42054",
|
"JohnDoe42054",
|
||||||
|
"BillyHill",
|
||||||
|
"emyth",
|
||||||
"gzmzmvp",
|
"gzmzmvp",
|
||||||
"Richard",
|
"Richard",
|
||||||
"奚明 刘",
|
"奚明 刘",
|
||||||
"Andrew",
|
"Andrew",
|
||||||
"Robert Wegemund",
|
"Robert Wegemund",
|
||||||
"Littlehuggy",
|
"Littlehuggy",
|
||||||
|
"Gregory Kozhemiak",
|
||||||
"준희 김",
|
"준희 김",
|
||||||
"Brian Buie",
|
"Brian Buie",
|
||||||
"Sadlip",
|
"Sadlip",
|
||||||
@@ -328,16 +334,16 @@
|
|||||||
"Tomohiro Baba",
|
"Tomohiro Baba",
|
||||||
"Mike Simone",
|
"Mike Simone",
|
||||||
"Noora",
|
"Noora",
|
||||||
"Pierce McBride",
|
|
||||||
"Joshua Gray",
|
"Joshua Gray",
|
||||||
"Mattssn",
|
"Mattssn",
|
||||||
"Mikko Hemilä",
|
"Morgandel",
|
||||||
"Jacob McDaniel",
|
"Jacob McDaniel",
|
||||||
|
"X",
|
||||||
|
"Sloan Steddy",
|
||||||
"Temikus",
|
"Temikus",
|
||||||
"Artokun",
|
"Artokun",
|
||||||
"Michael Taylor",
|
"Michael Taylor",
|
||||||
"Derek Baker",
|
"Derek Baker",
|
||||||
"Martial",
|
|
||||||
"Michael Anthony Scott",
|
"Michael Anthony Scott",
|
||||||
"Emil Andersson",
|
"Emil Andersson",
|
||||||
"Atilla Berke Pekduyar",
|
"Atilla Berke Pekduyar",
|
||||||
@@ -345,7 +351,6 @@
|
|||||||
"CryptoTraderJK",
|
"CryptoTraderJK",
|
||||||
"Decx _",
|
"Decx _",
|
||||||
"Davaitamin",
|
"Davaitamin",
|
||||||
"Rops Alot",
|
|
||||||
"tedcor",
|
"tedcor",
|
||||||
"Fotek Design",
|
"Fotek Design",
|
||||||
"四糸凜音",
|
"四糸凜音",
|
||||||
@@ -358,8 +363,6 @@
|
|||||||
"starbugx",
|
"starbugx",
|
||||||
"dc7431",
|
"dc7431",
|
||||||
"Crocket",
|
"Crocket",
|
||||||
"BillyHill",
|
|
||||||
"emyth",
|
|
||||||
"chriphost",
|
"chriphost",
|
||||||
"KitKatM",
|
"KitKatM",
|
||||||
"socrasteeze",
|
"socrasteeze",
|
||||||
@@ -383,35 +386,40 @@
|
|||||||
"g9p0o",
|
"g9p0o",
|
||||||
"TheHolySheep",
|
"TheHolySheep",
|
||||||
"Monte Won",
|
"Monte Won",
|
||||||
"Gregory Kozhemiak",
|
"SpringBootisTrash",
|
||||||
|
"carsten",
|
||||||
|
"ikok",
|
||||||
|
"Wolfe7D1",
|
||||||
"Draven T",
|
"Draven T",
|
||||||
"mrjuan",
|
|
||||||
"elleshar666",
|
"elleshar666",
|
||||||
|
"ACTUALLY_the_Real_Willem_Dafoe",
|
||||||
"Aquatic Coffee",
|
"Aquatic Coffee",
|
||||||
|
"Kauffy",
|
||||||
"John J Linehan",
|
"John J Linehan",
|
||||||
"ethanfel",
|
"ethanfel",
|
||||||
"Elliot E",
|
"Elliot E",
|
||||||
"Morgandel",
|
|
||||||
"Theerat Jiramate",
|
"Theerat Jiramate",
|
||||||
"Focuschannel",
|
"Focuschannel",
|
||||||
"Edward Kennedy",
|
"Edward Kennedy",
|
||||||
"Noah",
|
"Noah",
|
||||||
"X",
|
|
||||||
"Sloan Steddy",
|
|
||||||
"Vane Holzer",
|
"Vane Holzer",
|
||||||
|
"psytrax",
|
||||||
"hexxish",
|
"hexxish",
|
||||||
"Anthony Faxlandez",
|
"Anthony Faxlandez",
|
||||||
"battu",
|
"battu",
|
||||||
"notedfakes",
|
"notedfakes",
|
||||||
"Nathan",
|
"Nathan",
|
||||||
"NICHOLAS BAXLEY",
|
"NICHOLAS BAXLEY",
|
||||||
|
"Michael Scott",
|
||||||
"Pat Hen",
|
"Pat Hen",
|
||||||
"Xeeosat",
|
"Xeeosat",
|
||||||
"Saya",
|
"Saya",
|
||||||
"Ed Wang",
|
"Ed Wang",
|
||||||
"Jordan Shaw",
|
"Jordan Shaw",
|
||||||
|
"Wes Sims",
|
||||||
"g unit",
|
"g unit",
|
||||||
"Srdb",
|
"Srdb",
|
||||||
|
"Filippo Ferrari",
|
||||||
"JC",
|
"JC",
|
||||||
"Prompt Pirate",
|
"Prompt Pirate",
|
||||||
"uwutismxd",
|
"uwutismxd",
|
||||||
@@ -427,9 +435,8 @@
|
|||||||
"Pkrsky",
|
"Pkrsky",
|
||||||
"nanana",
|
"nanana",
|
||||||
"raf8osz",
|
"raf8osz",
|
||||||
"SpringBootisTrash",
|
"FeralOpticsAI",
|
||||||
"carsten",
|
"Pavlaki",
|
||||||
"ikok",
|
|
||||||
"Doug+Rintoul",
|
"Doug+Rintoul",
|
||||||
"Noor",
|
"Noor",
|
||||||
"Yorunai",
|
"Yorunai",
|
||||||
@@ -446,36 +453,34 @@
|
|||||||
"cocona",
|
"cocona",
|
||||||
"ElitaSSJ4",
|
"ElitaSSJ4",
|
||||||
"David Schenck",
|
"David Schenck",
|
||||||
"Wolfe7D1",
|
|
||||||
"blikkies",
|
"blikkies",
|
||||||
"Chris",
|
"Chris",
|
||||||
"Time Valentine",
|
"Time Valentine",
|
||||||
"Shock Shockor",
|
"Shock Shockor",
|
||||||
"ACTUALLY_the_Real_Willem_Dafoe",
|
|
||||||
"Михал Михалыч",
|
"Михал Михалыч",
|
||||||
"Matt",
|
"Matt",
|
||||||
"Goldwaters",
|
"Goldwaters",
|
||||||
"Kauffy",
|
|
||||||
"Zude",
|
"Zude",
|
||||||
|
"Frogmilk",
|
||||||
"SPJ",
|
"SPJ",
|
||||||
"Kyler",
|
"Kyler",
|
||||||
|
"Bryan Rutkowski",
|
||||||
"Justin Blaylock",
|
"Justin Blaylock",
|
||||||
"aRtFuL_DodGeR",
|
"aRtFuL_DodGeR",
|
||||||
"Nick Kage",
|
"Nick Kage",
|
||||||
"psytrax",
|
|
||||||
"Cyrus Fett",
|
"Cyrus Fett",
|
||||||
"Xenon Xue",
|
"Xenon Xue",
|
||||||
"Edward Ten Eyck",
|
"Edward Ten Eyck",
|
||||||
"Billy Gladky",
|
"Billy Gladky",
|
||||||
"Michael Scott",
|
|
||||||
"Probis",
|
"Probis",
|
||||||
"Solixer",
|
"Solixer",
|
||||||
"Wes Sims",
|
|
||||||
"ItsGeneralButtNaked",
|
"ItsGeneralButtNaked",
|
||||||
"Donor4115",
|
"Donor4115",
|
||||||
|
"jinksta187",
|
||||||
"Distortik",
|
"Distortik",
|
||||||
"Manu Thetug",
|
"Manu Thetug",
|
||||||
"Filippo Ferrari",
|
"Karlanx",
|
||||||
|
"operationancut",
|
||||||
"Youguang",
|
"Youguang",
|
||||||
"andrewzpong",
|
"andrewzpong",
|
||||||
"BossGame",
|
"BossGame",
|
||||||
@@ -486,11 +491,18 @@
|
|||||||
"Kevinj",
|
"Kevinj",
|
||||||
"Mitchell Robson",
|
"Mitchell Robson",
|
||||||
"POPPIN",
|
"POPPIN",
|
||||||
|
"YassineKhaled",
|
||||||
|
"Y",
|
||||||
|
"MatteKey",
|
||||||
|
"Flob",
|
||||||
|
"ShiroSenpai",
|
||||||
|
"Inkognito",
|
||||||
"G",
|
"G",
|
||||||
"Tan+Huynh",
|
"Tan+Huynh",
|
||||||
"Bob+Barker",
|
"Bob+Barker",
|
||||||
"D",
|
"D",
|
||||||
"Dark_Pest",
|
"Dark_Pest",
|
||||||
|
"Eldithor",
|
||||||
"Alex",
|
"Alex",
|
||||||
"Karru",
|
"Karru",
|
||||||
"ChaChanoKo",
|
"ChaChanoKo",
|
||||||
@@ -503,13 +515,10 @@
|
|||||||
"g",
|
"g",
|
||||||
"J",
|
"J",
|
||||||
"Alan+Cano",
|
"Alan+Cano",
|
||||||
"FeralOpticsAI",
|
|
||||||
"Pavlaki",
|
|
||||||
"BillyBoy84",
|
"BillyBoy84",
|
||||||
"Buecyb99",
|
"Buecyb99",
|
||||||
"Welkor",
|
"Welkor",
|
||||||
"John Martin",
|
"John Martin",
|
||||||
"Ink Temptation",
|
|
||||||
"JBsuede",
|
"JBsuede",
|
||||||
"moranqianlong",
|
"moranqianlong",
|
||||||
"Kalli Core",
|
"Kalli Core",
|
||||||
@@ -519,13 +528,12 @@
|
|||||||
"Dave Abraham",
|
"Dave Abraham",
|
||||||
"Joaquin Hierrezuelo",
|
"Joaquin Hierrezuelo",
|
||||||
"Locrospiel",
|
"Locrospiel",
|
||||||
"Frogmilk",
|
|
||||||
"Sean voets",
|
"Sean voets",
|
||||||
|
"Jarrid Lee",
|
||||||
"Kor",
|
"Kor",
|
||||||
"Joseph Hanson",
|
"Joseph Hanson",
|
||||||
"John Rednoulf",
|
"John Rednoulf",
|
||||||
"Kyron Mahan",
|
"Kyron Mahan",
|
||||||
"Bryan Rutkowski",
|
|
||||||
"Boba Smith",
|
"Boba Smith",
|
||||||
"TBitz33",
|
"TBitz33",
|
||||||
"Anonym dkjglfleeoeldldldlkf",
|
"Anonym dkjglfleeoeldldldlkf",
|
||||||
@@ -544,15 +552,12 @@
|
|||||||
"Pete Pain",
|
"Pete Pain",
|
||||||
"Jacob Winter",
|
"Jacob Winter",
|
||||||
"Ryan Presley Ng",
|
"Ryan Presley Ng",
|
||||||
"jinksta187",
|
|
||||||
"RHopkirk",
|
"RHopkirk",
|
||||||
"Andrew Wilkinson",
|
"Andrew Wilkinson",
|
||||||
"Karlanx",
|
|
||||||
"Lyavph",
|
"Lyavph",
|
||||||
"Maxim",
|
"Maxim",
|
||||||
"David",
|
"David",
|
||||||
"Meilo",
|
"Meilo",
|
||||||
"operationancut",
|
|
||||||
"shinonomeiro",
|
"shinonomeiro",
|
||||||
"Snille",
|
"Snille",
|
||||||
"MaartenAlbers",
|
"MaartenAlbers",
|
||||||
@@ -571,6 +576,8 @@
|
|||||||
"Scott",
|
"Scott",
|
||||||
"Muratoraccio",
|
"Muratoraccio",
|
||||||
"D",
|
"D",
|
||||||
|
"Akkas+Haque",
|
||||||
|
"Kachac",
|
||||||
"SAVEagleBasement",
|
"SAVEagleBasement",
|
||||||
"Kevin+Isom",
|
"Kevin+Isom",
|
||||||
"Rune+Osnes",
|
"Rune+Osnes",
|
||||||
@@ -600,12 +607,6 @@
|
|||||||
"Lev+Lanevskiy",
|
"Lev+Lanevskiy",
|
||||||
"low9",
|
"low9",
|
||||||
"Winged",
|
"Winged",
|
||||||
"YassineKhaled",
|
|
||||||
"Y",
|
|
||||||
"MatteKey",
|
|
||||||
"Flob",
|
|
||||||
"ShiroSenpai",
|
|
||||||
"Inkognito",
|
|
||||||
"Jacky+Ho",
|
"Jacky+Ho",
|
||||||
"generic404",
|
"generic404",
|
||||||
"abattoirblues",
|
"abattoirblues",
|
||||||
@@ -614,29 +615,34 @@
|
|||||||
"hayden",
|
"hayden",
|
||||||
"Obsidian.Studios",
|
"Obsidian.Studios",
|
||||||
"ahoystan",
|
"ahoystan",
|
||||||
|
"Zomba Mann",
|
||||||
"edk",
|
"edk",
|
||||||
"Tú Nguyễn Lý Hoàng",
|
"Tú Nguyễn Lý Hoàng",
|
||||||
"shira1011",
|
"shira1011",
|
||||||
|
"Neko Desco",
|
||||||
"Ben D",
|
"Ben D",
|
||||||
"G",
|
"G",
|
||||||
|
"Vinarus",
|
||||||
"ja s",
|
"ja s",
|
||||||
"Leslie Andrew Ridings",
|
"Leslie Andrew Ridings",
|
||||||
"Doug Mason",
|
"Doug Mason",
|
||||||
"scoreswazey",
|
"scoreswazey",
|
||||||
"Owen Gwosdz",
|
"Owen Gwosdz",
|
||||||
"Jarrid Lee",
|
|
||||||
"Poophead27 Blyat",
|
"Poophead27 Blyat",
|
||||||
"Mythspire",
|
"Mythspire",
|
||||||
"AZ Party Oasis",
|
"AZ Party Oasis",
|
||||||
"Devil Lude",
|
"Devil Lude",
|
||||||
"David Murcko",
|
"David Murcko",
|
||||||
|
"TheFusion",
|
||||||
"MR.Bear",
|
"MR.Bear",
|
||||||
"Jack Dole",
|
"Jack Dole",
|
||||||
"matt",
|
"matt",
|
||||||
"somethingtosay8",
|
"somethingtosay8",
|
||||||
|
"3zS4QNQ4",
|
||||||
"Terminuz",
|
"Terminuz",
|
||||||
"ivistorm",
|
"ivistorm",
|
||||||
"max blo",
|
"max blo",
|
||||||
|
"Ivan Imes",
|
||||||
"CptNeo",
|
"CptNeo",
|
||||||
"Jack Lawfield",
|
"Jack Lawfield",
|
||||||
"Borte",
|
"Borte",
|
||||||
@@ -645,7 +651,7 @@
|
|||||||
"Sage Himeros",
|
"Sage Himeros",
|
||||||
"Eric Ketchum",
|
"Eric Ketchum",
|
||||||
"Kevin Wallace",
|
"Kevin Wallace",
|
||||||
"David Spearing",
|
"Zeeble",
|
||||||
"ChicRic",
|
"ChicRic",
|
||||||
"Tigon",
|
"Tigon",
|
||||||
"BastardSama",
|
"BastardSama",
|
||||||
@@ -706,6 +712,9 @@
|
|||||||
"SelfishMedic",
|
"SelfishMedic",
|
||||||
"adderleighn",
|
"adderleighn",
|
||||||
"EnragedAntelope",
|
"EnragedAntelope",
|
||||||
|
"Somebody",
|
||||||
|
"Jasper",
|
||||||
|
"megameganck",
|
||||||
"thomasand01",
|
"thomasand01",
|
||||||
"Shiba+Sama",
|
"Shiba+Sama",
|
||||||
"miduzza",
|
"miduzza",
|
||||||
@@ -730,8 +739,6 @@
|
|||||||
"matter",
|
"matter",
|
||||||
"SRCRCOSS",
|
"SRCRCOSS",
|
||||||
"imer",
|
"imer",
|
||||||
"Akkas+Haque",
|
|
||||||
"Kachac",
|
|
||||||
"jcx29",
|
"jcx29",
|
||||||
"Drizzly",
|
"Drizzly",
|
||||||
"Nebuleux",
|
"Nebuleux",
|
||||||
@@ -751,24 +758,23 @@
|
|||||||
"KUJYAKU",
|
"KUJYAKU",
|
||||||
"Coeur+de+cochon",
|
"Coeur+de+cochon",
|
||||||
"han b",
|
"han b",
|
||||||
"Zomba Mann",
|
|
||||||
"Aquaneo",
|
"Aquaneo",
|
||||||
"Nico",
|
"Nico",
|
||||||
"Maximilian Krischan",
|
"Maximilian Krischan",
|
||||||
"Banana Joe",
|
"Banana Joe",
|
||||||
"proto merp",
|
"proto merp",
|
||||||
"_ G3n",
|
"_ G3n",
|
||||||
|
"Brandon Thomas",
|
||||||
"Donovan Jenkins",
|
"Donovan Jenkins",
|
||||||
"Hans Meier",
|
"Hans Meier",
|
||||||
"sicarius",
|
"sicarius",
|
||||||
"Michael Eid",
|
"Michael Eid",
|
||||||
"Wolf and Fox Legends",
|
"Wolf and Fox Legends",
|
||||||
"beersandbacon",
|
"beersandbacon",
|
||||||
"Neko Desco",
|
|
||||||
"Bob barker",
|
"Bob barker",
|
||||||
"Ninja Tom",
|
"Ninja Tom",
|
||||||
"karim ben brik",
|
"karim ben brik",
|
||||||
"Vinarus",
|
"Elemnt",
|
||||||
"Josh Snyder",
|
"Josh Snyder",
|
||||||
"Michael Zhu",
|
"Michael Zhu",
|
||||||
"Nemisu",
|
"Nemisu",
|
||||||
@@ -792,16 +798,15 @@
|
|||||||
"Forbidden Atelier",
|
"Forbidden Atelier",
|
||||||
"Thomas Sankowski",
|
"Thomas Sankowski",
|
||||||
"DrB",
|
"DrB",
|
||||||
|
"Nimhloth",
|
||||||
"Adictedtohumping",
|
"Adictedtohumping",
|
||||||
"Snorklebort",
|
"Snorklebort",
|
||||||
"vinter",
|
"vinter",
|
||||||
"Towelie",
|
"Towelie",
|
||||||
"TheFusion",
|
|
||||||
"Jean-françois SEMA",
|
"Jean-françois SEMA",
|
||||||
"3zS4QNQ4",
|
|
||||||
"Kurt",
|
"Kurt",
|
||||||
|
"Andrew Ly",
|
||||||
"Matt M.",
|
"Matt M.",
|
||||||
"Ivan Imes",
|
|
||||||
"J M",
|
"J M",
|
||||||
"Slacks",
|
"Slacks",
|
||||||
"Bouya shaka",
|
"Bouya shaka",
|
||||||
@@ -837,5 +842,5 @@
|
|||||||
"Somebody",
|
"Somebody",
|
||||||
"CK"
|
"CK"
|
||||||
],
|
],
|
||||||
"totalCount": 834
|
"totalCount": 839
|
||||||
}
|
}
|
||||||
@@ -414,9 +414,10 @@ class PromptServerProtocol(Protocol):
|
|||||||
"""Subset of PromptServer used by the handlers."""
|
"""Subset of PromptServer used by the handlers."""
|
||||||
|
|
||||||
instance: "PromptServerProtocol"
|
instance: "PromptServerProtocol"
|
||||||
|
sockets: dict # maps clientId (sid) → WebSocketResponse
|
||||||
|
|
||||||
def send_sync(
|
def send_sync(
|
||||||
self, event: str, payload: dict
|
self, event: str, payload: dict | None = None, sid: str | None = None
|
||||||
) -> None: # pragma: no cover - protocol
|
) -> None: # pragma: no cover - protocol
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -471,90 +472,154 @@ class BackupServiceProtocol(Protocol):
|
|||||||
|
|
||||||
|
|
||||||
class NodeRegistry:
|
class NodeRegistry:
|
||||||
"""Thread-safe registry for tracking LoRA nodes in active workflows."""
|
"""Thread-safe registry for tracking LoRA nodes across ComfyUI tabs.
|
||||||
|
|
||||||
|
Each connected ComfyUI browser tab (identified by its ``sid`` / ``clientId``)
|
||||||
|
registers its own set of workflow nodes. Queries merge all known tabs into
|
||||||
|
a single result so that the calling LM panel always sees *every* available
|
||||||
|
target node, regardless of which tab responded fastest.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._lock = asyncio.Lock()
|
self._lock = asyncio.Lock()
|
||||||
self._nodes: Dict[str, dict] = {}
|
# sid → {unique_id → node_info}
|
||||||
self._registry_updated = asyncio.Event()
|
self._tab_nodes: Dict[str, Dict[str, dict]] = {}
|
||||||
|
self._ready = asyncio.Event()
|
||||||
|
self._waiting_clients: set[str] = set()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pending_client_count(self) -> int:
|
||||||
|
"""Number of clients that have not yet responded in the current refresh cycle."""
|
||||||
|
return len(self._waiting_clients)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Helpers to build one node dict (extracted so it's reused for each tab)
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def _build_node_dict(node: dict) -> dict:
|
||||||
|
node_id = node["node_id"]
|
||||||
|
graph_id = str(node["graph_id"])
|
||||||
|
unique_id = f"{graph_id}:{node_id}"
|
||||||
|
node_type = node.get("type", "")
|
||||||
|
type_id = NODE_TYPES.get(node_type, 0)
|
||||||
|
bgcolor = node.get("bgcolor") or DEFAULT_NODE_COLOR
|
||||||
|
|
||||||
|
raw_capabilities = node.get("capabilities")
|
||||||
|
capabilities: dict = {}
|
||||||
|
if isinstance(raw_capabilities, dict):
|
||||||
|
capabilities = dict(raw_capabilities)
|
||||||
|
|
||||||
|
raw_widget_names: list | None = node.get("widget_names")
|
||||||
|
if not isinstance(raw_widget_names, list):
|
||||||
|
capability_widget_names = capabilities.get("widget_names")
|
||||||
|
raw_widget_names = (
|
||||||
|
capability_widget_names
|
||||||
|
if isinstance(capability_widget_names, list)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
widget_names: list[str] = []
|
||||||
|
if isinstance(raw_widget_names, list):
|
||||||
|
widget_names = [
|
||||||
|
str(widget_name)
|
||||||
|
for widget_name in raw_widget_names
|
||||||
|
if isinstance(widget_name, str) and widget_name
|
||||||
|
]
|
||||||
|
|
||||||
|
if widget_names:
|
||||||
|
capabilities["widget_names"] = widget_names
|
||||||
|
else:
|
||||||
|
capabilities.pop("widget_names", None)
|
||||||
|
|
||||||
|
if "supports_lora" in capabilities:
|
||||||
|
capabilities["supports_lora"] = bool(capabilities["supports_lora"])
|
||||||
|
|
||||||
|
comfy_class = node.get("comfy_class")
|
||||||
|
if not isinstance(comfy_class, str) or not comfy_class:
|
||||||
|
comfy_class = node_type if isinstance(node_type, str) else None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"id": node_id,
|
||||||
|
"graph_id": graph_id,
|
||||||
|
"graph_name": node.get("graph_name"),
|
||||||
|
"unique_id": unique_id,
|
||||||
|
"bgcolor": bgcolor,
|
||||||
|
"title": node.get("title"),
|
||||||
|
"type": type_id,
|
||||||
|
"type_name": node_type,
|
||||||
|
"comfy_class": comfy_class,
|
||||||
|
"capabilities": capabilities,
|
||||||
|
"widget_names": widget_names,
|
||||||
|
"mode": node.get("mode"),
|
||||||
|
"marker_role": node.get("marker_role"),
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Public API
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
async def register_nodes(self, sid: str, nodes: list[dict]) -> None:
|
||||||
|
"""Register/replace the node list for a single ComfyUI tab (identified by *sid*)."""
|
||||||
|
tab_nodes: dict[str, dict] = {}
|
||||||
|
for node in nodes:
|
||||||
|
nd = self._build_node_dict(node)
|
||||||
|
tab_nodes[nd["unique_id"]] = nd
|
||||||
|
|
||||||
async def register_nodes(self, nodes: list[dict]) -> None:
|
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
self._nodes.clear()
|
self._tab_nodes[sid] = tab_nodes
|
||||||
for node in nodes:
|
self._waiting_clients.discard(sid)
|
||||||
node_id = node["node_id"]
|
if not self._waiting_clients:
|
||||||
graph_id = str(node["graph_id"])
|
self._ready.set()
|
||||||
unique_id = f"{graph_id}:{node_id}"
|
|
||||||
node_type = node.get("type", "")
|
|
||||||
type_id = NODE_TYPES.get(node_type, 0)
|
|
||||||
bgcolor = node.get("bgcolor") or DEFAULT_NODE_COLOR
|
|
||||||
raw_capabilities = node.get("capabilities")
|
|
||||||
capabilities: dict = {}
|
|
||||||
if isinstance(raw_capabilities, dict):
|
|
||||||
capabilities = dict(raw_capabilities)
|
|
||||||
|
|
||||||
raw_widget_names: list | None = node.get("widget_names")
|
logger.debug("Registered %s nodes from client %s", len(nodes), sid)
|
||||||
if not isinstance(raw_widget_names, list):
|
|
||||||
capability_widget_names = capabilities.get("widget_names")
|
|
||||||
raw_widget_names = (
|
|
||||||
capability_widget_names
|
|
||||||
if isinstance(capability_widget_names, list)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
widget_names: list[str] = []
|
def prepare_for_refresh(self, active_sids: list[str]) -> None:
|
||||||
if isinstance(raw_widget_names, list):
|
"""Set the list of client IDs we expect to hear from during the next refresh cycle."""
|
||||||
widget_names = [
|
self._ready.clear()
|
||||||
str(widget_name)
|
self._waiting_clients = set(active_sids)
|
||||||
for widget_name in raw_widget_names
|
|
||||||
if isinstance(widget_name, str) and widget_name
|
|
||||||
]
|
|
||||||
|
|
||||||
if widget_names:
|
async def wait_for_all(self, timeout: float = 2.0) -> bool:
|
||||||
capabilities["widget_names"] = widget_names
|
"""Block until every client in the current waiting set has responded
|
||||||
else:
|
(or *timeout* seconds elapse). Returns ``True`` if all responded."""
|
||||||
capabilities.pop("widget_names", None)
|
if not self._waiting_clients:
|
||||||
|
return True
|
||||||
if "supports_lora" in capabilities:
|
|
||||||
capabilities["supports_lora"] = bool(capabilities["supports_lora"])
|
|
||||||
|
|
||||||
comfy_class = node.get("comfy_class")
|
|
||||||
if not isinstance(comfy_class, str) or not comfy_class:
|
|
||||||
comfy_class = node_type if isinstance(node_type, str) else None
|
|
||||||
|
|
||||||
self._nodes[unique_id] = {
|
|
||||||
"id": node_id,
|
|
||||||
"graph_id": graph_id,
|
|
||||||
"graph_name": node.get("graph_name"),
|
|
||||||
"unique_id": unique_id,
|
|
||||||
"bgcolor": bgcolor,
|
|
||||||
"title": node.get("title"),
|
|
||||||
"type": type_id,
|
|
||||||
"type_name": node_type,
|
|
||||||
"comfy_class": comfy_class,
|
|
||||||
"capabilities": capabilities,
|
|
||||||
"widget_names": widget_names,
|
|
||||||
"mode": node.get("mode"),
|
|
||||||
"marker_role": node.get("marker_role"),
|
|
||||||
}
|
|
||||||
logger.debug("Registered %s nodes in registry", len(nodes))
|
|
||||||
self._registry_updated.set()
|
|
||||||
|
|
||||||
async def get_registry(self) -> dict:
|
|
||||||
async with self._lock:
|
|
||||||
return {
|
|
||||||
"nodes": dict(self._nodes),
|
|
||||||
"node_count": len(self._nodes),
|
|
||||||
}
|
|
||||||
|
|
||||||
async def wait_for_update(self, timeout: float = 1.0) -> bool:
|
|
||||||
self._registry_updated.clear()
|
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self._registry_updated.wait(), timeout=timeout)
|
await asyncio.wait_for(self._ready.wait(), timeout=timeout)
|
||||||
return True
|
return True
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def get_merged_registry(self, active_sids: set[str] | None = None) -> dict:
|
||||||
|
"""Return the union of all known tab nodes, pruning any tab that is no
|
||||||
|
longer connected."""
|
||||||
|
async with self._lock:
|
||||||
|
# Garbage-collect stale entries (disconnected tabs)
|
||||||
|
if active_sids is not None:
|
||||||
|
for sid in list(self._tab_nodes):
|
||||||
|
if sid not in active_sids:
|
||||||
|
del self._tab_nodes[sid]
|
||||||
|
|
||||||
|
merged: dict[str, dict] = {}
|
||||||
|
tab_info: dict[str, dict] = {}
|
||||||
|
for sid, nodes in self._tab_nodes.items():
|
||||||
|
tab_info[sid] = {
|
||||||
|
"node_count": len(nodes),
|
||||||
|
"graph_names": list(
|
||||||
|
{
|
||||||
|
n.get("graph_name")
|
||||||
|
for n in nodes.values()
|
||||||
|
if n.get("graph_name")
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
merged.update(nodes)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"nodes": merged,
|
||||||
|
"node_count": len(merged),
|
||||||
|
"tab_count": len(self._tab_nodes),
|
||||||
|
"tabs": tab_info,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class HealthCheckHandler:
|
class HealthCheckHandler:
|
||||||
async def health_check(self, request: web.Request) -> web.Response:
|
async def health_check(self, request: web.Request) -> web.Response:
|
||||||
@@ -2995,10 +3060,21 @@ class NodeRegistryHandler:
|
|||||||
try:
|
try:
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
nodes = data.get("nodes", [])
|
nodes = data.get("nodes", [])
|
||||||
|
client_id = data.get("client_id")
|
||||||
if not isinstance(nodes, list):
|
if not isinstance(nodes, list):
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
{"success": False, "error": "nodes must be a list"}, status=400
|
{"success": False, "error": "nodes must be a list"}, status=400
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not isinstance(client_id, str) or not client_id:
|
||||||
|
return web.json_response(
|
||||||
|
{
|
||||||
|
"success": False,
|
||||||
|
"error": "Missing client_id parameter",
|
||||||
|
},
|
||||||
|
status=400,
|
||||||
|
)
|
||||||
|
|
||||||
for index, node in enumerate(nodes):
|
for index, node in enumerate(nodes):
|
||||||
if not isinstance(node, dict):
|
if not isinstance(node, dict):
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
@@ -3042,7 +3118,7 @@ class NodeRegistryHandler:
|
|||||||
else:
|
else:
|
||||||
node["graph_name"] = str(graph_name)
|
node["graph_name"] = str(graph_name)
|
||||||
|
|
||||||
await self._node_registry.register_nodes(nodes)
|
await self._node_registry.register_nodes(client_id, nodes)
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
{
|
{
|
||||||
"success": True,
|
"success": True,
|
||||||
@@ -3066,9 +3142,15 @@ class NodeRegistryHandler:
|
|||||||
status=503,
|
status=503,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Snapshot of currently-connected ComfyUI tabs
|
||||||
|
active_sids = list(self._prompt_server.instance.sockets.keys())
|
||||||
|
self._node_registry.prepare_for_refresh(active_sids)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._prompt_server.instance.send_sync("lora_registry_refresh", {})
|
self._prompt_server.instance.send_sync("lora_registry_refresh", {})
|
||||||
logger.debug("Sent registry refresh request to frontend")
|
logger.debug(
|
||||||
|
"Sent registry refresh request (expecting %s clients)", len(active_sids)
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.error("Failed to send registry refresh message: %s", exc)
|
logger.error("Failed to send registry refresh message: %s", exc)
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
@@ -3080,19 +3162,31 @@ class NodeRegistryHandler:
|
|||||||
status=500,
|
status=500,
|
||||||
)
|
)
|
||||||
|
|
||||||
registry_updated = await self._node_registry.wait_for_update(timeout=1.0)
|
if not await self._node_registry.wait_for_all(timeout=2.0):
|
||||||
if not registry_updated:
|
logger.warning(
|
||||||
logger.warning("Registry refresh timeout after 1 second")
|
"Registry refresh timeout after 2s (%s/%s clients responded)",
|
||||||
|
len(active_sids) - self._node_registry.pending_client_count,
|
||||||
|
len(active_sids),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Re-read current sockets after the wait: a tab may have connected
|
||||||
|
# while we were waiting, and we don't want to garbage-collect it.
|
||||||
|
current_sids = set(self._prompt_server.instance.sockets.keys())
|
||||||
|
registry_info = await self._node_registry.get_merged_registry(
|
||||||
|
active_sids=current_sids
|
||||||
|
)
|
||||||
|
|
||||||
|
if registry_info["node_count"] == 0:
|
||||||
|
logger.warning("No nodes registered after refresh")
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
{
|
{
|
||||||
"success": False,
|
"success": False,
|
||||||
"error": "Timeout Error",
|
"error": "Empty Registry",
|
||||||
"message": "Registry refresh timeout - ComfyUI frontend may not be responsive",
|
"message": "No workflow nodes found — ensure ComfyUI is open and the extension is loaded.",
|
||||||
},
|
},
|
||||||
status=408,
|
status=408,
|
||||||
)
|
)
|
||||||
|
|
||||||
registry_info = await self._node_registry.get_registry()
|
|
||||||
return web.json_response({"success": True, "data": registry_info})
|
return web.json_response({"success": True, "data": registry_info})
|
||||||
except Exception as exc: # pragma: no cover - defensive logging
|
except Exception as exc: # pragma: no cover - defensive logging
|
||||||
logger.error("Failed to get registry: %s", exc, exc_info=True)
|
logger.error("Failed to get registry: %s", exc, exc_info=True)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-lora-manager"
|
name = "comfyui-lora-manager"
|
||||||
description = "Revolutionize your workflow with the ultimate LoRA companion for ComfyUI!"
|
description = "Revolutionize your workflow with the ultimate LoRA companion for ComfyUI!"
|
||||||
version = "1.1.5"
|
version = "1.1.6"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aiohttp",
|
"aiohttp",
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ class FakePromptServer:
|
|||||||
sent = []
|
sent = []
|
||||||
|
|
||||||
class Instance:
|
class Instance:
|
||||||
def send_sync(self, event, payload):
|
sockets: dict = {}
|
||||||
|
|
||||||
|
def send_sync(self, event, payload, sid=None):
|
||||||
FakePromptServer.sent.append((event, payload))
|
FakePromptServer.sent.append((event, payload))
|
||||||
|
|
||||||
instance = Instance()
|
instance = Instance()
|
||||||
@@ -148,7 +150,8 @@ class TestNodeRegistryHandlerSnapshots:
|
|||||||
"type": "Lora Loader (LoraManager)",
|
"type": "Lora Loader (LoraManager)",
|
||||||
"title": "Test Loader",
|
"title": "Test Loader",
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"client_id": "test-client-1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -167,7 +170,7 @@ class TestNodeRegistryHandlerSnapshots:
|
|||||||
standalone_mode=False,
|
standalone_mode=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
request = FakeRequest(json_data={"nodes": []})
|
request = FakeRequest(json_data={"nodes": [], "client_id": "test-client-1"})
|
||||||
response = await handler.register_nodes(request)
|
response = await handler.register_nodes(request)
|
||||||
payload = json.loads(response.text)
|
payload = json.loads(response.text)
|
||||||
|
|
||||||
|
|||||||
@@ -586,7 +586,9 @@ class FakePromptServer:
|
|||||||
sent = []
|
sent = []
|
||||||
|
|
||||||
class Instance:
|
class Instance:
|
||||||
def send_sync(self, event, payload):
|
sockets: dict = {}
|
||||||
|
|
||||||
|
def send_sync(self, event, payload, sid=None):
|
||||||
FakePromptServer.sent.append((event, payload))
|
FakePromptServer.sent.append((event, payload))
|
||||||
|
|
||||||
instance = Instance()
|
instance = Instance()
|
||||||
@@ -601,7 +603,12 @@ async def test_register_nodes_requires_graph_id():
|
|||||||
standalone_mode=False,
|
standalone_mode=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
request = FakeRequest(json_data={"nodes": [{"node_id": 1}]})
|
request = FakeRequest(
|
||||||
|
json_data={
|
||||||
|
"nodes": [{"node_id": 1}],
|
||||||
|
"client_id": "test-client-1",
|
||||||
|
}
|
||||||
|
)
|
||||||
response = await handler.register_nodes(request)
|
response = await handler.register_nodes(request)
|
||||||
payload = json.loads(response.text)
|
payload = json.loads(response.text)
|
||||||
|
|
||||||
@@ -629,7 +636,8 @@ async def test_register_nodes_stores_graph_identifier():
|
|||||||
"type": "Lora Loader (LoraManager)",
|
"type": "Lora Loader (LoraManager)",
|
||||||
"title": "Loader",
|
"title": "Loader",
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"client_id": "test-client-1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -638,7 +646,7 @@ async def test_register_nodes_stores_graph_identifier():
|
|||||||
|
|
||||||
assert payload["success"] is True
|
assert payload["success"] is True
|
||||||
|
|
||||||
registry = await node_registry.get_registry()
|
registry = await node_registry.get_merged_registry()
|
||||||
assert registry["node_count"] == 1
|
assert registry["node_count"] == 1
|
||||||
stored_node = next(iter(registry["nodes"].values()))
|
stored_node = next(iter(registry["nodes"].values()))
|
||||||
assert stored_node["graph_id"] == "graph-123"
|
assert stored_node["graph_id"] == "graph-123"
|
||||||
@@ -664,7 +672,8 @@ async def test_register_nodes_defaults_graph_name_to_none():
|
|||||||
"type": "Lora Loader (LoraManager)",
|
"type": "Lora Loader (LoraManager)",
|
||||||
"title": "Root Loader",
|
"title": "Root Loader",
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"client_id": "test-client-1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -673,7 +682,7 @@ async def test_register_nodes_defaults_graph_name_to_none():
|
|||||||
|
|
||||||
assert payload["success"] is True
|
assert payload["success"] is True
|
||||||
|
|
||||||
registry = await node_registry.get_registry()
|
registry = await node_registry.get_merged_registry()
|
||||||
stored_node = next(iter(registry["nodes"].values()))
|
stored_node = next(iter(registry["nodes"].values()))
|
||||||
assert stored_node["graph_name"] is None
|
assert stored_node["graph_name"] is None
|
||||||
|
|
||||||
@@ -700,7 +709,8 @@ async def test_register_nodes_includes_capabilities():
|
|||||||
"widget_names": ["ckpt_name", "", 42],
|
"widget_names": ["ckpt_name", "", 42],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"client_id": "test-client-1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -709,7 +719,7 @@ async def test_register_nodes_includes_capabilities():
|
|||||||
|
|
||||||
assert payload["success"] is True
|
assert payload["success"] is True
|
||||||
|
|
||||||
registry = await node_registry.get_registry()
|
registry = await node_registry.get_merged_registry()
|
||||||
stored_node = next(iter(registry["nodes"].values()))
|
stored_node = next(iter(registry["nodes"].values()))
|
||||||
assert stored_node["capabilities"] == {
|
assert stored_node["capabilities"] == {
|
||||||
"supports_lora": False,
|
"supports_lora": False,
|
||||||
@@ -724,7 +734,9 @@ async def test_update_node_widget_sends_payload():
|
|||||||
|
|
||||||
class RecordingPromptServer:
|
class RecordingPromptServer:
|
||||||
class Instance:
|
class Instance:
|
||||||
def send_sync(self, event, payload):
|
sockets: dict = {}
|
||||||
|
|
||||||
|
def send_sync(self, event, payload, sid=None):
|
||||||
send_calls.append((event, payload))
|
send_calls.append((event, payload))
|
||||||
|
|
||||||
instance = Instance()
|
instance = Instance()
|
||||||
@@ -768,7 +780,9 @@ async def test_update_lora_code_includes_graph_identifier():
|
|||||||
|
|
||||||
class RecordingPromptServer:
|
class RecordingPromptServer:
|
||||||
class Instance:
|
class Instance:
|
||||||
def send_sync(self, event, payload):
|
sockets: dict = {}
|
||||||
|
|
||||||
|
def send_sync(self, event, payload, sid=None):
|
||||||
send_calls.append((event, payload))
|
send_calls.append((event, payload))
|
||||||
|
|
||||||
instance = Instance()
|
instance = Instance()
|
||||||
|
|||||||
@@ -151,7 +151,10 @@ app.registerExtension({
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ nodes: workflowNodes }),
|
body: JSON.stringify({
|
||||||
|
nodes: workflowNodes,
|
||||||
|
client_id: api.clientId ?? api.initialClientId ?? "",
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user