mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
+15
-14
@@ -39,27 +39,28 @@ And **SDNQ** improvements: now with *NPU* support and its own native *attention*
|
||||
- **Internal**
|
||||
- delay init of video models
|
||||
- **Fixes**
|
||||
- sdnq: warn instead of error for triton
|
||||
- amd: hipBLASLt improved detection, thanks @0xDELUXA
|
||||
- api: add missing endpoint registration
|
||||
- api: openapi schema exposure
|
||||
- api: stricter api request and response schemas
|
||||
- caption: button in standard-ui
|
||||
- embeddings: handle textual-inversion with new transformers
|
||||
- insightface: missing dependencies
|
||||
- pulid: import paths
|
||||
- processors: init code and multiple fixes
|
||||
- live preview: configurable pause when not in focus, thanks @Artheriax
|
||||
- log: strip ansi sequences from ring buffer and client side logging
|
||||
- measure: handle current kanvas stage
|
||||
- model metadata: handle invalid metadata and strip workflows
|
||||
- mps: install `torchsde` as requirement
|
||||
- vae: scale factor improved detection
|
||||
- ui: networks details scrollbars
|
||||
- onnxruntime: handle invalid version
|
||||
- onnxruntime: mark all import paths as non-critical
|
||||
- measure: handle current kanvas stage
|
||||
- caption: button in standard-ui
|
||||
- python: experimental/ignore version checks
|
||||
- hipBLASLt: improved detection, thanks @0xDELUXA
|
||||
- embeddings: handle textual-inversion with new transformers
|
||||
- options: handle compatibility options
|
||||
- log: strip ansi sequences from ring buffer and client side logging
|
||||
- model metadata: handle invalid metadata and strip workflows
|
||||
- processors: init code and multiple fixes
|
||||
- pulid: import paths
|
||||
- python: experimental/ignore version checks
|
||||
- sdnq: warn instead of error for `triton`
|
||||
- ui debounce aspect-ratio linked width/height controls
|
||||
- api: stricter api request and response schemas
|
||||
- api: openapi schema exposure
|
||||
- ui: networks details scrollbars
|
||||
- vae: scale factor improved detection
|
||||
|
||||
## Update for 2026-06-16
|
||||
|
||||
|
||||
+10
-2
@@ -64,7 +64,9 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/txt2img", self.generate.post_text2img, methods=["POST"], response_model=models.ResTxt2Img, tags=["Generation"])
|
||||
self.add_api_route("/sdapi/v1/img2img", self.generate.post_img2img, methods=["POST"], response_model=models.ResImg2Img, tags=["Generation"])
|
||||
self.add_api_route("/sdapi/v1/control", self.control.post_control, methods=["POST"], response_model=control.ResControl, tags=["Generation"])
|
||||
self.add_api_route("/sdapi/v1/process", self.process.extras_single_image_api, methods=["POST"], response_model=models.ResProcessImage, tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/extra-single-image", self.process.extras_single_image_api, methods=["POST"], response_model=models.ResProcessImage, tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/process-batch", self.process.extras_batch_images_api, methods=["POST"], response_model=models.ResProcessBatch, tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/extra-batch-images", self.process.extras_batch_images_api, methods=["POST"], response_model=models.ResProcessBatch, tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/preprocess", self.process.post_preprocess, methods=["POST"], tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/mask", self.process.post_mask, methods=["POST"], tags=["Processing"])
|
||||
@@ -80,23 +82,29 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/preprocessors", self.process.get_preprocess, methods=["GET"], response_model=list[process.ItemPreprocess])
|
||||
self.add_api_route("/sdapi/v1/masking", self.process.get_mask, methods=["GET"], response_model=process.ItemMask)
|
||||
self.add_api_route("/sdapi/v1/samplers", endpoints.get_samplers, methods=["GET"], response_model=list[models.ItemSampler])
|
||||
self.add_api_route("/sdapi/v1/schedulers", endpoints.get_schedulers, methods=["GET"], response_model=list[models.ItemScheduler])
|
||||
self.add_api_route("/sdapi/v1/upscalers", endpoints.get_upscalers, methods=["GET"], response_model=list[models.ItemUpscaler])
|
||||
self.add_api_route("/sdapi/v1/sd-models", endpoints.get_sd_models, methods=["GET"], response_model=list[models.ItemModel])
|
||||
self.add_api_route("/sdapi/v1/controlnets", endpoints.get_controlnets, methods=["GET"], response_model=list[str])
|
||||
self.add_api_route("/sdapi/v1/control-models", endpoints.get_control_models, methods=["GET"], response_model=list[str])
|
||||
self.add_api_route("/sdapi/v1/control-modes", endpoints.get_control_modes, methods=["GET"], response_model=dict[str, list[str]])
|
||||
self.add_api_route("/sdapi/v1/face-restorers", endpoints.get_restorers, methods=["GET"], response_model=list[models.ItemDetailer])
|
||||
self.add_api_route("/sdapi/v1/detailers", endpoints.get_detailers, methods=["GET"], response_model=list[models.ItemDetailer])
|
||||
self.add_api_route("/sdapi/v1/prompt-styles", endpoints.get_prompt_styles, methods=["GET"], response_model=list[models.ItemStyle])
|
||||
self.add_api_route("/sdapi/v1/embeddings", endpoints.get_embeddings, methods=["GET"], response_model=models.ResEmbeddings)
|
||||
self.add_api_route("/sdapi/v1/ip-adapters", endpoints.get_ip_adapters, methods=["GET"], response_model=list[str])
|
||||
self.add_api_route("/sdapi/v1/wildcards", endpoints.get_wildcards, methods=["GET"], response_model=list[dict], tags=["Enumerators"])
|
||||
self.add_api_route("/sdapi/v1/sd-vae", endpoints.get_sd_vaes, methods=["GET"], response_model=list[models.ItemVae])
|
||||
self.add_api_route("/sdapi/v1/extensions", endpoints.get_extensions_list, methods=["GET"], response_model=list[models.ItemExtension])
|
||||
self.add_api_route("/sdapi/v1/extra-networks", endpoints.get_extra_networks, methods=["GET"], response_model=list[models.ItemExtraNetwork])
|
||||
self.add_api_route("/sdapi/v1/extra-network-detail", endpoints.get_extra_network_detail, methods=["GET"], response_model=models.ItemExtraNetworkFull)
|
||||
self.add_api_route("/sdapi/v1/extra-network-details", endpoints.get_extra_network_details, methods=["GET"], response_model=models.ResExtraNetworkDetails)
|
||||
self.add_api_route("/sdapi/v1/unets", endpoints.get_unets, methods=["GET"], response_model=list[models.ItemUNet])
|
||||
|
||||
# functional api
|
||||
self.add_api_route("/sdapi/v1/file", endpoints.get_file, methods=["GET"], tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/delete-image", endpoints.get_deleteimage, methods=["GET"], tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/delete-file", endpoints.get_deletefile, methods=["GET"], tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/delete-image", endpoints.get_deleteimage, methods=["DELETE"], tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/delete-file", endpoints.get_deletefile, methods=["DELETE"], tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/png-info", endpoints.get_pnginfo, methods=["GET"], response_model=models.ResImageInfo, tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/png-info", endpoints.post_pnginfo, methods=["POST"], response_model=models.ResImageInfo, tags=["Functional"])
|
||||
self.add_api_route("/sdapi/v1/checkpoint", endpoints.get_checkpoint, methods=["GET"], tags=["Functional"])
|
||||
|
||||
@@ -210,7 +210,14 @@ def get_schedulers():
|
||||
"""List all available schedulers with their class names and options."""
|
||||
from modules.sd_samplers import list_samplers
|
||||
all_schedulers = list_samplers()
|
||||
return all_schedulers
|
||||
return [
|
||||
{
|
||||
'name': scheduler.name,
|
||||
'cls': scheduler.constructor.__name__ if scheduler.constructor is not None else None,
|
||||
'options': scheduler.options,
|
||||
}
|
||||
for scheduler in all_schedulers
|
||||
]
|
||||
|
||||
def post_unload_checkpoint():
|
||||
"""Unload the current model and refiner from memory to free VRAM."""
|
||||
@@ -331,6 +338,8 @@ def get_file(file: str):
|
||||
import os
|
||||
from pathlib import Path
|
||||
from starlette.responses import FileResponse
|
||||
if shared.demo is None:
|
||||
raise HTTPException(status_code=503, detail="server not ready")
|
||||
allowed_dirs = shared.demo.allowed_paths
|
||||
if not file.strip():
|
||||
raise HTTPException(status_code=400, detail="file path is required")
|
||||
@@ -345,6 +354,8 @@ def get_file(file: str):
|
||||
def get_deletefile(file: str):
|
||||
import os
|
||||
from pathlib import Path
|
||||
if shared.demo is None:
|
||||
raise HTTPException(status_code=503, detail="server not ready")
|
||||
allowed_dirs = shared.demo.allowed_paths
|
||||
if file is None or len(file.strip()) == 0:
|
||||
raise HTTPException(status_code=400, detail="file path is required")
|
||||
@@ -368,6 +379,8 @@ def get_deletefile(file: str):
|
||||
def get_deleteimage(file: str):
|
||||
import os
|
||||
from pathlib import Path
|
||||
if shared.demo is None:
|
||||
raise HTTPException(status_code=503, detail="server not ready")
|
||||
allowed_dirs = shared.demo.allowed_paths
|
||||
if file is None or len(file.strip()) == 0:
|
||||
raise HTTPException(status_code=400, detail="file path is required")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
from fastapi import Request, Depends, BackgroundTasks, Response
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
@@ -13,6 +14,12 @@ def get_js(request: Request):
|
||||
file = request.query_params.get("file", None)
|
||||
if (file is None) or (len(file) == 0):
|
||||
raise HTTPException(status_code=400, detail="file parameter is required")
|
||||
# Security: validate path is within allowed directories
|
||||
if shared.demo is None:
|
||||
raise HTTPException(status_code=503, detail="server not ready")
|
||||
allowed_dirs = shared.demo.allowed_paths
|
||||
if not any(Path(folder).absolute() in Path(file).absolute().parents for folder in allowed_dirs):
|
||||
raise HTTPException(status_code=403, detail=f"file {file}: must be in one of allowed directories")
|
||||
ext = file.split('.')[-1]
|
||||
if ext not in ['js', 'css', 'map', 'html', 'wasm', 'ttf', 'mjs', 'json']:
|
||||
raise HTTPException(status_code=400, detail=f"invalid file extension: {ext}")
|
||||
|
||||
Reference in New Issue
Block a user