webui.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from __future__ import annotations
  2. import os
  3. import time
  4. from modules import timer
  5. from modules import initialize_util
  6. from modules import initialize
  7. startup_timer = timer.startup_timer
  8. startup_timer.record("launcher")
  9. initialize.imports()
  10. initialize.check_versions()
  11. def create_api(app):
  12. from modules.api.api import Api
  13. from modules.call_queue import queue_lock
  14. api = Api(app, queue_lock)
  15. return api
  16. def api_only():
  17. from fastapi import FastAPI
  18. from modules.shared_cmd_options import cmd_opts
  19. initialize.initialize()
  20. app = FastAPI()
  21. initialize_util.setup_middleware(app)
  22. api = create_api(app)
  23. from modules import script_callbacks
  24. script_callbacks.before_ui_callback()
  25. script_callbacks.app_started_callback(None, app)
  26. print(f"Startup time: {startup_timer.summary()}.")
  27. api.launch(
  28. server_name=initialize_util.gradio_server_name(),
  29. port=cmd_opts.port if cmd_opts.port else 7861,
  30. root_path=f"/{cmd_opts.subpath}" if cmd_opts.subpath else ""
  31. )
  32. def warning_if_invalid_install_dir():
  33. """
  34. Shows a warning if the webui is installed under a path that contains a leading dot in any of its parent directories.
  35. Gradio '/file=' route will block access to files that have a leading dot in the path segments.
  36. We use this route to serve files such as JavaScript and CSS to the webpage,
  37. if those files are blocked, the webpage will not function properly.
  38. See https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/13292
  39. This is a security feature was added to Gradio 3.32.0 and is removed in later versions,
  40. this function replicates Gradio file access blocking logic.
  41. This check should be removed when it's no longer applicable.
  42. """
  43. from packaging.version import parse
  44. from pathlib import Path
  45. import gradio
  46. if parse('3.32.0') <= parse(gradio.__version__) < parse('4'):
  47. def abspath(path):
  48. """modified from Gradio 3.41.2 gradio.utils.abspath()"""
  49. if path.is_absolute():
  50. return path
  51. is_symlink = path.is_symlink() or any(parent.is_symlink() for parent in path.parents)
  52. return Path.cwd() / path if (is_symlink or path == path.resolve()) else path.resolve()
  53. webui_root = Path(__file__).parent
  54. if any(part.startswith(".") for part in abspath(webui_root).parts):
  55. print(f'''{"!"*25} Warning {"!"*25}
  56. WebUI is installed in a directory that has a leading dot (.) in one of its parent directories.
  57. This will prevent WebUI from functioning properly.
  58. Please move the installation to a different directory.
  59. Current path: "{webui_root}"
  60. For more information see: https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/13292
  61. {"!"*25} Warning {"!"*25}''')
  62. def webui():
  63. from modules.shared_cmd_options import cmd_opts
  64. launch_api = cmd_opts.api
  65. initialize.initialize()
  66. from modules import shared, ui_tempdir, script_callbacks, ui, progress, ui_extra_networks
  67. warning_if_invalid_install_dir()
  68. while 1:
  69. if shared.opts.clean_temp_dir_at_start:
  70. ui_tempdir.cleanup_tmpdr()
  71. startup_timer.record("cleanup temp dir")
  72. script_callbacks.before_ui_callback()
  73. startup_timer.record("scripts before_ui_callback")
  74. shared.demo = ui.create_ui()
  75. startup_timer.record("create ui")
  76. if not cmd_opts.no_gradio_queue:
  77. shared.demo.queue(64)
  78. gradio_auth_creds = list(initialize_util.get_gradio_auth_creds()) or None
  79. auto_launch_browser = False
  80. if os.getenv('SD_WEBUI_RESTARTING') != '1':
  81. if shared.opts.auto_launch_browser == "Remote" or cmd_opts.autolaunch:
  82. auto_launch_browser = True
  83. elif shared.opts.auto_launch_browser == "Local":
  84. auto_launch_browser = not cmd_opts.webui_is_non_local
  85. app, local_url, share_url = shared.demo.launch(
  86. share=cmd_opts.share,
  87. server_name=initialize_util.gradio_server_name(),
  88. server_port=cmd_opts.port,
  89. ssl_keyfile=cmd_opts.tls_keyfile,
  90. ssl_certfile=cmd_opts.tls_certfile,
  91. ssl_verify=cmd_opts.disable_tls_verify,
  92. debug=cmd_opts.gradio_debug,
  93. auth=gradio_auth_creds,
  94. inbrowser=auto_launch_browser,
  95. prevent_thread_lock=True,
  96. allowed_paths=cmd_opts.gradio_allowed_path,
  97. app_kwargs={
  98. "docs_url": "/docs",
  99. "redoc_url": "/redoc",
  100. },
  101. root_path=f"/{cmd_opts.subpath}" if cmd_opts.subpath else "",
  102. )
  103. startup_timer.record("gradio launch")
  104. # gradio uses a very open CORS policy via app.user_middleware, which makes it possible for
  105. # an attacker to trick the user into opening a malicious HTML page, which makes a request to the
  106. # running web ui and do whatever the attacker wants, including installing an extension and
  107. # running its code. We disable this here. Suggested by RyotaK.
  108. app.user_middleware = [x for x in app.user_middleware if x.cls.__name__ != 'CORSMiddleware']
  109. initialize_util.setup_middleware(app)
  110. progress.setup_progress_api(app)
  111. ui.setup_ui_api(app)
  112. if launch_api:
  113. create_api(app)
  114. ui_extra_networks.add_pages_to_demo(app)
  115. startup_timer.record("add APIs")
  116. with startup_timer.subcategory("app_started_callback"):
  117. script_callbacks.app_started_callback(shared.demo, app)
  118. timer.startup_record = startup_timer.dump()
  119. print(f"Startup time: {startup_timer.summary()}.")
  120. try:
  121. while True:
  122. server_command = shared.state.wait_for_server_command(timeout=5)
  123. if server_command:
  124. if server_command in ("stop", "restart"):
  125. break
  126. else:
  127. print(f"Unknown server command: {server_command}")
  128. except KeyboardInterrupt:
  129. print('Caught KeyboardInterrupt, stopping...')
  130. server_command = "stop"
  131. if server_command == "stop":
  132. print("Stopping server...")
  133. # If we catch a keyboard interrupt, we want to stop the server and exit.
  134. shared.demo.close()
  135. break
  136. # disable auto launch webui in browser for subsequent UI Reload
  137. os.environ.setdefault('SD_WEBUI_RESTARTING', '1')
  138. print('Restarting UI...')
  139. shared.demo.close()
  140. time.sleep(0.5)
  141. startup_timer.reset()
  142. script_callbacks.app_reload_callback()
  143. startup_timer.record("app reload callback")
  144. script_callbacks.script_unloaded_callback()
  145. startup_timer.record("scripts unloaded callback")
  146. initialize.initialize_rest(reload_script_modules=True)
  147. if __name__ == "__main__":
  148. from modules.shared_cmd_options import cmd_opts
  149. if cmd_opts.nowebui:
  150. api_only()
  151. else:
  152. webui()