Merge pull request #10980 from AUTOMATIC1111/sysinfo
Added sysinfo tab to settings
This commit is contained in:
commit
efc4c79b5e
@ -3,10 +3,30 @@ import textwrap
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
|
exception_records = []
|
||||||
|
|
||||||
|
|
||||||
|
def record_exception():
|
||||||
|
_, e, tb = sys.exc_info()
|
||||||
|
if e is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if exception_records and exception_records[-1] == e:
|
||||||
|
return
|
||||||
|
|
||||||
|
exception_records.append((e, tb))
|
||||||
|
|
||||||
|
if len(exception_records) > 5:
|
||||||
|
exception_records.pop(0)
|
||||||
|
|
||||||
|
|
||||||
def report(message: str, *, exc_info: bool = False) -> None:
|
def report(message: str, *, exc_info: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Print an error message to stderr, with optional traceback.
|
Print an error message to stderr, with optional traceback.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
record_exception()
|
||||||
|
|
||||||
for line in message.splitlines():
|
for line in message.splitlines():
|
||||||
print("***", line, file=sys.stderr)
|
print("***", line, file=sys.stderr)
|
||||||
if exc_info:
|
if exc_info:
|
||||||
@ -15,6 +35,8 @@ def report(message: str, *, exc_info: bool = False) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def print_error_explanation(message):
|
def print_error_explanation(message):
|
||||||
|
record_exception()
|
||||||
|
|
||||||
lines = message.strip().split("\n")
|
lines = message.strip().split("\n")
|
||||||
max_len = max([len(x) for x in lines])
|
max_len = max([len(x) for x in lines])
|
||||||
|
|
||||||
@ -25,6 +47,8 @@ def print_error_explanation(message):
|
|||||||
|
|
||||||
|
|
||||||
def display(e: Exception, task, *, full_traceback=False):
|
def display(e: Exception, task, *, full_traceback=False):
|
||||||
|
record_exception()
|
||||||
|
|
||||||
print(f"{task or 'error'}: {type(e).__name__}", file=sys.stderr)
|
print(f"{task or 'error'}: {type(e).__name__}", file=sys.stderr)
|
||||||
te = traceback.TracebackException.from_exception(e)
|
te = traceback.TracebackException.from_exception(e)
|
||||||
if full_traceback:
|
if full_traceback:
|
||||||
@ -44,6 +68,8 @@ already_displayed = {}
|
|||||||
|
|
||||||
|
|
||||||
def display_once(e: Exception, task):
|
def display_once(e: Exception, task):
|
||||||
|
record_exception()
|
||||||
|
|
||||||
if task in already_displayed:
|
if task in already_displayed:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
162
modules/sysinfo.py
Normal file
162
modules/sysinfo.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import platform
|
||||||
|
import hashlib
|
||||||
|
import pkg_resources
|
||||||
|
import psutil
|
||||||
|
import re
|
||||||
|
|
||||||
|
import launch
|
||||||
|
from modules import paths_internal, timer
|
||||||
|
|
||||||
|
checksum_token = "DontStealMyGamePlz__WINNERS_DONT_USE_DRUGS__DONT_COPY_THAT_FLOPPY"
|
||||||
|
environment_whitelist = {
|
||||||
|
"GIT",
|
||||||
|
"INDEX_URL",
|
||||||
|
"WEBUI_LAUNCH_LIVE_OUTPUT",
|
||||||
|
"GRADIO_ANALYTICS_ENABLED",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"TORCH_INDEX_URL",
|
||||||
|
"TORCH_COMMAND",
|
||||||
|
"REQS_FILE",
|
||||||
|
"XFORMERS_PACKAGE",
|
||||||
|
"GFPGAN_PACKAGE",
|
||||||
|
"CLIP_PACKAGE",
|
||||||
|
"OPENCLIP_PACKAGE",
|
||||||
|
"STABLE_DIFFUSION_REPO",
|
||||||
|
"K_DIFFUSION_REPO",
|
||||||
|
"CODEFORMER_REPO",
|
||||||
|
"BLIP_REPO",
|
||||||
|
"STABLE_DIFFUSION_COMMIT_HASH",
|
||||||
|
"K_DIFFUSION_COMMIT_HASH",
|
||||||
|
"CODEFORMER_COMMIT_HASH",
|
||||||
|
"BLIP_COMMIT_HASH",
|
||||||
|
"COMMANDLINE_ARGS",
|
||||||
|
"IGNORE_CMD_ARGS_ERRORS",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_bytes(num, suffix="B"):
|
||||||
|
for unit in ["", "K", "M", "G", "T", "P", "E", "Z", "Y"]:
|
||||||
|
if abs(num) < 1024 or unit == 'Y':
|
||||||
|
return f"{num:.0f}{unit}{suffix}"
|
||||||
|
num /= 1024
|
||||||
|
|
||||||
|
|
||||||
|
def get():
|
||||||
|
res = get_dict()
|
||||||
|
|
||||||
|
text = json.dumps(res, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
h = hashlib.sha256(text.encode("utf8"))
|
||||||
|
text = text.replace(checksum_token, h.hexdigest())
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
re_checksum = re.compile(r'"Checksum": "([0-9a-fA-F]{64})"')
|
||||||
|
|
||||||
|
|
||||||
|
def check(x):
|
||||||
|
m = re.search(re_checksum, x)
|
||||||
|
if not m:
|
||||||
|
return False
|
||||||
|
|
||||||
|
replaced = re.sub(re_checksum, f'"Checksum": "{checksum_token}"', x)
|
||||||
|
|
||||||
|
h = hashlib.sha256(replaced.encode("utf8"))
|
||||||
|
return h.hexdigest() == m.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_dict():
|
||||||
|
ram = psutil.virtual_memory()
|
||||||
|
|
||||||
|
res = {
|
||||||
|
"Platform": platform.platform(),
|
||||||
|
"Python": platform.python_version(),
|
||||||
|
"Version": launch.git_tag(),
|
||||||
|
"Commit": launch.commit_hash(),
|
||||||
|
"Script path": paths_internal.script_path,
|
||||||
|
"Data path": paths_internal.data_path,
|
||||||
|
"Extensions dir": paths_internal.extensions_dir,
|
||||||
|
"Checksum": checksum_token,
|
||||||
|
"Commandline": sys.argv,
|
||||||
|
"Torch env info": get_torch_sysinfo(),
|
||||||
|
"Exceptions": get_exceptions(),
|
||||||
|
"CPU": {
|
||||||
|
"model": platform.processor(),
|
||||||
|
"count logical": psutil.cpu_count(logical=True),
|
||||||
|
"count physical": psutil.cpu_count(logical=False),
|
||||||
|
},
|
||||||
|
"RAM": {
|
||||||
|
x: pretty_bytes(getattr(ram, x, 0)) for x in ["total", "used", "free", "active", "inactive", "buffers", "cached", "shared"] if getattr(ram, x, 0) != 0
|
||||||
|
},
|
||||||
|
"Extensions": get_extensions(enabled=True),
|
||||||
|
"Inactive extensions": get_extensions(enabled=False),
|
||||||
|
"Environment": get_environment(),
|
||||||
|
"Config": get_config(),
|
||||||
|
"Startup": timer.startup_record,
|
||||||
|
"Packages": sorted([f"{pkg.key}=={pkg.version}" for pkg in pkg_resources.working_set]),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def format_traceback(tb):
|
||||||
|
return [[f"{x.filename}, line {x.lineno}, {x.name}", x.line] for x in traceback.extract_tb(tb)]
|
||||||
|
|
||||||
|
|
||||||
|
def get_exceptions():
|
||||||
|
try:
|
||||||
|
from modules import errors
|
||||||
|
|
||||||
|
return [{"exception": str(e), "traceback": format_traceback(tb)} for e, tb in reversed(errors.exception_records)]
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
|
def get_environment():
|
||||||
|
return {k: os.environ[k] for k in sorted(os.environ) if k in environment_whitelist}
|
||||||
|
|
||||||
|
|
||||||
|
re_newline = re.compile(r"\r*\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_torch_sysinfo():
|
||||||
|
try:
|
||||||
|
import torch.utils.collect_env
|
||||||
|
info = torch.utils.collect_env.get_env_info()._asdict()
|
||||||
|
|
||||||
|
return {k: re.split(re_newline, str(v)) if "\n" in str(v) else v for k, v in info.items()}
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
|
def get_extensions(*, enabled):
|
||||||
|
|
||||||
|
try:
|
||||||
|
from modules import extensions
|
||||||
|
|
||||||
|
def to_json(x: extensions.Extension):
|
||||||
|
return {
|
||||||
|
"name": x.name,
|
||||||
|
"path": x.path,
|
||||||
|
"version": x.version,
|
||||||
|
"branch": x.branch,
|
||||||
|
"remote": x.remote,
|
||||||
|
}
|
||||||
|
|
||||||
|
return [to_json(x) for x in extensions.extensions if not x.is_builtin and x.enabled == enabled]
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
|
def get_config():
|
||||||
|
try:
|
||||||
|
from modules import shared
|
||||||
|
return shared.opts.data
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
@ -11,7 +12,7 @@ import numpy as np
|
|||||||
from PIL import Image, PngImagePlugin # noqa: F401
|
from PIL import Image, PngImagePlugin # noqa: F401
|
||||||
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
|
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
|
||||||
|
|
||||||
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, errors, shared_items, ui_settings, timer
|
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, errors, shared_items, ui_settings, timer, sysinfo
|
||||||
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
|
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
|
||||||
from modules.paths import script_path
|
from modules.paths import script_path
|
||||||
from modules.ui_common import create_refresh_button
|
from modules.ui_common import create_refresh_button
|
||||||
@ -1600,3 +1601,15 @@ def setup_ui_api(app):
|
|||||||
app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])
|
app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])
|
||||||
|
|
||||||
app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
|
app.add_api_route("/internal/profile-startup", lambda: timer.startup_record, methods=["GET"])
|
||||||
|
|
||||||
|
def download_sysinfo(attachment=False):
|
||||||
|
from fastapi.responses import PlainTextResponse
|
||||||
|
|
||||||
|
text = sysinfo.get()
|
||||||
|
filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.txt"
|
||||||
|
|
||||||
|
return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'})
|
||||||
|
|
||||||
|
app.add_api_route("/internal/sysinfo", download_sysinfo, methods=["GET"])
|
||||||
|
app.add_api_route("/internal/sysinfo-download", lambda: download_sysinfo(attachment=True), methods=["GET"])
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
from modules import ui_common, shared, script_callbacks, scripts, sd_models
|
from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo
|
||||||
from modules.call_queue import wrap_gradio_call
|
from modules.call_queue import wrap_gradio_call
|
||||||
from modules.shared import opts
|
from modules.shared import opts
|
||||||
from modules.ui_components import FormRow
|
from modules.ui_components import FormRow
|
||||||
@ -157,6 +157,17 @@ class UiSettings:
|
|||||||
with gr.TabItem("Defaults", id="defaults", elem_id="settings_tab_defaults"):
|
with gr.TabItem("Defaults", id="defaults", elem_id="settings_tab_defaults"):
|
||||||
loadsave.create_ui()
|
loadsave.create_ui()
|
||||||
|
|
||||||
|
with gr.TabItem("Sysinfo", id="sysinfo", elem_id="settings_tab_sysinfo"):
|
||||||
|
gr.HTML('<a href="./internal/sysinfo-download" class="sysinfo_big_link" download>Download system info</a><br /><a href="./internal/sysinfo">(or open as text in a new page)</a>', elem_id="sysinfo_download")
|
||||||
|
|
||||||
|
with gr.Row():
|
||||||
|
with gr.Column(scale=1):
|
||||||
|
sysinfo_check_file = gr.File(label="Check system info for validity", type='binary')
|
||||||
|
with gr.Column(scale=1):
|
||||||
|
sysinfo_check_output = gr.HTML("", elem_id="sysinfo_validity")
|
||||||
|
with gr.Column(scale=100):
|
||||||
|
pass
|
||||||
|
|
||||||
with gr.TabItem("Actions", id="actions", elem_id="settings_tab_actions"):
|
with gr.TabItem("Actions", id="actions", elem_id="settings_tab_actions"):
|
||||||
request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
|
request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
|
||||||
download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
|
download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
|
||||||
@ -215,6 +226,21 @@ class UiSettings:
|
|||||||
outputs=[],
|
outputs=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def check_file(x):
|
||||||
|
if x is None:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if sysinfo.check(x.decode('utf8', errors='ignore')):
|
||||||
|
return 'Valid'
|
||||||
|
|
||||||
|
return 'Invalid'
|
||||||
|
|
||||||
|
sysinfo_check_file.change(
|
||||||
|
fn=check_file,
|
||||||
|
inputs=[sysinfo_check_file],
|
||||||
|
outputs=[sysinfo_check_output],
|
||||||
|
)
|
||||||
|
|
||||||
self.interface = settings_interface
|
self.interface = settings_interface
|
||||||
|
|
||||||
def add_quicksettings(self):
|
def add_quicksettings(self):
|
||||||
|
13
style.css
13
style.css
@ -450,6 +450,19 @@ table.popup-table .link{
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sysinfo_download a.sysinfo_big_link{
|
||||||
|
font-size: 24pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sysinfo_download a{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sysinfo_validity{
|
||||||
|
font-size: 18pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* live preview */
|
/* live preview */
|
||||||
.progressDiv{
|
.progressDiv{
|
||||||
position: relative;
|
position: relative;
|
||||||
|
Loading…
Reference in New Issue
Block a user