diff --git a/javascript/settings.js b/javascript/settings.js index b2d981c2144..1e2afdb2ed1 100644 --- a/javascript/settings.js +++ b/javascript/settings.js @@ -69,3 +69,39 @@ onOptionsChanged(function() { }); }); +function downloadSysinfo() { + const pad = (n) => String(n).padStart(2, '0'); + const now = new Date(); + const YY = now.getFullYear(); + const MM = pad(now.getMonth() + 1); + const DD = pad(now.getDate()); + const HH = pad(now.getHours()); + const mm = pad(now.getMinutes()); + const link = document.createElement('a'); + link.download = `sysinfo-${YY}-${MM}-${DD}-${HH}-${mm}.json`; + const sysinfo_textbox = gradioApp().querySelector('#internal-sysinfo-textbox textarea'); + const content = sysinfo_textbox.value; + if (content.startsWith('file=')) { + link.href = content; + } else { + const blob = new Blob([content], {type: 'application/json'}); + link.href = URL.createObjectURL(blob); + } + link.click(); + sysinfo_textbox.value = ''; + updateInput(sysinfo_textbox); +} + +function openTabSysinfo() { + const sysinfo_textbox = gradioApp().querySelector('#internal-sysinfo-textbox textarea'); + const content = sysinfo_textbox.value; + if (content.startsWith('file=')) { + window.open(content, '_blank'); + } else { + const blob = new Blob([content], {type: 'application/json'}); + const url = URL.createObjectURL(blob); + window.open(url, '_blank'); + } + sysinfo_textbox.value = ''; + updateInput(sysinfo_textbox); +} diff --git a/modules/api/api.py b/modules/api/api.py index db2fc648019..8604c741f3a 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -17,7 +17,7 @@ from secrets import compare_digest import modules.shared as shared -from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, infotext_utils, sd_models, sd_schedulers +from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, infotext_utils, sd_models, sd_schedulers, sysinfo from modules.api import models from modules.shared import opts from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images @@ -33,6 +33,7 @@ from contextlib import closing from modules.progress import create_task_id, add_task_to_queue, start_task, finish_task, current_task + def script_name_to_index(name, scripts): try: return [script.title().lower() for script in scripts].index(name.lower()) @@ -244,6 +245,8 @@ def __init__(self, app: FastAPI, queue_lock: Lock): self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList) self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=list[models.ScriptInfo]) self.add_api_route("/sdapi/v1/extensions", self.get_extensions_list, methods=["GET"], response_model=list[models.ExtensionItem]) + self.add_api_route("/internal/sysinfo", sysinfo.download_sysinfo, methods=["GET"]) + self.add_api_route("/internal/sysinfo-download", lambda: sysinfo.download_sysinfo(attachment=True), methods=["GET"]) if shared.cmd_opts.api_server_stop: self.add_api_route("/sdapi/v1/server-kill", self.kill_webui, methods=["POST"]) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index e9a83d74e03..3afdfd49177 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -213,3 +213,13 @@ def get_config(): return json.load(f) except Exception as e: return str(e) + + +def download_sysinfo(attachment=False): + from fastapi.responses import PlainTextResponse + from datetime import datetime + + text = get() + filename = f"sysinfo-{datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json" + + return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'}) diff --git a/modules/ui.py b/modules/ui.py index 9a76b5fcd90..f6386ebf53f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1,4 +1,3 @@ -import datetime import mimetypes import os import sys @@ -10,10 +9,10 @@ import gradio.utils import numpy as np from PIL import Image, PngImagePlugin # noqa: F401 -from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401 +from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401 from modules import gradio_extensons, sd_schedulers # noqa: F401 -from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, sysinfo, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils +from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML, InputAccordion, ResizeHandleRow from modules.paths import script_path from modules.ui_common import create_refresh_button @@ -1223,16 +1222,5 @@ def quicksettings_hint(): 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')}.json" - - 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"]) - import fastapi.staticfiles app.mount("/webui-assets", fastapi.staticfiles.StaticFiles(directory=launch_utils.repo_dir('stable-diffusion-webui-assets')), name="webui-assets") diff --git a/modules/ui_settings.py b/modules/ui_settings.py index e53ad50f8f4..efedce91add 100644 --- a/modules/ui_settings.py +++ b/modules/ui_settings.py @@ -1,12 +1,13 @@ import gradio as gr -from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo, timer, shared_items +from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo, timer, shared_items, paths_internal, util from modules.call_queue import wrap_gradio_call_no_job from modules.options import options_section from modules.shared import opts from modules.ui_components import FormRow from modules.ui_gradio_extensions import reload_javascript from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path def get_value_for_setting(key): @@ -170,7 +171,28 @@ def create_ui(self, loadsave, dummy_component): loadsave.create_ui() with gr.TabItem("Sysinfo", id="sysinfo", elem_id="settings_tab_sysinfo"): - gr.HTML('Download system info
(or open as text in a new page)', elem_id="sysinfo_download") + download_sysinfo = gr.Button(value='Download system info', elem_id="internal-download-sysinfo", visible=False) + open_sysinfo = gr.Button(value='Open as text in a new page', elem_id="internal-open-sysinfo", visible=False) + sysinfo_html = gr.HTML('''Download system info
(or open as text in a new page)''', elem_id="sysinfo_download") + sysinfo_textbox = gr.Textbox(label='Sysinfo textarea', elem_id="internal-sysinfo-textbox", visible=False) + + def create_sysinfo(): + sysinfo_str = sysinfo.get() + if len(sysinfo_utf8 := sysinfo_str.encode('utf8')) > 2 ** 20: # 1MB + sysinfo_path = Path(paths_internal.script_path) / 'tmp' / 'sysinfo.json' + sysinfo_path.parent.mkdir(parents=True, exist_ok=True) + sysinfo_path.write_bytes(sysinfo_utf8) + return gr.update(), gr.update(value=f'file={util.truncate_path(sysinfo_path)}') + return gr.update(), gr.update(value=sysinfo_str) + + download_sysinfo.click( + fn=create_sysinfo, outputs=[sysinfo_html, sysinfo_textbox], show_progress=True).success( + fn=None, _js='downloadSysinfo' + ) + open_sysinfo.click( + fn=create_sysinfo, outputs=[sysinfo_html, sysinfo_textbox], show_progress=True).success( + fn=None, _js='openTabSysinfo' + ) with gr.Row(): with gr.Column(scale=1): @@ -313,7 +335,7 @@ def add_functionality(self, demo): for method in methods: method( - fn=lambda value, k=k: self.run_settings_single(value, key=k), + fn=lambda value, key=k: self.run_settings_single(value, key=key), inputs=[component], outputs=[component, self.text_settings], show_progress=info.refresh is not None,