mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
add server class
This commit is contained in:
+4
-1
@@ -66,7 +66,10 @@ def setup_logging(clean=False):
|
||||
"inspect.value.border": "black",
|
||||
}))
|
||||
level = logging.DEBUG if args.debug else logging.INFO
|
||||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s', filename=log_file, filemode='a', encoding='utf-8', force=True)
|
||||
try:
|
||||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s', filename=log_file, filemode='a', encoding='utf-8', force=True)
|
||||
except Exception:
|
||||
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s') # to be able to report unsupported python version
|
||||
log.setLevel(logging.DEBUG) # log to file is always at level debug for facility `sd`
|
||||
pretty_install(console=console)
|
||||
traceback_install(console=console, extra_lines=1, width=console.width, word_wrap=False, indent_guides=False, suppress=[])
|
||||
|
||||
@@ -566,9 +566,9 @@ table.settings-value-table td{
|
||||
|
||||
/* extra networks */
|
||||
.extra-networks > div > [id *= '_extra_']{ margin: 0.3em; }
|
||||
.extra-network-subdirs{ padding: 0.2em 0.35em; }
|
||||
.extra-network-subdirs button{ margin: 0 0.15em; }
|
||||
.extra-networks .tab-nav .search{ display: inline-block; max-width: 16em; margin: 0.3em; align-self: center; width: 16em; }
|
||||
.extra-network-subdirs { padding: 0.2em 0.35em; }
|
||||
.extra-network-subdirs button { margin: 0 0.15em; box-shadow: none; }
|
||||
.extra-networks .tab-nav .search { display: inline-block; max-width: 16em; margin: 0.3em; align-self: center; width: 16em; }
|
||||
#txt2img_extra_view, #img2img_extra_view { width: auto; }
|
||||
.extra-network-cards .nocards, .extra-network-thumbs .nocards{ margin: 1.25em 0.5em 0.5em 0.5em; }
|
||||
.extra-network-cards .nocards h1, .extra-network-thumbs .nocards h1{ font-size: 1.5em; margin-bottom: 1em; }
|
||||
|
||||
@@ -191,10 +191,12 @@ if __name__ == "__main__":
|
||||
while True:
|
||||
try:
|
||||
alive = instance.thread.is_alive()
|
||||
requests = instance.server_state.total_requests if hasattr(instance, 'server_state') else 0
|
||||
except Exception:
|
||||
alive = False
|
||||
requests = 0
|
||||
if round(time.time()) % 120 == 0:
|
||||
installer.log.debug(f'Server alive: {alive} Memory {get_memory_stats()}')
|
||||
installer.log.debug(f'Server alive={alive} Requests={requests} memory {get_memory_stats()} ')
|
||||
if not alive:
|
||||
if instance.wants_restart:
|
||||
installer.log.info('Server restarting...')
|
||||
|
||||
+15
-37
@@ -1,7 +1,6 @@
|
||||
import io
|
||||
import time
|
||||
import base64
|
||||
import logging
|
||||
from io import BytesIO
|
||||
from typing import List, Dict, Any
|
||||
from threading import Lock
|
||||
@@ -637,40 +636,19 @@ class Api:
|
||||
cuda = { 'error': f'{err}' }
|
||||
return models.MemoryResponse(ram = ram, cuda = cuda)
|
||||
|
||||
def launch_uvicorn(self):
|
||||
self.app.include_router(self.router)
|
||||
import uvicorn
|
||||
config: uvicorn.Config = {
|
||||
"host": "0.0.0.0" if shared.cmd_opts.listen else "127.0.0.1",
|
||||
"port": shared.cmd_opts.port if shared.cmd_opts.port else 7861,
|
||||
"loop": "auto", # auto, asyncio, uvloop
|
||||
"http": "auto", # auto, h11, httptools
|
||||
"interface": "auto", # auto, asgi3, asgi2, wsgi
|
||||
"ws": "auto", # auto, websockets, wsproto
|
||||
"log_level": logging.WARNING,
|
||||
"backlog": 4096, # default=2048
|
||||
"timeout_keep_alive": 60, # default=5
|
||||
"ssl_keyfile": shared.cmd_opts.tls_keyfile,
|
||||
"ssl_certfile": shared.cmd_opts.tls_certfile,
|
||||
}
|
||||
shared.log.info(f'API server: Uvicorn options={config}')
|
||||
uvicorn.run(self.app, **config)
|
||||
|
||||
def launch_hypercorn(self):
|
||||
import asyncio
|
||||
import hypercorn
|
||||
import hypercorn.asyncio
|
||||
config = hypercorn.config.Config()
|
||||
config.bind = [f'{"0.0.0.0" if shared.cmd_opts.listen else "127.0.0.1"}:{shared.cmd_opts.port if shared.cmd_opts.port else 7861}']
|
||||
config.keyfile = shared.cmd_opts.tls_keyfile
|
||||
config.certfile = shared.cmd_opts.tls_certfile
|
||||
config.keep_alive_timeout = 60 # default=5
|
||||
config.backlog = 4096 # default=100
|
||||
config.loglevel = "WARNING"
|
||||
config.max_app_queue_size = 64 # default=10
|
||||
shared.log.info(f'API server: Hypercorn options={vars(config)}')
|
||||
instance = hypercorn.asyncio.serve(self.app, config)
|
||||
asyncio.run(instance)
|
||||
|
||||
def launch(self):
|
||||
self.launch_uvicorn()
|
||||
config = {
|
||||
"listen": shared.cmd_opts.listen,
|
||||
"port": shared.cmd_opts.port,
|
||||
"keyfile": shared.cmd_opts.tls_keyfile,
|
||||
"certfile": shared.cmd_opts.tls_certfile,
|
||||
"loop": "auto",
|
||||
"http": "auto",
|
||||
}
|
||||
from modules.server import UvicornServer
|
||||
server = UvicornServer(self.app, **config)
|
||||
# from modules.server import HypercornServer
|
||||
# server = HypercornServer(self.app, **config)
|
||||
server.start()
|
||||
shared.log.info(f'API server: Uvicorn options={config}')
|
||||
return server
|
||||
|
||||
@@ -332,7 +332,6 @@ def read_state_dict(checkpoint_file, map_location=None): # pylint: disable=unuse
|
||||
|
||||
def get_checkpoint_state_dict(checkpoint_info: CheckpointInfo, timer):
|
||||
if checkpoint_info in checkpoints_loaded:
|
||||
# use checkpoint cache
|
||||
shared.log.info("Model weights loading: from cache")
|
||||
return checkpoints_loaded[checkpoint_info]
|
||||
res = read_state_dict(checkpoint_info.filename)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import threading
|
||||
import logging
|
||||
import uvicorn
|
||||
import fastapi
|
||||
|
||||
|
||||
class UvicornServer(uvicorn.Server):
|
||||
def __init__(self, app: fastapi.FastAPI, listen = None, port = None, keyfile = None, certfile = None, loop = "auto", http = "auto"):
|
||||
self.app: fastapi.FastAPI = app
|
||||
self.thread: threading.Thread = None
|
||||
self.wants_restart = False
|
||||
self.config = uvicorn.Config(
|
||||
app=self.app,
|
||||
host = "0.0.0.0" if listen else "127.0.0.1",
|
||||
port = port or 7861,
|
||||
loop = loop, # auto, asyncio, uvloop
|
||||
http = http, # auto, h11, httptools
|
||||
interface = "auto", # auto, asgi3, asgi2, wsgi
|
||||
ws = "auto", # auto, websockets, wsproto
|
||||
log_level = logging.WARNING,
|
||||
backlog = 4096, # default=2048
|
||||
timeout_keep_alive = 60, # default=5
|
||||
ssl_keyfile = keyfile,
|
||||
ssl_certfile = certfile,
|
||||
ws_max_size = 1024 * 1024 * 1024, # default 16MB
|
||||
)
|
||||
super().__init__(config=self.config)
|
||||
|
||||
def start(self):
|
||||
self.thread = threading.Thread(target=self.run, daemon=True)
|
||||
self.wants_restart = False
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
self.should_exit = True
|
||||
self.thread.join()
|
||||
|
||||
def restart(self):
|
||||
self.wants_restart = True
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
|
||||
class HypercornServer():
|
||||
def __init__(self, app: fastapi.FastAPI, listen = None, port = None, keyfile = None, certfile = None, loop = "auto", http = None):
|
||||
import asyncio
|
||||
import hypercorn
|
||||
self.app: fastapi.FastAPI = app
|
||||
self.server: HypercornServer = None
|
||||
self.thread = None
|
||||
self.task = None
|
||||
self.wants_restart = False
|
||||
self.loop = 'trio' if loop == 'auto' else loop # asyncio, uvloop, trio
|
||||
self.config = hypercorn.config.Config()
|
||||
self.config.bind = [f'{"0.0.0.0" if listen else "127.0.0.1"}:{port or 7861}']
|
||||
self.config.keyfile = keyfile
|
||||
self.config.certfile = certfile
|
||||
self.config.keep_alive_timeout = 60 # default=5
|
||||
self.config.backlog = 4096 # default=100
|
||||
self.config.loglevel = "WARNING"
|
||||
self.config.max_app_queue_size = 64 # default=10
|
||||
self.http = http # unused
|
||||
self.main_loop = asyncio.get_event_loop()
|
||||
|
||||
def run(self):
|
||||
import trio
|
||||
from hypercorn.trio import serve
|
||||
self.server = trio.run(serve, self.app, self.config)
|
||||
|
||||
def start(self):
|
||||
if self.loop == 'trio':
|
||||
self.thread = threading.Thread(target=self.run, daemon=True)
|
||||
self.thread.start()
|
||||
elif self.loop == 'asyncio': # does not run in thread
|
||||
import asyncio
|
||||
from hypercorn.asyncio import serve
|
||||
self.server = serve(self.app, self.config)
|
||||
asyncio.run(self.server)
|
||||
elif self.loop == 'uvloop': # does not run in thread
|
||||
import uvloop
|
||||
from hypercorn.asyncio import serve
|
||||
uvloop.install()
|
||||
from hypercorn.asyncio import serve
|
||||
self.server = serve(self.app, self.config)
|
||||
asyncio.run(self.server)
|
||||
+4
-4
@@ -237,10 +237,10 @@ def create_toprow(is_img2img):
|
||||
pause.click(fn=lambda: modules.shared.state.pause(), _js='checkPaused', inputs=[], outputs=[])
|
||||
with gr.Row(elem_id=f"{id_part}_tools"):
|
||||
paste = ToolButton(value=paste_symbol, elem_id="paste")
|
||||
clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
|
||||
extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks")
|
||||
prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply")
|
||||
save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create")
|
||||
clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt_btn")
|
||||
extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks_btn")
|
||||
prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply_btn")
|
||||
save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create_btn")
|
||||
clear_prompt_button.click(fn=lambda *x: x, _js="confirm_clear_prompt", inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt])
|
||||
with gr.Row(elem_id=f"{id_part}_counters"):
|
||||
token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"])
|
||||
|
||||
@@ -88,6 +88,10 @@ class ExtraNetworksPage:
|
||||
return abspath[len(parentdir):].replace('\\', '/')
|
||||
return ""
|
||||
|
||||
def is_empty(self, folder):
|
||||
files = [f for f in os.listdir(folder) if f.lower().endswith(".ckpt") or f.lower().endswith(".safetensors") or f.lower().endswith(".pt")]
|
||||
return len(files) == 0
|
||||
|
||||
def create_html(self, tabname):
|
||||
view = shared.opts.extra_networks_default_view
|
||||
items_html = ''
|
||||
@@ -103,15 +107,13 @@ class ExtraNetworksPage:
|
||||
subdir = os.path.abspath(x)[len(parentdir):].replace("\\", "/")
|
||||
while subdir.startswith("/"):
|
||||
subdir = subdir[1:]
|
||||
is_empty = len(os.listdir(x)) == 0
|
||||
if not is_empty and not subdir.endswith("/"):
|
||||
subdir = subdir + "/"
|
||||
subdirs[subdir] = 1
|
||||
if not self.is_empty(x):
|
||||
subdirs[subdir] = 1
|
||||
if subdirs:
|
||||
subdirs = {"": 1, **subdirs}
|
||||
subdirs_html = "".join([f"""
|
||||
<button class='lg secondary gradio-button custom-button{" search-all" if subdir=="" else ""}' onclick='extraNetworksSearchButton("{tabname}_extra_tabs", event)'>
|
||||
{html.escape(subdir if subdir!="" else "all")}
|
||||
{html.escape(subdir) if subdir!="" else "all"}
|
||||
</button>""" for subdir in subdirs])
|
||||
try:
|
||||
self.items = list(self.list_items())
|
||||
|
||||
@@ -258,6 +258,7 @@ def start_ui():
|
||||
prevent_thread_lock=True,
|
||||
max_threads=64,
|
||||
show_api=True,
|
||||
quiet=True,
|
||||
favicon_path='html/logo.ico',
|
||||
allowed_paths=[os.path.dirname(__file__), cmd_opts.data_dir],
|
||||
app_kwargs=fastapi_args,
|
||||
@@ -335,8 +336,8 @@ def api_only():
|
||||
modules.script_callbacks.app_started_callback(None, app)
|
||||
modules.sd_models.write_metadata()
|
||||
log.info(f"Startup time: {startup_timer.summary()}")
|
||||
api.launch()
|
||||
return api
|
||||
server = api.launch()
|
||||
return server
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user