diff --git a/modules/api/api.py b/modules/api/api.py index 0c309a822..4d83d6f3a 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -1,6 +1,7 @@ import io import time import base64 +import logging from io import BytesIO from typing import List, Dict, Any from threading import Lock @@ -11,7 +12,6 @@ from fastapi.exceptions import HTTPException from PIL import PngImagePlugin,Image import piexif import piexif.helper -import uvicorn import gradio as gr from modules import errors, shared, sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing from modules.api import models @@ -637,7 +637,40 @@ class Api: cuda = { 'error': f'{err}' } return models.MemoryResponse(ram = ram, cuda = cuda) - def launch(self, server_name, port): + def launch_uvicorn(self): self.app.include_router(self.router) - server_name = "0.0.0.0" if shared.cmd_opts.listen else None - uvicorn.run(self.app, host=server_name, port=port) + 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() diff --git a/modules/lora b/modules/lora index 038c09f55..c7fd336c5 160000 --- a/modules/lora +++ b/modules/lora @@ -1 +1 @@ -Subproject commit 038c09f552fd75dbe637d2b63d5ec141b1cd1c8f +Subproject commit c7fd336c5d5c0f05378dd34e7b5ca6ac8e972773 diff --git a/modules/middleware.py b/modules/middleware.py index f4b74d8f9..3eb18178a 100644 --- a/modules/middleware.py +++ b/modules/middleware.py @@ -42,7 +42,7 @@ def setup_middleware(app: FastAPI, cmd_opts): duration = str(round(time.time() - ts, 4)) res.headers["X-Process-Time"] = duration endpoint = req.scope.get('path', 'err') - if cmd_opts.api_log and endpoint.startswith('/sdapi'): + if (cmd_opts.api_log or cmd_opts.api_only) and endpoint.startswith('/sdapi'): log.info('API {t} {code} {prot}/{ver} {method} {endpoint} {cli} {duration}'.format( # pylint: disable=consider-using-f-string, logging-format-interpolation t = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), code = res.status_code, diff --git a/webui.py b/webui.py index 38479458b..857b26957 100644 --- a/webui.py +++ b/webui.py @@ -38,7 +38,7 @@ startup_timer.record("gradio") errors.install([gradio]) errors.log.debug('Loading Modules') -from installer import log, setup_logging +from installer import log, setup_logging, git_commit import ldm.modules.encoders.modules # pylint: disable=W0611,C0411,E0401 from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=W0611,C0411,C0412 from modules.paths import create_paths @@ -64,7 +64,6 @@ from modules.shared import cmd_opts, opts import modules.hypernetworks.hypernetwork from modules.middleware import setup_middleware startup_timer.record("libraries") - log.info('Libraries loaded') log.setLevel(logging.DEBUG if cmd_opts.debug else logging.INFO) logging.disable(logging.NOTSET if cmd_opts.debug else logging.DEBUG) @@ -73,6 +72,23 @@ if cmd_opts.server_name: else: server_name = "0.0.0.0" if cmd_opts.listen else None +fastapi_args = { + "version": f'0.0.{git_commit}', + "title": "SD.Next", + "description": "SD.Next", + "license_info": "/LICENSE.txt", +} +if cmd_opts.docs: + fastapi_args.update({ + "docs_url": "/docs", + "redocs_url": "/redocs", + "swagger_ui_parameters": { + "displayOperationId": True, + "showCommonExtensions": True, + "deepLinking": False, + } + }) + def check_rollback_vae(): if shared.cmd_opts.rollback_vae: @@ -233,24 +249,8 @@ def start_ui(): for line in file.readlines(): gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()] - import installer global local_url # pylint: disable=global-statement - gradio_kwargs = { - "version": f'0.0.{installer.git_commit}', - "title": "SD.Next", - "description": "SD.Next", - } - if cmd_opts.docs: - gradio_kwargs.update({ - "docs_url": "/docs", - "redocs_url": "/redocs", - "swagger_ui_parameters": { - "displayOperationId": True, - "showCommonExtensions": True, - "deepLinking": False, - } - }) - app, local_url, share_url = shared.demo.launch( + app, local_url, share_url = shared.demo.launch( # app is FastAPI(Starlette) instance share=cmd_opts.share, server_name=server_name, server_port=cmd_opts.port if cmd_opts.port != 7860 else None, @@ -259,13 +259,12 @@ def start_ui(): ssl_verify=not cmd_opts.tls_selfsign, debug=False, auth=[tuple(cred.split(':')) for cred in gradio_auth_creds] if gradio_auth_creds else None, - # inbrowser=cmd_opts.autolaunch, prevent_thread_lock=True, max_threads=64, show_api=True, favicon_path='html/logo.ico', allowed_paths=[os.path.dirname(__file__), cmd_opts.data_dir], - app_kwargs=gradio_kwargs, + app_kwargs=fastapi_args, ) if cmd_opts.data_dir is not None: ui_tempdir.register_tmp_file(shared.demo, os.path.join(cmd_opts.data_dir, 'x')) @@ -333,14 +332,14 @@ def webui(restart=False): def api_only(): start_common() - app = FastAPI() + app = FastAPI(**fastapi_args) setup_middleware(app, cmd_opts) api = create_api(app) api.wants_restart = False modules.script_callbacks.app_started_callback(None, app) modules.sd_models.write_metadata() log.info(f"Startup time: {startup_timer.summary()}") - 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) + api.launch() return api