Skip to content

Commit

Permalink
Update UI look and feel
Browse files Browse the repository at this point in the history
Add support for caching
  • Loading branch information
bmaltais committed Jan 20, 2025
1 parent 5fdefbd commit 12d45a6
Show file tree
Hide file tree
Showing 65 changed files with 4,896 additions and 3 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,9 @@ cython_debug/

# PyPI configuration file
.pypirc

# Other
*.npz
test/output
uv.lock
musubi_tuner_gui.log
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

[submodule "musubi-tuner"]
path = musubi-tuner
url = https://github.com/kohya-ss/musubi-tuner.git
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10
57 changes: 54 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,57 @@
# musubi-tuner-gui
GUI for the new musubi-tuner

Anyone who want to contribute to the GUI code are welcome. I will make this one use uv: https://github.com/astral-sh/uv as the python package manager to facilitate cross platform use. Will aim to support Linux and Windows. Not sure about MacOS. Those interested to the MacOS support side are welcome to contribute code to ensure proper support.
GUI for the new musubi-tuner.

Work until a viable Minimum Viable Product is ready will be found in the dev branch. Main will remain empty until contributors feel there is something work merging for a 1st release.
Contributions to the GUI code are welcome. This project uses [uv](https://github.com/astral-sh/uv) as the Python package manager to facilitate cross-platform use. The aim is to support Linux and Windows, with potential MacOS support pending contributions.

Work towards a Minimum Viable Product (MVP) will be done in the `dev` branch. The `main` branch will remain empty until there is a consensus on a viable first release.

## Installation

The installation process will be improved and automated in the future. For now, follow these steps:

1. Install uv (if not already present on your OS).

### Linux/MacOS

```sh
curl -LsSf https://astral.sh/uv/install.sh | sh
```

### Windows

```powershell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```

To add `C:\Users\berna\.local\bin` to your PATH, either restart your system or run:

#### CMD

```cmd
set Path=C:\Users\berna\.local\bin;%Path%
```

#### Powershell

```powershell
$env:Path = "C:\Users\berna\.local\bin;$env:Path"
```

## Starting the GUI

```shell
git clone --recursive https://github.com/bmaltais/musubi-tuner-gui.git
cd musubi-tuner-gui
uv run gui.py
```

## Caching generation

Until the GUI automastically ng, you have to do it manuallUse the followingtwo commands you ache images and txt prompts:e

```shell
uv run ./musubi-tuner/cache_latents.py --dataset_config "./test/config/dataset.toml" --vae "C:\Users\berna\Downloads\pytorch_model.pt" --vae_chunk_size 32 --vae_tiling

uv run ./musubi-tuner/cache_text_encoder_outputs.py --dataset_config "./test/config/dataset.toml" --text_encoder1 "C:\Users\berna\Downloads\llava_llama3_fp16.safetensors" --text_encoder2 "C:\Users\berna\Downloads\clip_l.safetensors" --batch_size 1
```
103 changes: 103 additions & 0 deletions assets/js/localization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
var re_num = /^[.\d]+$/;
var re_emoji = /[\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{1F9B0}-\u{1F9B3}]/u;

var original_lines = {};
var translated_lines = {};

function hasLocalization() {
return window.localization && Object.keys(window.localization).length > 0;
}

function textNodesUnder(el) {
var n, a = [], walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
while ((n = walk.nextNode())) a.push(n);
return a;
}

function canBeTranslated(node, text) {
if (!text) return false;
if (!node.parentElement) return false;

var parentType = node.parentElement.nodeName;
if (parentType == 'SCRIPT' || parentType == 'STYLE' || parentType == 'TEXTAREA') return false;

if (parentType == 'OPTION' || parentType == 'SPAN') {
var pnode = node;
for (var level = 0; level < 4; level++) {
pnode = pnode.parentElement;
if (!pnode) break;
}
}

if (re_num.test(text)) return false;
if (re_emoji.test(text)) return false;
return true;
}

function getTranslation(text) {
if (!text) return undefined;

if (translated_lines[text] === undefined) {
original_lines[text] = 1;
}

var tl = localization[text];
if (tl !== undefined) {
translated_lines[tl] = 1;
}

return tl;
}

function processTextNode(node) {
var text = node.textContent.trim();

if (!canBeTranslated(node, text)) return;

var tl = getTranslation(text);
if (tl !== undefined) {
node.textContent = tl;
}
}

function processNode(node) {
console.log(node.nodeType + " " + node.nodeName + " " + node.nodeValue)
if (node.nodeType == 3) {
processTextNode(node);
return;
}

if (node.title) {
let tl = getTranslation(node.title);
if (tl !== undefined) {
node.title = tl;
}
}

if (node.placeholder) {
let tl = getTranslation(node.placeholder);
if (tl !== undefined) {
node.placeholder = tl;
}
}

textNodesUnder(node).forEach(function(node) {
processTextNode(node);
});
}

document.addEventListener("DOMContentLoaded", function() {
if (!hasLocalization()) {
return;
}

onUiUpdate(function(m) {
m.forEach(function(mutation) {
mutation.addedNodes.forEach(function(node) {
processNode(node);
});
});
});

processNode(gradioApp());
});
104 changes: 104 additions & 0 deletions assets/js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
function gradioApp() {
const elems = document.getElementsByTagName('gradio-app');
const elem = elems.length == 0 ? document : elems[0];

if (elem !== document) {
elem.getElementById = function(id) {
return document.getElementById(id);
};
}
return elem.shadowRoot ? elem.shadowRoot : elem;
}

/**
* Get the currently selected top-level UI tab button (e.g. the button that says "Extras").
*/
function get_uiCurrentTab() {
return gradioApp().querySelector('#tabs > .tab-nav > button.selected');
}

/**
* Get the first currently visible top-level UI tab content (e.g. the div hosting the "txt2img" UI).
*/
function get_uiCurrentTabContent() {
return gradioApp().querySelector('#tabs > .tabitem[id^=tab_]:not([style*="display: none"])');
}

var uiUpdateCallbacks = [];
var uiAfterUpdateCallbacks = [];
var uiLoadedCallbacks = [];
var uiTabChangeCallbacks = [];
var uiAfterUpdateTimeout = null;
var uiCurrentTab = null;

/**
* Register callback to be called at each UI update.
* The callback receives an array of MutationRecords as an argument.
*/
function onUiUpdate(callback) {
uiUpdateCallbacks.push(callback);
}



function executeCallbacks(queue, arg) {
for (const callback of queue) {
try {
callback(arg);
} catch (e) {
console.error("error running callback", callback, ":", e);
}
}
}

/**
* Schedule the execution of the callbacks registered with onAfterUiUpdate.
* The callbacks are executed after a short while, unless another call to this function
* is made before that time. IOW, the callbacks are executed only once, even
* when there are multiple mutations observed.
*/
function scheduleAfterUiUpdateCallbacks() {
clearTimeout(uiAfterUpdateTimeout);
uiAfterUpdateTimeout = setTimeout(function() {
executeCallbacks(uiAfterUpdateCallbacks);
}, 200);
}

var executedOnLoaded = false;

document.addEventListener("DOMContentLoaded", function() {
var mutationObserver = new MutationObserver(function(m) {
if (!executedOnLoaded && gradioApp().querySelector('#txt2img_prompt')) {
executedOnLoaded = true;
executeCallbacks(uiLoadedCallbacks);
}

executeCallbacks(uiUpdateCallbacks, m);
scheduleAfterUiUpdateCallbacks();
const newTab = get_uiCurrentTab();
if (newTab && (newTab !== uiCurrentTab)) {
uiCurrentTab = newTab;
executeCallbacks(uiTabChangeCallbacks);
}
});
mutationObserver.observe(gradioApp(), {childList: true, subtree: true});
});

/**
* Add a ctrl+enter as a shortcut to start a generation
*/
document.addEventListener('keydown', function(e) {
var handled = false;
if (e.key !== undefined) {
if ((e.key == "Enter" && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
} else if (e.keyCode !== undefined) {
if ((e.keyCode == 13 && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
}
if (handled) {
var button = get_uiCurrentTabContent().querySelector('button[id$=_generate]');
if (button) {
button.click();
}
e.preventDefault();
}
});
Loading

0 comments on commit 12d45a6

Please sign in to comment.