Merge branch 'AUTOMATIC1111:master' into adjust-ddim-uniform-steps

This commit is contained in:
Martin Cairns 2022-11-01 08:34:39 +00:00 committed by GitHub
commit b88505925b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1666 additions and 1102 deletions

35
javascript/extensions.js Normal file
View file

@ -0,0 +1,35 @@
function extensions_apply(_, _){
disable = []
update = []
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
if(x.name.startsWith("enable_") && ! x.checked)
disable.push(x.name.substr(7))
if(x.name.startsWith("update_") && x.checked)
update.push(x.name.substr(7))
})
restart_reload()
return [JSON.stringify(disable), JSON.stringify(update)]
}
function extensions_check(){
gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
x.innerHTML = "Loading..."
})
return []
}
function install_extension_from_index(button, url){
button.disabled = "disabled"
button.value = "Installing..."
textarea = gradioApp().querySelector('#extension_to_install textarea')
textarea.value = url
textarea.dispatchEvent(new Event("input", { bubbles: true }))
gradioApp().querySelector('#install_extension_button').click()
}

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
" images in this directory. Loaded ": "개의 이미지가 이 경로에 존재합니다. ", " images in this directory. Loaded ": "개의 이미지가 이 경로에 존재합니다. ",
" pages": "페이지로 나뉘어 표시합니다.", " pages": "페이지로 나뉘어 표시합니다.",
", divided into ": "입니다. ", ", divided into ": "입니다. ",
". Use Installed tab to restart.": "에 성공적으로 설치하였습니다. 설치된 확장기능 탭에서 UI를 재시작해주세요.",
"1st and last digit must be 1. ex:'1, 2, 1'": "1st and last digit must be 1. ex:'1, 2, 1'", "1st and last digit must be 1. ex:'1, 2, 1'": "1st and last digit must be 1. ex:'1, 2, 1'",
"[wiki]": " [위키] 참조", "[wiki]": " [위키] 참조",
"A directory on the same machine where the server is running.": "WebUI 서버가 돌아가고 있는 디바이스에 존재하는 디렉토리를 선택해 주세요.", "A directory on the same machine where the server is running.": "WebUI 서버가 돌아가고 있는 디바이스에 존재하는 디렉토리를 선택해 주세요.",
@ -33,22 +34,28 @@
"Always save all generated images": "생성된 이미지 항상 저장하기", "Always save all generated images": "생성된 이미지 항상 저장하기",
"api": "", "api": "",
"append": "뒤에 삽입", "append": "뒤에 삽입",
"Append commas": "쉼표 삽입",
"Apply and restart UI": "적용 후 UI 재시작",
"Apply color correction to img2img results to match original colors.": "이미지→이미지 결과물이 기존 색상과 일치하도록 색상 보정 적용하기", "Apply color correction to img2img results to match original colors.": "이미지→이미지 결과물이 기존 색상과 일치하도록 색상 보정 적용하기",
"Apply selected styles to current prompt": "현재 프롬프트에 선택된 스타일 적용", "Apply selected styles to current prompt": "현재 프롬프트에 선택된 스타일 적용",
"Apply settings": "설정 적용하기", "Apply settings": "설정 적용하기",
"Auto focal point crop": "초점 기준 크롭(자동 감지)", "Auto focal point crop": "초점 기준 크롭(자동 감지)",
"Autocomplete options": "자동완성 설정",
"Batch count": "배치 수", "Batch count": "배치 수",
"Batch from Directory": "저장 경로로부터 여러장 처리", "Batch from Directory": "저장 경로로부터 여러장 처리",
"Batch img2img": "이미지→이미지 배치", "Batch img2img": "이미지→이미지 배치",
"Batch Process": "이미지 여러장 처리", "Batch Process": "이미지 여러장 처리",
"Batch size": "배치 크기", "Batch size": "배치 크기",
"behind": "최신 아님",
"BSRGAN 4x": "BSRGAN 4x", "BSRGAN 4x": "BSRGAN 4x",
"built with gradio": "gradio로 제작되었습니다", "built with gradio": "gradio로 제작되었습니다",
"Cancel generate forever": "반복 생성 취소", "Cancel generate forever": "반복 생성 취소",
"cfg cnt": "CFG 변화 횟수",
"cfg count": "CFG 변화 횟수", "cfg count": "CFG 변화 횟수",
"CFG Scale": "CFG 스케일", "CFG Scale": "CFG 스케일",
"cfg1 min/max": "CFG1 최소/최대", "cfg1 min/max": "CFG1 최소/최대",
"cfg2 min/max": "CFG2 최소/최대", "cfg2 min/max": "CFG2 최소/최대",
"Check for updates": "업데이트 확인",
"Check progress": "진행도 체크", "Check progress": "진행도 체크",
"Check progress (first)": "진행도 체크 (처음)", "Check progress (first)": "진행도 체크 (처음)",
"checkpoint": " 체크포인트 ", "checkpoint": " 체크포인트 ",
@ -64,6 +71,9 @@
"CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "CodeFormer 가중치 설정값 (0 = 최대 효과, 1 = 최소 효과)", "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "CodeFormer 가중치 설정값 (0 = 최대 효과, 1 = 최소 효과)",
"Collect": "즐겨찾기", "Collect": "즐겨찾기",
"Color variation": "색깔 다양성", "Color variation": "색깔 다양성",
"Combinations": "조합",
"Combinatorial batches": "조합 배치 수",
"Combinatorial generation": "조합 생성",
"copy": "복사", "copy": "복사",
"Create a grid where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows": "서로 다른 설정값으로 생성된 이미지의 그리드를 만듭니다. 아래의 설정으로 가로/세로에 어떤 설정값을 적용할지 선택하세요.", "Create a grid where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows": "서로 다른 설정값으로 생성된 이미지의 그리드를 만듭니다. 아래의 설정으로 가로/세로에 어떤 설정값을 적용할지 선택하세요.",
"Create a text file next to every image with generation parameters.": "생성된 이미지마다 생성 설정값을 담은 텍스트 파일 생성하기", "Create a text file next to every image with generation parameters.": "생성된 이미지마다 생성 설정값을 담은 텍스트 파일 생성하기",
@ -78,10 +88,12 @@
"custom fold": "커스텀 경로", "custom fold": "커스텀 경로",
"Custom Name (Optional)": "병합 모델 이름 (선택사항)", "Custom Name (Optional)": "병합 모델 이름 (선택사항)",
"Dataset directory": "데이터셋 경로", "Dataset directory": "데이터셋 경로",
"date": "생성 일자",
"DDIM": "DDIM", "DDIM": "DDIM",
"Decode CFG scale": "디코딩 CFG 스케일", "Decode CFG scale": "디코딩 CFG 스케일",
"Decode steps": "디코딩 스텝 수", "Decode steps": "디코딩 스텝 수",
"Delete": "삭제", "Delete": "삭제",
"delete next": "선택한 이미지부터 시작해서 삭제할 이미지 갯수",
"Denoising": "디노이징", "Denoising": "디노이징",
"Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models - 인페이팅에 뛰어남", "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models - 인페이팅에 뛰어남",
"Denoising strength": "디노이즈 강도", "Denoising strength": "디노이즈 강도",
@ -108,6 +120,7 @@
"Draw mask": "마스크 직접 그리기", "Draw mask": "마스크 직접 그리기",
"Drop File Here": "파일을 끌어 놓으세요", "Drop File Here": "파일을 끌어 놓으세요",
"Drop Image Here": "이미지를 끌어 놓으세요", "Drop Image Here": "이미지를 끌어 놓으세요",
"Dropdown": "드롭다운",
"Embedding": "임베딩", "Embedding": "임베딩",
"Embedding Learning rate": "임베딩 학습률", "Embedding Learning rate": "임베딩 학습률",
"Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "강조 : (텍스트)를 이용해 모델의 텍스트에 대한 가중치를 더 강하게 주고 [텍스트]를 이용해 더 약하게 줍니다.", "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "강조 : (텍스트)를 이용해 모델의 텍스트에 대한 가중치를 더 강하게 주고 [텍스트]를 이용해 더 약하게 줍니다.",
@ -127,6 +140,8 @@
"Euler a": "Euler a", "Euler a": "Euler a",
"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보다 높은 스텝 수는 효과가 미미함", "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보다 높은 스텝 수는 효과가 미미함",
"Existing Caption txt Action": "이미 존재하는 캡션 텍스트 처리", "Existing Caption txt Action": "이미 존재하는 캡션 텍스트 처리",
"Extension": "확장기능",
"Extensions": "확장기능",
"Extra": "고급", "Extra": "고급",
"Extras": "부가기능", "Extras": "부가기능",
"extras": "부가기능", "extras": "부가기능",
@ -134,7 +149,7 @@
"Face restoration": "얼굴 보정", "Face restoration": "얼굴 보정",
"Face restoration model": "얼굴 보정 모델", "Face restoration model": "얼굴 보정 모델",
"Fall-off exponent (lower=higher detail)": "감쇠 지수 (낮을수록 디테일이 올라감)", "Fall-off exponent (lower=higher detail)": "감쇠 지수 (낮을수록 디테일이 올라감)",
"favorites": "즐겨찾기", "Favorites": "즐겨찾기",
"File": "파일", "File": "파일",
"File format for grids": "그리드 이미지 파일 형식", "File format for grids": "그리드 이미지 파일 형식",
"File format for images": "이미지 파일 형식", "File format for images": "이미지 파일 형식",
@ -150,6 +165,7 @@
"First Page": "처음 페이지", "First Page": "처음 페이지",
"Firstpass height": "초기 세로길이", "Firstpass height": "초기 세로길이",
"Firstpass width": "초기 가로길이", "Firstpass width": "초기 가로길이",
"Fixed seed": "시드 고정",
"Focal point edges weight": "경계면 가중치", "Focal point edges weight": "경계면 가중치",
"Focal point entropy weight": "엔트로피 가중치", "Focal point entropy weight": "엔트로피 가중치",
"Focal point face weight": "얼굴 가중치", "Focal point face weight": "얼굴 가중치",
@ -186,6 +202,7 @@
"Image Browser": "이미지 브라우저", "Image Browser": "이미지 브라우저",
"Image for img2img": "Image for img2img", "Image for img2img": "Image for img2img",
"Image for inpainting with mask": "마스크로 인페인팅할 이미지", "Image for inpainting with mask": "마스크로 인페인팅할 이미지",
"Image not found (may have been already moved)": "이미지를 찾을 수 없습니다 (이미 옮겨졌을 수 있음)",
"Images Browser": "이미지 브라우저", "Images Browser": "이미지 브라우저",
"Images directory": "이미지 경로", "Images directory": "이미지 경로",
"Images filename pattern": "이미지 파일명 패턴", "Images filename pattern": "이미지 파일명 패턴",
@ -205,6 +222,10 @@
"Inpainting conditioning mask strength": "인페인팅 조절 마스크 강도", "Inpainting conditioning mask strength": "인페인팅 조절 마스크 강도",
"Input directory": "인풋 이미지 경로", "Input directory": "인풋 이미지 경로",
"Input images directory": "이미지 경로 입력", "Input images directory": "이미지 경로 입력",
"Install": "설치",
"Install from URL": "URL로부터 확장기능 설치",
"Installed": "설치된 확장기능",
"Installed into ": "확장기능을 ",
"Interpolation Method": "보간 방법", "Interpolation Method": "보간 방법",
"Interrogate\nCLIP": "CLIP\n분석", "Interrogate\nCLIP": "CLIP\n분석",
"Interrogate\nDeepBooru": "DeepBooru\n분석", "Interrogate\nDeepBooru": "DeepBooru\n분석",
@ -223,6 +244,7 @@
"Just resize": "리사이징", "Just resize": "리사이징",
"Keep -1 for seeds": "시드값 -1로 유지", "Keep -1 for seeds": "시드값 -1로 유지",
"keep whatever was there originally": "이미지 원본 유지", "keep whatever was there originally": "이미지 원본 유지",
"keyword": "프롬프트",
"Label": "라벨", "Label": "라벨",
"Lanczos": "Lanczos", "Lanczos": "Lanczos",
"Last prompt:": "마지막 프롬프트 : ", "Last prompt:": "마지막 프롬프트 : ",
@ -230,10 +252,12 @@
"Last saved image:": "마지막으로 저장된 이미지 : ", "Last saved image:": "마지막으로 저장된 이미지 : ",
"latent noise": "잠재 노이즈", "latent noise": "잠재 노이즈",
"latent nothing": "잠재 공백", "latent nothing": "잠재 공백",
"latest": "최신 버전",
"LDSR": "LDSR", "LDSR": "LDSR",
"LDSR processing steps. Lower = faster": "LDSR 스텝 수. 낮은 값 = 빠른 속도", "LDSR processing steps. Lower = faster": "LDSR 스텝 수. 낮은 값 = 빠른 속도",
"leakyrelu": "leakyrelu", "leakyrelu": "leakyrelu",
"Leave blank to save images to the default path.": "기존 저장 경로에 이미지들을 저장하려면 비워두세요.", "Leave blank to save images to the default path.": "기존 저장 경로에 이미지들을 저장하려면 비워두세요.",
"Leave empty for auto": "자동 설정하려면 비워두십시오",
"left": "왼쪽", "left": "왼쪽",
"linear": "linear", "linear": "linear",
"List of prompt inputs": "프롬프트 입력 리스트", "List of prompt inputs": "프롬프트 입력 리스트",
@ -242,11 +266,13 @@
"LMS Karras": "LMS Karras", "LMS Karras": "LMS Karras",
"Load": "불러오기", "Load": "불러오기",
"Loading...": "로딩 중...", "Loading...": "로딩 중...",
"Local directory name": "로컬 경로 이름",
"Localization (requires restart)": "현지화 (재시작 필요)", "Localization (requires restart)": "현지화 (재시작 필요)",
"Log directory": "로그 경로", "Log directory": "로그 경로",
"Loopback": "루프백", "Loopback": "루프백",
"Loops": "루프 수", "Loops": "루프 수",
"Loss:": "손실(Loss) : ", "Loss:": "손실(Loss) : ",
"Magic prompt": "매직 프롬프트",
"Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "동일한 시드 값으로 생성되었을 이미지를 주어진 해상도로 최대한 유사하게 재현합니다.", "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "동일한 시드 값으로 생성되었을 이미지를 주어진 해상도로 최대한 유사하게 재현합니다.",
"Make K-diffusion samplers produce same images in a batch as when making a single image": "K-diffusion 샘플러들이 단일 이미지를 생성하는 것처럼 배치에서도 동일한 이미지를 생성하게 하기", "Make K-diffusion samplers produce same images in a batch as when making a single image": "K-diffusion 샘플러들이 단일 이미지를 생성하는 것처럼 배치에서도 동일한 이미지를 생성하게 하기",
"Make Zip when Save?": "저장 시 Zip 생성하기", "Make Zip when Save?": "저장 시 Zip 생성하기",
@ -260,7 +286,9 @@
"Minimum number of pages per load": "한번 불러올 때마다 불러올 최소 페이지 수", "Minimum number of pages per load": "한번 불러올 때마다 불러올 최소 페이지 수",
"Modules": "모듈", "Modules": "모듈",
"Move face restoration model from VRAM into RAM after processing": "처리가 완료되면 얼굴 보정 모델을 VRAM에서 RAM으로 옮기기", "Move face restoration model from VRAM into RAM after processing": "처리가 완료되면 얼굴 보정 모델을 VRAM에서 RAM으로 옮기기",
"Move to favorites": "즐겨찾기로 옮기기",
"Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "하이퍼네트워크 훈련 진행 시 VAE와 CLIP을 RAM으로 옮기기. VRAM이 절약됩니다.", "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "하이퍼네트워크 훈련 진행 시 VAE와 CLIP을 RAM으로 옮기기. VRAM이 절약됩니다.",
"Moved to favorites": "즐겨찾기로 옮겨짐",
"Multiplier (M) - set to 0 to get model A": "배율 (M) - 0으로 적용하면 모델 A를 얻게 됩니다", "Multiplier (M) - set to 0 to get model A": "배율 (M) - 0으로 적용하면 모델 A를 얻게 됩니다",
"Name": "이름", "Name": "이름",
"Negative prompt": "네거티브 프롬프트", "Negative prompt": "네거티브 프롬프트",
@ -285,6 +313,7 @@
"original": "원본 유지", "original": "원본 유지",
"Original negative prompt": "기존 네거티브 프롬프트", "Original negative prompt": "기존 네거티브 프롬프트",
"Original prompt": "기존 프롬프트", "Original prompt": "기존 프롬프트",
"Others": "기타",
"Outpainting direction": "아웃페인팅 방향", "Outpainting direction": "아웃페인팅 방향",
"Outpainting mk2": "아웃페인팅 마크 2", "Outpainting mk2": "아웃페인팅 마크 2",
"Output directory": "이미지 저장 경로", "Output directory": "이미지 저장 경로",
@ -303,6 +332,7 @@
"Overwrite Old Hypernetwork": "기존 하이퍼네트워크 덮어쓰기", "Overwrite Old Hypernetwork": "기존 하이퍼네트워크 덮어쓰기",
"Page Index": "페이지 인덱스", "Page Index": "페이지 인덱스",
"parameters": "설정값", "parameters": "설정값",
"path name": "경로 이름",
"Path to directory where to write outputs": "결과물을 출력할 경로", "Path to directory where to write outputs": "결과물을 출력할 경로",
"Path to directory with input images": "인풋 이미지가 있는 경로", "Path to directory with input images": "인풋 이미지가 있는 경로",
"Paths for saving": "저장 경로", "Paths for saving": "저장 경로",
@ -424,6 +454,7 @@
"Skip": "건너뛰기", "Skip": "건너뛰기",
"Slerp angle": "구면 선형 보간 각도", "Slerp angle": "구면 선형 보간 각도",
"Slerp interpolation": "구면 선형 보간", "Slerp interpolation": "구면 선형 보간",
"sort by": "정렬 기준",
"Source": "원본", "Source": "원본",
"Source directory": "원본 경로", "Source directory": "원본 경로",
"Split image overlap ratio": "이미지 분할 겹침 비율", "Split image overlap ratio": "이미지 분할 겹침 비율",
@ -431,6 +462,7 @@
"Split oversized images": "사이즈가 큰 이미지 분할하기", "Split oversized images": "사이즈가 큰 이미지 분할하기",
"Stable Diffusion": "Stable Diffusion", "Stable Diffusion": "Stable Diffusion",
"Stable Diffusion checkpoint": "Stable Diffusion 체크포인트", "Stable Diffusion checkpoint": "Stable Diffusion 체크포인트",
"step cnt": "스텝 변화 횟수",
"step count": "스텝 변화 횟수", "step count": "스텝 변화 횟수",
"step1 min/max": "스텝1 최소/최대", "step1 min/max": "스텝1 최소/최대",
"step2 min/max": "스텝2 최소/최대", "step2 min/max": "스텝2 최소/최대",
@ -467,7 +499,9 @@
"txt2img": "텍스트→이미지", "txt2img": "텍스트→이미지",
"txt2img history": "텍스트→이미지 기록", "txt2img history": "텍스트→이미지 기록",
"uniform": "uniform", "uniform": "uniform",
"unknown": "알수 없음",
"up": "위쪽", "up": "위쪽",
"Update": "업데이트",
"Upload mask": "마스크 업로드하기", "Upload mask": "마스크 업로드하기",
"Upload prompt inputs": "입력할 프롬프트를 업로드하십시오", "Upload prompt inputs": "입력할 프롬프트를 업로드하십시오",
"Upscale Before Restoring Faces": "얼굴 보정을 진행하기 전에 업스케일링 먼저 진행하기", "Upscale Before Restoring Faces": "얼굴 보정을 진행하기 전에 업스케일링 먼저 진행하기",
@ -479,9 +513,12 @@
"Upscaler 2 visibility": "업스케일러 2 가시성", "Upscaler 2 visibility": "업스케일러 2 가시성",
"Upscaler for img2img": "이미지→이미지 업스케일러", "Upscaler for img2img": "이미지→이미지 업스케일러",
"Upscaling": "업스케일링", "Upscaling": "업스케일링",
"URL for extension's git repository": "확장기능의 git 레포 URL",
"Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "저해상도 이미지를 1차적으로 생성 후 업스케일을 진행하여, 이미지의 전체적인 구성을 바꾸지 않고 세부적인 디테일을 향상시킵니다.", "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "저해상도 이미지를 1차적으로 생성 후 업스케일을 진행하여, 이미지의 전체적인 구성을 바꾸지 않고 세부적인 디테일을 향상시킵니다.",
"Use an empty output directory to save pictures normally instead of writing to the output directory.": "저장 경로를 비워두면 기본 저장 폴더에 이미지들이 저장됩니다.", "Use an empty output directory to save pictures normally instead of writing to the output directory.": "저장 경로를 비워두면 기본 저장 폴더에 이미지들이 저장됩니다.",
"Use BLIP for caption": "캡션에 BLIP 사용", "Use BLIP for caption": "캡션에 BLIP 사용",
"Use checkbox to enable the extension; it will be enabled or disabled when you click apply button": "체크박스를 이용해 적용할 확장기능을 선택하세요. 변경사항은 적용 후 UI 재시작 버튼을 눌러야 적용됩니다.",
"Use checkbox to mark the extension for update; it will be updated when you click apply button": "체크박스를 이용해 업데이트할 확장기능을 선택하세요. 업데이트는 적용 후 UI 재시작 버튼을 눌러야 적용됩니다.",
"Use deepbooru for caption": "캡션에 deepbooru 사용", "Use deepbooru for caption": "캡션에 deepbooru 사용",
"Use dropout": "드롭아웃 사용", "Use dropout": "드롭아웃 사용",
"Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "다음 태그들을 사용해 이미지 파일명 형식을 결정하세요 : [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]. 비워두면 기본값으로 설정됩니다.", "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "다음 태그들을 사용해 이미지 파일명 형식을 결정하세요 : [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]. 비워두면 기본값으로 설정됩니다.",

83
modules/extensions.py Normal file
View file

@ -0,0 +1,83 @@
import os
import sys
import traceback
import git
from modules import paths, shared
extensions = []
extensions_dir = os.path.join(paths.script_path, "extensions")
def active():
return [x for x in extensions if x.enabled]
class Extension:
def __init__(self, name, path, enabled=True):
self.name = name
self.path = path
self.enabled = enabled
self.status = ''
self.can_update = False
repo = None
try:
if os.path.exists(os.path.join(path, ".git")):
repo = git.Repo(path)
except Exception:
print(f"Error reading github repository info from {path}:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
if repo is None or repo.bare:
self.remote = None
else:
self.remote = next(repo.remote().urls, None)
self.status = 'unknown'
def list_files(self, subdir, extension):
from modules import scripts
dirpath = os.path.join(self.path, subdir)
if not os.path.isdir(dirpath):
return []
res = []
for filename in sorted(os.listdir(dirpath)):
res.append(scripts.ScriptFile(self.path, filename, os.path.join(dirpath, filename)))
res = [x for x in res if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
return res
def check_updates(self):
repo = git.Repo(self.path)
for fetch in repo.remote().fetch("--dry-run"):
if fetch.flags != fetch.HEAD_UPTODATE:
self.can_update = True
self.status = "behind"
return
self.can_update = False
self.status = "latest"
def pull(self):
repo = git.Repo(self.path)
repo.remotes.origin.pull()
def list_extensions():
extensions.clear()
if not os.path.isdir(extensions_dir):
return
for dirname in sorted(os.listdir(extensions_dir)):
path = os.path.join(extensions_dir, dirname)
if not os.path.isdir(path):
continue
extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions)
extensions.append(extension)

View file

@ -17,6 +17,11 @@ paste_fields = {}
bind_list = [] bind_list = []
def reset():
paste_fields.clear()
bind_list.clear()
def quote(text): def quote(text):
if ',' not in str(text): if ',' not in str(text):
return text return text

View file

@ -7,7 +7,7 @@ import modules.ui as ui
import gradio as gr import gradio as gr
from modules.processing import StableDiffusionProcessing from modules.processing import StableDiffusionProcessing
from modules import shared, paths, script_callbacks from modules import shared, paths, script_callbacks, extensions
AlwaysVisible = object() AlwaysVisible = object()
@ -107,17 +107,8 @@ def list_scripts(scriptdirname, extension):
for filename in sorted(os.listdir(basedir)): for filename in sorted(os.listdir(basedir)):
scripts_list.append(ScriptFile(paths.script_path, filename, os.path.join(basedir, filename))) scripts_list.append(ScriptFile(paths.script_path, filename, os.path.join(basedir, filename)))
extdir = os.path.join(paths.script_path, "extensions") for ext in extensions.active():
if os.path.exists(extdir): scripts_list += ext.list_files(scriptdirname, extension)
for dirname in sorted(os.listdir(extdir)):
dirpath = os.path.join(extdir, dirname)
scriptdirpath = os.path.join(dirpath, scriptdirname)
if not os.path.isdir(scriptdirpath):
continue
for filename in sorted(os.listdir(scriptdirpath)):
scripts_list.append(ScriptFile(dirpath, filename, os.path.join(scriptdirpath, filename)))
scripts_list = [x for x in scripts_list if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)] scripts_list = [x for x in scripts_list if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
@ -127,11 +118,7 @@ def list_scripts(scriptdirname, extension):
def list_files_with_name(filename): def list_files_with_name(filename):
res = [] res = []
dirs = [paths.script_path] dirs = [paths.script_path] + [ext.path for ext in extensions.active()]
extdir = os.path.join(paths.script_path, "extensions")
if os.path.exists(extdir):
dirs += [os.path.join(extdir, d) for d in sorted(os.listdir(extdir))]
for dirpath in dirs: for dirpath in dirs:
if not os.path.isdir(dirpath): if not os.path.isdir(dirpath):

View file

@ -40,7 +40,7 @@ parser.add_argument("--lowram", action='store_true', help="load stable diffusion
parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram") parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram")
parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.")
parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast")
parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site (doesn't work for me but you might have better luck)") parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site")
parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None) parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None)
parser.add_argument("--ngrok-region", type=str, help="The region in which ngrok should start.", default="us") parser.add_argument("--ngrok-region", type=str, help="The region in which ngrok should start.", default="us")
parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer'))
@ -97,6 +97,8 @@ restricted_opts = {
"outdir_save", "outdir_save",
} }
cmd_opts.disable_extension_access = cmd_opts.share or cmd_opts.listen
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_swinir, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_swinir, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \
(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'swinir', 'esrgan', 'scunet', 'codeformer']) (devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'swinir', 'esrgan', 'scunet', 'codeformer'])
@ -132,6 +134,7 @@ class State:
current_image = None current_image = None
current_image_sampling_step = 0 current_image_sampling_step = 0
textinfo = None textinfo = None
need_restart = False
def skip(self): def skip(self):
self.skipped = True self.skipped = True
@ -354,6 +357,12 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters"
'eta_noise_seed_delta': OptionInfo(0, "Eta noise seed delta", gr.Number, {"precision": 0}), 'eta_noise_seed_delta': OptionInfo(0, "Eta noise seed delta", gr.Number, {"precision": 0}),
})) }))
options_templates.update(options_section((None, "Hidden options"), {
"disabled_extensions": OptionInfo([], "Disable those extensions"),
}))
options_templates.update()
class Options: class Options:
data = None data = None
@ -365,8 +374,9 @@ class Options:
def __setattr__(self, key, value): def __setattr__(self, key, value):
if self.data is not None: if self.data is not None:
if key in self.data: if key in self.data or key in self.data_labels:
self.data[key] = value self.data[key] = value
return
return super(Options, self).__setattr__(key, value) return super(Options, self).__setattr__(key, value)

View file

@ -19,7 +19,7 @@ import numpy as np
from PIL import Image, PngImagePlugin from PIL import Image, PngImagePlugin
from modules import sd_hijack, sd_models, localization, script_callbacks from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions
from modules.paths import script_path from modules.paths import script_path
from modules.shared import opts, cmd_opts, restricted_opts from modules.shared import opts, cmd_opts, restricted_opts
@ -671,6 +671,7 @@ def create_ui(wrap_gradio_gpu_call):
import modules.img2img import modules.img2img
import modules.txt2img import modules.txt2img
parameters_copypaste.reset()
with gr.Blocks(analytics_enabled=False) as txt2img_interface: with gr.Blocks(analytics_enabled=False) as txt2img_interface:
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False) txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False)
@ -1511,8 +1512,9 @@ def create_ui(wrap_gradio_gpu_call):
column = None column = None
with gr.Row(elem_id="settings").style(equal_height=False): with gr.Row(elem_id="settings").style(equal_height=False):
for i, (k, item) in enumerate(opts.data_labels.items()): for i, (k, item) in enumerate(opts.data_labels.items()):
section_must_be_skipped = item.section[0] is None
if previous_section != item.section: if previous_section != item.section and not section_must_be_skipped:
if cols_displayed < settings_cols and (items_displayed >= items_per_col or previous_section is None): if cols_displayed < settings_cols and (items_displayed >= items_per_col or previous_section is None):
if column is not None: if column is not None:
column.__exit__() column.__exit__()
@ -1531,6 +1533,8 @@ def create_ui(wrap_gradio_gpu_call):
if k in quicksettings_names and not shared.cmd_opts.freeze_settings: if k in quicksettings_names and not shared.cmd_opts.freeze_settings:
quicksettings_list.append((i, k, item)) quicksettings_list.append((i, k, item))
components.append(dummy_component) components.append(dummy_component)
elif section_must_be_skipped:
components.append(dummy_component)
else: else:
component = create_setting_component(k) component = create_setting_component(k)
component_dict[k] = component component_dict[k] = component
@ -1572,9 +1576,10 @@ def create_ui(wrap_gradio_gpu_call):
def request_restart(): def request_restart():
shared.state.interrupt() shared.state.interrupt()
settings_interface.gradio_ref.do_restart = True shared.state.need_restart = True
restart_gradio.click( restart_gradio.click(
fn=request_restart, fn=request_restart,
inputs=[], inputs=[],
outputs=[], outputs=[],
@ -1612,14 +1617,15 @@ def create_ui(wrap_gradio_gpu_call):
interfaces += script_callbacks.ui_tabs_callback() interfaces += script_callbacks.ui_tabs_callback()
interfaces += [(settings_interface, "Settings", "settings")] interfaces += [(settings_interface, "Settings", "settings")]
extensions_interface = ui_extensions.create_ui()
interfaces += [(extensions_interface, "Extensions", "extensions")]
with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
with gr.Row(elem_id="quicksettings"): with gr.Row(elem_id="quicksettings"):
for i, k, item in quicksettings_list: for i, k, item in quicksettings_list:
component = create_setting_component(k, is_quicksettings=True) component = create_setting_component(k, is_quicksettings=True)
component_dict[k] = component component_dict[k] = component
settings_interface.gradio_ref = demo
parameters_copypaste.integrate_settings_paste_fields(component_dict) parameters_copypaste.integrate_settings_paste_fields(component_dict)
parameters_copypaste.run_bind() parameters_copypaste.run_bind()

268
modules/ui_extensions.py Normal file
View file

@ -0,0 +1,268 @@
import json
import os.path
import shutil
import sys
import time
import traceback
import git
import gradio as gr
import html
from modules import extensions, shared, paths
available_extensions = {"extensions": []}
def check_access():
assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
def apply_and_restart(disable_list, update_list):
check_access()
disabled = json.loads(disable_list)
assert type(disabled) == list, f"wrong disable_list data for apply_and_restart: {disable_list}"
update = json.loads(update_list)
assert type(update) == list, f"wrong update_list data for apply_and_restart: {update_list}"
update = set(update)
for ext in extensions.extensions:
if ext.name not in update:
continue
try:
ext.pull()
except Exception:
print(f"Error pulling updates for {ext.name}:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
shared.opts.disabled_extensions = disabled
shared.opts.save(shared.config_filename)
shared.state.interrupt()
shared.state.need_restart = True
def check_updates():
check_access()
for ext in extensions.extensions:
if ext.remote is None:
continue
try:
ext.check_updates()
except Exception:
print(f"Error checking updates for {ext.name}:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
return extension_table()
def extension_table():
code = f"""<!-- {time.time()} -->
<table id="extensions">
<thead>
<tr>
<th><abbr title="Use checkbox to enable the extension; it will be enabled or disabled when you click apply button">Extension</abbr></th>
<th>URL</th>
<th><abbr title="Use checkbox to mark the extension for update; it will be updated when you click apply button">Update</abbr></th>
</tr>
</thead>
<tbody>
"""
for ext in extensions.extensions:
if ext.can_update:
ext_status = f"""<label><input class="gr-check-radio gr-checkbox" name="update_{html.escape(ext.name)}" checked="checked" type="checkbox">{html.escape(ext.status)}</label>"""
else:
ext_status = ext.status
code += f"""
<tr>
<td><label><input class="gr-check-radio gr-checkbox" name="enable_{html.escape(ext.name)}" type="checkbox" {'checked="checked"' if ext.enabled else ''}>{html.escape(ext.name)}</label></td>
<td><a href="{html.escape(ext.remote or '')}">{html.escape(ext.remote or '')}</a></td>
<td{' class="extension_status"' if ext.remote is not None else ''}>{ext_status}</td>
</tr>
"""
code += """
</tbody>
</table>
"""
return code
def normalize_git_url(url):
if url is None:
return ""
url = url.replace(".git", "")
return url
def install_extension_from_url(dirname, url):
check_access()
assert url, 'No URL specified'
if dirname is None or dirname == "":
*parts, last_part = url.split('/')
last_part = normalize_git_url(last_part)
dirname = last_part
target_dir = os.path.join(extensions.extensions_dir, dirname)
assert not os.path.exists(target_dir), f'Extension directory already exists: {target_dir}'
normalized_url = normalize_git_url(url)
assert len([x for x in extensions.extensions if normalize_git_url(x.remote) == normalized_url]) == 0, 'Extension with this URL is already installed'
tmpdir = os.path.join(paths.script_path, "tmp", dirname)
try:
shutil.rmtree(tmpdir, True)
repo = git.Repo.clone_from(url, tmpdir)
repo.remote().fetch()
os.rename(tmpdir, target_dir)
extensions.list_extensions()
return [extension_table(), html.escape(f"Installed into {target_dir}. Use Installed tab to restart.")]
finally:
shutil.rmtree(tmpdir, True)
def install_extension_from_index(url):
ext_table, message = install_extension_from_url(None, url)
return refresh_available_extensions_from_data(), ext_table, message
def refresh_available_extensions(url):
global available_extensions
import urllib.request
with urllib.request.urlopen(url) as response:
text = response.read()
available_extensions = json.loads(text)
return url, refresh_available_extensions_from_data(), ''
def refresh_available_extensions_from_data():
extlist = available_extensions["extensions"]
installed_extension_urls = {normalize_git_url(extension.remote): extension.name for extension in extensions.extensions}
code = f"""<!-- {time.time()} -->
<table id="available_extensions">
<thead>
<tr>
<th>Extension</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
"""
for ext in extlist:
name = ext.get("name", "noname")
url = ext.get("url", None)
description = ext.get("description", "")
if url is None:
continue
existing = installed_extension_urls.get(normalize_git_url(url), None)
install_code = f"""<input onclick="install_extension_from_index(this, '{html.escape(url)}')" type="button" value="{"Install" if not existing else "Installed"}" {"disabled=disabled" if existing else ""} class="gr-button gr-button-lg gr-button-secondary">"""
code += f"""
<tr>
<td><a href="{html.escape(url)}">{html.escape(name)}</a></td>
<td>{html.escape(description)}</td>
<td>{install_code}</td>
</tr>
"""
code += """
</tbody>
</table>
"""
return code
def create_ui():
import modules.ui
with gr.Blocks(analytics_enabled=False) as ui:
with gr.Tabs(elem_id="tabs_extensions") as tabs:
with gr.TabItem("Installed"):
with gr.Row():
apply = gr.Button(value="Apply and restart UI", variant="primary")
check = gr.Button(value="Check for updates")
extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False)
extensions_table = gr.HTML(lambda: extension_table())
apply.click(
fn=apply_and_restart,
_js="extensions_apply",
inputs=[extensions_disabled_list, extensions_update_list],
outputs=[],
)
check.click(
fn=check_updates,
_js="extensions_check",
inputs=[],
outputs=[extensions_table],
)
with gr.TabItem("Available"):
with gr.Row():
refresh_available_extensions_button = gr.Button(value="Load from:", variant="primary")
available_extensions_index = gr.Text(value="https://raw.githubusercontent.com/wiki/AUTOMATIC1111/stable-diffusion-webui/Extensions-index.md", label="Extension index URL").style(container=False)
extension_to_install = gr.Text(elem_id="extension_to_install", visible=False)
install_extension_button = gr.Button(elem_id="install_extension_button", visible=False)
install_result = gr.HTML()
available_extensions_table = gr.HTML()
refresh_available_extensions_button.click(
fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update()]),
inputs=[available_extensions_index],
outputs=[available_extensions_index, available_extensions_table, install_result],
)
install_extension_button.click(
fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]),
inputs=[extension_to_install],
outputs=[available_extensions_table, extensions_table, install_result],
)
with gr.TabItem("Install from URL"):
install_url = gr.Text(label="URL for extension's git repository")
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
install_button = gr.Button(value="Install", variant="primary")
install_result = gr.HTML(elem_id="extension_install_result")
install_button.click(
fn=modules.ui.wrap_gradio_call(install_extension_from_url, extra_outputs=[gr.update()]),
inputs=[install_dirname, install_url],
outputs=[extensions_table, install_result],
)
return ui

View file

@ -26,3 +26,4 @@ torchdiffeq
kornia kornia
lark lark
inflection inflection
GitPython

View file

@ -23,3 +23,4 @@ torchdiffeq==0.2.3
kornia==0.6.7 kornia==0.6.7
lark==1.1.2 lark==1.1.2
inflection==0.5.1 inflection==0.5.1
GitPython==3.1.27

View file

@ -530,6 +530,29 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
min-height: 480px !important; min-height: 480px !important;
} }
/* Extensions */
#tab_extensions table{
border-collapse: collapse;
}
#tab_extensions table td, #tab_extensions table th{
border: 1px solid #ccc;
padding: 0.25em 0.5em;
}
#tab_extensions table input[type="checkbox"]{
margin-right: 0.5em;
}
#tab_extensions button{
max-width: 16em;
}
#tab_extensions input[disabled="disabled"]{
opacity: 0.5;
}
/* The following handles localization for right-to-left (RTL) languages like Arabic. /* The following handles localization for right-to-left (RTL) languages like Arabic.
The rtl media type will only be activated by the logic in javascript/localization.js. The rtl media type will only be activated by the logic in javascript/localization.js.
If you change anything above, you need to make sure it is RTL compliant by just running If you change anything above, you need to make sure it is RTL compliant by just running
@ -607,4 +630,4 @@ Then, you will need to add the RTL counterpart only if needed in the rtl section
right: unset; right: unset;
left: 0.5em; left: 0.5em;
} }
} }

View file

@ -9,7 +9,7 @@ from fastapi.middleware.gzip import GZipMiddleware
from modules.paths import script_path from modules.paths import script_path
from modules import devices, sd_samplers, upscaler from modules import devices, sd_samplers, upscaler, extensions
import modules.codeformer_model as codeformer import modules.codeformer_model as codeformer
import modules.extras import modules.extras
import modules.face_restoration import modules.face_restoration
@ -60,6 +60,8 @@ def wrap_gradio_gpu_call(func, extra_outputs=None):
def initialize(): def initialize():
extensions.list_extensions()
if cmd_opts.ui_debug_mode: if cmd_opts.ui_debug_mode:
shared.sd_upscalers = upscaler.UpscalerLanczos().scalers shared.sd_upscalers = upscaler.UpscalerLanczos().scalers
modules.scripts.load_scripts() modules.scripts.load_scripts()
@ -92,15 +94,18 @@ def create_api(app):
api = Api(app, queue_lock) api = Api(app, queue_lock)
return api return api
def wait_on_server(demo=None): def wait_on_server(demo=None):
while 1: while 1:
time.sleep(0.5) time.sleep(0.5)
if demo and getattr(demo, 'do_restart', False): if shared.state.need_restart:
shared.state.need_restart = False
time.sleep(0.5) time.sleep(0.5)
demo.close() demo.close()
time.sleep(0.5) time.sleep(0.5)
break break
def api_only(): def api_only():
initialize() initialize()
@ -132,14 +137,16 @@ def webui():
app.add_middleware(GZipMiddleware, minimum_size=1000) app.add_middleware(GZipMiddleware, minimum_size=1000)
if (launch_api): if launch_api:
create_api(app) create_api(app)
wait_on_server(demo) wait_on_server(demo)
sd_samplers.set_samplers() sd_samplers.set_samplers()
print('Reloading Custom Scripts') print('Reloading extensions')
extensions.list_extensions()
print('Reloading custom scripts')
modules.scripts.reload_scripts() modules.scripts.reload_scripts()
print('Reloading modules: modules.ui') print('Reloading modules: modules.ui')
importlib.reload(modules.ui) importlib.reload(modules.ui)
@ -148,8 +155,6 @@ def webui():
print('Restarting Gradio') print('Restarting Gradio')
task = []
if __name__ == "__main__": if __name__ == "__main__":
if cmd_opts.nowebui: if cmd_opts.nowebui:
api_only() api_only()