├── ,gitignore ├── LICENSE.txt ├── README.md ├── app.py ├── config.json ├── requirements.txt ├── run.sh ├── settings.py ├── tasks.py ├── templates ├── animate_diff │ └── workflow.json ├── img2img │ └── launcher.json ├── img2vid │ └── workflow.json ├── svd │ └── launcher.json ├── upscale │ └── launcher.json └── vid2vid │ └── launcher.json └── utils.py /,gitignore: -------------------------------------------------------------------------------- 1 | # Python bytecode 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Distribution / packaging 7 | dist/ 8 | build/ 9 | *.egg-info/ 10 | *.egg 11 | 12 | # Virtual environments 13 | venv/ 14 | env/ 15 | ENV/ 16 | .venv/ 17 | .env 18 | 19 | # Streamlit specific 20 | .streamlit/secrets.toml 21 | .streamlit/config.toml 22 | 23 | # Project specific 24 | projects/ 25 | models/ 26 | **/comfyui_temp/ 27 | **/comfyui_output/ 28 | *.db 29 | *.sqlite3 30 | launcher_state.json 31 | outputs/ 32 | 33 | # Development and testing 34 | .coverage 35 | htmlcov/ 36 | .pytest_cache/ 37 | .mypy_cache/ 38 | .tox/ 39 | coverage.xml 40 | *.cover 41 | 42 | # Jupyter Notebook 43 | .ipynb_checkpoints 44 | 45 | # IDE specific files 46 | .idea/ 47 | .vscode/ 48 | *.swp 49 | *.swo 50 | *~ 51 | .ropeproject/ 52 | 53 | # OS specific files 54 | .DS_Store 55 | Thumbs.db 56 | desktop.ini 57 | 58 | # Logs 59 | *.log 60 | logs/ 61 | 62 | # Environment variables 63 | .env 64 | .env.local 65 | 66 | # Dependency lock files 67 | Pipfile.lock 68 | 69 | # Temporary files 70 | *.tmp 71 | tmp/ 72 | temp/ 73 | 74 | # Config files 75 | config.json -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComfyUI Workflow Launcher - Streamlit Edition 2 | 3 | ![GitHub last commit](https://img.shields.io/github/last-commit/murapadev/ComfyUI-Streamlit-Launcher) 4 | ![GitHub issues](https://img.shields.io/github/issues/murapadev/ComfyUI-Streamlit-Launcher) 5 | ![GitHub stars](https://img.shields.io/github/stars/murapadev/ComfyUI-Streamlit-Launcher?style=social) 6 | ![GitHub forks](https://img.shields.io/github/forks/murapadev/ComfyUI-Streamlit-Launcher?style=social) 7 | ![License](https://img.shields.io/github/license/murapadev/ComfyUI-Streamlit-Launcher) 8 | 9 | 🚀 A user-friendly interface for managing **ComfyUI** projects with **Streamlit**. 10 | 11 | ⚠️ **Work in Progress**: This project is actively being developed. Some features may change or be incomplete. 12 | 13 | --- 14 | 15 | ## ✨ Features 16 | 17 | - **Create workflows** from predefined templates 18 | - **Import workflows** from JSON files 19 | - **Manage projects** (start, stop, delete) 20 | - **Monitor system info** and model details 21 | - **Track workflow status** and port usage 22 | - **Modern, responsive UI** for seamless interaction 23 | 24 | --- 25 | 26 | ## 📦 Installation 27 | 28 | ### 1. Clone the repository 29 | 30 | ```bash 31 | git clone https://github.com/murapadev/ComfyUI-Streamlit-Launcher.git 32 | cd comfyui-launcher/streamlit 33 | ``` 34 | 35 | ### 2. Install dependencies 36 | 37 | ```bash 38 | pip install -r requirements.txt 39 | ``` 40 | 41 | --- 42 | 43 | ## 🚀 Usage 44 | 45 | ### Start the application 46 | 47 | ```bash 48 | streamlit run app.py 49 | ``` 50 | 51 | The app will be available at [http://localhost:8501](http://localhost:8501) by default. 52 | 53 | ### Creating a New Workflow 54 | 55 | 1. Click **"Create New Workflow"** (sidebar or home page) 56 | 2. Enter a **workflow name** 57 | 3. Select a **template** 58 | 4. (Optional) Specify a **fixed port** 59 | 5. Click **"Create Workflow"** 60 | 61 | ### Importing a Workflow 62 | 63 | 1. Click **"Import Workflow"** 64 | 2. Enter a **workflow name** 65 | 3. Upload a **JSON file** or paste JSON content 66 | 4. (Optional) Set a **fixed port** or skip model validation 67 | 5. Click **"Import Workflow"** 68 | 69 | ### Managing Workflows 70 | 71 | From the home page, you can: 72 | 73 | - **Start** ready workflows 74 | - **Open/Stop** running workflows 75 | - **Delete** workflows 76 | 77 | ### ⚙️ Settings 78 | 79 | Access system information and configurations, including: 80 | 81 | - **System & directory info** 82 | - **Port configuration** 83 | - **Model storage details** 84 | 85 | --- 86 | 87 | ## 📂 Directory Structure 88 | 89 | - `projects/` - Created ComfyUI projects 90 | - `models/` - Shared models directory 91 | - `templates/` - Workflow templates 92 | 93 | --- 94 | 95 | ## 📌 Requirements 96 | 97 | - Python **3.8+** 98 | - `streamlit>=1.24.0` 99 | - `requests>=2.28.1` 100 | - `psutil>=5.9.0` 101 | - `tqdm>=4.64.1` 102 | - `pillow>=9.3.0` 103 | - `watchdog>=3.0.0` 104 | - `pandas>=1.5.0` 105 | - `plotly>=5.13.0` 106 | - `streamlit-option-menu>=0.3.2` 107 | - `streamlit-extras>=0.3.0` 108 | - `python-dotenv>=1.0.0` 109 | - `celery` 110 | - *(Optional)* `torch>=2.0.0` (for ML functionality) 111 | 112 | --- 113 | 114 | ## 🤝 Contributing 115 | 116 | Contributions are welcome! To contribute: 117 | 118 | 1. **Fork** the repository 119 | 2. **Create a new branch** (`git checkout -b feature-name`) 120 | 3. **Commit your changes** (`git commit -m "Add feature"`) 121 | 4. **Push to your branch** (`git push origin feature-name`) 122 | 5. **Submit a Pull Request** 🚀 123 | 124 | --- 125 | 126 | ## 📜 License & Attribution 127 | 128 | This project is based on [ComfyUI-Launcher](https://github.com/ComfyWorkflows/ComfyUI-Launcher) ([AGPL-3.0 License](https://github.com/ComfyWorkflows/ComfyUI-Launcher/blob/bb6690462780abecaa733814d02f8ccee1b0a829/server/utils.py)). All derivative work complies with the original license terms. 129 | 130 | 📌 **Star this project** ⭐ if you find it useful! 131 | 132 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "credentials": { 3 | "civitai": { 4 | "apikey": "" 5 | } 6 | }, 7 | "directories": { 8 | "projects": "./projects", 9 | "models": "./models", 10 | "templates": "./templates" 11 | }, 12 | "port_configuration": { 13 | "allow_overridable_ports": true, 14 | "project_min_port": 4001, 15 | "project_max_port": 4100, 16 | "server_port": 8501 17 | } 18 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | streamlit>=1.24.0 2 | requests>=2.28.1 3 | psutil>=5.9.0 4 | tqdm>=4.64.1 5 | pillow>=9.3.0 6 | watchdog>=3.0.0 7 | pandas>=1.5.0 8 | plotly>=5.13.0 9 | streamlit-option-menu>=0.3.2 10 | streamlit-extras>=0.3.0 11 | python-dotenv>=1.0.0 12 | celery 13 | # torch is now optional - install only if needed for ML functionality 14 | # torch>=2.0.0 -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script runs the ComfyUI Launcher Streamlit application 4 | 5 | # Check if Python is installed 6 | if ! command -v python3 &> /dev/null; then 7 | echo "Python 3 is not installed. Please install Python 3 to run this application." 8 | exit 1 9 | fi 10 | 11 | # Check if required packages are installed 12 | if ! python3 -c "import streamlit" &> /dev/null; then 13 | echo "Installing required packages..." 14 | pip install -r requirements.txt 15 | fi 16 | 17 | # Create necessary directories 18 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 19 | mkdir -p "$DIR/projects" 20 | mkdir -p "$DIR/models" 21 | mkdir -p "$DIR/templates" 22 | 23 | # Check if streamlit_patches.py exists 24 | if [ ! -f "$DIR/streamlit_patches.py" ]; then 25 | echo "Warning: streamlit_patches.py not found. Some features may not work correctly." 26 | fi 27 | 28 | # Run the Streamlit application 29 | echo "Starting ComfyUI Launcher Streamlit application..." 30 | streamlit run "$DIR/app.py" "$@" -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import os.path 4 | 5 | # Load configuration from config.json 6 | CONFIG_FILEPATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json") 7 | 8 | def get_config(): 9 | """ 10 | Load the configuration from config.json file. 11 | If the file doesn't exist, create it with default values. 12 | 13 | Returns: 14 | dict: Configuration dictionary 15 | """ 16 | try: 17 | # Ensure the directory exists 18 | os.makedirs(os.path.dirname(CONFIG_FILEPATH), exist_ok=True) 19 | 20 | if os.path.exists(CONFIG_FILEPATH): 21 | with open(CONFIG_FILEPATH, "r") as f: 22 | config = json.load(f) 23 | return config 24 | else: 25 | # Define default configuration 26 | default_config = { 27 | "credentials": { 28 | "civitai": { 29 | "apikey": "" 30 | } 31 | }, 32 | "directories": { 33 | "projects": "./projects", 34 | "models": "./models", 35 | "templates": "./templates" 36 | }, 37 | "port_configuration": { 38 | "allow_overridable_ports": True, 39 | "project_min_port": 4001, 40 | "project_max_port": 4100, 41 | "server_port": 8501 42 | } 43 | } 44 | 45 | # Create the config file with default values 46 | with open(CONFIG_FILEPATH, "w") as f: 47 | json.dump(default_config, f, indent=2) 48 | 49 | return default_config 50 | except (FileNotFoundError, json.JSONDecodeError, PermissionError) as e: 51 | print(f"Warning: Could not load config file: {e}") 52 | # Return default configuration as fallback 53 | return { 54 | "credentials": {"civitai": {"apikey": ""}}, 55 | "directories": { 56 | "projects": "./projects", 57 | "models": "./models", 58 | "templates": "./templates" 59 | }, 60 | "port_configuration": { 61 | "allow_overridable_ports": True, 62 | "project_min_port": 4001, 63 | "project_max_port": 4100, 64 | "server_port": 8501 65 | } 66 | } 67 | 68 | # Load configuration 69 | config = get_config() 70 | 71 | # Get directory configurations with environment variable overrides 72 | # Environment variables take precedence over config file values 73 | PROJECTS_DIR = os.environ.get("PROJECTS_DIR", config["directories"]["projects"]) 74 | MODELS_DIR = os.environ.get("MODELS_DIR", config["directories"]["models"]) 75 | TEMPLATES_DIR = os.environ.get("TEMPLATES_DIR", config["directories"]["templates"]) 76 | 77 | # Create directories if they don't exist 78 | os.makedirs(PROJECTS_DIR, exist_ok=True) 79 | os.makedirs(MODELS_DIR, exist_ok=True) 80 | os.makedirs(TEMPLATES_DIR, exist_ok=True) 81 | 82 | # Get port configuration with environment variable overrides 83 | ALLOW_OVERRIDABLE_PORTS_PER_PROJECT = os.environ.get( 84 | "ALLOW_OVERRIDABLE_PORTS_PER_PROJECT", 85 | str(config["port_configuration"]["allow_overridable_ports"]) 86 | ).lower() == "true" 87 | 88 | PROJECT_MIN_PORT = int(os.environ.get( 89 | "PROJECT_MIN_PORT", 90 | str(config["port_configuration"]["project_min_port"]) 91 | )) 92 | 93 | PROJECT_MAX_PORT = int(os.environ.get( 94 | "PROJECT_MAX_PORT", 95 | str(config["port_configuration"]["project_max_port"]) 96 | )) 97 | 98 | SERVER_PORT = int(os.environ.get( 99 | "SERVER_PORT", 100 | str(config["port_configuration"]["server_port"]) 101 | )) -------------------------------------------------------------------------------- /tasks.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import shutil 4 | from celery import shared_task 5 | from utils import COMFYUI_REPO_URL, create_symlink, create_virtualenv, install_default_custom_nodes, install_pip_reqs, normalize_model_filepaths_in_workflow_json, run_command, run_command_in_project_venv, set_default_workflow_from_launcher_json, set_launcher_state_data, setup_custom_nodes_from_snapshot, setup_files_from_launcher_json, setup_initial_models_folder 6 | 7 | @shared_task(ignore_result=False) 8 | def create_comfyui_project( 9 | project_folder_path, models_folder_path, id, name, launcher_json=None, port=None, create_project_folder=True 10 | ): 11 | project_folder_path = os.path.abspath(project_folder_path) 12 | models_folder_path = os.path.abspath(models_folder_path) 13 | 14 | try: 15 | if create_project_folder: 16 | assert not os.path.exists(project_folder_path), f"Project folder already exists at {project_folder_path}" 17 | os.makedirs(project_folder_path) 18 | else: 19 | assert os.path.exists(project_folder_path), f"Project folder does not exist at {project_folder_path}" 20 | 21 | set_launcher_state_data( 22 | project_folder_path, 23 | {"id":id,"name":name, "status_message": "Downloading ComfyUI...", "state": "download_comfyui"}, 24 | ) 25 | # Modify the subprocess.run calls to capture and log the stdout 26 | run_command( 27 | ["git", "clone", COMFYUI_REPO_URL, os.path.join(project_folder_path, 'comfyui')], 28 | ) 29 | 30 | if launcher_json: 31 | comfyui_commit_hash = launcher_json["snapshot_json"]["comfyui"] 32 | if comfyui_commit_hash: 33 | run_command( 34 | ["git", "checkout", comfyui_commit_hash], 35 | cwd=os.path.join(project_folder_path, 'comfyui'), 36 | ) 37 | launcher_json['workflow_json'] = normalize_model_filepaths_in_workflow_json(launcher_json['workflow_json']) 38 | 39 | 40 | # move the comfyui/web/index.html file to comfyui/web/comfyui_index.html 41 | os.rename( 42 | os.path.join(project_folder_path, "comfyui", "web", "index.html"), 43 | os.path.join(project_folder_path, "comfyui", "web", "comfyui_index.html"), 44 | ) 45 | 46 | # copy the web/comfy_frame.html file to comfyui/web/index.html 47 | shutil.copy( 48 | os.path.join("web", "comfy_frame.html"), 49 | os.path.join(project_folder_path, "comfyui", "web", "index.html"), 50 | ) 51 | 52 | # remove the models folder that exists in comfyui and symlink the shared_models folder as models 53 | if os.path.exists(os.path.join(project_folder_path, "comfyui", "models")): 54 | shutil.rmtree( 55 | os.path.join(project_folder_path, "comfyui", "models"), ignore_errors=True 56 | ) 57 | 58 | if not os.path.exists(models_folder_path): 59 | setup_initial_models_folder(models_folder_path) 60 | 61 | # create a folder in project folder/comfyui/models that is a symlink to the models folder 62 | create_symlink(models_folder_path, os.path.join(project_folder_path, "comfyui", "models")) 63 | 64 | set_launcher_state_data( 65 | project_folder_path, 66 | {"status_message": "Installing ComfyUI...", "state": "install_comfyui"}, 67 | ) 68 | 69 | # create a new virtualenv in project folder/venv 70 | create_virtualenv(os.path.join(project_folder_path, 'venv')) 71 | 72 | # activate the virtualenv + install comfyui requirements 73 | run_command_in_project_venv( 74 | project_folder_path, 75 | f"pip install -r {os.path.join(project_folder_path, 'comfyui', 'requirements.txt')}", 76 | ) 77 | 78 | set_launcher_state_data( 79 | project_folder_path, 80 | { 81 | "status_message": "Installing custom nodes...", 82 | "state": "install_custom_nodes", 83 | }, 84 | ) 85 | 86 | # install default custom nodes 87 | install_default_custom_nodes(project_folder_path, launcher_json) 88 | 89 | setup_custom_nodes_from_snapshot(project_folder_path, launcher_json) 90 | 91 | # install pip requirements 92 | if launcher_json and "pip_requirements" in launcher_json: 93 | install_pip_reqs(project_folder_path, launcher_json["pip_requirements"]) 94 | 95 | # download all necessary files 96 | set_launcher_state_data( 97 | project_folder_path, 98 | { 99 | "status_message": "Downloading models & other files...", 100 | "state": "download_files", 101 | }, 102 | ) 103 | 104 | setup_files_from_launcher_json(project_folder_path, launcher_json) 105 | set_default_workflow_from_launcher_json(project_folder_path, launcher_json) 106 | 107 | if launcher_json: 108 | with open(os.path.join(project_folder_path, "launcher.json"), "w") as f: 109 | json.dump(launcher_json, f) 110 | 111 | if port is not None: 112 | with open(os.path.join(project_folder_path, "port.txt"), "w") as f: 113 | f.write(str(port)) 114 | 115 | set_launcher_state_data( 116 | project_folder_path, {"status_message": "Ready", "state": "ready"} 117 | ) 118 | except: 119 | # remove the project folder if an error occurs 120 | shutil.rmtree(project_folder_path, ignore_errors=True) 121 | raise -------------------------------------------------------------------------------- /templates/animate_diff/workflow.json: -------------------------------------------------------------------------------- 1 | { 2 | "last_node_id": 30, 3 | "last_link_id": 43, 4 | "nodes": [ 5 | { 6 | "id": 4, 7 | "type": "CLIPSetLastLayer", 8 | "pos": [ 9 | 431.14133986796236, 10 | 184.59417317288003 11 | ], 12 | "size": { 13 | "0": 315, 14 | "1": 58 15 | }, 16 | "flags": {}, 17 | "order": 6, 18 | "mode": 0, 19 | "inputs": [ 20 | { 21 | "name": "clip", 22 | "type": "CLIP", 23 | "link": 33 24 | } 25 | ], 26 | "outputs": [ 27 | { 28 | "name": "CLIP", 29 | "type": "CLIP", 30 | "links": [ 31 | 2, 32 | 3 33 | ], 34 | "shape": 3, 35 | "slot_index": 0 36 | } 37 | ], 38 | "properties": { 39 | "Node name for S&R": "CLIPSetLastLayer" 40 | }, 41 | "widgets_values": [ 42 | -2 43 | ] 44 | }, 45 | { 46 | "id": 5, 47 | "type": "PrimitiveNode", 48 | "pos": [ 49 | 279, 50 | 431 51 | ], 52 | "size": { 53 | "0": 285.6000061035156, 54 | "1": 82 55 | }, 56 | "flags": {}, 57 | "order": 0, 58 | "mode": 0, 59 | "outputs": [ 60 | { 61 | "name": "INT", 62 | "type": "INT", 63 | "links": [ 64 | 6, 65 | 16 66 | ], 67 | "slot_index": 0, 68 | "widget": { 69 | "name": "seed" 70 | } 71 | } 72 | ], 73 | "title": "Primitive (I'm using this as seed)", 74 | "properties": { 75 | "Run widget replace on values": false 76 | }, 77 | "widgets_values": [ 78 | 888888889, 79 | "fixed" 80 | ], 81 | "color": "#2a363b", 82 | "bgcolor": "#3f5159" 83 | }, 84 | { 85 | "id": 2, 86 | "type": "VAELoader", 87 | "pos": [ 88 | 179, 89 | 326 90 | ], 91 | "size": { 92 | "0": 385.8948669433594, 93 | "1": 58 94 | }, 95 | "flags": {}, 96 | "order": 1, 97 | "mode": 0, 98 | "outputs": [ 99 | { 100 | "name": "VAE", 101 | "type": "VAE", 102 | "links": [ 103 | 10, 104 | 23, 105 | 42 106 | ], 107 | "shape": 3, 108 | "slot_index": 0 109 | } 110 | ], 111 | "properties": { 112 | "Node name for S&R": "VAELoader" 113 | }, 114 | "widgets_values": [ 115 | "vae-ft-mse-840000-ema-pruned.safetensors" 116 | ] 117 | }, 118 | { 119 | "id": 6, 120 | "type": "CLIPTextEncode", 121 | "pos": [ 122 | 874, 123 | 287 124 | ], 125 | "size": { 126 | "0": 391.23883056640625, 127 | "1": 78.14339447021484 128 | }, 129 | "flags": {}, 130 | "order": 8, 131 | "mode": 0, 132 | "inputs": [ 133 | { 134 | "name": "clip", 135 | "type": "CLIP", 136 | "link": 3 137 | } 138 | ], 139 | "outputs": [ 140 | { 141 | "name": "CONDITIONING", 142 | "type": "CONDITIONING", 143 | "links": [ 144 | 5, 145 | 25 146 | ], 147 | "shape": 3, 148 | "slot_index": 0 149 | } 150 | ], 151 | "properties": { 152 | "Node name for S&R": "CLIPTextEncode" 153 | }, 154 | "widgets_values": [ 155 | "(worst quality, low quality: 1.4)" 156 | ], 157 | "color": "#322", 158 | "bgcolor": "#533" 159 | }, 160 | { 161 | "id": 25, 162 | "type": "ADE_AnimateDiffUniformContextOptions", 163 | "pos": [ 164 | 485, 165 | -298 166 | ], 167 | "size": { 168 | "0": 315, 169 | "1": 154 170 | }, 171 | "flags": {}, 172 | "order": 2, 173 | "mode": 0, 174 | "outputs": [ 175 | { 176 | "name": "CONTEXT_OPTIONS", 177 | "type": "CONTEXT_OPTIONS", 178 | "links": [ 179 | 37 180 | ], 181 | "shape": 3, 182 | "slot_index": 0 183 | } 184 | ], 185 | "properties": { 186 | "Node name for S&R": "ADE_AnimateDiffUniformContextOptions" 187 | }, 188 | "widgets_values": [ 189 | 16, 190 | 1, 191 | 4, 192 | "uniform", 193 | false 194 | ], 195 | "color": "#432", 196 | "bgcolor": "#653" 197 | }, 198 | { 199 | "id": 15, 200 | "type": "VAEDecode", 201 | "pos": [ 202 | 1771, 203 | 325 204 | ], 205 | "size": { 206 | "0": 210, 207 | "1": 46 208 | }, 209 | "flags": {}, 210 | "order": 15, 211 | "mode": 0, 212 | "inputs": [ 213 | { 214 | "name": "samples", 215 | "type": "LATENT", 216 | "link": 21 217 | }, 218 | { 219 | "name": "vae", 220 | "type": "VAE", 221 | "link": 23 222 | } 223 | ], 224 | "outputs": [ 225 | { 226 | "name": "IMAGE", 227 | "type": "IMAGE", 228 | "links": [ 229 | 39 230 | ], 231 | "shape": 3, 232 | "slot_index": 0 233 | } 234 | ], 235 | "properties": { 236 | "Node name for S&R": "VAEDecode" 237 | } 238 | }, 239 | { 240 | "id": 10, 241 | "type": "VAEDecode", 242 | "pos": [ 243 | 1759, 244 | -315 245 | ], 246 | "size": { 247 | "0": 210, 248 | "1": 46 249 | }, 250 | "flags": {}, 251 | "order": 10, 252 | "mode": 0, 253 | "inputs": [ 254 | { 255 | "name": "samples", 256 | "type": "LATENT", 257 | "link": 9 258 | }, 259 | { 260 | "name": "vae", 261 | "type": "VAE", 262 | "link": 10 263 | } 264 | ], 265 | "outputs": [ 266 | { 267 | "name": "IMAGE", 268 | "type": "IMAGE", 269 | "links": [ 270 | 40 271 | ], 272 | "shape": 3, 273 | "slot_index": 0 274 | } 275 | ], 276 | "properties": { 277 | "Node name for S&R": "VAEDecode" 278 | } 279 | }, 280 | { 281 | "id": 9, 282 | "type": "EmptyLatentImage", 283 | "pos": [ 284 | 853, 285 | -45 286 | ], 287 | "size": { 288 | "0": 315, 289 | "1": 106 290 | }, 291 | "flags": {}, 292 | "order": 3, 293 | "mode": 0, 294 | "outputs": [ 295 | { 296 | "name": "LATENT", 297 | "type": "LATENT", 298 | "links": [ 299 | 31 300 | ], 301 | "shape": 3, 302 | "slot_index": 0 303 | } 304 | ], 305 | "properties": { 306 | "Node name for S&R": "EmptyLatentImage" 307 | }, 308 | "widgets_values": [ 309 | 512, 310 | 512, 311 | 120 312 | ] 313 | }, 314 | { 315 | "id": 20, 316 | "type": "ADE_AnimateDiffLoaderWithContext", 317 | "pos": [ 318 | 866, 319 | -341 320 | ], 321 | "size": { 322 | "0": 315, 323 | "1": 190 324 | }, 325 | "flags": {}, 326 | "order": 5, 327 | "mode": 0, 328 | "inputs": [ 329 | { 330 | "name": "model", 331 | "type": "MODEL", 332 | "link": 34 333 | }, 334 | { 335 | "name": "context_options", 336 | "type": "CONTEXT_OPTIONS", 337 | "link": 37 338 | }, 339 | { 340 | "name": "motion_lora", 341 | "type": "MOTION_LORA", 342 | "link": null 343 | }, 344 | { 345 | "name": "motion_model_settings", 346 | "type": "MOTION_MODEL_SETTINGS", 347 | "link": null 348 | } 349 | ], 350 | "outputs": [ 351 | { 352 | "name": "MODEL", 353 | "type": "MODEL", 354 | "links": [ 355 | 29, 356 | 30 357 | ], 358 | "shape": 3, 359 | "slot_index": 0 360 | } 361 | ], 362 | "properties": { 363 | "Node name for S&R": "ADE_AnimateDiffLoaderWithContext" 364 | }, 365 | "widgets_values": [ 366 | "mm_sd_v15_v2.ckpt", 367 | "sqrt_linear (AnimateDiff)", 368 | 1, 369 | false 370 | ], 371 | "color": "#432", 372 | "bgcolor": "#653" 373 | }, 374 | { 375 | "id": 14, 376 | "type": "KSampler", 377 | "pos": [ 378 | 1390, 379 | 410 380 | ], 381 | "size": [ 382 | 315, 383 | 446 384 | ], 385 | "flags": {}, 386 | "order": 14, 387 | "mode": 0, 388 | "inputs": [ 389 | { 390 | "name": "model", 391 | "type": "MODEL", 392 | "link": 30 393 | }, 394 | { 395 | "name": "positive", 396 | "type": "CONDITIONING", 397 | "link": 26 398 | }, 399 | { 400 | "name": "negative", 401 | "type": "CONDITIONING", 402 | "link": 25 403 | }, 404 | { 405 | "name": "latent_image", 406 | "type": "LATENT", 407 | "link": 17 408 | }, 409 | { 410 | "name": "seed", 411 | "type": "INT", 412 | "link": 16, 413 | "widget": { 414 | "name": "seed" 415 | } 416 | } 417 | ], 418 | "outputs": [ 419 | { 420 | "name": "LATENT", 421 | "type": "LATENT", 422 | "links": [ 423 | 21 424 | ], 425 | "shape": 3, 426 | "slot_index": 0 427 | } 428 | ], 429 | "properties": { 430 | "Node name for S&R": "KSampler" 431 | }, 432 | "widgets_values": [ 433 | 888888889, 434 | "fixed", 435 | 25, 436 | 8, 437 | "euler", 438 | "normal", 439 | 0.6499999999999997 440 | ] 441 | }, 442 | { 443 | "id": 22, 444 | "type": "CheckpointLoaderSimple", 445 | "pos": [ 446 | 64, 447 | 163 448 | ], 449 | "size": { 450 | "0": 315, 451 | "1": 98 452 | }, 453 | "flags": {}, 454 | "order": 4, 455 | "mode": 0, 456 | "outputs": [ 457 | { 458 | "name": "MODEL", 459 | "type": "MODEL", 460 | "links": [ 461 | 34 462 | ], 463 | "shape": 3, 464 | "slot_index": 0 465 | }, 466 | { 467 | "name": "CLIP", 468 | "type": "CLIP", 469 | "links": [ 470 | 33 471 | ], 472 | "shape": 3, 473 | "slot_index": 1 474 | }, 475 | { 476 | "name": "VAE", 477 | "type": "VAE", 478 | "links": null, 479 | "shape": 3 480 | } 481 | ], 482 | "properties": { 483 | "Node name for S&R": "CheckpointLoaderSimple" 484 | }, 485 | "widgets_values": [ 486 | "ghostmix_v20Bakedvae.safetensors" 487 | ] 488 | }, 489 | { 490 | "id": 3, 491 | "type": "CLIPTextEncode", 492 | "pos": [ 493 | 884, 494 | 113 495 | ], 496 | "size": { 497 | "0": 377.7811279296875, 498 | "1": 124.52955627441406 499 | }, 500 | "flags": {}, 501 | "order": 7, 502 | "mode": 0, 503 | "inputs": [ 504 | { 505 | "name": "clip", 506 | "type": "CLIP", 507 | "link": 2 508 | } 509 | ], 510 | "outputs": [ 511 | { 512 | "name": "CONDITIONING", 513 | "type": "CONDITIONING", 514 | "links": [ 515 | 4, 516 | 26 517 | ], 518 | "shape": 3, 519 | "slot_index": 0 520 | } 521 | ], 522 | "properties": { 523 | "Node name for S&R": "CLIPTextEncode" 524 | }, 525 | "widgets_values": [ 526 | "(High resolution), close up, front view, female samurai, wearing samurai armor, asymmetrical design, origami, no morphing" 527 | ], 528 | "color": "#232", 529 | "bgcolor": "#353" 530 | }, 531 | { 532 | "id": 13, 533 | "type": "LatentUpscaleBy", 534 | "pos": [ 535 | 1000, 536 | 470 537 | ], 538 | "size": { 539 | "0": 315, 540 | "1": 82 541 | }, 542 | "flags": {}, 543 | "order": 11, 544 | "mode": 0, 545 | "inputs": [ 546 | { 547 | "name": "samples", 548 | "type": "LATENT", 549 | "link": 15 550 | } 551 | ], 552 | "outputs": [ 553 | { 554 | "name": "LATENT", 555 | "type": "LATENT", 556 | "links": [ 557 | 17 558 | ], 559 | "shape": 3, 560 | "slot_index": 0 561 | } 562 | ], 563 | "properties": { 564 | "Node name for S&R": "LatentUpscaleBy" 565 | }, 566 | "widgets_values": [ 567 | "nearest-exact", 568 | 1.5 569 | ] 570 | }, 571 | { 572 | "id": 27, 573 | "type": "VHS_VideoCombine", 574 | "pos": [ 575 | 2024, 576 | -327 577 | ], 578 | "size": [ 579 | 351.06327661132855, 580 | 575.0632766113285 581 | ], 582 | "flags": {}, 583 | "order": 13, 584 | "mode": 0, 585 | "inputs": [ 586 | { 587 | "name": "images", 588 | "type": "IMAGE", 589 | "link": 40 590 | } 591 | ], 592 | "outputs": [], 593 | "properties": { 594 | "Node name for S&R": "VHS_VideoCombine" 595 | }, 596 | "widgets_values": { 597 | "frame_rate": 8, 598 | "loop_count": 0, 599 | "filename_prefix": "AnimateDiff", 600 | "format": "image/gif", 601 | "pingpong": false, 602 | "save_image": true, 603 | "crf": 20, 604 | "save_metadata": true, 605 | "audio_file": "", 606 | "videopreview": { 607 | "hidden": false, 608 | "paused": false, 609 | "params": { 610 | "filename": "AnimateDiff_00020.gif", 611 | "subfolder": "", 612 | "type": "output", 613 | "format": "image/gif" 614 | } 615 | } 616 | }, 617 | "color": "#223", 618 | "bgcolor": "#335" 619 | }, 620 | { 621 | "id": 7, 622 | "type": "KSampler", 623 | "pos": [ 624 | 1400, 625 | -230 626 | ], 627 | "size": [ 628 | 326.86632226562506, 629 | 522.0268857421876 630 | ], 631 | "flags": {}, 632 | "order": 9, 633 | "mode": 0, 634 | "inputs": [ 635 | { 636 | "name": "model", 637 | "type": "MODEL", 638 | "link": 29 639 | }, 640 | { 641 | "name": "positive", 642 | "type": "CONDITIONING", 643 | "link": 4 644 | }, 645 | { 646 | "name": "negative", 647 | "type": "CONDITIONING", 648 | "link": 5 649 | }, 650 | { 651 | "name": "latent_image", 652 | "type": "LATENT", 653 | "link": 31 654 | }, 655 | { 656 | "name": "seed", 657 | "type": "INT", 658 | "link": 6, 659 | "widget": { 660 | "name": "seed" 661 | } 662 | } 663 | ], 664 | "outputs": [ 665 | { 666 | "name": "LATENT", 667 | "type": "LATENT", 668 | "links": [ 669 | 9, 670 | 15, 671 | 41 672 | ], 673 | "shape": 3, 674 | "slot_index": 0 675 | } 676 | ], 677 | "properties": { 678 | "Node name for S&R": "KSampler" 679 | }, 680 | "widgets_values": [ 681 | 888888889, 682 | "fixed", 683 | 25, 684 | 8, 685 | "euler", 686 | "normal", 687 | 1 688 | ] 689 | }, 690 | { 691 | "id": 29, 692 | "type": "VAEDecode", 693 | "pos": [ 694 | 1756.866322265625, 695 | -230 696 | ], 697 | "size": { 698 | "0": 210, 699 | "1": 46 700 | }, 701 | "flags": {}, 702 | "order": 12, 703 | "mode": 0, 704 | "inputs": [ 705 | { 706 | "name": "samples", 707 | "type": "LATENT", 708 | "link": 41 709 | }, 710 | { 711 | "name": "vae", 712 | "type": "VAE", 713 | "link": 42 714 | } 715 | ], 716 | "outputs": [ 717 | { 718 | "name": "IMAGE", 719 | "type": "IMAGE", 720 | "links": [], 721 | "shape": 3 722 | } 723 | ], 724 | "properties": { 725 | "Node name for S&R": "VAEDecode" 726 | } 727 | }, 728 | { 729 | "id": 28, 730 | "type": "VHS_VideoCombine", 731 | "pos": [ 732 | 2415, 733 | -323 734 | ], 735 | "size": [ 736 | 338.0673222656251, 737 | 562.0673222656251 738 | ], 739 | "flags": {}, 740 | "order": 16, 741 | "mode": 0, 742 | "inputs": [ 743 | { 744 | "name": "images", 745 | "type": "IMAGE", 746 | "link": 39 747 | } 748 | ], 749 | "outputs": [], 750 | "properties": { 751 | "Node name for S&R": "VHS_VideoCombine" 752 | }, 753 | "widgets_values": { 754 | "frame_rate": 8, 755 | "loop_count": 0, 756 | "filename_prefix": "AnimateDiff", 757 | "format": "image/gif", 758 | "pingpong": false, 759 | "save_image": true, 760 | "crf": 20, 761 | "save_metadata": true, 762 | "audio_file": "", 763 | "videopreview": { 764 | "hidden": false, 765 | "paused": false, 766 | "params": { 767 | "filename": "AnimateDiff_00021.gif", 768 | "subfolder": "", 769 | "type": "output", 770 | "format": "image/gif" 771 | } 772 | } 773 | }, 774 | "color": "#223", 775 | "bgcolor": "#335" 776 | } 777 | ], 778 | "links": [ 779 | [ 780 | 2, 781 | 4, 782 | 0, 783 | 3, 784 | 0, 785 | "CLIP" 786 | ], 787 | [ 788 | 3, 789 | 4, 790 | 0, 791 | 6, 792 | 0, 793 | "CLIP" 794 | ], 795 | [ 796 | 4, 797 | 3, 798 | 0, 799 | 7, 800 | 1, 801 | "CONDITIONING" 802 | ], 803 | [ 804 | 5, 805 | 6, 806 | 0, 807 | 7, 808 | 2, 809 | "CONDITIONING" 810 | ], 811 | [ 812 | 6, 813 | 5, 814 | 0, 815 | 7, 816 | 4, 817 | "INT" 818 | ], 819 | [ 820 | 9, 821 | 7, 822 | 0, 823 | 10, 824 | 0, 825 | "LATENT" 826 | ], 827 | [ 828 | 10, 829 | 2, 830 | 0, 831 | 10, 832 | 1, 833 | "VAE" 834 | ], 835 | [ 836 | 15, 837 | 7, 838 | 0, 839 | 13, 840 | 0, 841 | "LATENT" 842 | ], 843 | [ 844 | 16, 845 | 5, 846 | 0, 847 | 14, 848 | 4, 849 | "INT" 850 | ], 851 | [ 852 | 17, 853 | 13, 854 | 0, 855 | 14, 856 | 3, 857 | "LATENT" 858 | ], 859 | [ 860 | 21, 861 | 14, 862 | 0, 863 | 15, 864 | 0, 865 | "LATENT" 866 | ], 867 | [ 868 | 23, 869 | 2, 870 | 0, 871 | 15, 872 | 1, 873 | "VAE" 874 | ], 875 | [ 876 | 25, 877 | 6, 878 | 0, 879 | 14, 880 | 2, 881 | "CONDITIONING" 882 | ], 883 | [ 884 | 26, 885 | 3, 886 | 0, 887 | 14, 888 | 1, 889 | "CONDITIONING" 890 | ], 891 | [ 892 | 29, 893 | 20, 894 | 0, 895 | 7, 896 | 0, 897 | "MODEL" 898 | ], 899 | [ 900 | 30, 901 | 20, 902 | 0, 903 | 14, 904 | 0, 905 | "MODEL" 906 | ], 907 | [ 908 | 31, 909 | 9, 910 | 0, 911 | 7, 912 | 3, 913 | "LATENT" 914 | ], 915 | [ 916 | 33, 917 | 22, 918 | 1, 919 | 4, 920 | 0, 921 | "CLIP" 922 | ], 923 | [ 924 | 34, 925 | 22, 926 | 0, 927 | 20, 928 | 0, 929 | "MODEL" 930 | ], 931 | [ 932 | 37, 933 | 25, 934 | 0, 935 | 20, 936 | 1, 937 | "CONTEXT_OPTIONS" 938 | ], 939 | [ 940 | 39, 941 | 15, 942 | 0, 943 | 28, 944 | 0, 945 | "IMAGE" 946 | ], 947 | [ 948 | 40, 949 | 10, 950 | 0, 951 | 27, 952 | 0, 953 | "IMAGE" 954 | ], 955 | [ 956 | 41, 957 | 7, 958 | 0, 959 | 29, 960 | 0, 961 | "LATENT" 962 | ], 963 | [ 964 | 42, 965 | 2, 966 | 0, 967 | 29, 968 | 1, 969 | "VAE" 970 | ] 971 | ], 972 | "groups": [ 973 | { 974 | "title": "Change this to match your model reqs", 975 | "bounding": [ 976 | 414, 977 | 101, 978 | 416, 979 | 165 980 | ], 981 | "color": "#3f789e", 982 | "font_size": 24, 983 | "locked": false 984 | }, 985 | { 986 | "title": "Animation length determined by Latents passed in", 987 | "bounding": [ 988 | 722, 989 | -118, 990 | 550, 991 | 191 992 | ], 993 | "color": "#3f789e", 994 | "font_size": 24, 995 | "locked": false 996 | } 997 | ], 998 | "config": {}, 999 | "extra": {}, 1000 | "version": 0.4 1001 | } -------------------------------------------------------------------------------- /templates/img2img/launcher.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "workflow_json": { 4 | "last_node_id": 74, 5 | "last_link_id": 131, 6 | "nodes": [ 7 | { 8 | "id": 56, 9 | "type": "IPAdapterModelLoader", 10 | "pos": [ 11 | 227, 12 | -142 13 | ], 14 | "size": { 15 | "0": 315, 16 | "1": 58 17 | }, 18 | "flags": {}, 19 | "order": 0, 20 | "mode": 0, 21 | "outputs": [ 22 | { 23 | "name": "IPADAPTER", 24 | "type": "IPADAPTER", 25 | "label": "IPADAPTER", 26 | "links": [ 27 | 76 28 | ], 29 | "shape": 3, 30 | "slot_index": 0 31 | } 32 | ], 33 | "properties": { 34 | "Node name for S&R": "IPAdapterModelLoader" 35 | }, 36 | "widgets_values": [ 37 | "ip-adapter-faceid_sdxl.bin" 38 | ] 39 | }, 40 | { 41 | "id": 57, 42 | "type": "CLIPVisionLoader", 43 | "pos": [ 44 | 225, 45 | -34 46 | ], 47 | "size": { 48 | "0": 315, 49 | "1": 58 50 | }, 51 | "flags": {}, 52 | "order": 1, 53 | "mode": 0, 54 | "outputs": [ 55 | { 56 | "name": "CLIP_VISION", 57 | "type": "CLIP_VISION", 58 | "label": "CLIP_VISION", 59 | "links": [ 60 | 77 61 | ], 62 | "shape": 3, 63 | "slot_index": 0 64 | } 65 | ], 66 | "properties": { 67 | "Node name for S&R": "CLIPVisionLoader" 68 | }, 69 | "widgets_values": [ 70 | "clip_vision_vit_h.safetensors" 71 | ] 72 | }, 73 | { 74 | "id": 14, 75 | "type": "CheckpointLoaderSimple", 76 | "pos": [ 77 | -457, 78 | -83 79 | ], 80 | "size": { 81 | "0": 315, 82 | "1": 122 83 | }, 84 | "flags": {}, 85 | "order": 2, 86 | "mode": 0, 87 | "outputs": [ 88 | { 89 | "name": "MODEL", 90 | "type": "MODEL", 91 | "label": "MODEL", 92 | "links": [ 93 | 18 94 | ], 95 | "shape": 3, 96 | "slot_index": 0 97 | }, 98 | { 99 | "name": "CLIP", 100 | "type": "CLIP", 101 | "label": "CLIP", 102 | "links": [ 103 | 19 104 | ], 105 | "shape": 3, 106 | "slot_index": 1 107 | }, 108 | { 109 | "name": "VAE", 110 | "type": "VAE", 111 | "label": "VAE", 112 | "links": [ 113 | 17 114 | ], 115 | "shape": 3, 116 | "slot_index": 2 117 | } 118 | ], 119 | "properties": { 120 | "Node name for S&R": "CheckpointLoaderSimple" 121 | }, 122 | "widgets_values": [ 123 | "opendalle_v11.safetensors" 124 | ] 125 | }, 126 | { 127 | "id": 58, 128 | "type": "InsightFaceLoader", 129 | "pos": [ 130 | 232, 131 | 77 132 | ], 133 | "size": { 134 | "0": 315, 135 | "1": 58 136 | }, 137 | "flags": {}, 138 | "order": 3, 139 | "mode": 0, 140 | "outputs": [ 141 | { 142 | "name": "INSIGHTFACE", 143 | "type": "INSIGHTFACE", 144 | "label": "INSIGHTFACE", 145 | "links": [ 146 | 78 147 | ], 148 | "shape": 3, 149 | "slot_index": 0 150 | } 151 | ], 152 | "properties": { 153 | "Node name for S&R": "InsightFaceLoader" 154 | }, 155 | "widgets_values": [ 156 | "CUDA" 157 | ] 158 | }, 159 | { 160 | "id": 10, 161 | "type": "LoadImage", 162 | "pos": [ 163 | 93.5603162978168, 164 | 285.73159240416703 165 | ], 166 | "size": { 167 | "0": 315, 168 | "1": 314.0000305175781 169 | }, 170 | "flags": {}, 171 | "order": 4, 172 | "mode": 0, 173 | "outputs": [ 174 | { 175 | "name": "IMAGE", 176 | "type": "IMAGE", 177 | "label": "IMAGE", 178 | "links": [ 179 | 79, 180 | 129 181 | ], 182 | "slot_index": 0 183 | }, 184 | { 185 | "name": "MASK", 186 | "type": "MASK", 187 | "label": "MASK", 188 | "links": null, 189 | "shape": 3 190 | } 191 | ], 192 | "title": "Upload your image", 193 | "properties": { 194 | "Node name for S&R": "LoadImage" 195 | }, 196 | "widgets_values": [ 197 | "360_F_258899001_68CalsKTRk6PZQgWH9JhR4heBlncCko9.jpg", 198 | "image" 199 | ] 200 | }, 201 | { 202 | "id": 72, 203 | "type": "ControlNetLoader", 204 | "pos": [ 205 | 570, 206 | 749 207 | ], 208 | "size": { 209 | "0": 315, 210 | "1": 58 211 | }, 212 | "flags": {}, 213 | "order": 5, 214 | "mode": 4, 215 | "outputs": [ 216 | { 217 | "name": "CONTROL_NET", 218 | "type": "CONTROL_NET", 219 | "links": [ 220 | 121 221 | ], 222 | "shape": 3 223 | } 224 | ], 225 | "properties": { 226 | "Node name for S&R": "ControlNetLoader" 227 | }, 228 | "widgets_values": [ 229 | "control-lora-canny-rank256.safetensors" 230 | ] 231 | }, 232 | { 233 | "id": 71, 234 | "type": "ControlNetApplyAdvanced", 235 | "pos": [ 236 | 569, 237 | 541 238 | ], 239 | "size": { 240 | "0": 315, 241 | "1": 166 242 | }, 243 | "flags": {}, 244 | "order": 15, 245 | "mode": 4, 246 | "inputs": [ 247 | { 248 | "name": "positive", 249 | "type": "CONDITIONING", 250 | "link": 126 251 | }, 252 | { 253 | "name": "negative", 254 | "type": "CONDITIONING", 255 | "link": 125 256 | }, 257 | { 258 | "name": "control_net", 259 | "type": "CONTROL_NET", 260 | "link": 121, 261 | "slot_index": 2 262 | }, 263 | { 264 | "name": "image", 265 | "type": "IMAGE", 266 | "link": 130 267 | } 268 | ], 269 | "outputs": [ 270 | { 271 | "name": "positive", 272 | "type": "CONDITIONING", 273 | "links": [ 274 | 127 275 | ], 276 | "shape": 3, 277 | "slot_index": 0 278 | }, 279 | { 280 | "name": "negative", 281 | "type": "CONDITIONING", 282 | "links": [ 283 | 128 284 | ], 285 | "shape": 3, 286 | "slot_index": 1 287 | } 288 | ], 289 | "properties": { 290 | "Node name for S&R": "ControlNetApplyAdvanced" 291 | }, 292 | "widgets_values": [ 293 | 1, 294 | 0, 295 | 1 296 | ] 297 | }, 298 | { 299 | "id": 66, 300 | "type": "CLIPTextEncode", 301 | "pos": [ 302 | 928, 303 | 266 304 | ], 305 | "size": { 306 | "0": 422.84503173828125, 307 | "1": 164.31304931640625 308 | }, 309 | "flags": { 310 | "collapsed": true 311 | }, 312 | "order": 13, 313 | "mode": 0, 314 | "inputs": [ 315 | { 316 | "link": 111, 317 | "name": "clip", 318 | "type": "CLIP", 319 | "label": "clip" 320 | }, 321 | { 322 | "link": 110, 323 | "name": "text", 324 | "type": "STRING", 325 | "label": "text", 326 | "widget": { 327 | "name": "text" 328 | }, 329 | "slot_index": 1 330 | } 331 | ], 332 | "outputs": [ 333 | { 334 | "name": "CONDITIONING", 335 | "type": "CONDITIONING", 336 | "label": "CONDITIONING", 337 | "links": [ 338 | 126 339 | ], 340 | "slot_index": 0 341 | } 342 | ], 343 | "properties": { 344 | "Node name for S&R": "CLIPTextEncode" 345 | }, 346 | "widgets_values": [ 347 | "2d anime style woman, lace mask, short pixie redhead, starship on the background, " 348 | ] 349 | }, 350 | { 351 | "id": 70, 352 | "type": "CLIPTextEncode", 353 | "pos": [ 354 | 929, 355 | 313 356 | ], 357 | "size": { 358 | "0": 422.84503173828125, 359 | "1": 164.31304931640625 360 | }, 361 | "flags": { 362 | "collapsed": true 363 | }, 364 | "order": 14, 365 | "mode": 0, 366 | "inputs": [ 367 | { 368 | "link": 119, 369 | "name": "clip", 370 | "type": "CLIP", 371 | "label": "clip" 372 | }, 373 | { 374 | "link": 118, 375 | "name": "text", 376 | "type": "STRING", 377 | "label": "text", 378 | "widget": { 379 | "name": "text" 380 | }, 381 | "slot_index": 1 382 | } 383 | ], 384 | "outputs": [ 385 | { 386 | "name": "CONDITIONING", 387 | "type": "CONDITIONING", 388 | "label": "CONDITIONING", 389 | "links": [ 390 | 125 391 | ], 392 | "slot_index": 0 393 | } 394 | ], 395 | "properties": { 396 | "Node name for S&R": "CLIPTextEncode" 397 | }, 398 | "widgets_values": [ 399 | "2d anime style woman, lace mask, short pixie redhead, starship on the background, " 400 | ] 401 | }, 402 | { 403 | "id": 3, 404 | "type": "KSampler", 405 | "pos": [ 406 | 931, 407 | 521 408 | ], 409 | "size": { 410 | "0": 315, 411 | "1": 262 412 | }, 413 | "flags": {}, 414 | "order": 16, 415 | "mode": 0, 416 | "inputs": [ 417 | { 418 | "link": 81, 419 | "name": "model", 420 | "type": "MODEL", 421 | "label": "model" 422 | }, 423 | { 424 | "link": 127, 425 | "name": "positive", 426 | "type": "CONDITIONING", 427 | "label": "positive" 428 | }, 429 | { 430 | "link": 128, 431 | "name": "negative", 432 | "type": "CONDITIONING", 433 | "label": "negative" 434 | }, 435 | { 436 | "link": 43, 437 | "name": "latent_image", 438 | "type": "LATENT", 439 | "label": "latent_image", 440 | "slot_index": 3 441 | } 442 | ], 443 | "outputs": [ 444 | { 445 | "name": "LATENT", 446 | "type": "LATENT", 447 | "label": "LATENT", 448 | "links": [ 449 | 7 450 | ], 451 | "slot_index": 0 452 | } 453 | ], 454 | "properties": { 455 | "Node name for S&R": "KSampler" 456 | }, 457 | "widgets_values": [ 458 | 765566763195824, 459 | "randomize", 460 | 8, 461 | 2, 462 | "dpmpp_sde", 463 | "normal", 464 | 1 465 | ] 466 | }, 467 | { 468 | "id": 8, 469 | "type": "VAEDecode", 470 | "pos": [ 471 | 935, 472 | 829 473 | ], 474 | "size": { 475 | "0": 300.83819580078125, 476 | "1": 49.89173126220703 477 | }, 478 | "flags": {}, 479 | "order": 17, 480 | "mode": 0, 481 | "inputs": [ 482 | { 483 | "link": 7, 484 | "name": "samples", 485 | "type": "LATENT", 486 | "label": "samples" 487 | }, 488 | { 489 | "link": 17, 490 | "name": "vae", 491 | "type": "VAE", 492 | "label": "vae" 493 | } 494 | ], 495 | "outputs": [ 496 | { 497 | "name": "IMAGE", 498 | "type": "IMAGE", 499 | "label": "IMAGE", 500 | "links": [ 501 | 55 502 | ], 503 | "slot_index": 0 504 | } 505 | ], 506 | "properties": { 507 | "Node name for S&R": "VAEDecode" 508 | } 509 | }, 510 | { 511 | "id": 55, 512 | "type": "IPAdapterApplyFaceID", 513 | "pos": [ 514 | 680, 515 | -164 516 | ], 517 | "size": { 518 | "0": 315, 519 | "1": 326 520 | }, 521 | "flags": {}, 522 | "order": 12, 523 | "mode": 0, 524 | "inputs": [ 525 | { 526 | "link": 76, 527 | "name": "ipadapter", 528 | "type": "IPADAPTER", 529 | "label": "ipadapter" 530 | }, 531 | { 532 | "link": 77, 533 | "name": "clip_vision", 534 | "type": "CLIP_VISION", 535 | "label": "clip_vision" 536 | }, 537 | { 538 | "link": 78, 539 | "name": "insightface", 540 | "type": "INSIGHTFACE", 541 | "label": "insightface" 542 | }, 543 | { 544 | "link": 79, 545 | "name": "image", 546 | "type": "IMAGE", 547 | "label": "image" 548 | }, 549 | { 550 | "link": 80, 551 | "name": "model", 552 | "type": "MODEL", 553 | "label": "model" 554 | }, 555 | { 556 | "link": null, 557 | "name": "attn_mask", 558 | "type": "MASK", 559 | "label": "attn_mask" 560 | } 561 | ], 562 | "outputs": [ 563 | { 564 | "name": "MODEL", 565 | "type": "MODEL", 566 | "label": "MODEL", 567 | "links": [ 568 | 81 569 | ], 570 | "shape": 3, 571 | "slot_index": 0 572 | } 573 | ], 574 | "properties": { 575 | "Node name for S&R": "IPAdapterApplyFaceID" 576 | }, 577 | "widgets_values": [ 578 | 1, 579 | 0.1, 580 | "channel penalty", 581 | 0, 582 | 1, 583 | false, 584 | 1, 585 | false 586 | ] 587 | }, 588 | { 589 | "id": 73, 590 | "type": "Canny", 591 | "pos": [ 592 | 568, 593 | 857 594 | ], 595 | "size": { 596 | "0": 315, 597 | "1": 82 598 | }, 599 | "flags": { 600 | "collapsed": false 601 | }, 602 | "order": 9, 603 | "mode": 4, 604 | "inputs": [ 605 | { 606 | "name": "image", 607 | "type": "IMAGE", 608 | "link": 129 609 | } 610 | ], 611 | "outputs": [ 612 | { 613 | "name": "IMAGE", 614 | "type": "IMAGE", 615 | "links": [ 616 | 130, 617 | 131 618 | ], 619 | "shape": 3, 620 | "slot_index": 0 621 | } 622 | ], 623 | "properties": { 624 | "Node name for S&R": "Canny" 625 | }, 626 | "widgets_values": [ 627 | 0.01, 628 | 0.99 629 | ] 630 | }, 631 | { 632 | "id": 40, 633 | "type": "SaveImage", 634 | "pos": [ 635 | 1298, 636 | 129 637 | ], 638 | "size": { 639 | "0": 695.1788330078125, 640 | "1": 859.2650756835938 641 | }, 642 | "flags": {}, 643 | "order": 18, 644 | "mode": 0, 645 | "inputs": [ 646 | { 647 | "link": 55, 648 | "name": "images", 649 | "type": "IMAGE", 650 | "label": "images" 651 | } 652 | ], 653 | "properties": {}, 654 | "widgets_values": [ 655 | "TensorArt" 656 | ] 657 | }, 658 | { 659 | "id": 74, 660 | "type": "PreviewImage", 661 | "pos": [ 662 | 94, 663 | 653 664 | ], 665 | "size": [ 666 | 310.60825056914086, 667 | 256.2006718931643 668 | ], 669 | "flags": {}, 670 | "order": 11, 671 | "mode": 4, 672 | "inputs": [ 673 | { 674 | "name": "images", 675 | "type": "IMAGE", 676 | "link": 131 677 | } 678 | ], 679 | "properties": { 680 | "Node name for S&R": "PreviewImage" 681 | } 682 | }, 683 | { 684 | "id": 49, 685 | "type": "SDXLPromptStyler", 686 | "pos": [ 687 | 477, 688 | 253 689 | ], 690 | "size": { 691 | "0": 400, 692 | "1": 242 693 | }, 694 | "flags": { 695 | "collapsed": false 696 | }, 697 | "order": 6, 698 | "mode": 0, 699 | "outputs": [ 700 | { 701 | "name": "text_positive", 702 | "type": "STRING", 703 | "label": "text_positive", 704 | "links": [ 705 | 110 706 | ], 707 | "shape": 3, 708 | "slot_index": 0 709 | }, 710 | { 711 | "name": "text_negative", 712 | "type": "STRING", 713 | "label": "text_negative", 714 | "links": [ 715 | 118 716 | ], 717 | "shape": 3, 718 | "slot_index": 1 719 | } 720 | ], 721 | "title": "Write your promt", 722 | "properties": { 723 | "Node name for S&R": "SDXLPromptStyler" 724 | }, 725 | "widgets_values": [ 726 | "a portrait photo of a man, close up", 727 | "", 728 | "sai-line art", 729 | true, 730 | true, 731 | true 732 | ] 733 | }, 734 | { 735 | "id": 16, 736 | "type": "LoraLoader", 737 | "pos": [ 738 | -453, 739 | 106 740 | ], 741 | "size": { 742 | "0": 315, 743 | "1": 150 744 | }, 745 | "flags": {}, 746 | "order": 8, 747 | "mode": 0, 748 | "inputs": [ 749 | { 750 | "link": 18, 751 | "name": "model", 752 | "type": "MODEL", 753 | "label": "model" 754 | }, 755 | { 756 | "link": 19, 757 | "name": "clip", 758 | "type": "CLIP", 759 | "label": "clip" 760 | } 761 | ], 762 | "outputs": [ 763 | { 764 | "name": "MODEL", 765 | "type": "MODEL", 766 | "label": "MODEL", 767 | "links": [ 768 | 83 769 | ], 770 | "shape": 3, 771 | "slot_index": 0 772 | }, 773 | { 774 | "name": "CLIP", 775 | "type": "CLIP", 776 | "label": "CLIP", 777 | "links": [ 778 | 84 779 | ], 780 | "shape": 3, 781 | "slot_index": 1 782 | } 783 | ], 784 | "properties": { 785 | "Node name for S&R": "LoraLoader" 786 | }, 787 | "widgets_values": [ 788 | "lineartSDXL.safetensors", 789 | 0.5, 790 | 0 791 | ] 792 | }, 793 | { 794 | "id": 17, 795 | "type": "LoraLoader", 796 | "pos": [ 797 | -443, 798 | 320 799 | ], 800 | "size": { 801 | "0": 315, 802 | "1": 150 803 | }, 804 | "flags": {}, 805 | "order": 10, 806 | "mode": 0, 807 | "inputs": [ 808 | { 809 | "link": 83, 810 | "name": "model", 811 | "type": "MODEL", 812 | "label": "model" 813 | }, 814 | { 815 | "link": 84, 816 | "name": "clip", 817 | "type": "CLIP", 818 | "label": "clip" 819 | } 820 | ], 821 | "outputs": [ 822 | { 823 | "name": "MODEL", 824 | "type": "MODEL", 825 | "label": "MODEL", 826 | "links": [ 827 | 80 828 | ], 829 | "shape": 3, 830 | "slot_index": 0 831 | }, 832 | { 833 | "name": "CLIP", 834 | "type": "CLIP", 835 | "label": "CLIP", 836 | "links": [ 837 | 111, 838 | 119 839 | ], 840 | "shape": 3, 841 | "slot_index": 1 842 | } 843 | ], 844 | "properties": { 845 | "Node name for S&R": "LoraLoader" 846 | }, 847 | "widgets_values": [ 848 | "ip-adapter-faceid_sdxl_lora.safetensors", 849 | 0.5, 850 | 0 851 | ] 852 | }, 853 | { 854 | "id": 30, 855 | "type": "EmptyLatentImage", 856 | "pos": [ 857 | 927, 858 | 362 859 | ], 860 | "size": { 861 | "0": 315, 862 | "1": 106 863 | }, 864 | "flags": {}, 865 | "order": 7, 866 | "mode": 0, 867 | "outputs": [ 868 | { 869 | "name": "LATENT", 870 | "type": "LATENT", 871 | "label": "LATENT", 872 | "links": [ 873 | 43 874 | ], 875 | "shape": 3 876 | } 877 | ], 878 | "properties": { 879 | "Node name for S&R": "EmptyLatentImage" 880 | }, 881 | "widgets_values": [ 882 | 1024, 883 | 1024, 884 | 1 885 | ] 886 | } 887 | ], 888 | "links": [ 889 | [ 890 | 7, 891 | 3, 892 | 0, 893 | 8, 894 | 0, 895 | "LATENT" 896 | ], 897 | [ 898 | 17, 899 | 14, 900 | 2, 901 | 8, 902 | 1, 903 | "VAE" 904 | ], 905 | [ 906 | 18, 907 | 14, 908 | 0, 909 | 16, 910 | 0, 911 | "MODEL" 912 | ], 913 | [ 914 | 19, 915 | 14, 916 | 1, 917 | 16, 918 | 1, 919 | "CLIP" 920 | ], 921 | [ 922 | 43, 923 | 30, 924 | 0, 925 | 3, 926 | 3, 927 | "LATENT" 928 | ], 929 | [ 930 | 55, 931 | 8, 932 | 0, 933 | 40, 934 | 0, 935 | "IMAGE" 936 | ], 937 | [ 938 | 76, 939 | 56, 940 | 0, 941 | 55, 942 | 0, 943 | "IPADAPTER" 944 | ], 945 | [ 946 | 77, 947 | 57, 948 | 0, 949 | 55, 950 | 1, 951 | "CLIP_VISION" 952 | ], 953 | [ 954 | 78, 955 | 58, 956 | 0, 957 | 55, 958 | 2, 959 | "INSIGHTFACE" 960 | ], 961 | [ 962 | 79, 963 | 10, 964 | 0, 965 | 55, 966 | 3, 967 | "IMAGE" 968 | ], 969 | [ 970 | 80, 971 | 17, 972 | 0, 973 | 55, 974 | 4, 975 | "MODEL" 976 | ], 977 | [ 978 | 81, 979 | 55, 980 | 0, 981 | 3, 982 | 0, 983 | "MODEL" 984 | ], 985 | [ 986 | 83, 987 | 16, 988 | 0, 989 | 17, 990 | 0, 991 | "MODEL" 992 | ], 993 | [ 994 | 84, 995 | 16, 996 | 1, 997 | 17, 998 | 1, 999 | "CLIP" 1000 | ], 1001 | [ 1002 | 110, 1003 | 49, 1004 | 0, 1005 | 66, 1006 | 1, 1007 | "STRING" 1008 | ], 1009 | [ 1010 | 111, 1011 | 17, 1012 | 1, 1013 | 66, 1014 | 0, 1015 | "CLIP" 1016 | ], 1017 | [ 1018 | 118, 1019 | 49, 1020 | 1, 1021 | 70, 1022 | 1, 1023 | "STRING" 1024 | ], 1025 | [ 1026 | 119, 1027 | 17, 1028 | 1, 1029 | 70, 1030 | 0, 1031 | "CLIP" 1032 | ], 1033 | [ 1034 | 121, 1035 | 72, 1036 | 0, 1037 | 71, 1038 | 2, 1039 | "CONTROL_NET" 1040 | ], 1041 | [ 1042 | 125, 1043 | 70, 1044 | 0, 1045 | 71, 1046 | 1, 1047 | "CONDITIONING" 1048 | ], 1049 | [ 1050 | 126, 1051 | 66, 1052 | 0, 1053 | 71, 1054 | 0, 1055 | "CONDITIONING" 1056 | ], 1057 | [ 1058 | 127, 1059 | 71, 1060 | 0, 1061 | 3, 1062 | 1, 1063 | "CONDITIONING" 1064 | ], 1065 | [ 1066 | 128, 1067 | 71, 1068 | 1, 1069 | 3, 1070 | 2, 1071 | "CONDITIONING" 1072 | ], 1073 | [ 1074 | 129, 1075 | 10, 1076 | 0, 1077 | 73, 1078 | 0, 1079 | "IMAGE" 1080 | ], 1081 | [ 1082 | 130, 1083 | 73, 1084 | 0, 1085 | 71, 1086 | 3, 1087 | "IMAGE" 1088 | ], 1089 | [ 1090 | 131, 1091 | 73, 1092 | 0, 1093 | 74, 1094 | 0, 1095 | "IMAGE" 1096 | ] 1097 | ], 1098 | "groups": [ 1099 | { 1100 | "title": "The essentials", 1101 | "bounding": [ 1102 | 44, 1103 | 191, 1104 | 860, 1105 | 769 1106 | ], 1107 | "color": "#8A8", 1108 | "font_size": 40 1109 | } 1110 | ], 1111 | "config": {}, 1112 | "extra": {}, 1113 | "version": 0.4 1114 | }, 1115 | "snapshot_json": { 1116 | "comfyui": null, 1117 | "git_custom_nodes": { 1118 | "https://github.com/cubiq/ComfyUI_IPAdapter_plus": { 1119 | "hash": null, 1120 | "disabled": false 1121 | }, 1122 | "https://github.com/hylarucoder/ComfyUI-Eagle-PNGInfo": { 1123 | "hash": null, 1124 | "disabled": false 1125 | }, 1126 | "https://github.com/sipherxyz/comfyui-art-venture": { 1127 | "hash": null, 1128 | "disabled": false 1129 | }, 1130 | "https://github.com/twri/sdxl_prompt_styler": { 1131 | "hash": null, 1132 | "disabled": false 1133 | } 1134 | } 1135 | }, 1136 | "files": [ 1137 | [ 1138 | { 1139 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/44131596/download", 1140 | "dest_relative_path": "models/ipadapter/ip-adapter-faceid_sdxl.bin", 1141 | "sha256_checksum": "f455fed24e207c878ec1e0466b34a969d37bab857c5faa4e8d259a0b4ff63d7e", 1142 | "size": 1071149741 1143 | } 1144 | ], 1145 | [ 1146 | { 1147 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/2714420/download", 1148 | "dest_relative_path": "models/clip_vision/clip_vision_vit_h.safetensors", 1149 | "sha256_checksum": "9a11c14945fb98c7ac9a54fab5e498885731a0780260dad7adf41f6f59655ee5", 1150 | "size": 1972298538 1151 | } 1152 | ], 1153 | [ 1154 | { 1155 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/271469/download", 1156 | "dest_relative_path": "models/checkpoints/opendalle_v11.safetensors", 1157 | "sha256_checksum": "673887ace8a5c56388a10e8d576d08f609393d981ea4938511179b50f09bdcc4", 1158 | "size": 6939232042 1159 | }, 1160 | { 1161 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/c/17944/download", 1162 | "dest_relative_path": "models/checkpoints/opendalle_v11.safetensors", 1163 | "sha256_checksum": "673887ace8a5c56388a10e8d576d08f609393d981ea4938511179b50f09bdcc4", 1164 | "size": 6939228160 1165 | } 1166 | ], 1167 | [ 1168 | { 1169 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/c/71125/download", 1170 | "dest_relative_path": "models/loras/lineartSDXL.safetensors", 1171 | "sha256_checksum": "b747719129049ec50c9ac05ab207b8418e24bc2e12ee81036b9a157d422b99ab", 1172 | "size": 228453376 1173 | } 1174 | ], 1175 | [ 1176 | { 1177 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/274966/download", 1178 | "dest_relative_path": "models/loras/ip-adapter-faceid_sdxl_lora.safetensors", 1179 | "sha256_checksum": "4fcf93d6e8dc8dd18f5f9e51c8306f369486ed0aa0780ade9961308aff7f0d64", 1180 | "size": 371842896 1181 | } 1182 | ], 1183 | [ 1184 | { 1185 | "download_url" : "https://t3.ftcdn.net/jpg/02/58/89/90/360_F_258899001_68CalsKTRk6PZQgWH9JhR4heBlncCko9.jpg", 1186 | "dest_relative_path": "input/360_F_258899001_68CalsKTRk6PZQgWH9JhR4heBlncCko9.jpg", 1187 | "sha256_checksum": "3bf2316058abe90fb0fcf76e46ccb0fee433a1eaac36359222cdf401f513bc54", 1188 | "size" : 20474 1189 | } 1190 | ] 1191 | ], 1192 | "pip_requirements": [ 1193 | "insightface", 1194 | "onnxruntime", 1195 | "segment_anything", 1196 | "omegaconf" 1197 | ], 1198 | "os": {}, 1199 | "python_version": {} 1200 | } -------------------------------------------------------------------------------- /templates/img2vid/workflow.json: -------------------------------------------------------------------------------- 1 | { 2 | "last_node_id": 60, 3 | "last_link_id": 103, 4 | "nodes": [ 5 | { 6 | "id": 8, 7 | "type": "VAEDecode", 8 | "pos": [ 9 | 1990.130282335937, 10 | 333.6667562822272 11 | ], 12 | "size": { 13 | "0": 210, 14 | "1": 46 15 | }, 16 | "flags": {}, 17 | "order": 10, 18 | "mode": 0, 19 | "inputs": [ 20 | { 21 | "name": "samples", 22 | "type": "LATENT", 23 | "link": 79 24 | }, 25 | { 26 | "name": "vae", 27 | "type": "VAE", 28 | "link": 57 29 | } 30 | ], 31 | "outputs": [ 32 | { 33 | "name": "IMAGE", 34 | "type": "IMAGE", 35 | "links": [ 36 | 42, 37 | 88 38 | ], 39 | "slot_index": 0 40 | } 41 | ], 42 | "properties": { 43 | "Node name for S&R": "VAEDecode" 44 | } 45 | }, 46 | { 47 | "id": 53, 48 | "type": "ImageUpscaleWithModel", 49 | "pos": [ 50 | 1990.130282335937, 51 | 773.6667562822275 52 | ], 53 | "size": { 54 | "0": 241.79998779296875, 55 | "1": 46 56 | }, 57 | "flags": {}, 58 | "order": 12, 59 | "mode": 2, 60 | "inputs": [ 61 | { 62 | "name": "upscale_model", 63 | "type": "UPSCALE_MODEL", 64 | "link": 87 65 | }, 66 | { 67 | "name": "image", 68 | "type": "IMAGE", 69 | "link": 88 70 | } 71 | ], 72 | "outputs": [ 73 | { 74 | "name": "IMAGE", 75 | "type": "IMAGE", 76 | "links": [ 77 | 89 78 | ], 79 | "shape": 3, 80 | "slot_index": 0 81 | } 82 | ], 83 | "properties": { 84 | "Node name for S&R": "ImageUpscaleWithModel" 85 | } 86 | }, 87 | { 88 | "id": 47, 89 | "type": "VHS_VideoCombine", 90 | "pos": [ 91 | 2300.130282335937, 92 | 773.6667562822275 93 | ], 94 | "size": [ 95 | 315, 96 | 174 97 | ], 98 | "flags": {}, 99 | "order": 13, 100 | "mode": 2, 101 | "inputs": [ 102 | { 103 | "name": "images", 104 | "type": "IMAGE", 105 | "link": 89 106 | }, 107 | { 108 | "name": "frame_rate", 109 | "type": "INT", 110 | "link": 84, 111 | "widget": { 112 | "name": "frame_rate" 113 | } 114 | } 115 | ], 116 | "outputs": [], 117 | "properties": { 118 | "Node name for S&R": "VHS_VideoCombine" 119 | }, 120 | "widgets_values": { 121 | "frame_rate": 6, 122 | "loop_count": 0, 123 | "filename_prefix": "img2vid", 124 | "format": "video/h264-mp4", 125 | "pingpong": false, 126 | "save_image": false, 127 | "videopreview": { 128 | "hidden": false, 129 | "paused": false, 130 | "params": { 131 | "filename": "img2vid_00017_.mp4", 132 | "subfolder": "", 133 | "type": "temp", 134 | "format": "video/h264-mp4" 135 | } 136 | } 137 | } 138 | }, 139 | { 140 | "id": 14, 141 | "type": "VideoLinearCFGGuidance", 142 | "pos": [ 143 | 1240.1302823359367, 144 | 263.66675628222686 145 | ], 146 | "size": { 147 | "0": 315, 148 | "1": 58 149 | }, 150 | "flags": {}, 151 | "order": 6, 152 | "mode": 0, 153 | "inputs": [ 154 | { 155 | "name": "model", 156 | "type": "MODEL", 157 | "link": 23 158 | } 159 | ], 160 | "outputs": [ 161 | { 162 | "name": "MODEL", 163 | "type": "MODEL", 164 | "links": [ 165 | 39 166 | ], 167 | "shape": 3, 168 | "slot_index": 0 169 | } 170 | ], 171 | "properties": { 172 | "Node name for S&R": "VideoLinearCFGGuidance" 173 | }, 174 | "widgets_values": [ 175 | 1 176 | ] 177 | }, 178 | { 179 | "id": 15, 180 | "type": "ImageOnlyCheckpointLoader", 181 | "pos": [ 182 | 820.1302823359363, 183 | 263.66675628222686 184 | ], 185 | "size": { 186 | "0": 369.6000061035156, 187 | "1": 98 188 | }, 189 | "flags": {}, 190 | "order": 0, 191 | "mode": 0, 192 | "outputs": [ 193 | { 194 | "name": "MODEL", 195 | "type": "MODEL", 196 | "links": [ 197 | 23 198 | ], 199 | "shape": 3, 200 | "slot_index": 0 201 | }, 202 | { 203 | "name": "CLIP_VISION", 204 | "type": "CLIP_VISION", 205 | "links": [ 206 | 24 207 | ], 208 | "shape": 3, 209 | "slot_index": 1 210 | }, 211 | { 212 | "name": "VAE", 213 | "type": "VAE", 214 | "links": [ 215 | 25 216 | ], 217 | "shape": 3, 218 | "slot_index": 2 219 | } 220 | ], 221 | "properties": { 222 | "Node name for S&R": "ImageOnlyCheckpointLoader" 223 | }, 224 | "widgets_values": [ 225 | "svd_xt.safetensors" 226 | ] 227 | }, 228 | { 229 | "id": 24, 230 | "type": "VHS_VideoCombine", 231 | "pos": [ 232 | 2300.130282335937, 233 | 333.6667562822272 234 | ], 235 | "size": [ 236 | 315, 237 | 338.3125 238 | ], 239 | "flags": {}, 240 | "order": 11, 241 | "mode": 0, 242 | "inputs": [ 243 | { 244 | "name": "images", 245 | "type": "IMAGE", 246 | "link": 42 247 | }, 248 | { 249 | "name": "frame_rate", 250 | "type": "INT", 251 | "link": 59, 252 | "widget": { 253 | "name": "frame_rate" 254 | } 255 | } 256 | ], 257 | "outputs": [], 258 | "properties": { 259 | "Node name for S&R": "VHS_VideoCombine" 260 | }, 261 | "widgets_values": { 262 | "frame_rate": 6, 263 | "loop_count": 0, 264 | "filename_prefix": "img2vid", 265 | "format": "image/gif", 266 | "pingpong": false, 267 | "save_image": false, 268 | "videopreview": { 269 | "hidden": false, 270 | "paused": false, 271 | "params": { 272 | "filename": "img2vid_00003_.gif", 273 | "subfolder": "", 274 | "type": "temp", 275 | "format": "image/gif" 276 | } 277 | } 278 | } 279 | }, 280 | { 281 | "id": 34, 282 | "type": "ImageOnlyCheckpointLoader", 283 | "pos": [ 284 | 1590.364006835938, 285 | 190.14003784179684 286 | ], 287 | "size": { 288 | "0": 370, 289 | "1": 100 290 | }, 291 | "flags": {}, 292 | "order": 1, 293 | "mode": 0, 294 | "outputs": [ 295 | { 296 | "name": "MODEL", 297 | "type": "MODEL", 298 | "links": null, 299 | "shape": 3 300 | }, 301 | { 302 | "name": "CLIP_VISION", 303 | "type": "CLIP_VISION", 304 | "links": null, 305 | "shape": 3 306 | }, 307 | { 308 | "name": "VAE", 309 | "type": "VAE", 310 | "links": [ 311 | 57 312 | ], 313 | "shape": 3, 314 | "slot_index": 2 315 | } 316 | ], 317 | "properties": { 318 | "Node name for S&R": "ImageOnlyCheckpointLoader" 319 | }, 320 | "widgets_values": [ 321 | "svd_xt_image_decoder.safetensors" 322 | ] 323 | }, 324 | { 325 | "id": 3, 326 | "type": "KSampler", 327 | "pos": [ 328 | 1650.1302823359374, 329 | 333.6667562822272 330 | ], 331 | "size": { 332 | "0": 310, 333 | "1": 262 334 | }, 335 | "flags": {}, 336 | "order": 9, 337 | "mode": 0, 338 | "inputs": [ 339 | { 340 | "name": "model", 341 | "type": "MODEL", 342 | "link": 39 343 | }, 344 | { 345 | "name": "positive", 346 | "type": "CONDITIONING", 347 | "link": 40 348 | }, 349 | { 350 | "name": "negative", 351 | "type": "CONDITIONING", 352 | "link": 17 353 | }, 354 | { 355 | "name": "latent_image", 356 | "type": "LATENT", 357 | "link": 18 358 | } 359 | ], 360 | "outputs": [ 361 | { 362 | "name": "LATENT", 363 | "type": "LATENT", 364 | "links": [ 365 | 79 366 | ], 367 | "slot_index": 0 368 | } 369 | ], 370 | "properties": { 371 | "Node name for S&R": "KSampler" 372 | }, 373 | "widgets_values": [ 374 | 1337, 375 | "fixed", 376 | 35, 377 | 2.5, 378 | "euler_ancestral", 379 | "karras", 380 | 1 381 | ] 382 | }, 383 | { 384 | "id": 12, 385 | "type": "SVD_img2vid_Conditioning", 386 | "pos": [ 387 | 1240.1302823359367, 388 | 353.6667562822272 389 | ], 390 | "size": [ 391 | 315, 392 | 218 393 | ], 394 | "flags": {}, 395 | "order": 8, 396 | "mode": 0, 397 | "inputs": [ 398 | { 399 | "name": "clip_vision", 400 | "type": "CLIP_VISION", 401 | "link": 24 402 | }, 403 | { 404 | "name": "init_image", 405 | "type": "IMAGE", 406 | "link": 103, 407 | "slot_index": 1 408 | }, 409 | { 410 | "name": "vae", 411 | "type": "VAE", 412 | "link": 25 413 | }, 414 | { 415 | "name": "fps", 416 | "type": "INT", 417 | "link": 58, 418 | "widget": { 419 | "name": "fps" 420 | } 421 | }, 422 | { 423 | "name": "width", 424 | "type": "INT", 425 | "link": 101, 426 | "widget": { 427 | "name": "width" 428 | } 429 | }, 430 | { 431 | "name": "height", 432 | "type": "INT", 433 | "link": 102, 434 | "widget": { 435 | "name": "height" 436 | } 437 | } 438 | ], 439 | "outputs": [ 440 | { 441 | "name": "positive", 442 | "type": "CONDITIONING", 443 | "links": [ 444 | 40 445 | ], 446 | "shape": 3, 447 | "slot_index": 0 448 | }, 449 | { 450 | "name": "negative", 451 | "type": "CONDITIONING", 452 | "links": [ 453 | 17 454 | ], 455 | "shape": 3, 456 | "slot_index": 1 457 | }, 458 | { 459 | "name": "latent", 460 | "type": "LATENT", 461 | "links": [ 462 | 18 463 | ], 464 | "shape": 3, 465 | "slot_index": 2 466 | } 467 | ], 468 | "properties": { 469 | "Node name for S&R": "SVD_img2vid_Conditioning" 470 | }, 471 | "widgets_values": [ 472 | 1024, 473 | 576, 474 | 25, 475 | 32, 476 | 6, 477 | 0 478 | ] 479 | }, 480 | { 481 | "id": 50, 482 | "type": "UpscaleModelLoader", 483 | "pos": [ 484 | 1910.3640068359373, 485 | 680.1400378417969 486 | ], 487 | "size": { 488 | "0": 320, 489 | "1": 60 490 | }, 491 | "flags": {}, 492 | "order": 2, 493 | "mode": 2, 494 | "outputs": [ 495 | { 496 | "name": "UPSCALE_MODEL", 497 | "type": "UPSCALE_MODEL", 498 | "links": [ 499 | 87 500 | ], 501 | "shape": 3, 502 | "slot_index": 0 503 | } 504 | ], 505 | "properties": { 506 | "Node name for S&R": "UpscaleModelLoader" 507 | }, 508 | "widgets_values": [ 509 | "4xLSDIRDAT.pth" 510 | ] 511 | }, 512 | { 513 | "id": 58, 514 | "type": "Note", 515 | "pos": [ 516 | 2011.3640068359373, 517 | 865.1400378417969 518 | ], 519 | "size": [ 520 | 220, 521 | 90 522 | ], 523 | "flags": {}, 524 | "order": 3, 525 | "mode": 0, 526 | "title": "Upsampling Notes", 527 | "properties": { 528 | "text": "" 529 | }, 530 | "widgets_values": [ 531 | "Upsampling is disabled by default. Once you have a base generation you're happy with, select the 3 grayed out nodes and do CTRL+M to \"unmute\" them." 532 | ], 533 | "color": "#432", 534 | "bgcolor": "#653" 535 | }, 536 | { 537 | "id": 35, 538 | "type": "PrimitiveNode", 539 | "pos": [ 540 | 1240, 541 | 610 542 | ], 543 | "size": { 544 | "0": 210, 545 | "1": 82 546 | }, 547 | "flags": {}, 548 | "order": 4, 549 | "mode": 0, 550 | "outputs": [ 551 | { 552 | "name": "INT", 553 | "type": "INT", 554 | "links": [ 555 | 58, 556 | 59, 557 | 84 558 | ], 559 | "slot_index": 0, 560 | "widget": { 561 | "name": "fps" 562 | } 563 | } 564 | ], 565 | "title": "FPS", 566 | "properties": {}, 567 | "widgets_values": [ 568 | 6, 569 | "fixed" 570 | ] 571 | }, 572 | { 573 | "id": 60, 574 | "type": "ImageGenResolutionFromImage", 575 | "pos": [ 576 | 824, 577 | 753 578 | ], 579 | "size": { 580 | "0": 355.20001220703125, 581 | "1": 46 582 | }, 583 | "flags": {}, 584 | "order": 7, 585 | "mode": 0, 586 | "inputs": [ 587 | { 588 | "name": "image", 589 | "type": "IMAGE", 590 | "link": 100, 591 | "slot_index": 0 592 | } 593 | ], 594 | "outputs": [ 595 | { 596 | "name": "IMAGE_GEN_WIDTH (INT)", 597 | "type": "INT", 598 | "links": [ 599 | 101 600 | ], 601 | "shape": 3, 602 | "slot_index": 0 603 | }, 604 | { 605 | "name": "IMAGE_GEN_HEIGHT (INT)", 606 | "type": "INT", 607 | "links": [ 608 | 102 609 | ], 610 | "shape": 3, 611 | "slot_index": 1 612 | } 613 | ], 614 | "properties": { 615 | "Node name for S&R": "ImageGenResolutionFromImage" 616 | } 617 | }, 618 | { 619 | "id": 59, 620 | "type": "LoadImage", 621 | "pos": [ 622 | 849, 623 | 404 624 | ], 625 | "size": [ 626 | 315, 627 | 314.0000305175781 628 | ], 629 | "flags": {}, 630 | "order": 5, 631 | "mode": 0, 632 | "outputs": [ 633 | { 634 | "name": "IMAGE", 635 | "type": "IMAGE", 636 | "links": [ 637 | 100, 638 | 103 639 | ], 640 | "shape": 3, 641 | "slot_index": 0 642 | }, 643 | { 644 | "name": "MASK", 645 | "type": "MASK", 646 | "links": null, 647 | "shape": 3 648 | } 649 | ], 650 | "properties": { 651 | "Node name for S&R": "LoadImage" 652 | }, 653 | "widgets_values": [ 654 | "maxresdefault-1605111824-hq-width-1024px.jpg", 655 | "image" 656 | ] 657 | } 658 | ], 659 | "links": [ 660 | [ 661 | 17, 662 | 12, 663 | 1, 664 | 3, 665 | 2, 666 | "CONDITIONING" 667 | ], 668 | [ 669 | 18, 670 | 12, 671 | 2, 672 | 3, 673 | 3, 674 | "LATENT" 675 | ], 676 | [ 677 | 23, 678 | 15, 679 | 0, 680 | 14, 681 | 0, 682 | "MODEL" 683 | ], 684 | [ 685 | 24, 686 | 15, 687 | 1, 688 | 12, 689 | 0, 690 | "CLIP_VISION" 691 | ], 692 | [ 693 | 25, 694 | 15, 695 | 2, 696 | 12, 697 | 2, 698 | "VAE" 699 | ], 700 | [ 701 | 39, 702 | 14, 703 | 0, 704 | 3, 705 | 0, 706 | "MODEL" 707 | ], 708 | [ 709 | 40, 710 | 12, 711 | 0, 712 | 3, 713 | 1, 714 | "CONDITIONING" 715 | ], 716 | [ 717 | 42, 718 | 8, 719 | 0, 720 | 24, 721 | 0, 722 | "IMAGE" 723 | ], 724 | [ 725 | 57, 726 | 34, 727 | 2, 728 | 8, 729 | 1, 730 | "VAE" 731 | ], 732 | [ 733 | 58, 734 | 35, 735 | 0, 736 | 12, 737 | 3, 738 | "INT" 739 | ], 740 | [ 741 | 59, 742 | 35, 743 | 0, 744 | 24, 745 | 1, 746 | "INT" 747 | ], 748 | [ 749 | 79, 750 | 3, 751 | 0, 752 | 8, 753 | 0, 754 | "LATENT" 755 | ], 756 | [ 757 | 84, 758 | 35, 759 | 0, 760 | 47, 761 | 1, 762 | "INT" 763 | ], 764 | [ 765 | 87, 766 | 50, 767 | 0, 768 | 53, 769 | 0, 770 | "UPSCALE_MODEL" 771 | ], 772 | [ 773 | 88, 774 | 8, 775 | 0, 776 | 53, 777 | 1, 778 | "IMAGE" 779 | ], 780 | [ 781 | 89, 782 | 53, 783 | 0, 784 | 47, 785 | 0, 786 | "IMAGE" 787 | ], 788 | [ 789 | 100, 790 | 59, 791 | 0, 792 | 60, 793 | 0, 794 | "IMAGE" 795 | ], 796 | [ 797 | 101, 798 | 60, 799 | 0, 800 | 12, 801 | 4, 802 | "INT" 803 | ], 804 | [ 805 | 102, 806 | 60, 807 | 1, 808 | 12, 809 | 5, 810 | "INT" 811 | ], 812 | [ 813 | 103, 814 | 59, 815 | 0, 816 | 12, 817 | 1, 818 | "IMAGE" 819 | ] 820 | ], 821 | "groups": [ 822 | { 823 | "title": "img2vid", 824 | "bounding": [ 825 | 800, 826 | 97, 827 | 1824, 828 | 1028 829 | ], 830 | "color": "#a1309b", 831 | "font_size": 24 832 | } 833 | ], 834 | "config": {}, 835 | "extra": {}, 836 | "version": 0.4 837 | } -------------------------------------------------------------------------------- /templates/upscale/launcher.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "workflow_json": { 4 | "last_node_id": 1098, 5 | "last_link_id": 2130, 6 | "nodes": [ 7 | { 8 | "id": 1070, 9 | "type": "VAELoader", 10 | "pos": [ 11 | 0, 12 | 590 13 | ], 14 | "size": { 15 | "0": 400, 16 | "1": 60 17 | }, 18 | "flags": {}, 19 | "order": 0, 20 | "mode": 0, 21 | "outputs": [ 22 | { 23 | "name": "VAE", 24 | "type": "VAE", 25 | "links": [ 26 | 2106, 27 | 2122, 28 | 2126 29 | ], 30 | "shape": 3, 31 | "label": "Vae" 32 | } 33 | ], 34 | "properties": { 35 | "Node name for S&R": "VAELoader" 36 | }, 37 | "widgets_values": [ 38 | "sdxl_vae.safetensors" 39 | ], 40 | "color": "#222", 41 | "bgcolor": "#000" 42 | }, 43 | { 44 | "id": 1081, 45 | "type": "UpscaleModelLoader", 46 | "pos": [ 47 | 0, 48 | 940 49 | ], 50 | "size": [ 51 | 400, 52 | 60 53 | ], 54 | "flags": {}, 55 | "order": 1, 56 | "mode": 0, 57 | "outputs": [ 58 | { 59 | "name": "UPSCALE_MODEL", 60 | "type": "UPSCALE_MODEL", 61 | "links": [ 62 | 2109 63 | ], 64 | "shape": 3, 65 | "label": "Upscale Model" 66 | } 67 | ], 68 | "properties": { 69 | "Node name for S&R": "UpscaleModelLoader" 70 | }, 71 | "widgets_values": [ 72 | "4x-UltraSharp.pth" 73 | ], 74 | "color": "#222", 75 | "bgcolor": "#000" 76 | }, 77 | { 78 | "id": 1078, 79 | "type": "EmptyLatentImage", 80 | "pos": [ 81 | 0, 82 | 790 83 | ], 84 | "size": [ 85 | 400, 86 | 110 87 | ], 88 | "flags": {}, 89 | "order": 2, 90 | "mode": 0, 91 | "outputs": [ 92 | { 93 | "name": "LATENT", 94 | "type": "LATENT", 95 | "links": [ 96 | 2104 97 | ], 98 | "shape": 3, 99 | "label": "Latent", 100 | "slot_index": 0 101 | } 102 | ], 103 | "properties": { 104 | "Node name for S&R": "EmptyLatentImage" 105 | }, 106 | "widgets_values": [ 107 | 1344, 108 | 768, 109 | 1 110 | ], 111 | "color": "#222", 112 | "bgcolor": "#000" 113 | }, 114 | { 115 | "id": 1065, 116 | "type": "PrimitiveNode", 117 | "pos": [ 118 | 0, 119 | 30 120 | ], 121 | "size": { 122 | "0": 400, 123 | "1": 170 124 | }, 125 | "flags": {}, 126 | "order": 3, 127 | "mode": 0, 128 | "outputs": [ 129 | { 130 | "name": "STRING", 131 | "type": "STRING", 132 | "links": [ 133 | 2093 134 | ], 135 | "widget": { 136 | "name": "text" 137 | }, 138 | "label": "+" 139 | } 140 | ], 141 | "title": "Positive Prompt", 142 | "properties": { 143 | "Run widget replace on values": false 144 | }, 145 | "widgets_values": [ 146 | "Fallen Angle" 147 | ], 148 | "color": "#222", 149 | "bgcolor": "#000" 150 | }, 151 | { 152 | "id": 1066, 153 | "type": "PrimitiveNode", 154 | "pos": [ 155 | 0, 156 | 240 157 | ], 158 | "size": { 159 | "0": 400, 160 | "1": 160 161 | }, 162 | "flags": {}, 163 | "order": 4, 164 | "mode": 0, 165 | "outputs": [ 166 | { 167 | "name": "STRING", 168 | "type": "STRING", 169 | "links": [ 170 | 2098 171 | ], 172 | "widget": { 173 | "name": "text" 174 | }, 175 | "label": "-", 176 | "slot_index": 0 177 | } 178 | ], 179 | "title": "Negative Prompt", 180 | "properties": { 181 | "Run widget replace on values": false 182 | }, 183 | "widgets_values": [ 184 | "" 185 | ], 186 | "color": "#222", 187 | "bgcolor": "#000" 188 | }, 189 | { 190 | "id": 1064, 191 | "type": "CLIPTextEncode", 192 | "pos": [ 193 | 420, 194 | 30 195 | ], 196 | "size": [ 197 | 400, 198 | 50 199 | ], 200 | "flags": { 201 | "collapsed": false 202 | }, 203 | "order": 10, 204 | "mode": 0, 205 | "inputs": [ 206 | { 207 | "name": "clip", 208 | "type": "CLIP", 209 | "link": 2097, 210 | "label": "Clip" 211 | }, 212 | { 213 | "name": "text", 214 | "type": "STRING", 215 | "link": 2093, 216 | "widget": { 217 | "name": "text" 218 | }, 219 | "slot_index": 1, 220 | "label": "+" 221 | } 222 | ], 223 | "outputs": [ 224 | { 225 | "name": "CONDITIONING", 226 | "type": "CONDITIONING", 227 | "links": [ 228 | 2101, 229 | 2116 230 | ], 231 | "shape": 3, 232 | "label": "+", 233 | "slot_index": 0 234 | } 235 | ], 236 | "title": "Clip Encode", 237 | "properties": { 238 | "Node name for S&R": "CLIPTextEncode" 239 | }, 240 | "widgets_values": [ 241 | "Fallen Angle" 242 | ], 243 | "color": "#222", 244 | "bgcolor": "#000" 245 | }, 246 | { 247 | "id": 1067, 248 | "type": "CLIPTextEncode", 249 | "pos": [ 250 | 420, 251 | 120 252 | ], 253 | "size": [ 254 | 400, 255 | 50 256 | ], 257 | "flags": { 258 | "collapsed": false 259 | }, 260 | "order": 9, 261 | "mode": 0, 262 | "inputs": [ 263 | { 264 | "name": "clip", 265 | "type": "CLIP", 266 | "link": 2096, 267 | "label": "Clip" 268 | }, 269 | { 270 | "name": "text", 271 | "type": "STRING", 272 | "link": 2098, 273 | "widget": { 274 | "name": "text" 275 | }, 276 | "slot_index": 1, 277 | "label": "-" 278 | } 279 | ], 280 | "outputs": [ 281 | { 282 | "name": "CONDITIONING", 283 | "type": "CONDITIONING", 284 | "links": [ 285 | 2102, 286 | 2117 287 | ], 288 | "shape": 3, 289 | "label": "-", 290 | "slot_index": 0 291 | } 292 | ], 293 | "title": "Clip Encode", 294 | "properties": { 295 | "Node name for S&R": "CLIPTextEncode" 296 | }, 297 | "widgets_values": [ 298 | "" 299 | ], 300 | "color": "#222", 301 | "bgcolor": "#000" 302 | }, 303 | { 304 | "id": 1073, 305 | "type": "ControlNetLoader", 306 | "pos": [ 307 | 0, 308 | 690 309 | ], 310 | "size": { 311 | "0": 400, 312 | "1": 60 313 | }, 314 | "flags": {}, 315 | "order": 5, 316 | "mode": 0, 317 | "outputs": [ 318 | { 319 | "name": "CONTROL_NET", 320 | "type": "CONTROL_NET", 321 | "links": [ 322 | 2120 323 | ], 324 | "shape": 3, 325 | "label": "ControlNet", 326 | "slot_index": 0 327 | } 328 | ], 329 | "properties": { 330 | "Node name for S&R": "ControlNetLoader" 331 | }, 332 | "widgets_values": [ 333 | "control-lora-depth-rank256.safetensors" 334 | ], 335 | "color": "#222", 336 | "bgcolor": "#000" 337 | }, 338 | { 339 | "id": 1097, 340 | "type": "VAEDecode", 341 | "pos": [ 342 | 840, 343 | 750 344 | ], 345 | "size": { 346 | "0": 400, 347 | "1": 50 348 | }, 349 | "flags": {}, 350 | "order": 21, 351 | "mode": 0, 352 | "inputs": [ 353 | { 354 | "name": "samples", 355 | "type": "LATENT", 356 | "link": 2125, 357 | "label": "Latent" 358 | }, 359 | { 360 | "name": "vae", 361 | "type": "VAE", 362 | "link": 2126, 363 | "label": "Vae", 364 | "slot_index": 1 365 | } 366 | ], 367 | "outputs": [ 368 | { 369 | "name": "IMAGE", 370 | "type": "IMAGE", 371 | "links": [ 372 | 2127 373 | ], 374 | "shape": 3, 375 | "label": "Image", 376 | "slot_index": 0 377 | } 378 | ], 379 | "properties": { 380 | "Node name for S&R": "VAEDecode" 381 | }, 382 | "color": "#222", 383 | "bgcolor": "#000" 384 | }, 385 | { 386 | "id": 1096, 387 | "type": "VAEEncode", 388 | "pos": [ 389 | 840, 390 | 30 391 | ], 392 | "size": [ 393 | 400, 394 | 50 395 | ], 396 | "flags": {}, 397 | "order": 16, 398 | "mode": 0, 399 | "inputs": [ 400 | { 401 | "name": "pixels", 402 | "type": "IMAGE", 403 | "link": 2121, 404 | "label": "Image" 405 | }, 406 | { 407 | "name": "vae", 408 | "type": "VAE", 409 | "link": 2122, 410 | "label": "Vae", 411 | "slot_index": 1 412 | } 413 | ], 414 | "outputs": [ 415 | { 416 | "name": "LATENT", 417 | "type": "LATENT", 418 | "links": [ 419 | 2123 420 | ], 421 | "shape": 3, 422 | "label": "Latent", 423 | "slot_index": 0 424 | } 425 | ], 426 | "properties": { 427 | "Node name for S&R": "VAEEncode" 428 | }, 429 | "color": "#222", 430 | "bgcolor": "#000" 431 | }, 432 | { 433 | "id": 1086, 434 | "type": "VAEDecode", 435 | "pos": [ 436 | 420, 437 | 520 438 | ], 439 | "size": [ 440 | 400, 441 | 50 442 | ], 443 | "flags": {}, 444 | "order": 12, 445 | "mode": 0, 446 | "inputs": [ 447 | { 448 | "name": "samples", 449 | "type": "LATENT", 450 | "link": 2105, 451 | "label": "Latent" 452 | }, 453 | { 454 | "name": "vae", 455 | "type": "VAE", 456 | "link": 2106, 457 | "label": "Vae", 458 | "slot_index": 1 459 | } 460 | ], 461 | "outputs": [ 462 | { 463 | "name": "IMAGE", 464 | "type": "IMAGE", 465 | "links": [ 466 | 2108 467 | ], 468 | "shape": 3, 469 | "label": "Image", 470 | "slot_index": 0 471 | } 472 | ], 473 | "properties": { 474 | "Node name for S&R": "VAEDecode" 475 | }, 476 | "color": "#222", 477 | "bgcolor": "#000" 478 | }, 479 | { 480 | "id": 1087, 481 | "type": "ImageUpscaleWithModel", 482 | "pos": [ 483 | 420, 484 | 610 485 | ], 486 | "size": [ 487 | 400, 488 | 60 489 | ], 490 | "flags": {}, 491 | "order": 13, 492 | "mode": 0, 493 | "inputs": [ 494 | { 495 | "name": "upscale_model", 496 | "type": "UPSCALE_MODEL", 497 | "link": 2109, 498 | "label": "Upscale Model", 499 | "slot_index": 0 500 | }, 501 | { 502 | "name": "image", 503 | "type": "IMAGE", 504 | "link": 2108, 505 | "label": "Image" 506 | } 507 | ], 508 | "outputs": [ 509 | { 510 | "name": "IMAGE", 511 | "type": "IMAGE", 512 | "links": [ 513 | 2110 514 | ], 515 | "shape": 3, 516 | "label": "Image", 517 | "slot_index": 0 518 | } 519 | ], 520 | "properties": { 521 | "Node name for S&R": "ImageUpscaleWithModel" 522 | }, 523 | "color": "#222", 524 | "bgcolor": "#000" 525 | }, 526 | { 527 | "id": 1090, 528 | "type": "PreviewImage", 529 | "pos": [ 530 | 420, 531 | 840 532 | ], 533 | "size": [ 534 | 400, 535 | 460 536 | ], 537 | "flags": {}, 538 | "order": 15, 539 | "mode": 0, 540 | "inputs": [ 541 | { 542 | "name": "images", 543 | "type": "IMAGE", 544 | "link": 2111, 545 | "label": "Image" 546 | } 547 | ], 548 | "properties": { 549 | "Node name for S&R": "PreviewImage" 550 | }, 551 | "color": "#222", 552 | "bgcolor": "#000" 553 | }, 554 | { 555 | "id": 1083, 556 | "type": "Note", 557 | "pos": [ 558 | 0, 559 | 1040 560 | ], 561 | "size": [ 562 | 400, 563 | 260 564 | ], 565 | "flags": {}, 566 | "order": 6, 567 | "mode": 0, 568 | "properties": { 569 | "text": "" 570 | }, 571 | "widgets_values": [ 572 | "→ CRTL-M to Mute Nodes\n\n→ CRTL-B to Bypass Nodes\n\n→ Ratios: \n 21 : 9 1536 x 640\n 19 : 9 1472 x 704\n 16 : 9 1344 x 768\n 3 : 2 1216 x 832\n 7 : 5 1176 x 840\n 4 : 3 1152 x 896\n 1 : 1 1024 x 1024\n\n " 573 | ], 574 | "color": "#222", 575 | "bgcolor": "#000" 576 | }, 577 | { 578 | "id": 1085, 579 | "type": "KSampler", 580 | "pos": [ 581 | 420, 582 | 210 583 | ], 584 | "size": [ 585 | 400, 586 | 270 587 | ], 588 | "flags": {}, 589 | "order": 11, 590 | "mode": 0, 591 | "inputs": [ 592 | { 593 | "name": "model", 594 | "type": "MODEL", 595 | "link": 2107, 596 | "label": "Model" 597 | }, 598 | { 599 | "name": "positive", 600 | "type": "CONDITIONING", 601 | "link": 2101, 602 | "label": "+" 603 | }, 604 | { 605 | "name": "negative", 606 | "type": "CONDITIONING", 607 | "link": 2102, 608 | "label": "-" 609 | }, 610 | { 611 | "name": "latent_image", 612 | "type": "LATENT", 613 | "link": 2104, 614 | "label": "Latent" 615 | } 616 | ], 617 | "outputs": [ 618 | { 619 | "name": "LATENT", 620 | "type": "LATENT", 621 | "links": [ 622 | 2105 623 | ], 624 | "shape": 3, 625 | "label": "Latent", 626 | "slot_index": 0 627 | } 628 | ], 629 | "properties": { 630 | "Node name for S&R": "KSampler" 631 | }, 632 | "widgets_values": [ 633 | 736246290988511, 634 | "fixed", 635 | 50, 636 | 8, 637 | "dpmpp_2m_sde_gpu", 638 | "karras", 639 | 1 640 | ], 641 | "color": "#222", 642 | "bgcolor": "#000" 643 | }, 644 | { 645 | "id": 1095, 646 | "type": "KSampler", 647 | "pos": [ 648 | 840, 649 | 450 650 | ], 651 | "size": { 652 | "0": 400, 653 | "1": 260 654 | }, 655 | "flags": {}, 656 | "order": 20, 657 | "mode": 0, 658 | "inputs": [ 659 | { 660 | "name": "model", 661 | "type": "MODEL", 662 | "link": 2115, 663 | "label": "Model" 664 | }, 665 | { 666 | "name": "positive", 667 | "type": "CONDITIONING", 668 | "link": 2118, 669 | "label": "+" 670 | }, 671 | { 672 | "name": "negative", 673 | "type": "CONDITIONING", 674 | "link": 2119, 675 | "label": "-" 676 | }, 677 | { 678 | "name": "latent_image", 679 | "type": "LATENT", 680 | "link": 2123, 681 | "label": "Latent" 682 | } 683 | ], 684 | "outputs": [ 685 | { 686 | "name": "LATENT", 687 | "type": "LATENT", 688 | "links": [ 689 | 2125 690 | ], 691 | "shape": 3, 692 | "label": "Latent", 693 | "slot_index": 0 694 | } 695 | ], 696 | "properties": { 697 | "Node name for S&R": "KSampler" 698 | }, 699 | "widgets_values": [ 700 | 736246290988511, 701 | "fixed", 702 | 30, 703 | 8, 704 | "dpmpp_2m_sde_gpu", 705 | "karras", 706 | 0.65 707 | ], 708 | "color": "#222", 709 | "bgcolor": "#000" 710 | }, 711 | { 712 | "id": 1094, 713 | "type": "ControlNetApplyAdvanced", 714 | "pos": [ 715 | 840, 716 | 240 717 | ], 718 | "size": [ 719 | 400, 720 | 170 721 | ], 722 | "flags": {}, 723 | "order": 18, 724 | "mode": 0, 725 | "inputs": [ 726 | { 727 | "name": "positive", 728 | "type": "CONDITIONING", 729 | "link": 2116, 730 | "label": "+" 731 | }, 732 | { 733 | "name": "negative", 734 | "type": "CONDITIONING", 735 | "link": 2117, 736 | "label": "-" 737 | }, 738 | { 739 | "name": "control_net", 740 | "type": "CONTROL_NET", 741 | "link": 2120, 742 | "label": "ControlNet" 743 | }, 744 | { 745 | "name": "image", 746 | "type": "IMAGE", 747 | "link": 2128, 748 | "label": "LineartImage" 749 | } 750 | ], 751 | "outputs": [ 752 | { 753 | "name": "positive", 754 | "type": "CONDITIONING", 755 | "links": [ 756 | 2118 757 | ], 758 | "shape": 3, 759 | "label": "+", 760 | "slot_index": 0 761 | }, 762 | { 763 | "name": "negative", 764 | "type": "CONDITIONING", 765 | "links": [ 766 | 2119 767 | ], 768 | "shape": 3, 769 | "label": "-", 770 | "slot_index": 1 771 | } 772 | ], 773 | "properties": { 774 | "Node name for S&R": "ControlNetApplyAdvanced" 775 | }, 776 | "widgets_values": [ 777 | 0.85, 778 | 0, 779 | 0.75 780 | ], 781 | "color": "#222", 782 | "bgcolor": "#000" 783 | }, 784 | { 785 | "id": 1068, 786 | "type": "CheckpointLoaderSimple", 787 | "pos": [ 788 | 0, 789 | 440 790 | ], 791 | "size": { 792 | "0": 400, 793 | "1": 100 794 | }, 795 | "flags": {}, 796 | "order": 8, 797 | "mode": 0, 798 | "inputs": [ 799 | { 800 | "name": "ckpt_name", 801 | "type": "COMBO", 802 | "link": 2095, 803 | "widget": { 804 | "name": "ckpt_name" 805 | }, 806 | "slot_index": 0, 807 | "label": "Ckpt Name" 808 | } 809 | ], 810 | "outputs": [ 811 | { 812 | "name": "MODEL", 813 | "type": "MODEL", 814 | "links": [ 815 | 2107, 816 | 2115 817 | ], 818 | "shape": 3, 819 | "label": "Model", 820 | "slot_index": 0 821 | }, 822 | { 823 | "name": "CLIP", 824 | "type": "CLIP", 825 | "links": [ 826 | 2096, 827 | 2097 828 | ], 829 | "shape": 3, 830 | "label": "Clip", 831 | "slot_index": 1 832 | }, 833 | { 834 | "name": "VAE", 835 | "type": "VAE", 836 | "links": null, 837 | "shape": 3, 838 | "label": "Vae" 839 | } 840 | ], 841 | "properties": { 842 | "Node name for S&R": "CheckpointLoaderSimple" 843 | }, 844 | "widgets_values": [ 845 | "juggernautXL_v9Rundiffusionphoto2.safetensors" 846 | ], 847 | "color": "#222", 848 | "bgcolor": "#000" 849 | }, 850 | { 851 | "id": 1069, 852 | "type": "PrimitiveNode", 853 | "pos": [ 854 | 0, 855 | 440 856 | ], 857 | "size": [ 858 | 400, 859 | 110 860 | ], 861 | "flags": { 862 | "collapsed": false 863 | }, 864 | "order": 7, 865 | "mode": 0, 866 | "outputs": [ 867 | { 868 | "name": "COMBO", 869 | "type": "COMBO", 870 | "links": [ 871 | 2095 872 | ], 873 | "widget": { 874 | "name": "ckpt_name" 875 | }, 876 | "label": "Ckpt Name" 877 | } 878 | ], 879 | "title": "Checkpoint Name                                 ", 880 | "properties": { 881 | "Run widget replace on values": false 882 | }, 883 | "widgets_values": [ 884 | "juggernautXL_v9Rundiffusionphoto2.safetensors", 885 | "fixed", 886 | "v" 887 | ], 888 | "color": "#222", 889 | "bgcolor": "#000" 890 | }, 891 | { 892 | "id": 1093, 893 | "type": "PreviewImage", 894 | "pos": [ 895 | 840, 896 | 840 897 | ], 898 | "size": [ 899 | 400, 900 | 460 901 | ], 902 | "flags": {}, 903 | "order": 19, 904 | "mode": 0, 905 | "inputs": [ 906 | { 907 | "name": "images", 908 | "type": "IMAGE", 909 | "link": 2129, 910 | "label": "Image", 911 | "slot_index": 0 912 | } 913 | ], 914 | "properties": { 915 | "Node name for S&R": "PreviewImage" 916 | }, 917 | "color": "#222", 918 | "bgcolor": "#000" 919 | }, 920 | { 921 | "id": 1098, 922 | "type": "SaveImage", 923 | "pos": [ 924 | 1260, 925 | 30 926 | ], 927 | "size": [ 928 | 1290, 929 | 1270 930 | ], 931 | "flags": {}, 932 | "order": 22, 933 | "mode": 0, 934 | "inputs": [ 935 | { 936 | "name": "images", 937 | "type": "IMAGE", 938 | "link": 2127, 939 | "slot_index": 0, 940 | "label": "Iamge" 941 | } 942 | ], 943 | "properties": {}, 944 | "widgets_values": [ 945 | "%date:MM-dd hh mm ss% - Model-%CheckpointLoaderSimple.ckpt_name%" 946 | ], 947 | "color": "#222", 948 | "bgcolor": "#000" 949 | }, 950 | { 951 | "id": 1092, 952 | "type": "Canny", 953 | "pos": [ 954 | 839, 955 | 120 956 | ], 957 | "size": [ 958 | 400, 959 | 80 960 | ], 961 | "flags": {}, 962 | "order": 17, 963 | "mode": 0, 964 | "inputs": [ 965 | { 966 | "name": "image", 967 | "type": "IMAGE", 968 | "link": 2130, 969 | "label": "Image" 970 | } 971 | ], 972 | "outputs": [ 973 | { 974 | "name": "IMAGE", 975 | "type": "IMAGE", 976 | "links": [ 977 | 2128, 978 | 2129 979 | ], 980 | "shape": 3, 981 | "slot_index": 0, 982 | "label": "LineartImage" 983 | } 984 | ], 985 | "properties": { 986 | "Node name for S&R": "Canny" 987 | }, 988 | "widgets_values": [ 989 | 0.15, 990 | 0.4 991 | ], 992 | "color": "#222", 993 | "bgcolor": "#000" 994 | }, 995 | { 996 | "id": 1089, 997 | "type": "ImageScaleBy", 998 | "pos": [ 999 | 420, 1000 | 710 1001 | ], 1002 | "size": [ 1003 | 400, 1004 | 90 1005 | ], 1006 | "flags": {}, 1007 | "order": 14, 1008 | "mode": 0, 1009 | "inputs": [ 1010 | { 1011 | "name": "image", 1012 | "type": "IMAGE", 1013 | "link": 2110, 1014 | "label": "Image" 1015 | } 1016 | ], 1017 | "outputs": [ 1018 | { 1019 | "name": "IMAGE", 1020 | "type": "IMAGE", 1021 | "links": [ 1022 | 2111, 1023 | 2121, 1024 | 2130 1025 | ], 1026 | "shape": 3, 1027 | "label": "Image", 1028 | "slot_index": 0 1029 | } 1030 | ], 1031 | "properties": { 1032 | "Node name for S&R": "ImageScaleBy" 1033 | }, 1034 | "widgets_values": [ 1035 | "nearest-exact", 1036 | 0.5 1037 | ], 1038 | "color": "#222", 1039 | "bgcolor": "#000" 1040 | } 1041 | ], 1042 | "links": [ 1043 | [ 1044 | 2093, 1045 | 1065, 1046 | 0, 1047 | 1064, 1048 | 1, 1049 | "STRING" 1050 | ], 1051 | [ 1052 | 2095, 1053 | 1069, 1054 | 0, 1055 | 1068, 1056 | 0, 1057 | "COMBO" 1058 | ], 1059 | [ 1060 | 2096, 1061 | 1068, 1062 | 1, 1063 | 1067, 1064 | 0, 1065 | "CLIP" 1066 | ], 1067 | [ 1068 | 2097, 1069 | 1068, 1070 | 1, 1071 | 1064, 1072 | 0, 1073 | "CLIP" 1074 | ], 1075 | [ 1076 | 2098, 1077 | 1066, 1078 | 0, 1079 | 1067, 1080 | 1, 1081 | "STRING" 1082 | ], 1083 | [ 1084 | 2101, 1085 | 1064, 1086 | 0, 1087 | 1085, 1088 | 1, 1089 | "CONDITIONING" 1090 | ], 1091 | [ 1092 | 2102, 1093 | 1067, 1094 | 0, 1095 | 1085, 1096 | 2, 1097 | "CONDITIONING" 1098 | ], 1099 | [ 1100 | 2104, 1101 | 1078, 1102 | 0, 1103 | 1085, 1104 | 3, 1105 | "LATENT" 1106 | ], 1107 | [ 1108 | 2105, 1109 | 1085, 1110 | 0, 1111 | 1086, 1112 | 0, 1113 | "LATENT" 1114 | ], 1115 | [ 1116 | 2106, 1117 | 1070, 1118 | 0, 1119 | 1086, 1120 | 1, 1121 | "VAE" 1122 | ], 1123 | [ 1124 | 2107, 1125 | 1068, 1126 | 0, 1127 | 1085, 1128 | 0, 1129 | "MODEL" 1130 | ], 1131 | [ 1132 | 2108, 1133 | 1086, 1134 | 0, 1135 | 1087, 1136 | 1, 1137 | "IMAGE" 1138 | ], 1139 | [ 1140 | 2109, 1141 | 1081, 1142 | 0, 1143 | 1087, 1144 | 0, 1145 | "UPSCALE_MODEL" 1146 | ], 1147 | [ 1148 | 2110, 1149 | 1087, 1150 | 0, 1151 | 1089, 1152 | 0, 1153 | "IMAGE" 1154 | ], 1155 | [ 1156 | 2111, 1157 | 1089, 1158 | 0, 1159 | 1090, 1160 | 0, 1161 | "IMAGE" 1162 | ], 1163 | [ 1164 | 2115, 1165 | 1068, 1166 | 0, 1167 | 1095, 1168 | 0, 1169 | "MODEL" 1170 | ], 1171 | [ 1172 | 2116, 1173 | 1064, 1174 | 0, 1175 | 1094, 1176 | 0, 1177 | "CONDITIONING" 1178 | ], 1179 | [ 1180 | 2117, 1181 | 1067, 1182 | 0, 1183 | 1094, 1184 | 1, 1185 | "CONDITIONING" 1186 | ], 1187 | [ 1188 | 2118, 1189 | 1094, 1190 | 0, 1191 | 1095, 1192 | 1, 1193 | "CONDITIONING" 1194 | ], 1195 | [ 1196 | 2119, 1197 | 1094, 1198 | 1, 1199 | 1095, 1200 | 2, 1201 | "CONDITIONING" 1202 | ], 1203 | [ 1204 | 2120, 1205 | 1073, 1206 | 0, 1207 | 1094, 1208 | 2, 1209 | "CONTROL_NET" 1210 | ], 1211 | [ 1212 | 2121, 1213 | 1089, 1214 | 0, 1215 | 1096, 1216 | 0, 1217 | "IMAGE" 1218 | ], 1219 | [ 1220 | 2122, 1221 | 1070, 1222 | 0, 1223 | 1096, 1224 | 1, 1225 | "VAE" 1226 | ], 1227 | [ 1228 | 2123, 1229 | 1096, 1230 | 0, 1231 | 1095, 1232 | 3, 1233 | "LATENT" 1234 | ], 1235 | [ 1236 | 2125, 1237 | 1095, 1238 | 0, 1239 | 1097, 1240 | 0, 1241 | "LATENT" 1242 | ], 1243 | [ 1244 | 2126, 1245 | 1070, 1246 | 0, 1247 | 1097, 1248 | 1, 1249 | "VAE" 1250 | ], 1251 | [ 1252 | 2127, 1253 | 1097, 1254 | 0, 1255 | 1098, 1256 | 0, 1257 | "IMAGE" 1258 | ], 1259 | [ 1260 | 2128, 1261 | 1092, 1262 | 0, 1263 | 1094, 1264 | 3, 1265 | "IMAGE" 1266 | ], 1267 | [ 1268 | 2129, 1269 | 1092, 1270 | 0, 1271 | 1093, 1272 | 0, 1273 | "IMAGE" 1274 | ], 1275 | [ 1276 | 2130, 1277 | 1089, 1278 | 0, 1279 | 1092, 1280 | 0, 1281 | "IMAGE" 1282 | ] 1283 | ], 1284 | "groups": [], 1285 | "config": {}, 1286 | "extra": {}, 1287 | "version": 0.4 1288 | }, 1289 | "snapshot_json": { 1290 | "comfyui": null, 1291 | "git_custom_nodes": {} 1292 | }, 1293 | "files": [ 1294 | [ 1295 | { 1296 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/51672212/download", 1297 | "dest_relative_path": "models/vae/sdxl_vae.safetensors", 1298 | "sha256_checksum": "235745af8d86bf4a4c1b5b4f529868b37019a10f7c0b2e79ad0abca3a22bc6e1", 1299 | "size": 334641162 1300 | }, 1301 | { 1302 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/c/4238398/download", 1303 | "dest_relative_path": "models/vae/sdxl_vae.safetensors", 1304 | "sha256_checksum": "63aeecb90ff7bc1c115395962d3e803571385b61938377bc7089b36e81e92e2e", 1305 | "size": 334641152 1306 | } 1307 | ], 1308 | [ 1309 | { 1310 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/1106255/download", 1311 | "dest_relative_path": "models/upscale_models/4x-UltraSharp.pth", 1312 | "sha256_checksum": "a5812231fc936b42af08a5edba784195495d303d5b3248c24489ef0c4021fe01", 1313 | "size": 66961958 1314 | } 1315 | ], 1316 | [ 1317 | { 1318 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/1133434/download", 1319 | "dest_relative_path": "models/controlnet/control-lora-depth-rank256.safetensors", 1320 | "sha256_checksum": "559d2468951bf254c13bacd9c5d05d01ad67b060f6a73e8131d26ebf459c1c79", 1321 | "size": 774445779 1322 | } 1323 | ], 1324 | [ 1325 | { 1326 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/h/49467957/download", 1327 | "dest_relative_path": "models/checkpoints/juggernautXL_v9Rundiffusionphoto2.safetensors", 1328 | "sha256_checksum": "c9e3e68f89b8e38689e1097d4be4573cf308de4e3fd044c64ca697bdb4aa8bca", 1329 | "size": 7105348188 1330 | }, 1331 | { 1332 | "download_url": "https://comfyworkflows.com/api/comfyui-launcher/files/c/3913898/download", 1333 | "dest_relative_path": "models/checkpoints/juggernautXL_v9Rundiffusionphoto2.safetensors", 1334 | "sha256_checksum": "c9e3e68f89b8e38689e1097d4be4573cf308de4e3fd044c64ca697bdb4aa8bca", 1335 | "size": 7105351680 1336 | } 1337 | ] 1338 | ], 1339 | "pip_requirements": [], 1340 | "os": {}, 1341 | "python_version": {} 1342 | } 1343 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import shutil 4 | import socket 5 | import requests 6 | import hashlib 7 | import unicodedata 8 | import re 9 | import subprocess 10 | import threading 11 | from tqdm import tqdm 12 | from urllib.parse import urlparse 13 | from settings import PROJECT_MAX_PORT, PROJECT_MIN_PORT, PROJECTS_DIR, CONFIG_FILEPATH 14 | 15 | def check_url_structure(url): 16 | # Check for huggingface.co URL structure 17 | huggingface_pattern = r'^https://huggingface\.co/[\w-]+/[\w-]+/blob/[\w-]+\.(safetensors|bin|ckpt)$' 18 | if re.match(huggingface_pattern, url): 19 | return True 20 | 21 | # Check for civitai.com URL structure 22 | civitai_pattern = r'^https://civitai\.com/models/\d+$' 23 | if re.match(civitai_pattern, url): 24 | return True 25 | 26 | return False 27 | 28 | def slugify(value, allow_unicode=False): 29 | """ 30 | Taken from https://github.com/django/django/blob/master/django/utils/text.py 31 | Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated 32 | dashes to single dashes. Remove characters that aren't alphanumerics, 33 | underscores, or hyphens. Convert to lowercase. Also strip leading and 34 | trailing whitespace, dashes, and underscores. 35 | """ 36 | value = str(value) 37 | if allow_unicode: 38 | value = unicodedata.normalize('NFKC', value) 39 | else: 40 | value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii') 41 | value = re.sub(r'[^\w\s-]', '', value.lower()) 42 | return re.sub(r'[-\s]+', '-', value).strip('-_') 43 | 44 | 45 | COMFYUI_REPO_URL = "https://github.com/comfyanonymous/ComfyUI.git" 46 | 47 | MAX_DOWNLOAD_ATTEMPTS = 3 48 | 49 | CUSTOM_NODES_TO_IGNORE_FROM_SNAPSHOTS = ["ComfyUI-ComfyWorkflows", "ComfyUI-Manager"] 50 | 51 | CW_ENDPOINT = os.environ.get("CW_ENDPOINT", "https://comfyworkflows.com") 52 | 53 | # Use the already defined CONFIG_FILEPATH from settings.py 54 | # CONFIG_FILEPATH is now imported from settings.py 55 | 56 | # Define the default configuration with all settings 57 | DEFAULT_CONFIG = { 58 | "credentials": { 59 | "civitai": { 60 | "apikey": "" 61 | } 62 | }, 63 | "directories": { 64 | "projects": "./projects", 65 | "models": "./models", 66 | "templates": "./templates" 67 | }, 68 | "port_configuration": { 69 | "allow_overridable_ports": True, 70 | "project_min_port": 4001, 71 | "project_max_port": 4100, 72 | "server_port": 8501 73 | } 74 | } 75 | 76 | import os 77 | from typing import List, Dict, Optional, Union 78 | import json 79 | 80 | class ModelFileWithNodeInfo: 81 | def __init__(self, filename: str, original_filepath: str, normalized_filepath: str): 82 | self.filename = filename 83 | self.original_filepath = original_filepath 84 | self.normalized_filepath = normalized_filepath 85 | 86 | def convert_to_unix_path(path: str) -> str: 87 | return path.replace("\\\\", "/").replace("\\", "/") 88 | 89 | def convert_to_windows_path(path: str) -> str: 90 | return path.replace("/", "\\") 91 | 92 | def extract_model_file_names_with_node_info(json_data: Union[Dict, List], is_windows: bool = False) -> List[ModelFileWithNodeInfo]: 93 | file_names = [] 94 | model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'} 95 | 96 | def recursive_search(data: Union[Dict, List, str], in_nodes: bool, node_type: Optional[str]): 97 | if isinstance(data, dict): 98 | for key, value in data.items(): 99 | type_ = value.get('type') if isinstance(value, dict) else None 100 | recursive_search(value, key == 'nodes' if not in_nodes else in_nodes, type_ if in_nodes and not node_type else node_type) 101 | elif isinstance(data, list): 102 | for item in data: 103 | type_ = item.get('type') if isinstance(item, dict) else None 104 | recursive_search(item, in_nodes, type_ if in_nodes and not node_type else node_type) 105 | elif isinstance(data, str) and '.' in data: 106 | original_filepath = data 107 | normalized_filepath = convert_to_windows_path(original_filepath) if is_windows else convert_to_unix_path(original_filepath) 108 | filename = os.path.basename(data) 109 | 110 | if '.' + original_filepath.split('.')[-1] in model_filename_extensions: 111 | file_names.append(ModelFileWithNodeInfo(filename, original_filepath, normalized_filepath)) 112 | 113 | recursive_search(json_data, False, None) 114 | return file_names 115 | 116 | 117 | def print_process_output(process): 118 | for line in iter(process.stdout.readline, b''): 119 | print(line.decode(), end='') 120 | process.stdout.close() 121 | 122 | def run_command(cmd: List[str], cwd: Optional[str] = None, bg: bool = False) -> None: 123 | process = subprocess.Popen(" ".join(cmd), cwd=cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 124 | 125 | if bg: 126 | # Create a separate thread to handle the printing of the process's output 127 | threading.Thread(target=print_process_output, args=(process,), daemon=True).start() 128 | return process.pid 129 | else: 130 | print_process_output(process) 131 | assert process.wait() == 0 132 | 133 | def get_ckpt_names_with_node_info(workflow_json: Union[Dict, List], is_windows: bool) -> List[ModelFileWithNodeInfo]: 134 | ckpt_names = [] 135 | if isinstance(workflow_json, dict): 136 | ckpt_names = extract_model_file_names_with_node_info(workflow_json, is_windows) 137 | elif isinstance(workflow_json, list): 138 | for item in workflow_json: 139 | ckpt_names.extend(get_ckpt_names_with_node_info(item, is_windows)) 140 | return ckpt_names 141 | 142 | def normalize_model_filepaths_in_workflow_json(workflow_json: dict) -> dict: 143 | is_windows = os.name == "nt" 144 | ckpt_names = get_ckpt_names_with_node_info(workflow_json, is_windows) 145 | for ckpt_name in ckpt_names: 146 | workflow_json = json.dumps(workflow_json).replace(ckpt_name.original_filepath.replace("\\", "\\\\"), ckpt_name.normalized_filepath.replace("\\", "\\\\")) 147 | workflow_json = json.loads(workflow_json) 148 | return workflow_json 149 | 150 | 151 | def run_command_in_project_venv(project_folder_path, command): 152 | if os.name == "nt": # Check if running on Windows 153 | venv_activate = os.path.join(project_folder_path, "venv", "Scripts", "activate.bat") 154 | else: 155 | venv_activate = os.path.join(project_folder_path, "venv", "bin", "activate") 156 | 157 | assert os.path.exists(venv_activate), f"Virtualenv does not exist in project folder: {project_folder_path}" 158 | 159 | if os.name == "nt": 160 | command = ["call", venv_activate, "&&", command] 161 | else: 162 | command = [".", venv_activate, "&&", command] 163 | 164 | # Run the command using subprocess and capture stdout 165 | run_command(command) 166 | 167 | def run_command_in_project_comfyui_venv(project_folder_path, command, in_bg=False): 168 | venv_activate = os.path.join(project_folder_path, "venv", "Scripts", "activate.bat") if os.name == "nt" else os.path.join(project_folder_path, "venv", "bin", "activate") 169 | comfyui_dir = os.path.join(project_folder_path, "comfyui") 170 | 171 | assert os.path.exists(venv_activate), f"Virtualenv does not exist in project folder: {project_folder_path}" 172 | 173 | if os.name == "nt": 174 | return run_command([venv_activate, "&&", "cd", comfyui_dir, "&&", command], bg=in_bg) 175 | else: 176 | return run_command([".", venv_activate, "&&", "cd", comfyui_dir, "&&", command], bg=in_bg) 177 | 178 | 179 | def install_default_custom_nodes(project_folder_path, launcher_json=None): 180 | # install default custom nodes 181 | # comfyui-manager 182 | run_command(["git", "clone", f"https://github.com/ltdrdata/ComfyUI-Manager", os.path.join(project_folder_path, 'comfyui', 'custom_nodes', 'ComfyUI-Manager')]) 183 | 184 | # pip install comfyui-manager 185 | run_command_in_project_venv( 186 | project_folder_path, 187 | f"pip install -r {os.path.join(project_folder_path, 'comfyui', 'custom_nodes', 'ComfyUI-Manager', 'requirements.txt')}", 188 | ) 189 | 190 | run_command(["git", "clone", f"https://github.com/thecooltechguy/ComfyUI-ComfyWorkflows", os.path.join(project_folder_path, 'comfyui', 'custom_nodes', 'ComfyUI-ComfyWorkflows')]) 191 | 192 | # pip install comfyui-comfyworkflows 193 | run_command_in_project_venv( 194 | project_folder_path, 195 | f"pip install -r {os.path.join(project_folder_path, 'comfyui', 'custom_nodes', 'ComfyUI-ComfyWorkflows', 'requirements.txt')}", 196 | ) 197 | 198 | def setup_initial_models_folder(models_folder_path): 199 | assert not os.path.exists( 200 | models_folder_path 201 | ), f"Models folder already exists: {models_folder_path}" 202 | 203 | tmp_dir = os.path.join(os.path.dirname(models_folder_path), "tmp_comfyui") 204 | run_command(["git", "clone", COMFYUI_REPO_URL, tmp_dir]) 205 | 206 | shutil.move(os.path.join(tmp_dir, "models"), models_folder_path) 207 | shutil.rmtree(tmp_dir) 208 | 209 | 210 | def is_launcher_json_format(import_json): 211 | if "format" in import_json and import_json["format"] == "comfyui_launcher": 212 | return True 213 | return False 214 | 215 | def setup_custom_nodes_from_snapshot(project_folder_path, launcher_json): 216 | if not launcher_json: 217 | return 218 | for custom_node_repo_url, custom_node_repo_info in launcher_json["snapshot_json"][ 219 | "git_custom_nodes" 220 | ].items(): 221 | if any( 222 | [ 223 | custom_node_to_ignore in custom_node_repo_url 224 | for custom_node_to_ignore in CUSTOM_NODES_TO_IGNORE_FROM_SNAPSHOTS 225 | ] 226 | ): 227 | continue 228 | 229 | custom_node_hash = custom_node_repo_info["hash"] 230 | custom_node_disabled = custom_node_repo_info["disabled"] 231 | if custom_node_disabled: 232 | continue 233 | custom_node_name = custom_node_repo_url.split("/")[-1].replace(".git", "") 234 | custom_node_path = os.path.join( 235 | project_folder_path, "comfyui", "custom_nodes", custom_node_name 236 | ) 237 | 238 | # Clone the custom node repository 239 | run_command(["git", "clone", custom_node_repo_url, custom_node_path, "--recursive"]) 240 | 241 | if custom_node_hash: 242 | # Checkout the specific hash 243 | run_command(["git", "checkout", custom_node_hash], cwd=custom_node_path) 244 | 245 | pip_requirements_path = os.path.join(custom_node_path, "requirements.txt") 246 | if os.path.exists(pip_requirements_path): 247 | run_command_in_project_venv( 248 | project_folder_path, 249 | f"pip install -r {os.path.join(custom_node_path, 'requirements.txt')}", 250 | ) 251 | 252 | pip_requirements_post_path = os.path.join(custom_node_path, "requirements_post.txt") 253 | if os.path.exists(pip_requirements_post_path): 254 | run_command_in_project_venv( 255 | project_folder_path, 256 | f"pip install -r {os.path.join(custom_node_path, 'requirements_post.txt')}", 257 | ) 258 | 259 | install_script_path = os.path.join(custom_node_path, "install.py") 260 | if os.path.exists(install_script_path): 261 | run_command_in_project_venv(project_folder_path, f"python {install_script_path}") 262 | 263 | # for ComfyUI-CLIPSeg, we need to separately copy the clipseg.py file from ComfyUI-CLIPSeg/custom_nodes into `project_folder_path/comfyui/custom_nodes 264 | if custom_node_name == "ComfyUI-CLIPSeg": 265 | clipseg_custom_node_file_path = os.path.join(custom_node_path, "custom_nodes", "clipseg.py") 266 | shutil.copy(clipseg_custom_node_file_path, os.path.join(project_folder_path, "comfyui", "custom_nodes", "clipseg.py")) 267 | 268 | def compute_sha256_checksum(file_path): 269 | buf_size = 1024 270 | sha256 = hashlib.sha256() 271 | with open(file_path, "rb") as f: 272 | while True: 273 | data = f.read(buf_size) 274 | if not data: 275 | break 276 | sha256.update(data) 277 | return sha256.hexdigest().lower() 278 | 279 | def get_config(): 280 | """ 281 | Get the configuration from config.json, creating it with default values if it doesn't exist. 282 | 283 | Returns: 284 | dict: The configuration dictionary 285 | """ 286 | try: 287 | # Ensure the directory exists 288 | os.makedirs(os.path.dirname(CONFIG_FILEPATH), exist_ok=True) 289 | 290 | if os.path.exists(CONFIG_FILEPATH): 291 | with open(CONFIG_FILEPATH, "r") as f: 292 | config = json.load(f) 293 | return config 294 | else: 295 | # If file doesn't exist, create with defaults and return defaults 296 | with open(CONFIG_FILEPATH, "w") as f: 297 | json.dump(DEFAULT_CONFIG, f, indent=2) 298 | return DEFAULT_CONFIG.copy() 299 | except (FileNotFoundError, json.JSONDecodeError, PermissionError) as e: 300 | print(f"Warning: Could not load config file: {e}") 301 | # Create with defaults as fallback 302 | try: 303 | with open(CONFIG_FILEPATH, "w") as f: 304 | json.dump(DEFAULT_CONFIG, f, indent=2) 305 | except Exception as e: 306 | print(f"Error: Could not create config file: {e}") 307 | return DEFAULT_CONFIG.copy() 308 | 309 | def update_config(config_update): 310 | """ 311 | Update the configuration, merging with existing values 312 | 313 | Args: 314 | config_update (dict): Dictionary containing configuration updates 315 | 316 | Returns: 317 | dict: The updated configuration dictionary 318 | """ 319 | try: 320 | config = get_config() 321 | except Exception: 322 | config = DEFAULT_CONFIG.copy() 323 | 324 | # Deep merge the update with existing config 325 | def deep_merge(base, update): 326 | for key, value in update.items(): 327 | if key in base and isinstance(base[key], dict) and isinstance(value, dict): 328 | deep_merge(base[key], value) 329 | else: 330 | base[key] = value 331 | 332 | deep_merge(config, config_update) 333 | set_config(config) 334 | return config 335 | 336 | def set_config(config): 337 | """ 338 | Save the configuration to config.json 339 | 340 | Args: 341 | config (dict): The configuration dictionary to save 342 | """ 343 | try: 344 | # Ensure the directory exists 345 | os.makedirs(os.path.dirname(CONFIG_FILEPATH), exist_ok=True) 346 | with open(CONFIG_FILEPATH, "w") as f: 347 | json.dump(config, f, indent=2) 348 | except Exception as e: 349 | print(f"Error: Could not save config file: {e}") 350 | 351 | def setup_files_from_launcher_json(project_folder_path, launcher_json): 352 | if not launcher_json: 353 | return 354 | 355 | missing_download_files = set() 356 | config = get_config() 357 | 358 | # download all necessary files 359 | for file_infos in launcher_json["files"]: 360 | downloaded_file = False 361 | # try each source for the file until one works 362 | for file_info in file_infos: 363 | if downloaded_file: 364 | break 365 | cw_file_download_url = file_info["download_url"] 366 | dest_relative_path = file_info["dest_relative_path"] 367 | sha256_checksum = file_info["sha256_checksum"].lower() 368 | 369 | if not cw_file_download_url: 370 | print(f"WARNING: Could not find download URL for: {dest_relative_path}") 371 | missing_download_files.add(dest_relative_path) 372 | continue 373 | 374 | dest_path = os.path.join(project_folder_path, "comfyui", dest_relative_path) 375 | if os.path.exists(dest_path): 376 | if compute_sha256_checksum(dest_path) != sha256_checksum: 377 | old_dest_filename = os.path.basename(dest_path) 378 | new_dest_path = generate_incrementing_filename(dest_path) 379 | print(f"WARNING: File '{dest_relative_path}' already exists and has a different checksum, so renaming new file to: {new_dest_path}") 380 | dest_path = new_dest_path 381 | new_dest_filename = os.path.basename(new_dest_path) 382 | # we auto-rename the file in the launcher json to match the new filename, so that the user doesn't have to manually update the launcher/workflow json 383 | # TODO: Later, we need to update this to only replace the filename within its specific node type (since multiple nodes can refer to a common filename, but they would be different files) 384 | rename_file_in_launcher_json(launcher_json, old_dest_filename, new_dest_filename) 385 | else: 386 | print(f"File already exists: {dest_path}, so skipping download.") 387 | downloaded_file = True 388 | break 389 | 390 | os.makedirs(os.path.dirname(dest_path), exist_ok=True) 391 | 392 | num_attempts = 0 393 | download_successful = False 394 | 395 | print(f"Downloading file for: {dest_path}") 396 | 397 | if "/comfyui-launcher/" in cw_file_download_url: 398 | response = requests.get(cw_file_download_url) 399 | response.raise_for_status() 400 | response_json = response.json() 401 | download_urls = response_json["urls"] 402 | else: 403 | download_urls = [cw_file_download_url,] 404 | 405 | for download_url in download_urls: 406 | if download_successful: 407 | break 408 | num_attempts = 0 409 | while num_attempts < MAX_DOWNLOAD_ATTEMPTS: 410 | try: 411 | headers = {} 412 | 413 | # parse the url to get the host using 414 | hostname = urlparse(download_url).hostname 415 | if hostname == "civitai.com": 416 | headers["Authorization"] = f"Bearer {config['credentials']['civitai']['apikey']}" 417 | 418 | with requests.get( 419 | download_url, headers=headers, allow_redirects=True, stream=True 420 | ) as response: 421 | total_size = int(response.headers.get("content-length", 0)) 422 | with tqdm(total=total_size, unit="B", unit_scale=True) as pb: 423 | with open(dest_path, "wb") as f: 424 | for chunk in response.iter_content(chunk_size=10 * 1024): 425 | pb.update(len(chunk)) 426 | if chunk: 427 | f.write(chunk) 428 | if compute_sha256_checksum(dest_path) == sha256_checksum: 429 | download_successful = True 430 | if dest_relative_path in missing_download_files: 431 | missing_download_files.remove(dest_relative_path) 432 | break 433 | if os.path.exists(dest_path): 434 | os.remove(dest_path) 435 | except Exception as e: 436 | import traceback 437 | traceback.print_exc() 438 | if os.path.exists(dest_path): 439 | os.remove(dest_path) 440 | num_attempts += 1 441 | 442 | if not download_successful: 443 | print(f"WARNING: Failed to download file for: {dest_relative_path}") 444 | missing_download_files.add(dest_relative_path) 445 | continue 446 | 447 | downloaded_file = True 448 | break 449 | 450 | if not downloaded_file: 451 | print(f"WARNING: Failed to download file: {dest_relative_path}") 452 | missing_download_files.add(dest_relative_path) 453 | else: 454 | print(f"SUCCESS: Downloaded: {dest_relative_path}") 455 | return missing_download_files 456 | 457 | 458 | def get_launcher_json_for_workflow_json(workflow_json, resolved_missing_models, skip_model_validation): 459 | response = requests.post( 460 | f"{CW_ENDPOINT}/api/comfyui-launcher/setup_workflow_json?skipModelValidation={skip_model_validation}", 461 | json={"workflow": workflow_json, "isWindows": os.name == "nt", "resolved_missing_models": resolved_missing_models}, 462 | ) 463 | assert ( 464 | response.status_code == 200 or response.status_code == 400 465 | ), f"Failed to get launcher json for workflow json: {workflow_json}" 466 | return response.json() 467 | 468 | def generate_incrementing_filename(filepath): 469 | filename, file_extension = os.path.splitext(filepath) 470 | counter = 1 471 | while os.path.exists(filepath): 472 | filepath = f"{filename} ({counter}){file_extension}" 473 | counter += 1 474 | return filepath 475 | 476 | def rename_file_in_workflow_json(workflow_json, old_filename, new_filename): 477 | workflow_json_str = json.dumps(workflow_json) 478 | workflow_json_str = workflow_json_str.replace(old_filename, new_filename) 479 | return json.loads(workflow_json_str) 480 | 481 | def rename_file_in_launcher_json(launcher_json, old_filename, new_filename): 482 | workflow_json = launcher_json["workflow_json"] 483 | workflow_json_str = json.dumps(workflow_json) 484 | workflow_json_str = workflow_json_str.replace(old_filename, new_filename) 485 | workflow_json = json.loads(workflow_json_str) 486 | launcher_json["workflow_json"] = workflow_json 487 | 488 | 489 | def set_default_workflow_from_launcher_json(project_folder_path, launcher_json): 490 | if not launcher_json: 491 | return 492 | workflow_json = launcher_json["workflow_json"] 493 | with open( 494 | os.path.join( 495 | project_folder_path, "comfyui", "web", "scripts", "defaultGraph.js" 496 | ), 497 | "w", 498 | ) as f: 499 | f.write(f"export const defaultGraph = {json.dumps(workflow_json, indent=2)};") 500 | 501 | with open( 502 | os.path.join( 503 | project_folder_path, "comfyui", "custom_nodes", "ComfyUI-ComfyWorkflows", "current_graph.json" 504 | ), 505 | "w", 506 | ) as f: 507 | json.dump(workflow_json, f) 508 | 509 | 510 | def get_launcher_state(project_folder_path): 511 | state = {} 512 | launcher_folder_path = os.path.join(project_folder_path, ".launcher") 513 | os.makedirs(launcher_folder_path, exist_ok=True) 514 | 515 | state_path = os.path.join(launcher_folder_path, "state.json") 516 | 517 | if os.path.exists(state_path): 518 | with open(state_path, "r") as f: 519 | state = json.load(f) 520 | 521 | return state, state_path 522 | 523 | 524 | def set_launcher_state_data(project_folder_path, data: dict): 525 | launcher_folder_path = os.path.join(project_folder_path, ".launcher") 526 | os.makedirs(launcher_folder_path, exist_ok=True) 527 | 528 | existing_state, existing_state_path = get_launcher_state(project_folder_path) 529 | existing_state.update(data) 530 | 531 | with open(existing_state_path, "w") as f: 532 | json.dump(existing_state, f) 533 | 534 | def install_pip_reqs(project_folder_path, pip_reqs): 535 | if not pip_reqs: 536 | return 537 | print("Installing pip requirements...") 538 | with open(os.path.join(project_folder_path, "requirements.txt"), "w") as f: 539 | for req in pip_reqs: 540 | if isinstance(req, str): 541 | f.write(req + "\n") 542 | elif isinstance(req, dict): 543 | f.write(f"{req['_key']}=={req['_version']}\n") 544 | run_command_in_project_venv( 545 | project_folder_path, 546 | f"pip install -r {os.path.join(project_folder_path, 'requirements.txt')}", 547 | ) 548 | 549 | def get_project_port(id): 550 | project_path = os.path.join(PROJECTS_DIR, id) 551 | if os.path.exists(os.path.join(project_path, "port.txt")): 552 | with open(os.path.join(project_path, "port.txt"), "r") as f: 553 | return int(f.read().strip()) 554 | return find_free_port(PROJECT_MIN_PORT, PROJECT_MAX_PORT) 555 | 556 | def is_port_in_use(port: int) -> bool: 557 | import socket 558 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 559 | return s.connect_ex(('localhost', port)) == 0 560 | 561 | def find_free_port(start_port, end_port): 562 | for port in range(start_port, end_port + 1): 563 | with socket.socket() as s: 564 | try: 565 | s.bind(('', port)) 566 | return port 567 | except OSError: 568 | pass # Port is already in use, try the next one 569 | return None # No free port found in the range 570 | 571 | def create_symlink(source, target): 572 | if os.name == 'nt': # Check if running on Windows 573 | run_command(['mklink', '/D', target, source]) 574 | else: 575 | os.symlink(source, target, target_is_directory=True) 576 | 577 | def create_virtualenv(venv_path): 578 | run_command(['python', '-m', 'venv', venv_path]) --------------------------------------------------------------------------------