add files
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
name: Publish to Comfy registry
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'hetima' }}
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@v1
|
||||
with:
|
||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
@@ -4,3 +4,35 @@
|
||||
</p>
|
||||
|
||||
# ComfyUI-SingleLinePicker
|
||||
|
||||
リストからワンクリックでテキストを選択できるComfyUIのカスタムノードです。LoRAやプロンプトの切り替え作業を劇的に改善します。
|
||||
|
||||

|
||||
|
||||
## Nodes
|
||||
|
||||
### Single Line Picker
|
||||
|
||||
入力されたテキストを個々の行のリストとして表示します。選択された行を出力します。
|
||||
|
||||
表示されるテキストは、複数行テキストを出力する適当なノードからINPUTの`text`に繋げることで反映されます。最初の実行時やテキストの内容が変わると選択状態がリセットされ、何も出力しません。ノードを選択したときに出てくるツールボックスから部分実行を行えば全体の工程を行わずにテキストが流れ込みます。内容が固定の場合は一度読み込まれたら接続を切っても大丈夫です。
|
||||
|
||||
ノード情報パネルのParametersで`source_text`を直接編集することでも内容を変更できます。
|
||||
|
||||
ノードを選択したときに出てくるツールボックスに  マークのボタンが追加されます。これをクリックすると、インストールしているLoRAの一覧を取得しリストに表示します。後述するSLP Lora Loaderに直接出力できます。
|
||||
|
||||
**辞書モード**:テキストの一行目に`#dict`と記入すると2行目以降をコロンを挟んで「表示テキスト: 出力されるテキスト」と解釈して処理します。長い文章を簡潔なタイトルで把握することができます。
|
||||
|
||||

|
||||
|
||||
|
||||
### SLP Lora Loader / SLP Lora Loader (Model Only)
|
||||
|
||||
デフォルトのローダーとほぼ同じです。LoRAファイルの指定部分がコンボボックスではなくテキストになっているのでSingle Line Pickerを直接繋げることができます。
|
||||
|
||||
出力パラメータ`stem`を持っています。LoRAファイルの拡張子を除いたファイル名を出力します([audioscavenger/save-image-extended-comfyui](https://github.com/audioscavenger/save-image-extended-comfyui) はLoRAの名前を参照することができますが、SLP Lora Loaderの`lora_name`を参照しようとするとエラーが出たため名前を`lora_name_text`に変更しています。この`lora_name_text`を参照したとしてもエラーにはなりませんが、正常な値は取得できません。`stem`出力を加工するなりして対応してください)。
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.0.0
|
||||
- 最初のリリース
|
||||
|
||||
@@ -4,3 +4,34 @@
|
||||
</p>
|
||||
|
||||
# ComfyUI-SingleLinePicker
|
||||
|
||||
This is a custom node for ComfyUI that lets you select single line from lists of text with a single click. It dramatically improves the process of switching LoRA or prompts.
|
||||
|
||||

|
||||
|
||||
## Nodes
|
||||
|
||||
### Single Line Picker
|
||||
Displays the input text as a list of individual lines. Outputs the selected line.
|
||||
|
||||
The displayed text is reflected by connecting the `text` input to an appropriate node that outputs multi-line text. During the first execution or when the text content changes, the selection state resets and nothing is output. Performing a partial execution from the toolbox that appears when selecting the node allows text to flow in without running the entire process. If the content is static, it's fine to disconnect after it has been loaded once.
|
||||
|
||||
You can also change the content by directly editing `source_text` in the Parameters section of the node information panel.
|
||||
|
||||
When select this node, a button marked with the  icon will appear in the toolbox. Clicking this button retrieves a list of installed LoRA files and displays them. You can output directly to the SLP Lora Loader described later.
|
||||
|
||||
**Dictionary Mode**: Entering `#dict` on the first line of text causes subsequent lines to be interpreted as “Display Text: Output Text” separated by colon. This allows you to grasp long contents with concise titles.
|
||||
|
||||

|
||||
|
||||
|
||||
### SLP Lora Loader / SLP Lora Loader (Model Only)
|
||||
|
||||
It's almost identical to the default loader. Since the LoRA file selection part is text instead of a combo box so that connect a Single Line Picker directly.
|
||||
|
||||
It has an output parameter called `stem`. It outputs LoRA filename without file extension ([audioscavenger/save-image-extended-comfyui](https://github.com/audioscavenger/save-image-extended-comfyui) can reference LoRA name, but since attempting to reference `lora_name` in the SLP Lora Loader caused an error, the name has been changed to `lora_name_text`. Referencing this `lora_name_text` will not cause an error, but it will not retrieve the correct value. Please handle this by modifying the `stem` output or similar means).
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.0.0
|
||||
- Initial release
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
from .single_line_picker import SLPSingleLinePicker
|
||||
from .slp_lora_loader import SLPLoraLoader, SLPLoraLoaderModelOnly
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
SLPSingleLinePicker.NAME: SLPSingleLinePicker,
|
||||
SLPLoraLoader.NAME: SLPLoraLoader,
|
||||
SLPLoraLoaderModelOnly.NAME: SLPLoraLoaderModelOnly,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
SLPSingleLinePicker.NAME: SLPSingleLinePicker.DISPLAY_NAME,
|
||||
SLPLoraLoader.NAME: SLPLoraLoader.DISPLAY_NAME,
|
||||
SLPLoraLoaderModelOnly.NAME: SLPLoraLoaderModelOnly.DISPLAY_NAME,
|
||||
}
|
||||
|
||||
|
||||
WEB_DIRECTORY = "./js"
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 3.25C6.48579 3.25 5.25 4.48579 5.25 6V18C5.25 19.5142 6.48579 20.75 8 20.75H16C17.5142 20.75 18.75 19.5142 18.75 18V9.5C18.75 9.30109 18.671 9.11032 18.5303 8.96967L13.0303 3.46967C12.8897 3.32902 12.6989 3.25 12.5 3.25H8ZM6.75 6C6.75 5.31421 7.31421 4.75 8 4.75H11.75V9.5C11.75 9.91421 12.0858 10.25 12.5 10.25H17.25V18C17.25 18.6858 16.6858 19.25 16 19.25H8C7.31421 19.25 6.75 18.6858 6.75 18V6ZM16.1893 8.75L13.25 5.81066V8.75H16.1893ZM15.25 15C15.25 15.4142 14.9142 15.75 14.5 15.75H12.75V17.5C12.75 17.9142 12.4142 18.25 12 18.25C11.5858 18.25 11.25 17.9142 11.25 17.5V15.75H9.5C9.08579 15.75 8.75 15.4142 8.75 15C8.75 14.5858 9.08579 14.25 9.5 14.25H11.25V12.5C11.25 12.0858 11.5858 11.75 12 11.75C12.4142 11.75 12.75 12.0858 12.75 12.5V14.25H14.5C14.9142 14.25 15.25 14.5858 15.25 15Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 963 B |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,320 @@
|
||||
import { app } from "../../scripts/app.js"
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { ComfyWidgets } from "../../scripts/widgets.js";
|
||||
|
||||
|
||||
|
||||
app.registerExtension({
|
||||
name: "hetima.SLPSingleLinePicker",
|
||||
commands: [
|
||||
{
|
||||
id: "hetima-slpsinglelinepicker-get-loras",
|
||||
label: "Get Lora List",
|
||||
icon: "pi pi-file-plus",
|
||||
tooltip: "Get Lora List",
|
||||
function: () => {
|
||||
const slp = Array.from(app.canvas.selectedItems)[0];
|
||||
slp?.listLoraFiles?.();
|
||||
}
|
||||
}
|
||||
],
|
||||
getSelectionToolboxCommands: (selectedItem) => {
|
||||
// Return array of command IDs to show in the toolbox
|
||||
if (selectedItem.type == "HetimaSingleLinePicker") {
|
||||
return ["hetima-slpsinglelinepicker-get-loras"];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData.name === "HetimaSingleLinePicker") {
|
||||
const style = document.createElement("style");
|
||||
style.innerText = `
|
||||
.single-line-picker-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
white-space: nowrap;
|
||||
|
||||
background-color: var(--bg-color);
|
||||
color: var(--fg-color);
|
||||
}
|
||||
.single-line-picker-list-item {
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.single-line-picker-list-item-selected {
|
||||
background-color: var(--fg-color);
|
||||
color: var(--bg-color);
|
||||
}
|
||||
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
const addListItem = function (container) {
|
||||
const itm = document.createElement("div");
|
||||
itm.className = "single-line-picker-list-item";
|
||||
container.appendChild(itm);
|
||||
};
|
||||
|
||||
const setItemData = function (itm, label, realText) {
|
||||
itm.innerText = label;
|
||||
itm.dataset.realText = realText;
|
||||
}
|
||||
|
||||
const selectItem = function (itm) {
|
||||
if (!itm.classList.contains("single-line-picker-list-item-selected")) {
|
||||
itm.classList.add("single-line-picker-list-item-selected");
|
||||
}
|
||||
};
|
||||
|
||||
const deselectItem = function (itm) {
|
||||
if (itm.classList.contains("single-line-picker-list-item-selected")){
|
||||
itm.classList.remove("single-line-picker-list-item-selected");
|
||||
}
|
||||
};
|
||||
|
||||
const selectedText = function (container) {
|
||||
var result = "";
|
||||
const lineCount = container.childElementCount;
|
||||
for (let index = 0; index < lineCount; index++) {
|
||||
const div = container.children[index];
|
||||
if (div.classList.contains("single-line-picker-list-item-selected")) {
|
||||
if (result != "") {
|
||||
result += "\n";
|
||||
}
|
||||
result += div.dataset.realText;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const selectedIndexes = function (container) {
|
||||
var result = "";
|
||||
const lineCount = container.childElementCount;
|
||||
for (let index = 0; index < lineCount; index++) {
|
||||
const div = container.children[index];
|
||||
if (div.classList.contains("single-line-picker-list-item-selected")) {
|
||||
if (result != "") {
|
||||
result += ",";
|
||||
}
|
||||
result += index.toString();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
const ret = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
|
||||
const node = this;
|
||||
|
||||
node.properties = node.properties || {};
|
||||
node.properties.selected_indexes = node.properties.selected_indexes || "";
|
||||
|
||||
|
||||
this.textListWidget = ComfyWidgets["STRING"](this, "source_text", ["STRING", { multiline: true }], app).widget;
|
||||
this.textListWidget.inputEl.readOnly = true;
|
||||
this.textListWidget.callback = async (v) => {
|
||||
this.textListChanged();
|
||||
}
|
||||
this.textListWidget.hidden = true;
|
||||
|
||||
this.selectedTextWidget = ComfyWidgets["STRING"](this, "selected_text", ["STRING", { multiline: true }], app).widget;
|
||||
this.selectedTextWidget.inputEl.readOnly = true;
|
||||
this.selectedTextWidget.hidden = true;
|
||||
|
||||
// this.stemTextWidget = ComfyWidgets["STRING"](this, "stem", ["STRING", { multiline: false }], app).widget;
|
||||
// this.stemTextWidget.hidden = true;
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.className = "single-line-picker-container";
|
||||
// container.style.width = "100%";
|
||||
// container.style.height = "100%";
|
||||
// container.style.position = "relative";
|
||||
// container.style.display = "flex";
|
||||
// container.style.flexDirection = "column";
|
||||
// container.style.overflowX = "hidden";
|
||||
// container.style.overflowY = "auto";
|
||||
// container.style.whiteSpace = "nowrap";
|
||||
// container.style.background = "transparent";
|
||||
|
||||
node.container = container;
|
||||
node.container.addEventListener('click', (e) => {
|
||||
const lists = Array.from(e.currentTarget.children);
|
||||
const clicked_index = lists.findIndex(list => list === e.target);
|
||||
// -1 is deselect all
|
||||
const lineCount = this.container.childElementCount;
|
||||
for (let index = 0; index < lineCount; index++) {
|
||||
const div = this.container.children[index];
|
||||
if (index == clicked_index) {
|
||||
selectItem(div);
|
||||
}else{
|
||||
deselectItem(div);
|
||||
}
|
||||
}
|
||||
if (clicked_index > 0) {
|
||||
}
|
||||
node.selectionChanged(null);
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
node.listWidget = node.addDOMWidget("list", "TEXTLIST", container, {
|
||||
serialize: false,
|
||||
computeSize: () => {
|
||||
const width = Math.max(node.size[0] || 200, 200);
|
||||
const height = Math.max(node.size[1] || 200, 200);
|
||||
return [width, height];
|
||||
},
|
||||
});
|
||||
|
||||
node.textListChanged();
|
||||
return ret;
|
||||
};
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted;
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments);
|
||||
this.setTextList(message?.text);
|
||||
};
|
||||
|
||||
nodeType.prototype.selectionChanged = function (forceValue = null) {
|
||||
if (forceValue === null) {
|
||||
forceValue = selectedIndexes(this.container);
|
||||
} else {
|
||||
const idxs = forceValue.split(",").map(str => parseInt(str, 10));
|
||||
const lineCount = this.container.childElementCount;
|
||||
for (let index = 0; index < lineCount; index++) {
|
||||
const div = this.container.children[index];
|
||||
if (idxs.includes(index)) {
|
||||
selectItem(div);
|
||||
} else {
|
||||
deselectItem(div);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.properties.selected_indexes = forceValue;
|
||||
const text = selectedText(this.container);
|
||||
this.selectedTextWidget.value = text;
|
||||
|
||||
// const firstLine = text.split('\n')[0];
|
||||
// const stem = firstLine.substring(
|
||||
// Math.max(firstLine.lastIndexOf("/"), firstLine.lastIndexOf("\\")) + 1,
|
||||
// firstLine.lastIndexOf("."));
|
||||
// this.stemTextWidget.value = stem || firstLine;
|
||||
}
|
||||
|
||||
nodeType.prototype.textListChanged = function () {
|
||||
if (!this.container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const text = this.textListWidget.value;
|
||||
const texts = text.split('\n');
|
||||
let lineCount = texts.length;
|
||||
let dictMode = false;
|
||||
|
||||
if (lineCount > 1 && texts[0].toUpperCase().startsWith("#DICT")) {
|
||||
texts.shift();
|
||||
lineCount--;
|
||||
dictMode = true;
|
||||
}
|
||||
|
||||
|
||||
const needs = lineCount - this.container.childElementCount;
|
||||
if (needs > 0){
|
||||
for (let index = 0; index < needs; index++) {
|
||||
addListItem(this.container);
|
||||
}
|
||||
} else if (needs < 0) {
|
||||
for (let index = 0; index > needs; index--) {
|
||||
this.container.lastElementChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
for (let index = 0; index < lineCount; index++) {
|
||||
const div = this.container.children[index];
|
||||
let realText = texts[index];
|
||||
let label = texts[index];
|
||||
if (dictMode) {
|
||||
const items = texts[index].split(':');
|
||||
if (items.length > 1) {
|
||||
label = items.shift().trim();
|
||||
realText = items.join(':').trim();
|
||||
}
|
||||
}
|
||||
|
||||
setItemData(div, label, realText);
|
||||
deselectItem(div);
|
||||
}
|
||||
|
||||
this.properties.selected_indexes = "";
|
||||
this.selectedTextWidget.value = "";
|
||||
// this.stemTextWidget.value = "";
|
||||
this.setDirtyCanvas(true);
|
||||
};
|
||||
|
||||
nodeType.prototype.setTextList = function (texts) {
|
||||
var text = '';
|
||||
if (typeof texts === 'string') {
|
||||
text = texts;
|
||||
} else {
|
||||
for (let i = 0; i < texts.length; i++) {
|
||||
text += texts[i];
|
||||
}
|
||||
}
|
||||
if (this.textListWidget) {
|
||||
if (this.textListWidget.value != text) {
|
||||
this.textListWidget.value = text;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
nodeType.prototype.listLoraFiles = function () {
|
||||
async function fetchCheckpoints() {
|
||||
try {
|
||||
const response = await api.fetchApi("/models/loras");
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve the model:", error);
|
||||
}
|
||||
}
|
||||
|
||||
fetchCheckpoints().then((value) => {
|
||||
this.setTextList(value?.join?.("\n"));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
nodeType.prototype.onSerialize = function (info) {
|
||||
info.properties = {
|
||||
source_text: this.textListWidget.value || "",
|
||||
selected_indexes: this.properties.selected_indexes || ""
|
||||
};
|
||||
//info.widgets_values = [""];
|
||||
};
|
||||
|
||||
nodeType.prototype.onConfigure = function (info) {
|
||||
this.properties = this.properties || {};
|
||||
|
||||
if (info.properties) {
|
||||
this.textListWidget.value = info.properties.source_text || ""; //call textListChanged()
|
||||
this.properties.selected_indexes = info.properties.selected_indexes || "";
|
||||
}
|
||||
this.selectionChanged(this.properties.selected_indexes);
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
class SLPSingleLinePicker:
|
||||
|
||||
NAME = "HetimaSingleLinePicker"
|
||||
DISPLAY_NAME = "Single Line Picker"
|
||||
|
||||
CATEGORY = "SingleLinePicker"
|
||||
DESCRIPTION = "Select one line from the text list with a single click."
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"optional": {
|
||||
"text": ("STRING", {"multiline": True, "default": "", "forceInput": True, "tooltip": "text content for list"}),
|
||||
},
|
||||
"hidden": {
|
||||
"source_text": ("STRING", {}),
|
||||
"selected_text": ("STRING", {}),
|
||||
# "stem": ("STRING", {}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("STRING",)
|
||||
OUTPUT_TOOLTIPS = ("text content of selected line",)
|
||||
OUTPUT_NODE = True
|
||||
FUNCTION = "executed"
|
||||
|
||||
def executed(self, text=None, source_text=None, selected_text=None, **kwargs):
|
||||
if not text:
|
||||
return {"ui": { "text": source_text }, "result": (selected_text,)}
|
||||
if text == source_text:
|
||||
return {"ui": { "text": source_text }, "result": (selected_text,)}
|
||||
|
||||
return {"ui": { "text": text }, "result": ()}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
import folder_paths
|
||||
import comfy.sd
|
||||
import comfy.utils
|
||||
from pathlib import Path
|
||||
|
||||
class SLPLoraLoader:
|
||||
|
||||
NAME = "HetimaSLPLoraLoader"
|
||||
DISPLAY_NAME = "SLP Lora Loader"
|
||||
CATEGORY = "SingleLinePicker"
|
||||
|
||||
def __init__(self):
|
||||
self.loaded_lora = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}),
|
||||
"clip": ("CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}),
|
||||
"lora_name_text": ("STRING", {"tooltip": "The name of the LoRA."}),
|
||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}),
|
||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MODEL", "CLIP", "STRING")
|
||||
RETURN_NAMES = ("MODEL", "CLIP", "stem")
|
||||
OUTPUT_TOOLTIPS = ("The modified diffusion model.", "The modified CLIP model.", "The stem of lora file")
|
||||
FUNCTION = "load_lora"
|
||||
|
||||
DESCRIPTION = "LoRAs are used to modify diffusion and CLIP models, altering the way in which latents are denoised such as applying styles. Multiple LoRA nodes can be linked together."
|
||||
|
||||
def load_lora(self, model, clip, lora_name_text, strength_model, strength_clip):
|
||||
if not lora_name_text:
|
||||
return (model, clip, "")
|
||||
if strength_model == 0 and strength_clip == 0:
|
||||
return (model, clip, "")
|
||||
|
||||
|
||||
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name_text.splitlines()[0])
|
||||
lora = None
|
||||
if self.loaded_lora is not None:
|
||||
if self.loaded_lora[0] == lora_path:
|
||||
lora = self.loaded_lora[1]
|
||||
else:
|
||||
self.loaded_lora = None
|
||||
|
||||
if lora is None:
|
||||
lora = comfy.utils.load_torch_file(lora_path, safe_load=True)
|
||||
self.loaded_lora = (lora_path, lora)
|
||||
|
||||
model_lora, clip_lora = comfy.sd.load_lora_for_models(model, clip, lora, strength_model, strength_clip)
|
||||
return (model_lora, clip_lora, Path(lora_path).stem)
|
||||
|
||||
class SLPLoraLoaderModelOnly(SLPLoraLoader):
|
||||
|
||||
NAME = "HetimaSLPLoraLoaderModelOnly"
|
||||
DISPLAY_NAME = "SLP Lora Loader (Model Only)"
|
||||
|
||||
CATEGORY = "SingleLinePicker"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required": { "model": ("MODEL",),
|
||||
"lora_name_text": ("STRING",),
|
||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}),
|
||||
}}
|
||||
RETURN_TYPES = ("MODEL", "stem")
|
||||
RETURN_NAMES = ("MODEL", "stem")
|
||||
OUTPUT_TOOLTIPS = ("The modified diffusion model.", "The stem of lora file")
|
||||
|
||||
FUNCTION = "load_lora_model_only"
|
||||
|
||||
def load_lora_model_only(self, model, lora_name_text, strength_model):
|
||||
result = self.load_lora(model, None, lora_name_text, strength_model, 0)
|
||||
return (result[0], result[2])
|
||||
Reference in New Issue
Block a user