From cdce516331f0ed3d7002114e656c3ac87a804fc3 Mon Sep 17 00:00:00 2001 From: WenhaoZhang <42087078+niehen6174@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:33:18 +0800 Subject: [PATCH] [diffusion] api: add sampling parameters and model info endpoint to OpenAI API (#15071) Co-authored-by: niehen6174 Co-authored-by: Mick Co-authored-by: niehen6174 --- .../sglang/multimodal_gen/docs/openai_api.md | 27 +++++++++++++++++++ .../runtime/entrypoints/http_server.py | 26 +++++++++++++++++- .../runtime/entrypoints/openai/image_api.py | 20 ++++++++++++++ .../runtime/entrypoints/openai/protocol.py | 5 ++++ .../runtime/entrypoints/openai/video_api.py | 14 ++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) diff --git a/python/sglang/multimodal_gen/docs/openai_api.md b/python/sglang/multimodal_gen/docs/openai_api.md index 568104f13..1fc5677ae 100644 --- a/python/sglang/multimodal_gen/docs/openai_api.md +++ b/python/sglang/multimodal_gen/docs/openai_api.md @@ -25,6 +25,33 @@ sglang serve "${SERVER_ARGS[@]}" - **--model-path**: Path to the model or model ID. - **--port**: HTTP port to listen on (default: `30000`). +#### Get Model Information + +**Endpoint:** `GET /models` + +Returns information about the model served by this server, including model path, task type, pipeline configuration, and precision settings. + +**Curl Example:** + +```bash +curl -sS -X GET "http://localhost:30010/models" +``` + +**Response Example:** + +```json +{ + "model_path": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "task_type": "T2V", + "workload_type": "serving", + "pipeline_name": "wan_pipeline", + "pipeline_class": "WanPipeline", + "num_gpus": 4, + "dit_precision": "bf16", + "vae_precision": "fp16" +} +``` + --- ## Endpoints diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/http_server.py b/python/sglang/multimodal_gen/runtime/entrypoints/http_server.py index 9153e3c5d..e44e7b9a0 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/http_server.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/http_server.py @@ -3,7 +3,7 @@ import asyncio from contextlib import asynccontextmanager -from fastapi import APIRouter, FastAPI +from fastapi import APIRouter, FastAPI, Request from sglang.multimodal_gen.runtime.entrypoints.openai import image_api, video_api from sglang.multimodal_gen.runtime.server_args import ServerArgs @@ -40,6 +40,30 @@ async def health(): return {"status": "ok"} +@health_router.get("/models") +async def get_models(request: Request): + """Get information about the model served by this server.""" + from sglang.multimodal_gen.registry import get_model_info + + server_args: ServerArgs = request.app.state.server_args + model_info = get_model_info(server_args.model_path) + + response = { + "model_path": server_args.model_path, + "num_gpus": server_args.num_gpus, + "task_type": server_args.pipeline_config.task_type.name, + "dit_precision": server_args.pipeline_config.dit_precision, + "vae_precision": server_args.pipeline_config.vae_precision, + "workload_type": server_args.workload_type.value, + } + + if model_info: + response["pipeline_name"] = model_info.pipeline_cls.pipeline_name + response["pipeline_class"] = model_info.pipeline_cls.__name__ + + return response + + @health_router.get("/health_generate") async def health_generate(): # TODO : health generate endpoint diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py b/python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py index 1ac397f1c..73a4ad88a 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py @@ -55,6 +55,10 @@ def _build_sampling_params_from_request( image_path: Optional[str] = None, seed: Optional[int] = None, generator_device: Optional[str] = None, + negative_prompt: Optional[str] = None, + guidance_scale: Optional[float] = None, + num_inference_steps: Optional[int] = None, + enable_teacache: Optional[bool] = None, ) -> SamplingParams: if size is None: width, height = None, None @@ -77,6 +81,10 @@ def _build_sampling_params_from_request( output_file_name=f"{request_id}.{ext}", seed=seed, generator_device=generator_device, + guidance_scale=guidance_scale, + num_inference_steps=num_inference_steps, + enable_teacache=enable_teacache, + **({"negative_prompt": negative_prompt} if negative_prompt is not None else {}), ) return sampling_params @@ -118,6 +126,10 @@ async def generations( background=request.background, seed=request.seed, generator_device=request.generator_device, + negative_prompt=request.negative_prompt, + guidance_scale=request.guidance_scale, + num_inference_steps=request.num_inference_steps, + enable_teacache=request.enable_teacache, ) batch = prepare_request( server_args=get_global_server_args(), @@ -169,6 +181,10 @@ async def edits( seed: Optional[int] = Form(1024), generator_device: Optional[str] = Form("cuda"), user: Optional[str] = Form(None), + negative_prompt: Optional[str] = Form(None), + guidance_scale: Optional[float] = Form(None), + num_inference_steps: Optional[int] = Form(None), + enable_teacache: Optional[bool] = Form(False), ): request_id = generate_request_id() # Resolve images from either `image` or `image[]` (OpenAI SDK sends `image[]` when list is provided) @@ -198,6 +214,10 @@ async def edits( image_path=input_paths, seed=seed, generator_device=generator_device, + negative_prompt=negative_prompt, + guidance_scale=guidance_scale, + num_inference_steps=num_inference_steps, + enable_teacache=enable_teacache, ) batch = _build_req_from_sampling(sampling) diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/openai/protocol.py b/python/sglang/multimodal_gen/runtime/entrypoints/openai/protocol.py index 8675b038c..610f00415 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/openai/protocol.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/openai/protocol.py @@ -29,6 +29,10 @@ class ImageGenerationsRequest(BaseModel): seed: Optional[int] = 1024 generator_device: Optional[str] = "cuda" user: Optional[str] = None + negative_prompt: Optional[str] = None + guidance_scale: Optional[float] = None + num_inference_steps: Optional[int] = None + enable_teacache: Optional[bool] = False # Video API protocol models @@ -62,6 +66,7 @@ class VideoGenerationsRequest(BaseModel): guidance_scale: Optional[float] = None guidance_scale_2: Optional[float] = None negative_prompt: Optional[str] = None + enable_teacache: Optional[bool] = False class VideoListResponse(BaseModel): diff --git a/python/sglang/multimodal_gen/runtime/entrypoints/openai/video_api.py b/python/sglang/multimodal_gen/runtime/entrypoints/openai/video_api.py index 72b08e6ed..f613e05b6 100644 --- a/python/sglang/multimodal_gen/runtime/entrypoints/openai/video_api.py +++ b/python/sglang/multimodal_gen/runtime/entrypoints/openai/video_api.py @@ -82,6 +82,8 @@ def _build_sampling_params_from_request( sampling_kwargs["guidance_scale_2"] = request.guidance_scale_2 if request.negative_prompt is not None: sampling_kwargs["negative_prompt"] = request.negative_prompt + if request.enable_teacache is not None: + sampling_kwargs["enable_teacache"] = request.enable_teacache sampling_params = SamplingParams.from_user_sampling_params_args( model_path=server_args.model_path, server_args=server_args, @@ -139,6 +141,12 @@ async def create_video( size: Optional[str] = Form(None), fps: Optional[int] = Form(None), num_frames: Optional[int] = Form(None), + seed: Optional[int] = Form(1024), + generator_device: Optional[str] = Form("cuda"), + negative_prompt: Optional[str] = Form(None), + guidance_scale: Optional[float] = Form(None), + num_inference_steps: Optional[int] = Form(None), + enable_teacache: Optional[bool] = Form(False), extra_body: Optional[str] = Form(None), ): content_type = request.headers.get("content-type", "").lower() @@ -180,6 +188,12 @@ async def create_video( size=size, fps=fps_val, num_frames=num_frames_val, + seed=seed, + generator_device=generator_device, + negative_prompt=negative_prompt, + guidance_scale=guidance_scale, + num_inference_steps=num_inference_steps, + enable_teacache=enable_teacache, ) else: try: