Make Qwen Image 2.1 the production image worker

This commit is contained in:
Mikei386
2026-09-21 10:41:32 +02:00
parent aee31aa045
commit 5de4ac4b25
19 changed files with 531 additions and 346 deletions
+1 -1
View File
@@ -364,7 +364,7 @@ png = open('/tmp/test_dl.png', 'rb').read()
print(json.dumps({
'prompt': 'Behalte die Person bei und ändere nur den Hintergrund',
'size': '1024x1024',
'steps': 4,
'steps': 25,
'guidance': 1.0,
'response_format': 'b64_json',
'image_b64': base64.b64encode(png).decode(),
+16 -16
View File
@@ -23,7 +23,7 @@ def item(profile, state="exited"):
def image_item(state="exited"):
return {"Id": "id-flux", "State": state,
return {"Id": "id-qwen-image", "State": state,
"Labels": {controller.IMAGE_LABEL_KEY: controller.IMAGE_WORKER}}
@@ -32,9 +32,9 @@ def restore_item(state="exited"):
"Labels": {controller.IMAGE_LABEL_KEY: controller.RESTORE_WORKER}}
def qwen_image_test_item(state="exited"):
return {"Id": "id-qwen-image-test", "State": state,
"Labels": {controller.IMAGE_LABEL_KEY: controller.QWEN_IMAGE_TEST_WORKER}}
def flux_standby_item(state="exited"):
return {"Id": "id-flux-standby", "State": state,
"Labels": {controller.IMAGE_LABEL_KEY: controller.FLUX_STANDBY_WORKER}}
def tts_item(state="running"):
@@ -97,7 +97,7 @@ class ProfileControllerTests(unittest.TestCase):
self.assertEqual(result, {"music_worker": "acestep", "state": "running"})
self.assertEqual(calls, [
("POST", "/containers/id-ultra/stop?t=120"),
("POST", "/containers/id-flux/stop?t=20"),
("POST", "/containers/id-qwen-image/stop?t=20"),
("POST", "/containers/id-tts/stop?t=30"),
("POST", "/containers/id-music/start"),
])
@@ -158,10 +158,10 @@ class ProfileControllerTests(unittest.TestCase):
self.assertEqual(calls, [
("POST", "/containers/id-medium/stop?t=120"),
("POST", "/containers/id-tts/stop?t=30"),
("POST", "/containers/id-flux/start"),
("POST", "/containers/id-qwen-image/start"),
])
def test_restore_start_stops_flux_and_starts_restore(self):
def test_restore_start_stops_qwen_image_and_starts_restore(self):
profiles = {name: item(name) for name in controller.ALLOWED}
calls = []
@@ -178,11 +178,11 @@ class ProfileControllerTests(unittest.TestCase):
controller.set_image_worker(True, controller.RESTORE_WORKER)
self.assertEqual(calls, [
("POST", "/containers/id-tts/stop?t=30"),
("POST", "/containers/id-flux/stop?t=20"),
("POST", "/containers/id-qwen-image/stop?t=20"),
("POST", "/containers/id-restore/start"),
])
def test_qwen_image_test_is_allowlisted_and_exclusive(self):
def test_flux_standby_is_allowlisted_and_exclusive(self):
profiles = {name: item(name) for name in controller.ALLOWED}
profiles["medium"] = item("medium", "running")
calls = []
@@ -192,21 +192,21 @@ class ProfileControllerTests(unittest.TestCase):
return 204, b""
with patch.object(controller, "containers", return_value=profiles), \
patch.object(controller, "image_container", return_value=qwen_image_test_item()), \
patch.object(controller, "image_container", return_value=flux_standby_item()), \
patch.object(controller, "image_containers", return_value=[
image_item("running"), restore_item(), qwen_image_test_item()]), \
image_item("running"), restore_item(), flux_standby_item()]), \
patch.object(controller, "tts_container", return_value=tts_item()), \
patch.object(controller, "docker_request", side_effect=request):
result = controller.set_image_worker(
True, controller.QWEN_IMAGE_TEST_WORKER)
True, controller.FLUX_STANDBY_WORKER)
self.assertEqual(result, {
"image_worker": "qwen-image-2.1-test", "state": "running"})
"image_worker": "flux-standby", "state": "running"})
self.assertEqual(calls, [
("POST", "/containers/id-medium/stop?t=120"),
("POST", "/containers/id-tts/stop?t=30"),
("POST", "/containers/id-flux/stop?t=20"),
("POST", "/containers/id-qwen-image-test/start"),
("POST", "/containers/id-qwen-image/stop?t=20"),
("POST", "/containers/id-flux-standby/start"),
])
def test_profile_activation_stops_image_worker_first(self):
@@ -224,7 +224,7 @@ class ProfileControllerTests(unittest.TestCase):
patch.object(controller, "docker_request", side_effect=request):
controller.activate("fast")
self.assertEqual(calls, [
("POST", "/containers/id-flux/stop?t=120"),
("POST", "/containers/id-qwen-image/stop?t=120"),
("POST", "/containers/id-fast/start"),
])
+47
View File
@@ -0,0 +1,47 @@
import importlib.util
import os
import pathlib
import unittest
os.environ.setdefault("WORKER_TOKEN", "x" * 48)
PATH = (pathlib.Path(__file__).parents[1]
/ "platform/docker/qwen-image-worker/qwen_image_worker.py")
SPEC = importlib.util.spec_from_file_location("qwen_image_worker", PATH)
worker = importlib.util.module_from_spec(SPEC)
assert SPEC and SPEC.loader
SPEC.loader.exec_module(worker)
class QwenImageWorkerTests(unittest.TestCase):
def test_text_to_image_uses_empty_latent(self):
workflow = worker.make_workflow("test", 7, 25, 1024, 1024, [], "job")
self.assertEqual(workflow["6"]["inputs"]["latent_image"], ["5", 0])
self.assertIn("5", workflow)
self.assertNotIn("vae", workflow["4"]["inputs"])
def test_edit_uses_reference_latent_and_qwen_dynamic_inputs(self):
workflow = worker.make_workflow(
"edit <image1>", 7, 25, 1024, 1024,
["job-ref-1.png", "job-ref-2.jpg"], "job")
encode = workflow["4"]["inputs"]
self.assertEqual(workflow["6"]["inputs"]["latent_image"], ["4", 2])
self.assertEqual(encode["vae"], ["3", 0])
self.assertEqual(encode["image_1"], ["9", 0])
self.assertEqual(encode["image_2"], ["10", 0])
self.assertNotIn("5", workflow)
def test_router_contract_is_fixed_to_production_parameters(self):
request = {
"prompt": "test", "filename": "result.png", "width": 1024,
"height": 1024, "steps": 25, "guidance": 1.0, "seed": 42,
}
self.assertEqual(worker.validate_request(request)[1:],
("result.png", 1024, 1024, 25, 1.0, 42))
request["steps"] = 4
with self.assertRaisesRegex(ValueError, "steps=25"):
worker.validate_request(request)
if __name__ == "__main__":
unittest.main()