[diffusion] api: add sampling parameters and model info endpoint to OpenAI API (#15071)
Co-authored-by: niehen6174 <niehen.6174@gmail.com> Co-authored-by: Mick <mickjagger19@icloud.com> Co-authored-by: niehen6174 <nihen6174@gmail.com>
This commit is contained in:
co-authored by
niehen6174
Mick
niehen6174
parent
79ab57bd7a
commit
cdce516331
@@ -25,6 +25,33 @@ sglang serve "${SERVER_ARGS[@]}"
|
|||||||
- **--model-path**: Path to the model or model ID.
|
- **--model-path**: Path to the model or model ID.
|
||||||
- **--port**: HTTP port to listen on (default: `30000`).
|
- **--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
|
## Endpoints
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from contextlib import asynccontextmanager
|
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.entrypoints.openai import image_api, video_api
|
||||||
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
||||||
@@ -40,6 +40,30 @@ async def health():
|
|||||||
return {"status": "ok"}
|
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")
|
@health_router.get("/health_generate")
|
||||||
async def health_generate():
|
async def health_generate():
|
||||||
# TODO : health generate endpoint
|
# TODO : health generate endpoint
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ def _build_sampling_params_from_request(
|
|||||||
image_path: Optional[str] = None,
|
image_path: Optional[str] = None,
|
||||||
seed: Optional[int] = None,
|
seed: Optional[int] = None,
|
||||||
generator_device: Optional[str] = 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:
|
) -> SamplingParams:
|
||||||
if size is None:
|
if size is None:
|
||||||
width, height = None, None
|
width, height = None, None
|
||||||
@@ -77,6 +81,10 @@ def _build_sampling_params_from_request(
|
|||||||
output_file_name=f"{request_id}.{ext}",
|
output_file_name=f"{request_id}.{ext}",
|
||||||
seed=seed,
|
seed=seed,
|
||||||
generator_device=generator_device,
|
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
|
return sampling_params
|
||||||
|
|
||||||
@@ -118,6 +126,10 @@ async def generations(
|
|||||||
background=request.background,
|
background=request.background,
|
||||||
seed=request.seed,
|
seed=request.seed,
|
||||||
generator_device=request.generator_device,
|
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(
|
batch = prepare_request(
|
||||||
server_args=get_global_server_args(),
|
server_args=get_global_server_args(),
|
||||||
@@ -169,6 +181,10 @@ async def edits(
|
|||||||
seed: Optional[int] = Form(1024),
|
seed: Optional[int] = Form(1024),
|
||||||
generator_device: Optional[str] = Form("cuda"),
|
generator_device: Optional[str] = Form("cuda"),
|
||||||
user: Optional[str] = Form(None),
|
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()
|
request_id = generate_request_id()
|
||||||
# Resolve images from either `image` or `image[]` (OpenAI SDK sends `image[]` when list is provided)
|
# 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,
|
image_path=input_paths,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
generator_device=generator_device,
|
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)
|
batch = _build_req_from_sampling(sampling)
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class ImageGenerationsRequest(BaseModel):
|
|||||||
seed: Optional[int] = 1024
|
seed: Optional[int] = 1024
|
||||||
generator_device: Optional[str] = "cuda"
|
generator_device: Optional[str] = "cuda"
|
||||||
user: Optional[str] = None
|
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
|
# Video API protocol models
|
||||||
@@ -62,6 +66,7 @@ class VideoGenerationsRequest(BaseModel):
|
|||||||
guidance_scale: Optional[float] = None
|
guidance_scale: Optional[float] = None
|
||||||
guidance_scale_2: Optional[float] = None
|
guidance_scale_2: Optional[float] = None
|
||||||
negative_prompt: Optional[str] = None
|
negative_prompt: Optional[str] = None
|
||||||
|
enable_teacache: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class VideoListResponse(BaseModel):
|
class VideoListResponse(BaseModel):
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ def _build_sampling_params_from_request(
|
|||||||
sampling_kwargs["guidance_scale_2"] = request.guidance_scale_2
|
sampling_kwargs["guidance_scale_2"] = request.guidance_scale_2
|
||||||
if request.negative_prompt is not None:
|
if request.negative_prompt is not None:
|
||||||
sampling_kwargs["negative_prompt"] = request.negative_prompt
|
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(
|
sampling_params = SamplingParams.from_user_sampling_params_args(
|
||||||
model_path=server_args.model_path,
|
model_path=server_args.model_path,
|
||||||
server_args=server_args,
|
server_args=server_args,
|
||||||
@@ -139,6 +141,12 @@ async def create_video(
|
|||||||
size: Optional[str] = Form(None),
|
size: Optional[str] = Form(None),
|
||||||
fps: Optional[int] = Form(None),
|
fps: Optional[int] = Form(None),
|
||||||
num_frames: 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),
|
extra_body: Optional[str] = Form(None),
|
||||||
):
|
):
|
||||||
content_type = request.headers.get("content-type", "").lower()
|
content_type = request.headers.get("content-type", "").lower()
|
||||||
@@ -180,6 +188,12 @@ async def create_video(
|
|||||||
size=size,
|
size=size,
|
||||||
fps=fps_val,
|
fps=fps_val,
|
||||||
num_frames=num_frames_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:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user