diff --git a/modules/api/helpers.py b/modules/api/helpers.py index 0843f0615..78cd697d8 100644 --- a/modules/api/helpers.py +++ b/modules/api/helpers.py @@ -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): diff --git a/test/test-generation-api.py b/test/test-generation-api.py index 98ec18982..ca0888dbd 100644 --- a/test/test-generation-api.py +++ b/test/test-generation-api.py @@ -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()