diff --git a/.gitattributes b/.gitattributes index c7d9f3332a950355d5a77d85000f05e6f45435ea..e426494d02daa04542d31ef0bc647426c2589114 100644 --- a/.gitattributes +++ b/.gitattributes @@ -32,3 +32,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +sd-webui-cutoff/images/cover.jpg filter=lfs diff=lfs merge=lfs -text +sd-webui-cutoff/images/sample-1.png filter=lfs diff=lfs merge=lfs -text +sd-webui-cutoff/images/sample-2.png filter=lfs diff=lfs merge=lfs -text +sd-webui-cutoff/images/sample-3.png filter=lfs diff=lfs merge=lfs -text +sd-webui-llul/images/llul_yuv420p.mp4 filter=lfs diff=lfs merge=lfs -text +sd-webui-llul/images/mask_effect.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/bug_report.md b/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..1c116a060d90a3303fc913628d2ba4d789e412f4 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Enter these inputs '....' +2. Click on '....' + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots of error** +If applicable, add screenshots to help explain your problem. Or just dump the error. + +**Desktop (please complete the following information):** + - OS: [e.g. Windows] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/feature_request.md b/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000000000000000000000000000000000..f45586549c215746dd615f3b3a36518386097dc1 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE]" +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/infinite-zoom-automatic1111-webui/.gitignore b/infinite-zoom-automatic1111-webui/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2638864953cb6c7acab252461c3bc1972ea07782 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/.gitignore @@ -0,0 +1,132 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +.vscode/settings.json +.DS_Store +/.vs diff --git a/infinite-zoom-automatic1111-webui/CODE_OF_CONDUCT.md b/infinite-zoom-automatic1111-webui/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000000000000000000000000000000..ccb92a09cc958449f200f879f26aafd609c0ae6c --- /dev/null +++ b/infinite-zoom-automatic1111-webui/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +me@vahid.cloud. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/infinite-zoom-automatic1111-webui/LICENSE b/infinite-zoom-automatic1111-webui/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..b2725d87aebd097b150f6970db41c440190ec80f --- /dev/null +++ b/infinite-zoom-automatic1111-webui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 vahid khroasani + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/infinite-zoom-automatic1111-webui/README.md b/infinite-zoom-automatic1111-webui/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4342d6074a7989d4add30b604efb0c47723218ec --- /dev/null +++ b/infinite-zoom-automatic1111-webui/README.md @@ -0,0 +1,115 @@ +# Infinite Zoom extension for [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/). + +

+ + build status + +

+ +This is an extension for the AUTOMATIC1111's (and Vladmandic´s) webui that allows users to create infinite zoom effect videos using stable diffusion outpainting method. +

+ +

+ +## How to install? +
+ Click to expand + +1. Open [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/). + +2. Go to the `Extensions tab` > `Install from URL`. + +3. Enter `https://github.com/v8hid/infinite-zoom-automatic1111-webui.git` for the URL and leave the second field empty and wait for it to be installed. +> Screenshot + +4. Go to the Installed tab and press Apply, wait for installation, and restart. + +> Screenshot + +5. Wait for the Stable Diffusion WebUI to restart and now you can try the Infinite Zoom extension. + +
+ +## How to use? + +
+ Click to expand + + 1. Click on the Infinite Zoom tab Screenshot 2023-04-12 at 10 14 50 PM + + 2. Modify the parameters as you wish and click Generate video, the video will appear as soon as it generates + +
+ +**To learn more about the parameters, please refer to our [WIKI](https://github.com/v8hid/infinite-zoom-automatic1111-webui/wiki).** + ## Effective Friendly Tips for Optimal Outcomes + +
+ Click to expand + +* You're only as good as your model, so level up with an Inpainting model for killer results. + +* Heads up: Setting Mask Blur parameter above 0 will give you results that look like they've been hit by the ugly stick. + +* Just between us - don't forget to uncheck Apply color correction to img2img results to match original colors in the Stable Diffusion tab of the WebUI settings. You don't want your results looking like a bad Instagram filter. + +
+ +## Examples + +
+ Click to expand + + + +https://user-images.githubusercontent.com/62482657/232369614-e112d17a-db12-47b2-9795-5be4037fa9fe.mp4 + + +https://user-images.githubusercontent.com/62482657/231573289-2db85c57-540d-4c7d-859f-3c3ddfcd2c8a.mp4 + + +https://user-images.githubusercontent.com/62482657/231574588-3196beda-7237-407f-bc76-eae10599b5eb.mp4 + + +https://user-images.githubusercontent.com/62482657/231574839-9d3aab52-7a87-4658-88d0-46b8dd7f4b60.mp4 + +
+ +## How it works? +
+ Click to expand + +To start, let's break down the workflow of the extension into three main steps: + +- **Step 1: Choose an image to start with** +The program either generates an initial image using the first prompt you provide or you can upload your own image in the `custom initial image` field. This initial image will be the basis for the outpainting process. + +- **Step 2: Generate outpaint steps** +Once you have your initial image, the program will start generating outpaint steps. The number of outpaint steps is determined by the `Total Outpaint Steps` input. In each outpaint step, the program makes the initial image smaller in the center of the canvas and generates a new image in the empty space that is created. This process is repeated for each outpaint step until the desired number is reached. + +- **Step 3: Create a gradual zoom effect** +After all outpaint steps have been generated, the program creates an interpolation between each outpaint step to create a gradual zoom effect. The number of frames created between each outpaint step is determined by the `Zoom Speed` parameter and the `Frames per second` parameter. + +Number of frames for each outpaint step = `Zoom Speed` $\times$ `Frames per second` + +Length of each outpaint step in second = `Number of frames` $\div$ `Frames per second` + +
+ +## Google Colab version +It works on free colab plan + + + Open In Colab + + + GitHub Repo + + +## Contributing + +Contributions are welcome! Please follow these guidelines: + + 1. Fork the repository. + 2. Make your changes and commit them. + 3. Make sure to submit the pull request to the develop repository. diff --git a/infinite-zoom-automatic1111-webui/install.py b/infinite-zoom-automatic1111-webui/install.py new file mode 100644 index 0000000000000000000000000000000000000000..3d368fd42e87882c15098faa9b7973579bfa4ed4 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/install.py @@ -0,0 +1,6 @@ +import launch + +if not launch.is_installed("imageio"): + launch.run_pip("install imageio", "requirements 0 for Infinite-Zoom") +if not launch.is_installed("imageio-ffmpeg"): + launch.run_pip("install imageio-ffmpeg", "requirements 1 for Infinite-Zoom") diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__init__.py b/infinite-zoom-automatic1111-webui/iz_helpers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..19c0211d84011b7597bfb6aa0f3538d9ede7c9f5 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/__init__.py @@ -0,0 +1,2 @@ +# from .ui import on_ui_tabs +# from .settings import on_ui_settings diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/__init__.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43f8ec6ecd9797bc6dc34f4dd5592ae551bc2a43 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/__init__.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/helpers.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..758fcf626c34011cbed4e85c7b7d2c36b831783b Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/helpers.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/image.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/image.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0423311c7f187a118a1ecc2eda93ecbbc4392ba Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/image.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/prompt_util.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/prompt_util.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3af1e5495cabb7231a635acfcf04fa8090aac350 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/prompt_util.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/run.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/run.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebda129cfa8f68eb2b0331e501fedabd303902d6 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/run.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/sd_helpers.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/sd_helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f3983dcc45afa03dabbac096623e90c0b4a505e Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/sd_helpers.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/settings.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e74792aa7b6b1aaf01ef1492449ff0a2251fdb0 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/settings.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/static_variables.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/static_variables.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba4770736411917d0b379712f3c4fd3a444be7f9 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/static_variables.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/ui.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/ui.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4094692c5bf386b961f94043ddf123ec92e4a2b6 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/ui.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/video.cpython-310.pyc b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/video.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be200edd075f79c9ac4f0639e1f69990443eeef6 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/iz_helpers/__pycache__/video.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/extra.py b/infinite-zoom-automatic1111-webui/iz_helpers/extra.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/helpers.py b/infinite-zoom-automatic1111-webui/iz_helpers/helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..c7b110e4e5a2ab40f4b52182d75354c1756c3533 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/helpers.py @@ -0,0 +1,126 @@ +import math +import os +import modules.shared as shared +import modules.sd_models +import gradio as gr +from scripts import postprocessing_upscale +from .prompt_util import readJsonPrompt +import asyncio + + +def fix_env_Path_ffprobe(): + envpath = os.environ["PATH"] + ffppath = shared.opts.data.get("infzoom_ffprobepath", "") + + if ffppath and not ffppath in envpath: + path_sep = ";" if os.name == "nt" else ":" + os.environ["PATH"] = envpath + path_sep + ffppath + + +def closest_upper_divisible_by_eight(num): + if num % 8 == 0: + return num + else: + return math.ceil(num / 8) * 8 + + +def load_model_from_setting(model_field_name, progress, progress_desc): + # fix typo in Automatic1111 vs Vlad111 + if hasattr(modules.sd_models, "checkpoint_alisases"): + checkPList = modules.sd_models.checkpoint_alisases + elif hasattr(modules.sd_models, "checkpoint_aliases"): + checkPList = modules.sd_models.checkpoint_aliases + else: + raise Exception( + "This is not a compatible StableDiffusion Platform, can not access checkpoints" + ) + + model_name = shared.opts.data.get(model_field_name) + if model_name is not None and model_name != "": + checkinfo = checkPList[model_name] + + if not checkinfo: + raise NameError(model_field_name + " Does not exist in your models.") + + if progress: + progress(0, desc=progress_desc + checkinfo.name) + + modules.sd_models.load_model(checkinfo) + + +def do_upscaleImg(curImg, upscale_do, upscaler_name, upscale_by): + if not upscale_do: + return curImg + + # ensure even width and even height for ffmpeg + # if odd, switch to scale to mode + rwidth = round(curImg.width * upscale_by) + rheight = round(curImg.height * upscale_by) + + ups_mode = 2 # upscale_by + if (rwidth % 2) == 1: + ups_mode = 1 + rwidth += 1 + if (rheight % 2) == 1: + ups_mode = 1 + rheight += 1 + + if 1 == ups_mode: + print( + "Infinite Zoom: aligning output size to even width and height: " + + str(rwidth) + + " x " + + str(rheight), + end="\r", + ) + + pp = postprocessing_upscale.scripts_postprocessing.PostprocessedImage(curImg) + ups = postprocessing_upscale.ScriptPostprocessingUpscale() + ups.process( + pp, + upscale_mode=ups_mode, + upscale_by=upscale_by, + upscale_to_width=rwidth, + upscale_to_height=rheight, + upscale_crop=False, + upscaler_1_name=upscaler_name, + upscaler_2_name=None, + upscaler_2_visibility=0.0, + ) + return pp.image + +async def showGradioErrorAsync(txt, delay=1): + await asyncio.sleep(delay) # sleep for 1 second + raise gr.Error(txt) + +def putPrompts(files): + try: + with open(files.name, "r") as f: + file_contents = f.read() + + data = readJsonPrompt(file_contents,False) + return [ + gr.Textbox.update(data["prePrompt"]), + gr.DataFrame.update(data["prompts"]), + gr.Textbox.update(data["postPrompt"]), + gr.Textbox.update(data["negPrompt"]) + ] + + except Exception: + print( + "[InfiniteZoom:] Loading your prompt failed. It seems to be invalid. Your prompt table is preserved." + ) + + # error only be shown with raise, so ui gets broken. + #asyncio.run(showGradioErrorAsync("Loading your prompts failed. It seems to be invalid. Your prompt table has been preserved.",5)) + + return [gr.Textbox.update(), gr.DataFrame.update(), gr.Textbox.update(),gr.Textbox.update()] + + +def clearPrompts(): + return [ + gr.DataFrame.update(value=[[0, "Infinite Zoom. Start over"]]), + gr.Textbox.update(""), + gr.Textbox.update(""), + gr.Textbox.update("") + ] diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/image.py b/infinite-zoom-automatic1111-webui/iz_helpers/image.py new file mode 100644 index 0000000000000000000000000000000000000000..d84901a86a610b260cbcc376e058a0ab09e3ae2d --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/image.py @@ -0,0 +1,23 @@ +from PIL import Image + +def shrink_and_paste_on_blank(current_image, mask_width, mask_height): + """ + Decreases size of current_image by mask_width pixels from each side, + then adds a mask_width width transparent frame, + so that the image the function returns is the same size as the input. + :param current_image: input image to transform + :param mask_width: width in pixels to shrink from each side + :param mask_height: height in pixels to shrink from each side + """ + + # calculate new dimensions + width, height = current_image.size + new_width = width - 2 * mask_width + new_height = height - 2 * mask_height + + # resize and paste onto blank image + prev_image = current_image.resize((new_width, new_height)) + blank_image = Image.new("RGBA", (width, height), (0, 0, 0, 1)) + blank_image.paste(prev_image, (mask_width, mask_height)) + + return blank_image diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/prompt_util.py b/infinite-zoom-automatic1111-webui/iz_helpers/prompt_util.py new file mode 100644 index 0000000000000000000000000000000000000000..e44173e289aec5197afa186a6492762c724374f3 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/prompt_util.py @@ -0,0 +1,67 @@ +import json +from jsonschema import validate + +from .static_variables import ( + empty_prompt, + invalid_prompt, + jsonprompt_schemafile, + promptTableHeaders +) + +def completeOptionals(j): + if isinstance(j, dict): + # Remove header information, user dont pimp our ui + if "prompts" in j: + if "headers" in j["prompts"]: + del j["prompts"]["headers"] + j["prompts"]["headers"]=promptTableHeaders + + if "negPrompt" not in j: + j["negPrompt"]="" + + if "prePrompt" not in j: + if "commonPromptPrefix" in j: + j["prePrompt"]=j["commonPromptPrefix"] + else: + j["prePrompt"]="" + + if "postPrompt" not in j: + if "commonPromptSuffix" in j: + j["postPrompt"]=j["commonPromptSuffix"] + else: + j["postPrompt"]="" + + return j + + +def validatePromptJson_throws(data): + with open(jsonprompt_schemafile, "r") as s: + schema = json.load(s) + try: + validate(instance=data, schema=schema) + + except Exception: + raise Exception("Your prompts are not schema valid.") + + return completeOptionals(data) + + +def readJsonPrompt(txt, returnFailPrompt=False): + if not txt: + return empty_prompt + + try: + jpr = json.loads(txt) + except Exception: + if returnFailPrompt: + print (f"Infinite Zoom: Corrupted Json structure: {txt[:24]} ...") + return invalid_prompt + raise (f"Infinite Zoom: Corrupted Json structure: {txt[:24]} ...") + + try: + return validatePromptJson_throws(jpr) + except Exception: + if returnFailPrompt: + return invalid_prompt + pass + diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/promptschema.json b/infinite-zoom-automatic1111-webui/iz_helpers/promptschema.json new file mode 100644 index 0000000000000000000000000000000000000000..3946797ab734e20854fb4bd76a9b608f5f3929c4 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/promptschema.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "1.1", + "type": "object", + "properties": { + "prompts": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "oneOf": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "string" + } + ] + }, + { + "type": "string" + } + ], + "minItems": 0, + "maxItems": 999, + "uniqueItems": false + }, + "minItems": 0 + }, + "headers": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 2 + } + }, + "required": [ + "data" + ] + }, + "negPrompt": { + "type": "string" + }, + "prePrompt": { + "type": "string" + }, + "postPrompt": { + "type": "string" + } + }, + "required": [ + "prompts" + ] +} \ No newline at end of file diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/run.py b/infinite-zoom-automatic1111-webui/iz_helpers/run.py new file mode 100644 index 0000000000000000000000000000000000000000..d224af54996b6599bc0b4985b7b514df50397b99 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/run.py @@ -0,0 +1,512 @@ +import math, time, os +import numpy as np +from PIL import Image, ImageFilter, ImageDraw +from modules.ui import plaintext_to_html +import modules.shared as shared +from modules.paths_internal import script_path +from .helpers import ( + fix_env_Path_ffprobe, + closest_upper_divisible_by_eight, + load_model_from_setting, + do_upscaleImg, +) +from .sd_helpers import renderImg2Img, renderTxt2Img +from .image import shrink_and_paste_on_blank +from .video import write_video + + +def crop_fethear_ellipse(image, feather_margin=30, width_offset=0, height_offset=0): + # Create a blank mask image with the same size as the original image + mask = Image.new("L", image.size, 0) + draw = ImageDraw.Draw(mask) + + # Calculate the ellipse's bounding box + ellipse_box = ( + width_offset, + height_offset, + image.width - width_offset, + image.height - height_offset, + ) + + # Draw the ellipse on the mask + draw.ellipse(ellipse_box, fill=255) + + # Apply the mask to the original image + result = Image.new("RGBA", image.size) + result.paste(image, mask=mask) + + # Crop the resulting image to the ellipse's bounding box + cropped_image = result.crop(ellipse_box) + + # Create a new mask image with a black background (0) + mask = Image.new("L", cropped_image.size, 0) + draw = ImageDraw.Draw(mask) + + # Draw an ellipse on the mask image + draw.ellipse( + ( + 0 + feather_margin, + 0 + feather_margin, + cropped_image.width - feather_margin, + cropped_image.height - feather_margin, + ), + fill=255, + outline=0, + ) + + # Apply a Gaussian blur to the mask image + mask = mask.filter(ImageFilter.GaussianBlur(radius=feather_margin / 2)) + cropped_image.putalpha(mask) + res = Image.new(cropped_image.mode, (image.width, image.height)) + paste_pos = ( + int((res.width - cropped_image.width) / 2), + int((res.height - cropped_image.height) / 2), + ) + res.paste(cropped_image, paste_pos) + + return res + + +def outpaint_steps( + width, + height, + common_prompt_pre, + common_prompt_suf, + prompts, + negative_prompt, + seed, + sampler, + num_inference_steps, + guidance_scale, + inpainting_denoising_strength, + inpainting_mask_blur, + inpainting_fill_mode, + inpainting_full_res, + inpainting_padding, + init_img, + outpaint_steps, + out_config, + mask_width, + mask_height, + custom_exit_image, + frame_correction=True, # TODO: add frame_Correction in UI +): + main_frames = [init_img.convert("RGB")] + + for i in range(outpaint_steps): + print_out = ( + "Outpaint step: " + + str(i + 1) + + " / " + + str(outpaint_steps) + + " Seed: " + + str(seed) + ) + print(print_out) + current_image = main_frames[-1] + current_image = shrink_and_paste_on_blank( + current_image, mask_width, mask_height + ) + + mask_image = np.array(current_image)[:, :, 3] + mask_image = Image.fromarray(255 - mask_image).convert("RGB") + # create mask (black image with white mask_width width edges) + + if custom_exit_image and ((i + 1) == outpaint_steps): + current_image = custom_exit_image.resize( + (width, height), resample=Image.LANCZOS + ) + main_frames.append(current_image.convert("RGB")) + # print("using Custom Exit Image") + save2Collect(current_image, out_config, f"exit_img.png") + else: + pr = prompts[max(k for k in prompts.keys() if k <= i)] + processed, newseed = renderImg2Img( + f"{common_prompt_pre}\n{pr}\n{common_prompt_suf}".strip(), + negative_prompt, + sampler, + num_inference_steps, + guidance_scale, + seed, + width, + height, + current_image, + mask_image, + inpainting_denoising_strength, + inpainting_mask_blur, + inpainting_fill_mode, + inpainting_full_res, + inpainting_padding, + ) + + if len(processed.images) > 0: + main_frames.append(processed.images[0].convert("RGB")) + save2Collect(processed.images[0], out_config, f"outpain_step_{i}.png") + seed = newseed + # TODO: seed behavior + + if frame_correction and inpainting_mask_blur > 0: + corrected_frame = crop_inner_image( + main_frames[i + 1], mask_width, mask_height + ) + + enhanced_img = crop_fethear_ellipse( + main_frames[i], + 30, + inpainting_mask_blur / 3 // 2, + inpainting_mask_blur / 3 // 2, + ) + save2Collect(main_frames[i], out_config, f"main_frame_{i}") + save2Collect(enhanced_img, out_config, f"main_frame_enhanced_{i}") + corrected_frame.paste(enhanced_img, mask=enhanced_img) + main_frames[i] = corrected_frame + # else :TEST + # current_image.paste(prev_image, mask=prev_image) + return main_frames, processed + + +def create_zoom( + common_prompt_pre, + prompts_array, + common_prompt_suf, + negative_prompt, + num_outpainting_steps, + guidance_scale, + num_inference_steps, + custom_init_image, + custom_exit_image, + video_frame_rate, + video_zoom_mode, + video_start_frame_dupe_amount, + video_last_frame_dupe_amount, + inpainting_mask_blur, + inpainting_fill_mode, + zoom_speed, + seed, + outputsizeW, + outputsizeH, + batchcount, + sampler, + upscale_do, + upscaler_name, + upscale_by, + inpainting_denoising_strength=1, + inpainting_full_res=0, + inpainting_padding=0, + progress=None, +): + for i in range(batchcount): + print(f"Batch {i+1}/{batchcount}") + result = create_zoom_single( + common_prompt_pre, + prompts_array, + common_prompt_suf, + negative_prompt, + num_outpainting_steps, + guidance_scale, + num_inference_steps, + custom_init_image, + custom_exit_image, + video_frame_rate, + video_zoom_mode, + video_start_frame_dupe_amount, + video_last_frame_dupe_amount, + inpainting_mask_blur, + inpainting_fill_mode, + zoom_speed, + seed, + outputsizeW, + outputsizeH, + sampler, + upscale_do, + upscaler_name, + upscale_by, + inpainting_denoising_strength, + inpainting_full_res, + inpainting_padding, + progress, + ) + return result + + +def prepare_output_path(): + isCollect = shared.opts.data.get("infzoom_collectAllResources", False) + output_path = shared.opts.data.get("infzoom_outpath", "outputs") + + save_path = os.path.join( + output_path, shared.opts.data.get("infzoom_outSUBpath", "infinite-zooms") + ) + + if isCollect: + save_path = os.path.join(save_path, "iz_collect" + str(int(time.time()))) + + if not os.path.exists(save_path): + os.makedirs(save_path) + + video_filename = os.path.join( + save_path, "infinite_zoom_" + str(int(time.time())) + ".mp4" + ) + + return { + "isCollect": isCollect, + "save_path": save_path, + "video_filename": video_filename, + } + + +def save2Collect(img, out_config, name): + if out_config["isCollect"]: + img.save(f'{out_config["save_path"]}/{name}.png') + + +def frame2Collect(all_frames, out_config): + save2Collect(all_frames[-1], out_config, f"frame_{len(all_frames)}") + + +def frames2Collect(all_frames, out_config): + for i, f in enumerate(all_frames): + save2Collect(f, out_config, f"frame_{i}") + + +def crop_inner_image(outpainted_img, width_offset, height_offset): + width, height = outpainted_img.size + + center_x, center_y = int(width / 2), int(height / 2) + + # Crop the image to the center + cropped_img = outpainted_img.crop( + ( + center_x - width_offset, + center_y - height_offset, + center_x + width_offset, + center_y + height_offset, + ) + ) + prev_step_img = cropped_img.resize((width, height), resample=Image.LANCZOS) + # resized_img = resized_img.filter(ImageFilter.SHARPEN) + + return prev_step_img + + +def create_zoom_single( + common_prompt_pre, + prompts_array, + common_prompt_suf, + negative_prompt, + num_outpainting_steps, + guidance_scale, + num_inference_steps, + custom_init_image, + custom_exit_image, + video_frame_rate, + video_zoom_mode, + video_start_frame_dupe_amount, + video_last_frame_dupe_amount, + inpainting_mask_blur, + inpainting_fill_mode, + zoom_speed, + seed, + outputsizeW, + outputsizeH, + sampler, + upscale_do, + upscaler_name, + upscale_by, + inpainting_denoising_strength, + inpainting_full_res, + inpainting_padding, + progress, +): + # try: + # if gr.Progress() is not None: + # progress = gr.Progress() + # progress(0, desc="Preparing Initial Image") + # except Exception: + # pass + fix_env_Path_ffprobe() + out_config = prepare_output_path() + + prompts = {} + + for x in prompts_array: + try: + key = int(x[0]) + value = str(x[1]) + prompts[key] = value + except ValueError: + pass + + assert len(prompts_array) > 0, "prompts is empty" + + width = closest_upper_divisible_by_eight(outputsizeW) + height = closest_upper_divisible_by_eight(outputsizeH) + + current_image = Image.new(mode="RGBA", size=(width, height)) + mask_image = np.array(current_image)[:, :, 3] + mask_image = Image.fromarray(255 - mask_image).convert("RGB") + current_image = current_image.convert("RGB") + current_seed = seed + + if custom_init_image: + current_image = custom_init_image.resize( + (width, height), resample=Image.LANCZOS + ) + save2Collect(current_image, out_config, f"init_custom.png") + + else: + load_model_from_setting( + "infzoom_txt2img_model", progress, "Loading Model for txt2img: " + ) + + pr = prompts[min(k for k in prompts.keys() if k >= 0)] + processed, newseed = renderTxt2Img( + f"{common_prompt_pre}\n{pr}\n{common_prompt_suf}".strip(), + negative_prompt, + sampler, + num_inference_steps, + guidance_scale, + current_seed, + width, + height, + ) + if len(processed.images) > 0: + current_image = processed.images[0] + save2Collect(current_image, out_config, f"init_txt2img.png") + current_seed = newseed + + mask_width = math.trunc(width / 4) # was initially 512px => 128px + mask_height = math.trunc(height / 4) # was initially 512px => 128px + + num_interpol_frames = round(video_frame_rate * zoom_speed) + + all_frames = [] + + if upscale_do and progress: + progress(0, desc="upscaling inital image") + + load_model_from_setting( + "infzoom_inpainting_model", progress, "Loading Model for inpainting/img2img: " + ) + main_frames, processed = outpaint_steps( + width, + height, + common_prompt_pre, + common_prompt_suf, + prompts, + negative_prompt, + seed, + sampler, + num_inference_steps, + guidance_scale, + inpainting_denoising_strength, + inpainting_mask_blur, + inpainting_fill_mode, + inpainting_full_res, + inpainting_padding, + current_image, + num_outpainting_steps, + out_config, + mask_width, + mask_height, + custom_exit_image, + ) + all_frames.append( + do_upscaleImg(main_frames[0], upscale_do, upscaler_name, upscale_by) + if upscale_do + else main_frames[0] + ) + for i in range(len(main_frames) - 1): + # interpolation steps between 2 inpainted images (=sequential zoom and crop) + for j in range(num_interpol_frames - 1): + current_image = main_frames[i + 1] + interpol_image = current_image + save2Collect(interpol_image, out_config, f"interpol_img_{i}_{j}].png") + + interpol_width = math.ceil( + ( + 1 + - (1 - 2 * mask_width / width) + ** (1 - (j + 1) / num_interpol_frames) + ) + * width + / 2 + ) + + interpol_height = math.ceil( + ( + 1 + - (1 - 2 * mask_height / height) + ** (1 - (j + 1) / num_interpol_frames) + ) + * height + / 2 + ) + + interpol_image = interpol_image.crop( + ( + interpol_width, + interpol_height, + width - interpol_width, + height - interpol_height, + ) + ) + + interpol_image = interpol_image.resize((width, height)) + save2Collect(interpol_image, out_config, f"interpol_resize_{i}_{j}.png") + + # paste the higher resolution previous image in the middle to avoid drop in quality caused by zooming + interpol_width2 = math.ceil( + (1 - (width - 2 * mask_width) / (width - 2 * interpol_width)) + / 2 + * width + ) + + interpol_height2 = math.ceil( + (1 - (height - 2 * mask_height) / (height - 2 * interpol_height)) + / 2 + * height + ) + + prev_image_fix_crop = shrink_and_paste_on_blank( + main_frames[i], interpol_width2, interpol_height2 + ) + + interpol_image.paste(prev_image_fix_crop, mask=prev_image_fix_crop) + save2Collect(interpol_image, out_config, f"interpol_prevcrop_{i}_{j}.png") + + if upscale_do and progress: + progress(((i + 1) / num_outpainting_steps), desc="upscaling interpol") + + all_frames.append( + do_upscaleImg(interpol_image, upscale_do, upscaler_name, upscale_by) + if upscale_do + else interpol_image + ) + + if upscale_do and progress: + progress(((i + 1) / num_outpainting_steps), desc="upscaling current") + + all_frames.append( + do_upscaleImg(current_image, upscale_do, upscaler_name, upscale_by) + if upscale_do + else current_image + ) + + frames2Collect(all_frames, out_config) + + write_video( + out_config["video_filename"], + all_frames, + video_frame_rate, + video_zoom_mode, + int(video_start_frame_dupe_amount), + int(video_last_frame_dupe_amount), + ) + print("Video saved in: " + os.path.join(script_path, out_config["video_filename"])) + return ( + out_config["video_filename"], + main_frames, + processed.js(), + plaintext_to_html(processed.info), + plaintext_to_html(""), + ) diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/sd_helpers.py b/infinite-zoom-automatic1111-webui/iz_helpers/sd_helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..e6d5d6bedbc9b2d2c353a5f7b05ff2ddaa29d821 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/sd_helpers.py @@ -0,0 +1,81 @@ +from modules.processing import ( + process_images, + StableDiffusionProcessingTxt2Img, + StableDiffusionProcessingImg2Img, +) +import modules.shared as shared + + +def renderTxt2Img( + prompt, negative_prompt, sampler, steps, cfg_scale, seed, width, height +): + processed = None + p = StableDiffusionProcessingTxt2Img( + sd_model=shared.sd_model, + outpath_samples=shared.opts.outdir_txt2img_samples, + outpath_grids=shared.opts.outdir_txt2img_grids, + prompt=prompt, + negative_prompt=negative_prompt, + seed=seed, + sampler_name=sampler, + n_iter=1, + steps=steps, + cfg_scale=cfg_scale, + width=width, + height=height, + ) + processed = process_images(p) + newseed = p.seed + return processed, newseed + + +def renderImg2Img( + prompt, + negative_prompt, + sampler, + steps, + cfg_scale, + seed, + width, + height, + init_image, + mask_image, + inpainting_denoising_strength, + inpainting_mask_blur, + inpainting_fill_mode, + inpainting_full_res, + inpainting_padding, +): + processed = None + + p = StableDiffusionProcessingImg2Img( + sd_model=shared.sd_model, + outpath_samples=shared.opts.outdir_img2img_samples, + outpath_grids=shared.opts.outdir_img2img_grids, + prompt=prompt, + negative_prompt=negative_prompt, + seed=seed, + sampler_name=sampler, + n_iter=1, + steps=steps, + cfg_scale=cfg_scale, + width=width, + height=height, + init_images=[init_image], + denoising_strength=inpainting_denoising_strength, + mask_blur=inpainting_mask_blur, + inpainting_fill=inpainting_fill_mode, + inpaint_full_res=inpainting_full_res, + inpaint_full_res_padding=inpainting_padding, + mask=mask_image, + ) + # p.latent_mask = Image.new("RGB", (p.width, p.height), "white") + + processed = process_images(p) + # For those that use Image grids this will make sure that ffmpeg does not crash out + if (len(processed.images) > 1) and (processed.images[0].size[0] != processed.images[-1].size[0]): + processed.images.pop(0) + print("\nGrid image detected applying patch") + + newseed = p.seed + return processed, newseed diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/settings.py b/infinite-zoom-automatic1111-webui/iz_helpers/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..5b000c6b106a4d13bb7c77958e3775563a856daf --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/settings.py @@ -0,0 +1,108 @@ +import gradio as gr +import modules.shared as shared +from .static_variables import default_prompt + + +def on_ui_settings(): + section = ("infinite-zoom", "Infinite Zoom") + + shared.opts.add_option( + "infzoom_outpath", + shared.OptionInfo( + "outputs", + "Path where to store your infinite video. Default is Outputs", + gr.Textbox, + {"interactive": True}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_outSUBpath", + shared.OptionInfo( + "infinite-zooms", + "Which subfolder name to be created in the outpath. Default is 'infinite-zooms'", + gr.Textbox, + {"interactive": True}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_outsizeW", + shared.OptionInfo( + 512, + "Default width of your video", + gr.Slider, + {"minimum": 16, "maximum": 2048, "step": 16}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_outsizeH", + shared.OptionInfo( + 512, + "Default height your video", + gr.Slider, + {"minimum": 16, "maximum": 2048, "step": 16}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_ffprobepath", + shared.OptionInfo( + "", + "Writing videos has dependency to an existing FFPROBE executable on your machine. D/L here (https://github.com/BtbN/FFmpeg-Builds/releases) your OS variant and point to your installation path", + gr.Textbox, + {"interactive": True}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_txt2img_model", + shared.OptionInfo( + None, + "Name of your desired model to render keyframes (txt2img)", + gr.Dropdown, + lambda: {"choices": [x for x in list(shared.list_checkpoint_tiles()) if "inpainting" not in x]}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_inpainting_model", + shared.OptionInfo( + None, + "Name of your desired inpaint model (img2img-inpaint). Default is vanilla sd-v1-5-inpainting.ckpt ", + gr.Dropdown, + lambda: {"choices": [x for x in list(shared.list_checkpoint_tiles()) if "inpainting" in x]}, + section=section, + ), + ) + + shared.opts.add_option( + "infzoom_defPrompt", + shared.OptionInfo( + default_prompt, + "Default prompt-setup to start with'", + gr.Code, + {"interactive": True, "language": "json"}, + section=section, + ), + ) + + + shared.opts.add_option( + "infzoom_collectAllResources", + shared.OptionInfo( + False, + "!!! Store all images (txt2img, init_image,exit_image, inpainting, interpolation) into one folder in your OUTPUT Path. Very slow, a lot of data. Dont do this on long runs !!!", + gr.Checkbox, + {"interactive": True}, + section=section, + ), + ) + diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/static_variables.py b/infinite-zoom-automatic1111-webui/iz_helpers/static_variables.py new file mode 100644 index 0000000000000000000000000000000000000000..ed2616eda168d41e9a58f5df97c8f21145d6603d --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/static_variables.py @@ -0,0 +1,51 @@ +import os +from modules import scripts +import modules.sd_samplers + +default_sampling_steps = 35 +default_sampler = "DDIM" +default_cfg_scale = 8 +default_mask_blur = 48 +default_total_outpaints = 5 +promptTableHeaders = ["Start at second [0,1,...]", "Prompt"] + +default_prompt = """ +{ + "prePrompt": "Huge spectacular Waterfall in ", + "prompts": { + "data": [ + [0, "a dense tropical forest"], + [2, "a Lush jungle"], + [3, "a Thick rainforest"], + [5, "a Verdant canopy"] + ] + }, + "postPrompt": "epic perspective,(vegetation overgrowth:1.3)(intricate, ornamentation:1.1),(baroque:1.1), fantasy, (realistic:1) digital painting , (magical,mystical:1.2) , (wide angle shot:1.4), (landscape composed:1.2)(medieval:1.1),(tropical forest:1.4),(river:1.3) volumetric lighting ,epic, style by Alex Horley Wenjun Lin greg rutkowski Ruan Jia (Wayne Barlowe:1.2)", + "negPrompt": "frames, border, edges, borderline, text, character, duplicate, error, out of frame, watermark, low quality, ugly, deformed, blur, bad-artist" +} +""" + +empty_prompt = '{"prompts":{"data":[],"negPrompt":"", prePrompt:"", postPrompt:""}' + +invalid_prompt = { + "prompts": { + "data": [[0, "Your prompt-json is invalid, please check Settings"]], + }, + "negPrompt": "Invalid prompt-json", + "prePrompt": "Invalid prompt", + "postPrompt": "Invalid prompt", +} + +available_samplers = [ + s.name for s in modules.sd_samplers.samplers if "UniPc" not in s.name +] + +current_script_dir = scripts.basedir().split(os.sep)[ + -2: +] # contains install and our extension foldername +jsonprompt_schemafile = ( + current_script_dir[0] + + "/" + + current_script_dir[1] + + "/iz_helpers/promptschema.json" +) diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/ui.py b/infinite-zoom-automatic1111-webui/iz_helpers/ui.py new file mode 100644 index 0000000000000000000000000000000000000000..2607286e87b47937afefa60dd0823c0bad1281d0 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/ui.py @@ -0,0 +1,307 @@ +import gradio as gr +from .run import create_zoom +import modules.shared as shared +from webui import wrap_gradio_gpu_call +from modules.ui import create_output_panel + +from .static_variables import ( + default_prompt, + available_samplers, + default_total_outpaints, + default_sampling_steps, + default_cfg_scale, + default_mask_blur, + default_sampler, +) +from .helpers import putPrompts, clearPrompts +from .prompt_util import readJsonPrompt +from .static_variables import promptTableHeaders + + +def on_ui_tabs(): + with gr.Blocks(analytics_enabled=False) as infinite_zoom_interface: + gr.HTML( + """ +

+ GitHub Repo + Discord server +

+ + """ + ) + with gr.Row(): + generate_btn = gr.Button(value="Generate video", variant="primary") + interrupt = gr.Button(value="Interrupt", elem_id="interrupt_training") + with gr.Row(): + with gr.Column(scale=1, variant="panel"): + with gr.Tab("Main"): + with gr.Row(): + batchcount_slider = gr.Slider( + minimum=1, + maximum=25, + value=shared.opts.data.get("infzoom_batchcount", 1), + step=1, + label="Batch Count", + ) + main_outpaint_steps = gr.Number( + label="Total video length [s]", + value=default_total_outpaints, + precision=0, + interactive=True, + ) + + # safe reading json prompt + pr = shared.opts.data.get("infzoom_defPrompt", default_prompt) + jpr = readJsonPrompt(pr, True) + + main_common_prompt_pre = gr.Textbox( + value=jpr["prePrompt"], label="Common Prompt Prefix" + ) + + main_prompts = gr.Dataframe( + type="array", + headers=promptTableHeaders, + datatype=["number", "str"], + row_count=1, + col_count=(2, "fixed"), + value=jpr["prompts"], + wrap=True, + ) + + main_common_prompt_suf = gr.Textbox( + value=jpr["postPrompt"], label="Common Prompt Suffix" + ) + + main_negative_prompt = gr.Textbox( + value=jpr["negPrompt"], label="Negative Prompt" + ) + + # these button will be moved using JS under the dataframe view as small ones + exportPrompts_button = gr.Button( + value="Export prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_exP_butt", + ) + importPrompts_button = gr.UploadButton( + label="Import prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_imP_butt", + ) + exportPrompts_button.click( + None, + _js="exportPrompts", + inputs=[ + main_common_prompt_pre, + main_prompts, + main_common_prompt_suf, + main_negative_prompt, + ], + outputs=None, + ) + importPrompts_button.upload( + fn=putPrompts, + outputs=[ + main_common_prompt_pre, + main_prompts, + main_common_prompt_suf, + main_negative_prompt, + ], + inputs=[importPrompts_button], + ) + + clearPrompts_button = gr.Button( + value="Clear prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_clP_butt", + ) + clearPrompts_button.click( + fn=clearPrompts, + inputs=[], + outputs=[ + main_prompts, + main_negative_prompt, + main_common_prompt_pre, + main_common_prompt_suf, + ], + ) + + with gr.Accordion("Render settings"): + with gr.Row(): + seed = gr.Number( + label="Seed", value=-1, precision=0, interactive=True + ) + main_sampler = gr.Dropdown( + label="Sampler", + choices=available_samplers, + value=default_sampler, + type="value", + ) + with gr.Row(): + main_width = gr.Slider( + minimum=16, + maximum=2048, + value=shared.opts.data.get("infzoom_outsizeW", 512), + step=16, + label="Output Width", + ) + main_height = gr.Slider( + minimum=16, + maximum=2048, + value=shared.opts.data.get("infzoom_outsizeH", 512), + step=16, + label="Output Height", + ) + with gr.Row(): + main_guidance_scale = gr.Slider( + minimum=0.1, + maximum=15, + step=0.1, + value=default_cfg_scale, + label="Guidance Scale", + ) + sampling_step = gr.Slider( + minimum=1, + maximum=150, + step=1, + value=default_sampling_steps, + label="Sampling Steps for each outpaint", + ) + with gr.Row(): + init_image = gr.Image( + type="pil", label="Custom initial image" + ) + exit_image = gr.Image( + type="pil", label="Custom exit image", visible=False + ) + with gr.Tab("Video"): + video_frame_rate = gr.Slider( + label="Frames per second", + value=30, + minimum=1, + maximum=60, + ) + video_zoom_mode = gr.Radio( + label="Zoom mode", + choices=["Zoom-out", "Zoom-in"], + value="Zoom-out", + type="index", + ) + video_start_frame_dupe_amount = gr.Slider( + label="number of start frame dupe", + info="Frames to freeze at the start of the video", + value=0, + minimum=1, + maximum=60, + ) + video_last_frame_dupe_amount = gr.Slider( + label="number of last frame dupe", + info="Frames to freeze at the end of the video", + value=0, + minimum=1, + maximum=60, + ) + video_zoom_speed = gr.Slider( + label="Zoom Speed", + value=1.0, + minimum=0.1, + maximum=20.0, + step=0.1, + info="Zoom speed in seconds (higher values create slower zoom)", + ) + + with gr.Tab("Outpaint"): + inpainting_mask_blur = gr.Slider( + label="Mask Blur", + minimum=0, + maximum=64, + value=default_mask_blur, + ) + inpainting_fill_mode = gr.Radio( + label="Masked content", + choices=["fill", "original", "latent noise", "latent nothing"], + value="latent noise", + type="index", + ) + + with gr.Tab("Post proccess"): + upscale_do = gr.Checkbox(False, label="Enable Upscale") + upscaler_name = gr.Dropdown( + label="Upscaler", + elem_id="infZ_upscaler", + choices=[x.name for x in shared.sd_upscalers], + value=shared.sd_upscalers[0].name, + ) + upscale_by = gr.Slider( + label="Upscale by factor", + minimum=1, + maximum=8, + step=0.5, + value=2, + ) + with gr.Accordion("Help", open=False): + gr.Markdown( + """# Performance critical +Depending on amount of frames and which upscaler you choose it might took a long time to render. +Our best experience and trade-off is the R-ERSGAn4x upscaler. +""" + ) + + with gr.Column(scale=1, variant="compact"): + output_video = gr.Video(label="Output").style(width=512, height=512) + ( + out_image, + generation_info, + html_info, + html_log, + ) = create_output_panel( + "infinite-zoom", shared.opts.outdir_img2img_samples + ) + + generate_btn.click( + fn=wrap_gradio_gpu_call(create_zoom, extra_outputs=[None, "", ""]), + inputs=[ + main_common_prompt_pre, + main_prompts, + main_common_prompt_suf, + main_negative_prompt, + main_outpaint_steps, + main_guidance_scale, + sampling_step, + init_image, + exit_image, + video_frame_rate, + video_zoom_mode, + video_start_frame_dupe_amount, + video_last_frame_dupe_amount, + inpainting_mask_blur, + inpainting_fill_mode, + video_zoom_speed, + seed, + main_width, + main_height, + batchcount_slider, + main_sampler, + upscale_do, + upscaler_name, + upscale_by, + ], + outputs=[output_video, out_image, generation_info, html_info, html_log], + ) + + main_prompts.change( + fn=checkPrompts, inputs=[main_prompts], outputs=[generate_btn] + ) + + interrupt.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[]) + infinite_zoom_interface.queue() + return [(infinite_zoom_interface, "Infinite Zoom", "iz_interface")] + + +def checkPrompts(p): + return gr.Button.update( + interactive=any(0 in sublist for sublist in p) + or any("0" in sublist for sublist in p) + ) diff --git a/infinite-zoom-automatic1111-webui/iz_helpers/video.py b/infinite-zoom-automatic1111-webui/iz_helpers/video.py new file mode 100644 index 0000000000000000000000000000000000000000..cb1c5d95ce9bb8646c9121e671c72857b53856e4 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/iz_helpers/video.py @@ -0,0 +1,43 @@ +import numpy as np +import imageio +from PIL import Image + +def write_video(file_path, frames, fps, reversed=True, start_frame_dupe_amount=15, last_frame_dupe_amount=30): + """ + Writes frames to an mp4 video file + :param file_path: Path to output video, must end with .mp4 + :param frames: List of PIL.Image objects + :param fps: Desired frame rate + :param reversed: if order of images to be reversed (default = True) + """ + if reversed == True: + frames = frames[::-1] + + # Drop missformed frames + frames = [frame for frame in frames if frame.size == frames[0].size] + + # Create an imageio video writer, avoid block size of 512. + writer = imageio.get_writer(file_path, fps=fps, macro_block_size=None) + + # Duplicate the start and end frames + start_frames = [frames[0]] * start_frame_dupe_amount + end_frames = [frames[-1]] * last_frame_dupe_amount + + # Write the duplicated frames to the video writer + for frame in start_frames: + # Convert PIL image to numpy array + np_frame = np.array(frame) + writer.append_data(np_frame) + + # Write the frames to the video writer + for frame in frames: + np_frame = np.array(frame) + writer.append_data(np_frame) + + # Write the duplicated frames to the video writer + for frame in end_frames: + np_frame = np.array(frame) + writer.append_data(np_frame) + + # Close the video writer + writer.close() \ No newline at end of file diff --git a/infinite-zoom-automatic1111-webui/javascript/infinite-zoom-hints.js b/infinite-zoom-automatic1111-webui/javascript/infinite-zoom-hints.js new file mode 100644 index 0000000000000000000000000000000000000000..47261c21b8a958da9e45bc4010a7afe99f72a288 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/javascript/infinite-zoom-hints.js @@ -0,0 +1,49 @@ +// mouseover tooltips for various UI elements + +infzoom_titles = { + "Batch Count":"How many separate videos to create", + "Total video length [s]":"For each seconds frame (FPS) will be generated. Define prompts at which time they should start wihtin this duration.", + "Common Prompt Prefix":"Prompt inserted before each step", + "Common Prompt Suffix":"Prompt inserted after each step", + "Negative Prompt":"What your model shall avoid", + "Export prompts": "Downloads a JSON file to save all prompts", + "Import prompts": "Restore Prompts table from a specific JSON file", + "Clear prompts": "Start over, remove all entries from prompt table, prefix, suffix, negative", + "Custom initial image":"An image at the end resp. begin of your movie, depending or ZoomIn or Out", + "Custom exit image":"An image at the end resp. begin of your movie, depending or ZoomIn or Out", + "Zoom Speed":"Varies additional frames per second", + "Start at second [0,1,...]": "At which time the prompt has to be occure. We need at least one prompt starting at time 0", + "Generate video": "Start rendering. If it´s disabled the prompt table is invalid, check we have a start prompt at time 0" +} + + +onUiUpdate(function(){ + gradioApp().querySelectorAll('span, button, select, p').forEach(function(span){ + tooltip = infzoom_titles[span.textContent]; + + if(!tooltip){ + tooltip = infzoom_titles[span.value]; + } + + if(!tooltip){ + for (const c of span.classList) { + if (c in infzoom_titles) { + tooltip = infzoom_titles[c]; + break; + } + } + } + + if(tooltip){ + span.title = tooltip; + } + }) + + gradioApp().querySelectorAll('select').forEach(function(select){ + if (select.onchange != null) return; + + select.onchange = function(){ + select.title = infzoom_titles[select.value] || ""; + } + }) +}) diff --git a/infinite-zoom-automatic1111-webui/javascript/infinite-zoom.js b/infinite-zoom-automatic1111-webui/javascript/infinite-zoom.js new file mode 100644 index 0000000000000000000000000000000000000000..e1c258f6e5a073835b40c6e2f9ec2e00a018c3ef --- /dev/null +++ b/infinite-zoom-automatic1111-webui/javascript/infinite-zoom.js @@ -0,0 +1,54 @@ +// Function to download data to a file +function exportPrompts(cppre,p, cpsuf,np, filename = "infinite-zoom-prompts.json") { + + let J = { prompts: p, negPrompt: np, prePrompt: cppre, postPrompt: cpsuf } + + var file = new Blob([JSON.stringify(J,null,2)], { type: "text/csv" }); + if (window.navigator.msSaveOrOpenBlob) // IE10+ + window.navigator.msSaveOrOpenBlob(file, filename); + else { // Others + var a = document.createElement("a"), + url = URL.createObjectURL(file); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + setTimeout(function () { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); + } +} + +document.addEventListener("DOMContentLoaded", () => { + const onload = () => { + + if (typeof gradioApp === "function") { + /* move big buttons directly under the tabl of prompts as SMall ones */ + const wrap = gradioApp().querySelector("#tab_iz_interface .gradio-dataframe .controls-wrap") + + if (wrap) { + let butts = gradioApp().querySelectorAll("#tab_iz_interface .infzoom_tab_butt") + butts.forEach(b => { + wrap.appendChild(b) + b.classList.replace("lg", "sm") // smallest + }); + } + else { + setTimeout(onload, 2000); + } + } + else { + setTimeout(onload, 2000); + } + }; + onload(); +}); + + + + + + + + diff --git a/infinite-zoom-automatic1111-webui/scripts/__pycache__/infinite-zoom.cpython-310.pyc b/infinite-zoom-automatic1111-webui/scripts/__pycache__/infinite-zoom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6927e2c9a6f9015470fe0cefa6470f8e9047de2 Binary files /dev/null and b/infinite-zoom-automatic1111-webui/scripts/__pycache__/infinite-zoom.cpython-310.pyc differ diff --git a/infinite-zoom-automatic1111-webui/scripts/infinite-zoom.py b/infinite-zoom-automatic1111-webui/scripts/infinite-zoom.py new file mode 100644 index 0000000000000000000000000000000000000000..60751b0c3ab297837c25df962e39d2248ccaa9a9 --- /dev/null +++ b/infinite-zoom-automatic1111-webui/scripts/infinite-zoom.py @@ -0,0 +1,5 @@ +from modules import script_callbacks +from iz_helpers.ui import on_ui_tabs +from iz_helpers.settings import on_ui_settings +script_callbacks.on_ui_tabs(on_ui_tabs) +script_callbacks.on_ui_settings(on_ui_settings) \ No newline at end of file diff --git a/infinite-zoom-automatic1111-webui/style.css b/infinite-zoom-automatic1111-webui/style.css new file mode 100644 index 0000000000000000000000000000000000000000..bac0c3dcbbd42ffd1a2ff6ae8a51463c1b2209dd --- /dev/null +++ b/infinite-zoom-automatic1111-webui/style.css @@ -0,0 +1,10 @@ +#tab_iz_interface .gradio-dataframe .controls-wrap { + flex-direction: row-reverse; + justify-content: space-between; +} + +/* first column min width */ +#tab_iz_interface th:first-child { + flex: 0 0 0%; + width: 0; +} diff --git a/sd-webui-cutoff/.gitignore b/sd-webui-cutoff/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bee8a64b79a99590d5303307144172cfe824fbf7 --- /dev/null +++ b/sd-webui-cutoff/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/sd-webui-cutoff/LICENSE b/sd-webui-cutoff/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d1e1072ee5e1d109c15b6fd18756aedc2a401840 --- /dev/null +++ b/sd-webui-cutoff/LICENSE @@ -0,0 +1 @@ +MIT License diff --git a/sd-webui-cutoff/README.md b/sd-webui-cutoff/README.md new file mode 100644 index 0000000000000000000000000000000000000000..99f738af15d5007e60b944cf7d7a1aa2746ec509 --- /dev/null +++ b/sd-webui-cutoff/README.md @@ -0,0 +1,146 @@ +# Cutoff - Cutting Off Prompt Effect + +![cover](./images/cover.jpg) + +
+Update Info + +Upper is newer. + +
+
20e87ce264338b824296b7559679ed1bb0bdacd7
+
Skip empty targets.
+
03bfe60162ba418e18dbaf8f1b9711fd62195ef3
+
Add Disable for Negative prompt option. Default is True.
+
f0990088fed0f5013a659cacedb194313a398860
+
Accept an empty prompt.
+
+
+ +## What is this? + +This is an extension for [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) which limits the tokens' influence scope. + +## Usage + +1. Select `Enabled` checkbox. +2. Input words which you want to limit scope in `Target tokens`. +3. Generate images. + +## Note + +If the generated image was corrupted or something like that, try to change the `Weight` value or change the interpolation method to `SLerp`. Interpolation method can be found in `Details`. + +### `Details` section + +
+
Disable for Negative prompt.
+
If enabled, Cutoff will not work for the negative prompt. Default is true.
+
Cutoff strongly.
+
See description below. Default is false.
+
Interpolation method
+
How "padded" and "original" vectors will be interpolated. Default is Lerp.
+
Padding token
+
What token will be padded instead of Target tokens. Default is _ (underbar).
+
+ +## Examples + +``` +7th_anime_v3_A-fp16 / kl-f8-anime2 / DPM++ 2M Karras / 15 steps / 512x768 +Prompt: a cute girl, white shirt with green tie, red shoes, blue hair, yellow eyes, pink skirt +Negative Prompt: (low quality, worst quality:1.4), nsfw +Target tokens: white, green, red, blue, yellow, pink +``` + +Sample 1. + +![sample 1](./images/sample-1.png) + +Sample 2. (use `SLerp` for interpolation) + +![sample 2](./images/sample-2.png) + +Sample 3. + +![sample 3](./images/sample-3.png) + +## How it works + +- [Japanese](#japanese) +- [English](#english) + +or see [#5](https://github.com/hnmr293/sd-webui-cutoff/issues/5). + +![idea](./images/idea.png) + +### Japanese + +プロンプトをCLIPに通して得られる (77, 768) 次元の埋め込み表現(?正式な用語は分かりません)について、 +ごく単純には、77個の行ベクトルはプロンプト中の75個のトークン(+開始トークン+終了トークン)に対応していると考えられる。 + +※上図は作図上、この説明とは行と列を入れ替えて描いている。 + +このベクトルには単語単体の意味だけではなく、文章全体の、例えば係り結びなどの情報を集約したものが入っているはずである。 + +ここで `a cute girl, pink hair, red shoes` というプロンプトを考える。 +普通、こういったプロンプトの意図は + +1. `pink` は `hair` だけに係っており `shoes` には係っていない。 +2. 同様に `red` も `hair` には係っていない。 +3. `a cute girl` は全体に係っていて欲しい。`hair` や `shoes` は女の子に合うものが出て欲しい。 + +……というもののはずである。 + +しかしながら、[EvViz2](https://github.com/hnmr293/sd-webui-evviz2) などでトークン間の関係を見ると、そううまくはいっていないことが多い。 +つまり、`shoes` の位置のベクトルに `pink` の影響が出てしまっていたりする。 + +一方で上述の通り `a cute girl` の影響は乗っていて欲しいわけで、どうにかして、特定のトークンの影響を取り除けるようにしたい。 + +この拡張では、指定されたトークンを *padding token* に書き換えることでそれを実現している。 + +たとえば `red shoes` の部分に対応して `a cute girl, _ hair, red shoes` というプロンプトを生成する。`red` と `shoes` に対応する位置のベクトルをここから生成したもので上書きしてやることで、`pink` の影響を除外している。 + +これを `pink` の側から見ると、自分の影響が `pink hair` の範囲内に制限されているように見える。What is this? の "limits the tokens' influence scope" はそういう意味。 + +ところで `a cute girl` の方は、`pink hair, red shoes` の影響を受けていてもいいし受けなくてもいいような気がする。 +そこでこの拡張では、こういうどちらでもいいプロンプトに対して + +1. `a cute girl, pink hair, red shoes` +2. `a cute girl, _ hair, _ shoes` + +のどちらを適用するか選べるようにしている。`Details` の `Cutoff strongly` がそれで、オフのとき1.を、オンのとき2.を、それぞれ選ぶようになっている。 +元絵に近いのが出るのはオフのとき。デフォルトもこちらにしてある。 + +### English + +NB. The following text is a translation of the Japanese text above by [DeepL](https://www.deepl.com/translator). + +For the (77, 768) dimensional embedded representation (I don't know the formal terminology), one could simply assume that the 77 row vectors correspond to the 75 tokens (+ start token and end token) in the prompt. + +Note: The above figure is drawn with the rows and columns interchanged from this explanation. + +This vector should contain not only the meanings of individual words, but also the aggregate information of the whole sentence, for example, the connection between words. + +Consider the prompt `a cute girl, pink hair, red shoes`. Normally, the intent of such a prompt would be + +- `pink` is only for `hair`, not `shoes`. +- Similarly, `red` does not refer to `hair`. +- We want `a cute girl` to be about the whole thing, and we want the `hair` and `shoes` to match the girl. + +However, when we look at the relationship between tokens in [EvViz2](https://github.com/hnmr293/sd-webui-evviz2) and other tools, we see that it is not always that way. In other words, the position vector of the `shoes` may be affected by `pink`. + +On the other hand, as mentioned above, we want the influence of `a cute girl` to be present, so we want to be able to somehow remove the influence of a specific token. + +This extension achieves this by rewriting the specified tokens as a *padding token*. + +For example, for the `red shoes` part, we generate the prompt `a cute girl, _ hair, red shoes`, and by overwriting the position vectors corresponding to `red` and `shoes` with those generated from this prompt, we remove the influence of `pink`. + +From `pink`'s point of view, it appears that its influence is limited to the `pink hair`'s scope. + +By the way, `a cute girl` may or may not be influenced by `pink hair` and `red shoes`. So, in this extension, for such a prompt that can be either + +1. `a cute girl, pink hair, red shoes` +2. `a cute girl, _ hair, _ shoes` + +The `Cutoff strongly` in the `Details` section allows you to select 1 when it is off and 2 when it is on. The one that comes out closer to the original image is "off". The default is also set this way. diff --git a/sd-webui-cutoff/images/cover.jpg b/sd-webui-cutoff/images/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59072fe9205825e4620ae01c2e2d909284e1337d --- /dev/null +++ b/sd-webui-cutoff/images/cover.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:129a1d562085cd9af3c46ad42ce2a3133e5306d03a7c7e37942b634d55de3666 +size 1955200 diff --git a/sd-webui-cutoff/images/idea.png b/sd-webui-cutoff/images/idea.png new file mode 100644 index 0000000000000000000000000000000000000000..1e44a6a99246be77689f115b1e13c300e1cfdc66 Binary files /dev/null and b/sd-webui-cutoff/images/idea.png differ diff --git a/sd-webui-cutoff/images/sample-1.png b/sd-webui-cutoff/images/sample-1.png new file mode 100644 index 0000000000000000000000000000000000000000..8bf8d451a522e3c97f258f7e982c3fee7467d63f --- /dev/null +++ b/sd-webui-cutoff/images/sample-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4e36a8555ed4818a166fe7c86c4b91ba67d5255c6ef51ad206b163f1aa779c6 +size 5929523 diff --git a/sd-webui-cutoff/images/sample-2.png b/sd-webui-cutoff/images/sample-2.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbf2cf2f3aed2c169152014d2f331b55f0104ce --- /dev/null +++ b/sd-webui-cutoff/images/sample-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0546d2f8d3ea624b87839f8a0698a33db3465b3919540fc8c1f51b7467055455 +size 1016674 diff --git a/sd-webui-cutoff/images/sample-3.png b/sd-webui-cutoff/images/sample-3.png new file mode 100644 index 0000000000000000000000000000000000000000..232b671c818b5d9e9374a01daee4e0e1d0e9c666 --- /dev/null +++ b/sd-webui-cutoff/images/sample-3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1d43f8e30d9078417a8ba22fc28dec5a16279adad189c917efb7a99b8706a4d +size 1212008 diff --git a/sd-webui-cutoff/scripts/__pycache__/cutoff.cpython-310.pyc b/sd-webui-cutoff/scripts/__pycache__/cutoff.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66883f8063d89dc16a786bd454a7d5af178afb06 Binary files /dev/null and b/sd-webui-cutoff/scripts/__pycache__/cutoff.cpython-310.pyc differ diff --git a/sd-webui-cutoff/scripts/cutoff.py b/sd-webui-cutoff/scripts/cutoff.py new file mode 100644 index 0000000000000000000000000000000000000000..139da253c5f23ed51541b91a57dc81256ef01a60 --- /dev/null +++ b/sd-webui-cutoff/scripts/cutoff.py @@ -0,0 +1,257 @@ +from collections import defaultdict +from typing import Union, List, Tuple + +import numpy as np +import torch +from torch import Tensor, nn +import gradio as gr + +from modules.processing import StableDiffusionProcessing +from modules import scripts + +from scripts.cutofflib.sdhook import SDHook +from scripts.cutofflib.embedding import CLIP, generate_prompts, token_to_block +from scripts.cutofflib.utils import log, set_debug +from scripts.cutofflib.xyz import init_xyz + +NAME = 'Cutoff' +PAD = '_' + +def check_neg(s: str, negative_prompt: str, all_negative_prompts: Union[List[str],None]): + if s == negative_prompt: + return True + + if all_negative_prompts is not None: + return s in all_negative_prompts + + return False + +def slerp(t, v0, v1, DOT_THRESHOLD=0.9995): + # cf. https://memo.sugyan.com/entry/2022/09/09/230645 + + inputs_are_torch = False + input_device = v0.device + if not isinstance(v0, np.ndarray): + inputs_are_torch = True + v0 = v0.cpu().numpy() + v1 = v1.cpu().numpy() + + dot = np.sum(v0 * v1 / (np.linalg.norm(v0) * np.linalg.norm(v1))) + if np.abs(dot) > DOT_THRESHOLD: + v2 = (1 - t) * v0 + t * v1 + else: + theta_0 = np.arccos(dot) + sin_theta_0 = np.sin(theta_0) + theta_t = theta_0 * t + sin_theta_t = np.sin(theta_t) + s0 = np.sin(theta_0 - theta_t) / sin_theta_0 + s1 = sin_theta_t / sin_theta_0 + v2 = s0 * v0 + s1 * v1 + + if inputs_are_torch: + v2 = torch.from_numpy(v2).to(input_device) + + return v2 + + +class Hook(SDHook): + + def __init__( + self, + enabled: bool, + targets: List[str], + padding: Union[str,int], + weight: float, + disable_neg: bool, + strong: bool, + interpolate: str, + ): + super().__init__(enabled) + self.targets = targets + self.padding = padding + self.weight = float(weight) + self.disable_neg = disable_neg + self.strong = strong + self.intp = interpolate + + def interpolate(self, t1: Tensor, t2: Tensor, w): + if self.intp == 'lerp': + return torch.lerp(t1, t2, w) + else: + return slerp(w, t1, t2) + + def hook_clip(self, p: StableDiffusionProcessing, clip: nn.Module): + + skip = False + + def hook(mod: nn.Module, inputs: Tuple[List[str]], output: Tensor): + nonlocal skip + + if skip: + # called from below + return + + assert isinstance(mod, CLIP) + + prompts, *rest = inputs + assert len(prompts) == output.shape[0] + + # Check wether we are processing Negative prompt or not. + # I firmly believe there is no one who uses a negative prompt + # exactly identical to a prompt. + if self.disable_neg: + if all(check_neg(x, p.negative_prompt, p.all_negative_prompts) for x in prompts): + # Now we are processing Negative prompt and skip it. + return + + output = output.clone() + for pidx, prompt in enumerate(prompts): + tt = token_to_block(mod, prompt) + + cutoff = generate_prompts(mod, prompt, self.targets, self.padding) + switch_base = np.full_like(cutoff.sw, self.strong) + switch = np.full_like(cutoff.sw, True) + active = cutoff.active_blocks() + + prompt_to_tokens = defaultdict(lambda: []) + for tidx, (token, block_index) in enumerate(tt): + if block_index in active: + sw = switch.copy() + sw[block_index] = False + prompt = cutoff.text(sw) + else: + prompt = cutoff.text(switch_base) + prompt_to_tokens[prompt].append((tidx, token)) + + #log(prompt_to_tokens) + + ks = list(prompt_to_tokens.keys()) + if len(ks) == 0: + # without any (negative) prompts + ks.append('') + + try: + # + skip = True + vs = mod(ks) + finally: + skip = False + + tensor = output[pidx, :, :] # e.g. (77, 768) + for k, t in zip(ks, vs): + assert tensor.shape == t.shape + for tidx, token in prompt_to_tokens[k]: + log(f'{tidx:03} {token.token:<16} {k}') + tensor[tidx, :] = self.interpolate(tensor[tidx,:], t[tidx,:], self.weight) + + return output + + self.hook_layer(clip, hook) + + +class Script(scripts.Script): + + def __init__(self): + super().__init__() + self.last_hooker: Union[SDHook,None] = None + + def title(self): + return NAME + + def show(self, is_img2img): + return scripts.AlwaysVisible + + def ui(self, is_img2img): + with gr.Accordion(NAME, open=False): + enabled = gr.Checkbox(label='Enabled', value=False) + targets = gr.Textbox(label='Target tokens (comma separated)', placeholder='red, blue') + weight = gr.Slider(minimum=-1.0, maximum=2.0, step=0.01, value=0.5, label='Weight') + with gr.Accordion('Details', open=False): + disable_neg = gr.Checkbox(value=True, label='Disable for Negative prompt.') + strong = gr.Checkbox(value=False, label='Cutoff strongly.') + padding = gr.Textbox(label='Padding token (ID or single token)') + lerp = gr.Radio(choices=['Lerp', 'SLerp'], value='Lerp', label='Interpolation method') + + debug = gr.Checkbox(value=False, label='Debug log') + debug.change(fn=set_debug, inputs=[debug], outputs=[]) + + return [ + enabled, + targets, + weight, + disable_neg, + strong, + padding, + lerp, + debug, + ] + + def process( + self, + p: StableDiffusionProcessing, + enabled: bool, + targets_: str, + weight: Union[float,int], + disable_neg: bool, + strong: bool, + padding: Union[str,int], + intp: str, + debug: bool, + ): + set_debug(debug) + + if self.last_hooker is not None: + self.last_hooker.__exit__(None, None, None) + self.last_hooker = None + + if not enabled: + return + + if targets_ is None or len(targets_) == 0: + return + + targets = [x.strip() for x in targets_.split(',')] + targets = [x for x in targets if len(x) != 0] + + if len(targets) == 0: + return + + if padding is None: + padding = PAD + elif isinstance(padding, str): + if len(padding) == 0: + padding = PAD + else: + try: + padding = int(padding) + except: + if not padding.endswith(''): + padding += '' + + weight = float(weight) + intp = intp.lower() + + self.last_hooker = Hook( + enabled=True, + targets=targets, + padding=padding, + weight=weight, + disable_neg=disable_neg, + strong=strong, + interpolate=intp, + ) + + self.last_hooker.setup(p) + self.last_hooker.__enter__() + + p.extra_generation_params.update({ + f'{NAME} enabled': enabled, + f'{NAME} targets': targets, + f'{NAME} padding': padding, + f'{NAME} weight': weight, + f'{NAME} disable_for_neg': disable_neg, + f'{NAME} strong': strong, + f'{NAME} interpolation': intp, + }) + +init_xyz(Script, NAME) diff --git a/sd-webui-cutoff/scripts/cutofflib/__pycache__/embedding.cpython-310.pyc b/sd-webui-cutoff/scripts/cutofflib/__pycache__/embedding.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..343c3f133b12890adcb57f34bf7cce1fd4f69e92 Binary files /dev/null and b/sd-webui-cutoff/scripts/cutofflib/__pycache__/embedding.cpython-310.pyc differ diff --git a/sd-webui-cutoff/scripts/cutofflib/__pycache__/sdhook.cpython-310.pyc b/sd-webui-cutoff/scripts/cutofflib/__pycache__/sdhook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f412ab4fe620f02c62d5fc8a53a48357045fe494 Binary files /dev/null and b/sd-webui-cutoff/scripts/cutofflib/__pycache__/sdhook.cpython-310.pyc differ diff --git a/sd-webui-cutoff/scripts/cutofflib/__pycache__/utils.cpython-310.pyc b/sd-webui-cutoff/scripts/cutofflib/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cafbf8816cae4ba0dc1943be6ea4dcb6d9bfeb9 Binary files /dev/null and b/sd-webui-cutoff/scripts/cutofflib/__pycache__/utils.cpython-310.pyc differ diff --git a/sd-webui-cutoff/scripts/cutofflib/__pycache__/xyz.cpython-310.pyc b/sd-webui-cutoff/scripts/cutofflib/__pycache__/xyz.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb750825a19ef4daf7eac6c909b4369aa802f0c9 Binary files /dev/null and b/sd-webui-cutoff/scripts/cutofflib/__pycache__/xyz.cpython-310.pyc differ diff --git a/sd-webui-cutoff/scripts/cutofflib/embedding.py b/sd-webui-cutoff/scripts/cutofflib/embedding.py new file mode 100644 index 0000000000000000000000000000000000000000..df8c9232e56d380923af5c5612e997d11a851468 --- /dev/null +++ b/sd-webui-cutoff/scripts/cutofflib/embedding.py @@ -0,0 +1,214 @@ +from dataclasses import dataclass +from itertools import product +import re +from typing import Union, List, Tuple +import numpy as np +import open_clip +from modules.sd_hijack_clip import FrozenCLIPEmbedderWithCustomWordsBase as CLIP +from modules import prompt_parser, shared +from scripts.cutofflib.utils import log + +class ClipWrapper: + def __init__(self, te: CLIP): + self.te = te + self.v1 = hasattr(te.wrapped, 'tokenizer') + self.t = ( + te.wrapped.tokenizer if self.v1 + else open_clip.tokenizer._tokenizer + ) + + def token_to_id(self, token: str) -> int: + if self.v1: + return self.t._convert_token_to_id(token) # type: ignore + else: + return self.t.encoder[token] + + def id_to_token(self, id: int) -> str: + if self.v1: + return self.t.convert_ids_to_tokens(id) # type: ignore + else: + return self.t.decoder[id] + + def ids_to_tokens(self, ids: List[int]) -> List[str]: + if self.v1: + return self.t.convert_ids_to_tokens(ids) # type: ignore + else: + return [self.t.decoder[id] for id in ids] + + def token(self, token: Union[int,str]): + if isinstance(token, int): + return Token(token, self.id_to_token(token)) + else: + return Token(self.token_to_id(token), token) + + +@dataclass +class Token: + id: int + token: str + +class CutoffPrompt: + + @staticmethod + def _cutoff(prompt: str, clip: CLIP, tokens: List[str], padding: str): + def token_count(text: str): + tt = token_to_block(clip, text) + # tt[0] == clip.id_start (<|startoftext|>) + for index, (t, _) in enumerate(tt): + if t.id == clip.id_end: # <|endoftext|> + return index - 1 + return 0 # must not happen... + + re_targets = [ re.compile(r'\b' + re.escape(x) + r'\b') for x in tokens ] + replacer = [ ' ' + ' '.join([padding] * token_count(x)) + ' ' for x in tokens ] + + rows: List[Tuple[str,str]] = [] + for block in prompt.split(','): + b0 = block + for r, p in zip(re_targets, replacer): + block = r.sub(p, block) + b1 = block + rows.append((b0, b1)) + + return rows + + def __init__(self, prompt: str, clip: CLIP, tokens: List[str], padding: str): + self.prompt = prompt + rows = CutoffPrompt._cutoff(prompt, clip, tokens, padding) + self.base = np.array([x[0] for x in rows]) + self.cut = np.array([x[1] for x in rows]) + self.sw = np.array([False] * len(rows)) + + @property + def block_count(self): + return self.base.shape[0] + + def switch(self, block_index: int, to: Union[bool,None] = None): + if to is None: + to = not self.sw[block_index] + self.sw[block_index] = to + return to + + def text(self, sw=None): + if sw is None: + sw = self.sw + blocks = np.where(sw, self.cut, self.base) + return ','.join(blocks) + + def active_blocks(self) -> np.ndarray: + indices, = (self.base != self.cut).nonzero() + return indices + + def generate(self): + indices = self.active_blocks() + for diff_sw in product([False, True], repeat=indices.shape[0]): + sw = np.full_like(self.sw, False) + sw[indices] = diff_sw + yield diff_sw, self.text(sw) + + +def generate_prompts( + clip: CLIP, + prompt: str, + targets: List[str], + padding: Union[str,int,Token], +) -> CutoffPrompt: + + te = ClipWrapper(clip) + + if not isinstance(padding, Token): + o_pad = padding + padding = te.token(padding) + if padding.id == clip.id_end: + raise ValueError(f'`{o_pad}` is not a valid token.') + + result = CutoffPrompt(prompt, clip, targets, padding.token.replace('', '')) + + log(f'[Cutoff] replace: {", ".join(targets)}') + log(f'[Cutoff] to: {padding.token} ({padding.id})') + log(f'[Cutoff] original: {prompt}') + for i, (_, pp) in enumerate(result.generate()): + log(f'[Cutoff] #{i}: {pp}') + + return result + + +def token_to_block(clip: CLIP, prompt: str): + te = ClipWrapper(clip) + + # cf. sd_hijack_clip.py + + parsed = prompt_parser.parse_prompt_attention(prompt) + tokenized: List[List[int]] = clip.tokenize([text for text, _ in parsed]) + + CHUNK_LENGTH = 75 + id_start = te.token(clip.id_start) # type: ignore + id_end = te.token(clip.id_end) # type: ignore + comma = te.token(',') + + last_comma = -1 + current_block = 0 + current_tokens: List[Tuple[Token,int]] = [] + result: List[Tuple[Token,int]] = [] + + def next_chunk(): + nonlocal current_tokens, last_comma + + to_add = CHUNK_LENGTH - len(current_tokens) + if 0 < to_add: + current_tokens += [(id_end, -1)] * to_add + + current_tokens = [(id_start, -1)] + current_tokens + [(id_end, -1)] + + last_comma = -1 + result.extend(current_tokens) + current_tokens = [] + + for tokens, (text, weight) in zip(tokenized, parsed): + if text == 'BREAK' and weight == -1: + next_chunk() + continue + + p = 0 + while p < len(tokens): + token = tokens[p] + + if token == comma.id: + last_comma = len(current_tokens) + current_block += 1 + + elif ( + shared.opts.comma_padding_backtrack != 0 + and len(current_tokens) == CHUNK_LENGTH + and last_comma != -1 + and len(current_tokens) - last_comma <= shared.opts.comma_padding_backtrack + ): + break_location = last_comma + 1 + reloc_tokens = current_tokens[break_location:] + current_tokens = current_tokens[:break_location] + next_chunk() + current_tokens = reloc_tokens + + if len(current_tokens) == CHUNK_LENGTH: + next_chunk() + + embedding, embedding_length_in_tokens = clip.hijack.embedding_db.find_embedding_at_position(tokens, p) + if embedding is None: + if token == comma.id: + current_tokens.append((te.token(token), -1)) + else: + current_tokens.append((te.token(token), current_block)) + p += 1 + continue + + emb_len = int(embedding.vec.shape[0]) + if len(current_tokens) + emb_len > CHUNK_LENGTH: + next_chunk() + + current_tokens += [(te.token(0), current_block)] * emb_len + p += embedding_length_in_tokens + + if len(current_tokens) > 0: + next_chunk() + + return result diff --git a/sd-webui-cutoff/scripts/cutofflib/sdhook.py b/sd-webui-cutoff/scripts/cutofflib/sdhook.py new file mode 100644 index 0000000000000000000000000000000000000000..5be791c596e907ae835e41e337c919d96502e613 --- /dev/null +++ b/sd-webui-cutoff/scripts/cutofflib/sdhook.py @@ -0,0 +1,275 @@ +import sys +from typing import Any, Callable, Union + +from torch import nn +from torch.utils.hooks import RemovableHandle + +from ldm.modules.diffusionmodules.openaimodel import ( + TimestepEmbedSequential, +) +from ldm.modules.attention import ( + SpatialTransformer, + BasicTransformerBlock, + CrossAttention, + MemoryEfficientCrossAttention, +) +from ldm.modules.diffusionmodules.openaimodel import ( + ResBlock, +) +from modules.processing import StableDiffusionProcessing +from modules import shared + +class ForwardHook: + + def __init__(self, module: nn.Module, fn: Callable[[nn.Module, Callable[..., Any], Any], Any]): + self.o = module.forward + self.fn = fn + self.module = module + self.module.forward = self.forward + + def remove(self): + if self.module is not None and self.o is not None: + self.module.forward = self.o + self.module = None + self.o = None + self.fn = None + + def forward(self, *args, **kwargs): + if self.module is not None and self.o is not None: + if self.fn is not None: + return self.fn(self.module, self.o, *args, **kwargs) + return None + + +class SDHook: + + def __init__(self, enabled: bool): + self._enabled = enabled + self._handles: list[Union[RemovableHandle,ForwardHook]] = [] + + @property + def enabled(self): + return self._enabled + + @property + def batch_num(self): + return shared.state.job_no + + @property + def step_num(self): + return shared.state.current_image_sampling_step + + def __enter__(self): + if self.enabled: + pass + + def __exit__(self, exc_type, exc_value, traceback): + if self.enabled: + for handle in self._handles: + handle.remove() + self._handles.clear() + self.dispose() + + def dispose(self): + pass + + def setup( + self, + p: StableDiffusionProcessing + ): + if not self.enabled: + return + + wrapper = getattr(p.sd_model, "model", None) + + unet: Union[nn.Module,None] = getattr(wrapper, "diffusion_model", None) if wrapper is not None else None + vae: Union[nn.Module,None] = getattr(p.sd_model, "first_stage_model", None) + clip: Union[nn.Module,None] = getattr(p.sd_model, "cond_stage_model", None) + + assert unet is not None, "p.sd_model.diffusion_model is not found. broken model???" + self._do_hook(p, p.sd_model, unet=unet, vae=vae, clip=clip) # type: ignore + self.on_setup() + + def on_setup(self): + pass + + def _do_hook( + self, + p: StableDiffusionProcessing, + model: Any, + unet: Union[nn.Module,None], + vae: Union[nn.Module,None], + clip: Union[nn.Module,None] + ): + assert model is not None, "empty model???" + + if clip is not None: + self.hook_clip(p, clip) + + if unet is not None: + self.hook_unet(p, unet) + + if vae is not None: + self.hook_vae(p, vae) + + def hook_vae( + self, + p: StableDiffusionProcessing, + vae: nn.Module + ): + pass + + def hook_unet( + self, + p: StableDiffusionProcessing, + unet: nn.Module + ): + pass + + def hook_clip( + self, + p: StableDiffusionProcessing, + clip: nn.Module + ): + pass + + def hook_layer( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, tuple, Any], Any] + ): + if not self.enabled: + return + + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(module.register_forward_hook(fn)) + + def hook_layer_pre( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, tuple], Any] + ): + if not self.enabled: + return + + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(module.register_forward_pre_hook(fn)) + + def hook_forward( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, Callable[..., Any], Any], Any] + ): + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(ForwardHook(module, fn)) + + def log(self, msg: str): + print(msg, file=sys.stderr) + + +# enumerate SpatialTransformer in TimestepEmbedSequential +def each_transformer(unet_block: TimestepEmbedSequential): + for block in unet_block.children(): + if isinstance(block, SpatialTransformer): + yield block + +# enumerate BasicTransformerBlock in SpatialTransformer +def each_basic_block(trans: SpatialTransformer): + for block in trans.transformer_blocks.children(): + if isinstance(block, BasicTransformerBlock): + yield block + +# enumerate Attention Layers in TimestepEmbedSequential +# each_transformer + each_basic_block +def each_attns(unet_block: TimestepEmbedSequential): + for n, trans in enumerate(each_transformer(unet_block)): + for depth, basic_block in enumerate(each_basic_block(trans)): + # attn1: Union[CrossAttention,MemoryEfficientCrossAttention] + # attn2: Union[CrossAttention,MemoryEfficientCrossAttention] + + attn1, attn2 = basic_block.attn1, basic_block.attn2 + assert isinstance(attn1, CrossAttention) or isinstance(attn1, MemoryEfficientCrossAttention) + assert isinstance(attn2, CrossAttention) or isinstance(attn2, MemoryEfficientCrossAttention) + + yield n, depth, attn1, attn2 + +def each_unet_attn_layers(unet: nn.Module): + def get_attns(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, d, attn1, attn2 in each_attns(block): + kwargs = { + 'layer_index': layer_index, + 'trans_index': n, + 'block_index': d + } + yield format.format(attn_name='sattn', **kwargs), attn1 + yield format.format(attn_name='xattn', **kwargs), attn2 + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_attns(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + yield from get_attns(0, middle, 'M{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + + +def each_unet_transformers(unet: nn.Module): + def get_trans(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, trans in enumerate(each_transformer(block)): + kwargs = { + 'layer_index': layer_index, + 'block_index': n, + 'block_name': 'trans', + } + yield format.format(**kwargs), trans + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_trans(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{block_index:02}_{block_name}') + yield from get_trans(0, middle, 'M{layer_index:02}_{block_index:02}_{block_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{block_index:02}_{block_name}') + + +def each_resblock(unet_block: TimestepEmbedSequential): + for block in unet_block.children(): + if isinstance(block, ResBlock): + yield block + +def each_unet_resblock(unet: nn.Module): + def get_resblock(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, res in enumerate(each_resblock(block)): + kwargs = { + 'layer_index': layer_index, + 'block_index': n, + 'block_name': 'resblock', + } + yield format.format(**kwargs), res + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_resblock(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{block_index:02}_{block_name}') + yield from get_resblock(0, middle, 'M{layer_index:02}_{block_index:02}_{block_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{block_index:02}_{block_name}') + diff --git a/sd-webui-cutoff/scripts/cutofflib/utils.py b/sd-webui-cutoff/scripts/cutofflib/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..8a2962521792409bb4f154d343db132928a9343d --- /dev/null +++ b/sd-webui-cutoff/scripts/cutofflib/utils.py @@ -0,0 +1,11 @@ +import sys + +_debug = False + +def set_debug(is_debug: bool): + global _debug + _debug = is_debug + +def log(s: str): + if _debug: + print(s, file=sys.stderr) diff --git a/sd-webui-cutoff/scripts/cutofflib/xyz.py b/sd-webui-cutoff/scripts/cutofflib/xyz.py new file mode 100644 index 0000000000000000000000000000000000000000..19f3217fd5c09b2ce784a975e1f4e664f1d6bc44 --- /dev/null +++ b/sd-webui-cutoff/scripts/cutofflib/xyz.py @@ -0,0 +1,126 @@ +import os +from typing import Union, List, Callable + +from modules import scripts +from modules.processing import StableDiffusionProcessing, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img + + +def __set_value(p: StableDiffusionProcessing, script: type, index: int, value): + args = list(p.script_args) + + if isinstance(p, StableDiffusionProcessingTxt2Img): + all_scripts = scripts.scripts_txt2img.scripts + else: + all_scripts = scripts.scripts_img2img.scripts + + froms = [x.args_from for x in all_scripts if isinstance(x, script)] + for idx in froms: + assert idx is not None + args[idx + index] = value + + p.script_args = type(p.script_args)(args) + + +def to_bool(v: str): + if len(v) == 0: return False + v = v.lower() + if 'true' in v: return True + if 'false' in v: return False + + try: + w = int(v) + return bool(w) + except: + acceptable = ['True', 'False', '1', '0'] + s = ', '.join([f'`{v}`' for v in acceptable]) + raise ValueError(f'value must be one of {s}.') + + +class AxisOptions: + + def __init__(self, AxisOption: type, axis_options: list): + self.AxisOption = AxisOption + self.target = axis_options + self.options = [] + + def __enter__(self): + self.options.clear() + return self + + def __exit__(self, ex_type, ex_value, trace): + if ex_type is not None: + return + + for opt in self.options: + self.target.append(opt) + + self.options.clear() + + def create(self, name: str, type_fn: Callable, action: Callable, choices: Union[List[str],None]): + if choices is None or len(choices) == 0: + opt = self.AxisOption(name, type_fn, action) + else: + opt = self.AxisOption(name, type_fn, action, choices=lambda: choices) + return opt + + def add(self, axis_option): + self.target.append(axis_option) + + +__init = False + +def init_xyz(script: type, ext_name: str): + global __init + + if __init: + return + + for data in scripts.scripts_data: + name = os.path.basename(data.path) + if name != 'xy_grid.py' and name != 'xyz_grid.py': + continue + + if not hasattr(data.module, 'AxisOption'): + continue + + if not hasattr(data.module, 'axis_options'): + continue + + AxisOption = data.module.AxisOption + axis_options = data.module.axis_options + + if not isinstance(AxisOption, type): + continue + + if not isinstance(axis_options, list): + continue + + try: + create_options(ext_name, script, AxisOption, axis_options) + except: + pass + + __init = True + + +def create_options(ext_name: str, script: type, AxisOptionClass: type, axis_options: list): + with AxisOptions(AxisOptionClass, axis_options) as opts: + def define(param: str, index: int, type_fn: Callable, choices: List[str] = []): + def fn(p, x, xs): + __set_value(p, script, index, x) + + name = f'{ext_name} {param}' + return opts.create(name, type_fn, fn, choices) + + options = [ + define('Enabled', 0, to_bool, choices=['false', 'true']), + define('Targets', 1, str), + define('Weight', 2, float), + define('Disable for Negative Prompt', 3, to_bool, choices=['false', 'true']), + define('Strong', 4, to_bool, choices=['false', 'true']), + define('Padding', 5, str), + define('Interpolation', 6, str, choices=['Lerp', 'SLerp']), + ] + + for opt in options: + opts.add(opt) diff --git a/sd-webui-llul/.gitignore b/sd-webui-llul/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9f94e5dd988b2944cb27eeaa23ca1cf68e869d8c --- /dev/null +++ b/sd-webui-llul/.gitignore @@ -0,0 +1,2 @@ +.vscode +__pycache__ diff --git a/sd-webui-llul/LICENSE b/sd-webui-llul/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d1e1072ee5e1d109c15b6fd18756aedc2a401840 --- /dev/null +++ b/sd-webui-llul/LICENSE @@ -0,0 +1 @@ +MIT License diff --git a/sd-webui-llul/README.md b/sd-webui-llul/README.md new file mode 100644 index 0000000000000000000000000000000000000000..165698dcdb2b2ced0ed8ebef3f49e84823f99996 --- /dev/null +++ b/sd-webui-llul/README.md @@ -0,0 +1,43 @@ +# LLuL - Local Latent upscaLer + +![cover](./images/cover.jpg) + +https://user-images.githubusercontent.com/120772120/221390831-9fbccdf8-5898-4515-b988-d6733e8af3f1.mp4 + +## What is this? + +This is an extension for [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) which lets you to upscale latents locally. + +See above image. This is all what this extension does. + +## Usage + +1. Select `Enabled` checkbox. +2. Move gray box where you want to apply upscaling. +3. Generate image. + +## Examples + +![sample 2](./images/sample1.jpg) + +![sample 3](./images/sample2.jpg) + +![sample 4](./images/sample3.jpg) + +![sample 5](./images/sample4.jpg) + +- Weight 0.00 -> 0.20 Animation + +https://user-images.githubusercontent.com/120772120/221390834-7e2c1a1a-d7a6-46b0-8949-83c4d5839c33.mp4 + +## Mask + +The mask is now available. + +Each pixel values of the mask are treated as the scale factors of the interpolation weight. White is 1.0 (enabled), black is 0.0 (disabled) and gray reduces the weights. + +![mask sample](./images/mask_effect.jpg) + +## How it works + +![description of process](./images/desc.png) diff --git a/sd-webui-llul/images/cover.jpg b/sd-webui-llul/images/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e13d93d6984aa153412ff2e8bbfdd6326893726 Binary files /dev/null and b/sd-webui-llul/images/cover.jpg differ diff --git a/sd-webui-llul/images/cover.mp4 b/sd-webui-llul/images/cover.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..39fec8b725874eb3275935316c9dda7e469b41cc Binary files /dev/null and b/sd-webui-llul/images/cover.mp4 differ diff --git a/sd-webui-llul/images/cover_yuv420p.mp4 b/sd-webui-llul/images/cover_yuv420p.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..43f5f7718f90e4e55f7f5cd245e80610405912bd Binary files /dev/null and b/sd-webui-llul/images/cover_yuv420p.mp4 differ diff --git a/sd-webui-llul/images/desc.png b/sd-webui-llul/images/desc.png new file mode 100644 index 0000000000000000000000000000000000000000..c827387deef8067d76629f380018b4cccc3b2fc3 Binary files /dev/null and b/sd-webui-llul/images/desc.png differ diff --git a/sd-webui-llul/images/llul.mp4 b/sd-webui-llul/images/llul.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..b344c4a94dd832886ec4de44738343059227ad88 Binary files /dev/null and b/sd-webui-llul/images/llul.mp4 differ diff --git a/sd-webui-llul/images/llul_yuv420p.mp4 b/sd-webui-llul/images/llul_yuv420p.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..30893a1dc0676b83572946f4cd711f533908a20f --- /dev/null +++ b/sd-webui-llul/images/llul_yuv420p.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69b7ac823e0f0e5759886137708ab7cc62521baa2d9917f5c9a551fded46ac5e +size 1341189 diff --git a/sd-webui-llul/images/mask_effect.jpg b/sd-webui-llul/images/mask_effect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d7232768bebc576d77524be16632d611e830680 --- /dev/null +++ b/sd-webui-llul/images/mask_effect.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e4b6d4218a38fadeb7d2fa3502f247804b3dc2ffb344e6d9506f2107aa62c5c +size 1098988 diff --git a/sd-webui-llul/images/sample1.jpg b/sd-webui-llul/images/sample1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcfab5b07db02f77c8bb660c6b3bc40a8cd89eba Binary files /dev/null and b/sd-webui-llul/images/sample1.jpg differ diff --git a/sd-webui-llul/images/sample2.jpg b/sd-webui-llul/images/sample2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..34fed788497190604fdb28cd9ce16af5b2af0a41 Binary files /dev/null and b/sd-webui-llul/images/sample2.jpg differ diff --git a/sd-webui-llul/images/sample3.jpg b/sd-webui-llul/images/sample3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b7b173006ec6336d623adf01e3c2c4472ca4a21 Binary files /dev/null and b/sd-webui-llul/images/sample3.jpg differ diff --git a/sd-webui-llul/images/sample4.jpg b/sd-webui-llul/images/sample4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60657fc1bfb160c578d8a5ce629940324e31b638 Binary files /dev/null and b/sd-webui-llul/images/sample4.jpg differ diff --git a/sd-webui-llul/javascript/llul.js b/sd-webui-llul/javascript/llul.js new file mode 100644 index 0000000000000000000000000000000000000000..fa76503b935e0141f61a8897ca000c7104a56899 --- /dev/null +++ b/sd-webui-llul/javascript/llul.js @@ -0,0 +1,285 @@ +(function () { + + if (!globalThis.LLuL) globalThis.LLuL = {}; + const LLuL = globalThis.LLuL; + + function id(type, s) { + return `llul-${type}-${s}`; + } + + function isDark() { + return gradioApp().querySelector('.dark') !== null; + } + + const M = 2; + function setSize(canvas, width, height) { + width = Math.floor(+width / M); + height = Math.floor(+height / M); + if (canvas.width != width) canvas.width = width; + if (canvas.height != height) canvas.height = height; + } + + function updateXY(canvas) { + let x = +canvas.dataset.x, + y = +canvas.dataset.y, + m = +canvas.dataset.m, + mm = Math.pow(2, m), + w = +canvas.width * M, + h = +canvas.height * M; + if (x < 0) x = 0; + if (w < x + w / mm) x = Math.floor(w - w / mm); + if (y < 0) y = 0; + if (h < y + h / mm) y = Math.floor(h - h / mm); + + canvas.dataset.x = x; + canvas.dataset.y = y; + canvas.dataset.m = m; + + canvas.parentNode.querySelector('.llul-pos-x').value = x; + canvas.parentNode.querySelector('.llul-pos-y').value = y; + } + + let last_image = new Image(); + let hide_image = true; + async function draw(canvas) { + const + x = +canvas.dataset.x, + y = +canvas.dataset.y, + m = +canvas.dataset.m, + mm = Math.pow(2, m), + w = +canvas.width, + h = +canvas.height, + bg = canvas.dataset.bg; + + const ctx = canvas.getContext('2d'); + + if (bg) { + if (last_image?.src === bg) { + // do nothing + } else { + await (new Promise(resolve => { + last_image.onload = () => resolve(); + last_image.src = bg; + })); + } + hide_image = false; + } else { + last_image.src = ''; + hide_image = true; + } + + if (last_image.src && !hide_image) { + ctx.drawImage(last_image, 0, 0, +last_image.width, +last_image.height, 0, 0, +canvas.width, +canvas.height); + } else { + const bgcolor = isDark() ? 'black' : 'white'; + ctx.fillStyle = bgcolor; + ctx.fillRect(0, 0, +canvas.width, +canvas.height); + } + + ctx.fillStyle = 'gray'; + ctx.fillRect(x / M, y / M, Math.floor(w / mm), Math.floor(h / mm)); + } + + async function update_gradio(type, canvas) { + await LLuL.js2py(type, 'x', +canvas.dataset.x); + await LLuL.js2py(type, 'y', +canvas.dataset.y); + } + + function init(type) { + const $ = x => Array.from(gradioApp().querySelectorAll(x)).at(-1); + const cont = $('#' + id(type, 'container')); + const x = $('#' + id(type, 'x')); + const y = $('#' + id(type, 'y')); + const m = $(`#${id(type, 'm')} input[type=number]`); + const ms = $(`#${id(type, 'm')} input[type=range]`); + if (!cont || !x || !y || !m || !ms) return false; + + if (cont.querySelector('canvas')) return true; // already called + + const width = $(`#${type}_width input[type=number]`); + const height = $(`#${type}_height input[type=number]`); + const width2 = $(`#${type}_width input[type=range]`); + const height2 = $(`#${type}_height input[type=range]`); + + const pos_x = Math.floor(+width.value / 4); + const pos_y = Math.floor(+height.value / 4); + + const pos_cont = document.createElement('div'); + pos_cont.innerHTML = ` +
+ + +
+ `; + + const canvas = document.createElement('canvas'); + canvas.style.border = '1px solid gray'; + canvas.dataset.x = pos_x; + canvas.dataset.y = pos_y; + canvas.dataset.m = m.value; + + const bg_cont = document.createElement('div'); + bg_cont.classList.add('llul-bg-setting'); + bg_cont.innerHTML = ` +Load BG +Erase BG + + `; + + for (let ele of [width, height, width2, height2, m, ms]) { + ele.addEventListener('input', e => { + canvas.dataset.m = +m.value; + setSize(canvas, width.value, height.value); + updateXY(canvas); + draw(canvas); + }); + } + + // + // Event Listeners + // + + // canvas + + let dragging = false; + let last_x, last_y; + canvas.addEventListener('pointerdown', e => { + e.preventDefault(); + dragging = true; + last_x = e.offsetX; + last_y = e.offsetY; + }); + canvas.addEventListener('pointerup', async e => { + e.preventDefault(); + dragging = false; + await update_gradio(type, canvas); + }); + canvas.addEventListener('pointermove', e => { + if (!dragging) return; + const dx = e.offsetX - last_x, dy = e.offsetY - last_y; + const x = +canvas.dataset.x, y = +canvas.dataset.y; + canvas.dataset.x = x + dx * M; + canvas.dataset.y = y + dy * M; + last_x = e.offsetX; + last_y = e.offsetY; + updateXY(canvas); + draw(canvas); + }); + + // bg_cont + + function set_bg(url) { + canvas.dataset.bg = url; + draw(canvas); + } + bg_cont.querySelector('input[type=file]').addEventListener('change', e => { + const ele = e.target; + const files = ele.files; + if (files.length != 0) { + const file = files[0]; + const r = new FileReader(); + r.onload = () => set_bg(r.result); + r.readAsDataURL(file); + } + ele.value = ''; + }, false); + bg_cont.addEventListener('click', e => { + const ele = e.target; + if (ele.textContent == 'Load BG') { + bg_cont.querySelector('input[type=file]').click(); + } else if (ele.textContent == 'Erase BG') { + set_bg(''); + } + }); + + // pos_cont + + pos_cont.addEventListener('input', e => { + const ele = e.target; + let x = +canvas.dataset.x; + let y = +canvas.dataset.y; + if (ele.classList.contains(`llul-pos-x`)) { + x = +ele.value; + } else if (ele.classList.contains(`llul-pos-y`)) { + y = +ele.value; + } else { + return; + } + canvas.dataset.x = x; + canvas.dataset.y = y; + updateXY(canvas); + draw(canvas); + update_gradio(type, canvas); + }); + + cont.appendChild(pos_cont); + cont.appendChild(canvas); + cont.appendChild(bg_cont); + setSize(canvas, width.value, height.value); + updateXY(canvas); + draw(canvas); + + return true; + } + + function init2(type, init_fn) { + const get_acc = new Promise(resolve => { + (function try_get_acc() { + const acc = gradioApp().querySelector('#' + id(type, 'accordion')); + if (acc) { + resolve(acc); + } else { + setTimeout(try_get_acc, 500); + } + })(); + }); + + return get_acc.then(acc => { + const observer = new MutationObserver((list, observer) => { + for (let mut of list) { + //console.log(mut.type); + if (mut.type === 'childList') { + //console.log(mut.addedNodes); + //console.log(mut.removedNodes); + if (mut.addedNodes.length != 0) { + // closed -> opened + init_fn(type); + } else { + // opened -> closed + // do nothing + } + } + } + }); + observer.observe(acc, { childList: true, attributes: false, subtree: false }); + }); + } + + function init_LLuL() { + if (!LLuL.txt2img) { + LLuL.txt2img = init2('txt2img', init); + if (LLuL.txt2img) { + LLuL.txt2img.then(() => console.log('[LLuL] txt2img initialized')); + } + } + + if (!LLuL.img2img) { + LLuL.img2img = init2('img2img', init); + if (LLuL.img2img) { + LLuL.img2img.then(() => console.log('[LLuL] img2img initialized')); + } + } + + return LLuL.txt2img && LLuL.img2img; + } + + function apply() { + const ok = init_LLuL(); + if (!ok) { + setTimeout(apply, 500); + } + } + + apply(); + +})(); diff --git a/sd-webui-llul/javascript/uti.js b/sd-webui-llul/javascript/uti.js new file mode 100644 index 0000000000000000000000000000000000000000..34c9828901a05633ddd12a2a702dbac05393bf0c --- /dev/null +++ b/sd-webui-llul/javascript/uti.js @@ -0,0 +1,70 @@ +(function() { + + if (!globalThis.LLuL) globalThis.LLuL = {}; + + const OBJ = (function (NAME) { + + let _r = 0; + function to_gradio(v) { + // force call `change` event on gradio + return [v.toString(), (_r++).toString()]; + } + + function js2py(type, gradio_field, value) { + // set `value` to gradio's field + // (1) Click gradio's button. + // (2) Gradio will fire js callback to retrieve value to be set. + // (3) Gradio will fire another js callback to notify the process has been completed. + return new Promise(resolve => { + const callback_name = `${NAME}-${type}-${gradio_field}`; + + // (2) + globalThis[callback_name] = () => { + + delete globalThis[callback_name]; + + // (3) + const callback_after = callback_name + '_after'; + globalThis[callback_after] = () => { + delete globalThis[callback_after]; + resolve(); + }; + + return to_gradio(value); + }; + + // (1) + gradioApp().querySelector(`#${callback_name}_set`).click(); + }); + } + + function py2js(type, pyname, ...args) { + // call python's function + // (1) Set args to gradio's field + // (2) Click gradio's button + // (3) JS callback will be kicked with return value from gradio + + // (1) + return (args.length == 0 ? Promise.resolve() : js2py(type, pyname + '_args', JSON.stringify(args))) + .then(() => { + return new Promise(resolve => { + const callback_name = `${NAME}-${type}-${pyname}`; + // (3) + globalThis[callback_name] = value => { + delete globalThis[callback_name]; + resolve(value); + } + // (2) + gradioApp().querySelector(`#${callback_name}_get`).click(); + }); + }); + } + + return { js2py, py2js } + + })('llul'); + + if (!globalThis.LLuL.js2py) globalThis.LLuL.js2py = OBJ.js2py; + if (!globalThis.LLuL.py2js) globalThis.LLuL.py2js = OBJ.py2js; + +})(); \ No newline at end of file diff --git a/sd-webui-llul/scripts/__pycache__/llul.cpython-310.pyc b/sd-webui-llul/scripts/__pycache__/llul.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65e3cc728625709aef2d5f78bf8d3879cb349cdc Binary files /dev/null and b/sd-webui-llul/scripts/__pycache__/llul.cpython-310.pyc differ diff --git a/sd-webui-llul/scripts/__pycache__/llul_hooker.cpython-310.pyc b/sd-webui-llul/scripts/__pycache__/llul_hooker.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d07e63b66dde22a825b13a19af90fb7c25ceff44 Binary files /dev/null and b/sd-webui-llul/scripts/__pycache__/llul_hooker.cpython-310.pyc differ diff --git a/sd-webui-llul/scripts/__pycache__/llul_xyz.cpython-310.pyc b/sd-webui-llul/scripts/__pycache__/llul_xyz.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..190019bff5433bed72f8165e2c141e76a96df21e Binary files /dev/null and b/sd-webui-llul/scripts/__pycache__/llul_xyz.cpython-310.pyc differ diff --git a/sd-webui-llul/scripts/__pycache__/sdhook.cpython-310.pyc b/sd-webui-llul/scripts/__pycache__/sdhook.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb5a11ebd59b461523e0a0113b68bbd23003453a Binary files /dev/null and b/sd-webui-llul/scripts/__pycache__/sdhook.cpython-310.pyc differ diff --git a/sd-webui-llul/scripts/llul.py b/sd-webui-llul/scripts/llul.py new file mode 100644 index 0000000000000000000000000000000000000000..cc84f2526a64436282416b0a35cb8e6c3c9040ca --- /dev/null +++ b/sd-webui-llul/scripts/llul.py @@ -0,0 +1,289 @@ +import tempfile +from typing import Union, List, Callable + +import torch +import torchvision.transforms.functional +from PIL import Image +import gradio as gr + +from modules.processing import StableDiffusionProcessing, Processed +from modules import scripts + +from scripts.llul_hooker import Hooker, Upscaler, Downscaler +from scripts.llul_xyz import init_xyz + +NAME = 'LLuL' + +class Script(scripts.Script): + + def __init__(self): + super().__init__() + self.last_hooker: Union[Hooker,None] = None + + def title(self): + return NAME + + def show(self, is_img2img): + return scripts.AlwaysVisible + + def ui(self, is_img2img): + mode = 'img2img' if is_img2img else 'txt2img' + id = lambda x: f'{NAME.lower()}-{mode}-{x}' + js = lambda s: f'globalThis["{id(s)}"]' + + with gr.Group(): + with gr.Accordion(NAME, open=False, elem_id=id('accordion')): + enabled = gr.Checkbox(label='Enabled', value=False) + with gr.Row(): + weight = gr.Slider(minimum=-1, maximum=2, value=0.15, step=0.01, label='Weight') + multiply = gr.Slider(value=1, minimum=1, maximum=5, step=1, label='Multiplication (2^N)', elem_id=id('m')) + gr.HTML(elem_id=id('container')) + add_area_image = gr.Checkbox(value=True, label='Add the effective area to output images.') + + with gr.Row(): + use_mask = gr.Checkbox(value=False, label='Enable mask which scales the weight (black = 0.0, white = 1.0)') + mask = gr.File(interactive=True, label='Upload mask image', elem_id=id('mask')) + + force_float = gr.Checkbox(label='Force convert half to float on interpolation (for some platforms)', value=False) + understand = gr.Checkbox(label='I know what I am doing.', value=False) + with gr.Column(visible=False) as g: + layers = gr.Textbox(label='Layers', value='OUT') + apply_to = gr.CheckboxGroup(choices=['Resblock', 'Transformer', 'S. Attn.', 'X. Attn.', 'OUT'], value=['OUT'], label='Apply to') + start_steps = gr.Slider(minimum=1, maximum=300, value=5, step=1, label='Start steps') + max_steps = gr.Slider(minimum=0, maximum=300, value=0, step=1, label='Max steps') + with gr.Row(): + up = gr.Radio(choices=['Nearest', 'Bilinear', 'Bicubic'], value='Bilinear', label='Upscaling') + up_aa = gr.Checkbox(value=False, label='Enable AA for Upscaling.') + with gr.Row(): + down = gr.Radio(choices=['Nearest', 'Bilinear', 'Bicubic', 'Area', 'Pooling Max', 'Pooling Avg'], value='Bilinear', label='Downscaling') + down_aa = gr.Checkbox(value=False, label='Enable AA for Downscaling.') + intp = gr.Radio(choices=['Lerp', 'SLerp'], value='Lerp', label='interpolation method') + + understand.change( + lambda b: { g: gr.update(visible=b) }, + inputs=[understand], + outputs=[ + g # type: ignore + ] + ) + + with gr.Row(visible=False): + sink = gr.HTML(value='') # to suppress error in javascript + x = js2py('x', id, js, sink) + y = js2py('y', id, js, sink) + + return [ + enabled, + multiply, + weight, + understand, + layers, + apply_to, + start_steps, + max_steps, + up, + up_aa, + down, + down_aa, + intp, + x, + y, + force_float, + use_mask, + mask, + add_area_image, + ] + + def process( + self, + p: StableDiffusionProcessing, + enabled: bool, + multiply: Union[int,float], + weight: float, + understand: bool, + layers: str, + apply_to: Union[List[str],str], + start_steps: Union[int,float], + max_steps: Union[int,float], + up: str, + up_aa: bool, + down: str, + down_aa: bool, + intp: str, + x: Union[str,None] = None, + y: Union[str,None] = None, + force_float = False, + use_mask: bool = False, + mask: Union[tempfile._TemporaryFileWrapper,None] = None, + add_area_image: bool = True, # for postprocess + ): + if self.last_hooker is not None: + self.last_hooker.__exit__(None, None, None) + self.last_hooker = None + + if not enabled: + return + + if p.width < 128 or p.height < 128: + raise ValueError(f'Image size is too small to LLuL: {p.width}x{p.height}; expected >=128x128.') + + multiply = 2 ** int(max(multiply, 0)) + weight = float(weight) + if x is None or len(x) == 0: + x = str((p.width - p.width // multiply) // 2) + if y is None or len(y) == 0: + y = str((p.height - p.height // multiply) // 2) + + if understand: + lays = ( + None if len(layers) == 0 else + [x.strip() for x in layers.split(',')] + ) + if isinstance(apply_to, str): + apply_to = [x.strip() for x in apply_to.split(',')] + apply_to = [x.lower() for x in apply_to] + start_steps = max(1, int(start_steps)) + max_steps = max(1, [p.steps, int(max_steps)][1 <= max_steps]) + up_fn = Upscaler(up, up_aa) + down_fn = Downscaler(down, down_aa) + intp = intp.lower() + else: + lays = ['OUT'] + apply_to = ['out'] + start_steps = 5 + max_steps = int(p.steps) + up_fn = Upscaler('bilinear', aa=False) + down_fn = Downscaler('bilinear', aa=False) + intp = 'lerp' + + xf = float(x) + yf = float(y) + + mask_image = None + if use_mask and mask is not None: + # Can I read from passed tempfile._TemporaryFileWrapper??? + mask_image = Image.open(mask.name).convert('L') + intp = 'lerp' + + self.last_hooker = Hooker( + enabled=True, + multiply=int(multiply), + weight=weight, + layers=lays, + apply_to=apply_to, + start_steps=start_steps, + max_steps=max_steps, + up_fn=up_fn, + down_fn=down_fn, + intp=intp, + x=xf/p.width, + y=yf/p.height, + force_float=force_float, + mask_image=mask_image, + ) + + self.last_hooker.setup(p) + self.last_hooker.__enter__() + + p.extra_generation_params.update({ + f'{NAME} Enabled': enabled, + f'{NAME} Multiply': multiply, + f'{NAME} Weight': weight, + f'{NAME} Layers': lays, + f'{NAME} Apply to': apply_to, + f'{NAME} Start steps': start_steps, + f'{NAME} Max steps': max_steps, + f'{NAME} Upscaler': up_fn.name, + f'{NAME} Downscaler': down_fn.name, + f'{NAME} Interpolation': intp, + f'{NAME} x': x, + f'{NAME} y': y, + }) + + def postprocess( + self, + p: StableDiffusionProcessing, + proc: Processed, + enabled: bool, + multiply: Union[int,float], + weight: float, + understand: bool, + layers: str, + apply_to: Union[List[str],str], + start_steps: Union[int,float], + max_steps: Union[int,float], + up: str, + up_aa: bool, + down: str, + down_aa: bool, + intp: str, + x: Union[str,None] = None, + y: Union[str,None] = None, + force_float = False, + use_mask: bool = False, + mask: Union[tempfile._TemporaryFileWrapper,None] = None, + add_area_image: bool = True, + ): + if not enabled: + return + + multiply = int(2 ** int(max(multiply, 0))) + if x is None or len(x) == 0: + x = str((p.width - p.width // multiply) // 2) + if y is None or len(y) == 0: + y = str((p.height - p.height // multiply) // 2) + + xi0 = int(x) + yi0 = int(y) + xi1 = xi0 + p.width // multiply + yi1 = yi0 + p.height // multiply + + area = torch.zeros((1, p.height, p.width), dtype=torch.float) + area[:, yi0:yi1, xi0:xi1] = 1.0 + + pil_to_tensor = torchvision.transforms.functional.to_tensor + tensor_to_pil = torchvision.transforms.functional.to_pil_image + + if use_mask and mask is not None: + # Can I read from passed tempfile._TemporaryFileWrapper??? + mask_image = Image.open(mask.name).convert('L').resize((xi1 - xi0, yi1 - yi0), Image.BILINEAR) + mask_tensor = pil_to_tensor(mask_image) + # :: (1,h,w), each value is between 0 and 1 + area[:, yi0:yi1, xi0:xi1] = mask_tensor + + # (0.0, 1.0) -> (0.25, 1.0) + area.mul_(0.75).add_(0.25) + + for image_index in range(len(proc.images)): + is_grid = image_index < proc.index_of_first_image + if is_grid: + continue + + area_tensor = pil_to_tensor(proc.images[image_index]) + area_tensor.mul_(area) + area_image = tensor_to_pil(area_tensor, mode='RGB') + + i = image_index - proc.index_of_first_image + proc.images.append(area_image) + proc.all_prompts.append(proc.all_prompts[i]) + proc.all_negative_prompts.append(proc.all_negative_prompts[i]) + proc.all_seeds.append(proc.all_seeds[i]) + proc.all_subseeds.append(proc.all_subseeds[i]) + proc.infotexts.append(proc.infotexts[image_index]) + + +def js2py( + name: str, + id: Callable[[str], str], + js: Callable[[str], str], + sink: gr.components.IOComponent, +): + v_set = gr.Button(elem_id=id(f'{name}_set')) + v = gr.Textbox(elem_id=id(name)) + v_sink = gr.Textbox() + v_set.click(fn=None, _js=js(name), outputs=[v, v_sink]) + v_sink.change(fn=None, _js=js(f'{name}_after'), outputs=[sink]) + return v + + +init_xyz(Script) diff --git a/sd-webui-llul/scripts/llul_hooker.py b/sd-webui-llul/scripts/llul_hooker.py new file mode 100644 index 0000000000000000000000000000000000000000..b58cdcec84ff6d506a9524bcdb02a86b1c123530 --- /dev/null +++ b/sd-webui-llul/scripts/llul_hooker.py @@ -0,0 +1,382 @@ +import math +from typing import Union, Callable, List + +import torch +import torch.nn.functional as F +import torchvision.transforms.functional +from torch import nn, Tensor +from einops import rearrange +from PIL import Image +from modules.processing import StableDiffusionProcessing, slerp as Slerp + +from scripts.sdhook import ( + SDHook, + each_unet_attn_layers, + each_unet_transformers, + each_unet_resblock +) + + +class Upscaler: + + def __init__(self, mode: str, aa: bool): + mode = { + 'nearest': 'nearest-exact', + 'bilinear': 'bilinear', + 'bicubic': 'bicubic', + }.get(mode.lower(), mode) + self.mode = mode + self.aa = bool(aa) + + @property + def name(self): + s = self.mode + if self.aa: s += '-aa' + return s + + def __call__(self, x: Tensor, scale: float = 2.0): + return F.interpolate(x, scale_factor=scale, mode=self.mode, antialias=self.aa) + + +class Downscaler: + + def __init__(self, mode: str, aa: bool): + self._name = mode.lower() + intp, mode = { + 'nearest': (F.interpolate, 'nearest-exact'), + 'bilinear': (F.interpolate, 'bilinear'), + 'bicubic': (F.interpolate, 'bicubic'), + 'area': (F.interpolate, 'area'), + 'pooling max': (F.max_pool2d, ''), + 'pooling avg': (F.avg_pool2d, ''), + }[mode.lower()] + self.intp = intp + self.mode = mode + self.aa = bool(aa) + + @property + def name(self): + s = self._name + if self.aa: s += '-aa' + return s + + def __call__(self, x: Tensor, scale: float = 2.0): + if scale <= 1: + scale = float(scale) + scale_inv = 1 / scale + else: + scale_inv = float(scale) + scale = 1 / scale_inv + assert scale <= 1 + assert 1 <= scale_inv + + kwargs = {} + if len(self.mode) != 0: + kwargs['scale_factor'] = scale + kwargs['mode'] = self.mode + kwargs['antialias'] = self.aa + else: + kwargs['kernel_size'] = int(scale_inv) + return self.intp(x, **kwargs) + + +def lerp(v0, v1, t): + return torch.lerp(v0, v1, t) + +def slerp(v0, v1, t): + v = Slerp(t, v0, v1) + if torch.any(torch.isnan(v)).item(): + v = lerp(v0, v1, t) + return v + +class Hooker(SDHook): + + def __init__( + self, + enabled: bool, + multiply: int, + weight: float, + layers: Union[list,None], + apply_to: List[str], + start_steps: int, + max_steps: int, + up_fn: Callable[[Tensor,float], Tensor], + down_fn: Callable[[Tensor,float], Tensor], + intp: str, + x: float, + y: float, + force_float: bool, + mask_image: Union[Image.Image,None], + ): + super().__init__(enabled) + self.multiply = int(multiply) + self.weight = float(weight) + self.layers = layers + self.apply_to = apply_to + self.start_steps = int(start_steps) + self.max_steps = int(max_steps) + self.up = up_fn + self.down = down_fn + self.x0 = x + self.y0 = y + self.force_float = force_float + self.mask_image = mask_image + + if intp == 'lerp': + self.intp = lerp + elif intp == 'slerp': + self.intp = slerp + else: + raise ValueError(f'invalid interpolation method: {intp}') + + if not (1 <= self.multiply and (self.multiply & (self.multiply - 1) == 0)): + raise ValueError(f'multiplier must be power of 2, but not: {self.multiply}') + + if mask_image is not None: + if mask_image.mode != 'L': + raise ValueError(f'the mode of mask image is: {mask_image.mode}') + + def hook_unet(self, p: StableDiffusionProcessing, unet: nn.Module): + step = 0 + + def hook_step_pre(*args, **kwargs): + nonlocal step + step += 1 + + self.hook_layer_pre(unet, hook_step_pre) + + start_step = self.start_steps + max_steps = self.max_steps + M = self.multiply + + def create_pre_hook(name: str, ctx: dict): + def pre_hook(module: nn.Module, inputs: list): + ctx['skipped'] = True + + if step < start_step or max_steps < step: + return + + x, *rest = inputs + dim = x.dim() + if dim == 3: + # attension + bi, ni, chi = x.shape + wi, hi, Ni = self.get_size(p, ni) + x = rearrange(x, 'b (h w) c -> b c h w', w=wi) + if len(rest) != 0: + # x. attn. + rest[0] = torch.concat((rest[0], rest[0]), dim=0) + elif dim == 4: + # resblock, transformer + bi, chi, hi, wi = x.shape + if 0 < len(rest): + t_emb = rest[0] # t_emb (for resblock) or context (for transformer) + rest[0] = torch.concat((t_emb, t_emb), dim=0) + else: + # `out` layer + pass + else: + return + + # extract + w, h = wi // M, hi // M + if w == 0 or h == 0: + # input latent is too small to apply + return + + s0, t0 = int(wi * self.x0), int(hi * self.y0) + s1, t1 = s0 + w, t0 + h + if wi < s1: + s1 = wi + s0 = s1 - w + if hi < t1: + t1 = hi + t0 = t1 - h + + if s0 < 0 or t0 < 0: + raise ValueError(f'LLuL failed to process: s=({s0},{s1}), t=({t0},{t1})') + + x1 = x[:, :, t0:t1, s0:s1] + + # upscaling + x1 = self.up(x1, M) + if x1.shape[-1] < x.shape[-1] or x1.shape[-2] < x.shape[-2]: + dx = x.shape[-1] - x1.shape[-1] + dx1 = dx // 2 + dx2 = dx - dx1 + dy = x.shape[-2] - x1.shape[-2] + dy1 = dy // 2 + dy2 = dy - dy1 + x1 = F.pad(x1, (dx1, dx2, dy1, dy2), 'replicate') + + x = torch.concat((x, x1), dim=0) + if dim == 3: + x = rearrange(x, 'b c h w -> b (h w) c').contiguous() + + #print('I', tuple(inputs[0].shape), tuple(x.shape)) + ctx['skipped'] = False + return x, *rest + return pre_hook + + def create_post_hook(name: str, ctx: dict): + def post_hook(module: nn.Module, inputs: list, output: Tensor): + if step < start_step or max_steps < step: + return + + if ctx['skipped']: + return + + x = output + dim = x.dim() + if dim == 3: + bo, no, cho = x.shape + wo, ho, No = self.get_size(p, no) + x = rearrange(x, 'b (h w) c -> b c h w', w=wo) + elif dim == 4: + bo, cho, ho, wo = x.shape + else: + return + + assert bo % 2 == 0 + x, x1 = x[:bo//2], x[bo//2:] + + # downscaling + x1 = self.down(x1, M) + + # embed + w, h = x1.shape[-1], x1.shape[-2] + s0, t0 = int(wo * self.x0), int(ho * self.y0) + s1, t1 = s0 + w, t0 + h + if wo < s1: + s1 = wo + s0 = s1 - w + if ho < t1: + t1 = ho + t0 = t1 - h + + if s0 < 0 or t0 < 0: + raise ValueError(f'LLuL failed to process: s=({s0},{s1}), t=({t0},{t1})') + + x[:, :, t0:t1, s0:s1] = self.interpolate(x[:, :, t0:t1, s0:s1], x1, self.weight) + + if dim == 3: + x = rearrange(x, 'b c h w -> b (h w) c').contiguous() + + #print('O', tuple(inputs[0].shape), tuple(x.shape)) + return x + return post_hook + + def create_hook(name: str, **kwargs): + ctx = dict() + ctx.update(kwargs) + return ( + create_pre_hook(name, ctx), + create_post_hook(name, ctx) + ) + + def wrap_for_xattn(pre, post): + def f(module: nn.Module, o: Callable, *args, **kwargs): + inputs = list(args) + list(kwargs.values()) + inputs_ = pre(module, inputs) + if inputs_ is not None: + inputs = inputs_ + output = o(*inputs) + output_ = post(module, inputs, output) + if output_ is not None: + output = output_ + return output + return f + + # + # process each attention layers + # + for name, attn in each_unet_attn_layers(unet): + if self.layers is not None: + if not any(layer in name for layer in self.layers): + continue + + q_in = attn.to_q.in_features + k_in = attn.to_k.in_features + if q_in == k_in: + # self-attention + if 's. attn.' in self.apply_to: + pre, post = create_hook(name) + self.hook_layer_pre(attn, pre) + self.hook_layer(attn, post) + else: + # cross-attention + if 'x. attn.' in self.apply_to: + pre, post = create_hook(name) + self.hook_forward(attn, wrap_for_xattn(pre, post)) + + # + # process Resblocks + # + for name, res in each_unet_resblock(unet): + if 'resblock' not in self.apply_to: + continue + + if self.layers is not None: + if not any(layer in name for layer in self.layers): + continue + + pre, post = create_hook(name) + self.hook_layer_pre(res, pre) + self.hook_layer(res, post) + + # + # process Transformers (including s/x-attn) + # + for name, res in each_unet_transformers(unet): + if 'transformer' not in self.apply_to: + continue + + if self.layers is not None: + if not any(layer in name for layer in self.layers): + continue + + pre, post = create_hook(name) + self.hook_layer_pre(res, pre) + self.hook_layer(res, post) + + # + # process OUT + # + if 'out' in self.apply_to: + out = unet.out + pre, post = create_hook('out') + self.hook_layer_pre(out, pre) + self.hook_layer(out, post) + + def get_size(self, p: StableDiffusionProcessing, n: int): + # n := p.width / N * p.height / N + wh = p.width * p.height + N2 = wh // n + N = int(math.sqrt(N2)) + assert N*N == N2, f'N={N}, N2={N2}' + assert p.width % N == 0, f'width={p.width}, N={N}' + assert p.height % N == 0, f'height={p.height}, N={N}' + w, h = p.width // N, p.height // N + assert w * h == n, f'w={w}, h={h}, N={N}, n={n}' + return w, h, N + + def interpolate(self, v1: Tensor, v2: Tensor, t: float): + dtype = v1.dtype + if self.force_float: + v1 = v1.float() + v2 = v2.float() + + if self.mask_image is None: + v = self.intp(v1, v2, t) + else: + to_w, to_h = v1.shape[-1], v1.shape[-2] + resized_image = self.mask_image.resize((to_w, to_h), Image.BILINEAR) + mask = torchvision.transforms.functional.to_tensor(resized_image).to(device=v1.device, dtype=v1.dtype) + mask.unsqueeze_(0) # (C,H,W) -> (B,C,H,W) + mask.mul_(t) + v = self.intp(v1, v2, mask) + + if self.force_float: + v = v.to(dtype) + + return v diff --git a/sd-webui-llul/scripts/llul_xyz.py b/sd-webui-llul/scripts/llul_xyz.py new file mode 100644 index 0000000000000000000000000000000000000000..09c707ce8e435d7d3182a8e78d6edcf81f5d63b0 --- /dev/null +++ b/sd-webui-llul/scripts/llul_xyz.py @@ -0,0 +1,138 @@ +import os +from typing import Union, List, Callable + +from modules import scripts +from modules.processing import StableDiffusionProcessing, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img + + +def __set_value(p: StableDiffusionProcessing, script: type, index: int, value): + args = list(p.script_args) + + if isinstance(p, StableDiffusionProcessingTxt2Img): + all_scripts = scripts.scripts_txt2img.scripts + else: + all_scripts = scripts.scripts_img2img.scripts + + froms = [x.args_from for x in all_scripts if isinstance(x, script)] + for idx in froms: + assert idx is not None + args[idx + index] = value + if 3 < index: + args[idx + 3] = True + + p.script_args = type(p.script_args)(args) + + +def to_bool(v: str): + if len(v) == 0: return False + v = v.lower() + if 'true' in v: return True + if 'false' in v: return False + + try: + w = int(v) + return bool(w) + except: + acceptable = ['True', 'False', '1', '0'] + s = ', '.join([f'`{v}`' for v in acceptable]) + raise ValueError(f'value must be one of {s}.') + + +class AxisOptions: + + def __init__(self, AxisOption: type, axis_options: list): + self.AxisOption = AxisOption + self.target = axis_options + self.options = [] + + def __enter__(self): + self.options.clear() + return self + + def __exit__(self, ex_type, ex_value, trace): + if ex_type is not None: + return + + for opt in self.options: + self.target.append(opt) + + self.options.clear() + + def create(self, name: str, type_fn: Callable, action: Callable, choices: Union[List[str],None]): + if choices is None or len(choices) == 0: + opt = self.AxisOption(name, type_fn, action) + else: + opt = self.AxisOption(name, type_fn, action, choices=lambda: choices) + return opt + + def add(self, axis_option): + self.target.append(axis_option) + + +__init = False + +def init_xyz(script: type): + global __init + + if __init: + return + + for data in scripts.scripts_data: + name = os.path.basename(data.path) + if name != 'xy_grid.py' and name != 'xyz_grid.py': + continue + + if not hasattr(data.module, 'AxisOption'): + continue + + if not hasattr(data.module, 'axis_options'): + continue + + AxisOption = data.module.AxisOption + axis_options = data.module.axis_options + + if not isinstance(AxisOption, type): + continue + + if not isinstance(axis_options, list): + continue + + try: + create_options(script, AxisOption, axis_options) + except: + pass + + __init = True + + +def create_options(script: type, AxisOptionClass: type, axis_options: list): + ext_name = 'LLuL' + + with AxisOptions(AxisOptionClass, axis_options) as opts: + def define(param: str, index: int, type_fn: Callable, choices: List[str] = []): + def fn(p, x, xs): + __set_value(p, script, index, x) + + name = f'{ext_name} {param}' + return opts.create(name, type_fn, fn, choices) + + idx = 3 + options = [ + define('Enabled', 0, to_bool, choices=['false', 'true']), + define('Multiply', 1, int), + define('Weight', 2, float), + + #define('Understand', idx+0, to_bool, choices=['false', 'true']), + define('Layers', idx+1, str), + define('Apply to', idx+2, str, choices=['Resblock', 'Transformer', 'S. Attn.', 'X. Attn.', 'OUT']), + define('Start steps', idx+3, int), + define('Max steps', idx+4, int), + define('Upscaler', idx+5, str, choices=['Nearest', 'Bilinear', 'Bicubic']), + define('Upscaler AA', idx+6, to_bool, choices=['false', 'true']), + define('Downscaler', idx+7, str, choices=['Nearest', 'Bilinear', 'Bicubic', 'Area', 'Pooling Max', 'Pooling Avg']), + define('Downscaler AA', idx+8, to_bool, choices=['false', 'true']), + define('Interpolation method', idx+9, str, choices=['Lerp', 'SLerp']), + ] + + for opt in options: + opts.add(opt) diff --git a/sd-webui-llul/scripts/sdhook.py b/sd-webui-llul/scripts/sdhook.py new file mode 100644 index 0000000000000000000000000000000000000000..32ba915e3841c571464685256114510835473b9d --- /dev/null +++ b/sd-webui-llul/scripts/sdhook.py @@ -0,0 +1,275 @@ +import sys +from typing import Any, Callable, Union + +from torch import nn +from torch.utils.hooks import RemovableHandle + +from ldm.modules.diffusionmodules.openaimodel import ( + TimestepEmbedSequential, +) +from ldm.modules.attention import ( + SpatialTransformer, + BasicTransformerBlock, + CrossAttention, + MemoryEfficientCrossAttention, +) +from ldm.modules.diffusionmodules.openaimodel import ( + ResBlock, +) +from modules.processing import StableDiffusionProcessing +from modules import shared + +class ForwardHook: + + def __init__(self, module: nn.Module, fn: Callable[[nn.Module, Callable[..., Any], Any], Any]): + self.o = module.forward + self.fn = fn + self.module = module + self.module.forward = self.forward + + def remove(self): + if self.module is not None and self.o is not None: + self.module.forward = self.o + self.module = None + self.o = None + self.fn = None + + def forward(self, *args, **kwargs): + if self.module is not None and self.o is not None: + if self.fn is not None: + return self.fn(self.module, self.o, *args, **kwargs) + return None + + +class SDHook: + + def __init__(self, enabled: bool): + self._enabled = enabled + self._handles: list[Union[RemovableHandle,ForwardHook]] = [] + + @property + def enabled(self): + return self._enabled + + @property + def batch_num(self): + return shared.state.job_no + + @property + def step_num(self): + return shared.state.current_image_sampling_step + + def __enter__(self): + if self.enabled: + pass + + def __exit__(self, exc_type, exc_value, traceback): + if self.enabled: + for handle in self._handles: + handle.remove() + self._handles.clear() + self.dispose() + + def dispose(self): + pass + + def setup( + self, + p: StableDiffusionProcessing + ): + if not self.enabled: + return + + wrapper = getattr(p.sd_model, "model", None) + + unet: Union[nn.Module,None] = getattr(wrapper, "diffusion_model", None) if wrapper is not None else None + vae: Union[nn.Module,None] = getattr(p.sd_model, "first_stage_model", None) + clip: Union[nn.Module,None] = getattr(p.sd_model, "cond_stage_model", None) + + assert unet is not None, "p.sd_model.diffusion_model is not found. broken model???" + self._do_hook(p, p.sd_model, unet=unet, vae=vae, clip=clip) # type: ignore + self.on_setup() + + def on_setup(self): + pass + + def _do_hook( + self, + p: StableDiffusionProcessing, + model: Any, + unet: Union[nn.Module,None], + vae: Union[nn.Module,None], + clip: Union[nn.Module,None] + ): + assert model is not None, "empty model???" + + if clip is not None: + self.hook_clip(p, clip) + + if unet is not None: + self.hook_unet(p, unet) + + if vae is not None: + self.hook_vae(p, vae) + + def hook_vae( + self, + p: StableDiffusionProcessing, + vae: nn.Module + ): + pass + + def hook_unet( + self, + p: StableDiffusionProcessing, + unet: nn.Module + ): + pass + + def hook_clip( + self, + p: StableDiffusionProcessing, + clip: nn.Module + ): + pass + + def hook_layer( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, list, Any], Any] + ): + if not self.enabled: + return + + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(module.register_forward_hook(fn)) + + def hook_layer_pre( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, list], Any] + ): + if not self.enabled: + return + + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(module.register_forward_pre_hook(fn)) + + def hook_forward( + self, + module: Union[nn.Module,Any], + fn: Callable[[nn.Module, Callable[..., Any], Any], Any] + ): + assert module is not None + assert isinstance(module, nn.Module) + self._handles.append(ForwardHook(module, fn)) + + def log(self, msg: str): + print(msg, file=sys.stderr) + + +# enumerate SpatialTransformer in TimestepEmbedSequential +def each_transformer(unet_block: TimestepEmbedSequential): + for block in unet_block.children(): + if isinstance(block, SpatialTransformer): + yield block + +# enumerate BasicTransformerBlock in SpatialTransformer +def each_basic_block(trans: SpatialTransformer): + for block in trans.transformer_blocks.children(): + if isinstance(block, BasicTransformerBlock): + yield block + +# enumerate Attention Layers in TimestepEmbedSequential +# each_transformer + each_basic_block +def each_attns(unet_block: TimestepEmbedSequential): + for n, trans in enumerate(each_transformer(unet_block)): + for depth, basic_block in enumerate(each_basic_block(trans)): + # attn1: Union[CrossAttention,MemoryEfficientCrossAttention] + # attn2: Union[CrossAttention,MemoryEfficientCrossAttention] + + attn1, attn2 = basic_block.attn1, basic_block.attn2 + assert isinstance(attn1, CrossAttention) or isinstance(attn1, MemoryEfficientCrossAttention) + assert isinstance(attn2, CrossAttention) or isinstance(attn2, MemoryEfficientCrossAttention) + + yield n, depth, attn1, attn2 + +def each_unet_attn_layers(unet: nn.Module): + def get_attns(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, d, attn1, attn2 in each_attns(block): + kwargs = { + 'layer_index': layer_index, + 'trans_index': n, + 'block_index': d + } + yield format.format(attn_name='sattn', **kwargs), attn1 + yield format.format(attn_name='xattn', **kwargs), attn2 + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_attns(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + yield from get_attns(0, middle, 'M{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{trans_index:02}_{block_index:02}_{attn_name}') + + +def each_unet_transformers(unet: nn.Module): + def get_trans(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, trans in enumerate(each_transformer(block)): + kwargs = { + 'layer_index': layer_index, + 'block_index': n, + 'block_name': 'trans', + } + yield format.format(**kwargs), trans + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_trans(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{block_index:02}_{block_name}') + yield from get_trans(0, middle, 'M{layer_index:02}_{block_index:02}_{block_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{block_index:02}_{block_name}') + + +def each_resblock(unet_block: TimestepEmbedSequential): + for block in unet_block.children(): + if isinstance(block, ResBlock): + yield block + +def each_unet_resblock(unet: nn.Module): + def get_resblock(layer_index: int, block: TimestepEmbedSequential, format: str): + for n, res in enumerate(each_resblock(block)): + kwargs = { + 'layer_index': layer_index, + 'block_index': n, + 'block_name': 'resblock', + } + yield format.format(**kwargs), res + + def enumerate_all(blocks: nn.ModuleList, format: str): + for idx, block in enumerate(blocks.children()): + if isinstance(block, TimestepEmbedSequential): + yield from get_resblock(idx, block, format) + + inputs: nn.ModuleList = unet.input_blocks # type: ignore + middle: TimestepEmbedSequential = unet.middle_block # type: ignore + outputs: nn.ModuleList = unet.output_blocks # type: ignore + + yield from enumerate_all(inputs, 'IN{layer_index:02}_{block_index:02}_{block_name}') + yield from get_resblock(0, middle, 'M{layer_index:02}_{block_index:02}_{block_name}') + yield from enumerate_all(outputs, 'OUT{layer_index:02}_{block_index:02}_{block_name}') + diff --git a/sd-webui-llul/style.css b/sd-webui-llul/style.css new file mode 100644 index 0000000000000000000000000000000000000000..6b0d5073f45a45b183554ca7743e20a52ef0fe9d --- /dev/null +++ b/sd-webui-llul/style.css @@ -0,0 +1,37 @@ +.llul-bg-setting { + margin-top: 0.5em; +} + +.llul-bg-setting span { + display: inline-block; + margin: 0 0.5em; + padding: 0.5em; + outline: 1px solid black; + cursor: default; + user-select: none; +} + +.llul-bg-setting label { + user-select: none; +} + +#llul-txt2img-mask, +#llul-img2img-mask { + max-height: 2em; + overflow: visible; +} + +.llul-pos input { + display: inline-block; + border: none; + border-bottom: 1px solid black; + font-size: smaller !important; + width: 8em; + height: 1em; + background-color: transparent; + margin-right: 1em; +} + +.dark .llul-pos input { + border-bottom-color: white; +} diff --git a/stable-diffusion-webui-images-browser/.gitignore b/stable-diffusion-webui-images-browser/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f7bc0025490a2cfa74da7d7cdb034e819daea73c --- /dev/null +++ b/stable-diffusion-webui-images-browser/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +path_recorder.txt +__pycache__ +*.json +*.sqlite3 +*.log diff --git a/stable-diffusion-webui-images-browser/README.md b/stable-diffusion-webui-images-browser/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c4849f3219ebb94727c36ed1b16d087391829e1f --- /dev/null +++ b/stable-diffusion-webui-images-browser/README.md @@ -0,0 +1,61 @@ +## stable-diffusion-webui-images-browser + +A custom extension for [AUTOMATIC1111/stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui). + +This is an image browser for browsing past generated pictures, view their generated informations, send that information to txt2img, img2img and others, collect images to your "favorites" folder and delete the images you no longer need. + +## Installation + +The extension can be installed directly from within the **Extensions** tab within the Webui. + +You can also install it manually by running the following command from within the webui directory: + + git clone https://github.com/AlUlkesh/stable-diffusion-webui-images-browser/ extensions/stable-diffusion-webui-images-browser + +and restart your stable-diffusion-webui, then you can see the new tab "Image Browser". + +Please be aware that when scanning a directory for the first time, the png-cache will be built. This can take several minutes, depending on the amount of images. + +## Recent updates +- Image Reward scoring +- Size tooltip for thumbnails +- Optimized images in the thumbnail interface +- Send to ControlNet +- Hidable UI components +- Send to openOutpaint +- Regex search +- Maximum aesthetic_score filter +- Save ranking to EXIF option +- Maintenance tab +- Custom tabs +- Copy/Move to directory +- Keybindings +- Additional sorting and filtering by EXIF data including .txt file information +- Recyle bin option +- Add/Remove from saved directories, via buttons +- New dropdown with subdirs +- Option to not show the images from subdirs +- Refresh button +- Sort order +- View and save favorites with individual folder depth +- Now also supports jpg + +Please also check the [discussions](https://github.com/AlUlkesh/stable-diffusion-webui-images-browser/discussions) for major update information. + +## Keybindings +| Key | Explanation | +|---------|-------------| +| `0-5` | Ranks the current image, with 0 being the last option (None) | +| `F` | Adds the current image to Favorites | +| `R` | Refreshes the image gallery | +| `Delete` | Deletes the current image | +| `Ctrl + Arrow Left` | Goes to the previous page of images | +| `Ctrl + Arrow Right` | Goes to the next page of images | + +(Ctrl can be changed in settings) + +## Credit + +Credit goes to the original maintainer of this extension: https://github.com/yfszzx and to major contributors https://github.com/Klace and https://github.com/EllangoK + +Image Reward: https://github.com/THUDM/ImageReward diff --git a/stable-diffusion-webui-images-browser/install.py b/stable-diffusion-webui-images-browser/install.py new file mode 100644 index 0000000000000000000000000000000000000000..aac8b58c41be47704d350a6c5c0f9c87fd3daad9 --- /dev/null +++ b/stable-diffusion-webui-images-browser/install.py @@ -0,0 +1,7 @@ +import launch + +if not launch.is_installed("send2trash"): + launch.run_pip("install Send2Trash", "Send2Trash requirement for image browser") + +if not launch.is_installed("ImageReward"): + launch.run_pip("install image-reward", "ImageReward requirement for image browser") diff --git a/stable-diffusion-webui-images-browser/javascript/image_browser.js b/stable-diffusion-webui-images-browser/javascript/image_browser.js new file mode 100644 index 0000000000000000000000000000000000000000..7f642593bfb69f94ebb9016ff774d544f4eecf3e --- /dev/null +++ b/stable-diffusion-webui-images-browser/javascript/image_browser.js @@ -0,0 +1,742 @@ +let image_browser_state = "free" +let image_browser_webui_ready = false +let image_browser_started = false +let image_browser_console_log = "" +let image_browser_debug = false + +function image_browser_delay(ms){return new Promise(resolve => setTimeout(resolve, ms))} + +onUiLoaded(image_browser_start_it_up) + +async function image_browser_wait_for_webui() { + if (image_browser_debug) console.log("image_browser_wait_for_webui:start") + await image_browser_delay(500) + sd_model = gradioApp().getElementById("setting_sd_model_checkpoint") + if (!sd_model.querySelector(".eta-bar")) { + image_browser_webui_ready = true + image_browser_start() + } else { + // Set timeout for MutationObserver + const startTime = Date.now() + // 40 seconds in milliseconds + const timeout = 40000 + const webuiObserver = new MutationObserver(function(mutationsList) { + if (image_browser_debug) console.log("webuiObserver:start") + let found = false + outerLoop: for (let i = 0; i < mutationsList.length; i++) { + let mutation = mutationsList[i]; + if (mutation.type === "childList") { + for (let j = 0; j < mutation.removedNodes.length; j++) { + let node = mutation.removedNodes[j]; + if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains("eta-bar")) { + found = true + break outerLoop; + } + } + } + } + if (found || (Date.now() - startTime > timeout)) { + image_browser_webui_ready = true + webuiObserver.disconnect() + if (image_browser_debug) console.log("webuiObserver:end") + image_browser_start() + } + }) + webuiObserver.observe(gradioApp(), { childList:true, subtree:true }) + } + if (image_browser_debug) console.log("image_browser_wait_for_webui:end") +} + +async function image_browser_start_it_up() { + if (image_browser_debug) console.log("image_browser_start_it_up:start") + container = gradioApp().getElementById("image_browser_tabs_container") + let controls = container.querySelectorAll('[id*="_control_"]') + controls.forEach(function(control) { + control.style.pointerEvents = "none" + control.style.cursor = "not-allowed" + control.style.opacity = "0.65" + }) + let warnings = container.querySelectorAll('[id*="_warning_box"]') + warnings.forEach(function(warning) { + warning.innerHTML = '

Waiting for webui...' + }) + + image_browser_wait_for_webui() + if (image_browser_debug) console.log("image_browser_start_it_up:end") +} + +async function image_browser_lock(reason) { + if (image_browser_debug) console.log("image_browser_lock:start") + // Wait until lock removed + let i = 0 + while (image_browser_state != "free") { + await image_browser_delay(200) + i = i + 1 + if (i === 150) { + throw new Error("Still locked after 30 seconds. Please Reload UI.") + } + } + // Lock + image_browser_state = reason + if (image_browser_debug) console.log("image_browser_lock:end") +} + +async function image_browser_unlock() { + if (image_browser_debug) console.log("image_browser_unlock:start") + image_browser_state = "free" + if (image_browser_debug) console.log("image_browser_unlock:end") +} + +const image_browser_click_image = async function() { + if (image_browser_debug) console.log("image_browser_click_image:start") + await image_browser_lock("image_browser_click_image") + const tab_base_tag = image_browser_current_tab() + const container = gradioApp().getElementById(tab_base_tag + "_image_browser_container") + let child = this + let index = 0 + while((child = child.previousSibling) != null) { + index = index + 1 + } + const set_btn = container.querySelector(".image_browser_set_index") + let curr_idx + try { + curr_idx = set_btn.getAttribute("img_index") + } catch (e) { + curr_idx = -1 + } + if (curr_idx != index) { + set_btn.setAttribute("img_index", index) + } + await image_browser_unlock() + set_btn.click() + if (image_browser_debug) console.log("image_browser_click_image:end") +} + +async function image_browser_get_current_img(tab_base_tag, img_index, page_index, filenames, turn_page_switch, image_gallery) { + if (image_browser_debug) console.log("image_browser_get_current_img:start") + await image_browser_lock("image_browser_get_current_img") + img_index = gradioApp().getElementById(tab_base_tag + '_image_browser_set_index').getAttribute("img_index") + gradioApp().dispatchEvent(new Event("image_browser_get_current_img")) + await image_browser_unlock() + if (image_browser_debug) console.log("image_browser_get_current_img:end") + return [ + tab_base_tag, + img_index, + page_index, + filenames, + turn_page_switch, + image_gallery + ] +} + +async function image_browser_refresh_current_page_preview() { + if (image_browser_debug) console.log("image_browser_refresh_current_page_preview:start") + await image_browser_delay(200) + const preview_div = gradioApp().querySelector('.preview') + if (preview_div === null) { + if (image_browser_debug) console.log("image_browser_refresh_current_page_preview:end") + return + } + const tab_base_tag = image_browser_current_tab() + const gallery = gradioApp().querySelector(`#${tab_base_tag}_image_browser`) + const set_btn = gallery.querySelector(".image_browser_set_index") + const curr_idx = parseInt(set_btn.getAttribute("img_index")) + // no loading animation, so click immediately + const gallery_items = gallery.querySelectorAll(".thumbnail-item") + const curr_image = gallery_items[curr_idx] + curr_image.click() + if (image_browser_debug) console.log("image_browser_refresh_current_page_preview:end") +} + +async function image_browser_turnpage(tab_base_tag) { + if (image_browser_debug) console.log("image_browser_turnpage:start") + while (!image_browser_started) { + await image_browser_delay(200) + } + const gallery = gradioApp().querySelector(`#${tab_base_tag}_image_browser`) + let clear + try { + clear = gallery.querySelector("button[aria-label='Clear']") + if (clear) { + clear.click() + } + } catch (e) { + console.error(e) + } + if (image_browser_debug) console.log("image_browser_turnpage:end") +} + +const image_browser_get_current_img_handler = (del_img_btn) => { + if (image_browser_debug) console.log("image_browser_get_current_img_handler:start") + // Prevent delete button spam + del_img_btn.style.pointerEvents = "auto" + del_img_btn.style.cursor = "default" + del_img_btn.style.opacity = "1" + if (image_browser_debug) console.log("image_browser_get_current_img_handler:end") +} + +async function image_browser_select_image(tab_base_tag, img_index, select_image) { + if (image_browser_debug) console.log("image_browser_select_image:start") + if (select_image) { + await image_browser_lock("image_browser_select_image") + const del_img_btn = gradioApp().getElementById(tab_base_tag + "_image_browser_del_img_btn") + // Prevent delete button spam + del_img_btn.style.pointerEvents = "none" + del_img_btn.style.cursor = "not-allowed" + del_img_btn.style.opacity = "0.65" + + const gallery = gradioApp().getElementById(tab_base_tag + "_image_browser_gallery") + const gallery_items = gallery.querySelectorAll(".thumbnail-item") + if (img_index >= gallery_items.length || gallery_items.length == 0) { + const refreshBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page") + refreshBtn.dispatchEvent(new Event("click")) + } else { + const curr_image = gallery_items[img_index] + curr_image.click() + } + await image_browser_unlock() + + // Prevent delete button spam + gradioApp().removeEventListener("image_browser_get_current_img", () => image_browser_get_current_img_handler(del_img_btn)) + gradioApp().addEventListener("image_browser_get_current_img", () => image_browser_get_current_img_handler(del_img_btn)) + } + if (image_browser_debug) console.log("image_browser_select_image:end") +} + +async function image_browser_gototab(tabname) { + if (image_browser_debug) console.log("image_browser_gototab:start") + await image_browser_lock("image_browser_gototab") + + tabNav = gradioApp().querySelector(".tab-nav") + const tabNavChildren = tabNav.children + let tabNavButtonNum + if (typeof tabname === "number") { + let buttonCnt = 0 + for (let i = 0; i < tabNavChildren.length; i++) { + if (tabNavChildren[i].tagName === "BUTTON") { + if (buttonCnt === tabname) { + tabNavButtonNum = i + break + } + buttonCnt++ + } + } + } else { + for (let i = 0; i < tabNavChildren.length; i++) { + if (tabNavChildren[i].tagName === "BUTTON" && tabNavChildren[i].textContent.trim() === tabname) { + tabNavButtonNum = i + break + } + } + } + let tabNavButton = tabNavChildren[tabNavButtonNum] + tabNavButton.click() + + // Wait for click-action to complete + const startTime = Date.now() + // 60 seconds in milliseconds + const timeout = 60000 + + await image_browser_delay(100) + while (!tabNavButton.classList.contains("selected")) { + tabNavButton = tabNavChildren[tabNavButtonNum] + if (Date.now() - startTime > timeout) { + throw new Error("image_browser_gototab: 60 seconds have passed") + } + await image_browser_delay(200) + } + + await image_browser_unlock() + if (image_browser_debug) console.log("image_browser_gototab:end") +} + +async function image_browser_get_image_for_ext(tab_base_tag, image_index) { + if (image_browser_debug) console.log("image_browser_get_image_for_ext:start") + const image_browser_image = gradioApp().querySelectorAll(`#${tab_base_tag}_image_browser_gallery .thumbnail-item`)[image_index] + + const canvas = document.createElement("canvas") + const image = document.createElement("img") + image.src = image_browser_image.querySelector("img").src + + await image.decode() + + canvas.width = image.width + canvas.height = image.height + + canvas.getContext("2d").drawImage(image, 0, 0) + + if (image_browser_debug) console.log("image_browser_get_image_for_ext:end") + return canvas.toDataURL() +} + +function image_browser_openoutpaint_send(tab_base_tag, image_index, image_browser_prompt, image_browser_neg_prompt, name = "WebUI Resource") { + if (image_browser_debug) console.log("image_browser_openoutpaint_send:start") + image_browser_get_image_for_ext(tab_base_tag, image_index) + .then((dataURL) => { + // Send to openOutpaint + openoutpaint_send_image(dataURL, name) + + // Send prompt to openOutpaint + const tab = get_uiCurrentTabContent().id + + const prompt = image_browser_prompt + const negPrompt = image_browser_neg_prompt + openoutpaint.frame.contentWindow.postMessage({ + key: openoutpaint.key, + type: "openoutpaint/set-prompt", + prompt, + negPrompt, + }) + + // Change Tab + image_browser_gototab("openOutpaint") + }) + if (image_browser_debug) console.log("image_browser_openoutpaint_send:end") +} + +async function image_browser_controlnet_send(toTabNum, tab_base_tag, image_index, controlnetNum, controlnetType) { + if (image_browser_debug) console.log("image_browser_controlnet_send:start") + // Logic originally based on github.com/fkunn1326/openpose-editor + const dataURL = await image_browser_get_image_for_ext(tab_base_tag, image_index) + const blob = await (await fetch(dataURL)).blob() + const dt = new DataTransfer() + dt.items.add(new File([blob], "ImageBrowser.png", { type: blob.type })) + const list = dt.files + + await image_browser_gototab(toTabNum) + const current_tabid = image_browser_webui_current_tab() + const current_tab = current_tabid.replace("tab_", "") + const tab_controlnet = gradioApp().getElementById(current_tab + "_controlnet") + let accordion = tab_controlnet.querySelector("#controlnet > .label-wrap > .icon") + if (accordion.style.transform.includes("rotate(90deg)")) { + accordion.click() + // Wait for click-action to complete + const startTime = Date.now() + // 60 seconds in milliseconds + const timeout = 60000 + + await image_browser_delay(100) + while (accordion.style.transform.includes("rotate(90deg)")) { + accordion = tab_controlnet.querySelector("#controlnet > .label-wrap > .icon") + if (Date.now() - startTime > timeout) { + throw new Error("image_browser_controlnet_send/accordion: 60 seconds have passed") + } + await image_browser_delay(200) + } + } + + let inputImage + let inputContainer + if (controlnetType == "single") { + inputImage = gradioApp().getElementById(current_tab + "_controlnet_ControlNet_input_image") + } else { + const tabs = gradioApp().getElementById(current_tab + "_controlnet_tabs") + const tab_num = (parseInt(controlnetNum) + 1).toString() + tab_button = tabs.querySelector(".tab-nav > button:nth-child(" + tab_num + ")") + tab_button.click() + // Wait for click-action to complete + const startTime = Date.now() + // 60 seconds in milliseconds + const timeout = 60000 + + await image_browser_delay(100) + while (!tab_button.classList.contains("selected")) { + tab_button = tabs.querySelector(".tab-nav > button:nth-child(" + tab_num + ")") + if (Date.now() - startTime > timeout) { + throw new Error("image_browser_controlnet_send/tabs: 60 seconds have passed") + } + await image_browser_delay(200) + } + inputImage = gradioApp().getElementById(current_tab + "_controlnet_ControlNet-" + controlnetNum.toString() + "_input_image") + } + try { + inputContainer = inputImage.querySelector('div[data-testid="image"]') + } catch (e) {} + + const input = inputContainer.querySelector("input[type='file']") + + let clear + try { + clear = inputContainer.querySelector("button[aria-label='Clear']") + if (clear) { + clear.click() + } + } catch (e) { + console.error(e) + } + + try { + // Wait for click-action to complete + const startTime = Date.now() + // 60 seconds in milliseconds + const timeout = 60000 + while (clear) { + clear = inputContainer.querySelector("button[aria-label='Clear']") + if (Date.now() - startTime > timeout) { + throw new Error("image_browser_controlnet_send/clear: 60 seconds have passed") + } + await image_browser_delay(200) + } + } catch (e) { + console.error(e) + } + + input.value = "" + input.files = list + const event = new Event("change", { "bubbles": true, "composed": true }) + input.dispatchEvent(event) + if (image_browser_debug) console.log("image_browser_controlnet_send:end") +} + +function image_browser_controlnet_send_txt2img(tab_base_tag, image_index, controlnetNum, controlnetType) { + image_browser_controlnet_send(0, tab_base_tag, image_index, controlnetNum, controlnetType) +} + +function image_browser_controlnet_send_img2img(tab_base_tag, image_index, controlnetNum, controlnetType) { + image_browser_controlnet_send(1, tab_base_tag, image_index, controlnetNum, controlnetType) +} + +function image_browser_class_add(tab_base_tag) { + gradioApp().getElementById(tab_base_tag + '_image_browser').classList.add("image_browser_container") + gradioApp().getElementById(tab_base_tag + '_image_browser_set_index').classList.add("image_browser_set_index") + gradioApp().getElementById(tab_base_tag + '_image_browser_del_img_btn').classList.add("image_browser_del_img_btn") + gradioApp().getElementById(tab_base_tag + '_image_browser_gallery').classList.add("image_browser_gallery") +} + +function btnClickHandler(tab_base_tag, btn) { + if (image_browser_debug) console.log("btnClickHandler:start") + const tabs_box = gradioApp().getElementById("image_browser_tabs_container") + if (!tabs_box.classList.contains(tab_base_tag)) { + gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page").click() + tabs_box.classList.add(tab_base_tag) + } + if (image_browser_debug) console.log("btnClickHandler:end") +} + +function image_browser_init() { + if (image_browser_debug) console.log("image_browser_init:start") + const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") + if (tab_base_tags) { + const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",") + image_browser_tab_base_tags_list.forEach(function(tab_base_tag) { + image_browser_class_add(tab_base_tag) + }) + + const tab_btns = gradioApp().getElementById("image_browser_tabs_container").querySelector("div").querySelectorAll("button") + tab_btns.forEach(function(btn, i) { + const tab_base_tag = image_browser_tab_base_tags_list[i] + btn.setAttribute("tab_base_tag", tab_base_tag) + btn.removeEventListener('click', () => btnClickHandler(tab_base_tag, btn)) + btn.addEventListener('click', () => btnClickHandler(tab_base_tag, btn)) + }) + } + image_browser_keydown() + + const image_browser_swipe = gradioApp().getElementById("image_browser_swipe").getElementsByTagName("input")[0] + if (image_browser_swipe.checked) { + image_browser_touch() + } + if (image_browser_debug) console.log("image_browser_init:end") +} + +async function image_browser_wait_for_gallery_btn(tab_base_tag){ + if (image_browser_debug) console.log("image_browser_wait_for_gallery_btn:start") + await image_browser_delay(100) + while (!gradioApp().getElementById(image_browser_current_tab() + "_image_browser_gallery").getElementsByClassName("thumbnail-item")) { + await image_browser_delay(200) + } + if (image_browser_debug) console.log("image_browser_wait_for_gallery_btn:end") +} + +function image_browser_hijack_console_log() { + (function () { + const oldLog = console.log + console.log = function (message) { + const formattedTime = new Date().toISOString().slice(0, -5).replace(/[TZ]/g, ' ').trim().replace(/\s+/g, '-').replace(/:/g, '-') + image_browser_console_log = image_browser_console_log + formattedTime + " " + "image_browser.js: " + message + "\n" + oldLog.apply(console, arguments) + } + })() + image_browser_debug = true +} + +function get_js_logs() { + log_to_py = image_browser_console_log + image_browser_console_log = "" + return log_to_py +} + +function isNumeric(str) { + if (typeof str != "string") return false + return !isNaN(str) && !isNaN(parseFloat(str)) +} + +function image_browser_start() { + if (image_browser_debug) console.log("image_browser_start:start") + image_browser_init() + const mutationObserver = new MutationObserver(function(mutationsList) { + const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") + if (tab_base_tags) { + const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",") + image_browser_tab_base_tags_list.forEach(function(tab_base_tag) { + image_browser_class_add(tab_base_tag) + const tab_gallery_items = gradioApp().querySelectorAll('#' + tab_base_tag + '_image_browser .thumbnail-item') + + const image_browser_img_info_json = gradioApp().getElementById(tab_base_tag + "_image_browser_img_info").querySelector('[data-testid="textbox"]').value + const image_browser_img_info = JSON.parse(image_browser_img_info_json) + const filenames = Object.keys(image_browser_img_info) + + tab_gallery_items.forEach(function(gallery_item, i) { + gallery_item.removeEventListener('click', image_browser_click_image, true) + gallery_item.addEventListener('click', image_browser_click_image, true) + + const filename = filenames[i] + try { + let x = image_browser_img_info[filename].x + let y = image_browser_img_info[filename].y + if (isNumeric(x) && isNumeric(y)) { + gallery_item.title = x + "x" + y + } + } catch (e) {} + + document.onkeyup = async function(e) { + if (!image_browser_active()) { + if (image_browser_debug) console.log("image_browser_start:end") + return + } + const current_tab = image_browser_current_tab() + image_browser_wait_for_gallery_btn(current_tab).then(() => { + let gallery_btn + gallery_btn = gradioApp().getElementById(current_tab + "_image_browser_gallery").querySelector(".thumbnail-item .selected") + gallery_btn = gallery_btn && gallery_btn.length > 0 ? gallery_btn[0] : null + if (gallery_btn) { + image_browser_click_image.call(gallery_btn) + } + }) + } + }) + + const cls_btn = gradioApp().getElementById(tab_base_tag + '_image_browser_gallery').querySelector("svg") + if (cls_btn) { + cls_btn.removeEventListener('click', () => image_browser_renew_page(tab_base_tag), false) + cls_btn.addEventListener('click', () => image_browser_renew_page(tab_base_tag), false) + } + }) + const debug_level_option = gradioApp().getElementById("image_browser_debug_level_option").querySelector("textarea").value + if ((debug_level_option == 'javascript' || debug_level_option == 'capture') && !image_browser_debug) { + image_browser_hijack_console_log() + } + } + }) + mutationObserver.observe(gradioApp(), { childList:true, subtree:true }) + image_browser_started = true + image_browser_activate_controls() + if (image_browser_debug) console.log("image_browser_start:end") +} + +async function image_browser_activate_controls() { + if (image_browser_debug) console.log("image_browser_activate_controls:start") + await image_browser_delay(500) + container = gradioApp().getElementById("image_browser_tabs_container") + let controls = container.querySelectorAll('[id*="_control_"]') + controls.forEach(function(control) { + control.style.pointerEvents = "auto" + control.style.cursor = "default" + control.style.opacity = "1" + }) + let warnings = container.querySelectorAll('[id*="_warning_box"]') + warnings.forEach(function(warning) { + warning.innerHTML = "

 " + }) + if (image_browser_debug) console.log("image_browser_activate_controls:end") +} + +function image_browser_renew_page(tab_base_tag) { + if (image_browser_debug) console.log("image_browser_renew_page:start") + gradioApp().getElementById(tab_base_tag + '_image_browser_renew_page').click() + if (image_browser_debug) console.log("image_browser_renew_page:end") +} + +function image_browser_current_tab() { + if (image_browser_debug) console.log("image_browser_current_tab:start") + const tabs = gradioApp().getElementById("image_browser_tabs_container").querySelectorAll('[id$="_image_browser_container"]') + const tab_base_tags = gradioApp().getElementById("image_browser_tab_base_tags_list") + const image_browser_tab_base_tags_list = tab_base_tags.querySelector("textarea").value.split(",").sort((a, b) => b.length - a.length) + for (const element of tabs) { + if (element.style.display === "block") { + const id = element.id + const tab_base_tag = image_browser_tab_base_tags_list.find(element => id.startsWith(element)) || null + if (image_browser_debug) console.log("image_browser_current_tab:end") + return tab_base_tag + } + } + if (image_browser_debug) console.log("image_browser_current_tab:end") +} + +function image_browser_webui_current_tab() { + if (image_browser_debug) console.log("image_browser_webui_current_tab:start") + const tabs = gradioApp().getElementById("tabs").querySelectorAll('[id^="tab_"]') + let id + for (const element of tabs) { + if (element.style.display === "block") { + id = element.id + break + } + } + if (image_browser_debug) console.log("image_browser_webui_current_tab:end") + return id +} + +function image_browser_active() { + if (image_browser_debug) console.log("image_browser_active:start") + const ext_active = gradioApp().getElementById("tab_image_browser") + if (image_browser_debug) console.log("image_browser_active:end") + return ext_active && ext_active.style.display !== "none" +} + +function image_browser_keydown() { + if (image_browser_debug) console.log("image_browser_keydown:start") + gradioApp().addEventListener("keydown", function(event) { + // If we are not on the Image Browser Extension, dont listen for keypresses + if (!image_browser_active()) { + if (image_browser_debug) console.log("image_browser_keydown:end") + return + } + + // If the user is typing in an input field, dont listen for keypresses + let target + if (!event.composed) { // We shouldn't get here as the Shadow DOM is always active, but just in case + target = event.target + } else { + target = event.composedPath()[0] + } + if (!target || target.nodeName === "INPUT" || target.nodeName === "TEXTAREA") { + if (image_browser_debug) console.log("image_browser_keydown:end") + return + } + + const tab_base_tag = image_browser_current_tab() + + // Listens for keypresses 0-5 and updates the corresponding ranking (0 is the last option, None) + if (event.code >= "Digit0" && event.code <= "Digit5") { + const selectedValue = event.code.charAt(event.code.length - 1) + const radioInputs = gradioApp().getElementById(tab_base_tag + "_control_image_browser_ranking").getElementsByTagName("input") + for (const input of radioInputs) { + if (input.value === selectedValue || (selectedValue === '0' && input === radioInputs[radioInputs.length - 1])) { + input.checked = true + input.dispatchEvent(new Event("change")) + break + } + } + } + + const mod_keys = gradioApp().querySelector(`#${tab_base_tag}_image_browser_mod_keys textarea`).value + let modifiers_pressed = false + if (mod_keys.indexOf("C") !== -1 && mod_keys.indexOf("S") !== -1) { + if (event.ctrlKey && event.shiftKey) { + modifiers_pressed = true + } + } else if (mod_keys.indexOf("S") !== -1) { + if (!event.ctrlKey && event.shiftKey) { + modifiers_pressed = true + } + } else { + if (event.ctrlKey && !event.shiftKey) { + modifiers_pressed = true + } + } + + let modifiers_none = false + if (!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { + modifiers_none = true + } + + if (event.code == "KeyF" && modifiers_none) { + if (tab_base_tag == "image_browser_tab_favorites") { + if (image_browser_debug) console.log("image_browser_keydown:end") + return + } + const favoriteBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_favorites_btn") + favoriteBtn.dispatchEvent(new Event("click")) + } + + if (event.code == "KeyR" && modifiers_none) { + const refreshBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_renew_page") + refreshBtn.dispatchEvent(new Event("click")) + } + + if (event.code == "Delete" && modifiers_none) { + const deleteBtn = gradioApp().getElementById(tab_base_tag + "_image_browser_del_img_btn") + deleteBtn.dispatchEvent(new Event("click")) + } + + if (event.code == "ArrowLeft" && modifiers_pressed) { + const prevBtn = gradioApp().getElementById(tab_base_tag + "_control_image_browser_prev_page") + prevBtn.dispatchEvent(new Event("click")) + } + + if (event.code == "ArrowLeft" && modifiers_none) { + const tab_base_tag = image_browser_current_tab() + const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) + const curr_idx = parseInt(set_btn.getAttribute("img_index")) + set_btn.setAttribute("img_index", curr_idx - 1) + image_browser_refresh_current_page_preview() + } + + if (event.code == "ArrowRight" && modifiers_pressed) { + const nextBtn = gradioApp().getElementById(tab_base_tag + "_control_image_browser_next_page") + nextBtn.dispatchEvent(new Event("click")) + } + + if (event.code == "ArrowRight" && modifiers_none) { + const tab_base_tag = image_browser_current_tab() + const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) + const curr_idx = parseInt(set_btn.getAttribute("img_index")) + set_btn.setAttribute("img_index", curr_idx + 1) + image_browser_refresh_current_page_preview() + } + }) + if (image_browser_debug) console.log("image_browser_keydown:end") +} + +function image_browser_touch() { + if (image_browser_debug) console.log("image_browser_touch:start") + let touchStartX = 0 + let touchEndX = 0 + gradioApp().addEventListener("touchstart", function(event) { + if (!image_browser_active()) { + if (image_browser_debug) console.log("image_browser_touch:end") + return + } + touchStartX = event.touches[0].clientX; + }) + gradioApp().addEventListener("touchend", function(event) { + if (!image_browser_active()) { + if (image_browser_debug) console.log("image_browser_touch:end") + return + } + touchEndX = event.changedTouches[0].clientX + const touchDiffX = touchStartX - touchEndX + if (touchDiffX > 50) { + const tab_base_tag = image_browser_current_tab() + const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) + const curr_idx = parseInt(set_btn.getAttribute("img_index")) + if (curr_idx >= 1) { + set_btn.setAttribute("img_index", curr_idx - 1) + image_browser_refresh_current_page_preview() + } + } else if (touchDiffX < -50) { + const tab_base_tag = image_browser_current_tab() + const gallery = gradioApp().querySelector(`#${tab_base_tag}_image_browser`) + const gallery_items = gallery.querySelectorAll(".thumbnail-item") + const thumbnails = gallery_items.length / 2 + const set_btn = gradioApp().querySelector(`#${tab_base_tag}_image_browser .image_browser_set_index`) + const curr_idx = parseInt(set_btn.getAttribute("img_index")) + if (curr_idx + 1 < thumbnails) { + set_btn.setAttribute("img_index", curr_idx + 1) + image_browser_refresh_current_page_preview() + } + } + }) + if (image_browser_debug) console.log("image_browser_touch:end") +} diff --git a/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc b/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..202c64fb1e7ed491a95014c2e034bb268ec410f0 Binary files /dev/null and b/stable-diffusion-webui-images-browser/scripts/__pycache__/image_browser.cpython-310.pyc differ diff --git a/stable-diffusion-webui-images-browser/scripts/image_browser.py b/stable-diffusion-webui-images-browser/scripts/image_browser.py new file mode 100644 index 0000000000000000000000000000000000000000..98a68f0b4810de9b3baa17f6568c1773e08d3475 --- /dev/null +++ b/stable-diffusion-webui-images-browser/scripts/image_browser.py @@ -0,0 +1,1689 @@ +import gradio as gr +import csv +import importlib +import json +import logging +import math +import os +import platform +import random +import re +import shutil +import stat +import subprocess as sp +import sys +import tempfile +import time +import torch +import traceback +import hashlib +import modules.extras +import modules.images +import modules.ui +from datetime import datetime +from modules import paths, shared, script_callbacks, scripts, images +from modules.shared import opts, cmd_opts +from modules.ui_common import plaintext_to_html +from modules.ui_components import ToolButton, DropdownMulti +from PIL import Image, UnidentifiedImageError +from packaging import version +from pathlib import Path +from typing import List, Tuple +from itertools import chain +from io import StringIO + +try: + from scripts.wib import wib_db +except ModuleNotFoundError: + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "scripts"))) + from wib import wib_db + +try: + from send2trash import send2trash + send2trash_installed = True +except ImportError: + print("Image Browser: send2trash is not installed. recycle bin cannot be used.") + send2trash_installed = False + +try: + import ImageReward + image_reward_installed = True +except ImportError: + print("Image Browser: ImageReward is not installed, cannot be used.") + image_reward_installed = False + +# Force reload wib_db, as it doesn't get reloaded otherwise, if an extension update is started from webui +importlib.reload(wib_db) + +yappi_do = False + +components_list = ["Sort by", "Filename keyword search", "EXIF keyword search", "Ranking Filter", "Aesthestic Score", "Generation Info", "File Name", "File Time", "Open Folder", "Send to buttons", "Copy to directory", "Gallery Controls Bar", "Ranking Bar", "Delete Bar", "Additional Generation Info"] + +num_of_imgs_per_page = 0 +loads_files_num = 0 +image_ext_list = [".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp", ".svg"] +finfo_aes = {} +finfo_image_reward = {} +exif_cache = {} +finfo_exif = {} +aes_cache = {} +image_reward_cache = {} +none_select = "Nothing selected" +refresh_symbol = '\U0001f504' # 🔄 +up_symbol = '\U000025b2' # ▲ +down_symbol = '\U000025bc' # ▼ +caution_symbol = '\U000026a0' # ⚠ +folder_symbol = '\U0001f4c2' # 📂 +current_depth = 0 +init = True +copy_move = ["Move", "Copy"] +copied_moved = ["Moved", "Copied"] +np = "negative_prompt: " +openoutpaint = False +controlnet = False +js_dummy_return = None +log_file = os.path.join(scripts.basedir(), "image_browser.log") +image_reward_model = None + +def check_image_browser_active_tabs(): + # Check if Maintenance tab has been added to settings in addition to as a mandatory tab. If so, remove. + if hasattr(opts, "image_browser_active_tabs"): + active_tabs_no_maint = re.sub(r",\s*Maintenance", "", opts.image_browser_active_tabs) + if len(active_tabs_no_maint) != len(opts.image_browser_active_tabs): + shared.opts.__setattr__("image_browser_active_tabs", active_tabs_no_maint) + shared.opts.save(shared.config_filename) + +favorite_tab_name = "Favorites" +default_tab_options = ["txt2img", "img2img", "txt2img-grids", "img2img-grids", "Extras", favorite_tab_name, "Others"] +check_image_browser_active_tabs() +tabs_list = [tab.strip() for tab in chain.from_iterable(csv.reader(StringIO(opts.image_browser_active_tabs))) if tab] if hasattr(opts, "image_browser_active_tabs") else default_tab_options +try: + if opts.image_browser_enable_maint: + tabs_list.append("Maintenance") # mandatory tab +except AttributeError: + tabs_list.append("Maintenance") # mandatory tab + +path_maps = { + "txt2img": opts.outdir_samples or opts.outdir_txt2img_samples, + "img2img": opts.outdir_samples or opts.outdir_img2img_samples, + "txt2img-grids": opts.outdir_grids or opts.outdir_txt2img_grids, + "img2img-grids": opts.outdir_grids or opts.outdir_img2img_grids, + "Extras": opts.outdir_samples or opts.outdir_extras_samples, + favorite_tab_name: opts.outdir_save +} + +class ImageBrowserTab(): + + seen_base_tags = set() + + def __init__(self, name: str): + self.name: str = os.path.basename(name) if os.path.isdir(name) else name + self.path: str = os.path.realpath(path_maps.get(name, name)) + self.base_tag: str = f"image_browser_tab_{self.get_unique_base_tag(self.remove_invalid_html_tag_chars(self.name).lower())}" + + def remove_invalid_html_tag_chars(self, tag: str) -> str: + # Removes any character that is not a letter, a digit, a hyphen, or an underscore + removed = re.sub(r'[^a-zA-Z0-9\-_]', '', tag) + return removed + + def get_unique_base_tag(self, base_tag: str) -> str: + counter = 1 + while base_tag in self.seen_base_tags: + match = re.search(r'_(\d+)$', base_tag) + if match: + counter = int(match.group(1)) + 1 + base_tag = re.sub(r'_(\d+)$', f"_{counter}", base_tag) + else: + base_tag = f"{base_tag}_{counter}" + counter += 1 + self.seen_base_tags.add(base_tag) + return base_tag + + def __str__(self): + return f"Name: {self.name} / Path: {self.path} / Base tag: {self.base_tag} / Seen base tags: {self.seen_base_tags}" + +tabs_list = [ImageBrowserTab(tab) for tab in tabs_list] + +debug_level_types = ["none", "warning log", "debug log", "javascript log", "capture logs to file"] + +debug_levels_list = [] +for i in range(len(debug_level_types)): + level = debug_level_types[i].split(" ")[0] + text = str(i) + " - " + debug_level_types[i] + debug_levels_list.append((level, text)) + +def debug_levels(arg_value=None, arg_level=None, arg_text=None): + if arg_value is not None: + return arg_value, debug_levels_list[arg_value] + elif arg_level is not None: + for i, (level, text) in enumerate(debug_levels_list): + if level == arg_level: + return i, debug_levels_list[i] + elif arg_text is not None: + for i, (level, text) in enumerate(debug_levels_list): + if text == arg_text: + return i, debug_levels_list[i] + +# Logging +logger = None +def restart_debug(parameter): + global logger + logger = logging.getLogger(__name__) + logger.disabled = False + logger_mode = logging.ERROR + level_value = 0 + capture_level_value = 99 + if hasattr(opts, "image_browser_debug_level"): + warning_level_value, (warning_level, warning_level_text) = debug_levels(arg_level="warning") + debug_level_value, (debug_level, debug_level_text) = debug_levels(arg_level="debug") + capture_level_value, (capture_level, capture_level_text) = debug_levels(arg_level="capture") + level_value, (level, level_text) = debug_levels(arg_text=opts.image_browser_debug_level) + if level_value >= debug_level_value: + logger_mode = logging.DEBUG + elif level_value >= warning_level_value: + logger_mode = logging.WARNING + logger.setLevel(logger_mode) + if (logger.hasHandlers()): + logger.handlers.clear() + console_handler = logging.StreamHandler() + console_handler.setLevel(logger_mode) + formatter = logging.Formatter(f'%(asctime)s image_browser.py: %(message)s', datefmt='%Y-%m-%d-%H:%M:%S') + console_handler.setFormatter(formatter) + logger.addHandler(console_handler) + if level_value >= capture_level_value: + try: + os.unlink(log_file) + except FileNotFoundError: + pass + file_handler = logging.FileHandler(log_file) + file_handler.setLevel(logger_mode) + file_handler.setFormatter(formatter) + logger.addHandler(file_handler) + logger.warning(f"debug_level: {level_value}") + # Debug logging + if logger.getEffectiveLevel() == logging.DEBUG: + if parameter != "startup": + logging.disable(logging.NOTSET) + + logger.debug(f"{sys.executable} {sys.version}") + logger.debug(f"{platform.system()} {platform.version()}") + try: + git = os.environ.get('GIT', "git") + commit_hash = os.popen(f"{git} rev-parse HEAD").read() + except Exception as e: + commit_hash = e + logger.debug(f"{commit_hash}") + logger.debug(f"Gradio {gr.__version__}") + logger.debug(f"{paths.script_path}") + with open(cmd_opts.ui_config_file, "r") as f: + logger.debug(f.read()) + with open(cmd_opts.ui_settings_file, "r") as f: + logger.debug(f.read()) + logger.debug(os.path.realpath(__file__)) + logger.debug([str(tab) for tab in tabs_list]) + maint_last_msg = "Debug restarted" + + return parameter, maint_last_msg + +restart_debug("startup") + +def delete_recycle(filename): + if opts.image_browser_delete_recycle and send2trash_installed: + send2trash(filename) + else: + file = Path(filename) + file.unlink() + return + +def img_path_subdirs_get(img_path): + subdirs = [] + subdirs.append(none_select) + for item in os.listdir(img_path): + item_path = os.path.join(img_path, item) + if os.path.isdir(item_path): + subdirs.append(item_path) + return gr.update(choices=subdirs) + +def img_path_add_remove(img_dir, path_recorder, add_remove, img_path_depth): + img_dir = os.path.realpath(img_dir) + if add_remove == "add" or (add_remove == "remove" and img_dir in path_recorder): + if add_remove == "add": + path_recorder[img_dir] = { + "depth": int(img_path_depth), + "path_display": f"{img_dir} [{int(img_path_depth)}]" + } + wib_db.update_path_recorder(img_dir, path_recorder[img_dir]["depth"], path_recorder[img_dir]["path_display"]) + else: + del path_recorder[img_dir] + wib_db.delete_path_recorder(img_dir) + path_recorder_formatted = [value.get("path_display") for key, value in path_recorder.items()] + path_recorder_formatted = sorted(path_recorder_formatted, key=lambda x: natural_keys(x.lower())) + + if add_remove == "remove": + selected = path_recorder[list(path_recorder.keys())[0]]["path_display"] + else: + selected = path_recorder[img_dir]["path_display"] + return path_recorder, gr.update(choices=path_recorder_formatted, value=selected) + +def sort_order_flip(turn_page_switch, sort_order): + if sort_order == up_symbol: + sort_order = down_symbol + else: + sort_order = up_symbol + return 1, -turn_page_switch, sort_order + +def read_path_recorder(): + path_recorder = wib_db.load_path_recorder() + path_recorder_formatted = [value.get("path_display") for key, value in path_recorder.items()] + path_recorder_formatted = sorted(path_recorder_formatted, key=lambda x: natural_keys(x.lower())) + path_recorder_unformatted = list(path_recorder.keys()) + path_recorder_unformatted = sorted(path_recorder_unformatted, key=lambda x: natural_keys(x.lower())) + + return path_recorder, path_recorder_formatted, path_recorder_unformatted + +def pure_path(path): + if path == []: + return path, 0 + match = re.search(r" \[(\d+)\]$", path) + if match: + path = path[:match.start()] + depth = int(match.group(1)) + else: + depth = 0 + path = os.path.realpath(path) + return path, depth + +def browser2path(img_path_browser): + img_path, _ = pure_path(img_path_browser) + return img_path + +def totxt(file): + base, _ = os.path.splitext(file) + file_txt = base + '.txt' + + return file_txt + +def tab_select(): + path_recorder, path_recorder_formatted, path_recorder_unformatted = read_path_recorder() + return path_recorder, gr.update(choices=path_recorder_unformatted) + +def js_logs_output(js_log): + logger.debug(f"js_log: {js_log}") + return js_log + +def ranking_filter_settings(page_index, turn_page_switch, ranking_filter): + if ranking_filter == "Min-max": + interactive = True + else: + interactive = False + page_index = 1 + turn_page_switch = -turn_page_switch + return page_index, turn_page_switch, gr.update(interactive=interactive), gr.update(interactive=interactive) + +def reduplicative_file_move(src, dst): + def same_name_file(basename, path): + name, ext = os.path.splitext(basename) + f_list = os.listdir(path) + max_num = 0 + for f in f_list: + if len(f) <= len(basename): + continue + f_ext = f[-len(ext):] if len(ext) > 0 else "" + if f[:len(name)] == name and f_ext == ext: + if f[len(name)] == "(" and f[-len(ext)-1] == ")": + number = f[len(name)+1:-len(ext)-1] + if number.isdigit(): + if int(number) > max_num: + max_num = int(number) + return f"{name}({max_num + 1}){ext}" + name = os.path.basename(src) + save_name = os.path.join(dst, name) + src_txt_exists = False + if opts.image_browser_txt_files: + src_txt = totxt(src) + if os.path.exists(src_txt): + src_txt_exists = True + if not os.path.exists(save_name): + if opts.image_browser_copy_image: + shutil.copy2(src, dst) + if opts.image_browser_txt_files and src_txt_exists: + shutil.copy2(src_txt, dst) + else: + shutil.move(src, dst) + if opts.image_browser_txt_files and src_txt_exists: + shutil.move(src_txt, dst) + else: + name = same_name_file(name, dst) + if opts.image_browser_copy_image: + shutil.copy2(src, os.path.join(dst, name)) + if opts.image_browser_txt_files and src_txt_exists: + shutil.copy2(src_txt, totxt(os.path.join(dst, name))) + else: + shutil.move(src, os.path.join(dst, name)) + if opts.image_browser_txt_files and src_txt_exists: + shutil.move(src_txt, totxt(os.path.join(dst, name))) + +def save_image(file_name, filenames, page_index, turn_page_switch, dest_path): + if file_name is not None and os.path.exists(file_name): + reduplicative_file_move(file_name, dest_path) + message = f"

{copied_moved[opts.image_browser_copy_image]} to {dest_path}
" + if not opts.image_browser_copy_image: + # Force page refresh with checking filenames + filenames = [] + turn_page_switch = -turn_page_switch + else: + message = "
Image not found (may have been already moved)
" + + return message, filenames, page_index, turn_page_switch + +def delete_image(tab_base_tag_box, delete_num, name, filenames, image_index, visible_num, delete_confirm, turn_page_switch, image_page_list): + logger.debug("delete_image") + refresh = False + delete_num = int(delete_num) + image_index = int(image_index) + visible_num = int(visible_num) + image_page_list = json.loads(image_page_list) + new_file_list = [] + new_image_page_list = [] + if name == "": + refresh = True + else: + try: + index_files = list(filenames).index(name) + + index_on_page = image_page_list.index(name) + except ValueError as e: + print(traceback.format_exc(), file=sys.stderr) + # Something went wrong, force a page refresh + refresh = True + if not refresh: + if not delete_confirm: + delete_num = min(visible_num - index_on_page, delete_num) + new_file_list = filenames[:index_files] + filenames[index_files + delete_num:] + new_image_page_list = image_page_list[:index_on_page] + image_page_list[index_on_page + delete_num:] + + for i in range(index_files, index_files + delete_num): + if os.path.exists(filenames[i]): + if opts.image_browser_delete_message: + print(f"Deleting file {filenames[i]}") + delete_recycle(filenames[i]) + visible_num -= 1 + if opts.image_browser_txt_files: + txt_file = totxt(filenames[i]) + if os.path.exists(txt_file): + delete_recycle(txt_file) + else: + print(f"File does not exist {filenames[i]}") + # If we reach this point (which we shouldn't), things are messed up, better force a page refresh + refresh = True + + if refresh: + turn_page_switch = -turn_page_switch + select_image = False + else: + select_image = True + + return new_file_list, 1, turn_page_switch, visible_num, new_image_page_list, select_image, json.dumps(new_image_page_list) + +def traverse_all_files(curr_path, image_list, tab_base_tag_box, img_path_depth) -> List[Tuple[str, os.stat_result, str, int]]: + global current_depth + logger.debug(f"curr_path: {curr_path}") + if curr_path == "": + return image_list + f_list = [(os.path.join(curr_path, entry.name), entry.stat()) for entry in os.scandir(curr_path)] + for f_info in f_list: + fname, fstat = f_info + if os.path.splitext(fname)[1] in image_ext_list: + image_list.append(f_info) + elif stat.S_ISDIR(fstat.st_mode): + if (opts.image_browser_with_subdirs and tab_base_tag_box != "image_browser_tab_others") or (tab_base_tag_box == "image_browser_tab_others" and img_path_depth != 0 and (current_depth < img_path_depth or img_path_depth < 0)): + current_depth = current_depth + 1 + image_list = traverse_all_files(fname, image_list, tab_base_tag_box, img_path_depth) + current_depth = current_depth - 1 + return image_list + +def cache_exif(fileinfos): + global finfo_exif, exif_cache, finfo_aes, aes_cache, finfo_image_reward, image_reward_cache + + if yappi_do: + import yappi + import pandas as pd + yappi.set_clock_type("wall") + yappi.start() + + cache_exif_start = time.time() + new_exif = 0 + new_aes = 0 + conn, cursor = wib_db.transaction_begin() + for fi_info in fileinfos: + if any(fi_info[0].endswith(ext) for ext in image_ext_list): + found_exif = False + found_aes = False + if fi_info[0] in exif_cache: + finfo_exif[fi_info[0]] = exif_cache[fi_info[0]] + found_exif = True + if fi_info[0] in aes_cache: + finfo_aes[fi_info[0]] = aes_cache[fi_info[0]] + found_aes = True + if fi_info[0] in image_reward_cache: + finfo_image_reward[fi_info[0]] = image_reward_cache[fi_info[0]] + if not found_exif or not found_aes: + finfo_exif[fi_info[0]] = "0" + exif_cache[fi_info[0]] = "0" + finfo_aes[fi_info[0]] = "0" + aes_cache[fi_info[0]] = "0" + try: + image = Image.open(fi_info[0]) + (_, allExif, allExif_html) = modules.extras.run_pnginfo(image) + image.close() + except SyntaxError: + allExif = False + logger.warning(f"Extension and content don't match: {fi_info[0]}") + except UnidentifiedImageError as e: + allExif = False + logger.warning(f"UnidentifiedImageError: {e}") + except Image.DecompressionBombError as e: + allExif = False + logger.warning(f"DecompressionBombError: {e}: {fi_info[0]}") + except PermissionError as e: + allExif = False + logger.warning(f"PermissionError: {e}: {fi_info[0]}") + except FileNotFoundError as e: + allExif = False + logger.warning(f"FileNotFoundError: {e}: {fi_info[0]}") + except OSError as e: + if e.errno == 22: + logger.warning(f"Caught OSError with error code 22: {fi_info[0]}") + else: + raise + if allExif: + finfo_exif[fi_info[0]] = allExif + exif_cache[fi_info[0]] = allExif + wib_db.update_exif_data(conn, fi_info[0], allExif) + new_exif = new_exif + 1 + + m = re.search("(?:aesthetic_score:|Score:) (\d+.\d+)", allExif) + if m: + aes_value = m.group(1) + else: + aes_value = "0" + finfo_aes[fi_info[0]] = aes_value + aes_cache[fi_info[0]] = aes_value + wib_db.update_exif_data_by_key(conn, fi_info[0], "aesthetic_score", aes_value) + new_aes = new_aes + 1 + else: + try: + filename = os.path.splitext(fi_info[0])[0] + ".txt" + geninfo = "" + with open(filename) as f: + for line in f: + geninfo += line + finfo_exif[fi_info[0]] = geninfo + exif_cache[fi_info[0]] = geninfo + wib_db.update_exif_data_by_key(conn, fi_info[0], geninfo) + new_exif = new_exif + 1 + + m = re.search("(?:aesthetic_score:|Score:) (\d+.\d+)", geninfo) + if m: + aes_value = m.group(1) + else: + aes_value = "0" + finfo_aes[fi_info[0]] = aes_value + aes_cache[fi_info[0]] = aes_value + wib_db.update_exif_data_by_key(conn, fi_info[0], "aesthetic_score", aes_value) + new_aes = new_aes + 1 + except Exception: + logger.warning(f"cache_exif: No EXIF in image or txt file for {fi_info[0]}") + # Saved with defaults to not scan it again next time + finfo_exif[fi_info[0]] = "0" + exif_cache[fi_info[0]] = "0" + allExif = "0" + wib_db.update_exif_data(conn, fi_info[0], allExif) + new_exif = new_exif + 1 + + aes_value = "0" + finfo_aes[fi_info[0]] = aes_value + aes_cache[fi_info[0]] = aes_value + wib_db.update_exif_data_by_key(conn, fi_info[0], "aesthetic_score", aes_value) + new_aes = new_aes + 1 + wib_db.transaction_end(conn, cursor) + + if yappi_do: + yappi.stop() + pd.set_option('display.float_format', lambda x: '%.6f' % x) + yappi_stats = yappi.get_func_stats().strip_dirs() + data = [(s.name, s.ncall, s.tsub, s.ttot, s.ttot/s.ncall) for s in yappi_stats] + df = pd.DataFrame(data, columns=['name', 'ncall', 'tsub', 'ttot', 'tavg']) + print(df.to_string(index=False)) + yappi.get_thread_stats().print_all() + + cache_exif_end = time.time() + logger.debug(f"cache_exif: {new_exif}/{len(fileinfos)} cache_aes: {new_aes}/{len(fileinfos)} {round(cache_exif_end - cache_exif_start, 1)} seconds") + +def exif_rebuild(maint_wait): + global finfo_exif, exif_cache, finfo_aes, aes_cache, finfo_image_reward, image_reward_cache + if opts.image_browser_scan_exif: + logger.debug("Rebuild start") + exif_dirs = wib_db.get_exif_dirs() + finfo_aes = {} + finfo_image_reward = {} + exif_cache = {} + finfo_exif = {} + aes_cache = {} + image_reward_cache = {} + for key, value in exif_dirs.items(): + if os.path.exists(key): + print(f"Rebuilding {key}") + fileinfos = traverse_all_files(key, [], "", 0) + cache_exif(fileinfos) + logger.debug("Rebuild end") + maint_last_msg = "Rebuild finished" + else: + maint_last_msg = "Exif cache not enabled in settings" + + return maint_wait, maint_last_msg + +def exif_delete_0(maint_wait): + global finfo_exif, exif_cache, finfo_aes, aes_cache + if opts.image_browser_scan_exif: + conn, cursor = wib_db.transaction_begin() + wib_db.delete_exif_0(cursor) + wib_db.transaction_end(conn, cursor) + finfo_aes = {} + finfo_exif = {} + exif_cache = wib_db.load_exif_data(exif_cache) + aes_cache = wib_db.load_aes_data(aes_cache) + maint_last_msg = "Delete finished" + else: + maint_last_msg = "Exif cache not enabled in settings" + + return maint_wait, maint_last_msg + +def exif_update_dirs(maint_update_dirs_from, maint_update_dirs_to, maint_wait): + global exif_cache, aes_cache, image_reward_cache + if maint_update_dirs_from == "": + maint_last_msg = "From is empty" + elif maint_update_dirs_to == "": + maint_last_msg = "To is empty" + else: + maint_update_dirs_from = os.path.realpath(maint_update_dirs_from) + maint_update_dirs_to = os.path.realpath(maint_update_dirs_to) + rows = 0 + conn, cursor = wib_db.transaction_begin() + wib_db.update_path_recorder_mult(cursor, maint_update_dirs_from, maint_update_dirs_to) + rows = rows + cursor.rowcount + wib_db.update_exif_data_mult(cursor, maint_update_dirs_from, maint_update_dirs_to) + rows = rows + cursor.rowcount + wib_db.update_ranking_mult(cursor, maint_update_dirs_from, maint_update_dirs_to) + rows = rows + cursor.rowcount + wib_db.transaction_end(conn, cursor) + if rows == 0: + maint_last_msg = "No rows updated" + else: + maint_last_msg = f"{rows} rows updated. Please reload UI!" + + return maint_wait, maint_last_msg + +def reapply_ranking(path_recorder, maint_wait): + dirs = {} + + for tab in tabs_list: + if os.path.exists(tab.path): + dirs[tab.path] = tab.path + + for key in path_recorder: + if os.path.exists(key): + dirs[key] = key + + conn, cursor = wib_db.transaction_begin() + + # Traverse all known dirs, check if missing rankings are due to moved files + for key in dirs.keys(): + fileinfos = traverse_all_files(key, [], "", 0) + for (file, _) in fileinfos: + # Is there a ranking for this full filepath + ranking_by_file = wib_db.get_ranking_by_file(cursor, file) + if ranking_by_file is None: + name = os.path.basename(file) + (ranking_by_name, alternate_hash) = wib_db.get_ranking_by_name(cursor, name) + # Is there a ranking only for the filename + if ranking_by_name is not None: + hash = wib_db.get_hash(file) + (alternate_file, alternate_ranking) = ranking_by_name + if alternate_ranking is not None: + (alternate_hash,) = alternate_hash + # Does the found filename's file have no hash or the same hash? + if alternate_hash is None or hash == alternate_hash: + if os.path.exists(alternate_file): + # Insert ranking as a copy of the found filename's ranking + wib_db.insert_ranking(cursor, file, alternate_ranking, hash) + else: + # Replace ranking of the found filename + wib_db.replace_ranking(cursor, file, alternate_file, hash) + + wib_db.transaction_end(conn, cursor) + maint_last_msg = "Rankings reapplied" + + return maint_wait, maint_last_msg + +def atof(text): + try: + retval = float(text) + except ValueError: + retval = text + return retval + +def natural_keys(text): + ''' + alist.sort(key=natural_keys) sorts in human order + http://nedbatchelder.com/blog/200712/human_sorting.html + (See Toothy's implementation in the comments) + float regex comes from https://stackoverflow.com/a/12643073/190597 + ''' + return [ atof(c) for c in re.split(r'[+-]?([0-9]+(?:[.][0-9]*)?|[.][0-9]+)', text) ] + +def open_folder(path): + if os.path.exists(path): + # Code from ui_common.py + if not shared.cmd_opts.hide_ui_dir_config: + if platform.system() == "Windows": + os.startfile(path) + elif platform.system() == "Darwin": + sp.Popen(["open", path]) + elif "microsoft-standard-WSL2" in platform.uname().release: + sp.Popen(["wsl-open", path]) + else: + sp.Popen(["xdg-open", path]) + +def check_ext(ext): + found = False + scripts_list = scripts.list_scripts("scripts", ".py") + for scriptfile in scripts_list: + if ext in scriptfile.basedir.lower(): + found = True + break + return found + +def exif_search(needle, haystack, use_regex, case_sensitive): + found = False + if use_regex: + if case_sensitive: + pattern = re.compile(needle, re.DOTALL) + else: + pattern = re.compile(needle, re.DOTALL | re.IGNORECASE) + if pattern.search(haystack) is not None: + found = True + else: + if not case_sensitive: + haystack = haystack.lower() + needle = needle.lower() + if needle in haystack: + found = True + return found + +def get_all_images(dir_name, sort_by, sort_order, keyword, tab_base_tag_box, img_path_depth, ranking_filter, ranking_filter_min, ranking_filter_max, aes_filter_min, aes_filter_max, score_type, exif_keyword, negative_prompt_search, use_regex, case_sensitive): + global current_depth + logger.debug("get_all_images") + current_depth = 0 + fileinfos = traverse_all_files(dir_name, [], tab_base_tag_box, img_path_depth) + keyword = keyword.strip(" ") + + if opts.image_browser_scan_exif: + cache_exif(fileinfos) + + if len(keyword) != 0: + fileinfos = [x for x in fileinfos if keyword.lower() in x[0].lower()] + filenames = [finfo[0] for finfo in fileinfos] + + if opts.image_browser_scan_exif: + conn, cursor = wib_db.transaction_begin() + if len(exif_keyword) != 0: + if use_regex: + regex_error = False + try: + test_re = re.compile(exif_keyword, re.DOTALL) + except re.error as e: + regex_error = True + print(f"Regex error: {e}") + if (use_regex and not regex_error) or not use_regex: + if negative_prompt_search == "Yes": + fileinfos = [x for x in fileinfos if exif_search(exif_keyword, finfo_exif[x[0]], use_regex, case_sensitive)] + else: + result = [] + for file_info in fileinfos: + file_name = file_info[0] + file_exif = finfo_exif[file_name] + file_exif_lc = file_exif.lower() + start_index = file_exif_lc.find(np) + end_index = file_exif.find("\n", start_index) + if negative_prompt_search == "Only": + start_index = start_index + len(np) + sub_string = file_exif[start_index:end_index].strip() + if exif_search(exif_keyword, sub_string, use_regex, case_sensitive): + result.append(file_info) + else: + sub_string = file_exif[start_index:end_index].strip() + file_exif = file_exif.replace(sub_string, "") + + if exif_search(exif_keyword, file_exif, use_regex, case_sensitive): + result.append(file_info) + fileinfos = result + filenames = [finfo[0] for finfo in fileinfos] + wib_db.fill_work_files(cursor, fileinfos) + if len(aes_filter_min) != 0 or len(aes_filter_max) != 0: + try: + aes_filter_min_num = float(aes_filter_min) + except ValueError: + aes_filter_min_num = sys.float_info.min + try: + aes_filter_max_num = float(aes_filter_max) + except ValueError: + aes_filter_max_num = sys.float_info.max + + fileinfos = wib_db.filter_aes(cursor, fileinfos, aes_filter_min_num, aes_filter_max_num, score_type) + filenames = [finfo[0] for finfo in fileinfos] + if ranking_filter != "All": + ranking_filter_min_num = 1 + ranking_filter_max_num = 5 + if ranking_filter == "Min-max": + try: + ranking_filter_min_num = int(ranking_filter_min) + except ValueError: + ranking_filter_min_num = 0 + try: + ranking_filter_max_num = int(ranking_filter_max) + except ValueError: + ranking_filter_max_num = 0 + if ranking_filter_min_num < 1: + ranking_filter_min_num = 1 + if ranking_filter_max_num < 1 or ranking_filter_max_num > 5: + ranking_filter_max_num = 5 + + fileinfos = wib_db.filter_ranking(cursor, fileinfos, ranking_filter, ranking_filter_min_num, ranking_filter_max_num) + filenames = [finfo[0] for finfo in fileinfos] + + wib_db.transaction_end(conn, cursor) + + if sort_by == "date": + if sort_order == up_symbol: + fileinfos = sorted(fileinfos, key=lambda x: x[1].st_mtime) + else: + fileinfos = sorted(fileinfos, key=lambda x: -x[1].st_mtime) + filenames = [finfo[0] for finfo in fileinfos] + elif sort_by == "path name": + if sort_order == up_symbol: + fileinfos = sorted(fileinfos) + else: + fileinfos = sorted(fileinfos, reverse=True) + filenames = [finfo[0] for finfo in fileinfos] + elif sort_by == "random": + random.shuffle(fileinfos) + filenames = [finfo[0] for finfo in fileinfos] + elif sort_by == "ranking": + finfo_ranked = {} + for fi_info in fileinfos: + finfo_ranked[fi_info[0]], _ = get_ranking(fi_info[0]) + if sort_order == up_symbol: + fileinfos = dict(sorted(finfo_ranked.items(), key=lambda x: (x[1], x[0]))) + else: + fileinfos = dict(reversed(sorted(finfo_ranked.items(), key=lambda x: (x[1], x[0])))) + filenames = [finfo for finfo in fileinfos] + else: + sort_values = {} + exif_info = dict(finfo_exif) + if exif_info: + for k, v in exif_info.items(): + match = re.search(r'(?<='+ sort_by + ":" ').*?(?=(,|$))', v, flags=re.DOTALL|re.IGNORECASE) + if match: + sort_values[k] = match.group().strip() + else: + sort_values[k] = "0" + if sort_by == "aesthetic_score" or sort_by == "ImageRewardScore" or sort_by == "cfg scale": + sort_float = True + else: + sort_float = False + + if sort_order == down_symbol: + if sort_float: + fileinfos = [x for x in fileinfos if sort_values[x[0]] != "0"] + fileinfos.sort(key=lambda x: float(sort_values[x[0]]), reverse=True) + fileinfos = dict(fileinfos) + else: + fileinfos = dict(reversed(sorted(fileinfos, key=lambda x: natural_keys(sort_values[x[0]])))) + else: + if sort_float: + fileinfos = [x for x in fileinfos if sort_values[x[0]] != "0"] + fileinfos.sort(key=lambda x: float(sort_values[x[0]])) + fileinfos = dict(fileinfos) + else: + fileinfos = dict(sorted(fileinfos, key=lambda x: natural_keys(sort_values[x[0]]))) + filenames = [finfo for finfo in fileinfos] + else: + filenames = [finfo for finfo in fileinfos] + return filenames + +def get_image_thumbnail(image_list): + logger.debug("get_image_thumbnail") + optimized_cache = os.path.join(tempfile.gettempdir(),"optimized") + os.makedirs(optimized_cache,exist_ok=True) + thumbnail_list = [] + for image_path in image_list: + image_path_hash = hashlib.md5(image_path.encode("utf-8")).hexdigest() + cache_image_path = os.path.join(optimized_cache, image_path_hash + ".jpg") + if os.path.isfile(cache_image_path): + thumbnail_list.append(cache_image_path) + else: + try: + image = Image.open(image_path) + except OSError: + # If PIL cannot open the image, use the original path + thumbnail_list.append(image_path) + continue + width, height = image.size + left = (width - min(width, height)) / 2 + top = (height - min(width, height)) / 2 + right = (width + min(width, height)) / 2 + bottom = (height + min(width, height)) / 2 + thumbnail = image.crop((left, top, right, bottom)) + thumbnail.thumbnail((opts.image_browser_thumbnail_size, opts.image_browser_thumbnail_size)) + if thumbnail.mode != "RGB": + thumbnail = thumbnail.convert("RGB") + try: + thumbnail.save(cache_image_path, "JPEG") + thumbnail_list.append(cache_image_path) + except FileNotFoundError: + # Cannot save cache, use PIL object + thumbnail_list.append(thumbnail) + return thumbnail_list + +def set_tooltip_info(image_list): + image_browser_img_info = {} + conn, cursor = wib_db.transaction_begin() + for filename in image_list: + x, y = wib_db.select_x_y(cursor, filename) + image_browser_img_info[filename] = {"x": x, "y": y} + wib_db.transaction_end(conn, cursor) + image_browser_img_info_json = json.dumps(image_browser_img_info) + return image_browser_img_info_json + +def get_image_page(img_path, page_index, filenames, keyword, sort_by, sort_order, tab_base_tag_box, img_path_depth, ranking_filter, ranking_filter_min, ranking_filter_max, aes_filter_min, aes_filter_max, score_type, exif_keyword, negative_prompt_search, use_regex, case_sensitive, image_reward_button): + logger.debug("get_image_page") + if img_path == "": + return [], page_index, [], "", "", "", 0, "", None, "", "[]", image_reward_button + + # Set temp_dir from webui settings, so gradio uses it + if shared.opts.temp_dir != "": + tempfile.tempdir = shared.opts.temp_dir + + img_path, _ = pure_path(img_path) + filenames = get_all_images(img_path, sort_by, sort_order, keyword, tab_base_tag_box, img_path_depth, ranking_filter, ranking_filter_min, ranking_filter_max, aes_filter_min, aes_filter_max, score_type, exif_keyword, negative_prompt_search, use_regex, case_sensitive) + page_index = int(page_index) + length = len(filenames) + max_page_index = math.ceil(length / num_of_imgs_per_page) + page_index = max_page_index if page_index == -1 else page_index + page_index = 1 if page_index < 1 else page_index + page_index = max_page_index if page_index > max_page_index else page_index + idx_frm = (page_index - 1) * num_of_imgs_per_page + image_list = filenames[idx_frm:idx_frm + num_of_imgs_per_page] + + if opts.image_browser_scan_exif and opts.image_browser_img_tooltips: + image_browser_img_info = set_tooltip_info(image_list) + else: + image_browser_img_info = "[]" + + if opts.image_browser_use_thumbnail: + thumbnail_list = get_image_thumbnail(image_list) + else: + thumbnail_list = image_list + + visible_num = num_of_imgs_per_page if idx_frm + num_of_imgs_per_page < length else length % num_of_imgs_per_page + visible_num = num_of_imgs_per_page if visible_num == 0 else visible_num + + load_info = "
" + load_info += f"{length} images in this directory, divided into {int((length + 1) // num_of_imgs_per_page + 1)} pages" + load_info += "
" + + return filenames, gr.update(value=page_index, label=f"Page Index ({page_index}/{max_page_index})"), thumbnail_list, "", "", "", visible_num, load_info, None, json.dumps(image_list), image_browser_img_info, gr.update(visible=True) + +def get_current_file(tab_base_tag_box, num, page_index, filenames): + file = filenames[int(num) + int((page_index - 1) * num_of_imgs_per_page)] + return file + +def show_image_info(tab_base_tag_box, num, page_index, filenames, turn_page_switch, image_gallery): + logger.debug(f"show_image_info: tab_base_tag_box, num, page_index, len(filenames), num_of_imgs_per_page: {tab_base_tag_box}, {num}, {page_index}, {len(filenames)}, {num_of_imgs_per_page}") + if len(filenames) == 0: + # This should only happen if webui was stopped and started again and the user clicks on one of the still displayed images. + # The state with the filenames will be empty then. In that case we return None to prevent further errors and force a page refresh. + turn_page_switch = -turn_page_switch + file = None + tm = None + info = "" + else: + file_num = int(num) + int( + (page_index - 1) * num_of_imgs_per_page) + if file_num >= len(filenames): + # Last image to the right is deleted, page refresh + turn_page_switch = -turn_page_switch + file = None + tm = None + info = "" + else: + file = filenames[file_num] + tm = "
" + time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getmtime(file))) + "
" + try: + with Image.open(file) as image: + _, geninfo, info = modules.extras.run_pnginfo(image) + except UnidentifiedImageError as e: + info = "" + logger.warning(f"UnidentifiedImageError: {e}") + if opts.image_browser_use_thumbnail: + image_gallery = [image['name'] for image in image_gallery] + image_gallery[int(num)] = filenames[file_num] + return file, tm, num, file, turn_page_switch, info, image_gallery + else: + return file, tm, num, file, turn_page_switch, info + +def change_dir(img_dir, path_recorder, load_switch, img_path_browser, img_path_depth, img_path): + warning = None + img_path, _ = pure_path(img_path) + img_path_depth_org = img_path_depth + if img_dir == none_select: + return warning, gr.update(visible=False), img_path_browser, path_recorder, load_switch, img_path, img_path_depth + else: + img_dir, img_path_depth = pure_path(img_dir) + if warning is None: + try: + if os.path.exists(img_dir): + try: + f = os.listdir(img_dir) + except: + warning = f"'{img_dir} is not a directory" + else: + warning = "The directory does not exist" + except: + warning = "The format of the directory is incorrect" + if warning is None: + return "", gr.update(visible=True), img_path_browser, path_recorder, img_dir, img_dir, img_path_depth + else: + return warning, gr.update(visible=False), img_path_browser, path_recorder, load_switch, img_path, img_path_depth_org + +def update_move_text_one(btn): + btn_text = " ".join(btn.split()[1:]) + return f"{copy_move[opts.image_browser_copy_image]} {btn_text}" + +def update_move_text(favorites_btn, to_dir_btn): + return update_move_text_one(favorites_btn), update_move_text_one(to_dir_btn) + +def get_ranking(filename): + ranking_value = wib_db.select_ranking(filename) + return ranking_value, None + +def img_file_name_changed(img_file_name, favorites_btn, to_dir_btn): + ranking_current, ranking = get_ranking(img_file_name) + favorites_btn, to_dir_btn = update_move_text(favorites_btn, to_dir_btn) + + return ranking_current, ranking, "", favorites_btn, to_dir_btn + +def update_exif(img_file_name, key, value): + image = Image.open(img_file_name) + geninfo, items = images.read_info_from_image(image) + if geninfo is not None: + if f"{key}: " in geninfo: + if value == "None": + geninfo = re.sub(f', {key}: \d+(\.\d+)*', '', geninfo) + else: + geninfo = re.sub(f'{key}: \d+(\.\d+)*', f'{key}: {value}', geninfo) + else: + geninfo = f'{geninfo}, {key}: {value}' + + original_time = os.path.getmtime(img_file_name) + images.save_image(image, os.path.dirname(img_file_name), "", extension=os.path.splitext(img_file_name)[1][1:], info=geninfo, forced_filename=os.path.splitext(os.path.basename(img_file_name))[0], save_to_dirs=False) + os.utime(img_file_name, (original_time, original_time)) + return geninfo + +def update_ranking(img_file_name, ranking_current, ranking, img_file_info): + # ranking = None is different than ranking = "None"! None means no radio button selected. "None" means radio button called "None" selected. + if ranking is None: + return ranking_current, None, img_file_info + + saved_ranking, _ = get_ranking(img_file_name) + if saved_ranking != ranking: + wib_db.update_ranking(img_file_name, ranking) + if opts.image_browser_ranking_pnginfo and any(img_file_name.endswith(ext) for ext in image_ext_list): + img_file_info = update_exif(img_file_name, "Ranking", ranking) + return ranking, None, img_file_info + +def generate_image_reward(filenames, turn_page_switch, aes_filter_min, aes_filter_max): + global image_reward_model + if image_reward_model is None: + image_reward_model = ImageReward.load("ImageReward-v1.0") + conn, cursor = wib_db.transaction_begin() + for filename in filenames: + saved_image_reward_score, saved_image_reward_prompt = wib_db.select_image_reward_score(cursor, filename) + if saved_image_reward_score is None and saved_image_reward_prompt is not None: + with torch.no_grad(): + image_reward_score = image_reward_model.score(saved_image_reward_prompt, filename) + image_reward_score = f"{image_reward_score:.2f}" + try: + logger.warning(f"Generated ImageRewardScore: {image_reward_score} for {filename}") + except UnicodeEncodeError: + pass + wib_db.update_image_reward_score(cursor, filename, image_reward_score) + if any(filename.endswith(ext) for ext in image_ext_list): + img_file_info = update_exif(filename, "ImageRewardScore", image_reward_score) + wib_db.transaction_end(conn, cursor) + return -turn_page_switch, aes_filter_min, aes_filter_max + +def create_tab(tab: ImageBrowserTab, current_gr_tab: gr.Tab): + global init, exif_cache, aes_cache, image_reward_cache, openoutpaint, controlnet, js_dummy_return + dir_name = None + others_dir = False + maint = False + standard_ui = True + path_recorder = {} + path_recorder_formatted = [] + path_recorder_unformatted = [] + + if init: + db_version = wib_db.check() + logger.debug(f"db_version: {db_version}") + exif_cache = wib_db.load_exif_data(exif_cache) + aes_cache = wib_db.load_exif_data_by_key(aes_cache, "aesthetic_score", "Score") + image_reward_cache = wib_db.load_exif_data_by_key(image_reward_cache, "ImageRewardScore", "ImageRewardScore") + init = False + + path_recorder, path_recorder_formatted, path_recorder_unformatted = read_path_recorder() + openoutpaint = check_ext("openoutpaint") + controlnet = check_ext("controlnet") + + if tab.name == "Others": + others_dir = True + standard_ui = False + elif tab.name == "Maintenance": + maint = True + standard_ui = False + else: + dir_name = tab.path + + if standard_ui: + dir_name = str(Path(dir_name)) + if not os.path.exists(dir_name): + os.makedirs(dir_name) + + with gr.Row(): + path_recorder = gr.State(path_recorder) + with gr.Column(scale=10): + warning_box = gr.HTML("

 ", elem_id=f"{tab.base_tag}_image_browser_warning_box") + with gr.Column(scale=5, visible=(tab.name==favorite_tab_name)): + gr.HTML(f"

Favorites path from settings: {opts.outdir_save}") + + with gr.Row(visible=others_dir): + with gr.Column(scale=10): + img_path = gr.Textbox(dir_name, label="Images directory", placeholder="Input images directory", interactive=others_dir) + with gr.Column(scale=1): + img_path_depth = gr.Number(value="0", label="Sub directory depth") + with gr.Column(scale=1): + img_path_save_button = gr.Button(value="Add to / replace in saved directories") + + with gr.Row(visible=others_dir): + with gr.Column(scale=10): + img_path_browser = gr.Dropdown(choices=path_recorder_formatted, label="Saved directories") + with gr.Column(scale=1): + img_path_remove_button = gr.Button(value="Remove from saved directories") + + with gr.Row(visible=others_dir): + with gr.Column(scale=10): + img_path_subdirs = gr.Dropdown(choices=[none_select], value=none_select, label="Sub directories", interactive=True, elem_id=f"{tab.base_tag}_img_path_subdirs") + with gr.Column(scale=1): + img_path_subdirs_button = gr.Button(value="Get sub directories") + + with gr.Row(visible=standard_ui, elem_id=f"{tab.base_tag}_image_browser") as main_panel: + with gr.Column(): + with gr.Row(): + with gr.Column(scale=2): + with gr.Row(elem_id=f"{tab.base_tag}_image_browser_gallery_controls") as gallery_controls_panel: + with gr.Column(scale=2, min_width=20): + first_page = gr.Button("First Page", elem_id=f"{tab.base_tag}_control_image_browser_first_page") + with gr.Column(scale=2, min_width=20): + prev_page = gr.Button("Prev Page", elem_id=f"{tab.base_tag}_control_image_browser_prev_page") + with gr.Column(scale=2, min_width=20): + page_index = gr.Number(value=1, label="Page Index", elem_id=f"{tab.base_tag}_control_image_browser_page_index") + with gr.Column(scale=1, min_width=20): + refresh_index_button = ToolButton(value=refresh_symbol, elem_id=f"{tab.base_tag}_control_image_browser_refresh_index") + with gr.Column(scale=2, min_width=20): + next_page = gr.Button("Next Page", elem_id=f"{tab.base_tag}_control_image_browser_next_page") + with gr.Column(scale=2, min_width=20): + end_page = gr.Button("End Page", elem_id=f"{tab.base_tag}_control_image_browser_end_page") + with gr.Row(visible=False) as ranking_panel: + with gr.Column(scale=1, min_width=20): + ranking_current = gr.Textbox(value="None", label="Current ranking", interactive=False) + with gr.Column(scale=4, min_width=20): + ranking = gr.Radio(choices=["1", "2", "3", "4", "5", "None"], label="Set ranking to", elem_id=f"{tab.base_tag}_control_image_browser_ranking", interactive=True) + with gr.Row(): + image_gallery = gr.Gallery(show_label=False, elem_id=f"{tab.base_tag}_image_browser_gallery").style(grid=opts.image_browser_page_columns) + with gr.Row() as delete_panel: + with gr.Column(scale=1): + delete_num = gr.Number(value=1, interactive=True, label="delete next", elem_id=f"{tab.base_tag}_image_browser_del_num") + delete_confirm = gr.Checkbox(value=False, label="also delete off-screen images") + with gr.Column(scale=3): + delete = gr.Button('Delete', elem_id=f"{tab.base_tag}_image_browser_del_img_btn") + with gr.Row() as info_add_panel: + with gr.Accordion("Additional Generation Info", open=False): + img_file_info_add = gr.HTML() + + with gr.Column(scale=1): + with gr.Row() as sort_panel: + sort_by = gr.Dropdown(value="date", choices=["path name", "date", "aesthetic_score", "ImageRewardScore", "random", "cfg scale", "steps", "seed", "sampler", "size", "model", "model hash", "ranking"], label="Sort by") + sort_order = ToolButton(value=down_symbol) + with gr.Row() as filename_search_panel: + filename_keyword_search = gr.Textbox(value="", label="Filename keyword search") + with gr.Box() as exif_search_panel: + with gr.Row(): + exif_keyword_search = gr.Textbox(value="", label="EXIF keyword search") + negative_prompt_search = gr.Radio(value="No", choices=["No", "Yes", "Only"], label="Search negative prompt", interactive=True) + with gr.Row(): + case_sensitive = gr.Checkbox(value=False, label="case sensitive") + use_regex = gr.Checkbox(value=False, label=r"regex - e.g. ^(?!.*Hires).*$") + with gr.Box() as ranking_filter_panel: + with gr.Row(): + ranking_filter = gr.Radio(value="All", choices=["All", "1", "2", "3", "4", "5", "None", "Min-max"], label="Ranking filter", interactive=True) + with gr.Row(): + with gr.Column(scale=2, min_width=20): + ranking_filter_min = gr.Textbox(value="1", label="Minimum ranking", interactive=False) + with gr.Column(scale=2, min_width=20): + ranking_filter_max = gr.Textbox(value="5", label="Maximum ranking", interactive=False) + with gr.Column(scale=4, min_width=20): + gr.Textbox(value="Choose Min-max to activate these controls", label="", interactive=False) + with gr.Box() as aesthetic_score_filter_panel: + with gr.Row(): + with gr.Column(scale=4, min_width=20): + score_type = gr.Dropdown(value=opts.image_browser_scoring_type, choices=["aesthetic_score", "ImageReward Score"], label="Scoring type", interactive=True) + with gr.Column(scale=2, min_width=20): + image_reward_button = gr.Button(value="Generate ImageReward Scores for all images", interactive=image_reward_installed, visible=False) + with gr.Row(): + aes_filter_min = gr.Textbox(value="", label="Minimum score") + aes_filter_max = gr.Textbox(value="", label="Maximum score") + with gr.Row() as generation_info_panel: + img_file_info = gr.Textbox(label="Generation Info", interactive=False, lines=6,elem_id=f"{tab.base_tag}_image_browser_file_info") + with gr.Row() as filename_panel: + img_file_name = gr.Textbox(value="", label="File Name", interactive=False) + with gr.Row() as filetime_panel: + img_file_time= gr.HTML() + with gr.Row() as open_folder_panel: + open_folder_button = gr.Button(folder_symbol, visible=standard_ui or others_dir) + gr.HTML(" ") + gr.HTML(" ") + gr.HTML(" ") + with gr.Row(elem_id=f"{tab.base_tag}_image_browser_button_panel", visible=False) as button_panel: + with gr.Column(): + with gr.Row(): + if tab.name == favorite_tab_name: + favorites_btn_show = False + else: + favorites_btn_show = True + favorites_btn = gr.Button(f'{copy_move[opts.image_browser_copy_image]} to favorites', elem_id=f"{tab.base_tag}_image_browser_favorites_btn", visible=favorites_btn_show) + try: + send_to_buttons = modules.generation_parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"]) + except: + pass + sendto_openoutpaint = gr.Button("Send to openOutpaint", elem_id=f"{tab.base_tag}_image_browser_openoutpaint_btn", visible=openoutpaint) + with gr.Row(visible=controlnet): + sendto_controlnet_txt2img = gr.Button("Send to txt2img ControlNet", visible=controlnet) + sendto_controlnet_img2img = gr.Button("Send to img2img ControlNet", visible=controlnet) + controlnet_max = opts.data.get("control_net_max_models_num", 1) + sendto_controlnet_num = gr.Dropdown([str(i) for i in range(controlnet_max)], label="ControlNet number", value="0", interactive=True, visible=(controlnet and controlnet_max > 1)) + if controlnet_max is None: + sendto_controlnet_type = gr.Textbox(value="none", visible=False) + elif controlnet_max == 1: + sendto_controlnet_type = gr.Textbox(value="single", visible=False) + else: + sendto_controlnet_type = gr.Textbox(value="multiple", visible=False) + with gr.Row(elem_id=f"{tab.base_tag}_image_browser_to_dir_panel", visible=False) as to_dir_panel: + with gr.Box(): + with gr.Row(): + to_dir_path = gr.Textbox(label="Directory path") + with gr.Row(): + to_dir_saved = gr.Dropdown(choices=path_recorder_unformatted, label="Saved directories") + with gr.Row(): + to_dir_btn = gr.Button(f'{copy_move[opts.image_browser_copy_image]} to directory', elem_id=f"{tab.base_tag}_image_browser_to_dir_btn") + + with gr.Row(): + collected_warning = gr.HTML() + + with gr.Row(visible=False): + renew_page = gr.Button("Renew Page", elem_id=f"{tab.base_tag}_image_browser_renew_page") + visible_img_num = gr.Number() + tab_base_tag_box = gr.Textbox(tab.base_tag) + image_index = gr.Textbox(value=-1, elem_id=f"{tab.base_tag}_image_browser_image_index") + set_index = gr.Button('set_index', elem_id=f"{tab.base_tag}_image_browser_set_index") + filenames = gr.State([]) + hidden = gr.Image(type="pil", elem_id=f"{tab.base_tag}_image_browser_hidden_image") + image_page_list = gr.Textbox(elem_id=f"{tab.base_tag}_image_browser_image_page_list") + info1 = gr.Textbox() + info2 = gr.Textbox() + load_switch = gr.Textbox(value="load_switch", label="load_switch") + to_dir_load_switch = gr.Textbox(value="to dir load_switch", label="to_dir_load_switch") + turn_page_switch = gr.Number(value=1, label="turn_page_switch") + select_image = gr.Number(value=1) + img_path_add = gr.Textbox(value="add") + img_path_remove = gr.Textbox(value="remove") + favorites_path = gr.Textbox(value=opts.outdir_save) + mod_keys = "" + if opts.image_browser_mod_ctrl_shift: + mod_keys = f"{mod_keys}CS" + elif opts.image_browser_mod_shift: + mod_keys = f"{mod_keys}S" + image_browser_mod_keys = gr.Textbox(value=mod_keys, elem_id=f"{tab.base_tag}_image_browser_mod_keys") + image_browser_prompt = gr.Textbox(elem_id=f"{tab.base_tag}_image_browser_prompt") + image_browser_neg_prompt = gr.Textbox(elem_id=f"{tab.base_tag}_image_browser_neg_prompt") + js_logs = gr.Textbox() + image_browser_img_info = gr.Textbox(value="[]", elem_id=f"{tab.base_tag}_image_browser_img_info") + + # Maintenance tab + with gr.Row(visible=maint): + with gr.Column(scale=4): + gr.HTML(f"{caution_symbol} Caution: You should only use these options if you know what you are doing. {caution_symbol}") + with gr.Column(scale=3): + maint_wait = gr.HTML("Status:") + with gr.Column(scale=7): + gr.HTML(" ") + with gr.Row(visible=maint): + maint_last_msg = gr.Textbox(label="Last message", interactive=False) + with gr.Row(visible=maint): + with gr.Column(scale=1): + maint_exif_rebuild = gr.Button(value="Rebuild exif cache") + with gr.Column(scale=1): + maint_exif_delete_0 = gr.Button(value="Delete 0-entries from exif cache") + with gr.Column(scale=10): + gr.HTML(visible=False) + with gr.Row(visible=maint): + with gr.Column(scale=1): + maint_update_dirs = gr.Button(value="Update directory names in database") + with gr.Column(scale=10): + maint_update_dirs_from = gr.Textbox(label="From (full path)") + with gr.Column(scale=10): + maint_update_dirs_to = gr.Textbox(label="to (full path)") + with gr.Row(visible=maint): + with gr.Column(scale=1): + maint_reapply_ranking = gr.Button(value="Reapply ranking after moving files") + with gr.Column(scale=10): + gr.HTML(visible=False) + with gr.Row(visible=maint): + with gr.Column(scale=1): + maint_restart_debug = gr.Button(value="Restart debug") + with gr.Column(scale=10): + gr.HTML(visible=False) + with gr.Row(visible=maint): + with gr.Column(scale=1): + maint_get_js_logs = gr.Button(value="Get javascript logs") + with gr.Column(scale=10): + maint_show_logs = gr.Textbox(label="Javascript logs", lines=10, interactive=False) + with gr.Row(visible=False): + with gr.Column(scale=1): + maint_rebuild_ranking = gr.Button(value="Rebuild ranking from exif info") + with gr.Column(scale=10): + gr.HTML(visible=False) + + # Hide components based on opts.image_browser_hidden_components + hidden_component_map = { + "Sort by": sort_panel, + "Filename keyword search": filename_search_panel, + "EXIF keyword search": exif_search_panel, + "Ranking Filter": ranking_filter_panel, + "Aesthestic Score": aesthetic_score_filter_panel, + "Generation Info": generation_info_panel, + "File Name": filename_panel, + "File Time": filetime_panel, + "Open Folder": open_folder_panel, + "Send to buttons": button_panel, + "Copy to directory": to_dir_panel, + "Gallery Controls Bar": gallery_controls_panel, + "Ranking Bar": ranking_panel, + "Delete Bar": delete_panel, + "Additional Generation Info": info_add_panel + } + + if set(hidden_component_map.keys()) != set(components_list): + logger.warning(f"Invalid items present in either hidden_component_map or components_list. Make sure when adding new components they are added to both.") + + override_hidden = set() + if hasattr(opts, "image_browser_hidden_components"): + for item in opts.image_browser_hidden_components: + hidden_component_map[item].visible = False + override_hidden.add(hidden_component_map[item]) + + change_dir_outputs = [warning_box, main_panel, img_path_browser, path_recorder, load_switch, img_path, img_path_depth] + img_path.submit(change_dir, inputs=[img_path, path_recorder, load_switch, img_path_browser, img_path_depth, img_path], outputs=change_dir_outputs, show_progress=opts.image_browser_show_progress) + img_path_browser.change(change_dir, inputs=[img_path_browser, path_recorder, load_switch, img_path_browser, img_path_depth, img_path], outputs=change_dir_outputs, show_progress=opts.image_browser_show_progress) + # img_path_browser.change(browser2path, inputs=[img_path_browser], outputs=[img_path]) + to_dir_saved.change(change_dir, inputs=[to_dir_saved, path_recorder, to_dir_load_switch, to_dir_saved, img_path_depth, to_dir_path], outputs=[warning_box, main_panel, to_dir_saved, path_recorder, to_dir_load_switch, to_dir_path, img_path_depth], show_progress=opts.image_browser_show_progress) + + #delete + delete.click( + fn=delete_image, + inputs=[tab_base_tag_box, delete_num, img_file_name, filenames, image_index, visible_img_num, delete_confirm, turn_page_switch, image_page_list], + outputs=[filenames, delete_num, turn_page_switch, visible_img_num, image_gallery, select_image, image_page_list], + show_progress=opts.image_browser_show_progress + ).then( + fn=None, + _js="image_browser_select_image", + inputs=[tab_base_tag_box, image_index, select_image], + outputs=[js_dummy_return], + show_progress=opts.image_browser_show_progress + ) + + to_dir_btn.click(save_image, inputs=[img_file_name, filenames, page_index, turn_page_switch, to_dir_path], outputs=[collected_warning, filenames, page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + #turn page + first_page.click(lambda s:(1, -s) , inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + next_page.click(lambda p, s: (p + 1, -s), inputs=[page_index, turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + prev_page.click(lambda p, s: (p - 1, -s), inputs=[page_index, turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + end_page.click(lambda s: (-1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + load_switch.change(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + filename_keyword_search.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + exif_keyword_search.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + ranking_filter_min.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + ranking_filter_max.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + aes_filter_min.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + aes_filter_max.submit(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + sort_by.change(lambda s:(1, -s), inputs=[turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + page_index.submit(lambda s: -s, inputs=[turn_page_switch], outputs=[turn_page_switch], show_progress=opts.image_browser_show_progress) + renew_page.click(lambda s: -s, inputs=[turn_page_switch], outputs=[turn_page_switch], show_progress=opts.image_browser_show_progress) + refresh_index_button.click(lambda p, s:(p, -s), inputs=[page_index, turn_page_switch], outputs=[page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + img_path_depth.change(lambda s: -s, inputs=[turn_page_switch], outputs=[turn_page_switch], show_progress=opts.image_browser_show_progress) + + hide_on_thumbnail_view = [delete_panel, button_panel, ranking_panel, to_dir_panel, info_add_panel] + + sort_order.click( + fn=sort_order_flip, + inputs=[turn_page_switch, sort_order], + outputs=[page_index, turn_page_switch, sort_order], + show_progress=opts.image_browser_show_progress + ) + ranking_filter.change( + fn=ranking_filter_settings, + inputs=[page_index, turn_page_switch, ranking_filter], + outputs=[page_index, turn_page_switch, ranking_filter_min, ranking_filter_max], + show_progress=opts.image_browser_show_progress + ) + + # Others + img_path_subdirs_button.click( + fn=img_path_subdirs_get, + inputs=[img_path], + outputs=[img_path_subdirs], + show_progress=opts.image_browser_show_progress + ) + img_path_subdirs.change( + fn=change_dir, + inputs=[img_path_subdirs, path_recorder, load_switch, img_path_browser, img_path_depth, img_path], + outputs=change_dir_outputs, + show_progress=opts.image_browser_show_progress + ) + img_path_save_button.click( + fn=img_path_add_remove, + inputs=[img_path, path_recorder, img_path_add, img_path_depth], + outputs=[path_recorder, img_path_browser], + show_progress=opts.image_browser_show_progress + ) + img_path_remove_button.click( + fn=img_path_add_remove, + inputs=[img_path, path_recorder, img_path_remove, img_path_depth], + outputs=[path_recorder, img_path_browser], + show_progress=opts.image_browser_show_progress + ) + maint_exif_rebuild.click( + fn=exif_rebuild, + inputs=[maint_wait], + outputs=[maint_wait, maint_last_msg], + show_progress=True + ) + maint_exif_delete_0.click( + fn=exif_delete_0, + inputs=[maint_wait], + outputs=[maint_wait, maint_last_msg], + show_progress=True + ) + maint_update_dirs.click( + fn=exif_update_dirs, + inputs=[maint_update_dirs_from, maint_update_dirs_to, maint_wait], + outputs=[maint_wait, maint_last_msg], + show_progress=True + ) + maint_reapply_ranking.click( + fn=reapply_ranking, + inputs=[path_recorder, maint_wait], + outputs=[maint_wait, maint_last_msg], + show_progress=True + ) + maint_restart_debug.click( + fn=restart_debug, + inputs=[maint_wait], + outputs=[maint_wait, maint_last_msg], + show_progress=True + ) + maint_get_js_logs.click( + fn=js_logs_output, + _js="get_js_logs", + inputs=[js_logs], + outputs=[maint_show_logs], + show_progress=True + ) + + # other functions + if opts.image_browser_use_thumbnail: + set_index_outputs = [img_file_name, img_file_time, image_index, hidden, turn_page_switch, img_file_info_add, image_gallery] + else: + set_index_outputs = [img_file_name, img_file_time, image_index, hidden, turn_page_switch, img_file_info_add] + set_index.click(show_image_info, _js="image_browser_get_current_img", inputs=[tab_base_tag_box, image_index, page_index, filenames, turn_page_switch, image_gallery], outputs=set_index_outputs, show_progress=opts.image_browser_show_progress) + set_index.click(fn=lambda:(gr.update(visible=delete_panel not in override_hidden), gr.update(visible=button_panel not in override_hidden), gr.update(visible=ranking_panel not in override_hidden), gr.update(visible=to_dir_panel not in override_hidden), gr.update(visible=info_add_panel not in override_hidden)), inputs=None, outputs=hide_on_thumbnail_view, show_progress=opts.image_browser_show_progress) + + favorites_btn.click(save_image, inputs=[img_file_name, filenames, page_index, turn_page_switch, favorites_path], outputs=[collected_warning, filenames, page_index, turn_page_switch], show_progress=opts.image_browser_show_progress) + img_file_name.change(img_file_name_changed, inputs=[img_file_name, favorites_btn, to_dir_btn], outputs=[ranking_current, ranking, collected_warning, favorites_btn, to_dir_btn], show_progress=opts.image_browser_show_progress) + + hidden.change(fn=run_pnginfo, inputs=[hidden, img_path, img_file_name], outputs=[info1, img_file_info, info2, image_browser_prompt, image_browser_neg_prompt], show_progress=opts.image_browser_show_progress) + + #ranking + ranking.change(update_ranking, inputs=[img_file_name, ranking_current, ranking, img_file_info], outputs=[ranking_current, ranking, img_file_info], show_progress=opts.image_browser_show_progress) + + try: + modules.generation_parameters_copypaste.bind_buttons(send_to_buttons, hidden, img_file_info) + except: + pass + + if standard_ui: + current_gr_tab.select( + fn=tab_select, + inputs=[], + outputs=[path_recorder, to_dir_saved], + show_progress=opts.image_browser_show_progress + ) + open_folder_button.click( + fn=lambda: open_folder(dir_name), + inputs=[], + outputs=[], + show_progress=opts.image_browser_show_progress + ) + elif others_dir: + open_folder_button.click( + fn=open_folder, + inputs=[img_path], + outputs=[], + show_progress=opts.image_browser_show_progress + ) + if standard_ui or others_dir: + turn_page_switch.change( + fn=get_image_page, + inputs=[img_path, page_index, filenames, filename_keyword_search, sort_by, sort_order, tab_base_tag_box, img_path_depth, ranking_filter, ranking_filter_min, ranking_filter_max, aes_filter_min, aes_filter_max, score_type, exif_keyword_search, negative_prompt_search, use_regex, case_sensitive, image_reward_button], + outputs=[filenames, page_index, image_gallery, img_file_name, img_file_time, img_file_info, visible_img_num, warning_box, hidden, image_page_list, image_browser_img_info, image_reward_button], + show_progress=opts.image_browser_show_progress + ).then( + fn=None, + _js="image_browser_turnpage", + inputs=[tab_base_tag_box], + outputs=[js_dummy_return], + show_progress=opts.image_browser_show_progress + ) + turn_page_switch.change(fn=lambda:(gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)), inputs=None, outputs=hide_on_thumbnail_view, show_progress=opts.image_browser_show_progress) + sendto_openoutpaint.click( + fn=None, + inputs=[tab_base_tag_box, image_index, image_browser_prompt, image_browser_neg_prompt], + outputs=[js_dummy_return], + _js="image_browser_openoutpaint_send", + show_progress=opts.image_browser_show_progress ) + sendto_controlnet_txt2img.click( + fn=None, + inputs=[tab_base_tag_box, image_index, sendto_controlnet_num, sendto_controlnet_type], + outputs=[js_dummy_return], + _js="image_browser_controlnet_send_txt2img", + show_progress=opts.image_browser_show_progress + ) + sendto_controlnet_img2img.click( + fn=None, + inputs=[tab_base_tag_box, image_index, sendto_controlnet_num, sendto_controlnet_type], + outputs=[js_dummy_return], + _js="image_browser_controlnet_send_img2img", + show_progress=opts.image_browser_show_progress + ) + image_reward_button.click( + fn=generate_image_reward, + inputs=[filenames, turn_page_switch, aes_filter_min, aes_filter_max], + outputs=[turn_page_switch, aes_filter_min, aes_filter_max], + show_progress=True + ) + +def run_pnginfo(image, image_path, image_file_name): + if image is None: + return '', '', '', '', '' + try: + geninfo, items = images.read_info_from_image(image) + items = {**{'parameters': geninfo}, **items} + + info = '' + for key, text in items.items(): + info += f""" +

+

{plaintext_to_html(str(key))}

+

{plaintext_to_html(str(text))}

+
+ """.strip()+"\n" + except UnidentifiedImageError as e: + geninfo = None + info = "" + + if geninfo is None: + try: + filename = os.path.splitext(image_file_name)[0] + ".txt" + geninfo = "" + with open(filename) as f: + for line in f: + geninfo += line + except Exception: + logger.warning(f"run_pnginfo: No EXIF in image or txt file") + + if openoutpaint: + prompt, neg_prompt = wib_db.select_prompts(image_file_name) + if prompt == "0": + prompt = "" + if neg_prompt == "0": + neg_prompt = "" + else: + prompt = "" + neg_prompt = "" + + return '', geninfo, info, prompt, neg_prompt + + +def on_ui_tabs(): + global num_of_imgs_per_page, loads_files_num, js_dummy_return + num_of_imgs_per_page = int(opts.image_browser_page_columns * opts.image_browser_page_rows) + loads_files_num = int(opts.image_browser_pages_perload * num_of_imgs_per_page) + with gr.Blocks(analytics_enabled=False) as image_browser: + gradio_needed = "3.23.0" + if version.parse(gr.__version__) < version.parse(gradio_needed): + gr.HTML(f'

You are running Gradio version {gr.__version__}. This version of the extension requires at least Gradio version {gradio_needed}.

For more details see https://github.com/AlUlkesh/stable-diffusion-webui-images-browser/issues/116#issuecomment-1493259585

') + else: + with gr.Tabs(elem_id="image_browser_tabs_container") as tabs: + js_dummy_return = gr.Textbox(interactive=False, visible=False) + for i, tab in enumerate(tabs_list): + with gr.Tab(tab.name, elem_id=f"{tab.base_tag}_image_browser_container") as current_gr_tab: + with gr.Blocks(analytics_enabled=False): + create_tab(tab, current_gr_tab) + gr.Textbox(",".join( [tab.base_tag for tab in tabs_list] ), elem_id="image_browser_tab_base_tags_list", visible=False) + gr.Checkbox(value=opts.image_browser_swipe, elem_id=f"image_browser_swipe") + + javascript_level_value, (javascript_level, javascript_level_text) = debug_levels(arg_level="javascript") + level_value, (level, level_text) = debug_levels(arg_text=opts.image_browser_debug_level) + if level_value >= javascript_level_value: + debug_level_option = level + else: + debug_level_option = "" + gr.Textbox(value=debug_level_option, elem_id="image_browser_debug_level_option", visible=False) + + return (image_browser, "Image Browser", "image_browser"), + +def move_setting(cur_setting_name, old_setting_name, option_info, section, added): + try: + old_value = shared.opts.__getattr__(old_setting_name) + except AttributeError: + old_value = None + try: + new_value = shared.opts.__getattr__(cur_setting_name) + except AttributeError: + new_value = None + if old_value is not None and new_value is None: + # Add new option + shared.opts.add_option(cur_setting_name, shared.OptionInfo(*option_info, section=section)) + shared.opts.__setattr__(cur_setting_name, old_value) + added = added + 1 + # Remove old option + shared.opts.data.pop(old_setting_name, None) + + return added + +def on_ui_settings(): + # [current setting_name], [old setting_name], [default], [label], [component], [component_args] + active_tabs_description = f"List of active tabs (separated by commas). Available options are {', '.join(default_tab_options)}. Custom folders are also supported by specifying their path." + debug_level_choices = [] + for i in range(len(debug_level_types)): + level_value, (level, level_text) = debug_levels(arg_value=i) + debug_level_choices.append(level_text) + + image_browser_options = [ + ("image_browser_active_tabs", None, ", ".join(default_tab_options), active_tabs_description), + ("image_browser_hidden_components", None, [], "Select components to hide", DropdownMulti, lambda: {"choices": components_list}), + ("image_browser_with_subdirs", "images_history_with_subdirs", True, "Include images in sub directories"), + ("image_browser_copy_image", "images_copy_image", False, "Move buttons copy instead of move"), + ("image_browser_delete_message", "images_delete_message", True, "Print image deletion messages to the console"), + ("image_browser_txt_files", "images_txt_files", True, "Move/Copy/Delete matching .txt files"), + ("image_browser_debug_level", None, debug_level_choices[0], "Debug level", gr.Dropdown, lambda: {"choices": debug_level_choices}), + ("image_browser_delete_recycle", "images_delete_recycle", False, "Use recycle bin when deleting images"), + ("image_browser_scan_exif", "images_scan_exif", True, "Scan Exif-/.txt-data (initially slower, but required for many features to work)"), + ("image_browser_mod_shift", None, False, "Change CTRL keybindings to SHIFT"), + ("image_browser_mod_ctrl_shift", None, False, "or to CTRL+SHIFT"), + ("image_browser_enable_maint", None, True, "Enable Maintenance tab"), + ("image_browser_ranking_pnginfo", None, False, "Save ranking in image's pnginfo"), + ("image_browser_page_columns", "images_history_page_columns", 6, "Number of columns on the page"), + ("image_browser_page_rows", "images_history_page_rows", 6, "Number of rows on the page"), + ("image_browser_pages_perload", "images_history_pages_perload", 20, "Minimum number of pages per load"), + ("image_browser_use_thumbnail", None, False, "Use optimized images in the thumbnail interface (significantly reduces the amount of data transferred)"), + ("image_browser_thumbnail_size", None, 200, "Size of the thumbnails (px)"), + ("image_browser_swipe", None, False, "Swipe left/right navigates to the next image"), + ("image_browser_img_tooltips", None, True, "Enable thumbnail tooltips"), + ("image_browser_scoring_type", None, "aesthetic_score", "Default scoring type", gr.Dropdown, lambda: {"choices": ["aesthetic_score", "ImageReward Score"]}), + ("image_browser_show_progress", None, True, "Show progress indicator"), + ] + + section = ('image-browser', "Image Browser") + # Move historic setting names to current names + added = 0 + for cur_setting_name, old_setting_name, *option_info in image_browser_options: + if old_setting_name is not None: + added = move_setting(cur_setting_name, old_setting_name, option_info, section, added) + if added > 0: + shared.opts.save(shared.config_filename) + + for cur_setting_name, _, *option_info in image_browser_options: + shared.opts.add_option(cur_setting_name, shared.OptionInfo(*option_info, section=section)) + +script_callbacks.on_ui_settings(on_ui_settings) +script_callbacks.on_ui_tabs(on_ui_tabs) diff --git a/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc b/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc01b9e5440c47210ef9ce282e69274b27856eb4 Binary files /dev/null and b/stable-diffusion-webui-images-browser/scripts/wib/__pycache__/wib_db.cpython-310.pyc differ diff --git a/stable-diffusion-webui-images-browser/scripts/wib/wib_db.py b/stable-diffusion-webui-images-browser/scripts/wib/wib_db.py new file mode 100644 index 0000000000000000000000000000000000000000..4ff9ed1bb9e9b263dab3e137ec70d89d12e25036 --- /dev/null +++ b/stable-diffusion-webui-images-browser/scripts/wib/wib_db.py @@ -0,0 +1,888 @@ +import hashlib +import json +import os +import sqlite3 +from modules import scripts +from PIL import Image + +version = 6 + +path_recorder_file = os.path.join(scripts.basedir(), "path_recorder.txt") +aes_cache_file = os.path.join(scripts.basedir(), "aes_scores.json") +exif_cache_file = os.path.join(scripts.basedir(), "exif_data.json") +ranking_file = os.path.join(scripts.basedir(), "ranking.json") +archive = os.path.join(scripts.basedir(), "archive") +db_file = os.path.join(scripts.basedir(), "wib.sqlite3") +np = "Negative prompt: " +st = "Steps: " +timeout = 30 + +def create_filehash(cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS filehash ( + file TEXT PRIMARY KEY, + hash TEXT, + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + cursor.execute(''' + CREATE TRIGGER filehash_tr + AFTER UPDATE ON filehash + BEGIN + UPDATE filehash SET updated = CURRENT_TIMESTAMP WHERE file = OLD.file; + END; + ''') + + return + +def create_work_files(cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS work_files ( + file TEXT PRIMARY KEY + ) + ''') + + return + +def create_db(cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS db_data ( + key TEXT PRIMARY KEY, + value TEXT + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS path_recorder ( + path TEXT PRIMARY KEY, + depth INT, + path_display TEXT, + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + cursor.execute(''' + CREATE TRIGGER path_recorder_tr + AFTER UPDATE ON path_recorder + BEGIN + UPDATE path_recorder SET updated = CURRENT_TIMESTAMP WHERE path = OLD.path; + END; + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS exif_data ( + file TEXT, + key TEXT, + value TEXT, + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (file, key) + ) + ''') + + cursor.execute(''' + CREATE INDEX IF NOT EXISTS exif_data_key ON exif_data (key) + ''') + + cursor.execute(''' + CREATE TRIGGER exif_data_tr + AFTER UPDATE ON exif_data + BEGIN + UPDATE exif_data SET updated = CURRENT_TIMESTAMP WHERE file = OLD.file AND key = OLD.key; + END; + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS ranking ( + file TEXT PRIMARY KEY, + name TEXT, + ranking TEXT, + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + cursor.execute(''' + CREATE INDEX IF NOT EXISTS ranking_name ON ranking (name) + ''') + + cursor.execute(''' + CREATE TRIGGER ranking_tr + AFTER UPDATE ON ranking + BEGIN + UPDATE ranking SET updated = CURRENT_TIMESTAMP WHERE file = OLD.file; + END; + ''') + + create_filehash(cursor) + create_work_files(cursor) + + return + +def migrate_path_recorder(cursor): + if os.path.exists(path_recorder_file): + try: + with open(path_recorder_file) as f: + # json-version + path_recorder = json.load(f) + for path, values in path_recorder.items(): + path = os.path.realpath(path) + depth = values["depth"] + path_display = f"{path} [{depth}]" + cursor.execute(''' + INSERT INTO path_recorder (path, depth, path_display) + VALUES (?, ?, ?) + ''', (path, depth, path_display)) + except json.JSONDecodeError: + with open(path_recorder_file) as f: + # old txt-version + path = f.readline().rstrip("\n") + while len(path) > 0: + path = os.path.realpath(path) + cursor.execute(''' + INSERT INTO path_recorder (path, depth, path_display) + VALUES (?, ?, ?) + ''', (path, 0, f"{path} [0]")) + path = f.readline().rstrip("\n") + + return + +def update_exif_data(cursor, file, info): + prompt = "0" + negative_prompt = "0" + key_values = "0: 0" + if info != "0": + info_list = info.split("\n") + prompt = "" + negative_prompt = "" + key_values = "" + for info_item in info_list: + if info_item.startswith(st): + key_values = info_item + elif info_item.startswith(np): + negative_prompt = info_item.replace(np, "") + else: + if prompt == "": + prompt = info_item + else: + # multiline prompts + prompt = f"{prompt}\n{info_item}" + if key_values != "": + key_value_pairs = [] + key_value = "" + quote_open = False + for char in key_values + ",": + key_value += char + if char == '"': + quote_open = not quote_open + if char == "," and not quote_open: + try: + k, v = key_value.strip(" ,").split(": ") + except ValueError: + k = key_value.strip(" ,").split(": ")[0] + v = "" + key_value_pairs.append((k, v)) + key_value = "" + + try: + cursor.execute(''' + INSERT INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, "prompt", prompt)) + except sqlite3.IntegrityError: + # Duplicate, delete all "file" entries and try again + cursor.execute(''' + DELETE FROM exif_data + WHERE file = ? + ''', (file,)) + + cursor.execute(''' + INSERT INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, "prompt", prompt)) + + cursor.execute(''' + INSERT INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, "negative_prompt", negative_prompt)) + + for (key, value) in key_value_pairs: + try: + cursor.execute(''' + INSERT INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, key, value)) + except sqlite3.IntegrityError: + pass + + return + +def migrate_exif_data(cursor): + if os.path.exists(exif_cache_file): + with open(exif_cache_file, 'r') as file: + exif_cache = json.load(file) + + for file, info in exif_cache.items(): + file = os.path.realpath(file) + update_exif_data(cursor, file, info) + + return + +def migrate_ranking(cursor): + if os.path.exists(ranking_file): + with open(ranking_file, 'r') as file: + ranking = json.load(file) + for file, info in ranking.items(): + if info != "None": + file = os.path.realpath(file) + name = os.path.basename(file) + cursor.execute(''' + INSERT INTO ranking (file, name, ranking) + VALUES (?, ?, ?) + ''', (file, name, info)) + + return + +def get_hash(file): + # Get filehash without exif info + try: + image = Image.open(file) + except Exception as e: + print(e) + + hash = hashlib.sha512(image.tobytes()).hexdigest() + image.close() + + return hash + +def migrate_filehash(cursor, version): + if version <= "4": + create_filehash(cursor) + + cursor.execute(''' + SELECT file + FROM ranking + ''') + for (file,) in cursor.fetchall(): + if os.path.exists(file): + hash = get_hash(file) + cursor.execute(''' + INSERT INTO filehash (file, hash) + VALUES (?, ?) + ''', (file, hash)) + + return + +def migrate_work_files(cursor): + create_work_files(cursor) + + return + +def update_db_data(cursor, key, value): + cursor.execute(''' + INSERT OR REPLACE + INTO db_data (key, value) + VALUES (?, ?) + ''', (key, value)) + + return + +def get_version(): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT value + FROM db_data + WHERE key = 'version' + ''',) + db_version = cursor.fetchone() + + return db_version + +def migrate_path_recorder_dirs(cursor): + cursor.execute(''' + SELECT path, path_display + FROM path_recorder + ''') + for (path, path_display) in cursor.fetchall(): + real_path = os.path.realpath(path) + if path != real_path: + update_from = path + update_to = real_path + try: + cursor.execute(''' + UPDATE path_recorder + SET path = ?, + path_display = ? || SUBSTR(path_display, LENGTH(?) + 1) + WHERE path = ? + ''', (update_to, update_to, update_from, update_from)) + except sqlite3.IntegrityError as e: + # these are double keys, because the same file can be in the db with different path notations + (e_msg,) = e.args + if e_msg.startswith("UNIQUE constraint"): + cursor.execute(''' + DELETE FROM path_recorder + WHERE path = ? + ''', (update_from,)) + else: + raise + + return + +def migrate_exif_data_dirs(cursor): + cursor.execute(''' + SELECT file + FROM exif_data + ''') + for (filepath,) in cursor.fetchall(): + (path, file) = os.path.split(filepath) + real_path = os.path.realpath(path) + if path != real_path: + update_from = filepath + update_to = os.path.join(real_path, file) + try: + cursor.execute(''' + UPDATE exif_data + SET file = ? + WHERE file = ? + ''', (update_to, update_from)) + except sqlite3.IntegrityError as e: + # these are double keys, because the same file can be in the db with different path notations + (e_msg,) = e.args + if e_msg.startswith("UNIQUE constraint"): + cursor.execute(''' + DELETE FROM exif_data + WHERE file = ? + ''', (update_from,)) + else: + raise + + return + +def migrate_ranking_dirs(cursor, db_version): + if db_version == "1": + cursor.execute(''' + ALTER TABLE ranking + ADD COLUMN name TEXT + ''') + + cursor.execute(''' + CREATE INDEX IF NOT EXISTS ranking_name ON ranking (name) + ''') + + cursor.execute(''' + SELECT file, ranking + FROM ranking + ''') + for (filepath, ranking) in cursor.fetchall(): + if filepath == "" or ranking == "None": + cursor.execute(''' + DELETE FROM ranking + WHERE file = ? + ''', (filepath,)) + else: + (path, file) = os.path.split(filepath) + real_path = os.path.realpath(path) + name = file + update_from = filepath + update_to = os.path.join(real_path, file) + try: + cursor.execute(''' + UPDATE ranking + SET file = ?, + name = ? + WHERE file = ? + ''', (update_to, name, update_from)) + except sqlite3.IntegrityError as e: + # these are double keys, because the same file can be in the db with different path notations + (e_msg,) = e.args + if e_msg.startswith("UNIQUE constraint"): + cursor.execute(''' + DELETE FROM ranking + WHERE file = ? + ''', (update_from,)) + else: + raise + + return + +def check(): + if not os.path.exists(db_file): + conn, cursor = transaction_begin() + print("Image Browser: Creating database") + create_db(cursor) + update_db_data(cursor, "version", version) + migrate_path_recorder(cursor) + migrate_exif_data(cursor) + migrate_ranking(cursor) + migrate_filehash(cursor, str(version)) + transaction_end(conn, cursor) + print("Image Browser: Database created") + db_version = get_version() + conn, cursor = transaction_begin() + if db_version[0] <= "2": + # version 1 database had mixed path notations, changed them all to abspath + # version 2 database still had mixed path notations, because of windows short name, changed them all to realpath + print(f"Image Browser: Upgrading database from version {db_version[0]} to version {version}") + migrate_path_recorder_dirs(cursor) + migrate_exif_data_dirs(cursor) + migrate_ranking_dirs(cursor, db_version[0]) + if db_version[0] <= "4": + migrate_filehash(cursor, db_version[0]) + if db_version[0] <= "5": + migrate_work_files(cursor) + update_db_data(cursor, "version", version) + print(f"Image Browser: Database upgraded from version {db_version[0]} to version {version}") + transaction_end(conn, cursor) + + return version + +def load_path_recorder(): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT path, depth, path_display + FROM path_recorder + ''') + path_recorder = {path: {"depth": depth, "path_display": path_display} for path, depth, path_display in cursor.fetchall()} + + return path_recorder + +def select_ranking(file): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT ranking + FROM ranking + WHERE file = ? + ''', (file,)) + ranking_value = cursor.fetchone() + + if ranking_value is None: + return_ranking = "None" + else: + (return_ranking,) = ranking_value + + return return_ranking + +def update_ranking(file, ranking): + name = os.path.basename(file) + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + if ranking == "None": + cursor.execute(''' + DELETE FROM ranking + WHERE file = ? + ''', (file,)) + else: + cursor.execute(''' + INSERT OR REPLACE + INTO ranking (file, name, ranking) + VALUES (?, ?, ?) + ''', (file, name, ranking)) + + hash = get_hash(file) + cursor.execute(''' + INSERT OR REPLACE + INTO filehash (file, hash) + VALUES (?, ?) + ''', (file, hash)) + + return + +def select_image_reward_score(cursor, file): + cursor.execute(''' + SELECT value + FROM exif_data + WHERE file = ? + AND key = 'ImageRewardScore' + ''', (file,)) + image_reward_score = cursor.fetchone() + if image_reward_score is None: + return_image_reward_score = None + else: + (return_image_reward_score,) = image_reward_score + cursor.execute(''' + SELECT value + FROM exif_data + WHERE file = ? + AND key = 'prompt' + ''', (file,)) + image_reward_prompt = cursor.fetchone() + if image_reward_prompt is None: + return_image_reward_prompt = None + else: + (return_image_reward_prompt,) = image_reward_prompt + + return return_image_reward_score, return_image_reward_prompt + +def update_image_reward_score(cursor, file, image_reward_score): + cursor.execute(''' + INSERT OR REPLACE + INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, "ImageRewardScore", image_reward_score)) + + return + +def update_path_recorder(path, depth, path_display): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + INSERT OR REPLACE + INTO path_recorder (path, depth, path_display) + VALUES (?, ?, ?) + ''', (path, depth, path_display)) + + return + +def update_path_recorder(path, depth, path_display): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + INSERT OR REPLACE + INTO path_recorder (path, depth, path_display) + VALUES (?, ?, ?) + ''', (path, depth, path_display)) + + return + +def delete_path_recorder(path): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + DELETE FROM path_recorder + WHERE path = ? + ''', (path,)) + + return + +def update_path_recorder_mult(cursor, update_from, update_to): + cursor.execute(''' + UPDATE path_recorder + SET path = ?, + path_display = ? || SUBSTR(path_display, LENGTH(?) + 1) + WHERE path = ? + ''', (update_to, update_to, update_from, update_from)) + + return + +def update_exif_data_mult(cursor, update_from, update_to): + update_from = update_from + os.path.sep + update_to = update_to + os.path.sep + cursor.execute(''' + UPDATE exif_data + SET file = ? || SUBSTR(file, LENGTH(?) + 1) + WHERE file like ? || '%' + ''', (update_to, update_from, update_from)) + + return + +def update_ranking_mult(cursor, update_from, update_to): + update_from = update_from + os.path.sep + update_to = update_to + os.path.sep + cursor.execute(''' + UPDATE ranking + SET file = ? || SUBSTR(file, LENGTH(?) + 1) + WHERE file like ? || '%' + ''', (update_to, update_from, update_from)) + + return + +def delete_exif_0(cursor): + cursor.execute(''' + DELETE FROM exif_data + WHERE file IN ( + SELECT file FROM exif_data a + WHERE value = '0' + GROUP BY file + HAVING COUNT(*) = (SELECT COUNT(*) FROM exif_data WHERE file = a.file) + ) + ''') + + return + +def get_ranking_by_file(cursor, file): + cursor.execute(''' + SELECT ranking + FROM ranking + WHERE file = ? + ''', (file,)) + ranking_value = cursor.fetchone() + + return ranking_value + +def get_ranking_by_name(cursor, name): + cursor.execute(''' + SELECT file, ranking + FROM ranking + WHERE name = ? + ''', (name,)) + ranking_value = cursor.fetchone() + + if ranking_value is not None: + (file, _) = ranking_value + cursor.execute(''' + SELECT hash + FROM filehash + WHERE file = ? + ''', (file,)) + hash_value = cursor.fetchone() + else: + hash_value = None + + return ranking_value, hash_value + +def insert_ranking(cursor, file, ranking, hash): + name = os.path.basename(file) + cursor.execute(''' + INSERT INTO ranking (file, name, ranking) + VALUES (?, ?, ?) + ''', (file, name, ranking)) + + cursor.execute(''' + INSERT OR REPLACE + INTO filehash (file, hash) + VALUES (?, ?) + ''', (file, hash)) + + return + +def replace_ranking(cursor, file, alternate_file, hash): + name = os.path.basename(file) + cursor.execute(''' + UPDATE ranking + SET file = ? + WHERE file = ? + ''', (file, alternate_file)) + + cursor.execute(''' + INSERT OR REPLACE + INTO filehash (file, hash) + VALUES (?, ?) + ''', (file, hash)) + + return + +def transaction_begin(): + conn = sqlite3.connect(db_file, timeout=timeout) + conn.isolation_level = None + cursor = conn.cursor() + cursor.execute("BEGIN") + return conn, cursor + +def transaction_end(conn, cursor): + cursor.execute("COMMIT") + conn.close() + return + +def update_exif_data_by_key(cursor, file, key, value): + cursor.execute(''' + INSERT OR REPLACE + INTO exif_data (file, key, value) + VALUES (?, ?, ?) + ''', (file, key, value)) + + return + +def select_prompts(file): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT key, value + FROM exif_data + WHERE file = ? + AND KEY in ('prompt', 'negative_prompt') + ''', (file,)) + + rows = cursor.fetchall() + prompt = "" + neg_prompt = "" + for row in rows: + (key, value) = row + if key == 'prompt': + prompt = value + elif key == 'negative_prompt': + neg_prompt = value + + return prompt, neg_prompt + +def load_exif_data(exif_cache): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT file, group_concat( + case when key = 'prompt' or key = 'negative_prompt' then key || ': ' || value || '\n' + else key || ': ' || value + end, ', ') AS string + FROM ( + SELECT * + FROM exif_data + ORDER BY + CASE WHEN key = 'prompt' THEN 0 + WHEN key = 'negative_prompt' THEN 1 + ELSE 2 END, + key + ) + GROUP BY file + ''') + + rows = cursor.fetchall() + for row in rows: + exif_cache[row[0]] = row[1] + + return exif_cache + +def load_exif_data_by_key(cache, key1, key2): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT file, value + FROM exif_data + WHERE key IN (?, ?) + ''', (key1, key2)) + + rows = cursor.fetchall() + for row in rows: + cache[row[0]] = row[1] + + return cache + +def get_exif_dirs(): + with sqlite3.connect(db_file, timeout=timeout) as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT file + FROM exif_data + ''') + + rows = cursor.fetchall() + + dirs = {} + for row in rows: + dir = os.path.dirname(row[0]) + dirs[dir] = dir + + return dirs + +def fill_work_files(cursor, fileinfos): + filenames = [x[0] for x in fileinfos] + + cursor.execute(''' + DELETE + FROM work_files + ''') + + sql = ''' + INSERT INTO work_files (file) + VALUES (?) + ''' + + cursor.executemany(sql, [(x,) for x in filenames]) + + return + +def filter_aes(cursor, fileinfos, aes_filter_min_num, aes_filter_max_num, score_type): + if score_type == "aesthetic_score": + key = "aesthetic_score" + else: + key = "ImageRewardScore" + + cursor.execute(''' + DELETE + FROM work_files + WHERE file not in ( + SELECT file + FROM exif_data b + WHERE file = b.file + AND b.key = ? + AND CAST(b.value AS REAL) between ? and ? + ) + ''', (key, aes_filter_min_num, aes_filter_max_num)) + + cursor.execute(''' + SELECT file + FROM work_files + ''') + + rows = cursor.fetchall() + + fileinfos_dict = {pair[0]: pair[1] for pair in fileinfos} + fileinfos_new = [] + for (file,) in rows: + if fileinfos_dict.get(file) is not None: + fileinfos_new.append((file, fileinfos_dict[file])) + + return fileinfos_new + +def filter_ranking(cursor, fileinfos, ranking_filter, ranking_filter_min_num, ranking_filter_max_num): + if ranking_filter == "None": + cursor.execute(''' + DELETE + FROM work_files + WHERE file IN ( + SELECT file + FROM ranking b + WHERE file = b.file + ) + ''') + elif ranking_filter == "Min-max": + cursor.execute(''' + DELETE + FROM work_files + WHERE file NOT IN ( + SELECT file + FROM ranking b + WHERE file = b.file + AND b.ranking BETWEEN ? AND ? + ) + ''', (ranking_filter_min_num, ranking_filter_max_num)) + else: + cursor.execute(''' + DELETE + FROM work_files + WHERE file NOT IN ( + SELECT file + FROM ranking b + WHERE file = b.file + AND b.ranking = ? + ) + ''', (ranking_filter,)) + + cursor.execute(''' + SELECT file + FROM work_files + ''') + + rows = cursor.fetchall() + + fileinfos_dict = {pair[0]: pair[1] for pair in fileinfos} + fileinfos_new = [] + for (file,) in rows: + if fileinfos_dict.get(file) is not None: + fileinfos_new.append((file, fileinfos_dict[file])) + + return fileinfos_new + +def select_x_y(cursor, file): + cursor.execute(''' + SELECT value + FROM exif_data + WHERE file = ? + AND key = 'Size' + ''', (file,)) + size_value = cursor.fetchone() + + if size_value is None: + x = "?" + y = "?" + else: + (size,) = size_value + parts = size.split("x") + x = parts[0] + y = parts[1] + + return x, y \ No newline at end of file diff --git a/stable-diffusion-webui-images-browser/style.css b/stable-diffusion-webui-images-browser/style.css new file mode 100644 index 0000000000000000000000000000000000000000..e794b003666aa6377490a49c42737f20f9421688 --- /dev/null +++ b/stable-diffusion-webui-images-browser/style.css @@ -0,0 +1,11 @@ +.thumbnails.svelte-1tkea93.svelte-1tkea93 { + justify-content: initial; +} + +div[id^="image_browser_tab"][id$="image_browser_gallery"].hide_loading > .svelte-gjihhp { + display: none; +} + +.image_browser_gallery img { + object-fit: scale-down !important; +} diff --git a/stable-diffusion-webui-images-browser/wib.sqlite3 b/stable-diffusion-webui-images-browser/wib.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..758c3c8a02ed253702e00d39cd75d6d03f30b8e3 Binary files /dev/null and b/stable-diffusion-webui-images-browser/wib.sqlite3 differ diff --git a/stable-diffusion-webui-localization-zh_Hans/LICENSE b/stable-diffusion-webui-localization-zh_Hans/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..211d32e752cb61bd056436e8f7a806f12a626bb7 --- /dev/null +++ b/stable-diffusion-webui-localization-zh_Hans/LICENSE @@ -0,0 +1,663 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (c) 2023 AUTOMATIC1111 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/stable-diffusion-webui-localization-zh_Hans/README.md b/stable-diffusion-webui-localization-zh_Hans/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0085ad10645bfb3a51a40c90b88cbce1c68445f9 --- /dev/null +++ b/stable-diffusion-webui-localization-zh_Hans/README.md @@ -0,0 +1,21 @@ +# stable-diffusion-webui-localization-zh_Hans + +简体中文翻译扩展,适用于 [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)。 + +每 1 小时从翻译平台拉取快照。 + +- `zh-Hans (Stable)` 仅包含平台中标记已审阅的字串 +- `zh-Hans (Testing)` 包含所有翻译平台内含有译文的字串 + +交流群:https://pd.qq.com/s/gi9dr6skp + +## 安装 + +以下方式二选一: + +- **(推荐)** 通过开启 [启动器](https://www.bilibili.com/video/BV1ne4y1V7QU) 高级选项内 “启用云端页面汉化” 开关。 +- 通过安装扩展: + - 国内: + - `https://gitcode.net/overbill1683/stable-diffusion-webui-localization-zh_Hans.git` + - `https://jihulab.com/hunter0725/stable-diffusion-webui-localization-zh_Hans.git` + - 国际:`https://github.com/hanamizuki-ai/stable-diffusion-webui-localization-zh_Hans.git` diff --git a/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Stable).json b/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Stable).json new file mode 100644 index 0000000000000000000000000000000000000000..8d0a44f39ccd20bf967f233280a7d78bfdf358eb --- /dev/null +++ b/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Stable).json @@ -0,0 +1,1817 @@ +{ + "180 Degree Rotation" : "180 度旋转", + "1. Get Model Info by Civitai Url" : "从 Civitai 链接拉取模型信息", + "1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'" : "第一个和最后一个数字必须是 0,其他值应介于 0 和 1 之间。如:’0, 0.01, 0’", + "1st and last digit must be 1. ex:'1, 2, 1'" : "第一个和最后一个数字必须是 1。例:'1, 2, 1'", + "2D operator that scales the canvas size, multiplicatively. [static = 1.0]" : "缩放画布大小的2D操作符,以倍数缩放。[static=1.0]", + "2D operator to rotate canvas clockwise/anticlockwise in degrees per frame" : "2D 操作器对每帧动画顺时针/逆时针旋转所指定的角度", + "2D or 3D animation_mode" : "2D 或 3D 动画模式中", + "360 Panorama to 3D" : "360°全景图转 3D", + "3d glb" : "3D (GLB 格式)", + "3D Openpose" : "3D 骨架模型编辑 (3D Openpose)", + "3. Download Model" : "下载模型", + "90 Degree Rotation" : "90 度旋转", + "A, B or C" : "A, B 或 C", + "About" : "关于", + "Abs" : "绝对值", + "abs. path or url to audio file" : "音频文件的绝对路径或 URL", + "Access results in ‘Open results’." : "点击“打开最终效果图”获取增强后的图片", + "Action" : "操作", + "Action on existing caption" : "对已有标注的操作", + "Actions" : "其他操作", + "Activation keywords, comma-separated" : "该模型的触发词,以逗号分隔", + "Active" : "启用", + "Adaptive (Gaussian)" : "自适应(高斯)", + "Adaptive (Mean)" : "自适应(平均值)", + "➕ Add" : "➕ 添加", + "Add" : "添加", + "Add a second progress bar to the console that shows progress for an entire job." : "向控制台添加第二个进度条以显示作业的整体进度", + "add audio to video from file/url or init video" : "从文件/链接或初始化视频中提取音频", + "Add background image" : "添加背景图片", + "Add Background image" : "添加背景图片", + "Add Background Image" : "添加背景图片", + "Add difference" : "差额叠加", + "Add difference:A+(B-C)*alpha" : "差额叠加: A+(B-C)*α", + "Add extended info (seed, prompt) to filename when saving grid" : "保存网格图时,将扩展信息(随机种子、提示词)添加到文件名", + "Add hypernetwork to prompt" : "将 hypernetwork 添加到提示词", + "Additional Generation Info" : "附加生成信息", + "Additional tags (split by comma)" : "附加提示词 (逗号分隔)", + "Add layer normalization" : "启用网络层标准化处理", + "Add Lora to prompt" : "将 Lora 添加到提示词", + "Add LyCORIS to prompt" : "将 LyCORIS 添加到提示词", + "Add model hash to generation information" : "将模型哈希值添加到生成信息", + "Add model name to generation information" : "将模型名称添加到生成信息", + "AddNet Model 1" : "附加模型 1", + "AddNet Model 2" : "附加模型 2", + "AddNet Model 3" : "附加模型 3", + "AddNet Model 4" : "附加模型 4", + "AddNet Model 5" : "附加模型 5", + "AddNet TEnc Weight 1" : "附加模型 1 Text Encoder 权重", + "AddNet TEnc Weight 2" : "附加模型 2 Text Encoder 权重", + "AddNet TEnc Weight 3" : "附加模型 3 Text Encoder 权重", + "AddNet TEnc Weight 4" : "附加模型 4 Text Encoder 权重", + "AddNet TEnc Weight 5" : "附加模型 5 Text Encoder 权重", + "AddNet UNet Weight 1" : "附加模型 1 UNet 权重", + "AddNet UNet Weight 2" : "附加模型 2 UNet 权重", + "AddNet UNet Weight 3" : "附加模型 3 UNet 权重", + "AddNet UNet Weight 4" : "附加模型 4 UNet 权重", + "AddNet UNet Weight 5" : "附加模型 5 UNet 权重", + "AddNet Weight 1" : "附加模型 1 权重", + "AddNet Weight 2" : "附加模型 2 权重", + "AddNet Weight 3" : "附加模型 3 权重", + "AddNet Weight 4" : "附加模型 4 权重", + "AddNet Weight 5" : "附加模型 5 权重", + "Add number to filename when saving" : "在文件名前添加序号", + "Add/Remove..." : "添加/删除...", + "Add soundtrack" : "添加音轨", + "'add_soundtrack' and 'soundtrack_path' aren't being honoured in \"Interpolate an existing video\" mode. Original vid audio will be used instead with the same slow-mo rules above." : "‘添加音频’和‘音频路径’将不会在‘插入现有视频’模式中执行,原有视频的音频将会使用相同的慢动作规则设置", + "Add to Sequence X" : "添加到 X 轴", + "Add to Sequence Y" : "添加到 Y 轴", + "Add weights to Sequence X" : "将权重添加到 X 序列中", + "ADetailer CFG scale" : "After Detailer 提示词引导系数 (CFG scale)", + "ADetailer confidence threshold %" : "置信阈值 (单位: %)", + "ADetailer denoising strength" : "重绘幅度", + "ADetailer erosion (-) / dilation (+)" : "图像腐蚀 (-) / 图像膨胀 (+)", + "ADetailer mask blur" : "蒙版边缘模糊度", + "ADetailer model" : "After Detailer 模型", + "ADetailer negative prompt" : "After Detailer 反向提示词", + "ADetailer prompt" : "After Detailer 正向提示词", + "ADetailer x(→) offset" : "X轴 (→) 偏移", + "ADetailer y(↑) offset" : "Y轴 (↑) 偏移", + "A directory on the same machine where the server is running." : "服务器主机上某一文件夹", + "adjusts the overall contrast per frame [default neutral at 1.0]" : "调整每帧的整体对比度[默认值为1.0]", + "adjust the brightness of the mask. Should be a positive number, with 1.0 meaning no adjustment." : "调整蒙版的亮度。该值应该为正数,1.0 表示无调整", + "Admirable" : "极好的", + "ads" : "含广告", + "Advanced" : "高级", + "Affine" : "仿射", + "all" : "全部", + "All" : "全部", + "Allow detectmap auto saving" : "允许自动保存检测图 (detected maps)", + "Allow img2img" : "允许图生图", + "Allow NSFW" : "允许 NSFW", + "Allow other script to control this extension" : "允许其他脚本控制此扩展", + "allow overwrite" : "允许覆盖文件", + "Allow overwrite output-model" : "允许输出时覆盖同名模型", + "Allow Preview" : "允许预览", + "\uD83D\uDD04 All Reset" : "\uD83D\uDD04 全部重置", + "alpha" : "α", + "Alphabetical Order" : "字母顺序", + "alpha threshold" : "透明度阈值", + "Alpha threshold" : "透明度阈值", + "also delete off-screen images" : "允许同时删除屏幕外的图片", + "alternate" : "交替", + "Alternatively, use" : "或者,使用", + "Alternatively, you can enable" : "或者,您可以启用", + "Always discard next-to-last sigma" : "始终舍弃倒数第二个 sigma 值", + "Always Display Buttons" : "总是显示按钮", + "Always print all generation info to standard output" : "始终将所有生成信息输出到控制台", + "Always save all generated image grids" : "始终保存所有生成的网格图", + "Always save all generated images" : "始终保存所有生成的图像", + "amount of presence of previous frame to influence next frame, also controls steps in the following formula [steps - (strength_schedule * steps)]" : "前一帧影响下一帧的存在量,也控制下式中的步数:[steps - (strength_schedule * steps)]", + "Amount schedule" : "数量表", + "and" : "与", + "Angle" : "角度", + "animation" : "动画", + "Animation mode" : "动画模式", + "Anime-inclined great guide (by FizzleDorf) with lots of examples:" : "有许多有关动漫方向非常好的指导示例(by FizzleDorf)", + "Anime Remove Background" : "动漫移除背景模式", + "Annotator resolution" : "预处理器分辨率", + "Anti Blur" : "防模糊", + "API info may not be necessary for some boorus, but certain information or posts may fail to load without it. For example, Danbooru doesn't show certain posts in search results unless you auth as a Gold tier member." : "API 信息对于某些 booru 站点可能不是必需的,但如果没有它,某些信息或图帖可能无法加载。 例如,除非你的 API 验证属于黄金会员,否则 Danbooru 可能不会在搜索结果中显示某些图帖。", + "append" : "追加", + "Append" : "追加至末尾", + "Append interrogated prompt at each iteration" : "在每次迭代时添加反推出的提示词", + "Apply" : "应用", + "Apply and restart UI" : "应用更改并重载前端", + "Apply block weight from text" : "从文本框应用分块权重值", + "Apply changes to ALL displayed images" : "将更改应用于所有已显示的图像", + "Apply color correction to img2img results to match original colors." : "对图生图结果应用颜色校正以匹配原始颜色", + "Apply horizontal Flip" : "应用水平翻转", + "Apply Horizontal Flip" : "应用水平翻转", + "Apply Presets" : "应用预设", + "Apply selected styles to current prompt" : "将所选预设样式插入到当前提示词之后", + "Apply settings" : "保存设置", + "Apply to" : "应用到", + "Apply transfer control when loading models" : "加载模型时应用控制转移", + "a random seed will be used on each frame of the animation" : "随机种子将被应用于每帧动画中", + "Area" : "区域", + "as a UI to define your animation schedules (see the Parseq section in the Init tab)." : "作为定义动画参数表的UI(请参见初始化选项卡中的参数定序器部分)。", + "A setting of 1 will cause every frame to receive diffusion in the sequence of image outputs. A setting of 2 will only diffuse on every other frame, yet motion will still be in effect. The output of images during the cadence sequence will be automatically blended, additively and saved to the specified drive. This may improve the illusion of coherence in some workflows as the content and context of an image will not change or diffuse during frames that were skipped. Higher values of 4-8 cadence will skip over a larger amount of frames and only diffuse the “Nth” frame as set by the diffusion_cadence value. This may produce more continuity in an animation, at the cost of little opportunity to add more diffused content. In extreme examples, motion within a frame will fail to produce diverse prompt context, and the space will be filled with lines or approximations of content - resulting in unexpected animation patterns and artifacts. Video Input & Interpolation modes are not affected by diffusion_cadence." : "设置为 1 将使每个帧在图像输出序列中生成图像。设置为 2 将每隔一帧进行图像生成,但运动仍然有效。间隔序列期间的图像输出将自动混合、添加并保存到指定驱动器。这可能会改善某些工作流中的一致性错觉,因为图像的内容和上下文在跳过的帧期间不会改变或扩散。更高的间隔值,例如4-8,将跳过更多的帧,并仅生成由生成间隔值设置的“第N”帧。这可能会在动画中产生更多的连续性,但几乎没有机会添加更多的扩散内容。在极端的例子中,帧内的运动将无法产生不同的提示上下文,并且空间将充满线条或近似的内容,从而导致意外的动画模式和伪影。视频输入和插值模式不受生成间隔值的影响。", + "Attention Heatmap" : "关键词热力图", + "Attention texts for visualization. (comma separated)" : "待可视化关键词 (逗号分隔)", + "Audio (if provided) will *not* be transferred to the interpolated video if Slow-Mo is enabled." : "音频(如果提供了)在以下选项启用时将不会转码压制进帧插值后的视频内:慢动作", + "Author" : "作者", + "Author of this model" : "此模型的作者", + "auto" : "自动", + "Auto" : "自动", + "autocast" : "自动转换", + "auto-delete imgs when video is ready" : "视频完成时自动删除图片", + "Auto focal point crop" : "自动面部焦点剪裁", + "Automatic" : "自动识别", + "Auto SAM" : "自动 SAM", + "Auto SAM Config" : "自动 SAM 配置", + "Auto SAM is mainly for semantic segmentation and image layout generation, which is supported based on ControlNet. You must have ControlNet extension installed, and you should not change its directory name (sd-webui-controlnet)." : "自动 SAM主要用于语义分割和图像分层,基于 ControlNet。你必须安装 ControlNet 扩展,并且不能修改目录名 (sd-webui-controlnet)。", + "Auto segmentation output" : "自动语义分割输出", + "Auto-sized crop" : "自动按比例剪裁缩放", + "Available" : "可下载", + "A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M" : "最终模型权重是前两个模型按比例相加的结果。需要 A、B 两个模型。计算公式为 A * (1 - M) + B * M", + "background color" : "背景颜色", + "Backup/Restore" : "备份/恢复", + "Bake in VAE" : "嵌入 VAE 模型", + "Balanced" : "均衡", + "Base" : "基层值", + "Base Depth" : "基础深度", + "Base Sampler" : "基础采样器", + "Basic" : "基础", + "Basic info" : "基本信息", + "Batch" : "批量处理", + "Batch count" : "总批次数", + "Batch from directory" : "批量处理文件夹", + "Batch from Directory" : "批量处理文件夹", + "Batch img2img" : "批量图生图", + "Batch name" : "文件夹名称", + "batch process" : "批量处理", + "Batch Process" : "批量处理", + "Batch size" : "单批数量", + "Batch Size" : "单批数量", + "Benchmark Data" : "基准测试数据", + "Benchmarks..." : "基准测试...", + "beta" : "β", + "Better" : "更好的", + "Bicubic" : "双三次", + "Bilinear" : "双线性", + "Bilingual Localization" : "双语对照翻译", + "blend" : "混合", + "Blend" : "混合", + "Blend factor max" : "最大混合系数", + "Blend factor slope" : "混合斜率系数", + "Blend mode" : "混合模式", + "Block ID" : "区块 ID", + "Block size" : "区块大小", + "blur" : "模糊", + "Blur" : "模糊", + "Blur amount:" : "模糊度:", + "Blur edges of final overlay mask, if used. Minimum = 0 (no blur)" : "模糊最终覆盖遮罩的边缘(如果使用)。最小值=0(无模糊)", + "border" : "边框", + "Border" : "边缘", + "box_nms_thresh" : "箱体数量阈值", + "Branch" : "分支", + "brightness" : "亮度", + "built-in" : "内置", + "By comma" : "逗号分组", + "By default, the algorithm tends to like dark images too much, if you think the output is too dark or not dark enough, you can adjust this ratio. 1 = ‘Do not darken at all’, 0 = ‘A totally black image is ok’, default = 0.9." : "默认情况下,算法倾向于生成较黑的图像,如果你认为输出的图像太黑或不够黑,你可以调整最小照明比率。1=\"完全不变暗\",0=\"全黑的图像\",默认=0.9", + "By none" : "不分组", + "By tokens" : "词元分组", + "By vectors" : "向量分组", + "By words" : "单词分组", + "Cache LDSR model in memory" : "将 LDSR 模型缓存在内存中", + "Cadence" : "生成间隔", + "calculate dimension of LoRAs(It may take a few minutes if there are many LoRAs)" : "计算 LoRA 维度 (取决于模型数量,可能需要数分钟)", + "Camera Far" : "镜头最远渲染距离", + "Camera Focal Length" : "镜头焦距", + "Camera Near" : "镜头最近渲染距离", + "Camera Parameters" : "镜头参数", + "Can be empty,indicating no translation" : "可以为空,表示无需翻译", + "Cancel" : "取消", + "canny" : "canny (边缘检测)", + "Canvas Height" : "画布高度", + "Canvas Width" : "画布宽度", + "Card height for Extra Networks (px)" : "扩展模型卡牌高度 (px)", + "Card width for Extra Networks (px)" : "扩展模型卡牌宽度 (px)", + "cascadePSP" : "CascadePSP", + "case sensitive" : "区分大小写", + "Change brightness" : "调节亮度", + "Change contrast" : "调节对比度", + "Change gain" : "调节增强强度", + "Change gamma" : "调节伽马", + "Change saturation" : "调节饱和度", + "Change your brush width to make it thinner if you want to draw something." : "绘制内容前请先调整笔刷粗细。", + "Check Console log for Downloading Status" : "检查控制台日志以查看下载信息", + "Check for updates" : "检查更新", + "Check models' new version" : "检查模型版本更新", + "Check New Version from Civitai" : "从 Civitai 上检查版本更新", + "checkpoint" : "模型", + "Checkpoint" : "模型", + "Checkpoint A" : "大模型 A", + "Checkpoint B" : "大模型 B", + "Checkpoint format" : "输出模型格式", + "Checkpoint Format" : "输出模型格式", + "Checkpoint Merger" : "模型合并", + "Checkpoint schedule" : "模型表", + "Checkpoints to cache in RAM" : "保留在内存中的 Stable Diffusion 模型数量", + "check this box to enable guided images mode" : "选中该项启用引导图像模式", + "* check your CLI for outputs" : "检查 CLI 的输出", + "Choose latent sampling method" : "选择潜变量采样方法", + "Choose mode:" : "选择模式:", + "Choose preprocessor for semantic segmentation:" : "选择语义分割的预处理器:", + "Choose your favorite mask:" : "请选择你喜欢的蒙版:", + "Civitai Helper" : "Civitai 助手", + "Civitai URL or Model ID" : "Civitai 地址或模型 ID", + "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results" : "无分类器指导信息影响尺度(Classifier Free Guidance Scale) - 图像应在多大程度上服从提示词 - 较低的值会产生更有创意的结果", + "Cleanup non-default temporary directory when starting webui" : "启动 WebUI 时清理非默认临时目录", + "Clear prompt" : "清空提示词内容", + "Clear values" : "清空数值", + "Click Enhance." : "点击“增强”按钮", + "Click here after the generation to show the video" : "生成完成后点这里显示视频", + "Click to Upload" : "点击上传", + "CLiP model" : "CLiP 模型", + "Clip skip" : "跳过 CLIP 层数", + "CLIP Skip" : "CLIP 跳过", + "CLIP skip schedule" : "跳过 CLIP 层数表", + "clip_threshold" : "裁剪阈值", + "Close" : "关闭", + "Closer is brighter" : "越近越亮", + "cluster num" : "簇数", + "Codec" : "编码器格式", + "CodeFormer visibility" : "CodeFormer 可见度", + "CodeFormer Weight" : "CodeFormer 权重", + "CodeFormer weight (0 = maximum effect, 1 = minimum effect)" : "CodeFormer 权重 (为 0 时效果最大,为 1 时效果最小)", + "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect" : "CodeFormer 权重参数;为 0 时效果最大;为 1 时效果最小", + "Coherence" : "一致性", + "color_burn" : "颜色加深", + "color_coherence" : "颜色校正", + "Color coherence" : "颜色一致性", + "Color correction factor" : "颜色校正系数", + "color_dodge" : "颜色减淡", + "Color force Grayscale" : "强制颜色空间为灰度", + "Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited." : "以逗号分割的选项卡名称列表;这里列出的选项卡将首先按顺序出现在扩展模型面板中", + "Comp alpha schedule" : "混合透明度参数表", + "Compatibility" : "兼容性", + "Comp mask type" : "比较蒙版类型", + "Composable Mask scheduling" : "可组合的蒙版表", + "Composite video with previous frame init image in" : "前一帧初始图像的合成视频在", + "Comp save extra frames" : "压缩保存额外帧", + "Config file for Adapter models" : "Adapter 模型配置文件路径", + "Config file for Control Net models" : "ControlNet 模型配置文件路径", + "Config Name" : "配置名", + "Console logging" : "控制台日志记录", + "contrast" : "对比度", + "Contrast schedule" : "对比度参数表", + "Control Mode (Guess Mode)" : "控制类型 (猜测模式)", + "ControlNet inpaint model index" : "ControlNet 的 inpaint 模型启用单元页", + "Controlnet input directory" : "ControlNet 输入目录", + "ControlNet input directory" : "ControlNet 的输入目录", + "ControlNet Input Video Path" : "ControlNet 输入视频路径", + "ControlNet is more important" : "更倾向于让 ControlNet 自由发挥", + "ControlNet Mask Video Path" : "ControlNet 视频蒙版路径", + "ControlNet model" : "ControlNet 模型", + "ControlNet number" : "ControlNet 序号", + "ControlNet Segmentation Index" : "ControlNet 语义分割序号", + "ControlNet Video Input" : "ControlNet 视频输入", + "ControlNet Video Mask Input" : "ControlNet 视频蒙版输入", + "ControlNet weight" : "ControlNet 权重", + "Controls the strength of the diffusion on the init image. 0 = disabled" : "控制初始化图像生成器的强度。 0 = 禁用", + "Control Weight" : "控制权重", + "convert" : "转换", + "Convert a 360 spherical panorama to a 3D mesh" : "将单张 360° 球形全景图转换为 3D 网格", + "Convert a single 2D image to a 3D mesh" : "将单张 3D 图像转换为 3D 网格", + "Converted checkpoints will be saved in your" : "转换出的模型将会保存在你的", + "copy" : "复制", + "Copy" : "复制", + "Copy config from" : "复制配置文件", + "Copy image to:" : "复制当前图像到: ", + "Copy Metadata" : "开始复制元数据", + "Copy metadata to other models in directory" : "将元数据复制到文件夹中的其他模型", + "\uD83D\uDCCB Copy to clipboard" : "\uD83D\uDCCB 复制到剪切板", + "Copy to ControlNet Segmentation" : "复制到 ControlNet 语义分割", + "Copy to favorites" : "复制到收藏夹", + "Copy to Inpaint Upload & ControlNet Inpainting" : "复制到局部重绘和 ControlNet 重绘", + "cosine" : "余弦", + "cosine_with_restarts" : "周期重启余弦", + "Cover image" : "封面图像", + "Create a text file next to every image with generation parameters." : "同时为每个图片创建一个文本文件储存生成参数", + "Create blank canvas" : "创建空白画布", + "Create embedding" : "创建嵌入式模型", + "Create flipped copies" : "创建水平翻转副本", + "Create From Hub" : "从 Huggingface Hub 中创建", + "Create hypernetwork" : "创建超网络模型", + "Creates animation sequence from denoised intermediate steps with video frame interpolation to achieve desired animation duration" : "利用视频插值从降噪过程的中间步骤图像中生成动画", + "CRF" : "固定码率因子 (CRF)", + "Crop and resize" : "比例裁剪后缩放", + "Crop and Resize" : "比例裁剪后缩放", + "Crop to fit" : "裁剪以适应宽高比", + "Current" : "Current (当前帧)", + "Current Cache" : "当前缓存目录", + "Current Model" : "当前模型", + "Custom Config File" : "自定义配置文件", + "Custom Name (Optional)" : "自定义名称 (可选)", + "Custom settings file" : "自定义设置文件", + "Cutoff strongly." : "强效分隔", + "Daam script" : "Daam 脚本", + "darken" : "变暗", + "Dataset directory" : "数据集目录", + "date" : "日期", + "Date" : "日期", + "debug" : "调试", + "Debug info" : "调试信息", + "Debug log" : "调试日志", + "Decoder Tile Size" : "解码器区块大小", + "Default Image CFG" : "默认图像引导系数 (CFG)", + "default variables: in \\{\\}, like \\{init_mask\\}, \\{video_mask\\}, \\{everywhere\\}" : "默认变量:\\{\\},比如 \\{init_mask\\}, \\{video_mask\\}, \\{everywhere\\}", + "Default view for Extra Networks" : "默认扩展模型视图", + "delete" : "删除", + "Delete" : "删除", + "Delete Imgs" : "删除图像", + "Delete intermediate" : "删除临时文件", + "Delete intermediate frames after GIF generation" : "生成 GIF 后删除临时帧图片", + "delete or keep raw affected (interpolated/ upscaled depending on the UI section) png imgs" : "删除或保留受影响的原始(根据UI部分进行插值/放大)png图像", + "Delete Selected Skeleton (D key)" : "删除选中骨架 (D 键)", + "Denoising" : "重绘幅度", + "Denoising strength" : "重绘幅度 (Denoising strength)", + "Depth" : "深度", + "depth_leres" : "depth_leres (LeReS 深度图估算)", + "Depth Map" : "深度图", + "depth_midas" : "depth_midas (MiDaS 深度图估算)", + "Depth (Midas/Adabins)" : "深度模式 (Midas / Adabins)", + "Depth Prediction" : "深度估计预处理", + "Depth Prediction demo" : "深度估计预处理 Demo", + "depth_zoe" : "depth_zoe (ZoE 深度图估算)", + "Description" : "描述", + "description-based:" : "基于描述:", + "Destination directory" : "目标目录", + "Detailed" : "详细设置", + "Detailed Save As" : "详细保存为", + "Details" : "详细设置", + "Detect from image" : "从图片提取", + "difference" : "差值", + "Difference" : "差分", + "Diffuse the first frame based on an image, similar to img2img." : "基于图像生成第一帧,类似于图生图", + "Directly Draw Scribbles" : "直接绘制线稿", + "directory." : "目录。", + "Directory for detected maps auto saving" : "检测图 (detected maps) 保存路径", + "Directory for saving images using the Save button" : "“保存”按钮输出文件夹", + "Directory for temporary images; leave empty for default" : "临时图像目录;默认为空", + "Directory name pattern" : "目录名称格式", + "Disable" : "禁用", + "Disable all extensions" : "禁用所有扩展", + "disabled" : "禁用", + "Disabled" : "已禁用", + "Disable during hires pass" : "在高清修复过程中停用", + "Disable for Negative prompt." : "为反向提示词禁用本插件效果", + "Discard weights with matching name" : "删除匹配键名的表达式的权重", + "display both english and target language" : "同时显示英语和目标语言", + "Display name for this model" : "此模型的显示名", + "Divisions" : "分区方式", + "Do not add watermark to images" : "不在图像上添加水印", + "Do not append detectmap to output" : "不输出检测图 (detected maps) (如深度估算图、动作检测图等)", + "Do not do anything special" : "什么都不做", + "Do not make DPM++ SDE deterministic across different batch sizes." : "保留 DPM++ SDE 采样器 在不同的批次大小之间的结果差异", + "Do not resize images" : "不调整图像大小", + "Do not save grids consisting of one picture" : "当仅有一张图时不保存网格图", + "Do not save heatmap images" : "不保存热力图图像", + "Do not show any images in results for web" : "不在浏览器输出结果中显示任何图像", + "Download" : "下载", + "Download localization template" : "导出 localization 模板", + "Download Max Size Preview" : "下载最大尺寸预览图", + "Download missing models upon reading generation parameters from prompt" : "从生成参数中的提示词读取并下载缺失的模型", + "Download missing preview images on startup" : "启动时下载缺失的模型预览图", + "Download Model" : "下载模型", + "Download NSFW (adult) preview images" : "允许下载 NSFW (成人) 预览图", + "Downscaling" : "图片缩小", + "Drawing Canvas" : "创建画布", + "Draw legend" : "包含图例注释", + "Drop File Here" : "拖拽文件到此", + "Drop Image Here" : "拖动图像至此", + "Drop Video Here" : "拖动视频至此", + "Due to ControlNet base extension's inner works it needs its models to be located at 'extensions/deforum-for-automatic1111-webui/models'. So copy, symlink or move them there until a more elegant solution is found. And, as of now, it requires use_init checked for the first run. The ControlNet extension version used in the dev process is a24089a62e70a7fae44b7bf35b51fd584dd55e25, if even with all the other options above used it still breaks, upgrade/downgrade your CN version to this one." : "因为 ControlNet 基层插件在内工作,所以需要将 ControlNet 模型置于 “extensions/deforum-for-automatic1111-webui/models”文件夹内。在更优雅的解决方法出现之前,请复制,软链接 symlink 或者移动模型。 \n同时目前为止,该插件需要在第一次运行时检查 use_init。\n用于开发进程的 ControlNet 插件版本为 a24089a62e70a7fae44b7bf35b51fd584dd55e25。如果全部按照上文使用还是损坏,请将 ControlNet 版本升级/降级到上述版本。", + "Duplicate Skeleton (X-axis)" : "复制骨架(X 轴)", + "Duplicate Skeleton (Z-axis)" : "复制骨架(Z 轴)", + "Duration" : "时长", + "during the run sequence, only frames specified by this value will be extracted, saved, and diffused upon. A value of 1 indicates that every frame is to be accounted for. Values of 2 will use every other frame for the sequence. Higher values will skip that number of frames respectively." : "在运行序列期间,只有由该值指定的帧才会被提取、保存和生成。1表示要考虑每个帧。2表示每隔一帧用于序列。较高的值将分别跳过该帧数。", + "Editing Enabled" : "开启元数据编辑", + "Edit Openpose" : "编辑 Openpose", + "Effect" : "效果", + "Effective Block Analyzer" : "高效区块分析器", + "ema-only" : "仅保留 EMA 权重", + "Embedding Learning rate" : "嵌入式模型学习率", + "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention" : "强调符:使用 (文字) 使模型更关注该文本,使用 [文字] 减少其关注度", + "empty cannot be saved" : "留空时无法保存", + "empty strings cannot be translated" : "无法翻译空的文本", + "Enable" : "启用", + "Enable AA for Downscaling." : "缩小时使用反锯齿", + "Enable AA for Upscaling." : "放大时使用反锯齿", + "Enable ADetailer" : "启用 After Detailer", + "Enable Anti Burn (and everything)" : "启用 Anti Burn", + "Enable batch mode" : "启用批处理模式", + "Enable Bilingual Localization" : "启用双语对照翻译插件", + "Enable CFG-Based guidance" : "启用基于 CFG 的引导 (CFG-Based guidance)", + "Enable checkpoint scheduling" : "启用模型表", + "Enable CLIP skip scheduling" : "启用跳过 CLIP 层数表", + "Enable color correction" : "启用颜色校正", + "enabled" : "启用", + "Enabled" : "启用", + "Enable full page image viewer" : "启用全屏图像查看器", + "Enable GroundingDINO" : "启用 GroundingDINO", + "Enable guided images mode" : "启用引导图像模式", + "Enable Maintenance tab" : "启用 \"维护\" 选项卡", + "Enable MultiDiffusion" : "启用 MultiDiffusion", + "Enable noise multiplier scheduling" : "启用噪声乘法 (noise multiplier) 调度", + "Enable optimized monocular depth estimation" : "启用单色深度估算优化 (optimized monocular depth estimation)", + "Enable overwrite" : "允许覆盖", + "Enable perspective flip" : "启用透视翻转", + "Enable Pixel Perfect from lllyasviel. Configure your target width and height on txt2img/img2img default panel before preview if you wish to enable pixel perfect." : "启用 lllyasviel 的完美像素模式。在预览前,请在文生图/图生图界面配置好图像的宽度和高度。", + "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply." : "对 K 采样器启用量化以获得更清晰、干净的结果。这可能会改变现有的随机种子。需重启才能应用。", + "Enable Region 1" : "启用区域 1", + "Enable Region 2" : "启用区域 2", + "Enable Region 3" : "启用区域 3", + "Enable Region 4" : "启用区域 4", + "Enable Region 5" : "启用区域 5", + "Enable Region 7" : "启用区域 7", + "Enable Region 8" : "启用区域 8", + "Enable sampler scheduling" : "启用采样器明细表", + "Enable steps scheduling" : "启用迭代步数明细表", + "Enable Subseed scheduling" : "启用第二种子明细表", + "Enable tensorboard logging." : "启用 tensorboard 日志记录", + "Enable this to save VRAM." : "启用此项以节省显存 (VRAM)。", + "Encoder Color Fix" : "编码器颜色修复", + "Encoder Tile Size" : "编码器区块大小", + "end at this step" : "结束控制步数", + "End blur width" : "结束模糊宽度", + "Ending Control Step" : "引导终止步数", + "End Page" : "尾页", + "Engine" : "引擎", + "Enhance" : "增强", + "Enhanced img2img" : "图生图增强", + "Enter categody ids, separated by +. For example, if you want bed+person, your input should be 7+12 for ade20k and 59+0 for coco." : "在此输入类别 ID,用 + 分隔。例如,如果你想分割出 床 + 人,使用ade20k协议应该输入 7 + 12,使用coco协议应该输入 59 + 0。", + "Enter category IDs" : "输入类别ID", + "Enter hypernetwork layer structure" : "超网络层结构", + "Enter input path" : "填写输入目录", + "Enter output path" : "填写输出目录", + "Enter relative to webui folder or Full-Absolute path, and make sure it ends with something like this: '20230124234916_%09d.png', just replace 20230124234916 with your batch ID. The %05d is important, don't forget it!" : "输入绝对路径或者以 webui 为根目录的相对路径,同时确认路径结尾类似“20230124234916_%09d.png”。只需要将 20230124234916 替换为你的 batch ID。“%05d”很重要,别忘了!", + "Erase BG" : "移除背景图", + "Escape brackets" : "将结果中的括号进行转义处理", + "Eta noise seed delta" : "Eta 噪声种子偏移量 (ENSD)", + "Example: Default args should use 221 as total keyframes." : "示例:默认参数应使用 221 作为总关键帧数。", + "Example: seed_schedule could use 0:(5), 1:(-1), 219:(-1), 220:(5)" : "示例:种子数表可以使用 0:(5), 1:(-1), 219:(-1), 220:(5)", + "Exclude tags (split by comma)" : "排除提示词 (逗号分隔)", + "exclusion" : "排除", + "Excudes (split by comma)" : "排除 (逗号分隔)", + "EXIF keyword search" : "EXIF 关键词搜索", + "Expanded Mask" : "扩展后蒙版", + "Expand Mask" : "展开蒙版设置", + "Extension" : "扩展", + "Extension index URL" : "扩展列表地址", + "Extensions" : "扩展", + "extension to be installed." : "插件", + "Extra" : "▼", + "Extract from frame" : "提取开始帧", + "Extract nth frame" : "提取间隔帧数", + "Extract to frame" : "提取结束帧", + "Extract U-Net features" : "提取 U-Net 特征值", + "Extra generation params" : "附加生成参数", + "Extra Networks" : "扩展模型", + "Extra networks tab order" : "扩展模型类型选项卡顺序", + "Extra paths to scan for LoRA models, comma-separated. Paths containing commas must be enclosed in double quotes. In the path, \" (one quote) must be replaced by \"\" (two quotes)." : "扫描低秩微调模型 (LoRA) 的附加目录,以逗号分隔。包含逗号的路径必须用双引号括起来。 在路径中,\"(一个引号)必须替换为\"\"(两个引号)。", + "Extra path to scan for ControlNet models (e.g. training output directory)" : "检索 ControlNet 模型的附加目录(如训练输出目录)", + "extras" : "后期处理", + "Extras" : "后期处理", + "Extra text to add before <...> when adding extra network to prompt" : "在向提示词中添加扩展模型标签时在 <…> 之前添加额外文本", + "Face restoration" : "面部修复", + "Face restoration model" : "面部修复模型", + "fast" : "快速模式", + "Fast Decoder" : "使用快速解码器", + "Fast Encoder" : "使用快速编码器", + "Fast Encoder Color Fix" : "快速编码器颜色修复", + "Fast Encoder may change colors; Can fix it with more RAM and lower speed." : "快速编码器可能会导致颜色偏差;通过使用更大的内存和更慢的速度可以避免这个情况", + "favorites" : "收藏夹", + "Favorites" : "收藏夹", + "FFmpeg CRF value" : "FFmpeg CRF 值", + "FFmpeg path/ location" : "FFmpeg 路径", + "FFmpeg settings" : "FFmpeg 设置", + "File" : "文件", + "File format for grids" : "网格图文件格式", + "File format for images" : "图片文件后缀(格式)", + "filename" : "文件名", + "Filename" : "文件名", + "File Name" : "文件名", + "Filename keyword search" : "文件名关键词搜索", + "filename(option)" : "文件名 (可选)", + "File size limit for the above option, MB" : "上述选项的文件大小限制,单位:MB", + "Files to process" : "要处理的文件", + "fill down" : "向下扩展", + "fill left" : "向左扩展", + "fill right" : "向右扩展", + "fill up" : "向上扩展", + "Filter models by path name" : "按路径名筛选模型", + "find but bo translated:" : "已找到但无翻译:", + "First" : "First (第一生成帧)", + "First frame as init image" : "第一帧作为初始化图像", + "FirstGen" : "FirstGen (处理后生成的第一帧)", + "First Page" : "首页", + "Fixed seed" : "固定种子", + "Font for image grids that have text" : "网格图文字字体", + "For advanced keyframing with Math functions, see" : "更多关于公式关键帧的高级选项,见", + "Force convert half to float on interpolation (for some platforms)" : "在插值时强制将半精度浮点数转换为全精度 (适用于部分平台)", + "Force Reset" : "强制重置", + "for detailed explanation." : "以了解详细信息。", + "FOR HELP CLICK HERE" : "点击此处获取帮助", + "For hires fix, use width/height sliders to set final resolution rather than first pass (disables Upscale by, Resize width/height to)." : "在高分辨率修复中,通过长宽滑块设定最终分辨率 (关闭放大倍率和自适应分辨率设置)", + "For inpainting, include masked composite in results for web" : "使用重绘时,在网页结果中包含复合蒙版", + "For inpainting, include the greyscale mask in results for web" : "使用重绘时,在网页结果中包含灰度蒙版图", + "For inpainting, save a copy of the greyscale mask" : "使用重绘时,保存一份灰度蒙版副本", + "For inpainting, save a masked composite" : "使用重绘时,保存一份复合蒙版", + "For negative prompts, please write your positive prompt, then --neg ugly, text, assymetric, or any other negative tokens of your choice. OR:" : "对于反向提示词,请写出你的正向提示词,然后添加 --neg ugly,text,assymetric 等您选择的任何其他反向提示词。或者:", + "for your animation (leave blank to ignore)." : "用于你的动画中(留空表示忽略)", + "Found tags" : "匹配的提示词", + "fp16" : "fp16", + "fp32" : "fp32", + "Frame Interpolation" : "帧插值", + "Frame Interpolation to smooth out, slow-mo (or both) any video." : "进行帧插值来让任何视频获得顺滑的切换效果,慢动作(或两者皆可)", + "Frame Interpolation will *not* run if any of the following are enabled: 'Store frames in ram' / 'Skip video for run all'." : "帧差值将不会在以下任一选项启用时启动:“保存帧图像到内存” / “跳过视频”", + "Frames to Video" : "帧图片转视频", + "Free GPU" : "释放显存", + "Full res mask" : "全分辨率蒙版", + "Full res mask padding" : "全分辨率蒙版的填充尺寸", + "gamma" : "伽马值", + "Gamma" : "伽马值", + "Gather" : "生成", + "Gen" : "生成", + "Generate" : "生成", + "Generate forever" : "无限生成", + "Generate human masks" : "生成人工蒙版", + "Generate Info" : "生成信息", + "Generate inputframes" : "生成输入帧", + "Generate layout for batch process" : "生成批量处理的图像分布", + "Generate layout for single image" : "生成单张图像的图像分布", + "Generate Movie Mode" : "视频生成模式", + "Generation Info" : "生成信息", + "Get Civitai Model Info by Model Page URL" : "从 Civitai 模型页面链接拉取模型信息", + "*Get depth from uploaded video*" : "*从上传的视频中获取深度*", + "Get Model Info from Civitai" : "从 Civitai 上获取模型信息", + "Get Model Info from Civitai by URL" : "从 Civitai 链接获取模型信息", + "GFPGAN visibility" : "GFPGAN 强度", + "Glow" : "辉光", + "Glow mode" : "辉光模式", + "Gradient accumulation steps" : "梯度累加步数", + "Great" : "很好的", + "Grid layout" : "网格图布局", + "Grid row count; use -1 for autodetect and 0 for it to be same as batch size" : "网格图行数; 使用 -1 进行自动检测,使用 0 使其与单批数量相同", + "GroundingDINO batch progress status" : "GroundingDINO 批量处理状态", + "GroundingDINO Box Threshold" : "GroundingDINO 箱体阈值", + "GroundingDINO Detection Prompt" : "GroundingDINO 检测提示词", + "GroundingDINO Model (Auto download from huggingface)" : "GroundingDINO 模型(从huggingface自动下载)", + "GroundingDINO + Segment Anything can achieve [text prompt]->[object detection]->[segmentation]" : "GroundingDINO + Segment Anything 可以实现 [文本提示词]->[对象检测]->[语义分割]", + "Group/split table by: (when not started with single quote - so only for prompts, not for merge)" : "提示词分组方式(非单引号开头时):", + "Guess Mode" : "无提示词引导模式", + "Guidance End (T)" : "引导终止时机", + "Guidance Start (T)" : "引导介入时机", + "Guided Images" : "引导图像", + "Guided images schedules" : "引导图像参数表", + "haku_output" : "Haku 输出", + "Hands" : "手掌", + "hard_light" : "强光", + "has metadata" : "有元数据", + "height" : "高度", + "Height" : "高度", + "here" : "这里", + "Hidden UI tabs (requires restart)" : "需要隐藏的 UI 选项卡 (需要重启)", + "Hide annotator result" : "隐藏预处理预览结果", + "Hide caption" : "隐藏文本标注", + "Hide extensions with tags" : "隐藏含有以下标签的扩展", + "Hide heatmap images" : "隐藏热力图图像", + "Hide samplers in user interface (requires restart)" : "在用户界面中隐藏采样器 (需重启)", + "Highres. fix" : "高分辨率修复", + "hiresfix" : "高清修复", + "Hires. fix" : "高分辨率修复 (Hires. fix)", + "Hires steps" : "高分迭代步数(Hires steps)", + "Historical" : "Historical (当前帧前的倒数第二帧)", + "History" : "历史记录", + "Horizontal Mirroring" : "水平镜像", + "horizontal split num" : "水平分割数", + "Horizontal+Vertical Mirroring" : "水平+垂直镜像", + "how closely the image should conform to the prompt. Lower values produce more creative results. (recommended range 5-15)" : "图像应符合提示词的程度。较低的值会产生更具创造性的结果。(建议范围5-15)", + "how close to get to the colors of the input frame image/ the amount each frame during a tweening step to use the new images colors" : "如何接近输入帧图像的颜色 / 在中间计算步骤中使用新图像颜色的每帧数量", + "How many batches of images to create" : "创建多少批量次数的图像", + "how much the image should look like the previou one and new image frame init. strength schedule might be better if this is higher, around .75 during the keyfames you want to switch on" : "前一个图像和新的图像帧的初始化强度规划有多大的关系。在你想启用的关键帧中,如果这个数字高一点,大约0.75,可能会更好。", + "How often, in seconds, to flush the pending tensorboard events and summaries to disk." : "刷新间隔,单位为秒;将待处理的 Tensorboard 事件和摘要刷新到硬盘", + "hue" : "色度", + "Humans Masking" : "人工蒙版", + "Hybrid composite" : "混合合成模式", + "Hybrid motion" : "混合模式", + "Hybrid Schedules" : "混合参数表", + "Hybrid Settings" : "合成设置", + "Hybrid Video" : "视频合成", + "Hybrid Video Compositing in 2D/3D Mode" : "2D/3D 模式下的混合视频合成", + "Hypernetwork Learning rate" : "超网络模型学习率", + "If enabled, only images will be saved" : "启用时,仅保存图片", + "if enabled, raw imgs will be deleted after a successful video/ videos (upsacling, interpolation, gif) creation" : "如果启用,则在成功创建视频/视频(无损放大,插值,gif)后,将删除原始图像", + "If the saved image file size is above the limit, or its either width or height are above the limit, save a downscaled copy as JPG" : "当图像文件大小或尺寸超过限制,另存一份缩小的副本为 JPG 格式", + "If you still cannot understand, use default." : "如果你仍然无法理解,请保持默认值。", + "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them" : "对于拥有同名 .vae.pt 的模型,忽略外挂 VAE", + "I know what I am doing." : "高级选项", + "image" : "图像", + "Image" : "图像", + "Image browser" : "图库浏览器", + "Image Browser" : "图库浏览器", + "Image Count" : "图片数量", + "Image creation progress preview mode" : "图像生成过程预览模式", + "Image for Auto Segmentation" : "用于语义分割的图像", + "Image for Image Layout" : "用于图像分布的图像", + "Image for Segment Anything" : "用于分离的图像", + "Image height" : "图像高度", + "Image Init" : "图像初始化", + "Image Layout" : "图像分布", + "Image Parameters" : "图像参数", + "Image path" : "图像路径", + "Image preview height" : "预览图高度", + "Images directory" : "图像目录", + "Images filename pattern" : "图片文件名格式", + "Images to use for keyframe guidance" : "用于关键帧引导的图像", + "Image strength schedule" : "图像强度参数表", + "Image to 3D" : "图转 3D", + "Image to 3D mesh" : "图像转 3D 网格", + "Image width" : "图像宽度", + "img2img" : "图生图", + "img2img-grids" : "图生图 (网格)", + "Import a model from Huggingface.co instead of using a local checkpoint." : "从 Huggingface.co 导入模型而非使用本地的模型文件。", + "Important notes:" : "重要信息:", + "Important Notes:" : "重要事项:", + "Important notes and Help" : "重要信息与帮助", + "*Important* notes on Prompts" : "对于提示词模式的重要笔记", + "Import Model from Huggingface Hub" : "从 Huggingface Hub 载入模型", + "IN00" : "输入层 00", + "IN01" : "输入层 01", + "IN02" : "输入层 02", + "IN03" : "输入层 03", + "IN04" : "输入层 04", + "IN05" : "输入层 05", + "IN06" : "输入层 06", + "IN07" : "输入层 07", + "IN08" : "输入层 08", + "IN09" : "输入层 09", + "IN10" : "输入层 10", + "IN11" : "输入层 11", + "IN_A_00" : "模型 A 输入层 00", + "IN_A_01" : "模型 A 输入层 01", + "IN_A_02" : "模型 A 输入层 02", + "IN_A_03" : "模型 A 输入层 03", + "IN_A_04" : "模型 A 输入层 04", + "IN_A_05" : "模型 A 输入层 05", + "IN_A_06" : "模型 A 输入层 06", + "IN_A_07" : "模型 A 输入层 07", + "IN_A_08" : "模型 A 输入层 08", + "IN_A_09" : "模型 A 输入层 09", + "IN_A_10" : "模型 A 输入层 10", + "IN_A_11" : "模型 A 输入层 11", + "IN_B_00" : "模型 B 输入层 00", + "IN_B_01" : "模型 B 输入层 01", + "IN_B_02" : "模型 B 输入层 02", + "IN_B_03" : "模型 B 输入层 03", + "IN_B_04" : "模型 B 输入层 04", + "IN_B_05" : "模型 B 输入层 05", + "IN_B_06" : "模型 B 输入层 06", + "IN_B_07" : "模型 B 输入层 07", + "IN_B_08" : "模型 B 输入层 08", + "IN_B_09" : "模型 B 输入层 09", + "IN_B_11" : "模型 B 输入层 11", + "Include confident of tags matches in results" : "在结果中包含提示词的匹配置信度", + "Include resource hashes in image metadata (for resource auto-detection on Civitai)" : "在图像元数据中嵌入资源哈希值 (用于在 Civitai 上自动检测资源)", + "Index" : "索引", + "Info & Help" : "信息与帮助", + "Info, Links and Help" : "基本信息与帮助链接", + "In FPS" : "输入 FPS", + "In Frame Count" : "输入关键帧数", + "In \"Interpolate existing pics\" mode, FPS is determined *only* by output FPS slider. Audio will be added if requested even with slow-mo \"enabled\", as it does *nothing* in this mode." : "在‘插入已有图像’模式中,帧率仅由帧率设置滑块决定。音频将会加入,即使在慢动作模式启用情况下,且在此模式下什么都不会做。", + "Init" : "初始化", + "Initial denoising strength" : "初始去噪强度", + "Initialization text" : "初始化文本", + "Init image" : "初始化图像", + "Init Video" : "初始化视频", + "In Keyframes tab, you can also set" : "在关键帧页面中,你还可以设置", + "in <>, like , " : "<>,比如 , ", + "inpaint" : "局部重绘", + "Inpaint" : "局部重绘", + "Inpaint area" : "重绘区域", + "Inpaint batch mask directory (required for inpaint batch processing only)" : "批量重绘蒙版目录 (仅限批量重绘使用)", + "inpaint height" : "重绘高度", + "Inpaint masked" : "重绘蒙版内容", + "Inpaint not masked" : "重绘非蒙版内容", + "inpaint sketch" : "涂鸦重绘", + "Inpaint sketch" : "涂鸦重绘", + "Inpaint upload" : "上传重绘蒙版", + "inpaint width" : "重绘宽度", + "Input directory" : "输入目录", + "Input Directory" : "输入目录", + "Input Image" : "输入图像", + "Input images directory" : "输入图像目录", + "Input <= Output" : "输出图像 发送到 输入图像", + "Input path" : "输入目录", + "In Res" : "输入分辨率", + "Inspect" : "检查", + "Install" : "安装", + "installed" : "已安装", + "Installed" : "已安装", + "Install from URL" : "从网址安装", + "Installing..." : "正在安装...", + "instructs the run to start from a specified point" : "指示运行从指定点开始", + "integrations" : "集成功能", + "interactive splines and Bezier curves" : "交互式样条曲线和贝赛尔曲线", + "Intermediate files path" : "临时文件路径", + "Intermediate results may look better than the end results. /!\\ Intermediate results are cleaned after each run, save them elsewhere if you want to keep them." : "中间的结果可能比最终结果看起来更好。提示: 中间的结果在每次运行后都会被清理,如果你想保留它们,就把它们保存在其它地方", + "internal order" : "内部排序", + "Interpolation" : "插值", + "interpolation method" : "插值模式", + "Interpolation method" : "插值算法", + "Interpolation Method" : "融合算法", + "Interrogate" : "反推提示词", + "Interrogate\nCLIP" : "CLIP\n反推", + "Interrogate\nDeepBooru" : "DeepBooru\n反推", + "Interrogate Options" : "提示词反推设置", + "Interrogator" : "反推模型", + "interrupt" : "中止", + "Interrupt" : "中止", + "Invert colors" : "反转颜色", + "Invert colors if your image has white background." : "对于白色背景图片请开启颜色反转。", + "invert (from white bg & black line)" : "invert (白底黑线反色)", + "Invert Input Color" : "反转输入颜色", + "Invert mask" : "反转蒙版", + "is also a good option, it makes compact math formulae for Deforum keyframes by selecting various waveforms." : "也是一个很好的选择,它通过选择各种波形,为消噪关键帧生成紧凑的数学公式。", + "is experimental functions and NO PROOF of effectiveness." : " 为实验性功能,不保证有效性。", + "It takes time, just wait. Check console log for detail" : "检查需要一段时间,请耐心等待。检查控制台日志以查看详情。", + "It will translate prompt from your native language into English. So, you can write prompt with your native language." : "这会将您输入的提示词翻译为英文。因此,您可以直接用母语输入提示词。", + "JSON Validator" : "JSON 检查器中检查", + "Just resize" : "仅调整大小", + "Just Resize" : "直接调整大小", + "Just resize (latent upscale)" : "调整大小 (潜空间超分)", + "Keep -1 for seeds" : "保持种子随机", + "Keep blank if you don't have mask" : "如果没有遮罩, 请保持空白", + "Keep Imgs" : "保留原图", + "Keep occlusion edges" : "保持边缘封闭", + "Kernel schedule" : "Kernel 值表", + "Keyframes" : "关键帧", + "Keyframes: animation settings (animation mode, max frames, border)" : "关键帧:动画设置(动画模式,最大帧数,边界)", + "Keyframes: coherence (color coherence & cadence)" : "关键帧:一致性(颜色一致性和间隔)", + "Keyframes: depth warping" : "关键帧:深度扭曲", + "Keyframes: generation settings (noise, strength, contrast, scale)." : "关键帧:通用设置(噪点,强度,对比度,缩放)", + "Keyframes: motion parameters for 2D and 3D (angle, zoom, translation, rotation, perspective flip)." : "关键帧:2D 和 3D 的运动参数(角度,缩放,变换,旋转,透视翻转)", + "Keywords" : "关键词", + "LAB is a more linear approach to mimic human perception of color space - a good default setting for most users." : "LAB 是一种更为线性的方法,可以模拟人类对色彩空间的感知——这是大多数用户的一个很好的默认设置。", + "ladder" : "阶梯式", + "Latent Mirror mode" : "潜空间镜像应用模式", + "Latent Mirror style" : "潜空间镜像方式", + "Latent tile batch size" : "潜空间区块单批大小", + "Latent tile height" : "潜空间区块高度", + "Latent tile overlap" : "潜空间区块重叠", + "Latent tile width" : "潜空间区块宽度", + "latest" : "最新", + "Layer1" : "图层 1", + "Layer1 mask blur" : "图层 1 蒙版模糊度", + "Layer1 mask strength" : "图层 1 蒙版强度", + "Layer1 opacity" : "图层 1 透明度", + "Layer2" : "图层 2", + "Layer2 mask blur" : "图层 2 蒙版模糊度", + "Layer2 mask strength" : "图层 2 蒙版强度", + "Layer2 opacity" : "图层 2 透明度", + "Layer3" : "图层 3", + "Layer3 mask blur" : "图层 3 蒙版模糊度", + "Layer3 mask strength" : "图层 3 蒙版强度", + "Layer3 opacity" : "图层 3 透明度", + "Layer4" : "图层 4", + "Layer4 mask blur" : "图层 4 蒙版模糊度", + "Layer4 mask strength" : "图层 4 蒙版强度", + "Layer4 opacity" : "图层 4 透明度", + "Layer5" : "图层 5", + "Layer5 mask blur" : "图层 5 蒙版模糊度", + "Layer5 mask strength" : "图层 5 蒙版强度", + "Layer5 opacity" : "图层 5 透明度", + "Layers" : "图层", + "LDSR processing steps. Lower = faster" : "LDSR 处理步数。越少越快", + "Learning rate" : "学习率", + "Leave blank to save images to the default path." : "留空以将图像保存到默认路径", + "Leave empty for auto" : "留空时自动生成", + "Leave empty for default main branch" : "留空以使用默认分支", + "Leave empty to use img2img batch controlnet input directory" : "留空以使用图生图批量处理 ControlNet 输入目录", + "Leave empty to use input directory" : "留空以使用普通输入目录", + "Left click the image to add one positive point (black dot). Right click the image to add one negative point (red dot). Left click the point to remove it." : "左键点击图像添加一个黑色的正向标记点(想提取的部分)。右键点击图像添加一个红色的反向标记点(不想提取的部分)。左键再次点击可以删除标记点。", + "Legacy hash" : "旧哈希值", + "Len" : "长度", + "Lerp" : "线性插值", + "Licenses" : "开源许可协议", + "lighten" : "变亮", + "like here" : "链接", + "linear_burn" : "线性加深", + "linear_dodge" : "线性减淡", + "linear_light" : "线性光", + "lineart_anime" : "lineart_anime (动漫线稿提取)", + "lineart_anime_denoise" : "lineart_anime_denoise (动漫线稿提取 - 去噪)", + "lineart_coarse" : "lineart_coarse (粗略线稿提取)", + "lineart_realistic" : "lineart_realistic (写实线稿提取)", + "lineart_standard (form white bg & black line)" : "lineart_standard (标准线稿提取 - 白底黑线)", + "lineart_standard (from white bg & black line)" : "lineart_standard (标准线稿提取 - 白底黑线反色)", + "Link to DeepL" : "Deepl 在线翻译链接", + "List loaded embeddings" : "获取嵌入式模型列表", + "Live previews" : "实时过程预览", + "⚙️ Load" : "⚙️ 加载", + "Load" : "加载", + "Load All Settings" : "载入所有设置", + "Load an image." : "加载一张图片", + "Load BG" : "加载背景图", + "Load from:" : "加载扩展列表", + "Load from JSON" : "加载 JSON", + "load_history" : "加载历史记录", + "Loading..." : "载入中...", + "Load Scene" : "加载场景", + "Load Video Settings" : "载入视频设置", + "Local directory name" : "本地目录名", + "Localization file (Please leave `User interface` - `Localization` as None)" : "本地化文件 (请将\"用户界面\" - “本地化翻译”选项设置为“无”)", + "Localization (requires restart)" : "本地化翻译(需要重启)", + "Location" : "FFmpeg 所在位置", + "Log" : "日志", + "Log directory" : "日志目录", + "[Loopback] Automatically send generated images to this ControlNet unit" : "[回送] 自动发送生成后的图像到此 ControlNet unit", + "Loopback source" : "回送源", + "Looping recommendations:" : "循环设置建议:", + "LoRA Block Weight" : "LoRA 区块权重配置", + "LoRA directory (if not default)" : "LoRA 模型文件目录 (如非默认)", + "LoRA model name filter" : "按名称过滤低秩微调 (LoRA) 模型", + "Low VRAM" : "低显存模式", + "Low VRAM (8GB or below)" : "低显存 (8 GB 以下) 模式", + "M00" : "中间层", + "M_A_00" : "模型 A 中间层", + "Made by deforum.github.io, port for AUTOMATIC1111's webui maintained by kabachuha" : "由 deforum.github.io 制作,AUTOMATIC1111 的 webui 移植版本由 kabachuha 维护", + "Maintenance" : "维护", + "Make GIF" : "制作 GIF 文件", + "Make Images" : "制作图像", + "Make K-diffusion samplers produce same images in a batch as when making a single image" : "使 K-diffusion 采样器在批量生成与生成单个图像时,产出相同的结果", + "Make LoRA (A-B)" : "制作差分 LoRA (A-B)", + "Make LoRA (alpha * A - beta * B)" : "制作差分 LoRA (α × A - β × B)", + "Make your choices, adjust your settings, set a name, save. To edit a prior choice, select from dropdown and overwrite." : "做出选择,调整设置,设置名称,保存。要编辑先前的选择,请从下拉列表中选择并覆盖。", + "Make Zip when Save?" : "保存时创建 zip 压缩文件?", + "mask" : "蒙版", + "Mask blur" : "蒙版边缘模糊度", + "Mask brightness adjust" : "蒙版亮度调整", + "Mask by Category" : "按分类创建蒙版", + "mask content ratio" : "蒙版内容比例", + "Mask contrast adjust" : "蒙版对比度调整", + "Mask directory" : "遮罩图像目录", + "Masked content" : "蒙版区域内容处理", + "Mask file" : "蒙版文件", + "Mask fill" : "蒙版填充", + "Mask mode" : "蒙版模式", + "Mask overlay blur" : "蒙版覆盖模糊度", + "Mask schedule" : "蒙版参数表", + "Mask Setting" : "蒙版设置", + "masks from files: in [], like [mask1.png]" : "从文件中获取蒙版:[] ,比如 [mask1.png]", + "Max" : "最大值", + "Maximum aesthetic_score" : "最大美学评分", + "Maximum execution time (seconds)" : "最大执行时间(以秒为单位)", + "Maximum image size, in megapixels" : "上述选项的最大图像尺寸,单位:百万像素", + "Maximum ranking" : "最大评分", + "Max prompt words for [prompt_words] pattern" : "用于替代 [prompt_words] 占位符的最大提示词数量", + "Max steps" : "最大步数", + "M_B_00" : "模型 B 中间层", + "MBW" : "分块设置权重(MBW)", + "MBW Each" : "A/B 模型分别分块设置权重 (MBW Each)", + "mbw weights" : "分块权重", + "Memory" : "内存", + "Memory usage" : "内存使用量", + "Merge" : "合并", + "Merge!" : "融合", + "Merge Block Weighted" : "模型分块合并", + "Merge&Gen" : "融合并生成", + "Merge LoRAs" : "合并 LoRA", + "Merge Mode" : "融合算法", + "Merge models and load it for generation" : "融合模型并生成图片", + "Merge to Checkpoint" : "合并到大模型", + "Message" : "信息", + "Method" : "方案", + "MiDaS weight (vid2depth)" : "MiDaS 权重(vid2depth)", + "Min" : "最小值", + "minimum aesthetic_score" : "按美学评分下限过滤", + "Minimum aesthetic_score" : "最小美学评分", + "Minimum lighting ratio" : "最小照明比率", + "Minimum ranking" : "最小评分", + "min_mask_region_area" : "最小蒙版面积", + "missing metadata" : " 无元数据", + "Mixed" : "混合", + "mlsd" : "mlsd (M-LSD 直线线条检测)", + "mode" : "模式", + "Mode" : "模式", + "model" : "模型", + "Model" : "模型", + "Model 1" : "模型 1", + "Model 2" : "模型 2", + "Model 3" : "模型 3", + "Model 4" : "模型 4", + "Model 5" : "模型 5", + "model A" : "模型 A", + "model_A" : "模型 A", + "Model A" : "模型 A", + "Model_A" : "模型A", + "model B" : "模型 B", + "model_B" : "模型 B", + "Model B" : "模型 B", + "Model_B" : "模型 B", + "model C" : "模型 C", + "Model C" : "模型 C", + "Model cache size (requires restart)" : "模型缓存数量 (需重启)", + "Model Converter" : "模型转换", + "Model description/readme/notes/instructions" : "模型的描述信息/说明/注释/指引", + "model hash" : "模型哈希值", + "Model hash" : "模型哈希值", + "Model Name" : "模型名称", + "model of the upscaler to use. 'realesr-animevideov3' is much faster but yields smoother, less detailed results. the other models only do x4" : "需要使用的超分模型。 'realesr-animevideov3' 速度更快但生成的结果更平滑、更详细。其他超分模型只支持 4 倍放大", + "Model path" : "模型路径", + "Model Path" : "模型路径", + "Model path filter" : "按模型路径过滤", + "models" : "模型相关", + "Model Type" : "模型种类", + "Model Types" : "模型种类", + "Model Version" : "模型版本", + "More info about Anti Burn" : "关于 Anti Burn 的更多信息", + "Motion" : "运动参数", + "Mov2Mov output path for image" : "Mov2Mov 图片输出路径", + "Mov2Mov output path for vedio" : "Mov2Mov 视频输出路径", + "Move completion popup together with text cursor" : "将弹出窗口与文本光标一起移动", + "Move ControlNet images to CPU (if applicable)" : "将 ControlNet 图像移动到 CPU(如果适用)", + "Move face restoration model from VRAM into RAM after processing" : "处理完成后,将面部修复模型从显存卸载到内存", + "Move Mode (X key)" : "移动模式(X 键)", + "Move to favorites" : " 移动到收藏夹", + "Move VAE and CLIP to RAM when training if possible. Saves VRAM." : "如果可行,训练时将 VAE 和 CLIP 模型从显存移动到内存,可节省显存", + "Move VAE to GPU" : "将 VAE 移动到 GPU", + "Move VAE to GPU (if possible)" : "将 VAE 移动到 GPU (如果允许)", + "Multi ControlNet: Max models amount (requires restart)" : "多重 ControlNet 的最大模型数量 (需重启)", + "Multi-frame rendering" : "多帧渲染", + "Multi Model Merge" : "多模型合并", + "Multiplication (2^N)" : "倍率 (2^N)", + "multiplier" : "倍率", + "Multiplier" : "倍率", + "Multiplier for extra networks" : "扩展模型默认权重", + "Multiplier (M) - set to 0 to get model A" : "融合比例 (M) - 设为 0 等价于直接输出模型 A", + "multiply" : "乘积", + "Multi Proc Cmd" : "多进程命令", + "My prompt is more important" : "更注重提示词", + "name" : "名称", + "Name" : "名称", + "Name 0" : "名称 0", + "Name 1" : "名称 1", + "Name 10" : "名称 10", + "Name 11" : "名称 11", + "Name 12" : "名称 12", + "Name 13" : "名称 13", + "Name 14" : "名称 14", + "Name 15" : "名称 15", + "Name 2" : "名称 2", + "Name 3" : "名称 3", + "Name 4" : "名称 4", + "Name 5" : "名称 5", + "Name 6" : "名称 6", + "Name 7" : "名称 7", + "Name 8" : "名称 8", + "Name 9" : "名称 9", + "Nearest" : "近邻插值", + "need input your want to translate" : "请输入你想翻译的内容", + "Negative prompt" : "反向提示词", + "Negative Prompt" : "反向提示词", + "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)" : "反向提示词 (按 Ctrl+Enter 或 Alt+Enter 开始生成)\nNegative prompt", + "Negative Prompts" : "反向提示词", + "negative prompt to be appended to *all* prompts. DON'T use --neg here!" : "反向提示词会被添加到左右提示词内,请勿在此处使用 --neg 字段", + "Negative Prompt Weight" : "反向提示词权重", + "Negative Prompt, will also be appended" : "追加反向提示词", + "Network module" : "附加网络模块", + "Network module 1" : "附加模型 1", + "Network module 2" : "附加模型 2", + "Network module 3" : "附加模型 3", + "Network module 4" : "附加模型 4", + "Network module 5" : "附加模型 5", + "newest first" : "按发布日期倒序", + "New Scribble Drawing Height" : "新线稿画板高度", + "New Scribble Drawing Width" : "新线稿画板宽度", + "Next Page" : "下一页", + "no" : "否", + "No" : "否", + "no-ema" : "删除 EMA 权重", + "no find:" : "未找到:", + "No interpolation" : "原样输出", + "No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking." : "直接输出主要模型。需要一个模型 A。可用于模型格式转换和嵌入 VAE。", + "Noise" : "噪点参数", + "Noise mask schedule" : "噪点蒙版参数表", + "Noise multiplier for img2img" : "图生图噪声倍率", + "Noise multiplier schedule" : "噪声乘法调度(Noise multiplier schedule)", + "Noise schedule" : "噪点值表", + "Noise type" : "噪声类型", + "none" : "无", + "None" : "无", + "NONE" : "无", + "None (just grayscale)" : "什么都不做(灰度模式)", + "normal" : "正常", + "normal_bae" : "normal_bae (Bae 法线贴图提取)", + "normal_midas" : "normal_midas (Midas 法线贴图提取)", + "Normal with batch" : "正常(带批处理)", + "not" : "不会", + "Note that parseq overrides:" : "以下参数将会被参数定序器覆盖设置:", + "(not for Video Input mode)" : "(不是视频输入模式)", + "Nothing here. Add some content to the following directories:" : "暂无内容。请添加模型到以下目录:", + "NUl Image Enhancer" : "NUI 图像增强", + "Number of iterations" : "迭代次数", + "number of the frames that we will blend between current imagined image and input frame image" : "当前想象图像和输入帧图像之间混合的帧数", + "Number of vectors per token" : "每个词元 (token) 的向量数", + "official Deforum Discord" : "官方 Discord 频道", + "Official Deforum Wiki:" : "Deforum 官方 Wiki:", + "# of threads to use for hash calculation (increase if using an SSD)" : "用于哈希计算的线程数(如果使用 SSD 可适当增加)", + "oldest first" : "按发布日期正序", + "online" : "线上服务", + "Online 3D Openpose Editor" : "在线 3D Openpose 编辑器", + "Only copy to models with no metadata" : "仅复制到不含元数据的模型", + "Only copy to models with same session ID" : "仅复制到具有相同 Session ID 的模型", + "Only Hand" : "仅显示手部(移除脚部)", + "*Only in use with pix2pix checkpoints!*" : "仅限用于 pix2pix 检查点", + "Only masked" : "仅蒙版区域", + "Only masked padding, pixels" : "仅蒙版区域下边缘预留像素", + "Only Show Models have no Info" : "只显示缺少信息的模型", + "Only show models that have/don't have user-added metadata" : "按是否有元数据过滤模型", + "Only show .safetensors format models" : "只显示 .safetensors 格式的模型", + "Only use mid-control when inference" : "仅在生成图片时使用中间层控制 (mid-control)", + "(O)Output Model Name" : "输出模型文件名", + "Opacity" : "不透明度", + "Open images output directory" : "打开图像输出目录", + "Open intermediate results" : "立即打开当前效果图", + "Open New Scribble Drawing Canvas" : "创建新的线稿画板", + "Open output directory" : "打开输出目录", + "openpose" : "openpose (OpenPose 姿态)", + "OpenPose Editor" : "OpenPose 编辑器", + "openpose_face" : "openpose_face (OpenPose 姿态及脸部)", + "openpose_faceonly" : "openpose_faceonly (OpenPose 仅脸部)", + "openpose_full" : "openpose_full (OpenPose 姿态、手部及脸部)", + "openpose_hand" : "openpose_hand (OpenPose 姿态及手部)", + "Open results" : "打开最终效果图", + "Open TextEditor" : "打开文本编辑器", + "Open Url At Client Side" : "在浏览器侧打开链接", + "Optical Flow" : "光流法", + "Optical flow cadence" : "生成间隔中启用光流法", + "Options are all options hardcoded, and additional you added in additional_components.py" : "选项都是硬编码的选项,并且是您在 additional_components.py 中添加的附加选项", + "or" : "或", + "Order" : "排序", + "Original:" : "原项目:", + "Original First" : "原文在上", + "OriginalImg" : "OriginalImg (原始输入的第一帧)", + "Original negative prompt" : "原始反向提示词", + "Original Weights" : "原始权重", + "or, manually enhance the image" : "↓手动控制图像增强参数↓", + "Other" : "其他", + "Others" : "其它", + "Other Setting" : "其他设置", + "OUT00" : "输出层 00", + "OUT01" : "输出层 01", + "OUT02" : "输出层 02", + "OUT03" : "输出层 03", + "OUT04" : "输出层 04", + "OUT05" : "输出层 05", + "OUT06" : "输出层 06", + "OUT07" : "输出层 07", + "OUT08" : "输出层 08", + "OUT09" : "输出层 09", + "OUT10" : "输出层 10", + "OUT11" : "输出层 11", + "OUT_A_00" : "模型 A 输出层 00", + "OUT_A_01" : "模型 A 输出层 01", + "OUT_A_02" : "模型 A 输出层 02", + "OUT_A_03" : "模型 A 输出层 03", + "OUT_A_04" : "模型 A 输出层 04", + "OUT_A_05" : "模型 A 输出层 05", + "OUT_A_06" : "模型 A 输出层 06", + "OUT_A_07" : "模型 A 输出层 07", + "OUT_A_08" : "模型 A 输出层 08", + "OUT_A_09" : "模型 A 输出层 09", + "OUT_A_10" : "模型 A 输出层 10", + "OUT_A_11" : "模型 A 输出层 11", + "OUT_B_00" : "模型 B 输出层 00", + "OUT_B_01" : "模型 B 输出层 01", + "OUT_B_02" : "模型 B 输出层 02", + "OUT_B_03" : "模型 B 输出层 03", + "OUT_B_04" : "模型 B 输出层 04", + "OUT_B_05" : "模型 B 输出层 05", + "OUT_B_06" : "模型 B 输出层 06", + "OUT_B_07" : "模型 B 输出层 07", + "OUT_B_08" : "模型 B 输出层 08", + "OUT_B_09" : "模型 B 输出层 09", + "OUT_B_10" : "模型 B 输出层 10", + "OUT_B_11" : "模型 B 输出层 11", + "output" : "输出", + "Output" : "输出", + "Output animation path" : "动画输出路径", + "Output directory" : "输出目录", + "Output directory for grids; if empty, defaults to two directories below" : "网格图统一输出文件夹; 如果为空,则按以下两个文件夹分别输出", + "Output directory for images from extras tab" : "后期处理输出文件夹", + "Output directory for images; if empty, defaults to three directories below" : "统一输出文件夹; 如果为空,则按以下三个文件夹分别输出", + "Output directory for img2img grids" : "图生图网格输出文件夹", + "Output directory for img2img images" : "图生图输出文件夹", + "Output directory for txt2img grids" : "文生图网格输出文件夹", + "Output directory for txt2img images" : "文生图输出文件夹", + "Output filename format" : "输出文件名格式", + "Output filename formats" : "输出文件名格式", + "Output Image Width" : "输出图像宽度", + "Output Model Name" : "输出模型文件名", + "Output per image:" : "单独输出每张图像:", + "outputs" : "输出", + "Output settings: all settings (including fps and max frames)" : "输出设置:所有设置(包括帧率和最大帧数)", + "Output type" : "输出类型", + "output video resolution" : "输出视频的分辨率", + "Out Res" : "输出分辨率", + "overlay" : "叠加", + "Overlay mask" : "覆盖蒙版", + "override:" : "覆盖以下参数:", + "Override settings" : "覆盖设置", + "overwrite" : "允许覆盖", + "Overwrite extracted frames" : "覆盖已有帧", + "Overwrite image size" : "覆盖图像尺寸", + "Overwrite input frames" : "覆盖输入帧", + "Overwrite Old Embedding" : "覆盖同名嵌入式模型文件", + "Overwrite Old Hypernetwork" : "覆盖同名超网络模型文件", + "Padding token (ID or single token)" : "填充提示词(完整ID或者单个提示词)", + "Page Index" : "页码", + "Panorama to 3D mesh" : "全景图转 3D 网格", + "Parse!" : "解析", + "Parseq" : "参数定序器 (parameter sequencer)", + "Parseq does" : "参数定序器将", + "Parseq Manifest (JSON or URL)" : "参数定序器配置文件(JSON 或者链接)", + "Passing ControlNet parameters with \"Send to img2img\"" : "使用\"发送到图生图\"时传输 ControlNet 参数", + "Paths for saving" : "保存路径", + "Path to directory containing annotator model directories (requires restart, overrides corresponding command line flag)" : "预处理器模型 (annotator model) 的文件路径 (需重启,以覆盖相应的命令行标志)", + "Path to settings file you want to load. Path can be relative to webui folder OR full - absolute" : "需要加载的设置文件路径。该路径可以相对于 SD-WebUI 根目录,也可以是完整的绝对路径", + "PBRemTools" : "精确背景去除工具", + "performance" : "性能", + "Perform warmup" : "进行预热", + "Perspective" : "透视", + "Perspective Flip" : "透视翻转", + "Perspective flip gamma" : "透视翻转伽马值", + "Perspective flip phi" : "透视翻转角度(垂直)", + "Perspective flip theta" : "透视翻转角度(水平)", + "Pick Subfolder and Model Version" : "选择子目录与模型版本", + "pin_light" : "点光", + "Pixelize" : "像素化", + "Pixel Perfect" : "完美像素模式", + "Please add text prompts to generate masks" : "请添加文本提示词以生成蒙版", + "Please always keep values in math functions above 0." : "请始终保持数学函数中的值大于 0。", + "Please use smaller tile size when got CUDA error: out of memory." : "当出现 CUDA error: out of memory 时,使用更小的分块尺寸", + "Please use smaller tile size when see CUDA error: out of memory." : "当出现 CUDA error: out of memory 时,使用更小的尺寸大小", + "PNG info" : "PNG 图片信息", + "PNG Info" : "PNG 图片信息", + "PNGs" : "图片(PNG格式)", + "points_per_batch" : "每批采样点", + "points_per_side" : "每边采样点", + "Pooling Avg" : "池化平均值", + "Pooling Max" : "池化最大值", + ", port for AUTOMATIC1111's webui maintained by" : ", AUTOMATIC1111's webui 的端口维护是", + "Pose" : "姿势", + "Positions" : "分区位置", + "positive prompt to be appended to *all* prompts" : "正向提示词会被添加到所有提示词中", + "Postprocessing" : "后期处理", + "Post Processing" : "后期处理", + "Precision" : "精度", + "predicted_iou_threshold" : "预测交并比阈值", + "pred_iou_thresh" : "预测滤波阈值", + "prepend" : "前置", + "Prepend" : "添加到开头", + "Prepend additional tags" : "将额外标签前置", + "Preprocess images" : "图像预处理", + "Preprocessor" : "预处理器", + "Preprocessor resolution" : "预处理器分辨率", + "Prerequisites and Important Info:" : "前提条件和重要信息:", + "Preset" : "预设", + "Preset Manager" : "预设管理器", + "Presets" : "预设", + "Preset Weights" : "预设权重", + "Preset_Weights" : "预设权重", + "Prev batch" : "上一批", + "Prevent empty spots in grid (when set to autodetect)" : "自动检测并消除网格图中的空位", + "Preview annotator result" : "预览预处理结果", + "Preview automatically when add/remove points" : "添加/删除标记点时自动预览", + "Preview Segmentation" : "预览分离结果", + "Preview segmentation image" : "预览语义分割图像", + "Previous" : "Previous (上一生成帧)", + "Prev Page" : "上一页", + "Primary model (A)" : "模型 A", + "print change" : "打印变更", + "Print extra hypernetwork information to console." : "将额外的超网络 (hypernetwork) 信息输出到控制台", + "Process given file(s) under the input folder, seperate by comma" : "指定在输入文件夹中要处理图像的文件名 (使用逗号隔开)", + "Progressbar/preview update period, in milliseconds" : "进度条/预览图更新周期 (毫秒)", + "Prompt" : "提示词", + "prompting" : "提示词相关", + "Prompt (press Ctrl+Enter or Alt+Enter to generate)" : "正向提示词 (按 Ctrl+Enter 或 Alt+Enter 开始生成)\nPrompt", + "Prompts" : "提示词", + "Prompts are stored in JSON format. If you've got an error, check it in a" : "提示词以 JSON 格式存储。如果有错误,请在", + "Prompts are stored in JSON format. If you've got an error, check it in validator," : "提示词以 JSON 格式存储。如果您有错误,请在验证器中检查,", + "prompts for your animation in a JSON format. Use --neg words to add 'words' as negative prompt" : "动画的提示词以 JSON 格式储存。使用 --neg 字段去添加反向提示词", + "Prompts negative" : "反向提示词", + "Prompts positive" : "正向提示词", + "Prompt Translator" : "提示词翻译器", + "Prompt, will append to your t2i prompt" : "追加提示词", + "Provider" : "提供方", + "Pruning Methods" : "模型修剪", + "Put weight sets. float number x 25" : "输入权重,共 25 个浮点数,逗号分隔", + "Quality for saved jpeg images" : "保存 JPEG 图片的质量", + "Quick" : "快速设置", + "Quick batch" : "快速批处理", + "Quick Guide" : "快速指引", + "Quick Save" : "快速保存", + "Quicksettings list" : "快捷设置列表", + "range" : "范围", + "Range" : "范围", + "ranking" : "评分", + "ranking filter" : "按图片评分过滤", + "Ranking filter" : "评分过滤器", + "Rating" : "评分", + "Rating confidents" : "评级置信度", + "Read generation parameters from prompt or last generation if prompt is empty into user interface." : "从提示词或上次生成的图片中读取生成参数", + "*READ ME before you use this mode!*" : "请在使用前认真阅读", + "Read tabular commands" : "读取 tabular 命令", + "Read tags from text files" : "从文本文件中读取提示词", + "Rebuild exif cache" : "重建 EXIF 缓存", + "Ref image (for conviently locate regions)" : "参考图(用于方便定位区域)", + "refresh" : "刷新", + "Refresh" : "刷新", + "Refresh data" : "刷新数据", + "Refresh models" : "刷新模型列表", + "regex - e.g. ^(?!.*Hires).*$" : "正则表达式 - 如 ^(?!.*Hires).*$", + "Region 1" : "区域 1", + "Region 2" : "区域 2", + "Region 3" : "区域 3", + "Region 4" : "区域 4", + "Region 5" : "区域 5", + "Region 6" : "区域 6", + "Region 7" : "区域 7", + "Region 8" : "区域 8", + "Region Prompt Control" : "分区提示词控制", + "Regions" : "分区", + "Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights." : "输入正则表达式。键名匹配该表达式的权重将从最终合并模型中剔除。使用 ^model_ema 可剔除 EMA 权重。", + "Reload Cache List" : "重载缓存列表", + "Reload checkpoint" : "刷新模型列表", + "Reload custom script bodies (No ui updates, No restart)" : "重新加载自定义脚本主体(不进行界面更新及重启)", + "Reloading..." : "正在重新加载...", + "Reload Presets" : "重载预设", + "Reload Tags" : "重载标签", + "Reload the last SD checkpoint back into VRAM" : "重新将上次使用的 Stable Diffusion 模型加载到显存中", + "Reload UI" : "重载前端", + "Reloat List" : "重新加载列表", + "remake dimension" : "重制维度", + "Remove all point prompts" : "移除所有标记点", + "Remove background image" : "移除背景图片", + "Remove duplicated tag" : "删除重复标签", + "Remove selected" : "移除已选择的图片", + "replicate" : "复制", + "Request browser notifications" : "请求浏览器通知权限", + "Requires the" : "需要安装", + "reroll" : "回滚", + "Reroll blank frames" : "回滚空白帧", + "reset" : "重置", + "Reset" : "重置", + "Reset mixer" : "重置合并设置", + "Reset Tile Size" : "重置区块大小", + "Resize" : "缩放比例", + "Resize and fill" : "缩放后填充空白", + "Resize and Fill" : "缩放后填充空白", + "Resize height to" : "将高度调整为", + "Resize mode" : "缩放模式", + "Resize Mode" : "缩放模式", + "Resize seed from height" : "从高度中调整种子", + "Resize seed from width" : "从宽度中调整种子", + "Resize width to" : "将宽度调整为", + "Resolution" : "分辨率", + "Restart" : "重启", + "Restore faces" : "面部修复", + "Restore Faces" : "面部修复", + "Restore Faces, Tiling & more" : "面部修复,平铺图等更多选项", + "Restore Last Scene" : "恢复上次场景", + "Restore Selected Config" : "恢复所选配置", + "Result = A" : "结果 = A", + "Result = A * (1 - M) + B * M" : "结果 = A * (1 - M) + B * M", + "Result = A + (B - C) * M" : "结果 = A + (B - C) * M", + "Results" : "结果", + "Resume Animation" : "重启制作动画过程", + "Resume & Run from file" : "恢复动画与加载设置", + "Reuse seed from last generation, mostly useful if it was randomed" : "使用上一次生成的随机数种子,用于重现结果", + "RGB to BGR" : "RGB 转 BGR", + "RIFE v4.6 and FILM." : "RIFE v4.6 和 FILM.", + "Roll Channels" : "色彩通道轮替", + "Rotate images (clockwise)" : "旋转图像 (顺时针)", + "Run" : "运行参数", + "Run benchmark" : "运行基准测试", + "Run from Settings file" : "加载配置文件", + "Run Merge" : "开始合并", + "Run on incomplete" : "中断后仍然运行", + "Run: Sampler, Width, Height, tiling, resize seed." : "运行参数: 采样器,宽度,高度,平铺图,种子大小调整", + "Run: seed, subseed, subseed strength." : "运行参数:第二种子,第二种子强度", + "safetensors" : "safetensors", + "SAG Mask Threshold" : "SAG 蒙版阈值", + "same to Strength" : "与强度相同", + "SAM Model" : "SAM 模型", + "sampler" : "采样器", + "Sampler" : "采样器", + "Sampler parameters" : "采样器参数", + "Sampler schedule" : "采样器参数表", + "Sampling method" : "采样方法 (Sampler)", + "Sampling settings" : "采样器设置", + "Sampling steps" : "迭代步数 (Steps)", + "Sampling Steps" : "迭代步数 (Steps)", + "SAM requires an input image. Please upload an image first." : "SAM 需要你先上传一张图片。", + "saturation" : "饱和度", + "\uD83D\uDCBE Save" : "\uD83D\uDCBE 保存", + "Save" : "保存", + "Save a copy of image before applying color correction to img2img results" : "在对图生图结果应用颜色校正之前保存图像副本", + "Save a copy of image before applying highres fix." : "在进行高分辨率修复前保存初始图像副本", + "Save a copy of image before doing face restoration." : "在进行面部修复前保存图像副本", + "Save as float16" : "储存半精度 (float16) 模型", + "Save as half" : "保存半精度模型", + "Save as safetensors" : "存为 SafeTensors 格式", + "Save background instead of foreground" : "保存背景而不是前景", + "Save changes" : "保存更改", + "Save Current Config" : "保存当前配置", + "Save current settings" : "保存当前设置", + "Save current settings as default" : "将当前设置保存为默认值", + "Save depth map" : "保存深度图", + "Save depth maps" : "保存深度图", + "Save generated images within tensorboard." : "在 tensorboard 中保存所生成的图像", + "Save grids to a subdirectory" : "将网格图保存到子目录", + "Save images to a subdirectory" : "将图像保存到子目录", + "Save JSON" : "保存为 JSON 格式", + "Save mask" : "保存蒙版", + "Save masked image" : "保存蒙版后图像", + "Save Metadata" : "保存元数据", + "save model" : "保存模型", + "Save original image with mask and bounding box" : "保存带有蒙版和箱体的原始图像", + "Save PNG" : "保存为 PNG 格式", + "Save Presets" : "保存预设", + "Save Scene" : "保存场景", + "Save Setting" : "保存设置", + "save settings" : "储存设置", + "Save Settings" : "储存设置", + "Save style" : "将当前提示词储存为预设样式", + "save successful" : "保存成功", + "Save text information about generation parameters as chunks to png files" : "将图片生成参数保存到 PNG 文件中", + "Save to Presets" : "保存到预设", + "Save vector to text file" : "将向量保存到文本文件", + "Save with JSON" : "保存为 JSON 格式", + "Saving images/grids" : "图片保存设置", + "Saving to a directory" : "保存到文件夹", + "Scale by" : "缩放倍数", + "Scale to" : "缩放到", + "Scan" : "扫描", + "Scan Models for Civitai" : "扫描并匹配 Civitai 模型记录", + "Scanning takes time, just wait. Check console log for detail" : "扫描需要一段时间,请耐心等待。检查控制台日志以查看详情。", + "schedule" : "参数表", + "screen" : "屏幕", + "scribble_hed" : "scribble_hed (涂鸦 - 合成)", + "scribble_pidinet" : "scribble_pidinet (涂鸦 - 手绘)", + "scribble_xdog" : "scribble_xdog (涂鸦 - 强化边缘)", + "script" : "脚本", + "Script" : "脚本", + "Script Enabled" : "启用脚本", + "sd-parseq manifest" : "sd-parseq 配置文件", + "SD VAE" : "外挂 VAE 模型", + "search" : "搜索", + "Search" : "搜索", + "Search for embeddings" : "搜索嵌入式模型 (Embeddings)", + "Search for Loras" : "检索 Lora 模型", + "Search for LyCORIS/LoHa" : "检索 LyCORIS/LoHa 模型", + "Search Mode" : "搜索模式", + "Search negative prompt" : "检索反向提示词", + "Secondary model (B)" : "模型 B", + "See" : "查看", + "seed" : "随机数种子 (seed)", + "Seed" : "随机数种子 (Seed)", + "Seed behavior" : "种子生成方式", + "Seed iter N" : "种子迭代量 N", + "Seed schedule" : "种子数表", + "seed_schedule should start and end on the same seed." : "种子数表应该在同一种子上开始和结束。", + "See here for explanation of each parameter." : "有关每个参数的说明,请点击 这里 查看。", + "See the progress." : "查看图像增强的实时预览进程", + "Segment Anything" : "分离图像元素(Segment Anything)", + "Segment Anything Output" : "分离元素结果", + "Segment Anything status" : "Segment Anything 状态", + "segmentation prompt" : "图像切分提示词", + "Segmentation status" : "语义分割状态", + "Select activation function of hypernetwork. Recommended : Swish / Linear(none)" : "超网络的激活函数。推荐 Swish / Linear (线性)", + "(select Disco output format)." : "(选择Disco输出格式)", + "Selected" : "选择", + "Select Translater" : "选择翻译引擎", + "Select which Real-ESRGAN models to show in the web UI. (Requires restart)" : "选择在网页界面显示哪些 Real-ESRGAN 模型。(需重启)", + "Send image to tag selection" : "发送到 标签(Tag)选择", + "Send seed when sending prompt or image to other interface" : "将提示词或者图像发送到其他界面时,同时传送种子数值", + "Send size when sending prompt or image to another interface" : "将提示词或者图像发送到其他界面时,同时传送图像尺寸", + "Send this image to ControlNet." : "将图片发送至 ControlNet", + "Send to" : "发送到", + "Send to Blend" : "发送到 混合", + "Send to Canvas Editor" : "发送到 Canvas Editor", + "Send to ControlNet" : "发送到 ControlNet", + "Send to Effect" : "发送到 效果", + "Send to extras" : "发送到 后期处理", + "Send to img2img" : "发送到 图生图", + "Send to img2img:" : "发送到 图生图:", + "Send to img2img ControlNet" : "发送到 图生图 ControlNet", + "Send to inpaint" : "发送到 重绘", + "Send to inpaint upload" : "发送到 重绘蒙版", + "Send to ip2p" : "发送到 图生图 pix2pix", + "Send to Layer1" : "发送到图层 1", + "Send to Layer2" : "发送到图层 2", + "Send to Layer3" : "发送到图层 3", + "Send to Layer4" : "发送到图层 4", + "Send to Layer5" : "发送到图层 5", + "Send to Multi-Merge" : "发送到 多重合并", + "Send to openOutpaint" : "发送到 openOutpaint", + "Send to txt2img" : "发送到 文生图", + "Send to txt2img:" : "发送到 文生图:", + "Send to txt2img and img2img" : "发送到 文生图和图生图", + "Send to txt2img ControlNet" : "发送到 文生图 ControlNet", + "Separate UNet/Text Encoder weights" : "单独设置 UNet/Text Encoder 权重", + "Sequential Merge Parameters" : "合并参数序列", + "Sequential XY Merge and Generation" : "顺序合并并生成 XY 图", + "Server start time" : "服务器启动时间", + "Set Init tab's strength slider greater than 0. Recommended value (.65 - .80)." : "将Init选项卡的强度滑块设置为大于0。建议值(.65-.80)。", + "Set Random Pose" : "设置随机姿势", + "Set 'seed_behavior' to 'schedule' under the Seed Scheduling section below." : "在下面的“种子调度”部分下,将 “seed_behavior” 设置为 “schedule” 。", + "Set the preprocessor to [invert] If your image has white background and black lines." : "如果使用白底黑线图片,请使用 \"invert\" 预处理器。", + "Set the strength to 0 automatically when no init image is used" : "当无初始化图像在再被使用时,强度值将自动设置为 0", + "settings" : "设置", + "Settings" : "设置", + "Settings File" : "设置文件", + "Settings file Path can be relative to webui folder OR full - absolute" : "设置文件路径可以相对于 SD-WebUI 根目录,也可以是完整的绝对路径", + "settings for" : "设置包括", + "Settings stack. If it's not checked, it wont overwrite. Apply one, then another. Reset is old, update how you need." : "设置堆栈。如果未选中,则不会覆盖。应用一个,再应用另一个。重置已过时,请根据需要进行更新。", + "Set your total number of keyframes to be 21 more than the last inserted keyframe image." : "将关键帧总数设置为比上次插入的关键帧图像多21个。", + "Shapes" : "形状", + "Show all pages" : "显示所有设置页", + "Show batch images in gradio gallerie output" : "在 Gradio Gallerie 输出中批量显示图像", + "Show batch images in gradio gallery output" : "在 Gradio Gallery 输出中批量显示图像", + "Show Button On Thumb Mode" : "在缩略图模式下显示按钮", + "Show Civitai Link events in the console" : "在控制台输出 Civitai Link 事件", + "Show console debug" : "在控制台显示调试信息", + "Show extra networks" : "显示扩展模型面板", + "Show extra options" : "显示额外选项", + "Show generation progress in window title." : "在窗口标题中显示生成进度", + "Show grid in results for web" : "在网页输出结果中显示网格图", + "Show/hide extra networks" : "显示/隐藏扩展模型", + "Show live previews of the created image" : "显示当前生成图像的实时预览", + "Show more info" : "显示更多信息", + "Show Preview" : "显示预览", + "Show progressbar" : "显示进度条", + "Show result images" : "显示输出图像", + "Show warnings in console." : "在控制台中显示警告", + "shuffle" : "shuffle (随机洗牌)", + "Sigma schedule" : "Sigma 值表", + "Simple" : "单一值", + "Simple (Auto-value)" : "单一值(自动取值)", + "single image" : "单张图片", + "Single Image" : "单张图片", + "Single process" : "单张图片", + "sketch" : "涂鸦", + "Sketch" : "涂鸦", + "Skip" : "跳过", + "Skip img2img processing when using img2img initial image" : "使用图生图初始图像时跳过图生图处理", + "SKip NSFW Preview images" : "下载预览图时跳过含成人内容的图像", + "SKip NSFW Preview Images" : "下载预览图时跳过含成人内容的图像", + "Skip/Reset CLIP position_ids" : "跳过或重置 CLIP position_ids 键值", + "Skip video creation" : "跳过视频生成", + "softedge_hed" : "softedge_hed (HED 软边缘检测)", + "soft_light" : "柔光", + "sort by" : "排序方式", + "Sort by" : "排序方式", + "Sort by alphabetical order" : "按首字母顺序排序", + "Sort LoRA models by" : "低秩微调 (LoRA) 模型排序方式", + "Soundtrack path" : "音轨路径", + "Source" : "来源", + "Source directory" : "源目录", + "Source URL where this model could be found" : "该模型发布的原始网址", + "Specific branch name" : "特定分支名", + "specify a custom settings file and ignore settings displayed in the interface" : "指定自定义设置文件并忽略界面中显示的设置", + "Specify the amount that you wish to expand the mask by (recommend 0-10)" : "设定蒙版扩展量(建议0-10)", + "Specify the amount that you wish to expand the mask by (recommend 30)" : "设定蒙版扩展量(建议30)", + "specify your own seed schedule (found on the Keyframes page)" : "指定你自己的种子数表(可在关键帧选项卡中找到)", + "Split oversized images" : "分割过大的图像", + "stability_score_offset" : "稳定性得分偏移", + "stability_score_thresh" : "稳定性得分阈值", + "stability_score_threshold" : "稳定性得分阈值", + "Stable Diffusion checkpoint" : "Stable Diffusion 模型", + "Stackable" : "可堆叠", + "Stackable checkbox is not used for saves, it's used when making a selection from the dropdown, whether to apply as stackable or not" : "可堆叠复选框不用于保存,它用于从下拉列表中进行选择,无论是否应用为可堆叠", + "Start Auto Translate" : "开始自动翻译", + "Start batch process" : "开始批量处理", + "start extracting the input video only from this frame number" : "你所需要提取开始初始化视频的帧数", + "Starting Control Step" : "引导介入步数", + "Start steps" : "开始步数", + "State" : "运行状态", + "status" : "状态", + "Std" : "标准差", + "Step" : "迭代步数", + "Steps" : "迭代步数", + "Steps schedule" : "迭代步数明细表", + "*Stitch frames to video*" : "*将帧缝合到视频中*", + "Stop" : "停止", + "stop the extraction of the video at this frame number. -1 for no limits" : "你所需要提取结束初始化视频的帧数,-1 表示无限制(全部)", + "Stop XY" : "停止生成 X/Y 图", + "Store frames in ram" : "将帧保存到内存", + "strength" : "强度", + "Strength" : "强度", + "Strength 0 no init" : "强度为 0 时停用初始化", + "Styles" : "预设样式", + "Sub directory depth" : "子目录深度", + "Sub-folder" : "子文件夹", + "Submit" : "提交", + "Submit results" : "提交结果", + "SubSeed" : "第二种子", + "Subseed schedule" : "第二种子参数表", + "Subseed strength schedule" : "第二种子强度参数表", + "Sum" : "和", + "sum Twice:(A*(1-alpha)+B*alpha)*(1-beta)+C*beta" : "两次求和: (A*(1-α)+B*α)*(1-β)+C*β", + "SuperMerger" : "超级模型融合", + "Supported engines:" : "支持的引擎:", + "Supports boolean operations: (! - negation, & - and, | - or, ^ - xor, \\ - difference, () - nested operations)" : "支持布尔操作符:(!-否定/取反,&-与,|-或,^-异或,\\-差分,()-嵌套操作)", + "Switch prompt between Native language and English" : "切换提示词显示语言 (母语/英语)", + "Switch to Inpaint Upload" : "发送到 重绘蒙版", + "System" : "系统设置", + "System data" : "系统信息", + "System Info" : "系统信息", + "tab" : "选项卡", + "Tag Autocomplete" : "标签自动补全", + "Tag confidents" : "标签置信度", + "Tags" : "标签", + "Target language" : "目标语言", + "Target tokens (comma separated)" : "分隔目标提示词(逗号分隔)", + "temparature" : "色温", + "Tertiary model (C)" : "模型 C", + "TEST-MAX-ALL" : "全部测试", + "Text files directory (optional, will load from input dir if not specified)" : "文本文件目录 (可选, 如不指定将从输入目录加载)", + "Text files directory (Optional, will load from input dir if not specified)" : "文本文件目录 (可选, 如不指定将从输入目录加载)", + "The 1st and last keyframe images should match." : "第一个和最后一个关键帧图像应该匹配。", + "The algorithm is not able to enhance all images." : "本算法不能增强所有图像", + "The annotator directory inside the SAM extension directory is only a symbolic link. This is to save your space and make the extension repository clean." : "SAM 扩展目录中的解释器目录只是符号链接。这样能够节省你的硬盘空间,并使扩展库更加有序。", + "The code for this extension:" : "本插件的源代码链接:", + "The current workflow is [text prompt]->[object detection]->[segmentation]. Semantic segmentation support is in Auto SAM panel." : "目前的工作流是 [文本提示词]->[对象检测]->[语义分割]。语义分割支持在自动 SAM 面板中。", + "The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M" : "后两个模型的差值将叠加在主要模型上。需要输入 A、B、C 三个模型。计算公式为 A + (B - C) * M", + "the directory in which your mask video is located." : "你所需要使用的视频蒙版路径", + "the directory / URL at which your video file is located for Video Input mode only" : "视频文件所在的目录/链接,仅适用于视频输入模式", + "The frames per second that the video will run at" : "你所需要的视频帧数", + "The height of the output images, in pixels (must be a multiple of 64)" : "输出图像的高度(像素)(必须能整除于 64)", + "The other site allows for making keyframes using" : "另一方面,允许关键帧使用", + "the path to a custom settings file" : "自定义设置文件的路径", + "the path to your init image" : "初始化图像的路径", + "the path to your mask image" : "蒙版文件的路径", + "the path/ URL to an audio file to accompany the video" : "视频附带的音频文件的路径 / 链接", + "There is *no* Batch mode like in vanilla deforum. Please Use the txt2img tab for that." : "本插件没有批处理模式,请使用文生图选项卡。", + "the roll effect angle" : "所旋转的角度(X轴,一般性指水平)", + "the seed value will increment by 1 for each subsequent frame of the animation" : "对于动画的每个后续帧,种子数将增加 1", + "the seed will remain fixed across all frames of animation" : "动画中所有帧的随机种子将被固定", + "the tilt effect angle" : "所翻转的垂直角度(Y轴)", + "The untranslated characters will be translated automatically and will not affect the old translations. Use the function in the lower right corner to easily check and quickly modify the current translation.1,Save the setting;2,Click start button;3,Reload your browser." : "未翻译的提示词将自动翻译,不会影响已翻译过的提示词。使用右下方的功能按钮可以快速检查和修改当前的翻译。1.保存设置;2.点击启动按钮;3.重载浏览器。", + "The width of the output images, in pixels (must be a multiple of 64)" : "输出图像的宽度(像素,必须能整除于 64)", + "Third column (reference) image" : "第三列 (参考) 图像", + "This preset affects?" : "该预设中包含?", + "threshold" : "threshold (阈值)", + "Threshold" : "阈值", + "Thresholding Mode" : "阈值模式", + "Threshold schedule" : "阈值表", + "Threshold Value Lower" : "阈值下限", + "Threshold Value Upper" : "阈值上限", + "tile division BG Removers" : "分块化背景去除", + "tile_resample" : "tile_resample (分块重采样)", + "Tile size for all SwinIR." : "适用所有 SwinIR 系算法的图块尺寸 (Tile size)", + "Tile size for ESRGAN upscalers. 0 = no tiling." : "ESRGAN 使用的图块尺寸 (Tile size)。0 为不分块 (no tiling)", + "Tiling" : "平铺图 (Tiling)", + "Time" : "时间", + "timestamp" : "时间戳", + "Tips" : "小提示", + "To apply, go to quick set. Save now works immediately in other tab without restart, filters out non-common between tabs." : "要应用,请转到快速设置。现在保存可以立即在其他选项卡中工作,无需重新启动,过滤掉选项卡之间的不常见内容。", + "To enable, check use_mask in the Init tab" : "如果需要启用,请检查初始化选项卡中启用蒙版选项是否其启用", + "Token" : "词元", + "To Language" : "目标语言", + "(Total)" : "(合计)", + "Train" : "训练", + "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images" : "训练嵌入式或超网络模型;必须指定一个具有一组 1:1 宽高比图像的数据集目录", + "Train Embedding" : "训练嵌入式模型", + "Train Hypernetwork" : "训练超网络模型", + "training" : "训练相关", + "Training" : "训练", + "Training info" : "训练信息", + "Training parameters" : "训练参数", + "Transform Center X" : "旋转中心点 X 轴", + "Transform Center Y" : "旋转中心点 Y 轴", + "translate" : "翻译", + "Translate" : "翻译", + "Translated Negative Prompt" : "反向提示词翻译", + "Translated Prompt" : "提示词翻译", + "Translate Negative Prompt" : "翻译反向提示词", + "Translate Prompt" : "翻译提示词", + "Translate: x, y, z" : "平移:x, y, z", + "Translation display order" : "翻译显示顺序", + "Translation First" : "译文在上", + "Translation Service Setting" : "翻译服务设置", + "Translation X" : "平移 X", + "Translation Y" : "平移 Y", + "Translation Z" : "平移 Z", + "Triple sum:A*(1-alpha-beta)+B*alpha+C*beta" : "三重加权和: A*(1-α-β)+B*α+C*β", + "Turn on pin_memory for DataLoader. Makes training slightly faster but can increase memory usage." : "为数据加载器 (DataLoader) 启用 pin_memory 参数,以提升内存占用的代价提高训练速度", + "Tweening frames schedule" : "中间计算帧参数表", + "txt2img" : "文生图", + "txt2img-grids" : "文生图 (网格)", + "txt2img/img2img UI item order" : "文生图/图生图界面参数组件顺序", + "Type" : "类型", + "UI related" : "UI 界面相关", + "Uncheck all copies" : "取消勾选所有选择", + "U-Net features" : "U-Net 特征值", + "Unfreeze seed" : "不固定种子", + "uniform" : "均匀", + "UniPC variant" : "UniPC 变体", + "unknown" : "未知", + "Unload all interrogate models" : "卸载所有反推模型", + "Unload all models from memory" : "从内存中卸载所有模型", + "unload model" : "卸载模型", + "Unload model after running" : "反推完成后卸载模型", + "Unload models" : "卸载模型", + "Unload SD checkpoint to free VRAM" : "卸载 Stable Diffusion 模型以释放显存", + "Upcast cross attention layer to float32" : "将交叉关注层向上转换到 float32", + "Update" : "更新", + "update list" : "更新列表", + "Update Mask" : "更新蒙版", + "uploaded video FPS" : "上传视频的帧率", + "uploaded video resolution" : "上传视频的分辨率", + "uploaded video total frame count" : "上传视频的总帧数", + "Upscale" : "图像放大", + "Upscale by" : "放大倍数", + "Upscale factor" : "放大比率", + "Upscale height" : "放大高度", + "Upscale model" : "超分模型", + "Upscaler" : "放大算法", + "Upscaler 1" : "放大算法 1", + "Upscaler 2" : "放大算法 2", + "Upscaler 2 visibility" : "放大算法 2 强度", + "Upscale ratio" : "放大倍率", + "Upscaler for img2img" : "图生图放大算法", + "*Upscale uploaded video*" : "*超分已上传的视频*", + "Upscale width" : "放大宽度", + "Upscaling" : "图片放大", + "URL for extension's git repository" : "扩展的 git 仓库网址", + "Use" : "使用", + "Use alpha as mask" : "启用透明度蒙版", + "Use an" : "使用一个", + "Use another image as ControlNet input" : "使用另外的图像输入 ControlNet", + "Use another image as mask" : "使用另外的图像作为遮罩", + "Use BLIP for caption" : "使用 BLIP 生成标签 (自然语言)", + "Use Control Net inpaint model" : "使用 ControlNet 的 inpait 模型", + "Use cross attention optimizations while training" : "训练时开启 Cross Attention 优化", + "Use deepbooru for caption" : "使用 Deepbooru 生成标签", + "Use delta values for movement parameters" : "使用增量值作为运动参数", + "Use dropdown for sampler selection instead of radio group" : "采样器列表处使用下拉菜单取代单选框", + "Use dropout" : "使用 dropout", + "Use init" : "使用初始化", + "Use inpaint width/height" : "启用自定义重绘宽高", + "Use input image's alpha channel as mask" : "使用输入图像的透明度通道作为遮罩", + "Use Lora in uc diffusion model" : "在反向扩散模型中使用 LoRA", + "Use Lora in uc text model encoder" : "在反向文本编码器中使用 LoRA", + "Use lossless compression for webp images" : "对 WebP 图像使用无损压缩", + "Use mask" : "使用蒙版", + "Use mask as output alpha channel" : "使用遮罩作为透明度通道输出", + "Use mask video" : "使用视频蒙版", + "use MBW" : "使用分块合并", + "Use mid-control on highres pass (second pass)" : "进行高分辨率修复时使用中间层控制 (mid-control)", + "Use noise mask" : "使用噪点蒙版", + "Use old emphasis implementation. Can be useful to reproduce old seeds." : "使用旧的强调符号解析器,可用于复现早期种子结果 (2022-09-29)", + "Use old karras scheduler sigmas (0.1 to 10)." : "对于 Karras 调度器使用旧的 sigma 值范围 (0.1 - 10) (2023-01-01)", + "Use recursive with glob pattern" : "使用 glob 模式递归搜索", + "User interface" : "用户界面", + "username" : "用户名", + "Username" : "用户名", + "Use spaces instead of underscore" : "使用空格代替下划线", + "Uses your" : "使用你的", + "Use the negative_prompts field to automatically append all words as a negative prompt. *Don't* add --neg in the negative_prompts field!" : "使用 negative_prompts 字段自动将所有单词附加为反向提示词,不要在 negative_prempts 字段中添加 --neg !", + "Use this when scanning can not find a local model on civitai" : "无法通过扫描获取本地模型信息时使用此功能", + "Use upscaler name as filename suffix in the extras tab" : "后期处理时将超分算法名称添加到文件名后缀中", + "VAE Checkpoints to cache in RAM" : "保留在内存中的 VAE 模型数量", + "Variation seed" : "变异随机种子", + "Variation strength" : "变异强度", + "Vectors" : "向量", + "verbose console output" : "将详细信息输出到控制台", + "version" : "版本", + "Version" : "版本", + "Vertical Mirroring" : "垂直镜像", + "vertical split num" : "垂直分割数", + "Vid2depth" : "视频转深度", + "Video" : "视频", + "Video Depth" : "视频深度", + "Video Init" : "视频初始化", + "Video init path" : "初始化视频路径", + "video_init_path, extract_nth_frame, overwrite_extracted_frames" : "初始化视频路径,提取第N帧,覆盖提取帧数", + "Video Input" : "视频输入", + "video_input mode only, enables the extraction and use of a separate video file intended for use as a mask. White areas of the extracted video frames will not be affected by diffusion, while black areas will be fully effected. Lighter/darker areas are affected dynamically." : "仅视频输入模式使用,提取和使用单独的视频文件作为蒙版。提取的视频帧的白色区域将不受生成器的影响,而黑色区域将完全受到影响。较亮/较暗的区域会受到动态影响。", + "Video mask path" : "视频蒙版路径", + "Video Output Settings" : "视频输出设置", + "Video to get Depth from" : "从视频中获取深度", + "Video to Upscale" : "待放大视频", + "Video Upscaling" : "视频超分", + "Visualize" : "可视化预览", + "vivid_light" : "亮光", + "VRAM usage polls per second during generation. Set to 0 to disable." : "生成图像时,每秒查询显存 (VRAM) 使用情况的次数。设置为 0 可禁用", + "Weight" : "权重", + "Weight 1" : "权重 1", + "Weight 2" : "权重 2", + "Weight 3" : "权重 3", + "Weight 4" : "权重 4", + "Weight 5" : "权重 5", + "Weighted sum" : "加权和", + "Weights" : "权重", + "weights alpha" : "权重 α", + "Weights alpha" : "权重 α", + "weights beta" : "权重 β", + "Weights beta" : "权重 β", + "Weights Presets" : "权重预设", + "Weights setting" : "权重设置", + "Weights Setting" : "权重设置", + "Weight sum:A*(1-alpha)+B*alpha" : "加权和: A*(1-α)+B*α", + "Weight values" : "权重值", + "Weight_values" : "权重值", + "When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it." : "当添加扩展模型 (如 Hypernetwork 或 Lora) 到提示词中时,默认使用此倍率。", + "when checked, do not output a video" : "选中时,将不会输出视频", + "when enabled, will re-extract video frames each run. When using video_input mode, the run will be instructed to write video frames to the drive. If you’ve already populated the frames needed, uncheck this box to skip past redundant extraction, and immediately start the render. If you have not extracted frames, you must run at least once with this box checked to write the necessary frames." : "启用时,将在每次运行时重新提取视频帧。使用video_input模式时,运行程序将视频帧写入驱动器。如果已经填充了所需的帧,请取消选中此框以跳过多余的提取,然后立即开始渲染。如果尚未提取帧,则必须在选中此框的情况下至少运行一次,以写入必要的帧。", + "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint." : "当从 PNG 图片信息或粘贴文本读取生成参数到用户界面时,不要根据参数更改当前选定模型", + "when this box is checked, and FFMPEG mp4 is selected as the output format, an audio file will be multiplexed with the video." : "选中此框,并选择 FFMPEG mp4 作为输出格式时,音频文件将与视频复用。", + "When using 'Save' button, only save a single selected image" : "使用“保存”按钮时,只保存一个选定的图像", + "Whether to use optical flow to blend frames during cadence (if cadence more than 1)" : "在生成间隔期间,使用光流法渲染帧(即使间隔大于1)", + "Whole picture" : "整张图片", + "width" : "宽度", + "Width" : "宽度", + "Width/height limit for the above option, in pixels" : "上述选项的 宽/高 限制,单位:像素", + "[wiki]" : "[文档]", + "wiki" : "文档", + "will output a greyscale depth map image alongside the output images." : "将与输出图像一起输出灰度深度图图像。", + "With img2img, fill image's transparent parts with this color." : "在图生图中使用以下颜色填充透明区域", + "word masks" : " ", + "*Work In Progress*. All params below are going to be keyframable at some point. If you want to speedup the integration, join Deforum's development. \uD83D\uDE09" : "*正在开发*. 下面的所有参数在某些点是关键的。如果你想加快集成,请加入 Deforum 的开发。\uD83D\uDE09", + "write merged model ID to" : "将融合模型 ID 写入到", + "x center axis for 2D angle/zoom *only*" : "2D 旋转/缩放中 X 轴的中心点", + "xmenber" : "X 值", + "X panning" : "X 轴平移量", + "xtype" : "X 类型", + "X type" : "X 轴类型", + "X Types" : "X 轴类型", + "X values" : "X 轴值", + "X/Y plot" : "X/Y 图表", + "X/Y/Z plot" : "X/Y/Z 图表", + "XYZ plot" : "XYZ 图", + "y center axis for 2D angle/zoom *only*" : "2D 旋转/缩放中 Y 轴中心点", + "ymenber" : "Y 值", + "You can change the maximum execution time, by default it’s 30seconds." : "你可以调节最大执行时间,默认 30 秒。", + "You can enhance semantic segmentation for control_v11p_sd15_seg from lllyasviel. Non-semantic segmentation for Edit-Anything will be supported when they convert their models to lllyasviel format." : "你可以使用 lllyasviel 的 control_v11p_sd15_seg 模型进行语义分割。当模型转换为 lllyasviel 格式时,将还将支持Edit-Anything 的非语义分割。", + "You can generate image layout either in single image or in batch. Since there might be A LOT of outputs, there is no gallery for preview. You need to go to the output folder for either single image or batch process." : "你可以生成单张图像或批量的图像分布。由于可能有大量图片的输出,所以无法预览。你需要进入输出文件夹,查看和进行后续操作。", + "You can mask images by their categories via semantic segmentation. Please enter category ids (integers), separated by +. Visit here for ade20k and here for coco to get category->id map. Note that coco jumps some numbers, so the actual ID is line_number - 21." : "你可以通过语义分割模型按类别创建蒙版。请输入类别 ID(整数),用+分隔。可以访问 [这里] 获取 ade20k 的分类列表,或者 [这里] 获取 coco 的分类列表。注意,coco 会略过一些数字,所以实际的 ID 是列表中编号 -21。", + "You can stop the algorithm at any time" : "你可以在任意时间停止图像增强算法", + "You can try it by own, to dig more deeper into Abyss ..." : "可自行探索,以窥深渊...", + "You can use this as a guided image tool or as a looper depending on your settings in the keyframe images field. \n Set the keyframes and the images that you want to show up. \n Note: the number of frames between each keyframe should be greater than the tweening frames." : "根据关键帧图像字段中的设置,可以将其用作引导图像工具或循环器。\n设置要显示的关键帧和图像。\n注意:每个关键帧之间的帧数应大于中间帧。", + "You can use this as a guided image tool or as a looper depending on your settings in the keyframe images field. \n Set the keyframes and the images that you want to show up. \n Note: the number of frames between each keyframe should be greater than the tweening frames." : "根据关键帧图像字段中的设置,可以将其用作引导图像工具或循环器。\n设置要显示的关键帧和图像。\n注意:每个关键帧之间的帧数应大于中间帧。", + "You may configurate automatic sam generation. " : "你可以配置自动 SAM 的参数。", + "You may configurate the following items and generate masked image for all images under a directory. This mode is designed for generating LoRA/LyCORIS training set." : "你可以配置下面的项目,为目录下所有图像生成蒙版。该模式是为生成 LoRA / LyCORIS 训练集设计的。", + "Your Civitai API Key" : "Civitai API 密钥", + "Your Civitai Link Key" : "Civitai Link 密钥", + "Y panning" : "Y 轴平移量", + "ytype" : "Y 类型", + "Y type" : "Y 轴类型", + "Y Types" : "Y 轴类型", + "Y values" : "Y 轴值", + "Y Values" : "Y 轴值", + "Zip" : "打包下载", + "ZoeDepth was not trained on panoramic images. It doesn't know anything about panoramas or spherical projection. Here, we just treat the estimated depth as radius and some projection errors are expected. Nonetheless, ZoeDepth still works surprisingly well on 360 reconstruction." : "ZoeDepth 不是基于全景图像上训练的。它无法识别全景图或球形投影的特征。在这个选项卡,它仅把估计的深度当作半径,所以会产生一些预料中的投影误差。尽管如此,ZoeDepth 在 360° 重建模型上仍有令人惊讶的效果。", + "ZoeDepth was not trained on panoramic images. It doesn’t know anything about panoramas or spherical projection. Here, we just treat the estimated depth as radius and some projection errors are expected. Nonetheless, ZoeDepth still works surprisingly well on 360 reconstruction." : "ZoeDepth 不是基于全景图像上训练的。它无法识别全景图或球形投影的特征。在这个选项卡,它仅把估计的深度当作半径,所以会产生一些预料中的投影误差。尽管如此,ZoeDepth 在 360° 重建模型上仍有令人惊讶的效果。", + "Zoom" : "缩放参数", + "Zoom in masked area" : "缩放遮罩区域", + "Z type" : "Z 轴类型", + "Z values" : "Z 轴值" +} \ No newline at end of file diff --git a/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Testing).json b/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Testing).json new file mode 100644 index 0000000000000000000000000000000000000000..488eee9e30093edbee52f2c456dec489059ba331 --- /dev/null +++ b/stable-diffusion-webui-localization-zh_Hans/localizations/zh-Hans (Testing).json @@ -0,0 +1,3584 @@ +{ + "{{1-$$and$$__adjective__}}" : "{{1-3$$and$$__adjective__}}", + "{1-3$$artist1|artist2|artist3}" : "{1-3$$艺术家1|艺术家2|艺术家3}", + "180 Degree Rotation" : "180 度旋转", + "1. Create your wildcard library by copying a collection using the dropdown below." : "1.通过使用下拉菜单复制一个集合来创建您的通配符库。", + "1. Get Model Info by Civitai Url" : "从 Civitai 链接拉取模型信息", + "1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'" : "第一个和最后一个数字必须是 0,其他值应介于 0 和 1 之间。如:’0, 0.01, 0’", + "1st and last digit must be 1. ex:'1, 2, 1'" : "第一个和最后一个数字必须是 1。例:'1, 2, 1'", + "1. The tags common to all displayed images are shown in comma separated style." : "1. 所有显示图像的共同tag要用逗号分隔的样式显示。\n\n ", + "{2$$__artist__}" : "{2$$__艺术家__}", + "{2$$artist1|artist2|artist3}" : "{2$$艺术家1|艺术家2|艺术家3}", + "{2$$__artist__|__artist__}" : "{2$$__艺术家__|__艺术家_}", + "2. Click on any of the files that appear in the tree to edit them." : "2. 单击树中出现的任何文件来编辑它们。", + "2D and 3D settings" : "2D 及 3D 设定", + "2D operator that scales the canvas size, multiplicatively. [static = 1.0]" : "缩放画布大小的2D操作符,以倍数缩放。[static=1.0]", + "2D operator to rotate canvas clockwise/anticlockwise in degrees per frame" : "2D 操作器对每帧动画顺时针/逆时针旋转所指定的角度", + "2D or 3D animation_mode" : "2D 或 3D 动画模式中", + "2. When changes are applied, all tags in each displayed images are replaced." : "当应用更改时,所有所显示的图像的标签将会被替换", + "360 Panorama to 3D" : "360°全景图转 3D", + "3D Fov settings:" : "3D 视野设置:", + "3d glb" : "3D (GLB 格式)", + "3D Openpose" : "3D 骨架模型编辑 (3D Openpose)", + "3. Download Model" : "下载模型", + "3D Rendering" : "3D渲染中", + "3D settings" : "3D 设定", + "3. If you change some tags into blank, they will be erased." : "如果你更改某些标签到空白处,他们将会被移除", + "4. If you add some tags to the end, they will be added to the end/beginning of the text file." : "如果你将一些 tags 添加至末端,它们将被添加在文本文件的开始/末尾。", + "5. Changes are not applied to the text files until the \"Save all changes\" button is pressed." : "在按下保存所有更改的按钮之前,所有在文本文件中所做的更改将不会生效", + "5 times instead of 4." : "5 次而非 4 次。", + "60s Art" : "60 年代艺术风格", + "70s Art" : "70 年代艺术风格", + "80s Art" : "80 年代艺术风格", + "90 Degree Rotation" : "90 度旋转", + "(A10) Primary" : "(A10) 主要", + "(A1) Primary" : "(A1) 主要", + "(A2) Primary" : "(A2) 主要", + "(A3) Primary" : "(A3) 主要", + "(A4) Primary" : "(A4) 主要", + "(A5) Primary" : "(A5) 主要", + "(A6) Primary" : "(A6) 主要", + "(A7) Primary" : "(A7) 主要", + "(A8) Primary" : "(A8) 主要", + "(A9) Primary" : "(A9) 主要", + "A&B" : "A&B", + "A-B" : "A-B", + "A basic img2img script that will dump frames and build a video file. Suitable for creating interesting zoom-in warping movies. This is intended to be a versatile toolset to help you automate some img2img tasks." : "一个基本的图生图脚本,能够把多个帧图像构建成为视频文件,适用于创建有趣的变焦镜头影片。它是多功能的工具集,能够帮助你自动完成一系列图生图任务。", + "a bit better, but it conflicted with less-than, greater-than logic operators. This means that older templates may not work in v2.0.0, which is a bit of a pain. I only make breaking changes like this when I feel it's worthwhile." : "略优一点,但它与小于 (<)、大于 (>) 逻辑运算符有冲突,这意味着旧的模板可能无法在 v2.0.0 中使用,这有点麻烦。只有在值得这样做的时候,才会进行破坏性的改变。", + "A, B or C" : "A, B 或 C", + "About" : "关于", + "Abs" : "绝对值", + "abs. path or url to audio file" : "音频文件的绝对路径或 URL", + "Abstract Art" : "抽象艺术", + "Abstract Expressionism" : "抽象表现主义", + "Abstract Illusionism" : "抽象幻想主义", + "Academism" : "学院主义(学院派)", + "Accent" : "Catppuccin 主题风格(按钮颜色,根据主题样式不同会发生变化,不一定完全与描述相同)", + "Access results in ‘Open results’." : "点击“打开最终效果图”获取增强后的图片", + "Acclaimed" : "广受好评", + "According to Live preview subject setting" : "根据实时预览的主体设置", + "Accumulation steps" : "累加步数", + "Action" : "操作", + "Action on existing caption" : "对已有标注的操作", + "Action on exiting caption" : "对退出符的响应方式", + "Actions" : "其他操作", + "Activate Selected Script" : "激活选定脚本", + "Activate 'Show results in WebUI' checkbox to see results in the WebUI at the end (not recommended when processing a large number of images)" : "激活“在 WebUI 中显示结果”复选框,以在结束时在 WebUI 上查看结果(处理大量图像时不建议使用)", + "Activation keywords, comma-separated" : "该模型的触发词,以逗号分隔", + "Active" : "启用", + "Active in img2img (Requires restart)" : "在图生图中启用(需要保存设置并重启UI)", + "Active in negative prompts (Requires restart)" : "在反向提示词输入框中启用(需要保存设置并重启UI)", + "Active in third party textboxes [Dataset Tag Editor] (Requires restart)" : "在第三方输入框中启用 [数据集标签编辑器](需要保存设置并重启)", + "Active in txt2img (Requires restart)" : "在文生图中启用(需要保存设置并重启UI)", + "Adam Epsilon" : "Adam Epsilon (替代 0 的常量,防止直接除以 0)", + "Adam Weight Decay" : "Adam 权重衰减(Weight Decay)", + "Adaptive (Gaussian)" : "自适应(高斯)", + "Adaptive (Mean)" : "自适应(平均值)", + "➕ Add" : "➕ 添加", + "Add" : "添加", + "Add a button to convert the prompts used in NovelAI for use in the WebUI. In addition, add a button that allows you to recall a previously used prompt." : "添加一个按钮以将 NovelAI 中使用的提示词转换为在 WebUI 中使用。此外,添加一个按钮,让你可以调用以前使用过的提示词", + "Add ALL Displayed" : "添加所有已显示图片", + "Add a random artist to the prompt." : "随机添加一个艺术家到提示词中", + "Add a second progress bar to the console that shows progress for an entire job." : "向控制台添加第二个进度条以显示作业的整体进度", + "add audio to video from file/url or init video" : "从文件/链接或初始化视频中提取音频", + "Add background image" : "添加背景图片", + "Add Background image" : "添加背景图片", + "Add Background Image" : "添加背景图片", + "Add CLIP results to Caption" : "将 CLIP 结果添加到标签中", + "Add custom keyword(trigger word) mapping for selected LORA model." : "为选定的 LORA 模型添加自定义关键词(触发词)映射", + "Add Custom Mappings" : "添加自定义映射", + "Add DeepDanbooru Tags to Caption" : "将 DeepDanbooru 标签添加到标题", + "Add difference" : "差额叠加", + "Add difference:A+(B-C)*alpha" : "差额叠加: A+(B-C)*α", + "Added" : "已添加", + "Add emphasis to a randomly selected keyword in the prompt." : "在提示词中随机选择一个关键字加上强调符", + "Add extended info (seed, prompt) to filename when saving grid" : "保存网格图时,将扩展信息(随机种子、提示词)添加到文件名", + "Add hypernetwork to prompt" : "将 hypernetwork 添加到提示词", + "Add image number to grid" : "在网格图上添加图像编号", + "Add inpaint batch mask directory to enable inpaint batch processing." : "添加重绘蒙版目录去启用重绘蒙版功能", + "Additional Generation Info" : "附加生成信息", + "Additional tags (split by comma)" : "附加提示词 (逗号分隔)", + "Add layer normalization" : "启用网络层标准化处理", + "Add Lora to prompt" : "将 Lora 添加到提示词", + "Add LyCORIS to prompt" : "将 LyCORIS 添加到提示词", + "Add model hash to generation information" : "将模型哈希值添加到生成信息", + "Add model name to generation information" : "将模型名称添加到生成信息", + "AddNet Model 1" : "附加模型 1", + "AddNet Model 2" : "附加模型 2", + "AddNet Model 3" : "附加模型 3", + "AddNet Model 4" : "附加模型 4", + "AddNet Model 5" : "附加模型 5", + "AddNet TEnc Weight 1" : "附加模型 1 Text Encoder 权重", + "AddNet TEnc Weight 2" : "附加模型 2 Text Encoder 权重", + "AddNet TEnc Weight 3" : "附加模型 3 Text Encoder 权重", + "AddNet TEnc Weight 4" : "附加模型 4 Text Encoder 权重", + "AddNet TEnc Weight 5" : "附加模型 5 Text Encoder 权重", + "AddNet UNet Weight 1" : "附加模型 1 UNet 权重", + "AddNet UNet Weight 2" : "附加模型 2 UNet 权重", + "AddNet UNet Weight 3" : "附加模型 3 UNet 权重", + "AddNet UNet Weight 4" : "附加模型 4 UNet 权重", + "AddNet UNet Weight 5" : "附加模型 5 UNet 权重", + "AddNet Weight 1" : "附加模型 1 权重", + "AddNet Weight 2" : "附加模型 2 权重", + "AddNet Weight 3" : "附加模型 3 权重", + "AddNet Weight 4" : "附加模型 4 权重", + "AddNet Weight 5" : "附加模型 5 权重", + "Add number to filename when saving" : "在文件名前添加序号", + "Add/Remove..." : "添加/删除...", + "Adds a configurable dropdown to allow you to change UI preset settings in the txt2img and img2img tabs." : "添加一个可配置的下拉列表,允许您更改文生图 (txt2img) 和图生图 (img2img) 选项卡中的 UI 预设设置。", + "Adds a tab that lets you preview how CLIP model would tokenize your text." : "新增一个选项卡让你能够预览 CLIP 模型如何对你的文本进行词元拆分(tokenize)", + "Adds a tab to the webui that allows the user to automatically extract keyframes from video, and manually extract 512x512 crops of those frames for use in model training." : "向 webui 添加一个选项卡,允许用户自动从视频中提取关键帧,并手动裁剪 512x512 大小以用于模型训练", + "Adds customizable dynamic thresholding to allow high CFG Scale values without the burning / 'pop art' effect." : "添加可自定义的动态阈值,以允许用户使用更高的CFG值而不会产生高光处失去细节或过强的对比度等效果", + "Add selection [Enter]" : "添加选择 [输入]", + "Adds image aspect ratio selector buttons." : "添加图像长宽比选项按钮", + "Add soundtrack" : "添加音轨", + "'add_soundtrack' and 'soundtrack_path' aren't being honoured in \"Interpolate an existing video\" mode. Original vid audio will be used instead with the same slow-mo rules above." : "‘添加音频’和‘音频路径’将不会在‘插入现有视频’模式中执行,原有视频的音频将会使用相同的慢动作规则设置", + "Add to / replace in saved directories" : "添加/替换 已保存的目录", + "Add to Sequence X" : "添加到 X 轴", + "Add to Sequence Y" : "添加到 Y 轴", + "Add WD14 Tags to Caption" : "将 WD14 Tags 添加到到标题中", + "Add weights to Sequence X" : "将权重添加到 X 序列中", + "ADetailer CFG scale" : "After Detailer 提示词引导系数 (CFG scale)", + "ADetailer confidence threshold %" : "置信阈值 (单位: %)", + "ADetailer denoising strength" : "重绘幅度", + "ADetailer erosion (-) / dilation (+)" : "图像腐蚀 (-) / 图像膨胀 (+)", + "ADetailer mask blur" : "蒙版边缘模糊度", + "ADetailer model" : "After Detailer 模型", + "ADetailer negative prompt" : "After Detailer 反向提示词", + "ADetailer prompt" : "After Detailer 正向提示词", + "ADetailer x(→) offset" : "X轴 (→) 偏移", + "ADetailer y(↑) offset" : "Y轴 (↑) 偏移", + ": a dictionary of the shortcode's keyword arguments." : "简码关键字参数的字典", + "Adi Granov" : "阿迪·格拉诺夫", + "A directory on the same machine where the server is running." : "服务器主机上某一文件夹", + "A directory or a file" : "一个文件或文件夹", + "A directory or a file. Keep this empty to use the alpha channel of image as mask" : "填入目录或文件。保持为空以使用图像的alpha通道作为遮罩", + "Adjust desired FPS if needed/wanted. Default slider position is original FPS." : "调整所需的FPS。默认滑块位置为原始FPS。", + "Adjusts the generated prompt. You will need to experiment with this setting." : "调整生成的提示词,使用时要尝试调整此设置", + "adjusts the overall contrast per frame [default neutral at 1.0]" : "调整每帧的整体对比度[默认值为1.0]", + "Adjusts the size of the image by multiplying the original width and height by the selected value. Ignored if either Resize width to or Resize height to are non-zero." : "通过将原宽度和高度乘以选定值来调整图像的大小。如果宽度调整为非零或高度调整为非零,则忽略。", + "Adjust strength" : "调整强度", + "adjust the brightness of the mask. Should be a positive number, with 1.0 meaning no adjustment." : "调整蒙版的亮度。该值应该为正数,1.0 表示无调整", + "Admirable" : "极好的", + "Adolf Kosarek" : "阿道夫·科萨雷克", + "ads" : "含广告", + "Advanced" : "高级", + "Advanced options" : "高级选项", + "Advanced Seed Blending" : "高阶种子混合", + "Aesthetic Gradients" : "美术风格梯度", + "Aesthetic Image Scorer" : "美术风格评分", + "Aesthetic imgs embedding" : "美术风格图集 Embedding", + "Aesthetic learning rate" : "美术风格学习率", + "aesthetic_score" : "美学评分", + "Aesthetic scorer" : "美学评分器", + "Aesthetic steps" : "美术风格迭代步数", + "Aesthetic text for imgs" : "该图集的美术风格描述", + "Aesthetic weight" : "美术风格权重", + "Affine" : "仿射", + "A file on the same machine where the server is running." : "服务器主机上某一文件夹", + "A integrated translator for translating prompts to English using Deepl or Baidu." : "一个使用 DeepL 或百度将提示词翻译成英语的集成翻译器。", + "all" : "全部", + "All" : "全部", + "All Displayed Ones" : "所有已显示的", + "All models in this directory will receive the selected model's metadata" : "此目录下所有模型都将被粘贴与选中模型完全相同的元数据", + "Allow detectmap auto saving" : "允许自动保存检测图 (detected maps)", + "Allowed categories for random artists selection when using the Roll button" : "使用抽选艺术家按钮时将会随机的艺术家类别", + "Allow img2img" : "允许图生图", + "Allow NSFW" : "允许 NSFW", + "Allow other script to control this extension" : "允许其他脚本控制此扩展", + "allow overwrite" : "允许覆盖文件", + "Allow overwrite output-model" : "允许输出时覆盖同名模型", + "Allow Preview" : "允许预览", + "Allows for random parameters during txt2img generation. This script is processed for all generations, regardless of the script selected, meaning this script will function with others as well, such as AUTOMATIC1111/stable-diffusion-webui-wildcards" : "允许在文生图的生成期间使用随机的参数。无论选择哪种脚本,此脚本都会针对所有的生成进行处理,这意味着此脚本也可以与其他脚本一起使用,例如通配符脚本", + "Allows you to easily, or even completely automatically start using HTTPS." : "让你可以很简单地自动配置HTTPS", + "Allows you to include various shortcodes in your prompts. You can pull text from files, set up your own variables, process text through conditional functions, and so much more - it's like wildcards on steroids." : "允许你在提示词中包含各种短代码。 你可以从文件中提取文本、设置自己的变量、通过条件函数处理文本等等 - 就像是增强版的通配符", + "Allows you to manually edit textual inversion embeddings using sliders." : "让你可以手动用滑条编辑风格迁移 Embeddings 的参数", + "Allow the default Euler a Sampling method. (Does not produce good results)" : "允许使用默认的 Eular a 采样方法. (通常不会出漂亮的结果)", + "\uD83D\uDD04 All Reset" : "\uD83D\uDD04 全部重置", + "alpha" : "α", + "Alphabetical Order" : "字母顺序", + "alpha threshold" : "透明度阈值", + "Alpha threshold" : "透明度阈值", + "also delete off-screen images" : "允许同时删除屏幕外的图片", + "Also output single joined audio file (will be named _joined.wav)" : "同时输出一个音频文件(将命名为 <日期>_joined.wav)", + "Also, please set the booru selection here before using select or search." : "另外,在选择或搜索之前,请在这里设置你要用哪个 booru", + "alternate" : "交替", + "Alternate Steps" : "交替迭代", + "Alternatively, use" : "或者,使用", + "Alternatively, you can enable" : "或者,您可以启用", + "Always discard next-to-last sigma" : "始终舍弃倒数第二个 sigma 值", + "Always Display Buttons" : "总是显示按钮", + "Always print all generation info to standard output" : "始终将所有生成信息输出到控制台", + "Always save all generated image grids" : "始终保存所有生成的网格图", + "Always save all generated images" : "始终保存所有生成的图像", + "A merger of the two checkpoints will be generated in your" : "合并后的模型(ckpt)会生成在你的", + "amount of presence of previous frame to influence next frame, also controls steps in the following formula [steps - (strength_schedule * steps)]" : "前一帧影响下一帧的存在量,也控制下式中的步数:[steps - (strength_schedule * steps)]", + "Amount schedule" : "数量表", + "and" : "与", + "A negative prompt to use when generating class images. Can be empty." : "生成类图像时使用的否定提示。 可以为空。", + "A negative prompt to use when generating preview images." : "生成预览图像时使用的反向提示词", + "Angle" : "角度", + "animation" : "动画", + "animation_mode" : "动画模式", + "Animation mode" : "动画模式", + "`animation_mode: None` batches on list of *prompts*. (Batch mode disabled atm, only animation_prompts are working)" : "`animation_mode: None` *提示词*列表中的批次。 (批处理模式暂时禁用,只有 animation_prompts 有效)", + "Animation settings" : "动画设定", + "Anime-inclined great guide (by FizzleDorf) with lots of examples:" : "有许多有关动漫方向非常好的指导示例(by FizzleDorf)", + "Anime Remove Background" : "动漫移除背景模式", + "Annotator resolution" : "预处理器分辨率", + "An object detection and auto-mask extension for Stable Diffusion web UI." : "一个物件检测与自适应蒙版扩展", + "Anti Blur" : "防模糊", + "api" : "api", + "API info may not be necessary for some boorus, but certain information or posts may fail to load without it. For example, Danbooru doesn't show certain posts in search results unless you auth as a Gold tier member." : "API 信息对于某些 booru 站点可能不是必需的,但如果没有它,某些信息或图帖可能无法加载。 例如,除非你的 API 验证属于黄金会员,否则 Danbooru 可能不会在搜索结果中显示某些图帖。", + "API Key" : "API 密钥", + "API Keys" : "API 密钥", + "append" : "追加", + "Append" : "追加至末尾", + "Append Caption to File Name" : "把描述文本接在文件名后面", + "Append comma on tag autocompletion" : "自动添加逗号", + "Append commas" : "附加逗号", + "Append DeepDanbooru to Caption" : "把 DeepDanbooru 的结果接在已有的描述文本后面", + "Append interrogated prompt at each iteration" : "在每次迭代时添加反推出的提示词", + "Applies mirroring and flips to the latent images to produce anything from subtle balanced compositions to perfect reflections" : "将图像的潜空间状态进行镜像和翻转,以生成从轻度平衡的构图到完全对称的任何图像", + "Apply" : "应用", + "Apply and restart UI" : "应用更改并重载前端", + "Apply block weight from text" : "从文本框应用分块权重值", + "Apply changes to ALL displayed images" : "将更改应用于所有已显示的图像", + "Apply changes to filtered images" : "应用更改至过滤后的图片", + "Apply changes to selected image" : "将更改应用于所选图像", + "Apply color correction to img2img results to match original colors." : "对图生图结果应用颜色校正以匹配原始颜色", + "Apply horizontal Flip" : "应用水平翻转", + "Apply Horizontal Flip" : "应用水平翻转", + "Apply Lora to outputs rather than inputs when possible (experimental)" : "尽可能将低秩微调模型 (LoRA) 应用于输出而非输入 (实验性选项)", + "Apply Presets" : "应用预设", + "Apply selected styles to current prompt" : "将所选预设样式插入到当前提示词之后", + "Apply selection filter" : "应用选择过滤器", + "Apply settings" : "保存设置", + "Apply to" : "应用到", + "Apply transfer control when loading models" : "加载模型时应用控制转移", + "A prompt for generating classification/regularization images. See the readme for more info." : "生成分类/规范化图像用的提示词。详细信息请参阅 readme", + "a random seed will be used on each frame of the animation" : "随机种子将被应用于每帧动画中", + "A range can be provided:" : "项数可以有范围", + "Area" : "区域", + "Area lower bound" : "图片最小面积(宽*高)", + "Area upper bound" : "图片最大面积(宽*高)", + "Arguments are case-sensitive." : "参数区分大小写。", + "Arm Length" : "手臂长度", + "Artists to study" : "艺术家图库", + "Artist Tags" : "画师标签(Tags)", + "as a UI to define your animation schedules (see the Parseq section in the Init tab)." : "作为定义动画参数表的UI(请参见初始化选项卡中的参数定序器部分)。", + "Ascending" : "升序", + "A setting of 1 will cause every frame to receive diffusion in the sequence of image outputs. A setting of 2 will only diffuse on every other frame, yet motion will still be in effect. The output of images during the cadence sequence will be automatically blended, additively and saved to the specified drive. This may improve the illusion of coherence in some workflows as the content and context of an image will not change or diffuse during frames that were skipped. Higher values of 4-8 cadence will skip over a larger amount of frames and only diffuse the “Nth” frame as set by the diffusion_cadence value. This may produce more continuity in an animation, at the cost of little opportunity to add more diffused content. In extreme examples, motion within a frame will fail to produce diverse prompt context, and the space will be filled with lines or approximations of content - resulting in unexpected animation patterns and artifacts. Video Input & Interpolation modes are not affected by diffusion_cadence." : "设置为 1 将使每个帧在图像输出序列中生成图像。设置为 2 将每隔一帧进行图像生成,但运动仍然有效。间隔序列期间的图像输出将自动混合、添加并保存到指定驱动器。这可能会改善某些工作流中的一致性错觉,因为图像的内容和上下文在跳过的帧期间不会改变或扩散。更高的间隔值,例如4-8,将跳过更多的帧,并仅生成由生成间隔值设置的“第N”帧。这可能会在动画中产生更多的连续性,但几乎没有机会添加更多的扩散内容。在极端的例子中,帧内的运动将无法产生不同的提示上下文,并且空间将充满线条或近似的内容,从而导致意外的动画模式和伪影。视频输入和插值模式不受生成间隔值的影响。", + "Attempt to automatically set training parameters based on total VRAM. Still under development." : "尝试根据总显存(VRAM)自动设置训练参数。仍在开发中", + "Attention grabber" : "随机关键词吸引注意力", + "Attention Heatmap" : "关键词热力图", + "Attention texts for visualization. (comma separated)" : "待可视化关键词 (逗号分隔)", + "Audio (if provided) will *not* be transferred to the interpolated video if Slow-Mo is enabled." : "音频(如果提供了)在以下选项启用时将不会转码压制进帧插值后的视频内:慢动作", + "Author" : "作者", + "Author of this model" : "此模型的作者", + "auto" : "自动", + "Auto" : "自动", + "Auto-Adjust (WIP)" : "自动调整 (施工中)", + "autocast" : "自动转换", + "Autocomplete options" : "自动补全选项", + "auto-delete imgs when video is ready" : "视频完成时自动删除图片", + "Auto focal point crop" : "自动面部焦点剪裁", + "Automatic" : "自动识别", + "Automatically update your prompt with interesting modifiers. (Runs slowly the first time)" : "使用有趣的修饰符自动更新你的提示词。(第一次运行会比较慢)", + "Auto SAM" : "自动 SAM", + "Auto SAM Config" : "自动 SAM 配置", + "Auto SAM is mainly for semantic segmentation and image layout generation, which is supported based on ControlNet. You must have ControlNet extension installed, and you should not change its directory name (sd-webui-controlnet)." : "自动 SAM主要用于语义分割和图像分层,基于 ControlNet。你必须安装 ControlNet 扩展,并且不能修改目录名 (sd-webui-controlnet)。", + "Auto segmentation output" : "自动语义分割输出", + "Auto-sized crop" : "自动按比例剪裁缩放", + "Auto TLS-HTTPS" : "自动 TLS-HTTPS", + "Available" : "可下载", + "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result" : "一个固定随机数生成器输出的值 - 以相同参数和随机种子生成的图像会得到相同的结果\n\uD83C\uDFB2 将随机种子设置为-1,则每次都会使用一个新的随机数\n♻️ 重用上一次使用的随机种子,如果想要固定输出结果就会很有用", + "Average image color" : "平均图像颜色", + "A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M" : "最终模型权重是前两个模型按比例相加的结果。需要 A、B 两个模型。计算公式为 A * (1 - M) + B * M", + "a-z" : "按首字母正序", + "(B10) Secondary" : "(B10) 第二", + "(B1) Secondary" : "(B1) 第二", + "(B2) Secondary" : "(B2) 第二", + "(B3) Secondary" : "(B3) 第二", + "(B4) Secondary" : "(B4) 第二", + "(B5) Secondary" : "(B5) 第二", + "(B6) Secondary" : "(B6) 第二", + "(B7) Secondary" : "(B7) 第二", + "(B8) Secondary" : "(B8) 第二", + "(B9) Secondary" : "(B9) 第二", + "- Background" : "- 背景", + "background color" : "背景颜色", + "Backup original text file (original file will be renamed like filename.000, .001, .002, ...)" : "备份原本 txt 文件 (原文件会被重命名,类似于:.000, .001, .002, ...)", + "Backup/Restore" : "备份/恢复", + "Bake in VAE" : "嵌入 VAE 模型", + "Balance between eyes" : "双眼间的平衡", + "Balanced" : "均衡", + "Base" : "基层值", + "base_alpha" : "文本编码器比例", + "Base alpha" : "上述合并模式中的常数α值", + "Base Depth" : "基础深度", + "Base Ratio" : "基本比率", + "Base Sampler" : "基础采样器", + "Basic" : "基础", + "Basic info" : "基本信息", + "Batch" : "批量处理", + "Batch count" : "总批次数", + "Batch Edit Captions" : "批量编辑描述", + "Batch from directory" : "批量处理文件夹", + "Batch from Directory" : "批量处理文件夹", + "Batch img2img" : "批量图生图", + "batch_name" : "批次名称", + "Batch name" : "文件夹名称", + "batch process" : "批量处理", + "Batch Process" : "批量处理", + "Batch settings" : "批次设定", + "Batch size" : "单批数量", + "Batch Size" : "单批数量", + "Before your text is sent to the neural network, it gets turned into numbers in a process called tokenization. These tokens are how the neural network reads and interprets text. Thanks to our great friends at Shousetsu愛 for inspiration for this feature." : "在你的文本被发送到神经网络之前,它在一个称为词元化(tokenization)的过程中被转化为数字。这些词元(tokens)是神经网络阅读和解释文本的方式。感谢我们伟大的朋友 Shousetsu愛 为这个功能带来的灵感", + "behind" : "落后", + "Benchmark Data" : "基准测试数据", + "Benchmarks..." : "基准测试...", + "Be sure to check the 'Write prompts to file' checkbox if you don't want to lose the generated prompts. Note, one image is still generated." : "不想丢失生成的提示词的话,需确保勾选 “将提示词写入文件”\n注意依然会生成一张图像", + "beta" : "β", + "beta1" : "beta1", + "beta2" : "beta2", + "Better" : "更好的", + "bf16" : "bf16", + "Bicubic" : "双三次", + "Bilinear" : "双线性", + "Bilingual Localization" : "双语对照翻译", + "Bitwise operation" : "按位(Bitwise)运算", + "Blacklist" : "黑名单", + "Black outfill" : "填黑", + "blend" : "混合", + "Blend" : "混合", + "Blend Average" : "平均混合", + "Blend factor max" : "最大混合系数", + "Blend factor slope" : "混合斜率系数", + "Blend mode" : "混合模式", + "Block ID" : "区块 ID", + "Blocks" : "所启用的区块", + "Block size" : "区块大小", + "blur" : "模糊", + "Blur" : "模糊", + "Blur amount:" : "模糊度:", + "Blur edges of final overlay mask, if used. Minimum = 0 (no blur)" : "模糊最终覆盖遮罩的边缘(如果使用)。最小值=0(无模糊)", + "Blurred & stretched overlay" : "模糊拉伸的叠加层", + "- Body" : "- 身体", + "Body Parameters" : "身体参数", + "booru2prompt" : "booru转提示词", + "Booru Score Threshold" : "Booru 极限阈值", + "Booru tag autocompletion" : "Booru 标签(tag)自动补全", + "BOOST (multi-resolution merging)" : "BOOST (多分辨率合并)", + "border" : "边框", + "Border" : "边缘", + "Both" : "全部", + "box_nms_thresh" : "箱体数量阈值", + "Branch" : "分支", + "brightness" : "亮度", + "Bring prompts and setting into one column left side" : "将正反提示词输入框和设置移动到左侧", + "BSRGAN 4x" : "BSRGAN 4x", + "built-in" : "内置", + "built with gradio" : "基于 Gradio 构建", + "Built with Gradio" : "基于 Gradio 构建", + "Bulk process frames with chosen outfill method" : "使用选定的填充方法批量处理截取的帧", + "Bump seed (If > 0 do a Compare Paths but only one image. No video)" : "自动递增种子 (大于 0 的时候会对比变迁轨迹,但不会生成视频而是只是一张图)", + "by AUTOMATIC1111" : "来自 AUTOMATIC1111", + "By comma" : "逗号分组", + "By default, the algorithm tends to like dark images too much, if you think the output is too dark or not dark enough, you can adjust this ratio. 1 = ‘Do not darken at all’, 0 = ‘A totally black image is ok’, default = 0.9." : "默认情况下,算法倾向于生成较黑的图像,如果你认为输出的图像太黑或不够黑,你可以调整最小照明比率。1=\"完全不变暗\",0=\"全黑的图像\",默认=0.9", + "By none" : "不分组", + "By tokens" : "词元分组", + "By vectors" : "向量分组", + "By words" : "单词分组", + "(C10) Thertiary" : "(C10) 第三", + "(C1) Thertiary" : "(C1) 第三", + "(C2) Thertiary" : "(C2) 第三", + "(C3) Thertiary" : "(C3) 第三", + "(C4) Thertiary" : "(C4) 第三", + "(C5) Thertiary" : "(C5) 第三", + "(C6) Thertiary" : "(C6) 第三", + "(C7) Thertiary" : "(C7) 第三", + "(C8) Thertiary" : "(C8) 第三", + "(C9) Thertiary" : "(C9) 第三", + "Cache LDSR model in memory" : "将 LDSR 模型缓存在内存中", + "Cadence" : "生成间隔", + "calculate dimension of LoRAs(It may take a few minutes if there are many LoRAs)" : "计算 LoRA 维度 (取决于模型数量,可能需要数分钟)", + "Calculates aesthetic score for generated images using CLIP+MLP Aesthetic Score Predictor based on Chad Scorer" : "为生成出来的图像计算其美学分数。基于 Chad Scorer 使用 CLIP+MLP 美学分数预测器", + "Calculate training parameters for a human subject. Enables prior preservation." : "计算训练人物主体需要的参数。并启用先验存留(prior preservation)", + "Calculate training parameters for a non-human subject. Disables prior preservation." : "计算训练非人物主体需要的参数。并禁用先验存留(prior preservation)", + "- Camera" : "- 镜头", + "Camera Far" : "镜头最远渲染距离", + "Camera Focal Length" : "镜头焦距", + "Camera Near" : "镜头最近渲染距离", + "Camera Parameters" : "镜头参数", + "Can be empty,indicating no translation" : "可以为空,表示无需翻译", + "Cancel" : "取消", + "Cancel generate forever" : "停止无限生成", + "Cancel training." : "取消训练", + "canny" : "canny (边缘检测)", + "Canny high threshold" : "强边缘判断阈值(Canny high threshold)", + "Canny low threshold" : "弱边缘判断阈值(Canny low threshold)", + "Canvas Height" : "画布高度", + "- Canvas Size" : "- 画布尺寸", + "Canvas Width" : "画布宽度", + "Caption Backup File" : "描述备份文件", + "Caption File Ext" : "文件扩展名", + "Caption of Selected Image" : "被选图片的描述", + "Captions" : "描述文本", + "Caption Text File" : "描述文本文件", + "Card height for Extra Networks (px)" : "扩展模型卡牌高度 (px)", + "cards" : "卡牌视图", + "Card width for Extra Networks (px)" : "扩展模型卡牌宽度 (px)", + "cascadePSP" : "CascadePSP", + "case sensitive" : "区分大小写", + "Catppuccin Flavor" : "Catppuccin 主题样式(背景颜色)", + "⚠ Caution: You should only use these options if you know what you are doing. ⚠" : "⚠ 警告: 你需要清楚知道自己在做什么才能使用这些选项. ⚠", + "celu" : "celu", + "Center Crop" : "中心裁切", + "cfg scale" : "提示词相关性(CFG Scale)", + "CFG scale" : "提示词引导系数(CFG Scale)", + "CFG Scale" : "提示词引导系数 (CFG Scale)", + "CFG scale schedule" : "CFG 系数表", + "Change brightness" : "调节亮度", + "Change checkpoint" : "更改模型", + "Change contrast" : "调节对比度", + "Change CTRL keybindings to SHIFT" : "将 CTRL 绑定更改为 SHIFT", + "Change gain" : "调节增强强度", + "Change gamma" : "调节伽马", + "Changes are not applied to the text files until the \"Save all changes\" button is pressed." : "更改不会被应用至文本文件,直到 “保存所有更改” 按钮被按下", + "Change saturation" : "调节饱和度", + "* change 'type' to clear/reload dropdowns." : "改变坐标轴类型可清空、刷新选项", + "Change your brush width to make it thinner if you want to draw something." : "绘制内容前请先调整笔刷粗细。", + "Character Tags" : "角色标签(Tags)", + "Checkbox" : "勾选框", + "Check Console log for Downloading Status" : "检查控制台日志以查看下载信息", + "Check for updates" : "检查更新", + "Check models' new version" : "检查模型版本更新", + "Check models’ new version" : "检索模型的新版本", + "Check New Version from Civitai" : "从 Civitai 上检查版本更新", + "checkpoint" : "模型", + "Checkpoint" : "模型", + "Checkpoint A" : "大模型 A", + "Checkpoint B" : "大模型 B", + "Checkpoint Dropdown" : "模型(ckpt)列表", + "Checkpoint format" : "输出模型格式", + "Checkpoint Format" : "输出模型格式", + "Checkpoint Merger" : "模型合并", + "Checkpoint name" : "模型名", + "Checkpoints" : "模型", + "Checkpoint schedule" : "模型表", + "Checkpoints to cache in RAM" : "保留在内存中的 Stable Diffusion 模型数量", + "Check progress" : "查看进度", + "Check progress (first)" : "(首次)查看进度", + "check this box to enable guided images mode" : "选中该项启用引导图像模式", + "Check this if you want to generate random prompts, even if your seed is fixed" : "勾选此选项以在固定随机种子的情况下依然生成随机提示词", + "* check your CLI for outputs" : "检查 CLI 的输出", + "Choose a number of terms from a list, in this case we choose two artists:" : "从列表中选几项,这里选了两个艺术家", + "Choose latent sampling method" : "选择潜变量采样方法", + "Choose Min-max to activate these controls" : "选择 “最小 - 最大” 以激活此行控制", + "Choose mode:" : "选择模式:", + "Choose preprocessor for semantic segmentation:" : "选择语义分割的预处理器:", + "Choose your favorite mask:" : "请选择你喜欢的蒙版:", + "circle" : "圆", + "Civitai Helper" : "Civitai 助手", + "Civitai URL or Model ID" : "Civitai 地址或模型 ID", + "ckpt" : "ckpt", + "Class Batch Size" : "类每批数量(Class Batch Size)", + "Classification CFG Scale" : "分类提示词引导系数(Classification CFG scale)", + "Classification Dataset Directory" : "分类(Classification)数据集目录", + "Classification dataset directory (optional)." : "分类(Classification)数据集目录(可选)", + "Classification Image Negative Prompt" : "分类(classification)图像反向提示词", + "Classification Steps" : "分类(Classification)迭代步数", + "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results" : "无分类器指导信息影响尺度(Classifier Free Guidance Scale) - 图像应在多大程度上服从提示词 - 较低的值会产生更有创意的结果", + "Classifier path" : "分类器(Classifier)的路径", + "Class prompt" : "类(Class)提示词", + "Class Prompt" : "类(Class)提示词", + "Class Token + Description" : "类的词元(Token) + 描述", + "Class token(s) to swap, can be comma-separated" : "要互换的类的词元(Token),可以是以英文逗号分割的", + "Cleanup non-default temporary directory when starting webui" : "启动 WebUI 时清理非默认临时目录", + "Clear" : "清除", + "Clear ALL filters" : "清除所有过滤器", + "Clear inputs" : "清除输入", + "Clear prompt" : "清空提示词内容", + "Clear selection" : "清空选择", + "Clear tag filters" : "清除 tag 过滤器", + "Clear values" : "清空数值", + "Click Enhance." : "点击“增强”按钮", + "Click here after the generation to show the video" : "生成完成后点这里显示视频", + "Click to Upload" : "点击上传", + "clip" : "clip", + "Clip and renormalize" : "消减与重整", + "CLIP: maximum number of lines in text file (0 = No limit)" : "CLIP:文本文件中的最大行数(0 为无限制)", + "CLiP model" : "CLiP 模型", + "Clip skip" : "跳过 CLIP 层数", + "Clip Skip" : "CLIP 跳过", + "CLIP Skip" : "CLIP 跳过", + "CLIP: skip inquire categories" : "CLIP:跳过查询类别", + "CLIP skip schedule" : "跳过 CLIP 层数表", + "clip_threshold" : "裁剪阈值", + "Close" : "关闭", + "Closer is brighter" : "越近越亮", + "Close the video" : "关掉视频", + "cluster num" : "簇数", + "Codec" : "编码器格式", + "Codeformer" : "Codeformer", + "CodeFormer visibility" : "CodeFormer 可见度", + "CodeFormer Weight" : "CodeFormer 权重", + "CodeFormer weight (0 = maximum effect, 1 = minimum effect)" : "CodeFormer 权重 (为 0 时效果最大,为 1 时效果最小)", + "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect" : "CodeFormer 权重参数;为 0 时效果最大;为 1 时效果最小", + "Coherence" : "一致性", + "Coherence:" : "相干性:", + "Collect" : "收藏(保存)", + "Color" : "颜色", + "color_burn" : "颜色加深", + "color_coherence" : "颜色校正", + "Color coherence" : "颜色一致性", + "Color correction factor" : "颜色校正系数", + "color_dodge" : "颜色减淡", + "Color force Grayscale" : "强制颜色空间为灰度", + "color mode" : "色域模式", + "Color reduce algo" : "颜色减弱算法", + "colors" : "色块", + "Color variation" : "色彩变化", + "Comb" : "梳理", + "Combinations" : "组合", + "Combinatorial batches" : "组合批次", + "Combinatorial generation" : "组合生成", + "Combine axis" : "合并轴", + "Combined" : "兼有", + "Combine into one image." : "合并为一个图像", + "comma" : "逗号", + "Comma separated list" : "以逗号分割的列表", + "Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited." : "以逗号分割的选项卡名称列表;这里列出的选项卡将首先按顺序出现在扩展模型面板中", + "Comma-separated list of tags (\"artist, style, character, 2d, 3d...\")" : "以逗号分割的tags列表(\"artist,style,character,2d,3d...\")", + "Comma separated list. Specify ckpt OR ckpt:word" : "以逗号分割的列表。用以指定 ckpt 或 ckpt:字词", + "Common Tags" : "原 Tags(Common Tags)", + "Comp alpha schedule" : "混合透明度参数表", + "Compare paths (Separate travels from 1st seed to each destination)" : "对比变迁轨迹 (从第一个种子分别变迁到每一个目标种子)", + "Compatibility" : "兼容性", + "Comp mask type" : "比较蒙版类型", + "Composable Mask scheduling" : "可组合的蒙版表", + "Composite video with previous frame init image in" : "前一帧初始图像的合成视频在", + "Comp save extra frames" : "压缩保存额外帧", + "Compute on" : "计算单元", + "Concepts List" : "概念列表", + "Concepts List (Overrides instance/class settings below)" : "概念列表(将取代下面实例/类这两项设置)", + "Cond.fix: Disabled (none)" : "修复时调节:禁用 (无)", + "Cond.fix: Empty" : "修复时调节:空掉", + "Cond.fix: Full" : "修复时调节:完全", + "Cond.fix: Highest" : "修复时调节:最高", + "Cond.fix: High (recommended)" : "修复时调节:高 (推荐)", + "Cond.fix: Low" : "修复时调节:小", + "Cond.fix: Lowest" : "修复时调节:最小", + "Cond.fix: Medium" : "修复时调节:中", + "Cond. Image Mask Weight" : "图像调节屏蔽度", + "Conditionals" : "条件", + "conditioning-highres-fix" : "高分辨率修复原图调节", + "Conditioning Highres.fix strength (for sd-v1-5-inpainting)" : "高分辨率修复原图调节强度 (专为 sd-v1-5-inpainting 设计)", + "config" : "配置", + "Config file for Adapter models" : "Adapter 模型配置文件路径", + "Config file for Control Net models" : "ControlNet 模型配置文件路径", + "Config Name" : "配置名", + "Config Presets" : "预设配置", + "Config-Presets" : "预设配置", + "Connection errored out." : "连接出错", + "Console logging" : "控制台日志记录", + "constant" : "常量(constant)", + "constant_with_warmup" : "含预热的常量(constant)", + "Containing directory" : "目标模型目录", + "contrast" : "对比度", + "Contrast schedule" : "对比度参数表", + "Contrasts cut level" : "对比度切分水平", + "Control Mode (Guess Mode)" : "控制类型 (猜测模式)", + "ControlNet - 0" : "扩散控制网络(ControlNet) - 0", + "ControlNet - 1" : "扩散控制网络(ControlNet) - 1", + "ControlNet - 2" : "扩散控制网络(ControlNet) - 2", + "ControlNet - 3" : "扩散控制网络(ControlNet) - 3", + "ControlNet - 4" : "扩散控制网络(ControlNet) - 4", + "ControlNet - 5" : "扩散控制网络(ControlNet) - 5", + "ControlNet - 6" : "扩散控制网络(ControlNet) - 6", + "ControlNet - 7" : "扩散控制网络(ControlNet) - 7", + "ControlNet - 8" : "扩散控制网络(ControlNet) - 8", + "ControlNet - 9" : "扩散控制网络(ControlNet) - 9", + "[ControlNet] Guidance Strength" : "[ControlNet] 引导强度", + "ControlNet inpaint model index" : "ControlNet 的 inpaint 模型启用单元页", + "Controlnet input directory" : "ControlNet 输入目录", + "ControlNet input directory" : "ControlNet 的输入目录", + "ControlNet Input Video Path" : "ControlNet 输入视频路径", + "ControlNet is more important" : "更倾向于让 ControlNet 自由发挥", + "ControlNet Mask Video Path" : "ControlNet 视频蒙版路径", + "ControlNet model" : "ControlNet 模型", + "[ControlNet] Model" : "[ControlNet] 模型", + "ControlNet number" : "ControlNet 序号", + "[ControlNet] Preprocessor" : "[ControlNet] 预处理器", + "[ControlNet] Pre Resolution" : "[ControlNet] 预处理器 分辨率", + "[ControlNet] Pre Threshold A" : "[ControlNet] 预处理器 阈值A", + "[ControlNet] Pre Threshold B" : "[ControlNet] 预处理器 阈值B", + "[ControlNet] Resize Mode" : "[ControlNet] 缩放模式", + "ControlNet Segmentation Index" : "ControlNet 语义分割序号", + "ControlNet Video Input" : "ControlNet 视频输入", + "ControlNet Video Mask Input" : "ControlNet 视频蒙版输入", + "ControlNet weight" : "ControlNet 权重", + "[ControlNet] Weight" : "[ControlNet] 权重", + "Controls the maximum length in tokens of the generated prompt." : "按 token 数控制提示词生成的最大长度", + "Controls the strength of the diffusion on the init image. 0 = disabled" : "控制初始化图像生成器的强度。 0 = 禁用", + "Control Weight" : "控制权重", + "convert" : "转换", + "Convert a 360 spherical panorama to a 3D mesh" : "将单张 360° 球形全景图转换为 3D 网格", + "Convert a single 2D image to a 3D mesh" : "将单张 3D 图像转换为 3D 网格", + "Converted checkpoints will be saved in your" : "转换出的模型将会保存在你的", + "Convert Folder" : "转换该目录", + "Converts all images in a folder to audio" : "转换所选的图像目录内的图片为音频", + "copy" : "复制", + "Copy" : "复制", + "Copy and Overwrite" : "复制与覆写", + "Copy caption from selected images automatically" : "自动从被选图片中复制描述", + "Copy config from" : "复制配置文件", + "Copy image to:" : "复制当前图像到: ", + "Copy Metadata" : "开始复制元数据", + "Copy metadata to other models in directory" : "将元数据复制到文件夹中的其他模型", + "Copy Metdata" : "开始复制元数据", + "Copyright Tags" : "版权标签(Tags)", + "copy to clipboard" : "复制", + "\uD83D\uDCCB Copy to clipboard" : "\uD83D\uDCCB 复制到剪切板", + "Copy to ControlNet Segmentation" : "复制到 ControlNet 语义分割", + "Copy to directory" : "将图片复制到目标路径", + "Copy to favorites" : "复制到收藏夹", + "Copy to Inpaint Upload & ControlNet Inpainting" : "复制到局部重绘和 ControlNet 重绘", + "cosine" : "余弦", + "cosine_with_restarts" : "周期重启余弦", + "Count of final steps to average together:" : "用于平均的最终步数量:", + "Cover image" : "封面图像", + "Create" : "创建", + "Create aesthetic embedding" : "创建美术风格", + "Create aesthetic images embedding" : "创建美术风格图集 Embedding", + "Create a grid where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows" : "创建一个网格,图像将有不同的参数。使用下面的输入来指定哪些参数将由列和行共享", + "Create an aesthetic embedding out of any number of images" : "从任意数量的图像中创建美术风格 Embedding", + "Create an embedding from one or few pictures and use it to apply their style to generated images." : "用一张或多张图像创建一个 Embedding,并用它将图集的风格转移到要生成的图像上", + "Create animation" : "创建动画", + "Create a text file next to every image with generation parameters." : "同时为每个图片创建一个文本文件储存生成参数", + "Create blank canvas" : "创建空白画布", + "Create debug image" : "创建调试(debug)图像", + "Create embedding" : "创建嵌入式模型", + "Create flipped copies" : "创建水平翻转副本", + "Create From Hub" : "从 Huggingface Hub 中创建", + "Create hypernetwork" : "创建超网络模型", + "Create images embedding" : "创建图集 Embedding", + "Create Model" : "创建模型", + "Creates animation sequence from denoised intermediate steps with video frame interpolation to achieve desired animation duration" : "利用视频插值从降噪过程的中间步骤图像中生成动画", + "Create the danged model already." : "创建一个本就很牛的模型", + "Create txt2img canvas" : "创建文生图画布", + "CRF" : "固定码率因子 (CRF)", + "Crop and resize" : "比例裁剪后缩放", + "Crop and Resize" : "比例裁剪后缩放", + "Crop_high" : "裁剪高度", + "Crop Images" : "剪裁图像", + "crop_n_layers" : "分层层数", + "crop_nms_thresh" : "分层数量阈值", + "crop_n_points_downscale_factor" : "分层采样点坍缩因子", + "crop_overlap_ratio" : "分层重叠度", + "Cropping" : "剪裁", + "Crop to fit" : "裁剪以适应宽高比", + "Crop: top, left, bottom, right" : "裁剪:顶部,左,顶部,右", + "Cross-attention" : "X-Attn 优化方案", + "Ctrl+up/down precision when editing (attention:1.1)" : "使用 Ctrl + ↑/↓ 设置\"(tag:1.1)\"时的精度", + "Ctrl+up/down precision when editing " : "使用 Ctrl + ↑/↓ 设置\"\"时的精度", + "Current" : "Current (当前帧)", + "Current Booru" : "当前的 Booru", + "Current Cache" : "当前缓存目录", + "Current Model" : "当前模型", + "Custom color for invalid additional networks" : "无效额外网络的自定义颜色", + "Custom color of 0 weight" : "权重为0时的自定义颜色", + "Custom color of disabled dropdown" : "已禁用的下拉框的自定义颜色", + "Custom color of disabled scripts" : "已禁用脚本的自定义颜色", + "Custom color of enabled dropdown" : "已启用的下拉框的自定义颜色", + "Custom color of enabled scripts" : "已启用脚本的自定义颜色", + "Custom Config File" : "自定义配置文件", + "custom fold" : "自定义文件夹", + "Custom Name (Optional)" : "自定义名称 (可选)", + "Custom settings file" : "自定义设置文件", + "Custom size" : "自定义尺寸", + "custum name" : "自定义名称", + "Cutoff strongly." : "强效分隔", + "Daam script" : "Daam 脚本", + "darken" : "变暗", + "Dataset directory" : "数据集目录", + "Dataset Directory" : "数据集目录", + "Dataset folder structure" : "数据集文件夹结构", + "Dataset Images" : "数据集图片", + "Dataset Load Settings" : "数据集加载设置", + "Dataset Tag Editor" : "Dataset Tag Editor", + "date" : "日期", + "Date" : "日期", + "Date to" : "日期至", + "ddetailer" : "检测细致化", + "ddim" : "ddim", + "DDIM" : "DDIM", + "debug" : "调试", + "Debug info" : "调试信息", + "Debug log" : "调试日志", + "Decode CFG scale" : "解码提示词引导系数(CFG scale)", + "Decoder Tile Size" : "解码器区块大小", + "Decode steps" : "解码迭代步数", + "default" : "默认", + "Default cropped image output directory" : "裁切后的成品的默认输出目录", + "Default Image CFG" : "默认图像引导系数 (CFG)", + "Default Input Batch Output Directory" : "默认批量导入输出文件目录", + "Default Out Batches" : "默认输出批次数", + "Default Sampler" : "默认采样方法(Sampler)", + "Default Steps" : "默认迭代步数(Steps)", + "Default Text CFG" : "默认文本引导系数(CFG)", + "default variables: in \\{\\}, like \\{init_mask\\}, \\{video_mask\\}, \\{everywhere\\}" : "默认变量:\\{\\},比如 \\{init_mask\\}, \\{video_mask\\}, \\{everywhere\\}", + "Default view for Extra Networks" : "默认扩展模型视图", + "deforum-for-automatic1111-webui" : "Deforum", + "Deforum-webui (use tab extension instead!)" : "Deforum-webui (请使用选项卡上的扩展版本)", + "❌ Del" : "❌ 删除", + "delete" : "删除", + "❌Delete" : "❌删除", + "Delete" : "删除", + "Delete 0-entries from exif cache" : "从 EXIF 缓存删除 0-entries", + "DELETE cannot be undone. The files will be deleted completely." : "删除无法中断。文件会被完全删除。", + "DELETE File(s)" : "删除文件", + "Delete Imgs" : "删除图像", + "Delete intermediate" : "删除临时文件", + "Delete intermediate frames after GIF generation" : "生成 GIF 后删除临时帧图片", + "Delete list(-1 for all)" : "删除列表(全删填-1)", + "delete next" : "删除后 N 张", + "delete or keep raw affected (interpolated/ upscaled depending on the UI section) png imgs" : "删除或保留受影响的原始(根据UI部分进行插值/放大)png图像", + "Delete Selected Skeleton (D key)" : "删除选中骨架 (D 键)", + "Denoising" : "重绘幅度", + "Denoising Diffusion Implicit Models - best at inpainting" : "Denoising Diffusion Implicit models - 最擅长局部重绘", + "Denoising strength" : "重绘幅度 (Denoising strength)", + "Denoising strength change factor" : "重绘幅度的调整系数", + "Denoising strength for face images" : "脸部重绘幅度", + "Denoising strength for the entire image" : "全图重绘幅度", + "Denoising strength (Inpaint)" : "重绘幅度 (局部重绘)", + "----deprecated----" : "----以下内容在webUI新版本已移除----", + "Depth" : "深度", + "Depth aware img2img mask" : "深度感知图生图蒙版", + "depth_leres" : "depth_leres (LeReS 深度图估算)", + "depth_leres++" : "depth_leres++ (LeReS 深度图估算++)", + "Depth Library" : "深度图库", + "Depth Map" : "深度图", + "Depth Maps" : "深度图", + "depth_midas" : "depth_midas (MiDaS 深度图估算)", + "Depth (Midas/Adabins)" : "深度模式 (Midas / Adabins)", + "Depth Prediction" : "深度估计预处理", + "Depth Prediction demo" : "深度估计预处理 Demo", + "depth_zoe" : "depth_zoe (ZoE 深度图估算)", + "Descending" : "降序", + "Description" : "描述", + "description-based:" : "基于描述:", + "Deselect visible tags" : "取消选择可见的 tags", + "Destination directory" : "目标目录", + "Destination Directory" : "目标文件夹", + "Destination seed(s) (Comma separated)" : "目标种子 (逗号分割)", + "Detailed" : "详细设置", + "Detailed Save As" : "详细保存为", + "Details" : "详细设置", + "Detect from image" : "从图片提取", + "Detect from Image" : "从图像中检测", + "Detection confidence threshold % (A)" : "检测置信阈值 % (A)", + "Detection confidence threshold % (B)" : "检测置信阈值 % (B)", + "Detection Detailer" : "检测细致化", + "Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies." : "决定算法对图像内容的影响程度。设置 0 时,什么都不会改变,而在 1 时,你将获得不相关的图像。\n值低于 1.0 时,处理的迭代步数将少于“采样迭代步数”滑块指定的步数", + "deterministic" : "多次平均", + "difference" : "差值", + "Difference" : "差分", + "different" : "差异", + "Diffuse the first frame based on an image, similar to img2img." : "基于图像生成第一帧,类似于图生图", + "Dilation factor (A)" : "扩张(Dilation)因子 (A)", + "Dilation factor (B)" : "扩张因子 (B)", + "Dimension lower bound" : "最小分辨率", + "Dimension upper bound" : "最大分辨率", + "Directly Draw Scribbles" : "直接绘制线稿", + "Directories" : "目录", + "directory." : "目录。", + "Directory containing your image files" : "你需要处理的图片目录", + "Directory for batch input images" : "批量导入图像的文件目录", + "Directory for detected maps auto saving" : "检测图 (detected maps) 保存路径", + "Directory for saving images using the Save button" : "“保存”按钮输出文件夹", + "Directory for temporary images; leave empty for default" : "临时图像目录;默认为空", + "Directory name pattern" : "目录名称格式", + "Directory path" : "目标路径", + "Disable" : "禁用", + "Disable all extensions" : "禁用所有扩展", + "disable convert 'AND' to 'BREAK'" : "禁用将 \"AND \"转换为 \"BREAK\"", + "disabled" : "禁用", + "Disabled" : "已禁用", + "Disabled for batch input images" : "批量导入图像时禁用", + "Disable during hires pass" : "在高清修复过程中停用", + "Disabled when launched with --hide-ui-dir-config." : "启动 --hide-ui-dir-config 时禁用", + "Disable dynamic prompts by unchecking this box." : "取消勾选来禁用动态提示词", + "Disable for Negative prompt." : "为反向提示词禁用本插件效果", + "Disable image generation. Useful if you only want to generate text prompts." : "禁用图像生成。如果你只想生成文本提示词的话", + "Disable negative prompt" : "禁用反向提示词", + "Discard weights with matching name" : "删除匹配键名的表达式的权重", + "Dismiss" : "屏蔽", + "display both english and target language" : "同时显示英语和目标语言", + "Display name for this model" : "此模型的显示名", + "display_samples" : "显示样本", + "Displays autocompletion hints for tags from image booru boards such as Danbooru. Uses local tag CSV files and includes a config for customization." : "显示来自图像板块(image booru,如 Danbooru)的标签(tags)自动补完。使用本地标签(tag) CSV 文件,并包含可用于自定义配置的文件", + "Divide mode" : "分割模式", + "Divide Ratio" : "分割比率", + "Divisions" : "分区方式", + "Dominant image color" : "图像主色", + "Do not add watermark to images" : "不在图像上添加水印", + "Do not append detectmap to output" : "不输出检测图 (detected maps) (如深度估算图、动作检测图等)", + "Do not do anything special" : "什么都不做", + "Do not make DPM++ SDE deterministic across different batch sizes." : "保留 DPM++ SDE 采样器 在不同的批次大小之间的结果差异", + "Do not resize images" : "不调整图像大小", + "Do not save grids consisting of one picture" : "当仅有一张图时不保存网格图", + "Do not save heatmap images" : "不保存热力图图像", + "Do not show any images in results for web" : "不在浏览器输出结果中显示任何图像", + "Don't cache latents" : "不要缓存潜空间变量", + "Don't Cache Latents" : "不要缓存潜空间变量", + "Don't checkpoint the gradients, Duh. Set to False to slightly increase speed at the cost of a bit of VRAM." : "保存权重进度时不要保存梯度,啊不废话。设置为 False 以消耗一点显存(VRAM)为代价略微提高速度", + "Don't generate images" : "不生成图像", + "Don't outfill" : "不进行填充", + "dot size" : "点大小", + "double-straight-line" : "双直线", + "down" : "下", + "Download" : "下载", + "\uD83D\uDCBE Download image" : "\uD83D\uDCBE 下载图片", + "Download localization template" : "导出 localization 模板", + "Download Max Size Preview" : "下载最大尺寸预览图", + "Download missing models upon reading generation parameters from prompt" : "从生成参数中的提示词读取并下载缺失的模型", + "Download missing preview images on startup" : "启动时下载缺失的模型预览图", + "Download Model" : "下载模型", + "Download NSFW (adult) preview images" : "允许下载 NSFW (成人) 预览图", + "Downscaling" : "图片缩小", + "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt" : "在图像上画一个蒙版,脚本会根据提示重新生成蒙版区域的内容", + "Draw full canvas background" : "绘制完整的画布背景", + "Drawing Canvas" : "创建画布", + "Draw legend" : "包含图例注释", + "Draw Legends" : "输出坐标轴名字", + "Draw mask" : "绘制蒙版", + "DreamArtist Create embedding" : "梦作家 创建 Embedding", + "DreamArtist-sd-webui-extension" : "梦作家", + "DreamArtist Train" : "梦作家 训练", + "Dreambooth" : "Dreambooth", + "Dreambooth training based on Shivam Shiaro's repo, optimized for lower-VRAM GPUs." : "基于 Shivam Shiaro 的代码移植的 Dreambooth 训练,为低显存(lower-VRAM)显卡做了优化", + "Dropdown" : "下拉列表", + "Drop File Here" : "拖拽文件到此", + "Drop Image Here" : "拖动图像至此", + "Dropout tags when create texts" : "创建文本时随机丢弃一些 tags", + "Drop out tags when creating prompts." : "创建提示词时丢弃标签(tags)", + "Drop Video Here" : "拖动视频至此", + "Dry Run" : "试运行", + "Due to ControlNet base extension's inner works it needs its models to be located at 'extensions/deforum-for-automatic1111-webui/models'. So copy, symlink or move them there until a more elegant solution is found. And, as of now, it requires use_init checked for the first run. The ControlNet extension version used in the dev process is a24089a62e70a7fae44b7bf35b51fd584dd55e25, if even with all the other options above used it still breaks, upgrade/downgrade your CN version to this one." : "因为 ControlNet 基层插件在内工作,所以需要将 ControlNet 模型置于 “extensions/deforum-for-automatic1111-webui/models”文件夹内。在更优雅的解决方法出现之前,请复制,软链接 symlink 或者移动模型。 \n同时目前为止,该插件需要在第一次运行时检查 use_init。\n用于开发进程的 ControlNet 插件版本为 a24089a62e70a7fae44b7bf35b51fd584dd55e25。如果全部按照上文使用还是损坏,请将 ControlNet 版本升级/降级到上述版本。", + "duplicate" : "重复的", + "Duplicate Skeleton (X-axis)" : "复制骨架(X 轴)", + "Duplicate Skeleton (Z-axis)" : "复制骨架(Z 轴)", + "Duration" : "时长", + "during the run sequence, only frames specified by this value will be extracted, saved, and diffused upon. A value of 1 indicates that every frame is to be accounted for. Values of 2 will use every other frame for the sequence. Higher values will skip that number of frames respectively." : "在运行序列期间,只有由该值指定的帧才会被提取、保存和生成。1表示要考虑每个帧。2表示每隔一帧用于序列。较高的值将分别跳过该帧数。", + "Dynamic Prompts" : "动态提示词", + "Dynamic Prompts enabled" : "启用动态提示词", + "Each image is center-cropped with an automatically chosen width and height." : "每张图片都会以自动选择好的宽和高进行中心裁剪", + "Each key" : "显示所有层值", + "Each Tags" : "每个 Tags", + "edit" : "编辑", + "Edit Caption" : "编辑描述", + "Edit Caption of Selected Image" : "编辑被选图片的描述", + "Edit common tags." : "编辑 tags", + "Editing Enabled" : "开启元数据编辑", + "Edit Openpose" : "编辑 Openpose", + "Edit Tags" : "编辑 Tags (Edit Tags)", + "Effect" : "效果", + "Effective Block Analyzer" : "高效区块分析器", + "e.g. A portrait photo of embedding_name" : "示例: A portrait photo of embedding_name", + "Elliptic Limbs" : "椭圆四肢", + "elu" : "elu", + "EMA (nagetive)" : "EMA (负)", + "ema-only" : "仅保留 EMA 权重", + "EMA (positive)" : "EMA (正)", + "EMA replace steps (nagative)" : "EMA 替换步数 (负)", + "EMA replace steps (positive)" : "EMA 替换步数 (正)", + "Embedding" : "嵌入式模型(Embedding)", + "Embedding Editor" : "Embedding 编辑器", + "Embedding Learning rate" : "嵌入式模型学习率", + "Embeddings editor" : "Embeddings 编辑器", + "Embeddings: loaded" : "嵌入式(Embeddings):已加载", + "Embeddings: skipped" : "嵌入式(Embeddings):已跳过", + "Embedding token" : "Embedding 的词元(Token) / 关键词", + "Embedding to Shareable PNG" : "将 Embedding 转换为可分享的 PNG 图片文件", + "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention" : "强调符:使用 (文字) 使模型更关注该文本,使用 [文字] 减少其关注度", + "empty cannot be saved" : "留空时无法保存", + "empty strings cannot be translated" : "无法翻译空的文本", + "Enable" : "启用", + "Enable AA for Downscaling." : "缩小时使用反锯齿", + "Enable AA for Upscaling." : "放大时使用反锯齿", + "Enable ADetailer" : "启用 After Detailer", + "Enable Anti Burn (and everything)" : "启用 Anti Burn", + "Enable Autocomplete" : "启用Tag自动补全", + "Enable batch mode" : "启用批处理模式", + "Enable Bilingual Localization" : "启用双语对照翻译插件", + "Enable CFG-Based guidance" : "启用基于 CFG 的引导 (CFG-Based guidance)", + "Enable Checker" : "启用项检测", + "Enable checkpoint scheduling" : "启用模型表", + "Enable CLIP skip scheduling" : "启用跳过 CLIP 层数表", + "Enable color correction" : "启用颜色校正", + "Enable Control" : "启用控制", + "enabled" : "启用", + "Enabled" : "启用", + "Enable Devtools Log" : "启用开发工具日志", + "Enable dropdown check" : "启用下拉框检测", + "Enable Dynamic Thresholding (CFG Scale Fix)" : "启用动态阈值(提示词相关性修复 - CFG Scale Fix)", + "Enable extra network check" : "启用额外网络检测", + "Enable extras" : "打开 ▼", + "Enable full page image viewer" : "启用全屏图像查看器", + "Enable GroundingDINO" : "启用 GroundingDINO", + "Enable guided images mode" : "启用引导图像模式", + "Enable Jinja2 templates" : "启用 Jinja2 模板", + "Enable Maintenance tab" : "启用 \"维护\" 选项卡", + "Enable MultiDiffusion" : "启用 MultiDiffusion", + "Enable Noise Inversion" : "启用噪声反转", + "Enable noise multiplier scheduling" : "启用噪声乘法 (noise multiplier) 调度", + "Enable optimized monocular depth estimation" : "启用单色深度估算优化 (optimized monocular depth estimation)", + "Enable overwrite" : "允许覆盖", + "Enable perspective flip" : "启用透视翻转", + "Enable pixelization" : "启用像素化", + "Enable Pixel Perfect from lllyasviel. Configure your target width and height on txt2img/img2img default panel before preview if you wish to enable pixel perfect." : "启用 lllyasviel 的完美像素模式。在预览前,请在文生图/图生图界面配置好图像的宽度和高度。", + "Enable postprocessing operations in txt2img and img2img tabs" : "在文生图/图生图选项卡中启用后处理操作", + "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply." : "对 K 采样器启用量化以获得更清晰、干净的结果。这可能会改变现有的随机种子。需重启才能应用。", + "Enable Randomize extension" : "启用随机化扩展", + "Enable Region 1" : "启用区域 1", + "Enable Region 2" : "启用区域 2", + "Enable Region 3" : "启用区域 3", + "Enable Region 4" : "启用区域 4", + "Enable Region 5" : "启用区域 5", + "Enable Region 6" : "启用区域 6", + "Enable Region 7" : "启用区域 7", + "Enable Region 8" : "启用区域 8", + "enables all 3D motion parameters." : "启用所有 3D 运动参数", + "Enable sampler scheduling" : "启用采样器明细表", + "Enable scribble mode if your image has white background." : "使用白色背景图片时请启用涂鸦模式", + "Enable steps scheduling" : "启用迭代步数明细表", + "Enable Subseed scheduling" : "启用第二种子明细表", + "Enable Tag Autocompletion" : "启用Tag自动补全", + "Enable tensorboard logging." : "启用 tensorboard 日志记录", + "Enable this to save VRAM." : "启用此项以节省显存 (VRAM)。", + "Enable weight check" : "启用权重检测", + "Enabling this will provide better results and editability, but cost more VRAM." : "启用此功能将提供更好的结果和可编辑性,但会消耗更多显存(VRAM)", + "Encoder Color Fix" : "编码器颜色修复", + "Encoder Tile Size" : "编码器区块大小", + "end at this step" : "结束控制步数", + "End blur width" : "结束模糊宽度", + "Ending Control Step" : "引导终止步数", + "End Page" : "尾页", + "Engine" : "引擎", + "Enhance" : "增强", + "Enhanced img2img" : "图生图增强", + "Enter categody ids, separated by +. For example, if you want bed+person, your input should be 7+12 for ade20k and 59+0 for coco." : "在此输入类别 ID,用 + 分隔。例如,如果你想分割出 床 + 人,使用ade20k协议应该输入 7 + 12,使用coco协议应该输入 59 + 0。", + "Enter category IDs" : "输入类别ID", + "Enter hypernetwork layer structure" : "超网络层结构", + "Enter input path" : "填写输入目录", + "Enter output path" : "填写输出目录", + "Enter relative to webui folder or Full-Absolute path, and make sure it ends with something like this: '20230124234916_%09d.png', just replace 20230124234916 with your batch ID. The %05d is important, don't forget it!" : "输入绝对路径或者以 webui 为根目录的相对路径,同时确认路径结尾类似“20230124234916_%09d.png”。只需要将 20230124234916 替换为你的 batch ID。“%05d”很重要,别忘了!", + "Enter words and color hexes to mark weights on the sliders for guidance. Hint: Use the txt2img prompt token counter or" : "输入文字和颜色十六进制代码以在滑块上标记权重作为引导。 提示:使用文生图提示词词元计数器或使用", + "Entire Caption" : "整个描述", + "Envelope (Outer Fit)" : "信封模式 (贴合外边)", + "Erase BG" : "移除背景图", + "Error" : "错误", + "Error threshold" : "错误率控制(以百分比计算)", + "Escape brackets" : "将结果中的括号进行转义处理", + "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)" : "在 deepbooru 中使用转义 (\\) 括号(使其用作括号字符而不是强调符)", + "Escape parentheses on insertion" : "插入时转义括号", + "ESRGAN" : "ESRGAN", + "ESRGAN_4x" : "ESRGAN_4x", + "Eta" : "Eta", + "eta (noise multiplier) for ancestral samplers" : "ancestral 采样器的 eta (噪声乘数)", + "eta (noise multiplier) for DDIM" : "DDIM 的 eta (噪声乘数) ", + "Eta noise seed delta" : "Eta 噪声种子偏移量 (ENSD)", + "ETA Noise Seed Delta" : "Eta 噪声种子偏移量 (ENSD)", + "euler" : "euler", + "Euler" : "Euler", + "Euler a" : "Euler a", + "Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps higher than 30-40 does not help" : "Euler Ancestral - 非常有创意,可以根据迭代步数获得完全不同的图像,将迭代步数设置为高于 30-40 不会有正面作用", + "Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps to higher than 30-40 does not help" : "Euler Ancestral - 非常有创意,可以根据迭代步数获得完全不同的图像,将迭代步数设置为高于 30-40 不会有正面作用", + "Eval Preset" : "Eval 预设", + "ex A." : "例 A:", + "Example: Default args should use 221 as total keyframes." : "示例:默认参数应使用 221 作为总关键帧数。", + "Examples" : "例子", + "Example: seed_schedule could use 0:(5), 1:(-1), 219:(-1), 220:(5)" : "示例:种子数表可以使用 0:(5), 1:(-1), 219:(-1), 220:(5)", + "exampls: Change base alpha from 0.1 to 0.9" : "例:从 0.1 至 0.9 改变基层α", + "ex B." : "例 B:", + "ex C." : "例 C:", + "Exclude tags (split by comma)" : "排除提示词 (逗号分隔)", + "exclusion" : "排除", + "Excudes (split by comma)" : "排除 (逗号分隔)", + "exif keyword" : "搜索生成信息关键字", + "EXIF keyword search" : "EXIF 关键词搜索", + "Existing Caption Action" : "对已有的描述文本的行为", + "Existing Caption txt Action" : "对已有的 txt 描述文本的行为", + "Existing Prompt Contents" : "现存的提示词内容", + "Expanded Mask" : "扩展后蒙版", + "Expand Mask" : "展开蒙版设置", + "Experimental features (May be solve the problem of erratic training and difficult to reproduce [set EMA to 0.97])" : "实验性功能(可能解决训练不稳定和难以重现的问题 [将 EMA 设置为 0.97])", + "explicit" : "色情/露骨内容(Explicit)", + "Extension" : "扩展", + "extension by" : "扩展来自", + "extension by bbc_mc" : "由 bbc_mc 编写", + "Extension index URL" : "扩展列表地址", + "Extensions" : "扩展", + "Extension script for AUTOMATIC1111/stable-diffusion-webui to travel between prompts in latent space." : "一个在潜空间中对不同提示词之间进行插值渐变,并生成其渐变过程的扩展脚本", + "extension to be installed." : "插件", + "Extension version" : "扩展版本", + "Extra" : "▼", + "Extra args" : "额外参数", + "Extracted Frame Set" : "提取好的帧", + "Extract every nth frame" : "每第 n 帧提取一次", + "Extract Frames" : "提取帧", + "Extract from frame" : "提取开始帧", + "Extract nth frame" : "提取间隔帧数", + "Extract to frame" : "提取结束帧", + "Extract U-Net features" : "提取 U-Net 特征值", + "Extra file in alias only format" : "附加词库文件使用仅别称格式", + "Extra filename (do not use e621.csv here!)" : "附加词库文件(不要使用e621.csv)", + "Extra filename (for small sets of custom tags)" : "额外文件名(用于小部分的自定义Tag)", + "Extra generation params" : "附加生成参数", + "Extra Networks" : "扩展模型", + "Extra networks tab order" : "扩展模型类型选项卡顺序", + "Extra paths to scan for LoRA models, comma-separated. Paths containing commas must be enclosed in double quotes. In the path, \" (one quote) must be replaced by \"\" (two quotes)." : "扫描低秩微调模型 (LoRA) 的附加目录,以逗号分隔。包含逗号的路径必须用双引号括起来。 在路径中,\"(一个引号)必须替换为\"\"(两个引号)。", + "Extra path to scan for ControlNet models (e.g. training output directory)" : "检索 ControlNet 模型的附加目录(如训练输出目录)", + "Extra path to scan for LoRA models (e.g. training output directory)" : "检索低秩微调模型(LoRA)的附加目录", + "extras" : "后期处理", + "Extras" : "后期处理", + "extras history" : "更多选项卡的历史记录", + "Extra text to add before <...> when adding extra network to prompt" : "在向提示词中添加扩展模型标签时在 <…> 之前添加额外文本", + "Face detection confidence" : "脸部识别强度", + "Face Editor" : "脸部修复", + "Face margin" : "脸部选区大小", + "Face restoration" : "面部修复", + "Face restoration model" : "面部修复模型", + "Face Restore Model" : "面部修复模型", + "Fall-off exponent (lower=higher detail)" : "衰减指数(越小细节越好)", + "Far clip" : "远点削减", + "fast" : "快速模式", + "Fast Decoder" : "使用快速解码器", + "Fast Encoder" : "使用快速编码器", + "Fast Encoder Color Fix" : "快速编码器颜色修复", + "Fast Encoder may change colors; Can fix it with more RAM and lower speed." : "快速编码器可能会导致颜色偏差;通过使用更大的内存和更慢的速度可以避免这个情况", + "favorites" : "收藏夹", + "Favorites" : "收藏夹", + "FFmpeg CRF value" : "FFmpeg CRF 值", + "FFmpeg path/ location" : "FFmpeg 路径", + "FFmpeg settings" : "FFmpeg 设置", + "File" : "文件", + "File format for grids" : "网格图文件格式", + "File format for images" : "图片文件后缀(格式)", + "filename" : "文件名", + "Filename" : "文件名", + "File Name" : "文件名", + "filename_format" : "文件名格式", + "Filename join string" : "文件名连接用字符串", + "filename keyword" : "搜索文件名关键字", + "Filename keyword search" : "文件名关键词搜索", + "filename(option)" : "文件名 (可选)", + "Filename word regex" : "文件名用词的正则表达式", + "file not found: None" : "未检索到模型", + "File size limit for the above option, MB" : "上述选项的文件大小限制,单位:MB", + "Files to process" : "要处理的文件", + "File with inputs" : "含输入内容的文件", + "fill" : "填充", + "fill down" : "向下扩展", + "fill it with colors of the image" : "用图像的颜色(高强度模糊)填充它", + "fill it with latent space noise" : "于潜空间填充噪声", + "fill it with latent space zeroes" : "于潜空间填零", + "fill left" : "向左扩展", + "fill right" : "向右扩展", + "fill up" : "向上扩展", + "Filter by Selection" : "通过选择过滤", + "Filter by Tags" : "通过 Tags 过滤", + "Filter Images" : "过滤图片", + "Filter Images by Tags" : "通过 Tags 过滤图片", + "Filter Logic" : "过滤逻辑", + "Filter models by path name" : "按路径名筛选模型", + "Filter NSFW content" : "过滤成人内容(NSFW)", + "filter out those tags from deepbooru output (separated by comma)" : "从 Deepbooru 输出中过滤掉这些标记(用逗号分隔)", + "find but bo translated:" : "已找到但无翻译:", + "First" : "First (第一生成帧)", + "First frame as init image" : "第一帧作为初始化图像", + "FirstGen" : "FirstGen (处理后生成的第一帧)", + "First Page" : "首页", + "Firstpass height" : "首次高度", + "Firstpass width" : "首次宽度", + "Fix CFG" : "固定引导系数(CFG)", + "fixed" : "固定", + "Fixed Roll" : "固定旋转", + "Fixed seed" : "固定种子", + "Fixed size to resize images to" : "调整图像大小到固定大小", + "Fix Seed" : "固定变异种子(Seed)", + "Flatfile" : "纯文字文件", + "Float value from 0 to 1" : "从 0 到 1 的浮点数数值", + "Focal point edges weight" : "焦点线条权重", + "Focal point entropy weight" : "焦点熵权重", + "Focal point face weight" : "焦点面部权重", + "Font for image grids that have text" : "网格图文字字体", + "Foot Size" : "脚掌尺寸", + "For" : "用于", + "For advanced keyframing with Math functions, see" : "更多关于公式关键帧的高级选项,见", + "Force convert half to float on interpolation (for some platforms)" : "在插值时强制将半精度浮点数转换为全精度 (适用于部分平台)", + "Force image gallery to use temporary files" : "强制图库使用临时文件", + "Force Reset" : "强制重置", + "{% for colour in [\"red\", \"blue\", \"green\"] %}\n {% if colour == \"red\"}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% else %}\n {% prompt %}I hate {{ colour }} roses{% endprompt %}\n {% endif %}\n {% endfor %}" : "{% for colour in [\"red\", \"blue\", \"green\"] %}\n {% if colour == \"red\"}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% else %}\n {% prompt %}I hate {{ colour }} roses{% endprompt %}\n {% endif %}\n {% endfor %}", + "{% for colour in ['red', 'blue', 'green'] %}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% endfor %}" : "{% for colour in ['red', 'blue', 'green'] %}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% endfor %}", + "{% for colour in wildcard(\"__colours__\") %}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% endfor %}" : "{% for colour in wildcard(\"__colours__\") %}\n {% prompt %}I love {{ colour }} roses{% endprompt %}\n {% endfor %}", + "for detailed explanation." : "以了解详细信息。", + "Forearm" : "前臂长度", + "FOR HELP CLICK HERE" : "点击此处获取帮助", + "For hires fix, use width/height sliders to set final resolution rather than first pass (disables Upscale by, Resize width/height to)." : "在高分辨率修复中,通过长宽滑块设定最终分辨率 (关闭放大倍率和自适应分辨率设置)", + "For inpainting, include masked composite in results for web" : "使用重绘时,在网页结果中包含复合蒙版", + "For inpainting, include the greyscale mask in results for web" : "使用重绘时,在网页结果中包含灰度蒙版图", + "For inpainting, save a copy of the greyscale mask" : "使用重绘时,保存一份灰度蒙版副本", + "For inpainting, save a masked composite" : "使用重绘时,保存一份复合蒙版", + "Format" : "格式", + "format: http://127.0.0.1:port" : "格式: http://127.0.0.1:端口号", + "For negative prompts, please write your positive prompt, then --neg ugly, text, assymetric, or any other negative tokens of your choice. OR:" : "对于反向提示词,请写出你的正向提示词,然后添加 --neg ugly,text,assymetric 等您选择的任何其他反向提示词。或者:", + "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam." : "使用 SD 放大(SD upscale)时,图块(Tiles)之间应该有多少像素重叠。图块(Tiles)之间需要重叠才可以让它们在合并回一张图像时,没有清晰可见的接缝", + "for your animation (leave blank to ignore)." : "用于你的动画中(留空表示忽略)", + "Found tags" : "匹配的提示词", + "fp16" : "fp16", + "fp32" : "fp32", + "Frame Interpolation" : "帧插值", + "Frame Interpolation to smooth out, slow-mo (or both) any video." : "进行帧插值来让任何视频获得顺滑的切换效果,慢动作(或两者皆可)", + "Frame Interpolation will *not* run if any of the following are enabled: 'Store frames in ram' / 'Skip video for run all'." : "帧差值将不会在以下任一选项启用时启动:“保存帧图像到内存” / “跳过视频”", + "Framerate" : "帧率", + "Frames per second" : "每秒多少帧", + "Frames to Video" : "帧图片转视频", + "frappe" : "frappe/冰沙(深色-亮)", + "Free GPU" : "释放显存", + "Frequency" : "频率", + "From (full path)" : "从(输入完整路径)", + "From img2img2 settings" : "根据图生图的设置", + "Full" : "完整", + "Full res mask" : "全分辨率蒙版", + "Full res mask padding" : "全分辨率蒙版的填充尺寸", + "G" : "绿色色域", + "gamma" : "伽马值", + "Gamma" : "伽马值", + "Gap fill technique" : "间隙填充技术", + "Gather" : "生成", + "Gelbooru Prompt" : "Gelbooru标签自动摘录", + "gelu" : "gelu", + "Gen" : "生成", + "general" : "大众级/普通内容(General)", + "Generate" : "生成", + "Generate 3D inpainted mesh. (Sloooow)" : "生成 3D inpainted mesh (很慢很慢很慢)", + "Generate 4 demo videos with 3D inpainted mesh." : "使用 3D inpainted mesh 生成 4 个演示视频", + "Generate a checkpoint at the current training level." : "生成当前训练级别的模型权重进度(ckpt)", + "Generate a checkpoint at the current training lvel." : "生成当前训练级别的模型权重进度(ckpt)", + "Generate all possible prompts up to a maximum of Batch count * Batch size)" : "生成不超过(总批次数 * 每批数量)的所有可能的提示词", + "Generate a preview image every N steps, 0 to disable" : "每隔 N 步生成一次预览图,设置为 0 以禁用", + "Generate a sequence of images shifting attention in the prompt. This script enables you to give a range to the weight of tokens in a prompt and then generate a sequence of images stepping from the first one to the second." : "根据提示词生成一系列关注逐渐转移的图像。此脚本使你能够在提示词中为词元(token)的权重指定一个范围,然后生成从一端到另一端的一系列图像", + "Generate Captions" : "生成描述文本", + "Generate Ckpt" : "创建模型(ckpt)", + "Generate forever" : "无限生成", + "Generate human masks" : "生成人工蒙版", + "Generate Info" : "生成信息", + "Generate inputframes" : "生成输入帧", + "Generate layout for batch process" : "生成批量处理的图像分布", + "Generate layout for single image" : "生成单张图像的图像分布", + "Generate Movie Mode" : "视频生成模式", + "Generate Preview" : "生成预览", + "Generate preview images every N steps." : "每 N 步生成一次预览图像", + "Generate random prompts from lexica.art (your prompt is used as a search query)." : "从 lexica.art 生成随机提示词(你的提示词会被用作搜索查询)", + "Generate Skeleton/Depth/Normal/Canny Map" : "生成骨架/深度(Depth)/法线(Normal)/硬边缘描线(Canny)图", + "Generate Stereo anaglyph image (red/cyan)" : "生成 anaglyph 立体图(红/蓝)", + "Generate Stereo side-by-side image" : "生成并排立体图像 (side-by-side image)", + "Generate Video" : "生成视频", + "Generate video from inpainted mesh." : "从 inpainted mesh 生成视频", + "Generation Info" : "生成信息", + "Generation mode" : "生成模式", + "Generation settings:" : "一般设置:", + "Get Civitai Model Info by Model Page URL" : "从 Civitai 模型页面链接拉取模型信息", + "Get comma-separated list of models (for XY Grid)" : "生成逗号分隔的模型列表(方便X/Y表使用)", + "*Get depth from uploaded video*" : "*从上传的视频中获取深度*", + "Get javascript logs" : "获取 javascript 日志", + "Get List" : "获取列表", + "Get Model Info from Civitai" : "从 Civitai 上获取模型信息", + "Get Model Info from Civitai by URL" : "从 Civitai 链接获取模型信息", + "Get sub directories" : "打开子目录文件夹", + "Get Tags" : "从Gelbooru获取标签 (图像必须是原图且以Gelbooru原始的MD5哈希值命名)", + "GFPGAN" : "GFPGAN", + "GFPGAN visibility" : "GFPGAN 强度", + "gif" : "gif", + "Github" : "Github", + "give it a star on GitHub" : "在 Github 上给一个大大的 Star 来支持作者", + "GLOB patterns (comma separated)" : "需要匹配的图像后缀名(以英文逗号分割)", + "Glow" : "辉光", + "Glow mode" : "辉光模式", + "glu" : "glu", + "grad" : "梯度", + "Grad Accumulation Steps" : "梯度累加步数(Grad Accumulation Steps)", + "Gradient accumulation steps" : "梯度累加步数", + "Gradient Accumulation Steps" : "梯度累加步数(Gradient Accumulation Steps)", + "Gradient Checkpointing" : "梯度进度记录(Gradient Checkpointing) - 以时间换显存", + "grad_max" : "最大梯度", + "grad_min" : "最小梯度", + "gray" : "灰度模式", + "Great" : "很好的", + "Grid layout" : "网格图布局", + "Grid margins (px)" : "宫格图边框(像素)", + "Grid row count; use -1 for autodetect and 0 for it to be same as batch size" : "网格图行数; 使用 -1 进行自动检测,使用 0 使其与单批数量相同", + "grid_rows" : "宫格行数", + "GroundingDINO batch progress status" : "GroundingDINO 批量处理状态", + "GroundingDINO Box Threshold" : "GroundingDINO 箱体阈值", + "GroundingDINO Detection Prompt" : "GroundingDINO 检测提示词", + "GroundingDINO Model (Auto download from huggingface)" : "GroundingDINO 模型(从huggingface自动下载)", + "GroundingDINO + Segment Anything can achieve [text prompt]->[object detection]->[segmentation]" : "GroundingDINO + Segment Anything 可以实现 [文本提示词]->[对象检测]->[语义分割]", + "Group/split table by: (when not started with single quote - so only for prompts, not for merge)" : "提示词分组方式(非单引号开头时):", + "Guess Mode" : "无提示词引导模式", + "Guess what - this will be incredibly slow, but it will work for < 8GB GPUs." : "你猜怎么着 - 这将非常地慢我的老伙计,但它适用于 < 8GB 显存(VRAM)的 GPU", + "Guidance End (T)" : "引导终止时机", + "Guidance Start (T)" : "引导介入时机", + "Guidance strength (T)" : "引导强度(迭代参与%,Guidance strength)", + "Guided Images" : "引导图像", + "Guided images schedules" : "引导图像参数表", + "H" : "高", + "HakuImg" : "Haku 图像处理", + "haku_output" : "Haku 输出", + "Half" : "一半", + "Half Model" : "半模型", + "Hands" : "手掌", + "Hand Size" : "手掌尺寸", + "hard_light" : "强光", + "hardshrink" : "hardshrink", + "hardsigmoid" : "hardsigmoid", + "hardtanh" : "hardtanh", + "Has EMA:" : "是否有 EMA", + "hash" : "哈希", + "[hash:]" : "[hash:<算法>]", + "has metadata" : "有元数据", + "Head Size" : "头部尺寸", + "HED Resolution" : "HED 分辨率(HED Resolution)", + "height" : "高度", + "Height" : "高度", + "Help" : "帮助", + "Help for Jinja2 templates" : "Jinja2 模板帮助", + "here" : "这里", + "Here, a random number between 1 and 3 words from adjective.txt will be chosen and joined together with the word 'and' instead of the default comma." : "此处,会从 adjective.txt 中选取随机 1 至 3 行,以 'and' (而不是默认的逗号)拼接", + "Heun" : "Heun", + "Hidden UI tabs (requires restart)" : "需要隐藏的 UI 选项卡 (需要重启)", + "Hide annotator result" : "隐藏预处理预览结果", + "Hide caption" : "隐藏文本标注", + "Hide extensions with tags" : "隐藏含有以下标签的扩展", + "Hide heatmap images" : "隐藏热力图图像", + "Hide samplers in user interface (requires restart)" : "在用户界面中隐藏采样器 (需重启)", + "Highres. Denoising Strength" : "高清修复:重绘幅度", + "Highres. fix" : "高分辨率修复", + "Highres. Height" : "高清修复:第一遍高度", + "Highres. percentage chance" : "高清修复:随机概率", + "Highres. Width" : "高清修复:第一遍宽度", + "Hips" : "臀部尺寸", + "hiresfix" : "高清修复", + "Hires. fix" : "高分辨率修复 (Hires. fix)", + "Hires steps" : "高分迭代步数(Hires steps)", + "Hires upscaler" : "超分辨率高清算法", + "Historical" : "Historical (当前帧前的倒数第二帧)", + "History" : "历史记录", + "Horizontal" : "水平", + "Horizontal Mirroring" : "水平镜像", + "horizontal split num" : "水平分割数", + "Horizontal+Vertical Mirroring" : "水平+垂直镜像", + "Hough distance threshold (MLSD)" : "霍夫距离阈值(Hough distance threshold)(MLSD)", + "Hough Resolution" : "霍夫分辨率(Hough Resolution)", + "Hough value threshold (MLSD)" : "霍夫值阈值(Hough value threshold)(MLSD)", + "how closely the image should conform to the prompt. Lower values produce more creative results. (recommended range 5-15)" : "图像应符合提示词的程度。较低的值会产生更具创造性的结果。(建议范围5-15)", + "how close to get to the colors of the input frame image/ the amount each frame during a tweening step to use the new images colors" : "如何接近输入帧图像的颜色 / 在中间计算步骤中使用新图像颜色的每帧数量", + "how fast should the training go. Low values will take longer to train, high values may fail to converge (not generate accurate results) and/or may break the embedding (This has happened if you see Loss: nan in the training info textbox. If this happens, you need to manually restore your embedding from an older not-broken backup).\n\nYou can set a single numeric value, or multiple learning rates using the syntax:\n\n rate_1:max_steps_1, rate_2:max_steps_2, ...\n\nEG: 0.005:100, 1e-3:1000, 1e-5\n\nWill train with rate of 0.005 for first 100 steps, then 1e-3 until 1000 steps, then 1e-5 for all remaining steps." : "训练应该多快。低值将需要更长的时间来训练,高值可能无法收敛(无法产生准确的结果)以及/也许可能会破坏 Embedding(如果你在训练信息文本框中看到 Loss: nan 就会发生这种情况。如果发生这种情况,你需要从较旧的未损坏的备份手动恢复 Embedding)\n\n你可以使用以下语法设置单个数值或多个学习率:\n\n 率1:步限1, 率2:步限2, ...\n\n如: 0.005:100, 1e-3:1000, 1e-5\n\n即前 100 步将以 0.005 的速率训练,接着直到 1000 步为止以 1e-3 训练,然后剩余所有步以 1e-5 训练", + "How many batches of images to create" : "创建多少批量次数的图像", + "How many classifier/regularization images to generate at once." : "一次生成多少分类/规范化图像。", + "How many images to process at once per training step?" : "每步训练要处理多少张图像?", + "How many image to create in a single batch" : "每批创建多少图像", + "How many results to load at once" : "一次性加载Tag数", + "How many samples to generate per subject." : "每个主体生成多少样本", + "How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results" : "迭代改进生成的图像多少次;更高的值需要更长的时间;非常低的值会产生不好的结果", + "How many times to repeat processing an image and using it as input for the next iteration" : "重复处理图像并用作下次迭代输入的次数", + "how much the image should look like the previou one and new image frame init. strength schedule might be better if this is higher, around .75 during the keyfames you want to switch on" : "前一个图像和新的图像帧的初始化强度规划有多大的关系。在你想启用的关键帧中,如果这个数字高一点,大约0.75,可能会更好。", + "How much to blur the mask before processing, in pixels." : "处理前要对蒙版进行多强的模糊,以像素为单位", + "How often, in seconds, to flush the pending tensorboard events and summaries to disk." : "刷新间隔,单位为秒;将待处理的 Tensorboard 事件和摘要刷新到硬盘", + "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something)." : "想要产生多强烈的变化。设为 0 时,将没有效果。设为 1 时,你将获得完全产自差异随机种子的图像(此功能对带有 a 后缀的采样器无效)", + "hue" : "色度", + "HuggingFace Token" : "HuggingFace 令牌(Token)", + "\"Hug the middle\" during interpolation" : "在插值的途中 \"主动去找中间点\"", + "Humans Masking" : "人工蒙版", + "Hybrid composite" : "混合合成模式", + "Hybrid motion" : "混合模式", + "Hybrid Schedules" : "混合参数表", + "Hybrid Settings" : "合成设置", + "Hybrid Video" : "视频合成", + "Hybrid Video Compositing in 2D/3D Mode" : "2D/3D 模式下的混合视频合成", + "Hypernet str." : "超网络(Hypernetwork) 强度", + "Hypernetwork" : "超网络(Hypernetwork)", + "Hypernetwork Learning rate" : "超网络模型学习率", + "Hypernetworks List" : "可选的超网络列表", + "Hypernetwork strength" : "超网络(Hypernetwork) 强度", + "Hypernetwork strengths" : "超网络强度", + "ID input" : "ID 输入", + "Ids for tokenization (example: 9061, 631, 736)" : "用于词元化的 ID (例: 9061, 631, 736)", + "If $$ is not provided, then 1$$ is assumed." : "若没提供 $$,默认为 1$$", + "If an image is too large, crop it from the center." : "如果图像太大,裁掉边缘", + "If Empty" : "如果为空", + "If enabled, only images will be saved" : "启用时,仅保存图片", + "if enabled, raw imgs will be deleted after a successful video/ videos (upsacling, interpolation, gif) creation" : "如果启用,则在成功创建视频/视频(无损放大,插值,gif)后,将删除原始图像", + "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG" : "如果 PNG 图像大于 4MB 或宽高之一大于 4000,则缩小并保存副本为 JPG 图片", + "If setting2prompt width, which width-ratio between both columns (0: minimize setting, 1: 50/50, 6: minimize output gallery column)" : "设置文生图, 图生图双栏宽度比 (0: 最小化左侧栏宽度, 1: 双侧栏各占50%宽度, 6: 最小化右侧图像输出栏)", + "If the chosen number of terms is greater than the available terms, then some terms will be duplicated, otherwise chosen terms will be unique. This is useful in the case of wildcards, e.g." : "选的项数多于提供的项数时,有些项会重复,其余情况各选项会保持唯一;\n重复对于通配符很有用,例如:", + "If the groups wont drop down click" : "如果无法下拉组,点击", + "If the saved image file size is above the limit, or its either width or height are above the limit, save a downscaled copy as JPG" : "当图像文件大小或尺寸超过限制,另存一份缩小的副本为 JPG 格式", + "If this is set, then random prompts are generated, even if the seed is the same." : "如果设置了此项,则会生成随机提示词,即使种子相同", + "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner." : "如果启用此选项,水印将不会添加到生成出来的图像中。警告:如果你不添加水印,你的行为可能是不符合专业操守的", + "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing." : "如果这个值不为零,它将被添加到随机种子中,并在使用带有 Eta 的采样器时用于初始化随机噪声。你可以使用它来产生更多的图像变化,或者你可以使用它来模仿其他软件生成的图像,如果你知道你在做什么", + "If you are using these templates, please let me know if they are useful." : "如果你在用这些模板,请告诉我它们是否有用", + "If you liked this extension, please" : "如果你喜欢本插件,请", + "If you still cannot understand, use default." : "如果你仍然无法理解,请保持默认值。", + "If you want to display the original model as well for comparison" : "如果你同时想显示原本模型以做对比", + "If you want to use Width/Height which are not multiples of 64, please change noise_type to 'Uniform', in Keyframes --> Noise." : "如果你的宽 / 高参数不是 64 的倍数, 请改变噪点选项到 '统一的‘ ,该选项在关键帧---->噪点选项卡内", + "ignore" : "无视", + "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them" : "对于拥有同名 .vae.pt 的模型,忽略外挂 VAE", + "Ignores step count - uses a number of steps determined by the CFG and resolution" : "Ignores step count-使用由 CFG 和分辨率确定的步骤", + "Ignore the negative prompt. Magic Prompt and I'm feeling lucky generate negative prompts by default, check this to disable that functionality." : "忽略反向提示词\n魔法提示词和手气不错默认生成反向提示词,勾选此选项以禁用这种功能", + "I hate blue roses" : "I hate blue roses", + "I hate green roses" : "I hate green roses", + "I know what I am doing." : "高级选项", + "I love {{ choice('red', 'blue', 'green') }} roses" : "I love {{ choice('red', 'blue', 'green') }} roses", + "I love red roses" : "I love red roses", + "image" : "图像", + "Image" : "图像", + "Image border outfill method:" : "图像边缘的填充方法:", + "Image browser" : "图库浏览器", + "Image Browser" : "图库浏览器", + "Image CFG" : "图像引导系数(CFG)", + "Image CFG Scale" : "图像引导系数 (CFG)", + "Image Count" : "图片数量", + "Image creation progress preview mode" : "图像生成过程预览模式", + "Image Directory" : "图片目录", + "Image File" : "图像文件", + "Image for Auto Segmentation" : "用于语义分割的图像", + "Image for Image Layout" : "用于图像分布的图像", + "Image for img2img" : "图生图的图像", + "Image for inpainting with mask" : "用于局部重绘并手动画蒙版的图像", + "Image for Segment Anything" : "用于分离的图像", + "Image height" : "图像高度", + "Image Init" : "图像初始化", + "Image Layout" : "图像分布", + "Image Parameters" : "图像参数", + "Image path" : "图像路径", + "Image preview height" : "预览图高度", + "Images Browser" : "图库浏览器", + "Images directory" : "图像目录", + "Images filename pattern" : "图片文件名格式", + "Images to use for keyframe guidance" : "用于关键帧引导的图像", + "Image strength schedule" : "图像强度参数表", + "Image Tags" : "图像标签(Tags)", + "Image to 3D" : "图转 3D", + "Image to 3D mesh" : "图像转 3D 网格", + "Image width" : "图像宽度", + "Image with MD5 Hash" : "以MD5哈希值命名的图片文件", + "I'm feeling lucky" : "手气不错", + "img2img" : "图生图", + "img2img alternative test" : "图生图的另一种测试", + "img2img DDIM discretize" : "图生图 DDIM 离散化", + "img2img-grids" : "图生图 (网格)", + "img2img history" : "图生图历史记录", + "Implements an expressive template language for random or combinatorial prompt generation along with features to support deep wildcard directory structures." : "为随机或组合式提示词的生成实现了一种表达性模板语言,并支持深层目录结构中的通配符", + "Import a model from Huggingface.co instead of using a local checkpoint." : "从 Huggingface.co 导入模型而非使用本地的模型文件。", + "Important notes:" : "重要信息:", + "Important Notes:" : "重要事项:", + "Important notes and Help" : "重要信息与帮助", + "*Important* notes on Prompts" : "对于提示词模式的重要笔记", + "Import Model from Huggingface Hub" : "从 Huggingface Hub 载入模型", + "Import settings from file" : "从文件导入设置", + "IN00" : "输入层 00", + "IN01" : "输入层 01", + "IN02" : "输入层 02", + "IN03" : "输入层 03", + "IN04" : "输入层 04", + "IN05" : "输入层 05", + "IN06" : "输入层 06", + "IN07" : "输入层 07", + "IN08" : "输入层 08", + "IN09" : "输入层 09", + "IN10" : "输入层 10", + "IN11" : "输入层 11", + "IN_A_00" : "模型 A 输入层 00", + "IN_A_01" : "模型 A 输入层 01", + "IN_A_02" : "模型 A 输入层 02", + "IN_A_03" : "模型 A 输入层 03", + "IN_A_04" : "模型 A 输入层 04", + "IN_A_05" : "模型 A 输入层 05", + "IN_A_06" : "模型 A 输入层 06", + "IN_A_07" : "模型 A 输入层 07", + "IN_A_08" : "模型 A 输入层 08", + "IN_A_09" : "模型 A 输入层 09", + "IN_A_10" : "模型 A 输入层 10", + "IN_A_11" : "模型 A 输入层 11", + "IN_B_00" : "模型 B 输入层 00", + "IN_B_01" : "模型 B 输入层 01", + "IN_B_02" : "模型 B 输入层 02", + "IN_B_03" : "模型 B 输入层 03", + "IN_B_04" : "模型 B 输入层 04", + "IN_B_05" : "模型 B 输入层 05", + "IN_B_06" : "模型 B 输入层 06", + "IN_B_07" : "模型 B 输入层 07", + "IN_B_08" : "模型 B 输入层 08", + "IN_B_09" : "模型 B 输入层 09", + "IN_B_10" : "模型 B 输入层 10", + "IN_B_11" : "模型 B 输入层 11", + "Include artist tags in tag string" : "在标签字串中包含画师标签", + "Include character tags in tag string" : "在标签字串中包含角色标签", + "Include confident of tags matches in results" : "在结果中包含提示词的匹配置信度", + "Include copyright tags in tag string" : "在标签字串中包含版权标签", + "Include images in sub directories" : "显示子目录中的图片", + "Include meta tags in tag string" : "在标签字串中包含属性标签", + "Include resource hashes in image metadata (for resource auto-detection on Civitai)" : "在图像元数据中嵌入资源哈希值 (用于在 Civitai 上自动检测资源)", + "Include Separate Images" : "生成图表时,保留每一张图像", + "Include Sub Grids" : "预览子宫格图", + "Include Sub Images" : "预览子图像", + "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens" : "当使用超过 75 个词元(tokens)时,通过从 n 个词元中的最后一个逗号留空来提高一致性", + "Increment seed after each controlnet batch iteration" : "在每次 ControlNet 完成批量迭代后增加种子", + "Index" : "索引", + "Info" : "信息", + "Info and links" : "资讯和链接", + "Info & Help" : "信息与帮助", + "Info, Links and Help" : "基本信息与帮助链接", + "Info object" : "全部信息", + "Information, comment and share @" : "信息,评论和分享:", + "In FPS" : "输入 FPS", + "In Frame Count" : "输入关键帧数", + "In \"Interpolate existing pics\" mode, FPS is determined *only* by output FPS slider. Audio will be added if requested even with slow-mo \"enabled\", as it does *nothing* in this mode." : "在‘插入已有图像’模式中,帧率仅由帧率设置滑块决定。音频将会加入,即使在慢动作模式启用情况下,且在此模式下什么都不会做。", + "Init" : "初始化", + "Initial denoising strength" : "初始去噪强度", + "Initialization text" : "初始化文本", + "Initialization text (negative)" : "初始化文本(负面)", + "Init image" : "初始化图像", + "Init Video" : "初始化视频", + "In Keyframes tab, you can also set" : "在关键帧页面中,你还可以设置", + "in <>, like , " : "<>,比如 , ", + "In loopback mode, on each loop the denoising strength is multiplied by this value. <1 means decreasing variety so your sequence will converge on a fixed picture. >1 means increasing variety so your sequence will become more and more chaotic." : "在回送模式下,在每个循环中,重绘幅度都会乘以该值。<1 表示减少多样性,因此你的这一组图将集中在固定的图像上。>1 意味着增加多样性,因此你的这一组图将变得越来越混乱", + "inpaint" : "局部重绘", + "Inpaint" : "局部重绘", + "Inpaint area" : "重绘区域", + "Inpaint at full resolution" : "全分辨率局部重绘", + "Inpaint at full resolution padding, pixels" : "预留像素", + "Inpaint batch mask directory (required for inpaint batch processing only)" : "批量重绘蒙版目录 (仅限批量重绘使用)", + "inpaint_global_harmonious" : "Inpaint_Global_Harmonious(重绘 - 全局融合算法)", + "inpaint height" : "重绘高度", + "Inpainting conditioning mask strength" : "局部重绘时图像调节的蒙版屏蔽强度", + "Inpaint masked" : "重绘蒙版内容", + "Inpaint model B detections before model A runs" : "在模型 A 运行之前,先局部重绘模型 B 的检测", + "Inpaint not masked" : "重绘非蒙版内容", + "inpaint sketch" : "涂鸦重绘", + "Inpaint sketch" : "涂鸦重绘", + "Inpaint upload" : "上传重绘蒙版", + "inpaint width" : "重绘宽度", + "Input" : "导入", + "Input directory" : "输入目录", + "Input Directory" : "输入目录", + "Input Image" : "输入图像", + "Input images directory" : "输入图像目录", + "Input <= Output" : "输出图像 发送到 输入图像", + "Input path" : "输入目录", + "In queue..." : "排队中……", + "In Res" : "输入分辨率", + "Insert after" : "后插", + "Insert before" : "前插", + "Insert selected styles into prompt fields" : "在提示词中插入选定的模版风格", + "Inspect" : "检查", + "Inspiration" : "灵感", + "Install" : "安装", + "installed" : "已安装", + "Installed" : "已安装", + "Install from URL" : "从网址安装", + "Installing..." : "正在安装...", + "Instance prompt" : "实例(Instance)提示词", + "Instance prompt(Optional)" : "实例(Instance)提示词 (可选)", + "Instance Token + Class Token + Description" : "实例的词元 + 类的词元 + 描述", + "Instance Token + Description" : "实例的词元(Token) + 描述", + "Instance token to swap" : "要互换的实例的词元(Token)", + "Instead of generating random prompts from a template, combinatorial generation produces every possible prompt from the given string.\nThe prompt 'I {love|hate} {New York|Chicago} in {June|July|August}' will produce 12 variants in total.\nDon't forget to increase the 'Batch count'/'Batch size' value accordingly.\n\t\nThe value of the 'Seed' field is only used for the first image. To change this, look for 'Fixed seed' in the 'Advanced options' section." : "组合生成从给定的字符串中生成所有可能的提示词,而非随机其中一个\n'I {love|hate} {New York|Chicago} in {June|July|August}' 总共会生成 12 句提示词变体\n别忘记相应地增加 “批次(Batch count)” 和 “批量(Batch size)” 值\n\t\n“随机种子” 的值只用于第一图像,可在 “高级选项” 中的 “固定随机种子” 修改此行为", + "instructs the run to start from a specified point" : "指示运行从指定点开始", + "integrations" : "集成功能", + "interactive splines and Bezier curves" : "交互式样条曲线和贝赛尔曲线", + "Intermediate files path" : "临时文件路径", + "Intermediate results may look better than the end results. /!\\ Intermediate results are cleaned after each run, save them elsewhere if you want to keep them." : "中间的结果可能比最终结果看起来更好。提示: 中间的结果在每次运行后都会被清理,如果你想保留它们,就把它们保存在其它地方", + "internal order" : "内部排序", + "Interpolation" : "插值", + "interpolation method" : "插值模式", + "Interpolation method" : "插值算法", + "Interpolation Method" : "融合算法", + "Interrogate" : "反推提示词", + "Interrogate\nCLIP" : "CLIP\n反推", + "Interrogate\nDeepBooru" : "DeepBooru\n反推", + "Interrogate: deepbooru score threshold" : "反推:deepbooru 分数阈值", + "Interrogate: deepbooru sort alphabetically" : "反推:deepbooru 按字母顺序排序", + "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators)." : "反推:在生成结果中包含与模型标签 (tags) 相匹配的等级(对基于生成自然语言描述的反推没有影响)", + "Interrogate: keep models in VRAM" : "反推:将模型保留在显存中", + "Interrogate: maximum description length" : "反推:最大描述长度", + "Interrogate: minimum description length (excluding artists, etc..)" : "反推:最小描述长度(不包括艺术家等)", + "Interrogate: num_beams for BLIP" : "反推:BLIP 的 num_beams", + "Interrogate Options" : "提示词反推设置", + "Interrogate Result" : "Interrogate 结果", + "Interrogate Selected Image" : "Interrogate 被选图片", + "Interrogate: use artists from artists.csv" : "反推:使用 artists.csv 中的艺术家", + "Interrogator" : "反推模型", + "Interrogator Settings" : "Interrogator 设置", + "interrupt" : "中止", + "Interrupt" : "中止", + "In this case, a random number of artists between 1 and 3 is chosen." : "此例中,会从中随机选 1 至 3 个艺术家", + "Inversion steps" : "反转步数 (Steps)", + "Invert colors" : "反转颜色", + "Invert colors if your image has white background." : "对于白色背景图片请开启颜色反转。", + "Invert DepthMap" : "反转深度图", + "Invert DepthMap (black=near, white=far)" : "反转深度图 (黑色=近,白色=远)", + "invert (from white bg & black line)" : "invert (白底黑线反色)", + "Invert Input Color" : "反转输入颜色", + "Invert mask" : "反转蒙版", + "Invert selection" : "反向选择", + "is also a good option, it makes compact math formulae for Deforum keyframes by selecting various waveforms." : "也是一个很好的选择,它通过选择各种波形,为消噪关键帧生成紧凑的数学公式。", + "is equivalent to" : "等同于", + "is experimental functions and NO PROOF of effectiveness." : " 为实验性功能,不保证有效性。", + "Is negative text" : "是反向提示词", + "iter" : "迭代器", + "Iterate seed every line" : "每行输入都换一个随机种子", + "Iterations" : "迭代", + "It takes time, just wait. Check console log for detail" : "检查需要一段时间,请耐心等待。检查控制台日志以查看详情。", + "It will translate prompt from your native language into English. So, you can write prompt with your native language." : "这会将您输入的提示词翻译为英文。因此,您可以直接用母语输入提示词。", + "Javascript logs" : "Javascript 日志", + "Jinja2 documentation." : "Jinja2 文档", + "Jinja2 templates" : "Jinja2 模板", + "Jinja2 templates are an expressive alternative to the standard syntax. See the Help section below for instructions." : "Jinja2 模板是标准语法富有表现力的一种替代品,相关说明参见下方帮助栏", + "Jinja2 templates are based on the Jinja2 template engine. For more information see the" : "Jinja2 模板基于 Jinja2 模板引擎,更多信息参见", + "Jinja2 templates is an experimental feature for advanced template generation. It is not recommended for general use unless you are comfortable with writing scripts." : "Jinja2 模板是一个用于高级模板生成的实验特性。如果不熟悉编写脚本,正常使用时不推荐启用", + "Join the" : "加入", + "Join the official Deforum Discord discord.gg/deforum to share your creations and suggestions" : "加入官方 Deforum 的 Discord discord.gg/deforum 分享您的创作和建议", + "- Joints and Limbs" : "- 关节和四肢", + "json input path (Optional, only for append results)" : "json 输入路径(可选,只用于追加结果)", + "json path" : "json 路径", + "JSON Validator" : "JSON 检查器中检查", + "Just resize" : "仅调整大小", + "Just Resize" : "直接调整大小", + "Just resize (latent upscale)" : "调整大小 (潜空间超分)", + "KaimingNormal" : "Kaiming 正态", + "KaimingUniform" : "Kaiming 均匀", + "Keep -1 for seeds" : "保持种子随机", + "Keep blank if you don't have mask" : "如果没有遮罩, 请保持空白", + "Keep empty if dont use." : "不使用请留空", + "Keep Imgs" : "保留原图", + "Keep input image size" : "保持输入图像大小", + "Keep occlusion edges" : "保持边缘封闭", + "Keep resolution" : "保持分辨率不变", + "keep whatever was there originally" : "保留原来的图像,不进行预处理", + "Kernel schedule" : "Kernel 值表", + "kernel size" : "画笔大小", + "Keyframes" : "关键帧", + "Keyframes: animation settings (animation mode, max frames, border)" : "关键帧:动画设置(动画模式,最大帧数,边界)", + "Keyframes: coherence (color coherence & cadence)" : "关键帧:一致性(颜色一致性和间隔)", + "Keyframes: depth warping" : "关键帧:深度扭曲", + "Keyframes: generation settings (noise, strength, contrast, scale)." : "关键帧:通用设置(噪点,强度,对比度,缩放)", + "Keyframes: motion parameters for 2D and 3D (angle, zoom, translation, rotation, perspective flip)." : "关键帧:2D 和 3D 的运动参数(角度,缩放,变换,旋转,透视翻转)", + "keyword" : "搜索", + "Keywords" : "关键词", + "Krita Plugin." : "Krita 插件", + "Label" : "标记", + "LAB is a more linear approach to mimic human perception of color space - a good default setting for most users." : "LAB 是一种更为线性的方法,可以模拟人类对色彩空间的感知——这是大多数用户的一个很好的默认设置。", + "ladder" : "阶梯式", + "Lanczos" : "Lanczos", + "Last message" : "最后输出信息", + "Latent Mirroring" : "镜像潜空间图像", + "Latent Mirror mode" : "潜空间镜像应用模式", + "Latent Mirror style" : "潜空间镜像方式", + "latent noise" : "潜空间噪声", + "latent nothing" : "潜空间数值零", + "Latent tile batch size" : "潜空间区块单批大小", + "Latent tile height" : "潜空间区块高度", + "Latent tile overlap" : "潜空间区块重叠", + "Latent tile width" : "潜空间区块宽度", + "latest" : "最新", + "latte" : "latte/拿铁(浅色)", + "Layer1" : "图层 1", + "Layer1 mask blur" : "图层 1 蒙版模糊度", + "Layer1 mask strength" : "图层 1 蒙版强度", + "Layer1 opacity" : "图层 1 透明度", + "Layer2" : "图层 2", + "Layer2 mask blur" : "图层 2 蒙版模糊度", + "Layer2 mask strength" : "图层 2 蒙版强度", + "Layer2 opacity" : "图层 2 透明度", + "Layer3" : "图层 3", + "Layer3 mask blur" : "图层 3 蒙版模糊度", + "Layer3 mask strength" : "图层 3 蒙版强度", + "Layer3 opacity" : "图层 3 透明度", + "Layer4" : "图层 4", + "Layer4 mask blur" : "图层 4 蒙版模糊度", + "Layer4 mask strength" : "图层 4 蒙版强度", + "Layer4 opacity" : "图层 4 透明度", + "Layer5" : "图层 5", + "Layer5 mask blur" : "图层 5 蒙版模糊度", + "Layer5 mask strength" : "图层 5 蒙版强度", + "Layer5 opacity" : "图层 5 透明度", + "Layers" : "图层", + "LDSR" : "LDSR", + "LDSR processing steps. Lower = faster" : "LDSR 处理步数。越少越快", + "leakyrelu" : "leakyrelu", + "Learning rate" : "学习率", + "Learning Rate" : "学习率", + "Learning Rate Scheduler" : "学习率调度器(Scheduler)", + "Learning Rate Warmup Steps" : "学习率的预热步数", + "Leave blank to save images to the default path." : "留空以将图像保存到默认路径", + "Leave blank to save images to the same path." : "留空以将图像保存到相同路径", + "Leave blank to use base model VAE." : "留空以使用基底模型的 VAE", + "Leave blank to use instance prompt." : "留空以使用实例提示词", + "Leave blank to use same filename as original." : "留空时将使用与原文件相同的文件名", + "Leave empty for auto" : "留空时自动生成", + "Leave empty for default main branch" : "留空以使用默认分支", + "Leave empty to use img2img batch controlnet input directory" : "留空以使用图生图批量处理 ControlNet 输入目录", + "Leave empty to use input directory" : "留空以使用普通输入目录", + "left" : "左", + "Left click the image to add one positive point (black dot). Right click the image to add one negative point (red dot). Left click the point to remove it." : "左键点击图像添加一个黑色的正向标记点(想提取的部分)。右键点击图像添加一个红色的反向标记点(不想提取的部分)。左键再次点击可以删除标记点。", + "Legacy hash" : "旧哈希值", + "Leg Length" : "腿部长度", + "Len" : "长度", + "Length" : "长度", + "LeReS Resolution" : "LeReS 分辨率(LeReS Resolution)", + "Lerp" : "线性插值", + "Lets you edit captions in training datasets." : "让你可以在这里编辑训练数据集的描述文本", + "License: MIT" : "许可: MIT", + "Licenses" : "开源许可协议", + "lighten" : "变亮", + "like here" : "链接", + "Limb Width" : "四肢宽度", + "linear" : "线性(linear)", + "linear_burn" : "线性加深", + "linear_dodge" : "线性减淡", + "linear_light" : "线性光", + "lineart_anime" : "lineart_anime (动漫线稿提取)", + "lineart_anime_denoise" : "lineart_anime_denoise (动漫线稿提取 - 去噪)", + "lineart_coarse" : "lineart_coarse (粗略线稿提取)", + "lineart_realistic" : "lineart_realistic (写实线稿提取)", + "lineart_standard (form white bg & black line)" : "lineart_standard (标准线稿提取 - 白底黑线)", + "lineart_standard (from white bg & black line)" : "lineart_standard (标准线稿提取 - 白底黑线反色)", + "Link to DeepL" : "Deepl 在线翻译链接", + "Link to image page" : "链接到图片页面", + "List loaded embeddings" : "获取嵌入式模型列表", + "List of active tabs (separated by commas). Available options are txt2img, img2img, txt2img-grids, img2img-grids, Extras, Favorites, Others. Custom folders are also supported by specifying their path." : "激活的图像保存目录标签 (用逗号分隔). 可用的标签有, 文生图(txt2img),图生图(img2img), 文生图-网格(txt2img-grids), 图生图-网格(img2img-grids), 后期处理(Extras), 收藏夹(Favorites), 其它(Others). 也可以通过指定文件目录来自定义目录标签.", + "List of model names (with file extension) or their hashes to use as black/whitelist, separated by commas." : "用于黑/白名单的模型名称(带文件扩展名)或其哈希值的列表,用逗号分隔", + "List of prompt inputs" : "提示词输入列表", + "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply." : "设置项名称的列表,以英文逗号分隔,该设置会移动到顶部的快速访问栏,而不是默认的设置选项卡。有关设置名称,请参见 modules/shared.py。需要保存设置并重启才能应用", + "List-Up checkpoints" : "列出模型(ckpts)", + "Literals" : "字面量", + "Live previews" : "实时过程预览", + "Live preview subject" : "实时预览的主体", + "lms" : "lms", + "LMS" : "LMS", + "LMS Karras" : "LMS Karras", + "⚙️ Load" : "⚙️ 加载", + "Load" : "加载", + "Load All Settings" : "载入所有设置", + "Load an image." : "加载一张图片", + "Load BG" : "加载背景图", + "Load caption from filename if no text file exists" : "当文本文件不存在时,从文件名中加载描述", + "Loaded Model:" : "加载的模型", + "Load from:" : "加载扩展列表", + "Load from JSON" : "加载 JSON", + "Load from subdirectories" : "从子目录中加载", + "load_history" : "加载历史记录", + "Loading..." : "载入中...", + "Load model paramters from the last training session." : "从上次训练中加载模型参数", + "Load Params" : "载入参数", + "Load Preset" : "加载预设", + "Load results" : "加载结果", + "Load Scene" : "加载场景", + "Load Settings" : "载入设定", + "Loads weights from checkpoint before making images. You can either use hash or a part of filename (as seen in settings) for checkpoint name. Recommended to use with Y axis for less switching." : "在生成图像之前从模型(ckpt)中加载权重。你可以使用哈希值或文件名的一部分(如设置中所示)作为模型(ckpt)名称。建议用在Y轴上以减少过程中模型的切换", + "load_switch" : "载入开关", + "Load Video Settings" : "载入视频设置", + "Local directory name" : "本地目录名", + "localization" : "语言包", + "Localization file (Please leave `User interface` - `Localization` as None)" : "本地化文件 (请将\"用户界面\" - “本地化翻译”选项设置为“无”)", + "Localization (requires restart)" : "本地化翻译(需要重启)", + "Location" : "FFmpeg 所在位置", + "Log" : "日志", + "Log directory" : "日志目录", + "logsigmoid" : "logsigmoid", + "logsoftmax" : "logsoftmax", + "Loopback" : "回送", + "[Loopback] Automatically send generated images to this ControlNet unit" : "[回送] 自动发送生成后的图像到此 ControlNet unit", + "Loopback source" : "回送源", + "Loop back to initial seed" : "再变迁回初始种子", + "Looping recommendations:" : "循环设置建议:", + "Loops" : "迭代次数", + "LoRA Block Weight" : "LoRA 区块权重配置", + "LoRA directory (if not default)" : "LoRA 模型文件目录 (如非默认)", + "LoRA in negative textencoder" : "反向提示词中 LoRA 文本编码器权重", + "LoRA in negative U-net" : "反向提示词中 LoRA 的 U net 权重", + "LoRA model name filter" : "按名称过滤低秩微调 (LoRA) 模型", + "Loss for cond match (grad mode)" : "匹配文字调节(cond)损失 (梯度模式)", + "Loss for latent match (grad mode)" : "匹配潜空间(latent)损失 (梯度模式)", + "Lower Leg" : "小腿长度", + "Low fps" : "低帧率", + "Low VRAM" : "低显存模式", + "Low VRAM (8GB or below)" : "低显存 (8 GB 以下) 模式", + "M00" : "中间层", + "(M10) Multiplier" : "(M10) 倍率", + "(M1) Multiplier" : "(M1) 倍率", + "(M2) Multiplier" : "(M2) 倍率", + "(M3) Multiplier" : "(M3) 倍率", + "(M4) Multiplier" : "(M4) 倍率", + "(M5) Multiplier" : "(M5) 倍率", + "(M6) Multiplier" : "(M6) 倍率", + "(M7) Multiplier" : "(M7) 倍率", + "(M8) Multiplier" : "(M8) 倍率", + "(M9) Multiplier" : "(M9) 倍率", + "M_A_00" : "模型 A 中间层", + "macchiato" : "macchiato/玛奇朵(深色)", + "Made by" : "制作于", + "Made by deforum.github.io, port for AUTOMATIC1111's webui maintained by kabachuha" : "由 deforum.github.io 制作,AUTOMATIC1111 的 webui 移植版本由 kabachuha 维护", + "Magic prompt" : "魔法提示词", + "Magic Prompt adds interesting modifiers to your prompt for a little bit of extra spice.\nThe first time you use it, the MagicPrompt model is downloaded so be patient.\nIf you're running low on VRAM, you might get a CUDA error." : "魔法提示词在提示词中加入有趣的修饰,额外增添趣味\n首次使用时会下载 MagicPrompt 模型,请耐心等待\n在低显存情况下可能会导致 CUDA 报错", + "Magic prompt creativity" : "魔法提示词创意", + "Maintenance" : "维护", + "Make a backup copy of the model being edited when saving its metadata." : "保存元数据时,备份正在编辑的模型", + "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution" : "尝试生成图像,与同一随机种子在指定分辨率下生成的图像相似", + "Make GIF" : "制作 GIF 文件", + "make_grid" : "制作宫格", + "Make Images" : "制作图像", + "Make K-diffusion samplers produce same images in a batch as when making a single image" : "使 K-diffusion 采样器在批量生成与生成单个图像时,产出相同的结果", + "Make LoRA (A-B)" : "制作差分 LoRA (A-B)", + "Make LoRA (alpha * A - beta * B)" : "制作差分 LoRA (α × A - β × B)", + "Make your choices, adjust your settings, set a name, save. To edit a prior choice, select from dropdown and overwrite." : "做出选择,调整设置,设置名称,保存。要编辑先前的选择,请从下拉列表中选择并覆盖。", + "Make Zip when Save?" : "保存时创建 zip 压缩文件?", + "mask" : "蒙版", + "Mask" : "蒙版", + "Mask blur" : "蒙版边缘模糊度", + "Mask brightness adjust" : "蒙版亮度调整", + "Mask by Category" : "按分类创建蒙版", + "mask content ratio" : "蒙版内容比例", + "Mask contrast adjust" : "蒙版对比度调整", + "Mask directory" : "遮罩图像目录", + "Masked content" : "蒙版区域内容处理", + "Mask file" : "蒙版文件", + "Mask fill" : "蒙版填充", + "mask image:" : "蒙版图像:", + "Masking mode" : "蒙版模式", + "Mask Init" : "蒙版初始化", + "Mask mode" : "蒙版模式", + "Mask overlay blur" : "蒙版覆盖模糊度", + "Mask schedule" : "蒙版参数表", + "Mask Setting" : "蒙版设置", + "masks from files: in [], like [mask1.png]" : "从文件中获取蒙版:[] ,比如 [mask1.png]", + "Mask size" : "蒙版尺寸", + "Mask source" : "蒙版来源", + "Mask transparency" : "蒙版透明度", + "Match Frame 0 HSV" : "匹配帧 0 HSV", + "Match Frame 0 LAB" : "匹配帧 0 LAB", + "Match Frame 0 RGB" : "匹配帧 0 RGB", + "Match input size" : "匹配输入图尺寸", + "Match input size (size is ignored when using boost)" : "匹配输入尺寸(当使用 BOOST 时会忽略尺寸)", + "Math keyframing explanation docs.google.com/document/d/1pfW1PwbDIuW0cv-dnuyYj1UzPqe23BlSLTJsqazffXM/edit?usp=sharing" : "数学关键帧(Math keyframing)解释 docs.google.com/document/d/1pfW1PwbDIuW0cv-dnuyYj1UzPqe23BlSLTJsqazffXM/edit?usp=sharing", + "Max" : "最大值", + "Max Batch Count" : "最大批次数", + "Max Caption length (0=unlimited)" : "最大描述长度 (0 为无限制)", + "max_frames" : "最大帧数", + "Max frames" : "最大帧数", + "Max Gradient norms." : "最大梯度范数(Max Gradient norms)", + "Max Grad Norms" : "最大梯度范数(Max Grad Norms)", + "Max Image Size" : "最大图像尺寸", + "Maximize area" : "最大化面积", + "maximum aesthetic_score" : "按美学评分上限过滤", + "Maximum aesthetic_score" : "最大美学评分", + "Maximum execution time (seconds)" : "最大执行时间(以秒为单位)", + "Maximum image size, in megapixels" : "上述选项的最大图像尺寸,单位:百万像素", + "Maximum number of faces to detect" : "检测的最大人脸数量", + "Maximum number of images in upscaling cache" : "图像放大缓存中的最大图片数量", + "Maximum ranking" : "最大评分", + "Maximum results" : "候选Tag最大数量", + "Maximum steps fraction to mirror at" : "镜像干涉止步于总迭代步数的", + "Max magic prompt length" : "魔法提示词最大长度", + "Max number of dataset folders to show" : "要显示的最大数据集文件夹数", + "Max number of top tags to show" : "要显示的最大常见标签数", + "Max prompt words for [prompt_words] pattern" : "用于替代 [prompt_words] 占位符的最大提示词数量", + "Max resolution of temporary files" : "临时文件最大分辨率", + "Max steps" : "最大步数", + "Max Token Length" : "最大词元(Token)长度", + "Max Token Length (Requires Pad Tokens for > 75)" : "最大词元(Token)长度 (词元(Token) > 75 时会进行留空)", + "M_B_00" : "模型 B 中间层", + "MBW" : "分块设置权重(MBW)", + "MBW Each" : "A/B 模型分别分块设置权重 (MBW Each)", + "mbw weights" : "分块权重", + "mediapipe_face" : "mediapipe_face (脸部边缘检测)", + "Memory" : "内存", + "Memory Attention" : "内存注意", + "Memory optimization" : "显存优化选项", + "Memory usage" : "内存使用量", + "Merge" : "合并", + "Merge!" : "融合", + "Merge and gen" : "合并后生成", + "Merge And Gen" : "融合并生成", + "Merge and save" : "合并且保存", + "Merge Block Weighted" : "模型分块合并", + "Merge Board" : "合并面板", + "Merge&Gen" : "融合并生成", + "Merge LoRAs" : "合并 LoRA", + "Merge mode" : "合并模式", + "Merge Mode" : "融合算法", + "Merge models and load it for generation" : "融合模型并生成图片", + "Merge to Checkpoint" : "合并到大模型", + "Message" : "信息", + "Metadata to show in XY-Grid label for Model axes, comma-separated (example: \"ss_learning_rate, ss_num_epochs\")" : "显示在 X/Y 表标签下的元数据选项,以逗号分隔(示例:\"ss_learning_rate, ss_num_epochs\")", + "Meta Tags" : "属性标签(Tags)", + "Method" : "方案", + "midas" : "MiDaS 深度信息估算(MiDaS depth estimation)", + "Midas Resolution" : "MiDaS 分辨率(MiDaS Resolution)", + "MiDaS weight (vid2depth)" : "MiDaS 权重(vid2depth)", + "Mimic CFG Scale" : "模拟提示词相关性(Mimic CFG Scale)", + "Min" : "最小值", + "Minimize error" : "最低错误率", + "minimum aesthetic_score" : "按美学评分下限过滤", + "Minimum aesthetic_score" : "最小美学评分", + "Minimum lighting ratio" : "最小照明比率", + "Minimum number of pages per load" : "每次加载的最小页数", + "Minimum ranking" : "最小评分", + "min_mask_region_area" : "最小蒙版面积", + "Min-max" : "最小 - 最大", + "mish" : "mish", + "missing metadata" : " 无元数据", + "Mixed" : "混合", + "Mixed Precision" : "混合精度", + "mlsd" : "mlsd (M-LSD 直线线条检测)", + "mocha" : "mocha/摩卡(深色-暗)", + "mode" : "模式", + "Mode" : "模式", + "model" : "模型", + "Model" : "模型", + "Model 1" : "模型 1", + "Model 2" : "模型 2", + "Model 3" : "模型 3", + "Model 4" : "模型 4", + "Model 5" : "模型 5", + "model A" : "模型 A", + "model_A" : "模型 A", + "Model A" : "模型 A", + "Model_A" : "模型A", + "model B" : "模型 B", + "model_B" : "模型 B", + "Model B" : "模型 B", + "Model_B" : "模型 B", + "model C" : "模型 C", + "model_C" : "模型 C", + "Model C" : "模型 C", + "Model cache size (requires restart)" : "模型缓存数量 (需重启)", + "Model Converter" : "模型转换", + "Model description/readme/notes/instructions" : "模型的描述信息/说明/注释/指引", + "Model directory" : "模型目录", + "Model Epoch:" : "模型 Epoch 数", + "model hash" : "模型哈希值", + "Model hash" : "模型哈希值", + "Model list" : "模型列表", + "Model list will be output here" : "模型列表将会在此处输出", + "model_name" : "模型名", + "Model Name" : "模型名称", + "model of the upscaler to use. 'realesr-animevideov3' is much faster but yields smoother, less detailed results. the other models only do x4" : "需要使用的超分模型。 'realesr-animevideov3' 速度更快但生成的结果更平滑、更详细。其他超分模型只支持 4 倍放大", + "Model path" : "模型路径", + "Model Path" : "模型路径", + "Model path filter" : "按模型路径过滤", + "Model Revision:" : "模型版本号", + "models" : "模型相关", + "Models" : "模型", + "Models..." : "模型列表", + "Model Selection" : "模型选择", + "Model Type" : "模型种类", + "Model Types" : "模型种类", + "Model Version" : "模型版本", + "Mode to add the extra tags to the main tag list" : "选择将额外Tag添加到主要Tag列表的模式", + "Mode to use for model list" : "模型列表模式", + "Modules" : "模块", + "More info about Anti Burn" : "关于 Anti Burn 的更多信息", + "most_different" : "最大差异", + "Most frequent tags in captions" : "训练用描述文本里tags的频率列表", + "most_similar" : "最相似", + "Motion" : "运动参数", + "Motion parameters:" : "运动参数:", + "Mov2Mov output path for image" : "Mov2Mov 图片输出路径", + "Mov2Mov output path for vedio" : "Mov2Mov 视频输出路径", + "Move buttons copy instead of move" : "将图库浏览器内所有\"移动\"按钮改为\"复制\"按钮", + "Move completion popup together with text cursor" : "将弹出窗口与文本光标一起移动", + "Move ControlNet images to CPU (if applicable)" : "将 ControlNet 图像移动到 CPU(如果适用)", + "Move/Copy/Delete matching .txt files" : "将图片的移动、复制、删除操作应用到与之同名的 txt 文件", + "Moved or deleted images will be unloaded." : "被移动或被删除的图片会被卸载。", + "Move face restoration model from VRAM into RAM after processing" : "处理完成后,将面部修复模型从显存卸载到内存", + "Move File(s)" : "移动文件", + "Move Mode (X key)" : "移动模式(X 键)", + "Move or Delete" : "移动或删除", + "Move or Delete Files" : "移动/删除文件", + "Move quicksettings to image setting panel" : "移动快速设置到左侧图像设置面板", + "Move to directory" : "将图片移动到目标路径", + "Move to favorites" : " 移动到收藏夹", + "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM." : "训练超网络(Hypernetwork)时将 VAE 和 CLIP 从显存(VRAM)移放到内存(RAM),节省显存(VRAM)", + "Move VAE and CLIP to RAM when training if possible. Saves VRAM." : "如果可行,训练时将 VAE 和 CLIP 模型从显存移动到内存,可节省显存", + "Move VAE to GPU" : "将 VAE 移动到 GPU", + "Move VAE to GPU (if possible)" : "将 VAE 移动到 GPU (如果允许)", + "mp4" : "mp4", + "Multi ControlNet: Max models amount (requires restart)" : "多重 ControlNet 的最大模型数量 (需重启)", + "Multi-frame rendering" : "多帧渲染", + "Multi Merge" : "多重合并", + "Multi Model Merge" : "多模型合并", + "Multiple Hypernetworks" : "加载多个超网络(Hypernetworks)", + "Multiple lane merge support(up to 10). Save and Load your merging combination as Recipes, which is simple text." : "多通道合并支持(最多 10 个)。 保存或加载你的合并组合为配方,也就是一些简单的文本", + "Multiplication (2^N)" : "倍率 (2^N)", + "multiplier" : "倍率", + "Multiplier" : "倍率", + "Multiplier for extra networks" : "扩展模型默认权重", + "Multiplier (M) - set to 0 to get model A" : "融合比例 (M) - 设为 0 等价于直接输出模型 A", + "multiply" : "乘积", + "Multi Proc Cmd" : "多进程命令", + "multi-subject-render" : "多主体渲染器", + "My prompt is more important" : "更注重提示词", + "NAIConvert" : "NAI转换", + "name" : "名称", + "Name" : "名称", + "Name 0" : "名称 0", + "Name 1" : "名称 1", + "Name 10" : "名称 10", + "Name 11" : "名称 11", + "Name 12" : "名称 12", + "Name 13" : "名称 13", + "Name 14" : "名称 14", + "Name 15" : "名称 15", + "Name 2" : "名称 2", + "Name 3" : "名称 3", + "Name 4" : "名称 4", + "Name 5" : "名称 5", + "Name 6" : "名称 6", + "Name 7" : "名称 7", + "Name 8" : "名称 8", + "Name 9" : "名称 9", + "n_batch" : "批次", + "Near clip" : "近点削减", + "Nearest" : "近邻插值", + "need input your want to translate" : "请输入你想翻译的内容", + "negative" : "负面", + "Negative" : "反向提示词", + "Negative Filter" : "Negative 过滤器", + "Negative lr weight" : "反向的学习率权重", + "Negative prompt" : "反向提示词", + "Negative Prompt" : "反向提示词", + "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)" : "反向提示词 (按 Ctrl+Enter 或 Alt+Enter 开始生成)\nNegative prompt", + "Negative Prompts" : "反向提示词", + "negative prompt to be appended to *all* prompts. DON'T use --neg here!" : "反向提示词会被添加到左右提示词内,请勿在此处使用 --neg 字段", + "Negative Prompt Weight" : "反向提示词权重", + "Negative Prompt, will also be appended" : "追加反向提示词", + "Net height" : "网络高度", + "Net width" : "网络宽度", + "Network module" : "附加网络模块", + "Network module 1" : "附加模型 1", + "Network module 2" : "附加模型 2", + "Network module 3" : "附加模型 3", + "Network module 4" : "附加模型 4", + "Network module 5" : "附加模型 5", + "Network module (used throughout this tab)" : "附加网络类型(仅此页面使用)", + "newest first" : "按发布日期倒序", + "New preset name " : "新预设名称", + "New Scribble Drawing Height" : "新线稿画板高度", + "New Scribble Drawing Width" : "新线稿画板宽度", + "New text file will be created if you are using filename as captions." : "如果您使用文件名作为描述,将创建新的文本文件", + "Next batch" : "下一批", + "Next Page" : "下一页", + "no" : "否", + "No" : "否", + "no-ema" : "删除 EMA 权重", + "no find:" : "未找到:", + "No interpolation" : "原样输出", + "No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking." : "直接输出主要模型。需要一个模型 A。可用于模型格式转换和嵌入 VAE。", + "Noise" : "噪点参数", + "Noise Inversion" : "噪声反转", + "Noise mask schedule" : "噪点蒙版参数表", + "Noise multiplier for img2img" : "图生图噪声倍率", + "Noise multiplier schedule" : "噪声乘法调度(Noise multiplier schedule)", + "Noise schedule" : "噪点值表", + "Noise type" : "噪声类型", + "No model has new version" : "所有模型均是最新版本", + "none" : "无", + "None" : "无", + "NONE" : "无", + "None (just grayscale)" : "什么都不做(灰度模式)", + "norm" : "固定值", + "normal" : "正常", + "Normal background threshold" : "背景识别阈值(Normal background threshold)", + "normal_bae" : "normal_bae (Bae 法线贴图提取)", + "normal_midas" : "normal_midas (Midas 法线贴图提取)", + "Normal Resolution" : "法线贴图分辨率(Normal Resolution)", + "Normal with batch" : "正常(带批处理)", + "Nose To Neck" : "鼻颈距离", + "not" : "不会", + "Note:" : "注意:", + "NOTE: If the 'Generate' button doesn't work, go in Settings and click 'Restart Gradio and Refresh...'." : "注意:如果“生成”按钮不起作用,请进入“设置”并单击“重启 Gradio 及刷新...”。", + "Note that parseq overrides:" : "以下参数将会被参数定序器覆盖设置:", + "(not for Video Input mode)" : "(不是视频输入模式)", + "Nothing" : "无", + "Nothing here. Add some content to the following directories:" : "暂无内容。请添加模型到以下目录:", + "Nothing selected" : "无选中目录", + "----not work----" : "----以下内容无法被翻译,Bug----", + "NUl Image Enhancer" : "NUI 图像增强", + "Number" : "数量", + "Number of clusters:" : "簇数:", + "Number of columns on image gallery" : "图库显示图像列数", + "Number of columns on the page" : "每页列数", + "Number of frames" : "总帧数", + "Number of frames for lead in/out" : "渐入/渐出帧数", + "Number of grids in each row" : "每行显示多少格", + "number of images to delete consecutively next" : "接下来要连续删除的图像数", + "Number of iterations" : "迭代次数", + "Number of negative vectors per token" : "每个词元(token)的反向向量数", + "Number of pictures displayed on each page" : "每页显示的图像数量", + "Number of random seed(s)" : "随机种子数量", + "Number of repeats for a single input image per epoch; used only for displaying epoch number" : "每期(epoch)中单个输入图像的重复次数; 仅用于显示期数", + "Number of rows on the page" : "每页行数", + "Number of samples to generate" : "要生成的样本数", + "Number of Samples to Generate" : "要生成的样本数量", + "Number of sampling steps for upscaled picture. If 0, uses same as for original." : "高清化图片的迭代步数。如果为0,则使用与原图片相同的迭代步数。", + "Number of sampling steps to use when generating preview images." : "生成预览图像时要使用的采样迭代步数", + "Number of steps for the warmup in the lr scheduler." : "学习率调度器中的预热步数", + "number of the frames that we will blend between current imagined image and input frame image" : "当前想象图像和输入帧图像之间混合的帧数", + "Number of vectors per token" : "每个词元 (token) 的向量数", + "(O10) Output ckpt Name" : "(O10) ckpt 输出名", + "(O1) Output ckpt Name" : "(O1) ckpt 输出名", + "(O2) Output ckpt Name" : "(O2) ckpt 输出名", + "(O3) Output ckpt Name" : "(O3) ckpt 输出名", + "(O4) Output ckpt Name" : "(O4) ckpt 输出名", + "(O5) Output ckpt Name" : "(O5) ckpt 输出名", + "(O6) Output ckpt Name" : "(O6) ckpt 输出名", + "(O7) Output ckpt Name" : "(O7) ckpt 输出名", + "(O8) Output ckpt Name" : "(O8) ckpt 输出名", + "(O9) Output ckpt Name" : "(O9) ckpt 输出名", + "official Deforum Discord" : "官方 Discord 频道", + "Official Deforum Wiki:" : "Deforum 官方 Wiki:", + "# of threads to use for hash calculation (increase if using an SSD)" : "用于哈希计算的线程数(如果使用 SSD 可适当增加)", + "oldest first" : "按发布日期正序", + "old localizations" : "过时的语言包", + "Old unmaintained localizations that used to be a part of main repository" : "曾经在主分支上但现在不再维护的旧语言包", + "once" : "单次复用", + "online" : "线上服务", + "Online 3D Openpose Editor" : "在线 3D Openpose 编辑器", + "Only" : "仅检索负面提示词", + "Only applies to inpainting models. Determines how strongly to mask off the original image for inpainting and img2img. 1.0 means fully masked, which is the default behaviour. 0.0 means a fully unmasked conditioning. Lower values will help preserve the overall composition of the image, but will struggle with large changes." : "仅适用于局部重绘专用的模型(模型后缀为 inpainting.ckpt 的模型)。决定了蒙版在局部重绘以及图生图中屏蔽原图内容的强度。 1.0 表示完全屏蔽原图,这是默认行为。0.0 表示完全不屏蔽让原图进行图像调节。较低的值将有助于保持原图的整体构图,但很难遇到较大的变化", + "Only copy to models with no metadata" : "仅复制到不含元数据的模型", + "Only copy to models with same session ID" : "仅复制到具有相同 Session ID 的模型", + "Only extract keyframes (recommended)" : "只提取关键帧(推荐)", + "only for training" : "仅用于训练", + "Only Hand" : "仅显示手部(移除脚部)", + "*Only in use with pix2pix checkpoints!*" : "仅限用于 pix2pix 检查点", + "Only masked" : "仅蒙版区域", + "Only masked padding, pixels" : "仅蒙版区域下边缘预留像素", + "Only Selected Tags" : "只在被选 Tags", + "Only show alias" : "仅展示别名", + "Only Show Models have no Info" : "只显示缺少信息的模型", + "Only show models that have/don't have user-added metadata" : "按是否有元数据过滤模型", + "Only show .safetensors format models" : "只显示 .safetensors 格式的模型", + "Only use mid-control when inference" : "仅在生成图片时使用中间层控制 (mid-control)", + "Only use Random seeds (Unless comparing paths)" : "只用随机种子 (除非需要对比变迁轨迹)", + "(O)Output Model Name" : "输出模型文件名", + "Opacity" : "不透明度", + "Open..." : "打开...", + "Open drawing canvas!" : "创建绘图画布(使用手绘草稿而非上传的图片)", + "Open for Clip Aesthetic!" : "打开以调整 Clip 的美术风格!", + "Open images output directory" : "打开图像输出目录", + "Open intermediate results" : "立即打开当前效果图", + "Open New Scribble Drawing Canvas" : "创建新的线稿画板", + "Open output directory" : "打开输出目录", + "openpose" : "openpose (OpenPose 姿态)", + "openpose-editor" : "OpenPose 编辑器插件", + "OpenPose Editor" : "OpenPose 编辑器", + "openpose_face" : "openpose_face (OpenPose 姿态及脸部)", + "openpose_faceonly" : "openpose_faceonly (OpenPose 仅脸部)", + "openpose_full" : "openpose_full (OpenPose 姿态、手部及脸部)", + "openpose_hand" : "openpose_hand (OpenPose 姿态及手部)", + "Open results" : "打开最终效果图", + "Open TextEditor" : "打开文本编辑器", + "Open Url At Client Side" : "在浏览器侧打开链接", + "Optical Flow" : "光流法", + "Optical flow cadence" : "生成间隔中启用光流法", + "Optionally use [filewords] to read image captions from files." : "可选择使用 [filewords] 去从文件中读取图像的描述", + "(Optional) Path to directory with classification/regularization images" : "(可选)带有分类/规范化图像的目录路径", + "Optional, uses selected model's directory if blank" : "可选,若留空则使用默认目录", + "Options are all options hardcoded, and additional you added in additional_components.py" : "选项都是硬编码的选项,并且是您在 additional_components.py 中添加的附加选项", + "- or -" : "- 或 -", + "or" : "或", + "Order" : "排序", + "original" : "原图", + "Original:" : "原项目:", + "Original Deforum Github repo github.com/deforum/stable-diffusion" : "原始 Deforum Github 仓库 github.com/deforum/stable-diffusion", + ": Original extension" : ": 原始扩展名", + ": Original extension\nAvailable algorithms:" : ": 原始扩展名\\n可用算法:", + ": Original filename without extension" : ": 没有扩展名的原始文件名", + "Original filename without extension" : "没有扩展名的原始文件名", + "Original file's hash (good for deleting duplication)" : "原始文件的哈希值(有利于删除重复项)", + "Original First" : "原文在上", + "OriginalImg" : "OriginalImg (原始输入的第一帧)", + "Original negative prompt" : "原始反向提示词", + "Original prompt" : "初始提示词", + "Original Text = \"A, A, B, C\" Common Tags = \"B, A\" Edit Tags = \"X, Y\"" : "原文本 = \"A, A, B, C\" Common Tags = \"B, A\" Edit Tags = \"X, Y\"", + "Original Text = \"A, B, C\" Common Tags = \"(nothing)\" Edit Tags = \"X, Y\"" : "原文本 = \"A, B, C\" Common Tags = \"(nothing)\" Edit Tags = \"X, Y\"", + "Original Text = \"A, B, C, D, E\" Common Tags = \"A, B, D\" Edit Tags = \", X, \"" : "原文本 = \"A, B, C, D, E\" Common Tags = \"A, B, D\" Edit Tags = \", X, \"", + "Original Weights" : "原始权重", + "or, manually enhance the image" : "↓手动控制图像增强参数↓", + "or to CTRL+SHIFT" : "将 CTRL 绑定更改为 CTRL+SHIFT", + "Other" : "其他", + "others" : "其它", + "- Others" : "- 其它", + "Others" : "其它", + "Other Setting" : "其他设置", + "OUT" : "输出层?", + "OUT00" : "输出层 00", + "OUT01" : "输出层 01", + "OUT02" : "输出层 02", + "OUT03" : "输出层 03", + "OUT04" : "输出层 04", + "OUT05" : "输出层 05", + "OUT06" : "输出层 06", + "OUT07" : "输出层 07", + "OUT08" : "输出层 08", + "OUT09" : "输出层 09", + "OUT10" : "输出层 10", + "OUT11" : "输出层 11", + "OUT_A_00" : "模型 A 输出层 00", + "OUT_A_01" : "模型 A 输出层 01", + "OUT_A_02" : "模型 A 输出层 02", + "OUT_A_03" : "模型 A 输出层 03", + "OUT_A_04" : "模型 A 输出层 04", + "OUT_A_05" : "模型 A 输出层 05", + "OUT_A_06" : "模型 A 输出层 06", + "OUT_A_07" : "模型 A 输出层 07", + "OUT_A_08" : "模型 A 输出层 08", + "OUT_A_09" : "模型 A 输出层 09", + "OUT_A_10" : "模型 A 输出层 10", + "OUT_A_11" : "模型 A 输出层 11", + "OUT_B_00" : "模型 B 输出层 00", + "OUT_B_01" : "模型 B 输出层 01", + "OUT_B_02" : "模型 B 输出层 02", + "OUT_B_03" : "模型 B 输出层 03", + "OUT_B_04" : "模型 B 输出层 04", + "OUT_B_05" : "模型 B 输出层 05", + "OUT_B_06" : "模型 B 输出层 06", + "OUT_B_07" : "模型 B 输出层 07", + "OUT_B_08" : "模型 B 输出层 08", + "OUT_B_09" : "模型 B 输出层 09", + "OUT_B_10" : "模型 B 输出层 10", + "OUT_B_11" : "模型 B 输出层 11", + "Outfill border color:" : "填充颜色:", + "Outfill method:" : "填充方法:", + "Outpainting direction" : "向外绘制的方向", + "Outpainting mk2" : "向外绘制第二版", + "output" : "输出", + "Output" : "输出", + "Output animation path" : "动画输出路径", + "Output Batches" : "输出批次数", + "Output directory" : "输出目录", + "Output directory for grids; if empty, defaults to two directories below" : "网格图统一输出文件夹; 如果为空,则按以下两个文件夹分别输出", + "Output directory for images from extras tab" : "后期处理输出文件夹", + "Output directory for images; if empty, defaults to three directories below" : "统一输出文件夹; 如果为空,则按以下三个文件夹分别输出", + "Output directory for img2img grids" : "图生图网格输出文件夹", + "Output directory for img2img images" : "图生图输出文件夹", + "Output directory for mask previews" : "蒙版预览的输出目录", + "Output directory for masks" : "蒙版输出目录", + "Output directory for txt2img grids" : "文生图网格输出文件夹", + "Output directory for txt2img images" : "文生图输出文件夹", + ": Output extension (has no dot)" : "输出扩展名(没有'.'点)", + "Output filename" : "输出文件名", + "Output filename format" : "输出文件名格式", + "Output filename formats" : "输出文件名格式", + "output images will be placed in a folder with this name, inside of the img2img output folder" : "输出图像将会保存在指定名字的文件夹内,用于取代原有的图生图输出文件夹", + "Output Image Width" : "输出图像宽度", + "Output Model Name" : "输出模型文件名", + "Output path" : "输出目录", + "Output per image:" : "单独输出每张图像:", + "outputs" : "输出", + "Output settings: all settings (including fps and max frames)" : "输出设置:所有设置(包括帧率和最大帧数)", + "Output type" : "输出类型", + "output video resolution" : "输出视频的分辨率", + "Out Res" : "输出分辨率", + "overlay" : "叠加", + "Overlay mask" : "覆盖蒙版", + "override:" : "覆盖以下参数:", + "Override" : "覆盖", + "Override `Denoising strength` to 1?" : "覆写 `重绘幅度` 为 1?", + "Override inpaint to original" : "覆写局部重绘中的原图", + "Override mask blur to 0" : "蒙版模糊数值覆写为0", + "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)" : "覆写 `提示词` 为 `初始提示词`?(`反向提示词` 同理)", + "Override `Sampling method` to Euler?(this method is built for it)" : "覆写 `采样方法` 为 Euler?(这个方法就是为它设计的)", + "Override `Sampling Steps` to the same value as `Decode steps`?" : "覆写 `采样迭代步数` 为 `解码迭代步数`?", + "Override settings" : "覆盖设置", + "override_these_with_webui" : "用 webui 覆写这些", + "overwrite" : "允许覆盖", + "Overwrite" : "覆写", + "Overwrite extracted frames" : "覆盖已有帧", + "Overwrite image size" : "覆盖图像尺寸", + "Overwrite input frames" : "覆盖输入帧", + "Overwrite Old Embedding" : "覆盖同名嵌入式模型文件", + "Overwrite Old Hypernetwork" : "覆盖同名超网络模型文件", + "Pad begin/end frames" : "预留开始/结束帧", + "Padding token (ID or single token)" : "填充提示词(完整ID或者单个提示词)", + "Pad the input images token lenght to this amount. You probably want to do this." : "将输入图像的词元长度垫齐到此数量。你可能会想要这样做", + "Pad Tokens" : "词元(Tokens)垫齐", + "Page Index" : "页码", + "Page Number" : "页数", + "Pages:" : "页码: ", + "Panorama to 3D mesh" : "全景图转 3D 网格", + "Parse!" : "解析", + "Parseq" : "参数定序器 (parameter sequencer)", + "Parseq does" : "参数定序器将", + "Parseq Manifest (JSON or URL)" : "参数定序器配置文件(JSON 或者链接)", + "Parse Recipe" : "剖析配方", + "Parse Result" : "剖析结果", + "Passing ControlNet parameters with \"Send to img2img\"" : "使用\"发送到图生图\"时传输 ControlNet 参数", + "path name" : "路径名", + "Path relative to the webui folder" : "webui文件夹的相对路径", + "Paths for saving" : "保存路径", + "Path to classifier ckpt, can be empty" : "分类器的路径,可留空", + "Path to directory containing annotator model directories (requires restart, overrides corresponding command line flag)" : "预处理器模型 (annotator model) 的文件路径 (需重启,以覆盖相应的命令行标志)", + "Path to directory where to write outputs" : "进行输出的目录路径", + "Path to directory with classification images" : "分类图像的目录路径", + "Path to directory with input images" : "带有输入图像的目录路径", + "/path/to/images or /path/to/images/**/*" : "/path/to/images 或 /path/to/images/**/*", + "/path/to/images/* or /path/to/images/**/*" : "/图像/的/路径/* 或 /图像/的/路径/**/*", + "Path to JSON file with concepts to train." : "用于训练概念的 JSON 文件路径", + "Path to JSON file with concepts to train, or a JSON string." : "包含要训练的概念的 JSON 文件的路径,或 JSON 字符串", + "Path to read videos from" : "读取视频的路径", + "Path to settings file you want to load. Path can be relative to webui folder OR full - absolute" : "需要加载的设置文件路径。该路径可以相对于 SD-WebUI 根目录,也可以是完整的绝对路径", + "Path to store extracted frame sets in" : "储存截取帧的路径", + "PBRemTools" : "精确背景去除工具", + "performance" : "性能", + "Perform warmup" : "进行预热", + "Perspective" : "透视", + "Perspective Flip" : "透视翻转", + "Perspective flip gamma" : "透视翻转伽马值", + "Perspective flip phi" : "透视翻转角度(垂直)", + "Perspective flip theta" : "透视翻转角度(水平)", + "Pick every n-th frame" : "每 n 帧挑选 1 帧", + "Pick frames every n-th" : "每 n 帧挑选 1 帧", + "Pick Subfolder and Model Version" : "选择子目录与模型版本", + "pin_light" : "点光", + "Pix2Pix img CFG schedule" : "Pix2Pix 图像 CFG 表", + "Pixelize" : "像素化", + "Pixel Perfect" : "完美像素模式", + "Pixel size" : "像素块大小", + "Pixels to expand" : "拓展的像素数", + "Platform" : "运行平台", + "Please add text prompts to generate masks" : "请添加文本提示词以生成蒙版", + "Please always keep values in math functions above 0." : "请始终保持数学函数中的值大于 0。", + "Please test on small images before actual upscale. Default params require denoise <= 0.6" : "请在实际扩图前用小分辨率图像进行测试, 默认参数需求去噪强度小于或等于0.6", + "Please use smaller tile size when got CUDA error: out of memory." : "当出现 CUDA error: out of memory 时,使用更小的分块尺寸", + "Please use smaller tile size when see CUDA error: out of memory." : "当出现 CUDA error: out of memory 时,使用更小的尺寸大小", + "PLMS" : "PLMS", + "pndm" : "pndm", + "PNG info" : "PNG 图片信息", + "PNG Info" : "PNG 图片信息", + "PNGs" : "图片(PNG格式)", + "point1 x" : "X 轴点1", + "point1 y" : "Y 轴点1", + "point2 x" : "X 轴点2", + "point2 y" : "Y 轴点2", + "point3 y" : "Y 轴点3", + "points_per_batch" : "每批采样点", + "points_per_side" : "每边采样点", + "polynomial" : "多项式(polynomial)", + "Pooling Avg" : "池化平均值", + "Pooling Max" : "池化最大值", + "Poor man's outpainting" : "效果稍差的向外绘制", + ", port for AUTOMATIC1111's webui maintained by" : ", AUTOMATIC1111's webui 的端口维护是", + "Pose" : "姿势", + "Positions" : "分区位置", + "positive" : "正面", + "Positive" : "正向提示词", + "Positive \"filewords\" only" : "只限正向 \"filewords\"", + "Positive Filter" : "Positive 过滤器", + "Positive / Negative Prompts" : "正向 / 反向提示词", + "positive prompt to be appended to *all* prompts" : "正向提示词会被添加到所有提示词中", + "Postprocessing" : "后期处理", + "Post Processing" : "后期处理", + "Post-Processing" : "后处理", + "Postprocessing operation order" : "后处理操作顺序", + "Precision" : "精度", + "pre-depth background removal" : "pre-depth 背景消除", + "predicted_iou_threshold" : "预测交并比阈值", + "pred_iou_thresh" : "预测滤波阈值", + "Prefix" : "前缀", + "Preload images at startup" : "在启动时预加载图像", + "prelu" : "prelu", + "prepend" : "前置", + "Prepend" : "添加到开头", + "Prepend additional tags" : "将额外标签前置", + "Preprocess" : "预处理", + "Preprocess images" : "图像预处理", + "Preprocessor" : "预处理器", + "Preprocessor resolution" : "预处理器分辨率", + "Prerequisites and Important Info:" : "前提条件和重要信息:", + "Preset" : "预设", + "Preset Manager" : "预设管理器", + "Preset Name" : "预设名", + "Presets" : "预设", + "Preset Weights" : "预设权重", + "Preset_Weights" : "预设权重", + "Prespective flip — Low VRAM pseudo-3D mode:" : "透视翻转 — 低显存(VRAM)伪3D模式:", + "Press enter to add new tag" : "按下 Enter 键添加新提示词", + "Press enter to add tag" : "输入回车添加新标签", + "Pretrained VAE Name or Path" : "预训练的 VAE 名字或者路径", + "Prev batch" : "上一批", + "Prevent empty spots in grid (when set to autodetect)" : "自动检测并消除网格图中的空位", + "Preview annotator result" : "预览预处理结果", + "Preview automatically when add/remove points" : "添加/删除标记点时自动预览", + "Preview image negative prompt" : "预览图反向提示词", + "Preview image prompt" : "预览图提示词", + "Preview Segmentation" : "预览分离结果", + "Preview segmentation image" : "预览语义分割图像", + "Previous" : "Previous (上一生成帧)", + "Previous Page" : "前一页", + "Prev Page" : "上一页", + "Primary detection model (A)" : "首要检测模型 (A)", + "Primary model (A)" : "模型 A", + "Print" : "输出", + "print change" : "打印变更", + "Print debug logs to the console" : "将调试日志输出到控制台", + "Print extra hypernetwork information to console." : "将额外的超网络 (hypernetwork) 信息输出到控制台", + "Print image deletion messages to the console" : "打印图像删除信息到控制台", + "Print warning logs to the console" : "将警告信息输出到控制台", + "Prior Loss Weight" : "先验损失权重(Prior Loss Weight)", + "Process an image, use it as an input, repeat." : "处理一张图像,将其作为输入,并重复", + "Process given file(s) under the input folder, seperate by comma" : "指定在输入文件夹中要处理图像的文件名 (使用逗号隔开)", + "Process images in a directory on the same machine where the server is running." : "处理服务器主机上某一目录里的图像", + "Produce an image that can be tiled." : "生成可用于平铺(tiled)的图像", + "Progressbar/preview update period, in milliseconds" : "进度条/预览图更新周期 (毫秒)", + "Prompt" : "提示词", + "Prompt for face" : "针对脸部的提示词", + "Prompt for tokenization" : "给词元化准备的提示词", + "prompting" : "提示词相关", + "Prompt matrix" : "提示词矩阵", + "Prompt order" : "提示词顺序", + "Prompt (press Ctrl+Enter or Alt+Enter to generate)" : "正向提示词 (按 Ctrl+Enter 或 Alt+Enter 开始生成)\nPrompt", + "Prompts" : "提示词", + "Prompts are stored in JSON format. If you've got an error, check it in a" : "提示词以 JSON 格式存储。如果有错误,请在", + "Prompts are stored in JSON format. If you've got an error, check it in validator," : "提示词以 JSON 格式存储。如果您有错误,请在验证器中检查,", + "prompts for your animation in a JSON format. Use --neg words to add 'words' as negative prompt" : "动画的提示词以 JSON 格式储存。使用 --neg 字段去添加反向提示词", + "Prompts from file or textbox" : "从文本框或文件载入提示词", + "Prompts negative" : "反向提示词", + "Prompts positive" : "正向提示词", + "Prompt S/R" : "提示词搜索/替换", + "Prompt template" : "提示词模板", + "Prompt template file" : "提示词模版文件", + "Prompt Translator" : "提示词翻译器", + "prompt travel" : "提示词变迁", + "Prompt Travel" : "提示词变迁", + "Prompt, will append to your t2i prompt" : "追加提示词", + "Provider" : "提供方", + "Provides an interface to browse created images in the web browser." : "在网页浏览器里提供一个查看生成图像历史的界面", + "Provide Simplified Chinese localization for the WebUI" : "提供简体中文本地化翻译", + "Proxy" : "代理", + "Pruning Methods" : "模型修剪", + "Put variable parts at start of prompt" : "把可变部分放在提示词文本的开头", + "Put weight sets. float number x 25" : "输入权重,共 25 个浮点数,逗号分隔", + "quad" : "二阶", + "Quality for saved jpeg images" : "保存 JPEG 图片的质量", + "questionable" : "强烈性暗示/可疑内容(Questionable)", + "Quick" : "快速设置", + "Quick batch" : "快速批处理", + "Quick Guide" : "快速指引", + "Quick Save" : "快速保存", + "Quicksettings list" : "快捷设置列表", + "R" : "红色色域", + "random" : "随机", + "Random choices" : "随机选择", + "Randomize" : "随机化", + "Randomize CFG" : "随机引导系数(CFG)", + "Randomize CFG Scale" : "随机化 提示词引导系数(CFG Scale)", + "Randomize CLIP skip" : "随机化 在 CLIP 模型的最后哪一层停下 (Clip skip)", + "Randomize Height" : "随机化 高度", + "Randomize Highres. Denoising Strength" : "随机化 高分辨率修复的重绘幅度(Denoising)", + "Randomize Highres. Height" : "随机化 高分辨率修复的第一遍的高度", + "Randomize Highres. percentage" : "随机化 启用高分辨率修复的几率", + "Randomize Highres. Width" : "随机化 高分辨率修复的第一遍的宽度", + "Randomize Sampler" : "随机化 采样器", + "Randomize Seed" : "随机变异种子(Seed)", + "Randomize Steps" : "随机化 采样迭代步数", + "Randomize Width" : "随机化 宽度", + "Randomly decide to flip images horizontally." : "随机决定要不要水平翻转图像", + "Randomly display the pictures of the artist's or artistic genres typical style, more pictures of this artist or genre is displayed after selecting. So you don't have to worry about how hard it is to choose the right style of art when you create." : "随机显示一位艺术家或某艺术流派的图像,选择后会显示更多该艺术家或艺术流派的图像。所以你不用担心在创作时难以选择出想要的艺术风格", + "Randomly selects a keyword from the prompt and adds emphasis to it. Try this with Fixed Seed enabled." : "随机强调提示词中的一个关键词,尝试前要启用固定随机种子", + "Randomness" : "随机度", + "range" : "范围", + "Range" : "范围", + "Range of stepped values (min, max, step)" : "含步幅的随机范围 (最小, 最大, 步幅)", + "ranking" : "评分", + "ranking filter" : "按图片评分过滤", + "Ranking filter" : "评分过滤器", + "rating" : "评分", + "Rating" : "评分", + "Rating confidents" : "评级置信度", + "Read Caption from Selected Image" : "从选择的图片中读取描述", + "Read generation parameters from prompt or last generation if prompt is empty into user interface." : "从提示词或上次生成的图片中读取生成参数", + "*READ ME before you use this mode!*" : "请在使用前认真阅读", + "Read parameters (prompt, etc...) from txt2img tab when making previews" : "进行预览时,从文生图选项卡中读取参数(提示词等)", + "Read tabular commands" : "读取 tabular 命令", + "Read tags from text files" : "从文本文件中读取提示词", + "Reapply ranking after moving files" : "移动文件后重新评分", + "Rebuild exif cache" : "重建 EXIF 缓存", + "Recipe" : "配方", + "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8" : "推荐设置:采样迭代步数:80-100,采样器:Euler a,重绘幅度:0.8", + "Recommended settings: Use from inpaint tab, inpaint at full res ON, denoise <0.5" : "推荐设置:于局部重绘选项卡使用,开启全分辨率局部重绘,重绘幅度(Denoising) < 0.5", + "Reconstruction loss weight" : "重建 损失(loss) 权重", + "Reconstruct prompt from existing image and put it into the prompt field." : "从现有的图像中重构出提示词,并将其放入提示词的输入文本框", + "Record accessable images directories" : "记忆可访问的图像目录", + "Ref image (for conviently locate regions)" : "参考图(用于方便定位区域)", + "Reflect image around border" : "从边缘镜像图像内容", + "refresh" : "刷新", + "Refresh" : "刷新", + "Refresh Civitai Helper" : "刷新 Civitai 助手", + "Refresh Civitai Helper's model card buttons" : "刷新 Civitai 助手 的模型卡片按钮", + "Refresh data" : "刷新数据", + "Refresh Embeddings" : "刷新 Embeddings", + "Refresh models" : "刷新模型列表", + "Refresh openOutpaint" : "刷新 openOutpaint", + "Refresh page" : "刷新页面", + "regex - e.g. ^(?!.*Hires).*$" : "正则表达式 - 如 ^(?!.*Hires).*$", + "Region 1" : "区域 1", + "Region 2" : "区域 2", + "Region 3" : "区域 3", + "Region 4" : "区域 4", + "Region 5" : "区域 5", + "Region 6" : "区域 6", + "Region 7" : "区域 7", + "Region 8" : "区域 8", + "Region Prompt Control" : "分区提示词控制", + "Regions" : "分区", + "Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights." : "输入正则表达式。键名匹配该表达式的权重将从最终合并模型中剔除。使用 ^model_ema 可剔除 EMA 权重。", + "Related to original file" : "与原始文件相关", + "Related to output file" : "与输出文件相关", + "Reload Cache List" : "重载缓存列表", + "Reload checkpoint" : "刷新模型列表", + "Reload Checkpoints" : "重载模型(ckpt)", + "Reload custom script bodies (No ui updates, No restart)" : "重新加载自定义脚本主体(不进行界面更新及重启)", + "Reloading..." : "正在重新加载...", + "Reload Presets" : "重载预设", + "Reload/Save Settings (config.json)" : "重新载入/保存设置 (config.json)", + "Reload settings" : "重新载入设置", + "Reload Tags" : "重载标签", + "Reload the last SD checkpoint back into VRAM" : "重新将上次使用的 Stable Diffusion 模型加载到显存中", + "Reload UI" : "重载前端", + "Reloat List" : "重新加载列表", + "relu" : "relu", + "relu6" : "relu6", + "remake dimension" : "重制维度", + "Rembg Model" : "背景移除模型", + "➖ Remove" : "➖ 移除", + "Remove" : "移除", + "Remove all point prompts" : "移除所有标记点", + "Remove Auto Trans" : "移除自动翻译", + "Remove background" : "移除背景", + "Remove Background %" : "背景排除(%)", + "Remove background image" : "移除背景图片", + "Remove duplicated tag" : "删除重复标签", + "Remove duplicate tags" : "移除重复的 tags", + "Remove from saved directories" : "从已保存的目录中移除", + "Remove Near %" : "近景排除(%)", + "Remove results with the \"animated\" tag" : "删除带有\"animated\"(动图)标签的结果", + "Remove selected" : "移除已选择的图片", + "Remove selected tags" : "移除已选择的 tags", + "Remove selection [Delete]" : "移除选择 [删除]", + "Renew Page" : "刷新页面", + "Repeats" : "重复次数", + "replace" : "取代", + "Replace Class with Subject in Caption" : "将描述文本中的类(Class)替换成主体(Subject)", + "Replace order" : "取代顺序", + "Replace order (replace mode)" : "取代顺序 (取代模式)", + "replace preview" : "替换预览图像", + "Replace spaces with a comma and a space" : "用逗号', '替换空格", + "Replace Text" : "替换文本", + "Replace underscores with spaces" : "用空格替换下划线'_'", + "Replace underscores with spaces on insertion" : "插入时用空格替换下划线", + "replicate" : "复制", + "Request browser notifications" : "请求浏览器通知权限", + "Requires the" : "需要安装", + "reroll" : "回滚", + "Reroll blank frames" : "回滚空白帧", + "Re-run your combinatorial batch this many times with a different seed each time.\nThe maximum number of outputs = Combinatorial batches * Batch size * Batch count.\nTo specify the maximum number of prompt combinations use 'Batch count'/'Batch size' options." : "重复做多批次组合生成,每次用不同的随机种子\n最大输出数为 组合批次 * 批量(Batch size) * 批次(Batch count)\n在 “批次” 和 “批量” 处指定提示词组合的最大数量", + "Resblock" : "残差块(用于残差神经网络 ResNet)", + "reset" : "重置", + "Reset" : "重置", + "Reset Aspect Ratio" : "重置纵横比", + "\uD83C\uDFA5 Reset Camera" : "\uD83C\uDFA5 重置镜头", + "Reset mixer" : "重置合并设置", + "\uD83E\uDDCD Reset Pose" : "重置姿态", + "Reset recipe text area" : "重置配方文本区域", + "Reset Tile Size" : "重置区块大小", + "Reset vars" : "重置变量(vars)", + "Resize" : "缩放比例", + "Resize and fill" : "缩放后填充空白", + "Resize and Fill" : "缩放后填充空白", + "Resize crops to 512x512" : "缩放剪裁至 512x512", + "resize: from" : "从 ", + "Resize height to" : "将高度调整为", + "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio." : "将图像大小调整为目标分辨率。除非高度和宽度匹配,否则你将获得不正确的纵横比", + "Resize mode" : "缩放模式", + "Resize Mode" : "缩放模式", + "Resize seed from height" : "从高度中调整种子", + "Resize seed from width" : "从宽度中调整种子", + "Resizes image to this height. If 0, height is inferred from either of two nearby sliders." : "将图像调整到此高度。如果为0,则从附近的两个滑块中的任意一个其高度。", + "Resizes image to this width. If 0, width is inferred from either of two nearby sliders." : "将图像调整到此宽度。如果为0,则从附近的两个滑块中的任意一个推断其宽度。", + "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors." : "调整图像大小,使整个图像在目标分辨率内。用图像的颜色填充空白区域", + "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out." : "调整图像大小,使整个目标分辨率都被图像填充。裁剪多出来的部分", + "Resize width to" : "将宽度调整为", + "Resizing objective" : "缩放设置", + "Resolution" : "分辨率", + "R-ESRGAN 4x+ Anime6B" : "R-ESRGAN 4x+ Anime6B", + "Restart" : "重启", + "Restart debug" : "重启调试", + "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)" : "重启 Gradio 及刷新组件(仅限自定义脚本、ui.py、js 和 css)", + "Restart UI" : "重载前端", + "Restore Checkpoint after process" : "完成后恢复开始前选择的模型(ckpt)", + "Restore faces" : "面部修复", + "Restore Faces" : "面部修复", + "Restore Faces, Tiling & more" : "面部修复,平铺图等更多选项", + "Restore Last Scene" : "恢复上次场景", + "Restore low quality faces using GFPGAN neural network" : "使用 GFPGAN 神经网络修复低质量面部", + "Restore Selected Config" : "恢复所选配置", + "Restore settings to default" : "恢复至默认设置", + "Restore VAE" : "恢复VAE", + "Result = A" : "结果 = A", + "Result = A * (1 - M) + B * M" : "结果 = A * (1 - M) + B * M", + "Result = A + (B - C) * M" : "结果 = A + (B - C) * M", + "Result = \"A, B, C, X, Y\" (add X and Y to the end (default))" : "结果 = \"A, B, C, X, Y\" (将 X 和 Y 添加至末尾(默认))", + "Results" : "结果", + "Result = \"X, C, E\" (A->\"\", B->X, D->\"\")" : "结果 = \"X, C, E\" (A->\"\", B->X, D->\"\")", + "Result = \"X, Y, A, B, C\" (add X and Y to the beginning (\"Prepend additional tags\" checked))" : "结果 = \"X, Y, A, B, C\" (将 X 和 Y 添加至开头(请勾选“将 tags 添加至开头”))", + "Result = \"Y, Y, X, C\" (B->X, A->Y)" : "结果 = \"Y, Y, X, C\" (B->X, A->Y)", + "Resume Animation" : "重启制作动画过程", + "Resume from timestring" : "从时间字符串中重启", + "Resume & Run from file" : "恢复动画与加载设置", + "Resume timestring" : "重启开始的时间字符串", + "Reuse original image" : "复用原图", + "Reuse seed from last generation, mostly useful if it was randomed" : "使用上一次生成的随机数种子,用于重现结果", + "Reverse model sort order" : "逆序排序", + "rgb" : "RGB 色彩模式", + "RGB to BGR" : "RGB 转 BGR", + "RIFE v4.6 and FILM." : "RIFE v4.6 和 FILM.", + "right" : "右", + "Roll Channels" : "色彩通道轮替", + "Roll three" : "抽三位出来", + "Rotate images (clockwise)" : "旋转图像 (顺时针)", + "rrelu" : "rrelu", + "Run" : "运行参数", + "Run benchmark" : "运行基准测试", + "Run from Settings file" : "加载配置文件", + "Run Merge" : "开始合并", + "Run on incomplete" : "中断后仍然运行", + "Run Python code. Advanced user only. Must run program with --allow-code for this to work" : "运行 Python 代码。仅限老手使用。必须以 --allow-code 来开启程序,才能使其运行", + "Run: Sampler, Width, Height, tiling, resize seed." : "运行参数: 采样器,宽度,高度,平铺图,种子大小调整", + "Run: seed, subseed, subseed strength." : "运行参数:第二种子,第二种子强度", + "Run settings" : "运行设置", + "(S10) Inter-Method" : "(S10) 插值方法", + "(S1) Inter-Method" : "(S1) 插值方法", + "(S2) Inter-Method" : "(S2) 插值方法", + "(S3) Inter-Method" : "(S3) 插值方法", + "(S4) Inter-Method" : "(S4) 插值方法", + "(S5) Inter-Method" : "(S5) 插值方法", + "(S6) Inter-Method" : "(S6) 插值方法", + "(S7) Inter-Method" : "(S7) 插值方法", + "(S8) Inter-Method" : "(S8) 插值方法", + "(S9) Inter-Method" : "(S9) 插值方法", + "safetensors" : "safetensors", + "SAG Mask Threshold" : "SAG 蒙版阈值", + "same to Strength" : "与强度相同", + "SAM Model" : "SAM 模型", + "Sample CFG Scale" : "样本提示词引导系数(CFG Scale)", + "Sample extension. Allows you to use __name__ syntax in your prompt to get a random line from a file named name.txt in the wildcards directory. Also see Dynamic Prompts for similar functionality." : "扩展示例。允许你在提示词中使用 __name__ 语法时,会从 wildcards 目录中一个名为 name.txt 的文件中随机获取一行作为输入。动态提示词扩展也有类似功能", + "Sample guidance scale" : "样本的指导尺度(guidance scale) - 类似基准 CFG scale 的概念", + "Sample Image Negative Prompt" : "样本图像的反向提示词", + "Sample Image Prompt" : "样本图像的提示词", + "Sample Negative Prompt" : "反向提示词示例", + "sampler" : "采样器", + "Sampler" : "采样器", + "Sampler parameters" : "采样器参数", + "Sampler schedule" : "采样器参数表", + "Sample Seed" : "样本种子", + "Sample steps" : "样本迭代步数", + "Sample Steps" : "样本迭代步数", + "Sampling method" : "采样方法 (Sampler)", + "Sampling settings" : "采样器设置", + "Sampling steps" : "迭代步数 (Steps)", + "Sampling Steps" : "迭代步数 (Steps)", + "SAM requires an input image. Please upload an image first." : "SAM 需要你先上传一张图片。", + "saturation" : "饱和度", + "save" : "保存", + "\uD83D\uDCBE Save" : "\uD83D\uDCBE 保存", + "Save" : "保存", + "Save a checkpoint every N steps. " : "每 N 步保存一次模型权重进度(ckpt)", + "Save a checkpoint every N steps, 0 to disable" : "每隔 N 步保存一次模型权重进度(ckpt),设置为 0 以禁用", + "Save a copy of embedding to log directory every N steps, 0 to disable" : "每 N 步将 Embedding 的副本保存到日志目录,0 表示禁用", + "Save a copy of image before applying color correction to img2img results" : "在对图生图结果应用颜色校正之前保存图像副本", + "Save a copy of image before applying highres fix." : "在进行高分辨率修复前保存初始图像副本", + "Save a copy of image before doing face restoration." : "在进行面部修复前保存图像副本", + "Save all changes" : "保存所有更改", + "Save alpha crop" : "裁剪时保留透明度", + "Save an csv containing the loss to log directory every N steps, 0 to disable" : "每 N 步保存一个包含 loss 的 csv 表格到日志目录,0 表示禁用", + "Save an image to log directory every N steps, 0 to disable" : "每 N 步保存一张图像到日志目录,0 表示禁用", + "Save as float16" : "储存半精度 (float16) 模型", + "Save as half" : "保存半精度模型", + "Save as safetensors" : "存为 SafeTensors 格式", + "Save background instead of foreground" : "保存背景而不是前景", + "Save Caption to .txt File" : "储存描述文本为 .txt 文件", + "Save changes" : "保存更改", + "save checkpoint after merge" : "在整合后保存当前模型", + "Save Checkpoint Frequency" : "保存模型权重进度(ckpt)的频率", + "Save crops to:" : "储存裁剪好的成品到:", + "Save Current Config" : "保存当前配置", + "Save Current Model" : "保存当前模型", + "Save current prompts as a style. If you add the token {prompt} to the text, the style use that as placeholder for your prompt when you use the style in the future." : "将当前的提示词保存为模版风格。如果你在文本中添加{prompt}标记,那么将来你使用该模版风格时,你现有的提示词会替换模版风格中的{prompt}", + "Save current settings" : "保存当前设置", + "Save current settings as default" : "将当前设置保存为默认值", + "Saved directories" : "已保存的路径", + "Save depth map" : "保存深度图", + "Save DepthMap" : "保存深度图", + "Save depth maps" : "保存深度图", + "Save Embedding" : "保存 Embedding", + "Save for ALL presets" : "保存为所有预设", + "Save generated images within tensorboard." : "在 tensorboard 中保存所生成的图像", + "Save grids to a subdirectory" : "将网格图保存到子目录", + "Save images to a subdirectory" : "将图像保存到子目录", + "Save images with embedding in PNG chunks" : "保存图像,并在 PNG 图片文件中嵌入 Embedding 文件", + "Save JSON" : "保存为 JSON 格式", + "Save mask" : "保存蒙版", + "Save masked image" : "保存蒙版后图像", + "Save mask previews" : "保存蒙版预览", + "Save masks" : "保存蒙版", + "Save Metadata" : "保存元数据", + "save model" : "保存模型", + "Save options:" : "保存选项", + "Save original image" : "保存原始图像", + "Save original image with mask and bounding box" : "保存带有蒙版和箱体的原始图像", + "Save path for images" : "图像保存目录", + "Save PNG" : "保存为 PNG 格式", + "Save PNGinfo to grid" : "将生成参数写入宫格图(可用图片信息直接识别宫格图)", + "\uD83D\uDCBE\uD83E\uDDCD Save Pose" : "\uD83D\uDCBE\uD83E\uDDCD 保存姿态", + "Save preprocessed" : "保存预处理", + "Save Preset" : "保存预设", + "Save Presets" : "保存预设", + "Save Preview(s) Frequency" : "保存预览的频率", + "Save ranking in image's pnginfo" : "在PNG图片信息中保存评分", + "Save & Restart" : "保存并重启", + "Save results as video" : "保存结果为视频", + "save_sample_per_step" : "每步都储存样本", + "save_samples" : "储存样本", + "Save Scene" : "保存场景", + "save setting" : "保存设置", + "Save Setting" : "保存设置", + "save settings" : "储存设置", + "save_settings" : "储存设定", + "Save Settings" : "储存设置", + "Saves Optimizer state as separate *.optim file. Training can be resumed with HN itself and matching optim file." : "将优化器状态保存为单独的 *.optim 文件。可以使用超网络(HN)本身和匹配的 optim 文件继续中断了的训练。", + "Saves Optimizer state as separate *.optim file. Training of embedding or HN can be resumed with the matching optim file." : "将优化器状态保存为单独的optim文件。在训练嵌入式模型或者超网格化模型时可以根据匹配上的optim文件恢复训练进度", + "Save style" : "将当前提示词储存为预设样式", + "save successful" : "保存成功", + "Save text information about generation parameters as chunks to png files" : "将图片生成参数保存到 PNG 文件中", + "Save textual inversion and hypernet settings to a text file whenever training starts." : "每次训练开始时保存 TI 和 超网格 设置到文本文件中", + "Save the foreground masks" : "保存前景蒙版", + "Save to Presets" : "保存到预设", + "Save vector to text file" : "将向量保存到文本文件", + "Save Video Settings" : "保存视频设置", + "Save with JSON" : "保存为 JSON 格式", + "Saving images/grids" : "图片保存设置", + "Saving to a directory" : "保存到文件夹", + "Scale" : "缩放", + "Scale by" : "缩放倍数", + "Scale Factor" : "放大倍数", + "Scale from image size" : "从图像大小缩放", + "Scale Learning Rate" : "缩放学习率", + "Scale the learning rate by the number of GPUs, gradient accumulation steps, and batch size." : "通过 GPU 数量、梯度累加步数(gradient accumulation steps)和每批数量(batch size)来缩放学习率", + "Scale to" : "缩放到", + "Scale to Fit (Inner Fit)" : "缩放到比例 (贴合内边)", + "Scan" : "扫描", + "Scan Exif-/.txt-data (initially slower, but required for many features to work)" : "扫描图片的 Exif 信息与同名 txt 数据文件(初始读取速度较慢,许多功能都需要需要本选项启用)", + "Scan Exif-/.txt-data (slower, but required for exif-keyword-search)" : "扫描图片的 Exif 信息与同名 txt 文件(会拖慢读取速度,但使用搜索生成信息关键字的时候必须开启)", + "Scan Models for Civitai" : "扫描并匹配 Civitai 模型记录", + "Scanning takes time, just wait. Check console log for detail" : "扫描需要一段时间,请耐心等待。检查控制台日志以查看详情。", + "schedule" : "参数表", + "Scheduler" : "调度器(Scheduler)", + "Scheduler:" : "采样器", + "Schedule to use for official training stuff." : "选择要用于训练官方东西的调度器", + "screen" : "屏幕", + "scribble_hed" : "scribble_hed (涂鸦 - 合成)", + "Scribble Mode" : "涂鸦模式(反色,强制预处理器重新识别)", + "Scribble Mode (Invert colors)" : "涂鸦模式(反色,强制预处理器重新识别)", + "Scribble Mode (Reverse color)" : "涂鸦模式(反色,强制预处理器重新识别)", + "scribble_pidinet" : "scribble_pidinet (涂鸦 - 手绘)", + "scribble_xdog" : "scribble_xdog (涂鸦 - 强化边缘)", + "script" : "脚本", + "Script" : "脚本", + "Script Enabled" : "启用脚本", + "ScuNET GAN" : "ScuNET GAN", + "ScuNET PSNR" : "ScuNET PSNR", + "sd_dreambooth_extension" : "dreambooth 扩展", + "sd-dynamic-prompting" : "动态提示词", + "sd-dynamic-prompts" : "动态提示词", + "sd-extension-aesthetic-scorer" : "美学评分插件", + "sd-extension-system-info" : "系统信息面板", + "sd-parseq manifest" : "sd-parseq 配置文件", + "sd_smartprocess" : "智能预处理", + "SD upscale" : "使用 SD 放大(SD upscale)", + "SD VAE" : "外挂 VAE 模型", + "sdweb-merge-board" : "合并面板", + "sd-webui-gelbooru-prompt" : "Gelbooru标签自动摘录插件", + "sd-webui-multiple-hypernetworks" : "复数超网络加载", + "sdweb-xyplus" : "X/Y图表 Plus 插件", + "Seams fix:" : "接缝修复", + "search" : "搜索", + "Search" : "搜索", + "Search..." : "检索...", + "Search and Replace" : "搜索与替换", + "Search and Replace for all images displayed." : "搜索并替换所有显示的图像", + "Search and Replace in" : "在何处搜索和替换", + "Search Booru" : "搜 Booru", + "Search by alias" : "按别名检索", + "Search by translation" : "按照译文检索", + "Search for embeddings" : "搜索嵌入式模型 (Embeddings)", + "Search for hypernetworks" : "检索超网格", + "Search for Loras" : "检索 Lora 模型", + "Search for LyCORIS/LoHa" : "检索 LyCORIS/LoHa 模型", + "Search for wildcards" : "检索通配符", + "Search Mode" : "搜索模式", + "Search negative prompt" : "检索反向提示词", + "Search Results" : "搜寻结果", + "Search string" : "搜字串", + "Search Tags" : "查找 Tags", + "Search tags / Filter images by tags" : "通过 Tags 搜索 Tags / 过滤图片", + "Search Text" : "搜索文本", + "Secondary detection model (B) (optional)" : "次要检测模型 (B) (可选)", + "Secondary model (B)" : "模型 B", + "See" : "查看", + "seed" : "随机数种子 (seed)", + "Seed" : "随机数种子 (Seed)", + "seed_behavior" : "随机种子行为", + "Seed behavior" : "种子生成方式", + "Seed iter N" : "种子迭代量 N", + "Seed of a different picture to be mixed into the generation." : "将要参与生成的另一张图的随机种子", + "Seeds" : "随机种子", + "seed_schedule" : "种子调度(seed_schedule)", + "Seed schedule" : "种子数表", + "seed_schedule should start and end on the same seed." : "种子数表应该在同一种子上开始和结束。", + "seed travel" : "种子变迁", + "seed_travel" : "种子变迁", + "Seed travel" : "种子变迁", + "See here for explanation of each parameter." : "有关每个参数的说明,请点击 这里 查看。", + "See the progress." : "查看图像增强的实时预览进程", + "Segment Anything" : "分离图像元素(Segment Anything)", + "Segment Anything Output" : "分离元素结果", + "Segment Anything status" : "Segment Anything 状态", + "segmentation prompt" : "图像切分提示词", + "Segmentation status" : "语义分割状态", + "seg_ofade20k" : "seg_ofade20k (语义分割 - OneFormer 算法 - ADE20k 协议)", + "seg_ofcoco" : "seg_ofcoco (语义分割 - OneFormer 算法 - COCO 协议)", + "seg_ufade20k" : "seg_ufade20k (语义分割 - UniFormer 算法 - ADE20k 协议)", + "Select" : "选择", + "Select activation function of hypernetwork" : "选择超网络的激活函数", + "Select activation function of hypernetwork. Recommended : Swish / Linear(none)" : "超网络的激活函数。推荐 Swish / Linear (线性)", + "Select components to hide" : "选择要隐藏的组件", + "(select Disco output format)." : "(选择Disco输出格式)", + "selected" : "被选的", + "Selected" : "选择", + "Selected Image :" : "选择图片", + "Selected One" : "选择一个", + "Selected Tags" : "已选择的 Tags", + "Select Image" : "选择图像", + "Select images from the left gallery." : "从左侧选择图片", + "Select joining char" : "选择分隔符", + "Select Layer weights initialization. Recommended: Kaiming for relu-like, Xavier for sigmoid-like, Normal otherwise" : "选择初始化层权重的方案。建议:类relu 用 Kaiming; 类sigmoid 用 Xavier;其它就用正态", + "Select Layer weights initialization. relu-like - Kaiming, sigmoid-like - Xavier is recommended" : "选择初始化层权重的方案,类relu - Kaiming,类sigmoid - Xavier 都是比较推荐的选项", + "Select prompt" : "选择提示词(prompt)", + "Select Tags" : "选择 Tags", + "Select this if you want to use the same seed for every generated image.\nThis is useful if you want to test prompt variations while using the same seed.\nIf there are no wildcards then all the images will be identical." : "勾选此选项以对每张生成的图像用同样的随机种子\n这在想用同样的随机种子测试提示词变化时会有用\n没有通配符则所有图像会相同", + "Select Translater" : "选择翻译引擎", + "Select visible tags" : "选择可见的 tags", + "Select which Real-ESRGAN models to show in the web UI. (Requires restart)" : "选择在网页界面显示哪些 Real-ESRGAN 模型。(需重启)", + "selu" : "selu", + "Send image to tag selection" : "发送到 标签(Tag)选择", + "Send interrupt" : "发送中断指令", + "Send seed when sending prompt or image to other interface" : "将提示词或者图像发送到其他界面时,同时传送种子数值", + "Send size when sending prompt or image to another interface" : "将提示词或者图像发送到其他界面时,同时传送图像尺寸", + "Send this image to ControlNet." : "将图片发送至 ControlNet", + "Send to" : "发送到", + "Send to Blend" : "发送到 混合", + "Send to Canvas Editor" : "发送到 Canvas Editor", + "Send to ControlNet" : "发送到 ControlNet", + "Send to Effect" : "发送到 效果", + "Send to extras" : "发送到 后期处理", + "Send to img2img" : "发送到 图生图", + "Send to img2img:" : "发送到 图生图:", + "Send to img2img ControlNet" : "发送到 图生图 ControlNet", + "Send to inpaint" : "发送到 重绘", + "Send to inpaint upload" : "发送到 重绘蒙版", + "Send to ip2p" : "发送到 图生图 pix2pix", + "Send to Layer1" : "发送到图层 1", + "Send to Layer2" : "发送到图层 2", + "Send to Layer3" : "发送到图层 3", + "Send to Layer4" : "发送到图层 4", + "Send to Layer5" : "发送到图层 5", + "Send to Multi-Merge" : "发送到 多重合并", + "Send to openOutpaint" : "发送到 openOutpaint", + "Send to Recipe" : "发送到 配方", + "Send to txt2img" : "发送到 文生图", + "Send to txt2img:" : "发送到 文生图:", + "Send to txt2img and img2img" : "发送到 文生图和图生图", + "Send to txt2img ControlNet" : "发送到 文生图 ControlNet", + "sensitive" : "轻微性暗示/敏感内容(Sensitive)", + "Separate a list of words with commas, and the first word will be used as a keyword: script will search for this word in the prompt, and replace it with others" : "以逗号分割的单词列表,第一个单词将被用作关键词:脚本将在提示词中搜索这个单词,并用其他单词替换它", + "Separate a list of words with commas, and the script will make a variation of prompt with those words for their every possible order" : "以逗号分割的单词列表,脚本会排列出这些单词的所有排列方式,并加入提示词各生成一次", + "Separate prompts into parts using vertical pipe character (|) and the script will create a picture for every combination of them (except for the first part, which will be present in all combinations)" : "用竖线分隔符(|)将提示词分成若干部分,脚本将为它们每个可能的组合创建一个图像(始终保留提示的第一部分,使用相同的种子)", + "Separate UNet/Text Encoder weights" : "单独设置 UNet/Text Encoder 权重", + "Separate values for X axis using commas." : "使用逗号分隔 X 轴的值", + "Separate values for Y axis using commas." : "使用逗号分隔 Y 轴的值", + "Sequential Merge Parameters" : "合并参数序列", + "Sequential XY Merge and Generation" : "顺序合并并生成 XY 图", + "Server start time" : "服务器启动时间", + "\uD83D\uDDBC Set" : "\uD83D\uDDBC 设置", + "set_index" : "设置索引", + "Set Init tab's strength slider greater than 0. Recommended value (.65 - .80)." : "将Init选项卡的强度滑块设置为大于0。建议值(.65-.80)。", + "Set Random Pose" : "设置随机姿势", + "Set 'seed_behavior' to 'schedule' under the Seed Scheduling section below." : "在下面的“种子调度”部分下,将 “seed_behavior” 设置为 “schedule” 。", + "Set seed to -1, which will cause a new random number to be used every time" : "将随机种子设置为 -1,则每次都会使用一个新的随机数", + "Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle" : "设置在[prompt_words]选项中要使用的最大字数;注意:如果字数太长,可能会超过系统可处理的文件路径的最大长度", + "Set the preprocessor to [invert] If your image has white background and black lines." : "如果使用白底黑线图片,请使用 \"invert\" 预处理器。", + "Set the strength to 0 automatically when no init image is used" : "当无初始化图像在再被使用时,强度值将自动设置为 0", + "Set this or number of steps to train for, not both." : "设置这个或者'训练迭代步数',两者不能同时用", + "Set this to 2 to increase speed?" : "将此设置为 2 以提高速度?", + "settings" : "设置", + "Settings" : "设置", + "Settings File" : "设置文件", + "settings file path can be relative to webui folder OR full - absolute" : "设置文件路径可以相对于 SD-WebUI 根目录,也可以是完整的绝对路径", + "Settings file Path can be relative to webui folder OR full - absolute" : "设置文件路径可以相对于 SD-WebUI 根目录,也可以是完整的绝对路径", + "settings for" : "设置包括", + "Settings stack. If it's not checked, it wont overwrite. Apply one, then another. Reset is old, update how you need." : "设置堆栈。如果未选中,则不会覆盖。应用一个,再应用另一个。重置已过时,请根据需要进行更新。", + "Set your total number of keyframes to be 21 more than the last inserted keyframe image." : "将关键帧总数设置为比上次插入的关键帧图像多21个。", + "Shapes" : "形状", + "shift-attention" : "关注转移", + "Shift attention" : "关注转移", + "should be 2 or lower." : "应小于等于2", + "Shoulder To Hip" : "肩臀距离", + "Shoulder Width" : "肩宽", + "Show Ad" : "显示广告", + "Show all pages" : "显示所有设置页", + "Show all results" : "展示所有候选Tag", + "Show batch images in gradio gallerie output" : "在 Gradio Gallerie 输出中批量显示图像", + "Show batch images in gradio gallery output" : "在 Gradio Gallery 输出中批量显示图像", + "Show Button On Thumb Mode" : "在缩略图模式下显示按钮", + "Show Civitai Link events in the console" : "在控制台输出 Civitai Link 事件", + "Show console debug" : "在控制台显示调试信息", + "Show DepthMap" : "展示深度图", + "Show description of how to edit tags" : "展示如何编辑 tags", + "Show extra networks" : "显示扩展模型面板", + "Show extra options" : "显示额外选项", + "Show generated images in ui" : "在用户界面上显示生成了的图像", + "Show generation progress in window title." : "在窗口标题中显示生成进度", + "Show grid in results for web" : "在网页输出结果中显示网格图", + "Show HeatMap" : "展示热力图", + "Show/hide extra networks" : "显示/隐藏扩展模型", + "Show image creation progress every N sampling steps. Set 0 to disable." : "每 N 个采样迭代步数显示图像生成进度。设置 0 禁用", + "Show image creation progress every N sampling steps. Set to 0 to disable. Set to -1 to show after completion of batch." : "每 N 个采样迭代步数显示图像生成进度。设置 0 禁用,设置 -1 使预览在批量生成完成之后再显示", + "Show images zoomed in by default in full page image viewer" : "在整页图像查看器中,默认放大显示图像", + "Show live previews of the created image" : "显示当前生成图像的实时预览", + "Show more info" : "显示更多信息", + "Show new live preview image every N sampling steps. Set to -1 to show after completion of batch." : "每N个采样步骤更新一次实时预览图像,设置为-1以在每批次完成后显示,设置为0关闭实时预览 (建议设为0,开启会占用大量显存和显卡算力)", + "Show '?' next to tags, linking to its Danbooru or e621 wiki page (Warning: This is an external site and very likely contains NSFW examples!)" : "在Tag旁边显示'?',链接到其Danbooru或e621维基页面(警告:外部网站可能包含NSFW的内容!)", + "Show only favorite Axis Option" : "仅显示常用坐标轴类型", + "Show only the tags selected in the Positive Filter" : "只展示在 Positive 过滤器中的被选 tags", + "Show Preview" : "显示预览", + "Show previews of all images generated in a batch as a grid" : "通过网格图预览单个批次的所有图像", + "Show progressbar" : "显示进度条", + "Show result images" : "显示输出图像", + "Shows a gallery of generated pictures by artists separated into categories." : "将艺术家按类别划分,并显示其生成出来的图像", + "show_sample_per_step" : "每步都显示样本", + "Show Textbox" : "显示文本框", + "Show verbose debug info at console" : "在控制台中输出详尽的调试信息", + "Show warnings in console." : "在控制台中显示警告", + "Show Width/Height and Batch sliders in same row" : "将批次与批量设置整合到长宽设置的右侧", + "shuffle" : "shuffle (随机洗牌)", + "Shuffleing tags by ',' when create texts." : "创建文本时打乱以 ',' 分割的 tags", + "Shuffle tags by ',' when creating prompts." : "创建提示词时按 ',' 打乱标签(tags)", + "Sigma adjustment for finding noise for image" : "为寻找图中噪点的 Sigma 调整", + "sigma churn" : "sigma 流失率", + "Sigma Churn" : "Sigma Churn", + "Sigma max" : "最大 Sigma", + "Sigma min" : "最小 Sigma", + "sigma noise" : "sigma 噪声", + "Sigma noise" : "Sigma 噪声", + "Sigma schedule" : "Sigma 值表", + "sigma tmin" : "最小(tmin) sigma", + "sigmoid" : "sigmoid", + "sign" : "sign", + "silu" : "silu", + "similar" : "相似", + "Simple" : "单一值", + "Simple (Auto-value)" : "单一值(自动取值)", + "Simplified Chinese localization" : "简体中文本地化", + "single image" : "单张图片", + "Single Image" : "单张图片", + "Single process" : "单张图片", + "size" : "大小", + "Size of the thumbnails (px)" : "缩略图大小 (px)", + "sketch" : "涂鸦", + "Sketch" : "涂鸦", + "Skip" : "跳过", + "Skip img2img processing when using img2img initial image" : "使用图生图初始图像时跳过图生图处理", + "SKip NSFW Preview images" : "下载预览图时跳过含成人内容的图像", + "SKip NSFW Preview Images" : "下载预览图时跳过含成人内容的图像", + "Skip/Reset CLIP position_ids" : "跳过或重置 CLIP position_ids 键值", + "Skip steps" : "跳过步骤数", + "Skip video creation" : "跳过视频生成", + "Slerp angle" : "球面线性插值角度", + "Slerp interpolation" : "球面线性插值", + "Small script for AUTOMATIC1111/stable-diffusion-webui to create images that exists between seeds." : "一个用于生成不同随机种子之间的渐变过程的小脚本", + "Smart Preprocess" : "智能预处理", + "Smart pre-process including auto subject identification, caption subject swapping, and upscaling/facial restoration." : "智能预处理,包括自动主体识别、描述文本主体切换和放大/面部恢复", + "Smart Process" : "智能预处理", + "Smoothing" : "柔和度", + "Snapshot to Resume" : "恢复快照", + "softedge_hed" : "softedge_hed (HED 软边缘检测)", + "softedge_hedsafe" : "SoftEdge_HEDSafe(软边缘检测 - 保守 HED 算法)", + "softedge_pidinet" : "SoftEdge_PiDiNet(软边缘检测 - PiDiNet 算法)", + "softedge_pidisafe" : "SoftEdge_PiDiNetSafe(软边缘检测 - 保守 PiDiNet 算法)", + "soft_light" : "柔光", + "softmax" : "softmax", + "softmax2d" : "softmax2d", + "softmin" : "softmin", + "softplus" : "softplus", + "softshrink" : "softshrink", + "softsign" : "softsign", + "Solid color" : "纯色", + "sort by" : "排序方式", + "Sort by" : "排序方式", + "Sort by alphabetical order" : "按首字母顺序排序", + "Sort caption on save" : "保存时对描述排序", + "Sort LoRA models by" : "低秩微调 (LoRA) 模型排序方式", + "Sort models by" : "排序方式", + "Sort Order" : "排序方式", + "Sort tags" : "排序 tags", + "Sort tags in the images displayed." : "在已显示的图像中排序标签", + "Soundtrack path" : "音轨路径", + "Source" : "来源", + "Source Checkpoint" : "源模型(ckpt)", + "Source Checkpoint:" : "底模来源", + "Source directory" : "源目录", + "Source embedding to convert" : "用于转换的源 Embedding", + "Source URL where this model could be found" : "该模型发布的原始网址", + "space" : "空格", + "Specific branch name" : "特定分支名", + "specify a custom settings file and ignore settings displayed in the interface" : "指定自定义设置文件并忽略界面中显示的设置", + "Specify the amount that you wish to expand the mask by (recommend 0-10)" : "设定蒙版扩展量(建议0-10)", + "Specify the amount that you wish to expand the mask by (recommend 30)" : "设定蒙版扩展量(建议30)", + "specify your own seed schedule (found on the Keyframes page)" : "指定你自己的种子数表(可在关键帧选项卡中找到)", + "Split image overlap ratio" : "分割图像重叠的比率", + "Split image threshold" : "图像分割阈值", + "Split over-sized images" : "分割过大的图像", + "Split oversized images" : "分割过大的图像", + "Split oversized images into two" : "将过大的图像分为两份", + "SSAA" : "超级采样抗锯齿", + "stability_score_offset" : "稳定性得分偏移", + "stability_score_thresh" : "稳定性得分阈值", + "stability_score_threshold" : "稳定性得分阈值", + "Stable Diffusion" : "Stable Diffusion", + "Stable Diffusion checkpoint" : "Stable Diffusion 模型", + "stable-diffusion-webui-aesthetic-gradients" : "美术风格梯度", + "stable-diffusion-webui-aesthetic-image-scorer" : "美术风格评分", + "stable-diffusion-webui-artists-to-study" : "艺术家图库", + "stable-diffusion-webui-auto-tls-https" : "自动 tls-https", + "stable-diffusion-webui-conditioning-highres-fix" : "高分辨率修复原图调节强度 ", + "stable-diffusion-webui-dataset-tag-editor" : "数据集标签编辑器", + "stable-diffusion-webui-embedding-editor" : "Embedding 编辑器", + "stable-diffusion-webui-inspiration" : "灵感", + "stable-diffusion-webui-localization-zh_CN" : "简体中文语言包", + "stable-diffusion-webui-localization-zh_TW" : "正體中文語言包", + "stable-diffusion-webui-pixelization" : "像素化插件", + "stable-diffusion-webui-prompt-travel" : "提示词变迁", + "stable-diffusion-webui-randomize" : "随机化", + "stable-diffusion-webui-tokenizer" : "词元分析器(tokenizer)", + "stable-diffusion-webui-wildcards" : "通配符", + "Stackable" : "可堆叠", + "Stackable checkbox is not used for saves, it's used when making a selection from the dropdown, whether to apply as stackable or not" : "可堆叠复选框不用于保存,它用于从下拉列表中进行选择,无论是否应用为可堆叠", + "Start Auto Translate" : "开始自动翻译", + "Start batch process" : "开始批量处理", + "Start drawing" : "开始绘制", + "start extracting the input video only from this frame number" : "你所需要提取开始初始化视频的帧数", + "Start from Axis" : "优先遍历的坐标轴", + "Starting Control Step" : "引导介入步数", + "Start steps" : "开始步数", + "Start training." : "开始训练", + "State" : "运行状态", + "status" : "状态", + "Status:" : "状态", + "Std" : "标准差", + "Step" : "迭代步数", + "Step count" : "步数 (梯度模式)", + "Step count (grad mode)" : "步数 (梯度模式)", + "Step method" : "步进方法 (梯度模式)", + "Step method (grad mode)" : "步进方法 (梯度模式)", + "steps" : "采样迭代步数(Steps)", + "Steps" : "迭代步数", + "Steps animation" : "预览动画化 (Steps animation)", + "Steps between prompts" : "每个提示词之间的迭代步伐", + "Step size" : "步幅 (梯度模式)", + "Step size (grad mode)" : "步幅 (梯度模式)", + "Steps schedule" : "迭代步数明细表", + "*Stitch frames to video*" : "*将帧缝合到视频中*", + "Stop" : "停止", + "Stop at CLIP layers" : "在 CLIP 模型的最后哪一层停下 (Clip skip)", + "Stop At last layers of CLIP model" : "在 CLIP 模型的最后哪一层停下 (Clip skip)", + "Stop processing current image and continue processing." : "停止处理当前图像,并继续处理下一个", + "Stop processing images and return any results accumulated so far." : "停止处理图像,并返回迄今为止累积的任何结果", + "stop the extraction of the video at this frame number. -1 for no limits" : "你所需要提取结束初始化视频的帧数,-1 表示无限制(全部)", + "Stop XY" : "停止生成 X/Y 图", + "Store all steps of inference also (slow!)" : "同时保存推理中的所有步 (慢!)", + "Store frames in ram" : "将帧保存到内存", + "straight-line" : "直线", + "strength" : "强度", + "Strength" : "强度", + "Strength 0 no init" : "强度为 0 时停用初始化", + "Strength schedule" : "强度表", + "Stretch image" : "拉伸图像", + "Stretch pixels at border" : "延伸边缘的像素", + "Style 1" : "模版风格 1", + "Style 2" : "模版风格 2", + "StylePile" : "风格加码", + "Styles" : "预设样式", + "Style to apply; styles have components for both positive and negative prompts and apply to both" : "要使用的模版风格; 模版风格包含正向和反向提示词,并应用于两者\n\uD83C\uDFA8 随机添加一个艺术家到提示词中\n ↙️ 从提示词中读取生成参数,如果提示词为空,则读取上一次的生成参数到用户界面\n\uD83D\uDCBE 将当前的提示词保存为模版风格(保存在styles.csv)\n\uD83D\uDCCB 将所选模板风格,应用于当前提示词\n如果你在文本中添加{prompt}标记,并保存为模版风格\n那么将来你使用该模版风格时,你现有的提示词会替换模版风格中的{prompt}", + "Sub directories" : "图像目录的子目录", + "Sub directory depth" : "子目录深度", + "Sub-folder" : "子文件夹", + "Subject Class" : "主体类别(Subject Class)", + "Subject class to crop (leave blank to auto-detect)" : "要裁剪的主体类别(Subject class)(留空以自动检测)", + "Subject Name" : "主体(Subject)名", + "Subject Name to replace class with in cations" : "描述文本中要替换类(class)的主体名(subject)", + "Submit" : "提交", + "Submit results" : "提交结果", + "subseed" : "差异随机种子", + "SubSeed" : "第二种子", + "Subseed schedule" : "第二种子参数表", + "subseed_strength" : "差异随机种子强度", + "Subseed strength schedule" : "第二种子强度参数表", + "Suffix" : "后缀", + "Sum" : "和", + "sum Twice:(A*(1-alpha)+B*alpha)*(1-beta)+C*beta" : "两次求和: (A*(1-α)+B*α)*(1-β)+C*β", + "SuperMerger" : "超级模型融合", + "Supported engines:" : "支持的引擎:", + "Supports boolean operations: (! - negation, & - and, | - or, ^ - xor, \\ - difference, () - nested operations)" : "支持布尔操作符:(!-否定/取反,&-与,|-或,^-异或,\\-差分,()-嵌套操作)", + "Swap axes" : "交换XY轴", + "Swap X/Y axes" : "X/Y 轴互换", + "Swap X/Z axes" : "X/Z 轴互换", + "Swap Y/Z axes" : "Y/Z 轴互换", + "Swipe left/right navigates to the next image" : "左右滑动时导航到下一张图片", + "swish" : "swish", + "Switch negative prompt between Native language and English" : "切换反向提示词显示语言 (母语/英语)", + "Switch prompt between Native language and English" : "切换提示词显示语言 (母语/英语)", + "Switch to Inpaint Upload" : "发送到 重绘蒙版", + "symbol:color-hex, symbol:color-hex, ..." : "文字:颜色代码, 文字:颜色代码, ...", + "system" : "系统", + "System" : "系统设置", + "System data" : "系统信息", + "System Info" : "系统信息", + "t2ia_color_grid" : "T2ia_Color_Grid(自适应 像素画处理)", + "t2ia_sketch_pidi" : "T2ia_Sketch_PiDi(自适应 手绘边缘处理)", + "t2ia_style_clipvision" : "T2ia_Style_Clipvision(自适应 风格迁移处理)", + "tab" : "选项卡", + "Tag Autocomplete" : "标签自动补全", + "Tag confidents" : "标签置信度", + "Tag filename" : "选择使用的Tag文件名", + "Tagger" : "WD 1.4 标签器(Tagger)", + "Tags" : "标签", + "tags from the images displayed." : "已显示图像的 tags", + "tanh" : "tanh", + "tanhshrink" : "tanhshrink", + "Target" : "目标", + "Target ControlNet number" : "目标 ControlNet 编号", + "Target dataset num: 0" : "目标数据集数量:", + "Target language" : "目标语言", + "Target Language" : "目标语言", + "Target size type" : "目标尺寸类型", + "Target tokens (comma separated)" : "分隔目标提示词(逗号分隔)", + "temparature" : "色温", + "template" : "模板", + "TEnc Weight 1" : "Text Encoder 权重 1", + "TEnc Weight 2" : "Text Encoder 权重 2", + "TEnc Weight 3" : "Text Encoder 权重 3", + "TEnc Weight 4" : "Text Encoder 权重 4", + "TEnc Weight 5" : "Text Encoder 权重 5", + "Tertiary model (C)" : "模型 C", + "TEST-MAX-ALL" : "全部测试", + "Text" : "文本", + "Textbox" : "文本框", + "Text CFG" : "文本引导系数(CFG)", + "text encoder" : "文本编码器", + "Text files directory (optional, will load from input dir if not specified)" : "文本文件目录 (可选, 如不指定将从输入目录加载)", + "Text files directory (Optional, will load from input dir if not specified)" : "文本文件目录 (可选, 如不指定将从输入目录加载)", + "Text input" : "文本输入", + "Textual Inversion" : "嵌入式(T.I. Embedding)", + "The 1st and last keyframe images should match." : "第一个和最后一个关键帧图像应该匹配。", + "The algorithm is not able to enhance all images." : "本算法不能增强所有图像", + "The annotator directory inside the SAM extension directory is only a symbolic link. This is to save your space and make the extension repository clean." : "SAM 扩展目录中的解释器目录只是符号链接。这样能够节省你的硬盘空间,并使扩展库更加有序。", + "The beta1 parameter for the Adam optimizer." : "Adam 优化器的 beta1 参数", + "The beta2 parameter for the Adam optimizer." : "Adam 优化器的 beta2 参数", + "The Classifier-Free Guidance Scale to use for classifier/regularization images." : "用于分类/规范化图像的提示词引导系数(CFG Scale - 无分类器指导信息影响尺度(Classifier-Free Guidance Scale))", + "The code for this extension:" : "本插件的源代码链接:", + "The current workflow is [text prompt]->[object detection]->[segmentation]. Semantic segmentation support is in Auto SAM panel." : "目前的工作流是 [文本提示词]->[对象检测]->[语义分割]。语义分割支持在自动 SAM 面板中。", + "The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M" : "后两个模型的差值将叠加在主要模型上。需要输入 A、B、C 三个模型。计算公式为 A + (B - C) * M", + "The directory containing classification/regularization images." : "包含分类/规范化图像的目录", + "The directory containing training images." : "包含训练图像的目录", + "the directory in which your mask video is located." : "你所需要使用的视频蒙版路径", + "the directory / URL at which your video file is located for Video Input mode only" : "视频文件所在的目录/链接,仅适用于视频输入模式", + "The frames per second that the video will run at" : "你所需要的视频帧数", + "The generated file is a slugified version of the prompt and can be found in the same directory as the generated images.\nE.g. in ./outputs/txt2img-images/." : "生成的文件包含处理过的提示词,和生成的图像在同一目录\n例如 ./outputs/txt2img-images/", + "The height of the output images, in pixels (must be a multiple of 64)" : "输出图像的高度(像素)(必须能整除于 64)", + "The learning rate scheduler to use." : "要使用的学习率调度器", + "the maximum number of output images to be created" : "所需要生成的最大输出图像数", + "The model to train." : "要训练的模型", + "The name of the model to create." : "要创建的模型的名称", + "The number of steps to use when generating classifier/regularization images." : "生成分类/规范化图像时使用的步数", + "The official port of Deforum, an extensive script for 2D and 3D animations, supporting keyframable sequences, dynamic math parameters (even inside the prompts), dynamic masking, depth estimation and warping." : "Deforum 的官方移植,一个用于 2D 和 3D 动画的扩展脚本,支持关键帧序列、动态数学参数(甚至可用于提示词内)、动态蒙版、深度预测和变形", + "The other site allows for making keyframes using" : "另一方面,允许关键帧使用", + "the path to a custom settings file" : "自定义设置文件的路径", + "The path to the concepts JSON file, or a JSON string." : "储存概念的 JSON 文件的路径,或 JSON 字符串", + "the path to your init image" : "初始化图像的路径", + "the path to your mask image" : "蒙版文件的路径", + "the path/ URL to an audio file to accompany the video" : "视频附带的音频文件的路径 / 链接", + "The prompt to use when generating preview images." : "生成预览图像时使用的提示词", + "The rate at which the model learns. Default is 0.000005. Use a lower value like 0.000002 or 0.000001 for more complex subjects...like people." : "模型的学习速率。默认为 0.000005。对于更复杂的主体......比如人物,使用较低的值,如 0.000002 或 0.000001", + "There is *no* Batch mode like in vanilla deforum. Please Use the txt2img tab for that." : "本插件没有批处理模式,请使用文生图选项卡。", + "the required timestamp to reference when resuming. Currently only available in 2D & 3D mode, the timestamp is saved as the settings .txt file name as well as images produced during your previous run. The format follows: yyyymmddhhmmss - a timestamp of when the run was started to diffuse." : "重启开始时需要指定的时间戳。目前仅支持在 2D 和 3D模式中可用,该时间戳在中断之前的图像生成过程中所保存的 settings.txt 中。参数格式如下: yyyymmddhhmmss -开始运行本插件时会自动生成一个时间戳", + "The resolution of input images. You probably want to pre-process them to match this." : "输入图像的分辨率。你可能希望对它们进行预处理以匹配它", + "the roll effect angle" : "所旋转的角度(X轴,一般性指水平)", + "The seed to use when generating samples. Set to -1 to use a random seed every time." : "生成样本时使用的随机种子。设置为 -1 时每次都使用随机的种子", + "the seed value will increment by 1 for each subsequent frame of the animation" : "对于动画的每个后续帧,种子数将增加 1", + "the seed will remain fixed across all frames of animation" : "动画中所有帧的随机种子将被固定", + "The source checkpoint to extract for training." : "用于训练的要提取的源模型(ckpt)", + "the tilt effect angle" : "所翻转的垂直角度(Y轴)", + "The untranslated characters will be translated automatically and will not affect the old translations. Use the function in the lower right corner to easily check and quickly modify the current translation.1,Save the setting;2,Click start button;3,Reload your browser." : "未翻译的提示词将自动翻译,不会影响已翻译过的提示词。使用右下方的功能按钮可以快速检查和修改当前的翻译。1.保存设置;2.点击启动按钮;3.重载浏览器。", + "The URL to the model on huggingface. Should be in the format of 'developer/model_name'." : "huggingface 模型的 URL。应为 'developer/model_name' 的格式", + "The width of the output images, in pixels (must be a multiple of 64)" : "输出图像的宽度(像素,必须能整除于 64)", + "Thigh" : "大腿长度", + "Third column (reference) image" : "第三列 (参考) 图像", + "This extension works well with text captions in comma-separated style (such as the tags generated by DeepBooru interrogator)." : "使用以逗号分隔的描述会让插件更好的工作。(比如由 DeepBooru interrogator 生成的 tags)", + "This fork for auto1111's webui github.com/deforum-art/deforum-for-automatic1111-webui" : "此克隆用于 auto1111 的 webui github.com/deforum-art/deforum-for-automatic1111-webui", + "This is Extension for rewriting Inpainting conditioning mask strength value relative to Denoising strength at runtime. This is useful for Inpainting models such as sd-v1-5-inpainting.ckpt" : "这是在运行时重新实现的局部重绘图像调节蒙版强度(相对于重绘强度)的扩展。这对于局部重绘专用的模型(例如 sd-v1-5-inpainting.ckpt)很有用", + "This is your models list." : "这是您的模型列表", + "This mode works ONLY with 2D/3D animation modes. Interpolation and Video Input modes aren't supported." : "此模式仅适用于2D/3D动画模式。不支持帧插值和视频输入模式。", + "This preset affects?" : "该预设中包含?", + "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is." : "该正则表达式将用于从文件名中提取单词,并将它们合并到用于训练的标签文本中。留空以保持文件名文本不变。", + "This script is deprecated. Please use the full Deforum extension instead." : "此脚本已弃用。请改用完整的 Deforum 扩展", + "This SD extension allows you to turn posts from various image boorus into stable diffusion prompts. It does so by pulling a list of tags down from their API. You can copy-paste in a link to the post you want yourself, or use the built-in search feature to do it all without leaving SD." : "此扩展允许你将来自各种 booru 的图帖转换为提示词。它通过从对应的 API 中提取标签(tags)列表来实现。你可以自己复制粘贴你需要的图帖的链接,或者使用内置的搜索功能在不离开 webui 的情况下完成所有操作", + "This string will be used to join split words into a single line if the option above is enabled." : "如果启用了上述选项,则此处的字符会用于将拆分的单词接合为同一行", + "This text is used to rotate the feature space of the imgs embs" : "此文本用于旋转图集 Embeddings 的特征空间", + "This will produce one prompt for each colour in the wildcard.txt file." : "会为 colours.txt 中的每个颜色产生一条提示词", + "This will produce the following prompts:" : "会产生下列提示词", + "This will produce three prompts, one for each color. The prompt tag is used to mark the text that will be used as the prompt. If no prompt tag is present then only one prompt is assumed" : "会产生三条提示词,每个颜色各一条;\n prompt 标签用于标记作为提示词的文本;\n 如果没有 prompt 标签则默认为仅一条提示词", + "This will randomly choose one of the three colors." : "会随机从三种颜色中选一个", + "threshold" : "threshold (阈值)", + "Threshold" : "阈值", + "Threshold A" : "阈值A(此值根据预处理器选项不同发生变化,滑动条不可用时代表此预处理器无该项设置)", + "Threshold B" : "阈值B(此值根据预处理器选项不同发生变化,滑动条不可用时代表此预处理器无该项设置)", + "Thresholding Mode" : "阈值模式", + "Threshold schedule" : "阈值表", + "Threshold Value Lower" : "阈值下限", + "Threshold Value Upper" : "阈值上限", + "thumbs" : "缩略视图", + "tile division BG Removers" : "分块化背景去除", + "tile_gaussian" : "Tile_Gaussian(拼贴画模糊处理)", + "Tile overlap" : "图块重叠的像素(Tile overlap)", + "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam." : "ESRGAN 的图块重叠(Tile overlap)像素。较小时可见接缝", + "Tile overlap, in pixels for SwinIR. Low values = visible seam." : "SwinIR 的图块重叠(Tile overlap)像素。较小时可见接缝", + "tile_resample" : "tile_resample (分块重采样)", + "Tile size for all SwinIR." : "适用所有 SwinIR 系算法的图块尺寸 (Tile size)", + "Tile size for ESRGAN upscalers. 0 = no tiling." : "ESRGAN 使用的图块尺寸 (Tile size)。0 为不分块 (no tiling)", + "Tiling" : "平铺图 (Tiling)", + "Time" : "时间", + "Time in ms to wait before triggering completion again (Requires restart)" : "再次显示自动补全Tag的等待时间,以毫秒(ms)为单位(需要保存设置并重启UI)", + "timestamp" : "时间戳", + "Tips" : "小提示", + "title" : "标题", + "to" : " 调整至 ", + "To apply, go to quick set. Save now works immediately in other tab without restart, filters out non-common between tabs." : "要应用,请转到快速设置。现在保存可以立即在其他选项卡中工作,无需重新启动,过滤掉选项卡之间的不常见内容。", + "To enable, check use_mask in the Init tab" : "如果需要启用,请检查初始化选项卡中启用蒙版选项是否其启用", + "To enable seed schedule select seed behavior — 'schedule'" : "要启用种子调度,请选择随机种子行为——“调度”", + "to fix the issue." : "修复", + "to (full path)" : "到(输入完整路径)", + "Token" : "词元", + "Tokenize" : "词元拆分(Tokenize)", + "tokenizer" : "词元分析器(tokenizer)", + "Tokenizer" : "词元分析器(Tokenizer)", + "Token Length" : "Token 长度", + "Tokens" : "词元(Tokens)", + "To Language" : "目标语言", + "Tone Curve" : "色域曲线", + "Torch active: Peak amount of VRAM used by Torch during generation, excluding cached data.\nTorch reserved: Peak amount of VRAM allocated by Torch, including all active and cached data.\nSys VRAM: Peak amount of VRAM allocation across all applications / total GPU VRAM (peak utilization%)." : "Torch active: 在生成过程中,Torch使用的显存(VRAM)峰值,不包括缓存的数据。\nTorch reserved: Torch 分配的显存(VRAM)的峰值量,包括所有活动和缓存数据。\nSys VRAM: 所有应用程序分配的显存(VRAM)的峰值量 / GPU 的总显存(VRAM)(峰值利用率%)", + "to see which words are constructed using multiple sub-words, e.g. 'computer' doesn't exist in stable diffusion's CLIP dictionary and instead 'compu' and 'ter' are used (1 word but 2 embedding vectors). Currently buggy and needs a moment to process before pressing the button. If it doesn't work after a moment, try adding a random space to refresh it." : "查看哪些词是使用多个子词构成的,例如 Stable Diffusion 的 CLIP 字典中不存在 'computer',而是使用 'compu' 以及 'ter'(1 个单词但使用 2 个 Embedding 向量)。目前这个扩展还有点问题,在按下按钮之前需要一点时间来处理。如果过了一会还是不行,试试随便加个空格刷新一下", + "to see which words are constructed using multiple sub-words, e.g. 'computer' doesn't exist in stable diffusion's CLIP dictionary and instead 'compu' and 'ter' are used (1 word but 2 Embedding vectors). Currently buggy and needs a moment to process before pressing the button. If it doesn't work after a moment, try adding a random space to refresh it." : "查看哪些词是使用多个子词构成的,例如 Stable Diffusion 的 CLIP 字典中不存在 'computer',而是使用 'compu' 以及 'ter'(1 个单词但使用 2 个 Embedding 向量)。目前这个扩展还有点问题,在按下按钮之前需要一点时间来处理。如果过了一会还是不行,试试随便加个空格刷新一下", + "to share your creations and suggestions." : "分享你的创意和建议", + "(Total)" : "(合计)", + "Total Images" : "总图像数量", + "Total number of classification images to use. Set to 0 to disable." : "要使用的分类(classification)图像总数。设置为 0 以禁用", + "Total number of classification/regularization images to use. If no images exist, they will be generated. Set to 0 to disable prior preservation." : "要使用的分类/规范化图像总数。如果没有图像,就生成一些。设置为 0 以禁用先验存留(prior preservation)", + "Total Number of Class/Reg Images" : "用于分类/规范化的图像总数", + "Total number of training steps to perform. If provided, overrides num_train_epochs." : "要执行的训练迭代步数总数。如果填了,则覆盖 '训练多少期(num_train_epochs)'", + "Towards Controllable One-Shot Text-to-Image Generation via Contrastive Prompt-Tuning." : "通过对比调整提示词,实现可控的单发文本到图像生成", + "Traditional Chinese localization" : "正體中文本地化", + "Train" : "训练", + "Train an embedding; must specify a directory with a set of 1:1 ratio images" : "训练 Embedding; 必须指定一组具有 1:1 比例图像的目录", + "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images" : "训练嵌入式或超网络模型;必须指定一个具有一组 1:1 宽高比图像的数据集目录", + "Train EMA" : "训练 EMA", + "Train Embedding" : "训练嵌入式模型", + "Train Hypernetwork" : "训练超网络模型", + "training" : "训练相关", + "Training" : "训练", + "# Training Epochs" : "训练多少期(Epochs)", + "Training Epochs" : "训练多少期(Epochs)", + "Training info" : "训练信息", + "Training parameters" : "训练参数", + "training-picker" : "训练图挑选器", + "Training Picker" : "训练图挑选器", + "Training steps" : "训练迭代步数", + "Training Steps" : "训练迭代步数", + "Training Wizard (Object/Style)" : "训练配置器 (物件/风格)", + "Training Wizard (Person)" : "训练配置器 (人物)", + "Train Model" : "训练模型", + "Train multiple concepts from a JSON file or string." : "从 JSON 文件或字符串训练多个概念", + "Train Text Encoder" : "训练文本编码器", + "Train with DreamArtist" : "使用梦作家训练", + "Train with reconstruction" : "训练时开启重建", + "Trajectory" : "轨迹", + "Transform Center X" : "旋转中心点 X 轴", + "Transform Center Y" : "旋转中心点 Y 轴", + "Transformer" : "变换器", + "translate" : "翻译", + "Translate" : "翻译", + "translated fail:" : "翻译失败:", + "Translated Negative Prompt" : "反向提示词翻译", + "Translated Prompt" : "提示词翻译", + "Translated Status" : "翻译状态", + "translated text" : "翻译后文本", + "Translate Negative Prompt" : "翻译反向提示词", + "Translate Prompt" : "翻译提示词", + "Translate: x, y, z" : "平移:x, y, z", + "Translation display order" : "翻译显示顺序", + "Translation filename" : "翻译文件名", + "Translation file uses old 3-column translation format instead of the new 2-column one" : "翻译文件使用旧的三栏式翻译格式,而不是新的二栏式格式", + "Translation First" : "译文在上", + "Translation Service Setting" : "翻译服务设置", + "Translation X" : "平移 X", + "Translation Y" : "平移 Y", + "Translation Z" : "平移 Z", + "Transparent" : "透明", + "Travel mode" : "变迁模式", + "Travel steps between stages" : "每个阶段变迁的迭代步数", + "Triple sum:A*(1-alpha-beta)+B*alpha+C*beta" : "三重加权和: A*(1-α-β)+B*α+C*β", + "Truncate tags by token count" : "通过 token 计数截断标签", + "Truncate tags by token count." : "按 token 计数截断 tags", + "Turn on pin_memory for DataLoader. Makes training slightly faster but can increase memory usage." : "为数据加载器 (DataLoader) 启用 pin_memory 参数,以提升内存占用的代价提高训练速度", + "turn_page_switch" : "翻页开关", + "Turn the depthmap into absolute black/white" : "转换深度图为纯黑或纯白", + "Tweening frames schedule" : "中间计算帧参数表", + "txt2img" : "文生图", + "txt2img-grids" : "文生图 (网格)", + "txt2img history" : "文生图历史记录", + "txt2img/img2img UI item order" : "文生图/图生图界面参数组件顺序", + "Type" : "类型", + "UI related" : "UI 界面相关", + "ui text" : "UI文本", + "Uncheck all copies" : "取消勾选所有选择", + "U-Net features" : "U-Net 特征值", + "UNet Weight 1" : "UNet 权重 1", + "UNet Weight 2" : "UNet 权重 2", + "UNet Weight 3" : "UNet 权重 3", + "UNet Weight 4" : "UNet 权重 4", + "UNet Weight 5" : "UNet 权重 5", + "Unfreeze Model" : "解冻模型", + "Unfreeze seed" : "不固定种子", + "uniform" : "均匀", + "UniPC order (must be < sampling steps)" : "UniPC 的预测校正次数 (需小于采样步数)", + "UniPC skip type" : "UniPC 跳过类型", + "UniPC variant" : "UniPC 变体", + "unknown" : "未知", + "Unlink seed from prompt" : "将随机种子与提示词解绑", + "Unload all interrogate models" : "卸载所有反推模型", + "Unload all models from memory" : "从内存中卸载所有模型", + "unload model" : "卸载模型", + "Unload model after running" : "反推完成后卸载模型", + "Unload models" : "卸载模型", + "Unload SD checkpoint to free VRAM" : "卸载 Stable Diffusion 模型以释放显存", + "Unload VAE and CLIP from VRAM when training" : "训练时从显存(VRAM)中取消 VAE 和 CLIP 的加载", + "unprompted" : "非文本(代码化)提示词", + "Unprompted" : "非文本(代码化)提示词", + "up" : "上", + "Upcast cross attention layer to float32" : "将交叉关注层向上转换到 float32", + "Update" : "更新", + "Update directory names in database" : "更新数据库中的文件夹名字", + "Update instructions:" : "更新指引(英文):", + "update list" : "更新列表", + "Update Mask" : "更新蒙版", + "uploaded video FPS" : "上传视频的帧率", + "uploaded video resolution" : "上传视频的分辨率", + "uploaded video total frame count" : "上传视频的总帧数", + "Upload mask" : "上传蒙版", + "Upload prompt inputs" : "上传提示词输入文件", + "Upper Arm" : "上臂长度", + "Upscale" : "图像放大", + "Upscale and Resize" : "放大并调整大小", + "Upscale Before Restoring Faces" : "放大后再进行面部修复", + "Upscale by" : "放大倍数", + "Upscale factor" : "放大比率", + "Upscale height" : "放大高度", + "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back" : "正常放大图像,将结果分割成图块(tiles),用图生图改进每个图块,最后将整个图像合并回来", + "Upscale latent space image when doing hires. fix" : "做高分辨率修复时,也放大潜空间图像", + "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image" : "将蒙版区域(包括预留像素长度的缓冲区域)放大到目标分辨率,进行局部重绘。\n然后缩小并粘贴回原始图像中", + "Upscale model" : "超分模型", + "Upscaler" : "放大算法", + "Upscaler 1" : "放大算法 1", + "Upscaler 2" : "放大算法 2", + "Upscaler 2 visibility" : "放大算法 2 强度", + "Upscale ratio" : "放大倍率", + "Upscale Ratio" : "放大比例", + "Upscaler for img2img" : "图生图放大算法", + "*Upscale uploaded video*" : "*超分已上传的视频*", + "Upscale width" : "放大宽度", + "Upscaling" : "图片放大", + "URL" : "网址", + "URL for extension's git repository" : "扩展的 git 仓库网址", + "Uscale the image in latent space. Alternative is to produce the full image from latent representation, upscale that, and then move it back to latent space." : "放大潜空间中的图像。而另一种方法是,从潜变量表达中直接解码并生成完整的图像,接着放大它,然后再将其编码回潜空间", + "Use" : "使用", + "Use 8bit Adam" : "使用 8bit Adam", + "Use alpha as mask" : "启用透明度蒙版", + "Use an" : "使用一个", + "Use an empty output directory to save pictures normally instead of writing to the output directory." : "输出图像到一个空目录,而非设置里指定的输出目录", + "Use another image as ControlNet input" : "使用另外的图像输入 ControlNet", + "Use another image as mask" : "使用另外的图像作为遮罩", + "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition" : "首先以较小的分辨率生成初步图像,接着放大图像,然后在不更改构图的情况下改进其中的细节", + "Use base prompt" : "使用基础提示词(Base Prompt)", + "Use batch input directory as image source" : "使用文件目录批量导入图像源", + "Use BLIP for caption" : "使用 BLIP 生成标签 (自然语言)", + "Use common negative prompt" : "使用常见反面提示词(Common Negative Prompt)", + "Use common prompt" : "使用常见提示词(Common Prompt)", + "Use Concepts List" : "使用概念列表", + "Use Control Net inpaint model" : "使用 ControlNet 的 inpait 模型", + "Use CPU Only (SLOW)" : "只用 CPU (很慢)", + "Use cross attention optimizations while training" : "训练时开启 Cross Attention 优化", + "Use custom colors" : "使用自定义颜色", + "Use Custom Threshold (Booru)" : "使用自定义阈值 (Booru)", + "Use Custom Threshold (WDv1.4 Tagger)" : "使用自定义阈值 (WDv1.4 Tagger)", + "Use deepbooru for caption" : "使用 Deepbooru 生成标签", + "Use delta values for movement parameters" : "使用增量值作为运动参数", + "Use different seed for each picture" : "为每张图片使用不同随机种子", + "Use dropdown for sampler selection instead of radio group" : "采样器列表处使用下拉菜单取代单选框", + "Use dropout" : "使用 dropout", + "Use EMA for finetuning" : "使用 EMA 进行微调", + "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime], [datetime