diff --git a/python/sglang/multimodal_gen/apps/webui/README.md b/python/sglang/multimodal_gen/apps/webui/README.md index 8f64c3918..104070af8 100644 --- a/python/sglang/multimodal_gen/apps/webui/README.md +++ b/python/sglang/multimodal_gen/apps/webui/README.md @@ -1,17 +1,22 @@ # SGLang Diffusion WebUI User Guide -SGLang Diffusion WebUI provides an intuitive Gradio-based interface for image and video generation, supporting parameter tuning and real-time previews. +SGLang Diffusion WebUI provides an intuitive Gradio-based interface for image and video generation, supporting parameter +tuning and real-time previews. ## Prerequisites + The WebUI runs on Gradio. To get started, install Gradio first: + ```bash pip install gradio==6.1.0 ``` ## Launch WebUI Service + SGLang Diffusion now includes an integrated WebUI. Simply add the `--webui` parameter when starting the service. ### Launch Text-to-Image Service + ```bash SERVER_ARGS=( --model-path black-forest-labs/FLUX.1-dev @@ -20,7 +25,9 @@ SERVER_ARGS=( WEBUI_PORT=2333 sglang serve "${SERVER_ARGS[@]}" --webui --webui-port ${WEBUI_PORT} ``` + ### Launch Text-to-Video Service + ```bash SERVER_ARGS=( --model-path Wan-AI/Wan2.2-T2V-A14B-Diffusers @@ -31,23 +38,26 @@ sglang serve "${SERVER_ARGS[@]}" --webui --webui-port ${WEBUI_PORT} ``` ## Port Forwarding -Once the WebUI service is running, you need to use **SSH port forwarding** to securely access the remote service from your local machine. -In most cases:​ Your IDE (like VS Code, Cursor, etc.) can handle this automatically. Check your IDE's remote development or port forwarding features. Otherwise, execute this command manually. +Once the WebUI service is running, you need to use **SSH port forwarding** to securely access the remote service from +your local machine. + +In most cases: Your IDE (like VS Code, Cursor, etc.) can handle this automatically. Check your IDE's remote development +or port forwarding features. Otherwise, execute this command manually. ```bash ssh -L ${WEBUI_PORT}:localhost:${WEBUI_PORT} user_name@machine_name ``` -Learn more about port forwarding:​ [Port Forwarding](https://en.wikipedia.org/wiki/Port_forwarding). +Learn more about port forwarding: [Port Forwarding](https://en.wikipedia.org/wiki/Port_forwarding). ## Interface Instructions 1. Task mode is automatically determined by the `num_frames` parameter: - - num_frames = 1: Text-to-Image mode - - num_frames > 1: Text-to-Video mode + - num_frames = 1: Text-to-Image mode + - num_frames > 1: Text-to-Video mode 2. After generation, manually click: - - Image output: View generated images - - Video output: View generated videos + - Image output: View generated images + - Video output: View generated videos Once launched, access the interface at `http://localhost:${WEBUI_PORT}` in your browser. diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py b/python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py index 23d05e5dd..c42e1515d 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py @@ -232,6 +232,7 @@ class DiffGenerator: sample, fps=req.fps, save_output=req.save_output, + # TODO: output file path for req should be determined save_file_path=req.output_file_path( num_outputs, output_idx ), diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/utils.py b/python/sglang/multimodal_gen/runtime/entrypoints/utils.py index 2d2f2f9ca..0789605df 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/utils.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/utils.py @@ -91,7 +91,7 @@ def post_process_sample( ) else: imageio.imwrite(save_file_path, frames[0]) - logger.info(f"Saved output to {CYAN}{save_file_path}{RESET}") + logger.info(f"Output saved to {CYAN}{save_file_path}{RESET}") else: logger.info(f"No output path provided, output not saved") diff --git a/python/sglang/multimodal_gen/test/run_suite.py b/python/sglang/multimodal_gen/test/run_suite.py index 42f78e469..eaa103a6b 100644 --- a/python/sglang/multimodal_gen/test/run_suite.py +++ b/python/sglang/multimodal_gen/test/run_suite.py @@ -99,7 +99,7 @@ def run_pytest(files, filter_expr=None): print("No files to run.") return 0 - base_cmd = [sys.executable, "-m", "pytest", "-s", "-v", "--log-cli-level=INFO"] + base_cmd = [sys.executable, "-m", "pytest", "-s", "-v"] # Add pytest -k filter if provided if filter_expr: @@ -124,20 +124,20 @@ def run_pytest(files, filter_expr=None): cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, - bufsize=1, + bufsize=0, ) - output_lines = [] + output_bytes = bytearray() while True: - line = process.stdout.readline() - if not line and process.poll() is not None: + chunk = process.stdout.read(4096) + if not chunk: break - if line: - sys.stdout.write(line) - output_lines.append(line) + sys.stdout.buffer.write(chunk) + sys.stdout.buffer.flush() + output_bytes.extend(chunk) - returncode = process.poll() + process.wait() + returncode = process.returncode if returncode == 0: return 0 @@ -152,7 +152,7 @@ def run_pytest(files, filter_expr=None): return 0 # check if the failure is due to an assertion in test_server_utils.py - full_output = "".join(output_lines) + full_output = output_bytes.decode("utf-8", errors="replace") is_perf_assertion = ( "multimodal_gen/test/server/test_server_utils.py" in full_output and "AssertionError" in full_output diff --git a/python/sglang/multimodal_gen/test/server/test_server_utils.py b/python/sglang/multimodal_gen/test/server/test_server_utils.py index 2aea02a2f..819953164 100644 --- a/python/sglang/multimodal_gen/test/server/test_server_utils.py +++ b/python/sglang/multimodal_gen/test/server/test_server_utils.py @@ -322,6 +322,7 @@ class ServerManager: with pipe: for line in iter(pipe.readline, ""): sys.stdout.write(line) + sys.stdout.flush() file.write(line) file.flush() except Exception as e: @@ -360,6 +361,8 @@ class ServerManager: """Wait for server to become ready.""" start = time.time() ready_message = "Application startup complete." + log_period = 30 + prev_log_period_count = 0 while time.time() - start < self.wait_deadline: if process.poll() is not None: @@ -378,8 +381,10 @@ class ServerManager: logger.debug("Could not read log yet: %s", e) elapsed = int(time.time() - start) - logger.info("[server-test] Waiting for server... elapsed=%ss", elapsed) - time.sleep(5) + if (elapsed // log_period) > prev_log_period_count: + prev_log_period_count = elapsed // log_period + logger.info("[server-test] Waiting for server... elapsed=%ss", elapsed) + time.sleep(1) tail = self._get_log_tail(stdout_path) raise TimeoutError(f"Server not ready within {self.wait_deadline}s.\n{tail}")