From 4574fc2f8fd8c9eddbef7ae189e76a746c03cfe0 Mon Sep 17 00:00:00 2001 From: w4ffl35 <25737761+w4ffl35@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:10:12 -0600 Subject: [PATCH] build fixes --- Dockerfile | 1 + airunner.spec | 297 ++++++------------ build.airunner.linux.prod.spec | 9 +- dobuild.py | 6 +- setup.py | 2 +- src/airunner/alembic.ini | 2 +- src/airunner/app.py | 15 +- src/airunner/handlers/llm/agent/base_agent.py | 5 +- src/airunner/handlers/llm/huggingface_llm.py | 1 + src/airunner/main.py | 16 +- src/airunner/styles_mixin.py | 23 ++ src/airunner/utils/file_system/operations.py | 36 --- src/airunner/widgets/base_widget.py | 25 -- src/airunner/windows/base_window.py | 16 +- src/airunner/windows/main/main_window.py | 59 +--- .../windows/settings/airunner_settings.py | 2 + src/airunner/workers/tts_generator_worker.py | 4 +- 17 files changed, 166 insertions(+), 353 deletions(-) create mode 100644 src/airunner/styles_mixin.py delete mode 100644 src/airunner/utils/file_system/operations.py diff --git a/Dockerfile b/Dockerfile index d327b28aa..c6272e0e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -151,3 +151,4 @@ ENV HOME=/app ENV PATH="/home/appuser/.local/bin:${PATH}" ENV PYTHONUSERBASE=/home/appuser/.local COPY build.airunner.linux.prod.spec build.airunner.linux.prod.spec +RUN echo "test" diff --git a/airunner.spec b/airunner.spec index 35dc47889..e260cebcd 100644 --- a/airunner.spec +++ b/airunner.spec @@ -1,230 +1,129 @@ # -*- mode: python ; coding: utf-8 -*- + +import site import os -import shutil -from PyInstaller.utils.hooks import copy_metadata, collect_data_files -import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5) -os.environ["AIRUNNER_ENVIRONMENT"] = "prod" -libraries = [ - "./venv/lib/python3.10/site-packages/h5py.libs/", - "./venv/lib/python3.10/site-packages/scipy.libs/", - "./venv/lib/python3.10/site-packages/pillow.libs/", - "./venv/lib/python3.10/site-packages/tokenizers/", - "./opencv_python_headless.libs/", - "./venv/lib/python3.10/site-packages/torchaudio/lib/", - "./venv/lib/python3.10/site-packages/torch/lib/", - "/usr/lib/python3.10", - "/usr/lib/x86_64-linux-gnu/", - "/usr/local/lib/", - "/usr/local/lib/python3.10", - "/usr/local/lib/python3.10/dist-packages", - "./venv/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/", - "./venv/lib/python3.10/site-packages/PySide6/Qt/lib/", - "/usr/lib/x86_64-linux-gnu/qt6/plugins/platforms/", - "./venv/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/", -] -os.environ["LD_LIBRARY_PATH"] = ":".join(libraries) -block_cipher = None -DEBUGGING = True -EXCLUDE_BINARIES = True -EXE_NAME = "airunner" # used when creating a binary instead of a folder -EXE_STRIP = False -EXE_UPX = True -EXE_RUNTIME_TMP_DIR = None -COLLECT_NAME = 'airunner' -COLLECT_STRIP = False -COLLECT_UPX = True -datas = [ -] -datas += copy_metadata('tqdm') -datas += copy_metadata('regex') -datas += copy_metadata('requests') -datas += copy_metadata('packaging') -datas += copy_metadata('filelock') -datas += copy_metadata('numpy') -datas += copy_metadata('tokenizers') -datas += copy_metadata('transformers') -datas += copy_metadata('rich') -datas += copy_metadata('sympy') -datas += copy_metadata('opencv-python-headless') -datas += collect_data_files("torch", include_py_files=True) -datas += collect_data_files("torchvision", include_py_files=True) -#datas += collect_data_files("JIT", include_py_files=True) -# datas += collect_data_files("pytorch_lightning", include_py_files=True) -# datas += collect_data_files("lightning_fabric", include_py_files=True) -datas += collect_data_files("transformers", include_py_files=True) -datas += collect_data_files("sympy", include_py_files=True) -datas += collect_data_files("controlnet_aux", include_py_files=True) -datas += collect_data_files("PySide6", include_py_files=True) -# datas += collect_data_files('PySide6', subdir='plugins/platforms') -#datas += [('/usr/lib/x86_64-linux-gnu/qt6/plugins/platforms', 'PySide6/plugins/platforms')] + +# Get the site-packages path +site_packages_path = site.getsitepackages()[0] a = Analysis( - [ - f'./src/airunner/main.py', - ], + ['./src/airunner/main.py'], pathex=[ - "./venv/lib/python3.10/site-packages/", - "./venv/lib/python3.10/site-packages/torch/lib", - "./venv/lib/python3.10/site-packages/tokenizers", - "./venv/lib/python3.10/site-packages/tensorflow", - "/usr/lib/x86_64-linux-gnu/", + './src', ], binaries=[ - ('/usr/lib/x86_64-linux-gnu/libcudnn_ops_infer.so.8', '.'), + ('/usr/lib/x86_64-linux-gnu/libpython3.10.so', '.'), + ('./venv/lib/python3.10/site-packages/tiktoken/_tiktoken.cpython-310-x86_64-linux-gnu.so', '.'), + ('/usr/lib/x86_64-linux-gnu/libcudnn.so.8', '.'), # Add libcudnn shared libraries + ('/usr/lib/x86_64-linux-gnu/libcudnn_adv_infer.so.8', '.'), + ('/usr/lib/x86_64-linux-gnu/libcudnn_adv_train.so.8', '.'), ('/usr/lib/x86_64-linux-gnu/libcudnn_cnn_infer.so.8', '.'), - # ('/usr/lib/x86_64-linux-gnu/qt6/plugins/platforms/libqxcb.so', '.'), - # ('/usr/lib/x86_64-linux-gnu/libxcb-cursor.so', '.') - ('./venv/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/clea.so', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-cursor.so', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-cursor.so.0', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-xinerama.so.0', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-xinput.so.0', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-icccm.so.4', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-image.so.0', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-keysyms.so.1', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-render-util.so.0', '.'), - ('/usr/lib/x86_64-linux-gnu/libxcb-xkb.so.1', '.'), + ('/usr/lib/x86_64-linux-gnu/libcudnn_cnn_train.so.8', '.'), + ('/usr/lib/x86_64-linux-gnu/libcudnn_ops_infer.so.8', '.'), + ('/usr/lib/x86_64-linux-gnu/libcudnn_ops_train.so.8', '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_adv.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_cnn.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_engines_precompiled.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_engines_runtime_compiled.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_graph.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_heuristic.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn_ops.so.9'), '.'), + (os.path.join(site_packages_path, 'nvidia/cudnn/lib/libcudnn.so.9'), '.'), + + ], + datas=[ + ('./src/airunner/alembic.ini', '.'), + (os.path.join(site_packages_path, 'inflect'), 'inflect'), + (os.path.join(site_packages_path, 'controlnet_aux'), 'controlnet_aux'), + (os.path.join(site_packages_path, 'diffusers'), 'diffusers'), + (os.path.join(site_packages_path, 'tiktoken'), 'tiktoken'), + (os.path.join(site_packages_path, 'tiktoken_ext'), 'tiktoken_ext'), + (os.path.join(site_packages_path, 'pydantic'), 'pydantic'), + (os.path.join(site_packages_path, 'xformers'), 'xformers'), + (os.path.join(site_packages_path, 'nvidia'), 'nvidia'), + (os.path.join(site_packages_path, 'llama_index'), 'llama_index'), + # Add other data files or directories here ], - datas=datas, hiddenimports=[ - "xcb-cursor0", - "airunner", - #"JIT", - "tqdm", - "diffusers", - "transformers", - "nvidia", - "torch", - "torchvision", - "torchvision.io", - "logging", - "logging.config", - "einops", - # "omegaconf", - "contextlib", - "itertools", - #"pytorch_lightning", - "huggingface_hub.hf_api", - "huggingface_hub.repository", - "inspect", - "psutil", - "matplotlib", - "numpy", - "PIL._tkinter_finder", - "sympy", - "opencv-python-headless", - "pytz", - "PySide6", + 'airunner', + 'airunner.data.models', + 'airunner.data.models.settings_models', + 'airunner.utils.db.column_exists', + 'airunner.data.bootstrap.controlnet_bootstrap_data', + 'airunner.data.bootstrap.font_settings_bootstrap_data', + 'airunner.data.bootstrap.imagefilter_bootstrap_data', + 'airunner.data.bootstrap.model_bootstrap_data', + 'airunner.data.bootstrap.pipeline_bootstrap_data', + 'airunner.data.bootstrap.prompt_templates_bootstrap_data', + 'diffusers', + 'diffusers.loaders', + 'diffusers.loaders.ip_adapter', + 'diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion', + 'torch', + 'torch.jit', + 'torch.jit._script', + 'torch.jit.frontend', + 'torch._sources', + 'xformers', + 'xformers.ops', + 'xformers.ops.fmha', + 'xformers.ops.fmha.triton_splitk', + 'tiktoken', + 'tiktoken.model', + 'tiktoken.registry', + 'tiktoken_ext', + 'nvidia', + 'nvidia.lib', + 'nvidia.lib.cudnn', + 'llama_index', + 'llama_index.core', + 'llama_index.readers', + 'llama_index.readers.file', + 'llama_index.core.node_parser', + 'llama_index.core.chat_engine', + 'llama_index.core.indices.keyword_table', + 'llama_index.core.base.llms.types', ], hookspath=[], hooksconfig={}, runtime_hooks=[], - excludes=[ - "tcl", - "tcl8", - "cmake", - "cryptography", - "email-validator", - "google", - "google-auth", - "google-auth-oauthlib", - "google-pasta", - "Jinja2", - "lightning-cloud", - "Markdown", - "markdown-it-py", - "MarkupSafe", - "mdurl", - "ninja", - "nvidia-pyindex", - "tensorboard", - "tensorboard-data-server", - "tensorboard-plugin-wit", - "unattended-upgrades", - "watchfiles", - "wcwidth", - "websocket-client", - "websockets", - ], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, + excludes=[], noarchive=False, + optimize=0, ) -pyz = PYZ( - a.pure, - a.zipped_data, - cipher=block_cipher -) +pyz = PYZ(a.pure) + exe = EXE( pyz, a.scripts, [], - exclude_binaries=EXCLUDE_BINARIES, - name=EXE_NAME, - debug=DEBUGGING, - strip=EXE_STRIP, - upx=EXE_UPX, - runtime_tmpdir=EXE_RUNTIME_TMP_DIR, - console=DEBUGGING + exclude_binaries=True, + name='airunner', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + # onefile=True, ) coll = COLLECT( exe, a.binaries, - a.zipfiles, a.datas, - strip=COLLECT_STRIP, - upx=COLLECT_UPX, + strip=False, + upx=True, upx_exclude=[], - name=COLLECT_NAME + name='airunner', ) import shutil -import os -import glob - -# Define source directories -source_dirs = ['./src/airunner/widgets', './src/airunner/windows'] -destination_base_dir = './dist/airunner' - -# Copy all .ui files from source directories to the destination directory -for source_dir in source_dirs: - for templates_dir in glob.glob(os.path.join(source_dir, '**', 'templates'), recursive=True): - for ui_file in glob.glob(os.path.join(templates_dir, '*.ui'), recursive=True): - # Create the corresponding subdirectory in the destination directory - relative_path = os.path.relpath(ui_file, source_dir) - destination_dir = os.path.join(destination_base_dir, os.path.dirname(relative_path)) - os.makedirs(destination_dir, exist_ok=True) - # Copy the .ui file to the destination directory - shutil.copy(ui_file, destination_dir) - - - -os.makedirs('./dist/airunner/diffusers/pipelines/stable_diffusion', exist_ok=True) -os.makedirs('./dist/airunner/images', exist_ok=True) - -# copy files for distribution -# shutil.copyfile('./linux.itch.toml', './dist/airunner/.itch.toml') -shutil.copyfile('./src/airunner/images/splashscreen.png', './dist/airunner/images/splashscreen.png') -shutil.copytree('src/airunner/styles/icons/dark/', './dist/airunner/icons/dark/') -shutil.copytree('src/airunner/styles/icons/light/', './dist/airunner/icons/light/') - -# copy alembic files +shutil.copytree('./src/airunner/images/', './dist/airunner/_internal/airunner/images/') +shutil.copytree('./src/airunner/styles/', './dist/airunner/_internal/airunner/styles/') shutil.copytree('./src/airunner/alembic/', './dist/airunner/_internal/alembic/') -shutil.copyfile('./src/airunner/alembic.ini', './dist/airunner/_internal/alembic.ini') - -# copy bootstrap data shutil.copytree('./src/airunner/data/', './dist/airunner/data/') - -# copy sd config files -# shutil.copyfile('./src/airunner/v1.yaml', './dist/airunner/v1.yaml') -# shutil.copyfile('./src/airunner/v2.yaml', './dist/airunner/v2.yaml') - -# copy llamaindex nltk cache requirements -shutil.copytree('./lib/corpora', './dist/airunner/_internal/llama_index/core/_static/nltk_cache/corpora') -shutil.copytree('./lib/tokenizers', './dist/airunner/_internal/llama_index/core/_static/nltk_cache/tokenizers') - -# shutil.copyfile( -# f'./venv/lib/python3.10/site-packages/JIT/__pycache__/random.cpython-310.pyc', -# f'./dist/airunner/random.pyc' -# ) +shutil.copytree('./lib/tokenizers/punkt', './dist/airunner/_internal/llama_index/core/_static/nltk_cache/tokenizers/punkt') diff --git a/build.airunner.linux.prod.spec b/build.airunner.linux.prod.spec index ee0705207..7c687fd33 100644 --- a/build.airunner.linux.prod.spec +++ b/build.airunner.linux.prod.spec @@ -56,6 +56,7 @@ a = Analysis( f'/app/airunner/src/airunner/main.py', ], pathex=[ + "/app/airunner/src", "/home/appuser/.local/lib/python3.10/site-packages/", "/home/appuser/.local/lib/python3.10/site-packages/torch/lib/", "/home/appuser/.local/lib/python3.10/site-packages/tokenizers/", @@ -195,8 +196,8 @@ os.makedirs('/app/dist/airunner/images', exist_ok=True) # Copy files for distribution shutil.copyfile('/app/airunner/src/airunner/images/splashscreen.png', '/app/dist/airunner/images/splashscreen.png') -shutil.copytree('/app/airunner/src/airunner/styles/icons/dark/', '/app/dist/airunner/styles/icons/dark/') -shutil.copytree('/app/airunner/src/airunner/styles/icons/light/', '/app/dist/airunner/styles/icons/light/') +# shutil.copytree('/app/airunner/src/airunner/styles/icons/dark/', '/app/dist/airunner/styles/icons/dark/') +# shutil.copytree('/app/airunner/src/airunner/styles/icons/light/', '/app/dist/airunner/styles/icons/light/') # Copy alembic files shutil.copytree('/app/airunner/src/airunner/alembic/', '/app/dist/airunner/_internal/alembic/') @@ -206,5 +207,5 @@ shutil.copyfile('/app/airunner/src/airunner/alembic.ini', '/app/dist/airunner/_i shutil.copytree('/app/airunner/src/airunner/data/', '/app/dist/airunner/data/') # Copy llamaindex nltk cache requirements -shutil.copytree('/app/airunner/lib/corpora', '/app/dist/airunner/_internal/llama_index/core/_static/nltk_cache/corpora') -shutil.copytree('/app/airunner/lib/tokenizers', '/app/dist/airunner/_internal/llama_index/core/_static/nltk_cache/tokenizers') +# shutil.copytree('/app/airunner/lib/corpora', '/app/dist/airunner/_internal/llama_index/core/_static/nltk_cache/corpora') +# shutil.copytree('/app/airunner/lib/tokenizers', '/app/dist/airunner/_internal/llama_index/core/_static/nltk_cache/tokenizers') diff --git a/dobuild.py b/dobuild.py index e289cd824..88e37ae4f 100644 --- a/dobuild.py +++ b/dobuild.py @@ -3,7 +3,7 @@ import json -os.chdir("/app/airunner") -os.system("git pull") -os.system("python3 -m pip install .") +# os.chdir("/app/airunner") +# os.system("git pull") +# os.system("python3 -m pip install .") diff --git a/setup.py b/setup.py index d49cc8154..5c067297e 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name="airunner", - version="3.0.16", + version="3.0.17", author="Capsize LLC", description="A Stable Diffusion GUI", long_description=open("README.md", "r", encoding="utf-8").read(), diff --git a/src/airunner/alembic.ini b/src/airunner/alembic.ini index fc78f382d..4c32be0e1 100644 --- a/src/airunner/alembic.ini +++ b/src/airunner/alembic.ini @@ -105,7 +105,7 @@ level = INFO handlers = qualname = alembic -[handler_console] +[handler_console]pyinstaller~/ class = StreamHandler args = (sys.stderr,) level = NOTSET diff --git a/src/airunner/app.py b/src/airunner/app.py index 105fac92e..add0cdd5b 100644 --- a/src/airunner/app.py +++ b/src/airunner/app.py @@ -7,6 +7,8 @@ import signal import traceback from functools import partial +from pathlib import Path + from PySide6 import QtCore from PySide6.QtCore import ( QObject, @@ -29,6 +31,8 @@ from airunner.mediator_mixin import MediatorMixin from airunner.windows.main.settings_mixin import SettingsMixin from airunner.data.models.settings_models import ApplicationSettings, AIModels +from airunner.windows.main.main_window import MainWindow +from airunner.handlers.logger import Logger class App( @@ -43,20 +47,15 @@ class App( def __init__( self, main_window_class: QWindow = None, - restrict_os_access=None, defendatron=None ): """ Initialize the application and run as a GUI application or a socket server. :param main_window_class: The main window class to use for the application. """ - from airunner.windows.main.main_window import MainWindow - from airunner.handlers.logger import Logger - self.main_window_class_ = main_window_class or MainWindow self.app = None self.logger = Logger(prefix=self.__class__.__name__) - self.restrict_os_access = restrict_os_access self.defendatron = defendatron self.splash = None @@ -185,7 +184,10 @@ def display_splash_screen(app): screen = screens.at(0) except AttributeError: screen = screens[0] - pixmap = QPixmap("images/splashscreen.png") + + base_dir = Path(os.path.dirname(os.path.realpath(__file__))) + stylesheet_path = base_dir / "images" / "splashscreen.png" + pixmap = QPixmap(stylesheet_path) splash = QSplashScreen( screen, pixmap, @@ -217,7 +219,6 @@ def show_main_application( """ try: window = self.main_window_class_( - restrict_os_access=self.restrict_os_access, defendatron=self.defendatron ) except Exception as e: diff --git a/src/airunner/handlers/llm/agent/base_agent.py b/src/airunner/handlers/llm/agent/base_agent.py index 2bc9a008a..2d14c2158 100644 --- a/src/airunner/handlers/llm/agent/base_agent.py +++ b/src/airunner/handlers/llm/agent/base_agent.py @@ -9,7 +9,6 @@ from PySide6.QtCore import QObject from llama_index.core import Settings - from llama_index.readers.file import EpubReader, PDFReader, MarkdownReader from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter @@ -830,10 +829,12 @@ def __load_rag(self): def __load_rag_tokenizer(self): self.logger.debug("Loading RAG tokenizer...") + # TODO pass def __load_rag_model(self): self.logger.debug("Loading RAG model...") + # TODO pass def __load_embeddings(self): @@ -856,6 +857,8 @@ def __load_file_extractor(self): } def __load_document_reader(self): + if self.target_files is None or len(self.target_files) == 0: + return self.logger.debug("Loading document reader...") try: self.__document_reader = SimpleDirectoryReader( diff --git a/src/airunner/handlers/llm/huggingface_llm.py b/src/airunner/handlers/llm/huggingface_llm.py index 5cb7e1209..86da6b641 100644 --- a/src/airunner/handlers/llm/huggingface_llm.py +++ b/src/airunner/handlers/llm/huggingface_llm.py @@ -10,6 +10,7 @@ CompletionResponseGen, LLMMetadata, ) + from llama_index.core.bridge.pydantic import Field, PrivateAttr from llama_index.core.callbacks import CallbackManager from llama_index.core.constants import ( diff --git a/src/airunner/main.py b/src/airunner/main.py index 85d1fd1f0..82e89e10b 100755 --- a/src/airunner/main.py +++ b/src/airunner/main.py @@ -38,28 +38,24 @@ ################################################################ from airunner.app import App -################################################################ +############################################################### # Import Alembic modules to run migrations. ################################################################ from alembic.config import Config from alembic import command +from pathlib import Path def setup_database(): - here = os.path.dirname(os.path.abspath(__file__)) - alembic_file = os.path.join( - here, - "alembic.ini" - ) + base_path = Path(os.path.dirname(os.path.realpath(__file__))) + alembic_file = base_path / "alembic.ini" + alembic_dir = base_path / "alembic" alembic_cfg = Config(alembic_file) - # set he script_location to the current directory - alembic_cfg.set_main_option("script_location", os.path.join(here, "alembic")) + alembic_cfg.set_main_option("script_location", str(alembic_dir)) command.upgrade(alembic_cfg, "head") - def main(): setup_database() App( - restrict_os_access=None, defendatron=facehuggershield.huggingface.defendatron ) diff --git a/src/airunner/styles_mixin.py b/src/airunner/styles_mixin.py new file mode 100644 index 000000000..a98e23b65 --- /dev/null +++ b/src/airunner/styles_mixin.py @@ -0,0 +1,23 @@ +import os +from pathlib import Path + +from airunner.settings import DARK_THEME_NAME, LIGHT_THEME_NAME + + +class StylesMixin: + """ + Dependent on the SettingsMixin being used in the same class + """ + def set_stylesheet(self): + """ + Sets the stylesheet for the application based on the current theme + """ + theme_name = DARK_THEME_NAME if self.application_settings.dark_mode_enabled else LIGHT_THEME_NAME + base_dir = Path(os.path.dirname(os.path.realpath(__file__))) + stylesheet_path = base_dir / "styles" / theme_name / "styles.qss" + + self.setStyleSheet( + stylesheet_path.read_text() + if self.application_settings.override_system_theme + else "" + ) diff --git a/src/airunner/utils/file_system/operations.py b/src/airunner/utils/file_system/operations.py deleted file mode 100644 index 1d4f192c4..000000000 --- a/src/airunner/utils/file_system/operations.py +++ /dev/null @@ -1,36 +0,0 @@ -import os -from pathlib import Path -from PySide6.QtCore import QObject -from airunner.mediator_mixin import MediatorMixin -from airunner.settings import DARK_THEME_NAME, LIGHT_THEME_NAME -from airunner.windows.main.settings_mixin import SettingsMixin - - -class FileSystemOperations( - QObject, - MediatorMixin, - SettingsMixin -): - def __init__(self): - MediatorMixin.__init__(self) - SettingsMixin.__init__(self) - super().__init__() - - here = Path(os.path.dirname(os.path.realpath(__file__))) - self.allowed_paths = [ - str(here / ".." / ".." / "styles" / DARK_THEME_NAME / "styles.qss"), - str(here / ".." / ".." / "styles" / LIGHT_THEME_NAME / "styles.qss"), - ] - - def _check_path(self, path): - if path not in self.allowed_paths: - raise PermissionError(f"Access to {path} is not allowed") - - def read_stylesheet(self): - theme_name = DARK_THEME_NAME if self.application_settings.dark_mode_enabled else LIGHT_THEME_NAME - here = Path(os.path.dirname(os.path.realpath(__file__))) - path = str(here / ".." / ".." / "styles" / theme_name / "styles.qss") - - self._check_path(path) - stylesheet_path = Path(path) - return stylesheet_path.read_text() diff --git a/src/airunner/widgets/base_widget.py b/src/airunner/widgets/base_widget.py index 6c2956aad..99b83a675 100644 --- a/src/airunner/widgets/base_widget.py +++ b/src/airunner/widgets/base_widget.py @@ -178,28 +178,3 @@ def set_is_checked(self, element, val): return True except AttributeError: return False - - def set_form_value(self, element, settings_key_name): - val = self.get_plain_text(element) - if val is None: - val = self.get_text(element) - if val is None: - val = self.get_value(element) - if val is None: - val = self.get_is_checked(element) - print("TODO: finish this") - - def set_stylesheet(self, ui=None): - """ - Sets the stylesheet for the application based on the current theme - """ - ui = ui or self - if self.application_settings.override_system_theme: - theme_name = DARK_THEME_NAME if self.application_settings.dark_mode_enabled else LIGHT_THEME_NAME - here = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(here, "..", "styles", theme_name, "styles.qss"), "r") as f: - stylesheet = f.read() - ui.setStyleSheet(stylesheet) - else: - ui.setStyleSheet("") - ui.update() diff --git a/src/airunner/windows/base_window.py b/src/airunner/windows/base_window.py index 484a69ed1..139d377a2 100644 --- a/src/airunner/windows/base_window.py +++ b/src/airunner/windows/base_window.py @@ -3,6 +3,7 @@ from PySide6.QtWidgets import QDialog from airunner.mediator_mixin import MediatorMixin from airunner.settings import DARK_THEME_NAME, LIGHT_THEME_NAME +from airunner.styles_mixin import StylesMixin from airunner.windows.main.ai_model_mixin import AIModelMixin from airunner.windows.main.settings_mixin import SettingsMixin @@ -11,6 +12,7 @@ class BaseWindow( QDialog, MediatorMixin, SettingsMixin, + StylesMixin, AIModelMixin ): template_class_ = None @@ -39,17 +41,3 @@ def __init__(self, **kwargs): def initialize_window(self): pass - - def set_stylesheet(self): - """ - Sets the stylesheet for the application based on the current theme - """ - if self.application_settings.override_system_theme: - theme_name = DARK_THEME_NAME if self.application_settings.dark_mode_enabled else LIGHT_THEME_NAME - here = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(here, "..", "styles", theme_name, "styles.qss"), "r") as f: - stylesheet = f.read() - self.setStyleSheet(stylesheet) - else: - self.setStyleSheet("") - self.update() diff --git a/src/airunner/windows/main/main_window.py b/src/airunner/windows/main/main_window.py index 57183a908..9d1ab87ea 100644 --- a/src/airunner/windows/main/main_window.py +++ b/src/airunner/windows/main/main_window.py @@ -4,6 +4,7 @@ import urllib import webbrowser from functools import partial +from pathlib import Path import requests from PIL import Image @@ -32,7 +33,7 @@ STATUS_NORMAL_COLOR_DARK, NSFW_CONTENT_DETECTED_MESSAGE, ORGANIZATION, - APPLICATION_NAME + APPLICATION_NAME, DARK_THEME_NAME, LIGHT_THEME_NAME ) from airunner.enums import ( SignalCode, @@ -41,14 +42,13 @@ LLMAction, ModelType, ModelStatus ) from airunner.mediator_mixin import MediatorMixin -from airunner.resources_dark_rc import * from airunner.settings import ( BASE_PATH, BUG_REPORT_LINK, VULNERABILITY_REPORT_LINK ) +from airunner.styles_mixin import StylesMixin from airunner.utils.convert_image_to_base64 import convert_image_to_base64 -from airunner.utils.file_system.operations import FileSystemOperations from airunner.utils.get_version import get_version from airunner.utils.set_widget_state import set_widget_state @@ -71,6 +71,7 @@ class MainWindow( QMainWindow, MediatorMixin, SettingsMixin, + StylesMixin, PipelineMixin, AIModelMixin ): @@ -111,7 +112,6 @@ def __init__( tts_enabled: bool = False, stt_enabled: bool = False, ai_mode: bool = True, - restrict_os_access=None, defendatron=None, **kwargs ): @@ -121,11 +121,8 @@ def __init__( self.disable_tts = disable_tts self.disable_stt = disable_stt - self.restrict_os_access = restrict_os_access self.defendatron = defendatron self.quitting = False - self._override_system_theme = None - self._dark_mode_enabled = None self.update_popup = None self._document_path = None self.prompt = None @@ -177,10 +174,6 @@ def __init__( self._updating_settings = False self.register_signals() - self.register( - SignalCode.APPLICATION_SETTINGS_CHANGED_SIGNAL, - self.on_application_settings_changed_signal - ) self.initialize_ui() self.worker_manager = None @@ -558,10 +551,10 @@ def register_signals(self): self.register(SignalCode.TOGGLE_LLM_SIGNAL, self.on_toggle_llm) self.register(SignalCode.APPLICATION_RESET_SETTINGS_SIGNAL, self.action_reset_settings) self.register(SignalCode.APPLICATION_RESET_PATHS_SIGNAL, self.on_reset_paths_signal) - self.register(SignalCode.REFRESH_STYLESHEET_SIGNAL, self.refresh_stylesheet) self.register(SignalCode.MODEL_STATUS_CHANGED_SIGNAL, self.on_model_status_changed_signal) self.register(SignalCode.KEYBOARD_SHORTCUTS_UPDATED, self.on_keyboard_shortcuts_updated) - self.register(SignalCode.HISTORY_UPDATED, self.on_history_updated) + self.register(SignalCode.HISTORY_UPDATED, self.on_history_updated), + self.register(SignalCode.REFRESH_STYLESHEET_SIGNAL, self.on_theme_changed_signal) def on_reset_paths_signal(self): self.reset_path_settings() @@ -600,18 +593,17 @@ def on_bash_execute_signal(self, data: dict) -> str: args = data["args"] return bash_execute(args[0]) - def on_application_settings_changed_signal(self): - if not self._updating_settings: - self.set_stylesheet() + def on_theme_changed_signal(self): + self.set_stylesheet() def initialize_ui(self): self.logger.debug("Loading UI") self.ui.setupUi(self) + self.set_stylesheet() self.restore_state() self.status_widget = StatusWidget() self.statusBar().addPermanentWidget(self.status_widget) self.emit_signal(SignalCode.APPLICATION_CLEAR_STATUS_MESSAGE_SIGNAL) - self.set_stylesheet() self.initialize_widget_elements() self.ui.actionUndo.setEnabled(False) self.ui.actionRedo.setEnabled(False) @@ -917,8 +909,6 @@ def _disable_nsfw_filter(self, show_nsfw_warning=None): self.toggle_nsfw_filter() self.emit_signal(SignalCode.SAFETY_CHECKER_UNLOAD_SIGNAL) - def action_toggle_darkmode(self): - self.set_stylesheet() ###### End window handlers ###### def show_update_message(self): @@ -930,31 +920,6 @@ def show_update_message(self): def show_update_popup(self): self.update_popup = UpdateWindow() - def refresh_stylesheet(self): - self.set_stylesheet(force=True) - - def set_stylesheet(self, ui=None, force=False): - """ - Sets the stylesheet for the application based on the current theme - """ - if ( - self._override_system_theme is not self.application_settings.override_system_theme or - self._dark_mode_enabled is not self.application_settings.dark_mode_enabled or - force - ): - ui = ui or self - self._override_system_theme = self.application_settings.override_system_theme - self._dark_mode_enabled = self.application_settings.dark_mode_enabled - - if self._override_system_theme: - self.logger.debug("Setting stylesheet") - - stylesheet = FileSystemOperations().read_stylesheet() - ui.setStyleSheet(stylesheet) - else: - self.logger.debug("Using system theme") - ui.setStyleSheet("") - def show_setup_wizard(self): AppInstaller(close_on_cancel=False) @@ -1093,12 +1058,6 @@ def _initialize_window(self): self.center() self.set_window_title() - def display(self): - self.logger.debug("Displaying window") - self.set_stylesheet() - self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowType.Window) - self.show() - def center(self): availableGeometry = QGuiApplication.primaryScreen().availableGeometry() frameGeometry = self.frameGeometry() diff --git a/src/airunner/windows/settings/airunner_settings.py b/src/airunner/windows/settings/airunner_settings.py index a917deebb..f9a1e1ba8 100644 --- a/src/airunner/windows/settings/airunner_settings.py +++ b/src/airunner/windows/settings/airunner_settings.py @@ -228,9 +228,11 @@ def on_item_clicked(self, index): elif name == "dark_mode": checked = item.checkState() == Qt.CheckState.Checked self.update_application_settings("dark_mode_enabled", checked) + self.emit_signal(SignalCode.REFRESH_STYLESHEET_SIGNAL) elif name == "override_system_theme": checked = item.checkState() == Qt.CheckState.Checked self.update_application_settings("override_system_theme", checked) + self.emit_signal(SignalCode.REFRESH_STYLESHEET_SIGNAL) elif name == "check_for_updates": checked = item.checkState() == Qt.CheckState.Checked self.update_application_settings("latest_version_check", checked) diff --git a/src/airunner/workers/tts_generator_worker.py b/src/airunner/workers/tts_generator_worker.py index 03a5667f8..8f07e248e 100644 --- a/src/airunner/workers/tts_generator_worker.py +++ b/src/airunner/workers/tts_generator_worker.py @@ -2,6 +2,8 @@ import threading from airunner.enums import SignalCode, TTSModel, ModelStatus +from airunner.handlers.tts.espeak_tts_handler import EspeakTTSHandler +from airunner.handlers.tts.speecht5_tts_handler import SpeechT5TTSHandler from airunner.workers.worker import Worker @@ -68,10 +70,8 @@ def start_worker_thread(self): tts_model = self.tts_settings.model.lower() if tts_model == TTSModel.ESPEAK.value: - from airunner.handlers.tts.espeak_tts_handler import EspeakTTSHandler tts_handler_class_ = EspeakTTSHandler else: - from airunner.handlers.tts.speecht5_tts_handler import SpeechT5TTSHandler tts_handler_class_ = SpeechT5TTSHandler self.tts = tts_handler_class_() if self.application_settings.tts_enabled: