Merge pull request #4897 from vladmandic/fix/api-sampler-resolution

Fix/api sampler resolution
This commit is contained in:
Vladimir Mandic
2026-06-07 10:00:40 +02:00
committed by GitHub
4 changed files with 42 additions and 5 deletions
+9 -3
View File
@@ -17,9 +17,15 @@ def register_upload_store(getter_fn):
def validate_sampler_name(name):
config = sd_samplers.all_samplers_map.get(name, None)
if config is None:
raise HTTPException(status_code=404, detail="Sampler not found")
return name
if config is not None:
return name
# accept case-insensitive and alias variants, returning the canonical name so the
# exact-match lookup in create_sampler resolves instead of silently using the model default
if isinstance(name, str) and name not in ('', 'None'):
sampler = sd_samplers.find_sampler(name)
if sampler is not None:
return sampler.name
raise HTTPException(status_code=404, detail="Sampler not found")
def decode_base64_to_image(encoding, quiet=False):
+1 -1
View File
@@ -302,7 +302,7 @@ ReqImg2Img = PydanticModelGenerator(
StableDiffusionProcessingImg2Img,
[
{"key": "sampler_index", "type": Union[int, str], "default": 0},
{"key": "sampler_name", "type": str, "default": "UniPC"},
{"key": "sampler_name", "type": str, "default": "Default"},
{"key": "hr_sampler_name", "type": str, "default": "Same as primary"},
{"key": "init_images", "type": list, "default": None},
{"key": "denoising_strength", "type": float, "default": 0.5},
+1 -1
View File
@@ -742,7 +742,7 @@ def create_settings(cmd_opts):
"schedulers_solver_order": OptionInfo(0, "Solver order (where", gr.Slider, {"minimum": 0, "maximum": 5, "step": 1, "visible": False}),
"schedulers_use_loworder": OptionInfo(True, "Use simplified solvers in final steps", gr.Checkbox, {"visible": False}),
"schedulers_prediction_type": OptionInfo("default", "Override model prediction type", gr.Radio, {"choices": ["default", "epsilon", "sample", "v_prediction", "flow_prediction"], "visible": False}),
"schedulers_sigma": OptionInfo("default", "Sigma algorithm", gr.Radio, {"choices": ["default", "karras", "exponential", "polyexponential"], "visible": False}),
"schedulers_sigma": OptionInfo("default", "Sigma algorithm", gr.Radio, {"choices": ["default", "karras", "betas", "exponential", "lambdas", "flowmatch"], "visible": False}),
"schedulers_beta_schedule": OptionInfo("default", "Beta schedule", gr.Dropdown, {"choices": ["default", "linear", "scaled_linear", "squaredcos_cap_v2", "sigmoid"], "visible": False}),
"schedulers_use_thresholding": OptionInfo(False, "Use dynamic thresholding", gr.Checkbox, {"visible": False}),
"schedulers_timestep_spacing": OptionInfo("default", "Timestep spacing", gr.Dropdown, {"choices": ["default", "linspace", "leading", "trailing"], "visible": False}),
+31
View File
@@ -210,6 +210,36 @@ class GenerationAPITest:
data, elapsed = self._txt2img({'sampler_name': sampler})
self._check_generation(data, f'generate_{sampler}', elapsed)
def test_sampler_name_resolution(self, available_samplers):
"""Sampler name resolution: a case-insensitive name resolves to the canonical sampler
(and is applied, not silently swapped for the model default), while an unknown name is
rejected rather than falling back to the default scheduler."""
self._category = 'samplers'
print("\n--- Sampler Name Resolution ---")
if self._critical_error:
self.skip('sampler_lenient_case', self._critical_error)
self.skip('sampler_unknown_rejected', self._critical_error)
return
canonical = next((s for s in ('Euler a', 'DPM++ 2M', 'UniPC') if s in available_samplers), None)
if canonical is None:
self.skip('sampler_lenient_case', 'no known sampler available')
else:
data, _ = self._txt2img({'sampler_name': canonical.lower()})
if 'error' in data:
self.record(False, 'sampler_lenient_case', f"lowercase '{canonical.lower()}' rejected: {data}")
else:
resolved = canonical in self._get_info(data)
self.record(resolved, 'sampler_lenient_case',
f"'{canonical.lower()}' -> '{canonical}'" if resolved
else f"generated but '{canonical}' not in info (model default used?)")
data, _ = self._txt2img({'sampler_name': 'ThisIsNotARealSampler'})
rejected = 'error' in data
self.record(rejected, 'sampler_unknown_rejected',
'unknown name rejected' if rejected else 'unknown name was NOT rejected')
# =========================================================================
# Tests: Color Grading Params
# =========================================================================
@@ -577,6 +607,7 @@ class GenerationAPITest:
# Samplers
available = self.test_samplers_list()
self.test_samplers_generate(available)
self.test_sampler_name_resolution(available)
# Grading
self.run_grading_tests()