-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added update notification
- Loading branch information
Showing
13 changed files
with
801 additions
and
287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
|
||
import WorkflowNodeAdder from './WorkflowNodeAdder.js'; | ||
import DropdownStepper from './DropdownStepper.js'; | ||
|
||
class LoraWorkflowManager { | ||
constructor(workflow, flowConfig) { | ||
this.workflowManager = new WorkflowNodeAdder(workflow); | ||
this.flowConfig = flowConfig; | ||
this.container = document.getElementById('side-workflow-controls'); | ||
this.addButton = null; | ||
this.initializeUI(); | ||
} | ||
|
||
initializeUI() { | ||
this.addButton = document.createElement('button'); | ||
this.addButton.textContent = '+LoRA'; | ||
this.addButton.classList.add('add-lora-button'); | ||
this.addButton.style.marginBottom = '5px'; | ||
this.container.appendChild(this.addButton); | ||
this.addButton.addEventListener('click', () => this.handleAddLora()); | ||
} | ||
|
||
handleAddLora() { | ||
try { | ||
const newNodeId = this.workflowManager.addLora(); | ||
|
||
const dynamicConfig = this.createDynamicConfig(newNodeId); | ||
|
||
const loraContainer = document.createElement('div'); | ||
loraContainer.id = dynamicConfig.id; | ||
loraContainer.classList.add('dropdown-stepper-container'); | ||
this.container.appendChild(loraContainer); | ||
new DropdownStepper(dynamicConfig, this.workflowManager.getWorkflow()); | ||
|
||
} catch (error) { | ||
console.error('Error adding LoRA:', error); | ||
} | ||
} | ||
|
||
createDynamicConfig(nodeId) { | ||
return { | ||
id: `LoraLoader_${nodeId}`, | ||
label: "LoRA", | ||
dropdown: { | ||
url: "LoraLoaderModelOnly", | ||
key: "lora_name", | ||
nodePath: `${nodeId}.inputs.lora_name` | ||
}, | ||
steppers: [ | ||
{ | ||
id: `lorastrength_${nodeId}`, | ||
label: "Strength", | ||
minValue: 0, | ||
maxValue: 5, | ||
step: 0.01, | ||
defValue: 1, | ||
precision: 2, | ||
scaleFactor: 1, | ||
container: `lorastrength_container_${nodeId}`, | ||
nodePath: `${nodeId}.inputs.strength_model` | ||
} | ||
] | ||
}; | ||
} | ||
|
||
getWorkflow() { | ||
return this.workflowManager.getWorkflow(); | ||
} | ||
} | ||
export default LoraWorkflowManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
class WorkflowNodeAdder { | ||
constructor(workflow) { | ||
if (typeof workflow !== 'object' || workflow === null || Array.isArray(workflow)) { | ||
throw new TypeError('Workflow must be a non-null object'); | ||
} | ||
this.workflow = { ...workflow }; | ||
this.existingIds = new Set(Object.keys(this.workflow).map(id => parseInt(id, 10))); | ||
this.highestId = this._getHighestNodeId(); | ||
this.loraCount = this._countExistingLoras(); | ||
} | ||
|
||
addLora() { | ||
const newLoraId = this._getNextNodeId(); | ||
const loraNode = this._createLoraNode(newLoraId); | ||
|
||
const existingLoras = this._findLoraNodes(); | ||
|
||
if (existingLoras.length === 0) { | ||
const modelLoaders = this._findModelLoaders(); | ||
if (modelLoaders.length === 0) { | ||
throw new Error('No model loader found in the workflow to attach LoRA'); | ||
} | ||
|
||
modelLoaders.forEach(loader => { | ||
const originalModelInput = loader.inputs.model; | ||
loader.inputs.model = [newLoraId.toString(), 0]; | ||
loraNode.inputs.model = originalModelInput; | ||
}); | ||
} else { | ||
const lastLora = existingLoras[existingLoras.length - 1]; | ||
const originalModelInput = lastLora.inputs.model; | ||
lastLora.inputs.model = [newLoraId.toString(), 0]; | ||
loraNode.inputs.model = originalModelInput; | ||
} | ||
|
||
this.workflow[newLoraId.toString()] = loraNode; | ||
this.existingIds.add(newLoraId); | ||
this.highestId = newLoraId; | ||
this.loraCount += 1; | ||
|
||
return newLoraId; | ||
} | ||
|
||
getWorkflow() { | ||
return this.workflow; | ||
} | ||
|
||
_createLoraNode(id) { | ||
return { | ||
inputs: { | ||
lora_name: "lora.safetensors", | ||
strength_model: 1, | ||
model: [] | ||
}, | ||
class_type: "LoraLoaderModelOnly", | ||
_meta: { | ||
title: "LoraLoaderModelOnly" | ||
} | ||
}; | ||
} | ||
|
||
_findLoraNodes() { | ||
return Object.entries(this.workflow) | ||
.filter(([_, node]) => node.class_type === "LoraLoaderModelOnly") | ||
.map(([id, node]) => ({ id: parseInt(id, 10), ...node })); | ||
} | ||
|
||
_findModelLoaders() { | ||
const modelLoaders = []; | ||
|
||
Object.entries(this.workflow).forEach(([id, node]) => { | ||
if (node.inputs && Array.isArray(node.inputs.model) && node.inputs.model.length === 2) { | ||
modelLoaders.push({ id: parseInt(id, 10), ...node }); | ||
} | ||
}); | ||
|
||
return modelLoaders; | ||
} | ||
|
||
_getNextNodeId() { | ||
return this.highestId + 1; | ||
} | ||
|
||
_getHighestNodeId() { | ||
return Math.max(...this.existingIds, 0); | ||
} | ||
|
||
_countExistingLoras() { | ||
return this._findLoraNodes().length; | ||
} | ||
} | ||
|
||
export default WorkflowNodeAdder; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const state = { | ||
jobQueue: [], | ||
currentJobId: 0, | ||
isProcessing: false, | ||
}; | ||
|
||
export default state; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import state from './state.js'; | ||
|
||
class StateManager { | ||
static addJob(job) { | ||
state.jobQueue.push(job); | ||
} | ||
|
||
static getNextJob() { | ||
return state.jobQueue[0]; | ||
} | ||
|
||
static removeJob() { | ||
state.jobQueue.shift(); | ||
} | ||
|
||
static incrementJobId() { | ||
state.currentJobId += 1; | ||
return state.currentJobId; | ||
} | ||
|
||
static setProcessing(value) { | ||
state.isProcessing = value; | ||
} | ||
|
||
static isProcessing() { | ||
return state.isProcessing; | ||
} | ||
|
||
static getJobQueue() { | ||
return state.jobQueue; | ||
} | ||
|
||
static getCurrentJobId() { | ||
return state.currentJobId; | ||
} | ||
} | ||
|
||
export default StateManager; |
Oops, something went wrong.