Skip to content

Commit

Permalink
Merge pull request #162 from VoltaML/visual-upgrade
Browse files Browse the repository at this point in the history
UI upgrade, reworked themes, logs, theme editor, custom themes
  • Loading branch information
Stax124 authored Oct 24, 2023
2 parents b500683 + d3c6f2b commit 356f8b6
Show file tree
Hide file tree
Showing 98 changed files with 3,502 additions and 1,962 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ docs/.vitepress/dist
external
/tmp
/data
/data/settings.json
/AITemplate

# Ignore for black
Expand Down
5 changes: 3 additions & 2 deletions api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ async def shutdown_event():
app.include_router(ws.router, prefix="/api/websockets")

# Mount outputs folder
output_folder = Path("data/outputs")
output_folder.mkdir(exist_ok=True)
app.mount("/data/outputs", StaticFiles(directory="data/outputs"), name="outputs")

# Mount static files (css, js, images, etc.)
Expand All @@ -184,7 +182,10 @@ async def shutdown_event():
CacheControlMiddleware, cache_control=CacheControl("no-cache")
)
static_app.mount("/", StaticFiles(directory="frontend/dist/assets"), name="assets")

app.mount("/assets", static_app)
app.mount("/static", StaticFiles(directory="static"), name="extra_static_files")
app.mount("/themes", StaticFiles(directory="data/themes"), name="themes")

origins = ["*"]

Expand Down
14 changes: 14 additions & 0 deletions api/routes/general.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import sys
from pathlib import Path

from fastapi import APIRouter

Expand Down Expand Up @@ -83,3 +84,16 @@ async def queue_clear():
queue.clear()

return {"message": "Queue cleared"}


@router.get("/themes")
async def themes():
"Get all available themes"

path = Path("data/themes")
files = []
for file in path.glob("*.json"):
files.append(file.stem)

files.sort()
return files
6 changes: 3 additions & 3 deletions api/routes/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ async def inpaint_job(job: InpaintQueueEntry):

@router.post("/controlnet")
async def controlnet_job(job: ControlNetQueueEntry):
"Generate variations of the image"
"Generate images based on a reference image"

image_bytes = job.data.image
assert isinstance(image_bytes, bytes)
Expand Down Expand Up @@ -123,7 +123,7 @@ async def realesrgan_upscale_job(job: UpscaleQueueEntry):

@router.post("/generate-aitemplate")
async def generate_aitemplate(request: AITemplateBuildRequest):
"Generate a AITemplate model from a local model"
"Generate an AITemplate model from a local model"

await gpu.build_aitemplate_engine(request)

Expand All @@ -132,7 +132,7 @@ async def generate_aitemplate(request: AITemplateBuildRequest):

@router.post("/generate-dynamic-aitemplate")
async def generate_dynamic_aitemplate(request: AITemplateDynamicBuildRequest):
"Generate a AITemplate engine from a local model"
"Generate an AITemplate engine from a local model"

await gpu.build_dynamic_aitemplate_engine(request)

Expand Down
4 changes: 2 additions & 2 deletions api/routes/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

@router.post("/save")
async def save_configuration(settings: config.Configuration):
"Receive settings from the frontend and save them to the config file"
"Update settings and save them to the config file"

reload_required = False
if config.config.api.device != settings.api.device:
Expand All @@ -40,7 +40,7 @@ async def save_configuration(settings: config.Configuration):

@router.get("/")
async def get_configuration():
"Return the current configuration to the frontend"
"Get current settings"

logger.debug(f"Sending configuration to frontend: {config.config}")
return config.config
Expand Down
1 change: 0 additions & 1 deletion api/websockets/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ def broadcast_sync(self, data: Data):
assert self.loop is not None # For type safety
asyncio.set_event_loop(self.loop)
except AssertionError:
logger.info("WARNING: No event loop found, assuming we are running tests")
return

for connection in self.active_connections:
Expand Down
4 changes: 3 additions & 1 deletion core/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class APIConfig:
# Websockets and intervals
websocket_sync_interval: float = 0.02
websocket_perf_interval: float = 1.0
enable_websocket_logging: bool = True

# TomeSD
use_tomesd: bool = False # really extreme, probably will have to wait around until tome improves a bit
Expand Down Expand Up @@ -234,7 +235,8 @@ class InterrogatorConfig:
class FrontendConfig:
"Configuration for the frontend"

theme: Literal["dark", "light"] = "dark"
theme: str = "dark"
background_image_override: str = ""
enable_theme_editor: bool = False
image_browser_columns: int = 5
on_change_timer: int = 0
Expand Down
27 changes: 27 additions & 0 deletions core/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
import re
import threading
from io import BytesIO
from pathlib import Path
from typing import Dict, List, Union
Expand Down Expand Up @@ -119,3 +120,29 @@ def images_to_response(images: Union[List[Image.Image], List[str]], time: float)
"time": time,
"images": [convert_image_to_base64(i) for i in images], # type: ignore
}


def debounce(wait_time: float):
"""
Decorator that will debounce a function so that it is called after wait_time seconds
If it is called multiple times, will wait for the last call to be debounced and run only this one.
"""

def decorator(function):
def debounced(*args, **kwargs):
def call_function():
debounced._timer = None
return function(*args, **kwargs)

# if we already have a call to the function currently waiting to be executed, reset the timer
if debounced._timer is not None:
debounced._timer.cancel()

# after wait_time, call the function provided to the decorator with its arguments
debounced._timer = threading.Timer(wait_time, call_function)
debounced._timer.start()

debounced._timer = None
return debounced

return decorator
42 changes: 42 additions & 0 deletions core/logger/websocket_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from logging import LogRecord, StreamHandler
from typing import TYPE_CHECKING, Optional

from api import websocket_manager
from api.websockets.data import Data
from core.functions import debounce

if TYPE_CHECKING:
from core.config.config import Configuration


class WebSocketLoggingHandler(StreamHandler):
"Broadcasts log messages to all connected clients."

def __init__(self, config: Optional["Configuration"]):
super().__init__()
self.buffer = []
self.config = config

def emit(self, record: LogRecord):
if not self.config:
return
if self.config.api.enable_websocket_logging is False:
return

msg = f"{record.levelname} {self.format(record)}"
self.buffer.insert(0, msg)

# Prevent buffer from growing too large
if len(self.buffer) > 100:
self.send()

self.debounced_send()

@debounce(0.5)
def debounced_send(self):
self.send()

def send(self):
msg = "\n".join(self.buffer)
self.buffer.clear()
websocket_manager.broadcast_sync(Data(data={"message": msg}, data_type="log"))
21 changes: 21 additions & 0 deletions data/themes/dark.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"volta": {
"base": "dark",
"blur": "6px",
"backgroundImage": "https://raw.githubusercontent.com/VoltaML/voltaML-fast-stable-diffusion/2cf7a8abf1e5035a0dc57a67cd13505653c492f6/static/volta-dark-background.svg"
},
"common": {
"fontSize": "15px",
"fontWeight": "600"
},
"Card": {
"color": "rgba(24, 24, 28, 0.6)"
},
"Layout": {
"color": "rgba(16, 16, 20, 0.6)",
"siderColor": "rgba(24, 24, 28, 0)"
},
"Tabs": {
"colorSegment": "rgba(24, 24, 28, 0.6)"
}
}
10 changes: 10 additions & 0 deletions data/themes/dark_flat.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"volta": {
"base": "dark",
"blur": "0"
},
"common": {
"fontSize": "15px",
"fontWeight": "600"
}
}
21 changes: 21 additions & 0 deletions data/themes/light.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"volta": {
"base": "light",
"blur": "6px",
"backgroundImage": "https://raw.githubusercontent.com/VoltaML/voltaML-fast-stable-diffusion/2cf7a8abf1e5035a0dc57a67cd13505653c492f6/static/volta-light-background.svg"
},
"common": {
"fontSize": "15px",
"fontWeight": "600"
},
"Card": {
"color": "rgba(255, 255, 255, 0.6)"
},
"Layout": {
"color": "rgba(255, 255, 255, 0.6)",
"siderColor": "rgba(24, 24, 28, 0)"
},
"Tabs": {
"colorSegment": "rgba(255, 255, 255, 0.6)"
}
}
10 changes: 10 additions & 0 deletions data/themes/light_flat.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"volta": {
"base": "light",
"blur": "0"
},
"common": {
"fontSize": "15px",
"fontWeight": "600"
}
}
25 changes: 25 additions & 0 deletions frontend/dist/assets/404View.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { d as defineComponent, e as openBlock, f as createElementBlock, g as createVNode, w as withCtx, h as unref, c3 as NResult, i as NCard } from "./index.js";
const _hoisted_1 = { style: { "width": "100vw", "height": "100vh", "display": "flex", "align-items": "center", "justify-content": "center", "backdrop-filter": "blur(4px)" } };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "404View",
setup(__props) {
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
createVNode(unref(NCard), { style: { "max-width": "40vw", "border-radius": "12px" } }, {
default: withCtx(() => [
createVNode(unref(NResult), {
status: "404",
title: "You got lucky, this page doesn't exist!",
description: "Next time, there will be a rickroll.",
size: "large"
})
]),
_: 1
})
]);
};
}
});
export {
_sfc_main as default
};
2 changes: 1 addition & 1 deletion frontend/dist/assets/AboutView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { _ as _export_sfc, o as openBlock, a as createElementBlock, b as createBaseVNode } from "./index.js";
import { _ as _export_sfc, e as openBlock, f as createElementBlock, n as createBaseVNode } from "./index.js";
const _sfc_main = {};
const _hoisted_1 = { class: "about" };
const _hoisted_2 = /* @__PURE__ */ createBaseVNode("h1", null, "This is an about page", -1);
Expand Down
42 changes: 21 additions & 21 deletions frontend/dist/assets/AccelerateView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { T as cB, ae as cM, ad as c, aw as cE, aW as iconSwitchTransition, af as cNotM, d as defineComponent, V as useConfig, aj as useRtl, W as useTheme, a6 as provide, s as h, az as flatten, aA as getSlot, S as createInjectionKey, bi as stepsLight, U as inject, b1 as throwError, c as computed, Z as useThemeClass, ay as resolveWrappedSlot, ak as resolveSlot, aL as NIconSwitchTransition, ao as createKey, a2 as call, al as NBaseIcon, bj as FinishedIcon, bk as ErrorIcon, x as useMessage, v as useState, r as ref, o as openBlock, a as createElementBlock, e as createVNode, w as withCtx, f as unref, B as NSpace, N as NCard, b as createBaseVNode, p as NSelect, h as NButton, i as createTextVNode, m as NModal, z as serverUrl, u as useSettings, k as createBlock, L as NTabPane, M as NTabs } from "./index.js";
import { Q as cB, ab as cM, aa as c, at as cE, aT as iconSwitchTransition, ac as cNotM, d as defineComponent, S as useConfig, ag as useRtl, T as useTheme, a3 as provide, C as h, aw as flatten, ax as getSlot, P as createInjectionKey, bg as stepsLight, R as inject, a_ as throwError, c as computed, W as useThemeClass, av as resolveWrappedSlot, ah as resolveSlot, aI as NIconSwitchTransition, al as createKey, $ as call, ai as NBaseIcon, bh as FinishedIcon, bi as ErrorIcon, b as useMessage, u as useState, D as ref, e as openBlock, f as createElementBlock, g as createVNode, w as withCtx, h as unref, j as NSpace, i as NCard, n as createBaseVNode, x as NSelect, E as NButton, m as createTextVNode, bd as NModal, s as serverUrl, a as useSettings, v as createBlock, G as NTabPane, H as NTabs } from "./index.js";
import { N as NSlider, a as NSwitch } from "./Switch.js";
import { N as NInputNumber } from "./InputNumber.js";
const style = cB("steps", `
Expand Down Expand Up @@ -494,30 +494,30 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
options: modelOptions.value,
style: { "margin-right": "12px" }
}, null, 8, ["value", "options"])
])
]),
_: 1
}),
createVNode(unref(NSpace), {
vertical: "",
justify: "center",
style: { "width": "100%" },
align: "center"
}, {
default: withCtx(() => [
createVNode(unref(NButton), {
style: { "margin-top": "16px", "padding": "0 92px" },
type: "success",
ghost: "",
loading: building.value,
disabled: building.value || modelOptions.value.length === 0,
onClick: onAccelerateClick
]),
createVNode(unref(NSpace), {
vertical: "",
justify: "center",
style: { "width": "100%" },
align: "center"
}, {
default: withCtx(() => [
createTextVNode("Accelerate")
createVNode(unref(NButton), {
style: { "margin-top": "16px", "padding": "0 92px" },
type: "success",
ghost: "",
loading: building.value,
disabled: building.value || modelOptions.value.length === 0,
onClick: onAccelerateClick
}, {
default: withCtx(() => [
createTextVNode("Accelerate")
]),
_: 1
}, 8, ["loading", "disabled"])
]),
_: 1
}, 8, ["loading", "disabled"])
})
]),
_: 1
}),
Expand Down
2 changes: 1 addition & 1 deletion frontend/dist/assets/CloudUpload.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { d as defineComponent, o as openBlock, a as createElementBlock, b as createBaseVNode } from "./index.js";
import { d as defineComponent, e as openBlock, f as createElementBlock, n as createBaseVNode } from "./index.js";
const _hoisted_1 = {
xmlns: "http://www.w3.org/2000/svg",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
Expand Down
2 changes: 1 addition & 1 deletion frontend/dist/assets/DescriptionsItem.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ad as c, T as cB, af as cNotM, ae as cM, aw as cE, aX as insideModal, aY as insidePopover, d as defineComponent, V as useConfig, W as useTheme, c as computed, Z as useThemeClass, bQ as useCompitable, az as flatten, s as h, aT as repeat, aA as getSlot, bR as descriptionsLight, ao as createKey } from "./index.js";
import { aa as c, Q as cB, ac as cNotM, ab as cM, at as cE, aU as insideModal, aV as insidePopover, d as defineComponent, S as useConfig, T as useTheme, c as computed, W as useThemeClass, bS as useCompitable, aw as flatten, C as h, aQ as repeat, ax as getSlot, bT as descriptionsLight, al as createKey } from "./index.js";
function getVNodeChildren(vNode, slotName = "default", fallback = []) {
const { children } = vNode;
if (children !== null && typeof children === "object" && !Array.isArray(children)) {
Expand Down
Loading

0 comments on commit 356f8b6

Please sign in to comment.