44import os .path
55import app .api .globals as cms_globals
66
7- from typing import Dict , Any , Optional , Union , Type
7+ from typing import Dict , Any , Optional
88from concurrent .futures import ThreadPoolExecutor
99from anyio .lowlevel import RunVar
1010from anyio import CapacityLimiter
1818from app .api .auth .db import make_sure_db_and_tables
1919from app .api .auth .users import Props
2020from app .api .dependencies import ModelServiceDep
21- from app .api .utils import add_exception_handlers , add_rate_limiter , init_vllm_engine
21+ from app .api .utils import (
22+ add_exception_handlers ,
23+ add_rate_limiter ,
24+ init_vllm_engine ,
25+ init_sglang_engine ,
26+ ForwardedPrefixMiddleware ,
27+ )
2228from app .config import Settings
23- from app .domain import Tags , TagsStreamable , TagsGenerative
2429from app .management .tracker_client import TrackerClient
2530from app .utils import get_settings , unpack_model_data_package , get_model_data_package_base_name
2631from app .exception import ConfigurationException
2934logging .getLogger ("asyncio" ).setLevel (logging .ERROR )
3035logger = logging .getLogger ("cms" )
3136
32-
3337def get_model_server (config : Settings , msd_overwritten : Optional [ModelServiceDep ] = None ) -> FastAPI :
3438 """
3539 Initialises a FastAPI app instance configured for the CMS model service.
@@ -111,7 +115,10 @@ def get_stream_server(config: Settings, msd_overwritten: Optional[ModelServiceDe
111115 return app
112116
113117
114- def get_generative_server (config : Settings , msd_overwritten : Optional [ModelServiceDep ] = None ) -> FastAPI :
118+ def get_generative_server (
119+ config : Settings ,
120+ msd_overwritten : Optional [ModelServiceDep ] = None ,
121+ ) -> FastAPI :
115122 """
116123 Initialises a FastAPI instance configured for a generative server.
117124
@@ -134,6 +141,9 @@ def get_generative_server(config: Settings, msd_overwritten: Optional[ModelServi
134141 if config .ENABLE_TRAINING_APIS == "true" :
135142 app = _load_supervised_training_router (app )
136143 logger .debug ("Supervised training router loaded" )
144+ if config .DISABLE_UNSUPERVISED_TRAINING != "true" :
145+ app = _load_unsupervised_training_router (app )
146+ logger .debug ("Unsupervised training router loaded" )
137147 app = _load_training_operations (app )
138148
139149 if config .AUTH_USER_ENABLED == "true" :
@@ -147,25 +157,71 @@ def get_generative_server(config: Settings, msd_overwritten: Optional[ModelServi
147157
148158 return app
149159
150- def get_vllm_server (config : Settings , model_package_path : str , model_name : str , log_level : str = "info" ) -> FastAPI :
160+ def get_vllm_server (
161+ config : Settings ,
162+ model_package_path : str ,
163+ model_name : str ,
164+ log_level : str = "info" ,
165+ server_args : Optional [str ] = None ,
166+ ) -> FastAPI :
151167 """
152168 Initialises a FastAPI instance configured for a vLLM server.
153169
154170 Args:
155171 config (Settings): The CMS configuration.
156172 model_package_path (str): The path to the model package file.
157173 model_name (str): The name of the model.
158- log_level (str): The log level for the VLLM engine. Default to "info".
174+ log_level (str): The log level for the vLLM engine. Default to "info".
175+ server_args (Optional[str]): The arguments to pass to the vLLM engine.
176+
177+ Returns:
178+ FastAPI: A FastAPI app instance.
179+ """
180+
181+ app = _get_app (None , streamable = False )
182+ model_dir_path = os .path .join (
183+ os .path .dirname (model_package_path ), get_model_data_package_base_name (model_package_path )
184+ )
185+ if unpack_model_data_package (model_package_path , model_dir_path ):
186+ async def _startup () -> None :
187+ await init_vllm_engine (app , config , model_dir_path , model_name , log_level , server_args )
188+
189+ app .add_event_handler ("startup" , _startup )
190+ else :
191+ raise ConfigurationException (f"Model package archive format is not supported: { model_package_path } " )
192+
193+ return app
159194
195+
196+ def get_sglang_server (
197+ config : Settings ,
198+ model_package_path : str ,
199+ model_name : str ,
200+ log_level : str = "info" ,
201+ server_args : Optional [str ] = None ,
202+ ) -> FastAPI :
203+ """
204+ Initialises a FastAPI instance configured for an SGLang server.
205+
206+ Args:
207+ config (Settings): The CMS configuration.
208+ model_package_path (str): The path to the model package file.
209+ model_name (str): The name of the model.
210+ log_level (str): The log level for the SGLang engine. Default to "info".
211+ server_args (Optional[str]): The arguments to pass to the SGLang engine.
160212 Returns:
161213 FastAPI: A FastAPI app instance.
162214 """
163215
164216 app = _get_app (None , streamable = False )
165- model_dir_path = os .path .join (os .path .dirname (model_package_path ), get_model_data_package_base_name (model_package_path ))
217+ model_dir_path = os .path .join (
218+ os .path .dirname (model_package_path ), get_model_data_package_base_name (model_package_path )
219+ )
166220 if unpack_model_data_package (model_package_path , model_dir_path ):
167- loop = asyncio .get_event_loop ()
168- app = loop .run_until_complete (init_vllm_engine (app , model_dir_path , model_name , log_level ))
221+ async def _startup () -> None :
222+ await init_sglang_engine (app , config , model_dir_path , model_name , log_level , server_args )
223+
224+ app .add_event_handler ("startup" , _startup )
169225 else :
170226 raise ConfigurationException (f"Model package archive format is not supported: { model_package_path } " )
171227
@@ -204,32 +260,21 @@ def _get_app(
204260 generative : bool = False ,
205261) -> FastAPI :
206262 config = get_settings ()
207- tags : Union [Type [Tags ], Type [TagsStreamable ], Type [TagsGenerative ]]
208- if generative :
209- tags = TagsGenerative
210- elif streamable :
211- tags = TagsStreamable
212- else :
213- tags = Tags
214- tags_metadata = [{
215- "name" : tag .name ,
216- "description" : tag .value
217- } for tag in tags ]
263+
218264 app = FastAPI (
219265 title = "CogStack ModelServe" ,
220266 summary = "A model serving and governance system for CogStack NLP solutions" ,
221267 docs_url = None ,
222268 redoc_url = None ,
223269 debug = (config .DEBUG == "true" ),
224- openapi_tags = tags_metadata ,
225270 )
271+
272+ app .add_middleware (ForwardedPrefixMiddleware ) # type: ignore
226273 add_exception_handlers (app )
227274
228- instrumentator = None
229- if not generative :
230- instrumentator = Instrumentator (
231- excluded_handlers = ["/docs" , "/redoc" , "/metrics" , "/openapi.json" , "/favicon.ico" , "none" ]
232- ).instrument (app )
275+ instrumentator = Instrumentator (
276+ excluded_handlers = ["/docs" , "/redoc" , "/metrics" , "/openapi.json" , "/favicon.ico" , "none" ]
277+ ).instrument (app )
233278
234279 if msd_overwritten is not None :
235280 cms_globals .model_service_dep = msd_overwritten
@@ -279,8 +324,9 @@ async def redoc_doc(req: Request) -> HTMLResponse:
279324 )
280325
281326 @app .get ("/" , include_in_schema = False )
282- async def root_redirect () -> RedirectResponse :
283- return RedirectResponse (url = "/docs" )
327+ async def root_redirect (req : Request ) -> RedirectResponse :
328+ root_path = req .scope .get ("root_path" , "" ).rstrip ("/" )
329+ return RedirectResponse (url = f"{ req .url .scheme } ://{ req .url .netloc } { root_path } /docs" )
284330
285331 @app .on_event ("shutdown" )
286332 async def on_shutdown () -> None :
0 commit comments