Skip to content

Commit fdc39b2

Browse files
committed
New UI Code Transfer
* Transfer of working code for new UI from other folder * Tested to make sure that a brand new install works * Re-structured code to be better organized * Added a new docs folder for installation instructions for each platform * Moved Git documentation images to a separate folder * Fixed a couple of minor bugs related to a brand new install * Updated README for new version * Updated environment.yaml even though I am unable to install using it at my end
1 parent 231d0b4 commit fdc39b2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3017
-742
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ simple3.py
1414
stable_diffusion_seeds.ipynb
1515
test.py
1616
test2.py
17+
clip-vit-large-patch14
18+
__pycache__
19+
config.json
20+
test

README.md

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,94 @@
1-
# Stable Diffusion for Apple Silicon
1+
# Stable Diffusion GUI
22

3-
This repo is my work on getting Stable Diffusion working on Apple Silicon macs by keeping things as simple as possible. The requirements are kept as simple as possible and probably the most complicated thing is the GUI which allows you to set up all your image generation parameters on a GUI whether you are on a Mac, Linux, or Windows.
3+
This repo is my work on getting a functional and feature-rich GUI working for Stable Diffusion. All the development and testing was done on Apple Silicon macs but the code should work under Windows and Linux as well. It has been tested under Windows and Linux, but not extensively — if you find bugs, please do let me know and I'll fix them 🙂
44

5-
**Note:** All development has been done on an Apple Silicon Mac and this has been optimized for Apple Silicon. It does work on an Intel Mac too but look at the Installation Errors section below below for help if things go wrong with the installation. Also, on a 2017 MacBook Pro, it took about 40 minutes to generate a single image! No testing has been done on any other platform (Windows and Linux) but it should (theoretically) work on other platforms too.
5+
The aim of the GUI is to keep things as simple as possible and yet provide as many features as is necessary to get your work done should you do a lot of image generation using Stable Diffusion. The original aim was to keep the Python package requirements as low (and simple) as possible while providing a GUI that works on a Mac, Linux, or Windows. However, the package requirements might change as more functionality is added to the GUI.
66

7-
![gui](assets/gui.jpg)
7+
**Note:** All development has been done on an Apple Silicon Mac and this has been optimized for Apple Silicon. It does work on an Intel Mac too but look at the Installation Errors section below below for help if things go wrong with the installation. Also, on a 2017 MacBook Pro, it took about 40 minutes to generate a single image!
8+
9+
![gui](screens/01-main.jpg)
810

911
The GUI has the following functionality:
1012

11-
* You can choose between generating via just a text prompt or a text + image prompt
13+
* You can generate images via just a text prompt or a text prompt + image (either txt2img or img2img)
14+
15+
* Remember all the prompts you've used in the past and allows you to manage them via a simple interface
16+
17+
* Allows you to add modifiers (such as artists, art styles etc.) to your prompts, provides a built-in list of modifiers, and allows you to manage the list of modifiers and modifier categories. You can add as many new modifiers as you want or organize them as you want.
18+
19+
![03-prompts](/Users/fahim/Code/Python/sd-gui/screens/03-prompts.jpg)
20+
21+
* You can use the default Standard Diffusion scheduler/sampler or select another scheduler/sampler from the available list.
22+
1223
* You can specify the size of the image that you want to generate
13-
* Remembers the last settings (and prompt) you used the next time you run the script
14-
* Remembers your last 20 prompts and allows you to select an old prompt via the history list
15-
* Has the ability to switch between multiple schedulers to compare generated images
24+
25+
* Remembers the last settings (and prompt) you used the next time you run the app
26+
1627
* Can generate more than one image at a time and allows you to view all generated images in the GUI
28+
1729
* Saves all generated images and the accompanying prompt info to hard drive
18-
* Allows you to delete any image and its prompt info from the GUI itself
30+
31+
* Allows you to delete any image and its prompt info from within the GUI itself
32+
1933
* Shows you the seed for any image so that you can use that seed to generate image variants
2034

21-
## Installation
35+
* Allows you to run the GUI locally but run a server elsewhere so that you can connect to the server from the GUI and do image generation on the server — great for when your local machine isn't powerful enough for SD but you still want the convenience of the GUI locally.
2236

23-
You will need the following:
37+
* Shows a log of all console output and errors within the app itself so that you can see what is going on without having to go back to the console to see what happened.
2438

25-
* An Apple Silicon or Intel mac (has not been tested on anything else)
26-
* macOS 12.3 Monterey or later
27-
* Python
39+
* Has a built-in basic editor so that you can create basic prompt images or create masks from a generated image for inpainting.
2840

29-
Before you start your installation, you might also want to sign up at [Hugging Face](https://huggingface.co/) since you'll need a Hugging Face user account in order to download the Stable Diffusion models. Do note also that you would need to visit the [Hugging Face Stable Diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v1-4) and accept their license before you would be able to download the model — you'll need to download the model during the installation.
41+
![02-editor](/Users/fahim/Code/Python/sd-gui/screens/02-editor.jpg)
3042

31-
There's also an [Installation Errors](#installation-errors) section further down. Please refer to that if you run into issues since common issues that others have faced are documented there 🙂
43+
* Allows you to in/outpaint images from within the image editor interface.
3244

33-
To get set up, you'll need to run the following commands in terminal one at a time. Do note that some of these commands would require you to make decisions and respond to prompts. If you are not comforable with that, this process might not be for you 🙂
45+
* Has a built-in image gallery which shows you all images in the app output folder and if the images were generated from within the app, also shows creation and prompt information for those images.
3446

35-
There is some limited information which might help you in this blog post, but that too doesn't go into a lot of detail: https://write.farook.org/adventures-in-imagineering-mining-the-apple-silicon/
47+
![04-gallery](/Users/fahim/Code/Python/sd-gui/screens/04-gallery.jpg)
3648

37-
**Note:** Make sure you are in the folder location where you want to have this repo before you start running the following commands.
49+
## Installation
3850

39-
```bash
40-
# install Homebrew
41-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
42-
43-
# Install miniconda to manage your Python environments
44-
/bin/bash -c "$(curl -fsSL https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh)"
45-
# If the above line does not work to install miniconda correctly (some have reported issues) try the instructions at this link instead: https://docs.conda.io/projects/conda/en/latest/user-guide/install/macos.html
46-
#Also, if you are on an Intel Mac, use the following command to install miniconda for Intel macs:
47-
# /bin/bash -c "$(curl -fsSL https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh)"
48-
49-
# Create and activate new conda environment named ml
50-
conda config --append channels conda-forge
51-
conda create -n ml python=3.8.8
52-
conda activate ml
51+
Before you start your installation, you might also want to sign up at [Hugging Face](https://huggingface.co/) since you'll need a Hugging Face user account in order to download the Stable Diffusion models. Do note also that you would need to visit the [Hugging Face Stable Diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v1-4) and accept their license before you would be able to download the model — you'll need to download the model during the installation.
5352

54-
# Install the needed Python packages
55-
conda install pytorch torchvision torchaudio -c pytorch-nightly
56-
conda install transformers
57-
conda install -c conda-forge diffusers
58-
conda install ftfy
53+
There's also an [Installation Errors](#installation-errors) section further down in this document. Please refer to that if you run into issues since common issues that others have faced are documented there 🙂
5954

60-
# Install git and git-lfs via Homebrew
61-
brew install git git-lfs
55+
To get set up, you'll need to run the following commands in terminal one at a time. Do note that some of these commands would require you to make decisions and respond to prompts. If you are not comforable with that, this process might not be for you and you might wan to try one of the one-click installers [listed here](https://www.reddit.com/r/StableDiffusion/comments/xi83vo/stable_diffusion_guis_for_apple_silicon/) 🙂
6256

63-
# Clone this repo and create output folder
64-
git clone https://github.com/FahimF/sd-gui.git
65-
cd sd-gui
66-
mkdir output
57+
For installation instructions for each OS, refer to the relevant OS sub-document below for installation instructions. The sub-documents are a work in progress and will be updated over time as I test fully on each OS:
6758

68-
# Clone the Hugging Face model repo - you will need the Hugging Face user and password for this step
69-
git lfs install
70-
git clone https://huggingface.co/CompVis/stable-diffusion-v1-4
71-
```
59+
* [macOS](docs/macos.md)
7260

73-
If all of the above worked correctly and there were no issues, then you should be set 🙂
61+
* [Windows](docs/windows.md)
7462

75-
If you are still at the terminal, simply type the following to launch the UI:
63+
* [Linux](docs/linux.md)
7664

77-
```
78-
python gui.py
65+
## Running the GUI
66+
67+
Once you've complted the installation following the installation instructions above, if you are still at the terminal, simply type the following to launch the UI:
68+
69+
```bash
70+
python app.py
7971
```
8072

8173
If you closed the terminal or want to use the UI at some other point, you'd have to navigate back to where you have this repo (`sd-gui`) before you run the above command.
8274

83-
**Note:** If you are not familiar with conda, do note that every time you close your terminal, your Python environment will revert to the base environment when you next start terminal. But the base environment does not have all the packages you installed above since those are in the `ml` environment. So you have to switch to that environment (and to the `sd-gui` folder) before you can run the GUI again. So you'll need to run something like the following each time you start a new terminal session:
75+
**Note:** If you are not familiar with conda, do note that every time you close your terminal, your Python environment will revert to the base environment when you next start a terminal session.
76+
77+
The base environment does not have all the packages you installed above since those are in the `ml` environment. So you have to switch to that environment (and navigate to the `sd-gui` folder) before you can run the GUI again. So you'll need to run something like the following each time you start a new terminal session:
8478

8579
```bash
8680
conda activate ml
8781
cd sd-gui
88-
python guin.py
82+
python app.py
8983
```
9084

9185
Of course, in the above, change the `cd sd-gui` to put the actual location of `sd-gui` on your hard disk 🙂
9286

93-
### Installation Errors
87+
### Running the Server
88+
89+
90+
91+
## Installation Errors
9492

9593
* If you get a Homebrew error like this: `homebrew-core is a shallow clone` then run the following command in terminal:
9694

@@ -159,6 +157,14 @@ python guin.py
159157

160158
## Known Issues
161159

160+
* The latest Pytorch night (1.13.0.dev20220930) appears to be much slower in generating images on an Apple Silicon machine than the previous Pytorch nightly that I used (1.13.0.dev20220922). I don't know if this is a permanent situation or something that will get fixed in the future. I tried setting up conda to install using the particular nightly version that is faster (at least for me) but conda could not find that particular build — if you have a solution for that, please let me know. If you do want to switch to the faster Pytorch nightly version, the only way I know of is to run the folloiwng command *after* you've completed the installation as detailed above:
161+
162+
```bash
163+
pip install --pre -r requirements.txt -f https://download.pytorch.org/whl/nightly/torch_nightly.html
164+
```
165+
162166
* ~~You get an error message saying: "[indices should be either on cpu or on the same device as the indexed tensor (cpu)](https://github.com/huggingface/diffusers/issues/239)" Know issue that has been reported to Hugging Face. Read the issue comments to see [how it can be fixed](https://github.com/huggingface/diffusers/issues/239#issuecomment-1236092655) by modifying the diffusers source code ...~~(Fixed in the latest Hugging Face diffusers dev branch. Should be out with diffusers 0.4.0)
167+
163168
* ~~You get an error saying: "[Cannot convert a MPS Tensor to float64 dtype as the MPS framework doesn't support float64. Please use float32 instead](https://github.com/huggingface/diffusers/issues/358)" Known issue that has been reported to Hugging Face. Read the issue comments to see [how it can be fixed](https://github.com/huggingface/diffusers/issues/358#issue-1361673427) by modifying the diffusers source code ...~~ (Appears to have been a PyTorch nightly issue.)
169+
164170
* ~~If you try to generate an image using both an image and a text prompt, you'll get a brown image as the result. This used to work previously but is broken in the diffusers 0.3.0 release. [Issue reported](https://github.com/huggingface/diffusers/issues/462).~~ (Appears to have been a PyTorch nightly issue.)

app.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import sys
2+
import pathlib
3+
4+
from tools.config import Config
5+
from PyQt5.QtCore import Qt, pyqtSlot, QThread, QObject, pyqtSignal
6+
from PyQt5.QtGui import QPalette, QColor, QIcon, QTextCursor
7+
from PyQt5.QtWidgets import QMainWindow, QApplication, QTabWidget, QSplitter, QPlainTextEdit
8+
from queue import Queue
9+
from ui.gallery_tab import GalleryTab
10+
from ui.generator_tab import GeneratorTab
11+
from ui.editor_tab import EditorTab
12+
from ui.prompts_tab import PromptsTab
13+
14+
class LogStream(object):
15+
save_stdout = sys.stdout
16+
save_stderr = sys.stderr
17+
18+
def __init__(self, queue):
19+
self.queue = queue
20+
21+
def write(self, text):
22+
self.queue.put(text)
23+
self.save_stdout.write(text)
24+
25+
def flush(self):
26+
pass
27+
28+
class LogReceiver(QObject):
29+
signal = pyqtSignal(str)
30+
31+
def __init__(self, queue, *args, **kwargs):
32+
QObject.__init__(self, *args, **kwargs)
33+
self.queue = queue
34+
35+
@pyqtSlot()
36+
def run(self):
37+
while True:
38+
text = self.queue.get()
39+
self.signal.emit(text)
40+
41+
class Window(QMainWindow):
42+
prev_line = ''
43+
44+
def __init__(self):
45+
super(Window, self).__init__()
46+
self.cfg = Config()
47+
# System color changes
48+
palette = QPalette()
49+
palette.setColor(QPalette.Highlight, QColor.fromRgb(2, 113, 177))
50+
QApplication.setPalette(palette)
51+
# UI elements
52+
self.setWindowTitle("Stable Diffusion")
53+
self.asset_path = pathlib.Path(__file__).parent / 'assets'
54+
self.move(0, 0)
55+
# self.setGeometry(0, 0, 1020, 1150)
56+
self.resize(1150, 1150)
57+
self.setup()
58+
self.show()
59+
60+
def setup(self):
61+
# Main splitter
62+
main_split = QSplitter(Qt.Vertical)
63+
# Tabs
64+
self.tabs = QTabWidget()
65+
self.tabs.setContentsMargins(0, 0, 0, 0)
66+
self.tabGen = GeneratorTab(self.cfg)
67+
self.tabGen.setContentsMargins(0, 0, 0, 0)
68+
self.tabs.addTab(self.tabGen, "Generate Images")
69+
self.tabEditor = EditorTab(self.cfg)
70+
self.tabEditor.setContentsMargins(0, 0, 0, 0)
71+
self.tabs.addTab(self.tabEditor, "Edit Images")
72+
self.tabPrompts = PromptsTab(self.cfg)
73+
self.tabPrompts.setContentsMargins(0, 0, 0, 0)
74+
self.tabs.addTab(self.tabPrompts, "Prompts")
75+
self.tabGallery = GalleryTab(self.cfg)
76+
self.tabGallery.setContentsMargins(0, 0, 0, 0)
77+
self.tabs.addTab(self.tabGallery, "Gallery")
78+
main_split.addWidget(self.tabs)
79+
# Log area
80+
self.logs = QPlainTextEdit()
81+
self.logs.setContentsMargins(0, 0, 0, 0)
82+
self.logs.setReadOnly(True)
83+
main_split.addWidget(self.logs)
84+
main_split.setSizes([1150, 50])
85+
main_split.setStretchFactor(23, 1)
86+
self.setCentralWidget(main_split)
87+
# Pass editor to other tabs which need it
88+
self.tabGen.editor_tab = self.tabEditor
89+
self.tabGallery.editor_tab = self.tabEditor
90+
91+
@pyqtSlot(str)
92+
def log_text(self, line):
93+
self.logs.moveCursor(QTextCursor.End)
94+
if self.prev_line.endswith('it/s]') or self.prev_line.endswith('s/it]'):
95+
if line.endswith('it/s]') or line.endswith('s/it]'):
96+
# Replace last line and move on
97+
cursor = self.logs.textCursor()
98+
cursor.select(QTextCursor.LineUnderCursor)
99+
cursor.removeSelectedText()
100+
cursor.deletePreviousChar()
101+
# Insert new line
102+
self.logs.insertPlainText(line)
103+
self.prev_line = line
104+
105+
if __name__ == '__main__':
106+
# Create Queue and redirect system output to this queue
107+
queue = Queue()
108+
# sys.stdout = sys.stderr = LogStream(queue)
109+
# The app
110+
app = QApplication(sys.argv)
111+
app.setWindowIcon(QIcon(str('assets/icon.png')))
112+
win = Window()
113+
# Create thread that will listen on the other end of the queue, and send the text to log console
114+
thread = QThread()
115+
receiver = LogReceiver(queue)
116+
receiver.signal.connect(win.log_text)
117+
receiver.moveToThread(thread)
118+
thread.started.connect(receiver.run)
119+
thread.start()
120+
# Start app
121+
sys.exit(app.exec_())

assets/draw.png

2.69 KB
Loading

assets/erase.png

2.74 KB
Loading

assets/fill.png

2.83 KB
Loading

assets/gui.jpg

-515 KB
Binary file not shown.

assets/icon.png

11.7 KB
Loading

assets/next.png

1.33 KB
Loading

assets/previous.png

1.33 KB
Loading

0 commit comments

Comments
 (0)