22# (https://github.com/sgl-project/sglang/blob/main/python/sglang/multimodal_gen/runtime/entrypoints/http_server.py)
33
44from contextlib import asynccontextmanager
5- from collections .abc import AsyncIterator
5+ from collections .abc import AsyncIterator , Callable
66import os
77
88import uvicorn
1818 clear_state ,
1919 set_state ,
2020)
21- from fastvideo .entrypoints .openai .serving_engine import OpenAIServingEngine
21+ from fastvideo .entrypoints .openai .serving_engine import OpenAIServingEngine , ServingGenerator
22+ from fastvideo .entrypoints .openai .protocol import VideoGenerationRequest
2223from fastvideo .entrypoints .video_generator import VideoGenerator
2324from fastvideo .fastvideo_args import FastVideoArgs
2425from fastvideo .logger import init_logger
@@ -60,10 +61,13 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
6061 served_model_name : str | None = app .state .served_model_name
6162 default_request : GenerationRequest | None = getattr (app .state , "default_request" , None )
6263
63- logger .info ("Loading model from %s ..." , args .model_path )
64- generator = VideoGenerator .from_fastvideo_args (args )
65- serving_engine = OpenAIServingEngine (generator )
66- logger .info ("Model loaded successfully." )
64+ logger .info ("Initializing %s generation runtime for %s ..." , app .state .runtime , args .model_path )
65+ # A non-CUDA runtime (e.g. MLX) supplies its own generator_factory instead
66+ # of the default VideoGenerator/Executor path -- see MLXWanGenerator.
67+ factory = app .state .generator_factory
68+ generator = factory () if factory is not None else VideoGenerator .from_fastvideo_args (args )
69+ serving_engine = OpenAIServingEngine (generator , app .state .video_request_validator )
70+ logger .info ("Generation runtime ready." )
6771
6872 set_state (
6973 generator ,
@@ -91,8 +95,18 @@ def create_app(
9195 output_dir : str = DEFAULT_OUTPUT_DIR ,
9296 default_request : GenerationRequest | None = None ,
9397 served_model_name : str | None = None ,
98+ * ,
99+ generator_factory : Callable [[], ServingGenerator ] | None = None ,
100+ video_request_validator : Callable [[VideoGenerationRequest ], None ] | None = None ,
101+ runtime : str = "cuda" ,
94102) -> FastAPI :
95- """Build the FastAPI application with all routers mounted"""
103+ """Build the FastAPI application with all routers mounted.
104+
105+ ``generator_factory``/``video_request_validator``/``runtime`` let a
106+ non-CUDA backend (MLX) plug in its own generator and request rules
107+ without a separate app-building path. Defaults reproduce the original
108+ CUDA-only behavior exactly.
109+ """
96110
97111 app = FastAPI (
98112 title = "FastVideo OpenAI-Compatible API" ,
@@ -103,6 +117,9 @@ def create_app(
103117 app .state .output_dir = output_dir
104118 app .state .default_request = default_request
105119 app .state .served_model_name = served_model_name
120+ app .state .generator_factory = generator_factory
121+ app .state .video_request_validator = video_request_validator
122+ app .state .runtime = runtime
106123
107124 app .add_middleware (
108125 CORSMiddleware ,
@@ -148,7 +165,10 @@ async def openai_validation_error(_request: Request, exc: RequestValidationError
148165
149166 app .include_router (common_router )
150167 app .include_router (video_router )
151- app .include_router (image_router )
168+ # The MLX runtime only wires video-with-audio generation (see
169+ # fastvideo/mlx_runtime/); image generation has no MLX backend yet.
170+ if runtime != "mlx" :
171+ app .include_router (image_router )
152172
153173 @app .get ("/health" )
154174 async def health ():
0 commit comments