[diffusion] webui: reference to content task and better visualization capabilities (#16017)
This commit is contained in:
@@ -18,23 +18,23 @@ SGLang Diffusion now includes an integrated WebUI. Simply add the `--webui` para
|
||||
### Launch Text-to-Image Service
|
||||
|
||||
```bash
|
||||
SERVER_ARGS=(
|
||||
--model-path black-forest-labs/FLUX.1-dev
|
||||
--num-gpus 2
|
||||
)
|
||||
WEBUI_PORT=2333
|
||||
sglang serve "${SERVER_ARGS[@]}" --webui --webui-port ${WEBUI_PORT}
|
||||
sglang serve black-forest-labs/FLUX.1-dev --num-gpus 1 --webui --webui-port 2333
|
||||
```
|
||||
|
||||
### Launch Text-to-Video Service
|
||||
|
||||
```bash
|
||||
SERVER_ARGS=(
|
||||
--model-path Wan-AI/Wan2.2-T2V-A14B-Diffusers
|
||||
--num-gpus 2
|
||||
)
|
||||
WEBUI_PORT=2333
|
||||
sglang serve "${SERVER_ARGS[@]}" --webui --webui-port ${WEBUI_PORT}
|
||||
sglang serve Wan-AI/Wan2.2-T2V-A14B-Diffusers --num-gpus 1 --webui --webui-port 2333
|
||||
```
|
||||
|
||||
### Launch Image-to-Image Service
|
||||
```bash
|
||||
sglang serve --model-path Qwen/Qwen-Image-Edit-2511 --num-gpus 1 --webui --webui-port 2333
|
||||
```
|
||||
|
||||
### Launch Image-to-Video Service
|
||||
```bash
|
||||
sglang serve Wan-AI/Wan2.2-TI2V-5B-Diffusers --num-gpus 1 --webui --webui-port 2333
|
||||
```
|
||||
|
||||
## Port Forwarding
|
||||
@@ -53,11 +53,6 @@ Learn more about port forwarding: [Port Forwarding](https://en.wikipedia.org/wik
|
||||
|
||||
## 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
|
||||
2. After generation, manually click:
|
||||
- Image output: View generated images
|
||||
- Video output: View generated videos
|
||||
You can view your model path and task name directly in the UI. We'd appreciate any feedback you'd like to share.
|
||||
|
||||
Once launched, access the interface at `http://localhost:${WEBUI_PORT}` in your browser.
|
||||
|
||||
@@ -11,6 +11,9 @@ from sglang.multimodal_gen.runtime.entrypoints.utils import (
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.scheduler_client import sync_scheduler_client
|
||||
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
||||
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
||||
|
||||
logger = init_logger(__name__)
|
||||
|
||||
|
||||
def add_webui_args(parser: argparse.ArgumentParser):
|
||||
@@ -22,15 +25,31 @@ def add_webui_args(parser: argparse.ArgumentParser):
|
||||
|
||||
def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
# import gradio in function to avoid CI crash
|
||||
|
||||
import gradio as gr
|
||||
from huggingface_hub import model_info
|
||||
|
||||
# init client
|
||||
sync_scheduler_client.initialize(server_args)
|
||||
|
||||
task_name = model_info(server_args.model_path).pipeline_tag
|
||||
|
||||
if task_name in ("text-to-video", "image-to-video", "video-to-video"):
|
||||
task_type = "video"
|
||||
elif task_name in ["text-to-image", "image-to-image"]:
|
||||
task_type = "image"
|
||||
else:
|
||||
raise ValueError(
|
||||
f"The task name {task_name} of model {server_args.model_path} is not a valid task name. Please check the model path."
|
||||
)
|
||||
video_visible_only = task_type == "video"
|
||||
image_visible_only = task_type == "image"
|
||||
|
||||
# server_args will be reused in gradio_generate function
|
||||
def gradio_generate(
|
||||
prompt,
|
||||
negative_prompt,
|
||||
reference_image_paths_str,
|
||||
seed,
|
||||
num_frames,
|
||||
frames_per_second,
|
||||
@@ -45,9 +64,20 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
So we use global variable sampling_params_kwargs to avoid pass this param, because gradio does not support this.
|
||||
return [ np.ndarray, None ] | [None, np.ndarray]
|
||||
"""
|
||||
if reference_image_paths_str:
|
||||
if "," in reference_image_paths_str:
|
||||
logger.warning(
|
||||
f"Warning: please use English comma to separate the reference image paths, and the reference image paths is: {reference_image_paths_str}"
|
||||
)
|
||||
reference_image_paths_str = reference_image_paths_str.replace(",", ",")
|
||||
image_path = [path.strip() for path in reference_image_paths_str.split(",")]
|
||||
else:
|
||||
image_path = None
|
||||
|
||||
sampling_params_kwargs = dict(
|
||||
prompt=prompt,
|
||||
negative_prompt=negative_prompt,
|
||||
image_path=image_path,
|
||||
seed=seed,
|
||||
num_frames=num_frames,
|
||||
fps=frames_per_second,
|
||||
@@ -68,6 +98,14 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
)
|
||||
result = sync_scheduler_client.forward([batch])
|
||||
save_file_path = str(os.path.join(batch.output_path, batch.output_file_name))
|
||||
if result.output is None:
|
||||
sampling_params_str = "\n".join(
|
||||
[f"{key}: {value}" for key, value in sampling_params_kwargs.items()]
|
||||
)
|
||||
raise ValueError(
|
||||
f"No output is generated by client, and their sampling params is: {sampling_params_str}"
|
||||
)
|
||||
|
||||
frames = post_process_sample(
|
||||
result.output[0],
|
||||
batch.data_type,
|
||||
@@ -83,7 +121,9 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
gr.Markdown("# 🚀 SGLang Diffusion Application")
|
||||
launched_model = gr.Textbox(label="Model", value=server_args.model_path)
|
||||
with gr.Row():
|
||||
launched_model_box = gr.Textbox(label="Model", value=server_args.model_path)
|
||||
task_name_box = gr.Textbox(label="Task name", value=task_name)
|
||||
|
||||
with gr.Row():
|
||||
with gr.Column(scale=4):
|
||||
@@ -98,12 +138,6 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
num_frames = gr.Slider(
|
||||
minimum=1, maximum=161, value=81, step=1, label="num_frames"
|
||||
)
|
||||
frames_per_second = gr.Slider(
|
||||
minimum=4, maximum=60, value=16, step=1, label="frames_per_second"
|
||||
)
|
||||
width = gr.Number(label="width", precision=0, value=720)
|
||||
height = gr.Number(label="height", precision=0, value=480)
|
||||
num_inference_steps = gr.Slider(
|
||||
@@ -112,21 +146,42 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
guidance_scale = gr.Slider(
|
||||
minimum=0.0, maximum=10, value=5, step=0.01, label="guidance_scale"
|
||||
)
|
||||
num_frames = gr.Slider(
|
||||
minimum=1,
|
||||
maximum=181,
|
||||
value=81,
|
||||
step=1,
|
||||
label="num_frames",
|
||||
visible=video_visible_only,
|
||||
)
|
||||
frames_per_second = gr.Slider(
|
||||
minimum=4,
|
||||
maximum=60,
|
||||
value=16,
|
||||
step=1,
|
||||
label="frames_per_second",
|
||||
visible=video_visible_only,
|
||||
)
|
||||
reference_image_paths_str = gr.Textbox(
|
||||
label="reference images",
|
||||
placeholder="Examples: 'image1.png, image2.png' or 'https://example.com/image1.png, https://example.com/image2.png'",
|
||||
)
|
||||
enable_teacache = gr.Checkbox(label="enable_teacache", value=False)
|
||||
|
||||
with gr.Tabs() as tabs:
|
||||
with gr.TabItem("Image output", id=1):
|
||||
image_out = gr.Image(
|
||||
label="Generated Image",
|
||||
)
|
||||
with gr.TabItem("Video output", id=2):
|
||||
video_out = gr.Video(label="Generated Video")
|
||||
with gr.Column():
|
||||
image_out = gr.Image(
|
||||
label="Generated Image", visible=image_visible_only
|
||||
)
|
||||
video_out = gr.Video(
|
||||
label="Generated Video", visible=video_visible_only
|
||||
)
|
||||
|
||||
run_btn.click(
|
||||
fn=gradio_generate,
|
||||
inputs=[
|
||||
prompt,
|
||||
negative_prompt,
|
||||
reference_image_paths_str,
|
||||
seed,
|
||||
num_frames,
|
||||
frames_per_second,
|
||||
@@ -143,6 +198,7 @@ def run_sgl_diffusion_webui(server_args: ServerArgs):
|
||||
server_port=server_args.webui_port,
|
||||
quiet=True,
|
||||
prevent_thread_lock=True,
|
||||
show_error=True,
|
||||
)
|
||||
|
||||
# print banner
|
||||
|
||||
Reference in New Issue
Block a user