浏览代码

Merge pull request #3328 from FuturePrayer/AUTOMATIC1111_api_auth_support

feat: Supports making requests to the Automatic1111 backend when running with the --api-auth parameter
Timothy Jaeryang Baek 10 月之前
父节点
当前提交
16a8eebd8d

+ 38 - 16
backend/apps/images/main.py

@@ -1,5 +1,6 @@
 import re
 import requests
+import base64
 from fastapi import (
     FastAPI,
     Request,
@@ -36,6 +37,7 @@ from config import (
     IMAGE_GENERATION_ENGINE,
     ENABLE_IMAGE_GENERATION,
     AUTOMATIC1111_BASE_URL,
+    AUTOMATIC1111_API_AUTH,
     COMFYUI_BASE_URL,
     COMFYUI_CFG_SCALE,
     COMFYUI_SAMPLER,
@@ -49,7 +51,6 @@ from config import (
     AppConfig,
 )
 
-
 log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["IMAGES"])
 
@@ -75,11 +76,10 @@ app.state.config.OPENAI_API_KEY = IMAGES_OPENAI_API_KEY
 
 app.state.config.MODEL = IMAGE_GENERATION_MODEL
 
-
 app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
+app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH
 app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
 
-
 app.state.config.IMAGE_SIZE = IMAGE_SIZE
 app.state.config.IMAGE_STEPS = IMAGE_STEPS
 app.state.config.COMFYUI_CFG_SCALE = COMFYUI_CFG_SCALE
@@ -88,6 +88,16 @@ app.state.config.COMFYUI_SCHEDULER = COMFYUI_SCHEDULER
 app.state.config.COMFYUI_SD3 = COMFYUI_SD3
 
 
+def get_automatic1111_api_auth():
+    if app.state.config.AUTOMATIC1111_API_AUTH == None:
+        return ""
+    else:
+        auth1111_byte_string = app.state.config.AUTOMATIC1111_API_AUTH.encode('utf-8')
+        auth1111_base64_encoded_bytes = base64.b64encode(auth1111_byte_string)
+        auth1111_base64_encoded_string = auth1111_base64_encoded_bytes.decode('utf-8')
+        return f"Basic {auth1111_base64_encoded_string}"
+
+
 @app.get("/config")
 async def get_config(request: Request, user=Depends(get_admin_user)):
     return {
@@ -113,6 +123,7 @@ async def update_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user
 
 class EngineUrlUpdateForm(BaseModel):
     AUTOMATIC1111_BASE_URL: Optional[str] = None
+    AUTOMATIC1111_API_AUTH: Optional[str] = None
     COMFYUI_BASE_URL: Optional[str] = None
 
 
@@ -120,15 +131,15 @@ class EngineUrlUpdateForm(BaseModel):
 async def get_engine_url(user=Depends(get_admin_user)):
     return {
         "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
+        "AUTOMATIC1111_API_AUTH": app.state.config.AUTOMATIC1111_API_AUTH,
         "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
     }
 
 
 @app.post("/url/update")
 async def update_engine_url(
-    form_data: EngineUrlUpdateForm, user=Depends(get_admin_user)
+        form_data: EngineUrlUpdateForm, user=Depends(get_admin_user)
 ):
-
     if form_data.AUTOMATIC1111_BASE_URL == None:
         app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
     else:
@@ -150,8 +161,14 @@ async def update_engine_url(
         except Exception as e:
             raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e))
 
+    if form_data.AUTOMATIC1111_API_AUTH == None:
+        app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH
+    else:
+        app.state.config.AUTOMATIC1111_API_AUTH = form_data.AUTOMATIC1111_API_AUTH
+
     return {
         "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL,
+        "AUTOMATIC1111_API_AUTH": app.state.config.AUTOMATIC1111_API_AUTH,
         "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL,
         "status": True,
     }
@@ -172,7 +189,7 @@ async def get_openai_config(user=Depends(get_admin_user)):
 
 @app.post("/openai/config/update")
 async def update_openai_config(
-    form_data: OpenAIConfigUpdateForm, user=Depends(get_admin_user)
+        form_data: OpenAIConfigUpdateForm, user=Depends(get_admin_user)
 ):
     if form_data.key == "":
         raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)
@@ -198,7 +215,7 @@ async def get_image_size(user=Depends(get_admin_user)):
 
 @app.post("/size/update")
 async def update_image_size(
-    form_data: ImageSizeUpdateForm, user=Depends(get_admin_user)
+        form_data: ImageSizeUpdateForm, user=Depends(get_admin_user)
 ):
     pattern = r"^\d+x\d+$"  # Regular expression pattern
     if re.match(pattern, form_data.size):
@@ -225,7 +242,7 @@ async def get_image_size(user=Depends(get_admin_user)):
 
 @app.post("/steps/update")
 async def update_image_size(
-    form_data: ImageStepsUpdateForm, user=Depends(get_admin_user)
+        form_data: ImageStepsUpdateForm, user=Depends(get_admin_user)
 ):
     if form_data.steps >= 0:
         app.state.config.IMAGE_STEPS = form_data.steps
@@ -262,7 +279,8 @@ def get_models(user=Depends(get_current_user)):
 
         else:
             r = requests.get(
-                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models"
+                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models",
+                headers={"authorization": get_automatic1111_api_auth()}
             )
             models = r.json()
             return list(
@@ -289,7 +307,8 @@ async def get_default_model(user=Depends(get_admin_user)):
             return {"model": (app.state.config.MODEL if app.state.config.MODEL else "")}
         else:
             r = requests.get(
-                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
+                url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
+                headers={"authorization": get_automatic1111_api_auth()}
             )
             options = r.json()
             return {"model": options["sd_model_checkpoint"]}
@@ -307,8 +326,10 @@ def set_model_handler(model: str):
         app.state.config.MODEL = model
         return app.state.config.MODEL
     else:
+        api_auth = get_automatic1111_api_auth()
         r = requests.get(
-            url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options"
+            url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
+            headers={"authorization": api_auth}
         )
         options = r.json()
 
@@ -317,6 +338,7 @@ def set_model_handler(model: str):
             r = requests.post(
                 url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options",
                 json=options,
+                headers={"authorization": api_auth},
             )
 
         return options
@@ -324,8 +346,8 @@ def set_model_handler(model: str):
 
 @app.post("/models/default/update")
 def update_default_model(
-    form_data: UpdateModelForm,
-    user=Depends(get_current_user),
+        form_data: UpdateModelForm,
+        user=Depends(get_current_user),
 ):
     return set_model_handler(form_data.model)
 
@@ -401,10 +423,9 @@ def save_url_image(url):
 
 @app.post("/generations")
 def generate_image(
-    form_data: GenerateImageForm,
-    user=Depends(get_current_user),
+        form_data: GenerateImageForm,
+        user=Depends(get_current_user),
 ):
-
     width, height = tuple(map(int, app.state.config.IMAGE_SIZE.split("x")))
 
     r = None
@@ -519,6 +540,7 @@ def generate_image(
             r = requests.post(
                 url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img",
                 json=data,
+                headers={"authorization": get_automatic1111_api_auth()},
             )
 
             res = r.json()

+ 5 - 0
backend/config.py

@@ -1166,6 +1166,11 @@ AUTOMATIC1111_BASE_URL = PersistentConfig(
     "image_generation.automatic1111.base_url",
     os.getenv("AUTOMATIC1111_BASE_URL", ""),
 )
+AUTOMATIC1111_API_AUTH = PersistentConfig(
+    "AUTOMATIC1111_API_AUTH",
+    "image_generation.automatic1111.api_auth",
+    os.getenv("AUTOMATIC1111_API_AUTH", ""),
+)
 
 COMFYUI_BASE_URL = PersistentConfig(
     "COMFYUI_BASE_URL",

+ 28 - 2
src/lib/components/admin/Settings/Images.svelte

@@ -29,6 +29,7 @@
 	let enableImageGeneration = false;
 
 	let AUTOMATIC1111_BASE_URL = '';
+	let AUTOMATIC1111_API_AUTH = '';
 	let COMFYUI_BASE_URL = '';
 
 	let OPENAI_API_BASE_URL = '';
@@ -74,7 +75,8 @@
 			}
 		} else {
 			const res = await updateImageGenerationEngineUrls(localStorage.token, {
-				AUTOMATIC1111_BASE_URL: AUTOMATIC1111_BASE_URL
+				AUTOMATIC1111_BASE_URL: AUTOMATIC1111_BASE_URL,
+				AUTOMATIC1111_API_AUTH: AUTOMATIC1111_API_AUTH
 			}).catch((error) => {
 				toast.error(error);
 				return null;
@@ -82,6 +84,7 @@
 
 			if (res) {
 				AUTOMATIC1111_BASE_URL = res.AUTOMATIC1111_BASE_URL;
+				AUTOMATIC1111_API_AUTH = res.AUTOMATIC1111_API_AUTH;
 
 				await getModels();
 
@@ -89,7 +92,7 @@
 					toast.success($i18n.t('Server connection verified'));
 				}
 			} else {
-				({ AUTOMATIC1111_BASE_URL } = await getImageGenerationEngineUrls(localStorage.token));
+				({ AUTOMATIC1111_BASE_URL,AUTOMATIC1111_API_AUTH } = await getImageGenerationEngineUrls(localStorage.token));
 			}
 		}
 	};
@@ -128,6 +131,7 @@
 			const URLS = await getImageGenerationEngineUrls(localStorage.token);
 
 			AUTOMATIC1111_BASE_URL = URLS.AUTOMATIC1111_BASE_URL;
+			AUTOMATIC1111_API_AUTH = URLS.AUTOMATIC1111_API_AUTH;
 			COMFYUI_BASE_URL = URLS.COMFYUI_BASE_URL;
 
 			const config = await getOpenAIConfig(localStorage.token);
@@ -270,6 +274,28 @@
 					{$i18n.t('(e.g. `sh webui.sh --api`)')}
 				</a>
 			</div>
+
+			<div class=" mb-2.5 text-sm font-medium">{$i18n.t('AUTOMATIC1111 Api Auth String')}</div>
+			<div class="flex w-full">
+				<div class="flex-1 mr-2">
+					<input
+						class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
+						placeholder={$i18n.t('Enter api auth string (e.g. username:password)')}
+						bind:value={AUTOMATIC1111_API_AUTH}
+					/>
+				</div>
+			</div>
+
+			<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
+				{$i18n.t('Include `--api-auth` flag when running stable-diffusion-webui')}
+				<a
+					class=" text-gray-300 font-medium"
+					href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/13993"
+					target="_blank"
+				>
+                    {$i18n.t('(e.g. `sh webui.sh --api --api-auth username_password`)').replace('_',':')}
+				</a>
+			</div>
 		{:else if imageGenerationEngine === 'comfyui'}
 			<div class=" mb-2.5 text-sm font-medium">{$i18n.t('ComfyUI Base URL')}</div>
 			<div class="flex w-full">

+ 4 - 0
src/lib/i18n/locales/zh-CN/translation.json

@@ -2,6 +2,7 @@
 	"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' 或 '-1' 表示无过期时间。",
 	"(Beta)": "(测试版)",
 	"(e.g. `sh webui.sh --api`)": "(例如 `sh webui.sh --api`)",
+    "(e.g. `sh webui.sh --api --api-auth username_password`)": "(例如 `sh webui.sh --api --api-auth username_password`)",
 	"(latest)": "(最新版)",
 	"{{ models }}": "{{ models }}",
 	"{{ owner }}: You cannot delete a base model": "{{ owner }}:您不能删除基础模型",
@@ -65,6 +66,7 @@
 	"Audio settings updated successfully": "",
 	"August": "八月",
 	"Auto-playback response": "自动念出回复内容",
+	"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api鉴权字符串",
 	"AUTOMATIC1111 Base URL": "AUTOMATIC1111 基础地址",
 	"AUTOMATIC1111 Base URL is required.": "需要 AUTOMATIC1111 基础地址。",
 	"available!": "版本可用!",
@@ -228,6 +230,7 @@
 	"Enter stop sequence": "输入停止序列 (Stop Sequence)",
 	"Enter Tavily API Key": "输入 Tavily API 密钥",
 	"Enter Top K": "输入 Top K",
+	"Enter api auth string (e.g. username:password)": "输入api鉴权路径 (例如:username:password)",
 	"Enter URL (e.g. http://127.0.0.1:7860/)": "输入地址 (例如:http://127.0.0.1:7860/)",
 	"Enter URL (e.g. http://localhost:11434)": "输入地址 (例如:http://localhost:11434)",
 	"Enter Your Email": "输入您的电子邮箱",
@@ -294,6 +297,7 @@
 	"Import Models": "导入模型",
 	"Import Prompts": "导入提示词",
 	"Import Tools": "导入工具",
+	"Include `--api-auth` flag when running stable-diffusion-webui": "运行 stable-diffusion-webui 时包含 `--api-auth` 标志",
 	"Include `--api` flag when running stable-diffusion-webui": "运行 stable-diffusion-webui 时包含 `--api` 标志",
 	"Info": "信息",
 	"Input commands": "输入命令",