From 8dd91dde66a25a6f28321e11fea00a022f46339b Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Tue, 13 Oct 2026 08:08:24 +0000 Subject: [PATCH] fix(diffusers): keep negative_prompt unless negative embeds are set The sd_embed branch dropped negative_prompt for every pipeline, which discarded the user's negative prompt for Flux, where no negative embeds are produced. Only drop it when negative_prompt_embeds is present, and move the check to a helper that has unit tests. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Ettore Di Giacinto --- backend/python/diffusers/backend.py | 8 +++---- backend/python/diffusers/load_options.py | 11 +++++++++ backend/python/diffusers/test_load_options.py | 24 ++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/backend/python/diffusers/backend.py b/backend/python/diffusers/backend.py index 558f4374c..f88cadec0 100755 --- a/backend/python/diffusers/backend.py +++ b/backend/python/diffusers/backend.py @@ -36,7 +36,7 @@ from diffusers_dynamic_loader import ( get_available_pipelines, load_diffusers_pipeline, ) -from load_options import single_file_load_kwargs +from load_options import drop_negative_prompt_if_embedded, single_file_load_kwargs # Import specific items still needed for special cases and safety checker from diffusers import DiffusionPipeline, ControlNetModel @@ -882,9 +882,9 @@ class BackendServicer(backend_pb2_grpc.BackendServicer): prompt = prompt, ) - # remove negative_prompt that may have been added earlier from options to avoid conflict - # errors from passing both negative_prompt and negative_prompt_embeds - kwargs.pop('negative_prompt', None) + # negative_prompt conflicts with negative_prompt_embeds; pipelines that + # got no negative embeds (e.g. Flux) keep the user's negative prompt + drop_negative_prompt_if_embedded(kwargs) image = self.pipe( guidance_scale=self.cfg_scale, diff --git a/backend/python/diffusers/load_options.py b/backend/python/diffusers/load_options.py index fba08fc53..e80fc9781 100644 --- a/backend/python/diffusers/load_options.py +++ b/backend/python/diffusers/load_options.py @@ -5,3 +5,14 @@ def single_file_load_kwargs(original_config_file: str, from_single_file: bool) - if from_single_file and original_config_file: return {"original_config_file": original_config_file} return {} + + +def drop_negative_prompt_if_embedded(kwargs: dict) -> dict: + """Remove negative_prompt from pipeline kwargs when negative_prompt_embeds is set. + + Diffusers rejects both being passed together. Pipelines without negative + embeddings keep the user's negative prompt. + """ + if "negative_prompt_embeds" in kwargs: + kwargs.pop("negative_prompt", None) + return kwargs diff --git a/backend/python/diffusers/test_load_options.py b/backend/python/diffusers/test_load_options.py index 286b38836..39fc9472c 100644 --- a/backend/python/diffusers/test_load_options.py +++ b/backend/python/diffusers/test_load_options.py @@ -2,7 +2,10 @@ import unittest -from backend.python.diffusers.load_options import single_file_load_kwargs +from backend.python.diffusers.load_options import ( + drop_negative_prompt_if_embedded, + single_file_load_kwargs, +) class SingleFileLoadKwargsTest(unittest.TestCase): @@ -22,5 +25,24 @@ class SingleFileLoadKwargsTest(unittest.TestCase): self.assertEqual(single_file_load_kwargs("", True), {}) +class DropNegativePromptTest(unittest.TestCase): + def test_drops_negative_prompt_when_embeds_present(self): + kwargs = {"negative_prompt": "blurry", "negative_prompt_embeds": object()} + drop_negative_prompt_if_embedded(kwargs) + self.assertNotIn("negative_prompt", kwargs) + self.assertIn("negative_prompt_embeds", kwargs) + + def test_keeps_negative_prompt_without_embeds(self): + kwargs = {"negative_prompt": "blurry", "prompt_embeds": object()} + drop_negative_prompt_if_embedded(kwargs) + self.assertEqual(kwargs["negative_prompt"], "blurry") + + def test_no_negative_prompt_is_fine(self): + self.assertEqual( + drop_negative_prompt_if_embedded({"negative_prompt_embeds": 1}), + {"negative_prompt_embeds": 1}, + ) + + if __name__ == "__main__": unittest.main()