2023-05-20 15:26:16 -06:00
from __future__ import annotations
2022-08-27 12:32:28 -06:00
import os
2023-01-03 08:38:21 -07:00
import sys
2022-10-01 14:47:42 -06:00
import time
2022-10-01 15:50:03 -06:00
import importlib
2022-08-31 02:04:19 -06:00
import signal
2023-01-03 18:43:05 -07:00
import re
2023-03-12 06:51:12 -06:00
import warnings
2023-03-29 15:46:03 -06:00
import json
2023-05-02 00:08:00 -06:00
from threading import Thread
2023-05-19 08:28:41 -06:00
from typing import Iterable
2023-05-02 00:08:00 -06:00
2023-06-12 03:21:01 -06:00
from fastapi import FastAPI
2022-11-04 12:36:47 -06:00
from fastapi . middleware . cors import CORSMiddleware
2022-10-07 15:56:00 -06:00
from fastapi . middleware . gzip import GZipMiddleware
2023-01-23 07:17:31 -07:00
from packaging import version
2022-10-07 15:56:00 -06:00
2023-01-23 11:28:59 -07:00
import logging
2023-05-19 07:08:40 -06:00
2023-01-23 11:28:59 -07:00
logging . getLogger ( " xformers " ) . addFilter ( lambda record : ' A matching Triton is not available ' not in record . getMessage ( ) )
2023-05-21 12:55:14 -06:00
from modules import paths , timer , import_hook , errors , devices # noqa: F401
2023-03-11 06:27:58 -07:00
2023-05-20 15:41:41 -06:00
startup_timer = timer . startup_timer
2022-10-06 04:21:32 -06:00
2023-01-03 18:43:05 -07:00
import torch
2023-05-10 00:02:23 -06:00
import pytorch_lightning # noqa: F401 # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them
2023-03-14 05:46:09 -06:00
warnings . filterwarnings ( action = " ignore " , category = DeprecationWarning , module = " pytorch_lightning " )
2023-03-30 08:57:54 -06:00
warnings . filterwarnings ( action = " ignore " , category = UserWarning , module = " torchvision " )
2023-04-29 03:36:50 -06:00
2023-03-30 08:57:54 -06:00
2023-03-11 06:27:58 -07:00
startup_timer . record ( " import torch " )
import gradio
startup_timer . record ( " import gradio " )
2023-05-10 00:02:23 -06:00
import ldm . modules . encoders . modules # noqa: F401
2023-03-11 06:27:58 -07:00
startup_timer . record ( " import ldm " )
2023-05-19 06:35:16 -06:00
from modules import extra_networks
2023-05-11 01:09:29 -06:00
from modules . call_queue import wrap_gradio_gpu_call , wrap_queued_call , queue_lock # noqa: F401
2023-01-20 22:36:07 -07:00
2023-01-03 18:43:05 -07:00
# Truncate version number of nightly/local build of PyTorch to not cause exceptions with CodeFormer or Safetensors
if " .dev " in torch . __version__ or " +git " in torch . __version__ :
2023-02-18 09:31:02 -07:00
torch . __long_version__ = torch . __version__
2023-01-06 05:06:26 -07:00
torch . __version__ = re . search ( r ' [ \ d.]+[ \ d] ' , torch . __version__ ) . group ( 0 )
2023-01-03 18:43:05 -07:00
2023-05-09 23:43:42 -06:00
from modules import shared , sd_samplers , upscaler , extensions , localization , ui_tempdir , ui_extra_networks , config_states
2022-09-26 08:29:50 -06:00
import modules . codeformer_model as codeformer
import modules . face_restoration
import modules . gfpgan_model as gfpgan
2022-09-03 03:08:45 -06:00
import modules . img2img
2022-10-02 06:56:22 -06:00
2022-09-26 08:29:50 -06:00
import modules . lowvram
import modules . scripts
import modules . sd_hijack
2023-05-18 13:48:28 -06:00
import modules . sd_hijack_optimizations
2022-09-17 03:05:04 -06:00
import modules . sd_models
2022-10-30 08:54:31 -06:00
import modules . sd_vae
2023-05-27 06:47:33 -06:00
import modules . sd_unet
2022-09-26 08:29:50 -06:00
import modules . txt2img
2022-10-30 08:46:43 -06:00
import modules . script_callbacks
2023-01-09 13:35:40 -07:00
import modules . textual_inversion . textual_inversion
2023-01-15 08:50:56 -07:00
import modules . progress
2022-10-02 06:56:22 -06:00
2022-09-26 08:29:50 -06:00
import modules . ui
2022-09-26 09:27:18 -06:00
from modules import modelloader
2022-09-26 08:29:50 -06:00
from modules . shared import cmd_opts
2022-10-11 06:51:22 -06:00
import modules . hypernetworks . hypernetwork
2022-09-03 03:08:45 -06:00
2023-03-11 06:27:58 -07:00
startup_timer . record ( " other imports " )
2022-11-27 01:52:53 -07:00
2022-11-14 13:07:13 -07:00
if cmd_opts . server_name :
server_name = cmd_opts . server_name
else :
server_name = " 0.0.0.0 " if cmd_opts . listen else None
2022-09-08 03:17:26 -06:00
2022-11-27 01:52:53 -07:00
2023-04-29 01:21:01 -06:00
def fix_asyncio_event_loop_policy ( ) :
"""
The default ` asyncio ` event loop policy only automatically creates
event loops in the main threads . Other threads must create event
loops explicitly or ` asyncio . get_event_loop ` ( and therefore
` . IOLoop . current ` ) will fail . Installing this policy allows event
loops to be created automatically on any thread , matching the
behavior of Tornado versions prior to 5.0 ( or 5.0 on Python 2 ) .
"""
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
import asyncio
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
if sys . platform == " win32 " and hasattr ( asyncio , " WindowsSelectorEventLoopPolicy " ) :
# "Any thread" and "selector" should be orthogonal, but there's not a clean
# interface for composing policies so pick the right base.
_BasePolicy = asyncio . WindowsSelectorEventLoopPolicy # type: ignore
else :
_BasePolicy = asyncio . DefaultEventLoopPolicy
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
class AnyThreadEventLoopPolicy ( _BasePolicy ) : # type: ignore
""" Event loop policy that allows loop creation on any thread.
Usage : :
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
asyncio . set_event_loop_policy ( AnyThreadEventLoopPolicy ( ) )
"""
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
def get_event_loop ( self ) - > asyncio . AbstractEventLoop :
try :
return super ( ) . get_event_loop ( )
except ( RuntimeError , AssertionError ) :
# This was an AssertionError in python 3.4.2 (which ships with debian jessie)
# and changed to a RuntimeError in 3.4.3.
# "There is no current event loop in thread %r"
loop = self . new_event_loop ( )
self . set_event_loop ( loop )
return loop
2023-04-03 03:05:49 -06:00
2023-04-29 01:21:01 -06:00
asyncio . set_event_loop_policy ( AnyThreadEventLoopPolicy ( ) )
2023-04-03 03:05:49 -06:00
2022-11-27 01:52:53 -07:00
2023-01-23 07:17:31 -07:00
def check_versions ( ) :
2023-01-30 04:56:28 -07:00
if shared . cmd_opts . skip_version_check :
return
2023-04-29 03:36:50 -06:00
expected_torch_version = " 2.0.0 "
2023-01-23 07:17:31 -07:00
if version . parse ( torch . __version__ ) < version . parse ( expected_torch_version ) :
errors . print_error_explanation ( f """
You are running torch { torch . __version__ } .
The program is tested to work with torch { expected_torch_version } .
To reinstall the desired version , run with commandline flag - - reinstall - torch .
2023-01-30 04:56:28 -07:00
Beware that this will cause a lot of large files to be downloaded , as well as
there are reports of issues with training tab on the latest version .
Use - - skip - version - check commandline argument to disable this check .
2023-01-23 07:17:31 -07:00
""" .strip())
2023-05-28 06:42:19 -06:00
expected_xformers_version = " 0.0.20 "
2023-01-23 07:17:31 -07:00
if shared . xformers_available :
import xformers
if version . parse ( xformers . __version__ ) < version . parse ( expected_xformers_version ) :
errors . print_error_explanation ( f """
You are running xformers { xformers . __version__ } .
The program is tested to work with xformers { expected_xformers_version } .
To reinstall the desired version , run with commandline flag - - reinstall - xformers .
2023-01-30 04:56:28 -07:00
Use - - skip - version - check commandline argument to disable this check .
2023-01-23 07:17:31 -07:00
""" .strip())
2023-05-17 08:06:45 -06:00
def restore_config_state_file ( ) :
2023-03-29 15:46:03 -06:00
config_state_file = shared . opts . restore_config_state_file
2023-05-17 08:06:45 -06:00
if config_state_file == " " :
return
2023-03-29 15:46:03 -06:00
shared . opts . restore_config_state_file = " "
shared . opts . save ( shared . config_filename )
if os . path . isfile ( config_state_file ) :
print ( f " *** About to restore extension state from file: { config_state_file } " )
with open ( config_state_file , " r " , encoding = " utf-8 " ) as f :
config_state = json . load ( f )
2023-03-29 17:32:54 -06:00
config_states . restore_extension_config ( config_state )
2023-03-29 15:46:03 -06:00
startup_timer . record ( " restore extension config " )
2023-03-29 18:22:45 -06:00
elif config_state_file :
2023-03-29 17:32:54 -06:00
print ( f " !!! Config state backup not found: { config_state_file } " )
2023-03-29 15:46:03 -06:00
2023-05-17 08:06:45 -06:00
2023-05-19 06:52:29 -06:00
def validate_tls_options ( ) :
if not ( cmd_opts . tls_keyfile and cmd_opts . tls_certfile ) :
return
try :
if not os . path . exists ( cmd_opts . tls_keyfile ) :
print ( " Invalid path to TLS keyfile given " )
if not os . path . exists ( cmd_opts . tls_certfile ) :
print ( f " Invalid path to TLS certfile: ' { cmd_opts . tls_certfile } ' " )
except TypeError :
cmd_opts . tls_keyfile = cmd_opts . tls_certfile = None
print ( " TLS setup invalid, running webui without TLS " )
else :
print ( " Running with TLS " )
startup_timer . record ( " TLS " )
2023-05-19 08:28:41 -06:00
def get_gradio_auth_creds ( ) - > Iterable [ tuple [ str , . . . ] ] :
"""
Convert the gradio_auth and gradio_auth_path commandline arguments into
an iterable of ( username , password ) tuples .
"""
def process_credential_line ( s ) - > tuple [ str , . . . ] | None :
s = s . strip ( )
if not s :
return None
return tuple ( s . split ( ' : ' , 1 ) )
if cmd_opts . gradio_auth :
for cred in cmd_opts . gradio_auth . split ( ' , ' ) :
cred = process_credential_line ( cred )
if cred :
yield cred
if cmd_opts . gradio_auth_path :
with open ( cmd_opts . gradio_auth_path , ' r ' , encoding = " utf8 " ) as file :
for line in file . readlines ( ) :
for cred in line . strip ( ) . split ( ' , ' ) :
cred = process_credential_line ( cred )
if cred :
yield cred
2023-05-19 06:54:47 -06:00
def configure_sigint_handler ( ) :
# make the program just exit at ctrl+c without waiting for anything
def sigint_handler ( sig , frame ) :
print ( f ' Interrupted with signal { sig } in { frame } ' )
os . _exit ( 0 )
if not os . environ . get ( " COVERAGE_RUN " ) :
# Don't install the immediate-quit handler when running under coverage,
# as then the coverage report won't be generated.
signal . signal ( signal . SIGINT , sigint_handler )
2023-05-19 07:00:53 -06:00
def configure_opts_onchange ( ) :
shared . opts . onchange ( " sd_model_checkpoint " , wrap_queued_call ( lambda : modules . sd_models . reload_model_weights ( ) ) , call = False )
shared . opts . onchange ( " sd_vae " , wrap_queued_call ( lambda : modules . sd_vae . reload_vae_weights ( ) ) , call = False )
shared . opts . onchange ( " sd_vae_as_default " , wrap_queued_call ( lambda : modules . sd_vae . reload_vae_weights ( ) ) , call = False )
shared . opts . onchange ( " temp_dir " , ui_tempdir . on_tmpdir_changed )
shared . opts . onchange ( " gradio_theme " , shared . reload_gradio_theme )
2023-05-20 13:29:51 -06:00
shared . opts . onchange ( " cross_attention_optimization " , wrap_queued_call ( lambda : modules . sd_hijack . model_hijack . redo_hijack ( shared . sd_model ) ) , call = False )
2023-05-19 07:00:53 -06:00
startup_timer . record ( " opts onchange " )
2023-05-17 08:06:45 -06:00
def initialize ( ) :
fix_asyncio_event_loop_policy ( )
2023-05-19 06:52:29 -06:00
validate_tls_options ( )
2023-05-19 06:54:47 -06:00
configure_sigint_handler ( )
2023-05-17 08:06:45 -06:00
check_versions ( )
2023-05-19 07:08:40 -06:00
modelloader . cleanup_models ( )
configure_opts_onchange ( )
modules . sd_models . setup_model ( )
startup_timer . record ( " setup SD model " )
codeformer . setup_model ( cmd_opts . codeformer_models_path )
startup_timer . record ( " setup codeformer " )
gfpgan . setup_model ( cmd_opts . gfpgan_models_path )
startup_timer . record ( " setup gfpgan " )
initialize_rest ( reload_script_modules = False )
2023-05-17 08:06:45 -06:00
2023-05-19 07:08:40 -06:00
def initialize_rest ( * , reload_script_modules = False ) :
"""
Called both from initialize ( ) and when reloading the webui .
"""
sd_samplers . set_samplers ( )
2023-05-17 08:06:45 -06:00
extensions . list_extensions ( )
startup_timer . record ( " list extensions " )
restore_config_state_file ( )
2022-10-20 09:58:52 -06:00
if cmd_opts . ui_debug_mode :
2022-10-24 00:39:46 -06:00
shared . sd_upscalers = upscaler . UpscalerLanczos ( ) . scalers
modules . scripts . load_scripts ( )
2022-10-20 09:58:52 -06:00
return
2022-10-24 00:39:46 -06:00
2023-05-19 07:08:40 -06:00
modules . sd_models . list_models ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " list SD models " )
2023-05-19 07:08:40 -06:00
localization . list_localizations ( cmd_opts . localizations_dir )
2022-08-25 12:52:05 -06:00
2023-05-20 15:41:41 -06:00
with startup_timer . subcategory ( " load scripts " ) :
modules . scripts . load_scripts ( )
2023-03-11 06:27:58 -07:00
2023-05-19 07:08:40 -06:00
if reload_script_modules :
for module in [ module for name , module in sys . modules . items ( ) if name . startswith ( " modules.ui " ) ] :
importlib . reload ( module )
startup_timer . record ( " reload script modules " )
2023-05-02 09:44:16 -06:00
modelloader . load_upscalers ( )
2023-05-10 14:41:08 -06:00
startup_timer . record ( " load upscalers " )
2023-05-02 09:44:16 -06:00
2022-10-30 08:54:31 -06:00
modules . sd_vae . refresh_vae_list ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " refresh VAE " )
2023-01-09 13:35:40 -07:00
modules . textual_inversion . textual_inversion . list_textual_inversion_templates ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " refresh textual inversion templates " )
2023-01-09 13:35:40 -07:00
2023-05-18 13:48:28 -06:00
modules . script_callbacks . on_list_optimizers ( modules . sd_hijack_optimizations . list_optimizers )
modules . sd_hijack . list_optimizers ( )
startup_timer . record ( " scripts list_optimizers " )
2023-05-27 06:47:33 -06:00
modules . sd_unet . list_unets ( )
startup_timer . record ( " scripts list_unets " )
2023-05-23 09:02:09 -06:00
def load_model ( ) :
"""
Accesses shared . sd_model property to load model .
After it ' s available, if it has been loaded before this access by some extension,
its optimization may be None because the list of optimizaers has neet been filled
by that time , so we apply optimization again .
"""
shared . sd_model # noqa: B018
if modules . sd_hijack . current_optimizer is None :
modules . sd_hijack . apply_optimizations ( )
Thread ( target = load_model ) . start ( )
2023-01-13 23:56:59 -07:00
2023-05-21 12:55:14 -06:00
Thread ( target = devices . first_time_calculation ) . start ( )
2023-01-13 23:56:59 -07:00
2023-01-20 22:36:07 -07:00
shared . reload_hypernetworks ( )
2023-05-19 07:08:40 -06:00
startup_timer . record ( " reload hypernetworks " )
2023-01-20 22:36:07 -07:00
2023-05-19 06:27:23 -06:00
ui_extra_networks . initialize ( )
2023-05-19 06:35:16 -06:00
ui_extra_networks . register_default_pages ( )
2023-01-20 22:36:07 -07:00
extra_networks . initialize ( )
2023-05-19 06:35:16 -06:00
extra_networks . register_default_extra_networks ( )
2023-05-19 07:08:40 -06:00
startup_timer . record ( " initialize extra networks " )
2022-08-31 13:19:30 -06:00
2022-10-02 12:26:38 -06:00
2023-03-11 10:01:08 -07:00
def setup_middleware ( app ) :
2023-05-19 06:37:13 -06:00
app . middleware_stack = None # reset current middleware to allow modifying user provided list
2023-03-11 10:01:08 -07:00
app . add_middleware ( GZipMiddleware , minimum_size = 1000 )
2023-05-19 06:37:13 -06:00
configure_cors_middleware ( app )
app . build_middleware_stack ( ) # rebuild middleware stack on-the-fly
def configure_cors_middleware ( app ) :
cors_options = {
" allow_methods " : [ " * " ] ,
" allow_headers " : [ " * " ] ,
" allow_credentials " : True ,
}
if cmd_opts . cors_allow_origins :
cors_options [ " allow_origins " ] = cmd_opts . cors_allow_origins . split ( ' , ' )
if cmd_opts . cors_allow_origins_regex :
cors_options [ " allow_origin_regex " ] = cmd_opts . cors_allow_origins_regex
app . add_middleware ( CORSMiddleware , * * cors_options )
2022-11-04 12:36:47 -06:00
2022-10-17 10:58:34 -06:00
def create_api ( app ) :
2022-10-17 02:38:32 -06:00
from modules . api . api import Api
2022-10-18 00:51:53 -06:00
api = Api ( app , queue_lock )
2022-10-17 10:58:34 -06:00
return api
2022-10-31 08:36:45 -06:00
2022-10-17 10:58:34 -06:00
def api_only ( ) :
initialize ( )
2022-10-01 11:31:58 -06:00
2022-10-17 10:58:34 -06:00
app = FastAPI ( )
2023-03-11 10:01:08 -07:00
setup_middleware ( app )
2022-10-17 10:58:34 -06:00
api = create_api ( app )
2022-11-02 01:04:35 -06:00
modules . script_callbacks . app_started_callback ( None , app )
2023-03-11 06:27:58 -07:00
print ( f " Startup time: { startup_timer . summary ( ) } . " )
2022-10-17 10:58:34 -06:00
api . launch ( server_name = " 0.0.0.0 " if cmd_opts . listen else " 127.0.0.1 " , port = cmd_opts . port if cmd_opts . port else 7861 )
2022-10-06 03:08:48 -06:00
2023-05-16 11:58:35 -06:00
2022-10-20 09:32:17 -06:00
def webui ( ) :
launch_api = cmd_opts . api
2022-10-17 02:38:32 -06:00
initialize ( )
2022-10-17 00:58:42 -06:00
2022-10-17 02:38:32 -06:00
while 1 :
2022-11-27 01:52:53 -07:00
if shared . opts . clean_temp_dir_at_start :
ui_tempdir . cleanup_tmpdr ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " cleanup temp dir " )
2022-11-27 01:52:53 -07:00
2023-01-21 06:15:53 -07:00
modules . script_callbacks . before_ui_callback ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " scripts before_ui_callback " )
2023-01-21 06:15:53 -07:00
2022-11-27 23:00:10 -07:00
shared . demo = modules . ui . create_ui ( )
2023-03-11 06:27:58 -07:00
startup_timer . record ( " create ui " )
2022-10-18 09:51:36 -06:00
2023-03-20 23:49:08 -06:00
if not cmd_opts . no_gradio_queue :
2023-01-21 08:47:54 -07:00
shared . demo . queue ( 64 )
2023-05-19 08:28:41 -06:00
gradio_auth_creds = list ( get_gradio_auth_creds ( ) ) or None
2023-02-19 03:11:48 -07:00
2023-01-14 03:38:10 -07:00
app , local_url , share_url = shared . demo . launch (
2022-10-02 12:26:38 -06:00
share = cmd_opts . share ,
2022-11-05 03:06:51 -06:00
server_name = server_name ,
2022-10-02 12:26:38 -06:00
server_port = cmd_opts . port ,
2022-11-05 03:06:51 -06:00
ssl_keyfile = cmd_opts . tls_keyfile ,
ssl_certfile = cmd_opts . tls_certfile ,
2023-04-27 19:30:19 -06:00
ssl_verify = cmd_opts . disable_tls_verify ,
2022-10-02 12:26:38 -06:00
debug = cmd_opts . gradio_debug ,
2023-05-19 08:28:41 -06:00
auth = gradio_auth_creds ,
2023-06-05 11:52:05 -06:00
inbrowser = cmd_opts . autolaunch and os . getenv ( ' SD_WEBUI_RESTARTING ' ) != ' 1 ' ,
2023-05-18 01:36:11 -06:00
prevent_thread_lock = True ,
allowed_paths = cmd_opts . gradio_allowed_path ,
2023-05-22 00:53:24 -06:00
app_kwargs = {
" docs_url " : " /docs " ,
" redoc_url " : " /redoc " ,
} ,
2022-10-02 12:26:38 -06:00
)
2023-05-11 14:46:45 -06:00
2023-06-05 11:47:18 -06:00
# after initial launch, disable --autolaunch for subsequent restarts
cmd_opts . autolaunch = False
2023-03-11 06:27:58 -07:00
startup_timer . record ( " gradio launch " )
2022-11-04 01:07:29 -06:00
# gradio uses a very open CORS policy via app.user_middleware, which makes it possible for
# an attacker to trick the user into opening a malicious HTML page, which makes a request to the
2022-12-14 19:01:32 -07:00
# running web ui and do whatever the attacker wants, including installing an extension and
# running its code. We disable this here. Suggested by RyotaK.
2022-11-04 01:07:29 -06:00
app . user_middleware = [ x for x in app . user_middleware if x . cls . __name__ != ' CORSMiddleware ' ]
2023-03-11 10:01:08 -07:00
setup_middleware ( app )
2022-10-02 12:26:38 -06:00
2023-01-15 08:50:56 -07:00
modules . progress . setup_progress_api ( app )
2023-05-08 07:46:35 -06:00
modules . ui . setup_ui_api ( app )
2023-01-15 08:50:56 -07:00
2022-10-31 08:36:45 -06:00
if launch_api :
2022-10-17 10:58:34 -06:00
create_api ( app )
2022-10-02 12:26:38 -06:00
2023-01-28 12:52:27 -07:00
ui_extra_networks . add_pages_to_demo ( app )
2023-05-20 15:41:41 -06:00
startup_timer . record ( " add APIs " )
with startup_timer . subcategory ( " app_started_callback " ) :
modules . script_callbacks . app_started_callback ( shared . demo , app )
2023-03-11 06:27:58 -07:00
2023-05-20 15:41:41 -06:00
timer . startup_record = startup_timer . dump ( )
2023-03-11 06:27:58 -07:00
print ( f " Startup time: { startup_timer . summary ( ) } . " )
2022-10-30 08:46:43 -06:00
2023-04-25 08:27:24 -06:00
if cmd_opts . subpath :
redirector = FastAPI ( )
redirector . get ( " / " )
2023-05-09 22:52:45 -06:00
gradio . mount_gradio_app ( redirector , shared . demo , path = f " / { cmd_opts . subpath } " )
2023-04-25 08:27:24 -06:00
2023-05-11 14:46:45 -06:00
try :
while True :
server_command = shared . state . wait_for_server_command ( timeout = 5 )
if server_command :
if server_command in ( " stop " , " restart " ) :
break
else :
print ( f " Unknown server command: { server_command } " )
except KeyboardInterrupt :
2023-05-16 11:58:35 -06:00
print ( ' Caught KeyboardInterrupt, stopping... ' )
2023-05-11 14:46:45 -06:00
server_command = " stop "
if server_command == " stop " :
2023-05-16 11:58:35 -06:00
print ( " Stopping server... " )
2023-05-11 14:46:45 -06:00
# If we catch a keyboard interrupt, we want to stop the server and exit.
shared . demo . close ( )
break
2023-05-20 15:41:41 -06:00
2023-01-03 08:38:21 -07:00
print ( ' Restarting UI... ' )
2023-05-11 14:46:45 -06:00
shared . demo . close ( )
time . sleep ( 0.5 )
2023-03-12 12:25:22 -06:00
startup_timer . reset ( )
2023-05-19 07:08:40 -06:00
modules . script_callbacks . app_reload_callback ( )
startup_timer . record ( " app reload callback " )
2023-01-06 03:55:50 -07:00
modules . script_callbacks . script_unloaded_callback ( )
2023-05-19 07:08:40 -06:00
startup_timer . record ( " scripts unloaded callback " )
initialize_rest ( reload_script_modules = True )
2023-01-20 22:36:07 -07:00
2022-09-11 09:48:36 -06:00
2022-09-08 03:17:26 -06:00
if __name__ == " __main__ " :
2022-10-18 00:51:53 -06:00
if cmd_opts . nowebui :
2022-10-17 10:58:34 -06:00
api_only ( )
2022-10-17 02:38:32 -06:00
else :
2022-10-20 09:32:17 -06:00
webui ( )