3030 search_models ,
3131 set_huggingface_token ,
3232 get_huggingface_token ,
33- get_model_details ,
3433 extract_quantization ,
3534 list_grouped_safetensors_downloads ,
3635 get_safetensors_manifest_entries ,
@@ -213,6 +212,27 @@ class SafetensorsBundleRequest(BaseModel):
213212 files : List [Dict [str , Any ]]
214213
215214
215+ _param_registry_cache : Dict [str , tuple ] = {}
216+ _PARAM_REGISTRY_CACHE_TTL = 30.0
217+
218+
219+ def _param_registry_cache_key (store , engine : str ) -> str :
220+ active = store .get_active_engine_version (engine ) if engine in (
221+ "llama_cpp" ,
222+ "ik_llama" ,
223+ "lmdeploy" ,
224+ ) else None
225+ version = (active or {}).get ("version" ) or ""
226+ catalog_mtime = 0.0
227+ try :
228+ catalog_mtime = os .path .getmtime (
229+ os .path .join (store ._config_dir , "engine_params_catalog.yaml" )
230+ )
231+ except OSError :
232+ pass
233+ return f"{ engine } :{ version } :{ catalog_mtime } "
234+
235+
216236@router .get ("/param-registry" )
217237async def get_param_registry_endpoint (engine : str = "llama_cpp" ):
218238 """Return param definitions from ``engine_params_catalog.yaml`` plus studio-only fields (read-only)."""
@@ -223,8 +243,16 @@ async def get_param_registry_endpoint(engine: str = "llama_cpp"):
223243 from backend .studio_engine_fields import studio_sections_for_engine
224244
225245 store = get_store ()
246+ cache_key = _param_registry_cache_key (store , engine )
247+ now = time .monotonic ()
248+ cached = _param_registry_cache .get (cache_key )
249+ if cached and now - cached [1 ] < _PARAM_REGISTRY_CACHE_TTL :
250+ return cached [0 ]
251+
226252 if engine not in ("llama_cpp" , "ik_llama" , "lmdeploy" ):
227- return registry_payload_from_entry (engine , None , [], has_active_engine = False )
253+ payload = registry_payload_from_entry (engine , None , [], has_active_engine = False )
254+ _param_registry_cache [cache_key ] = (payload , now )
255+ return payload
228256
229257 studio = studio_sections_for_engine (engine )
230258 active = store .get_active_engine_version (engine )
@@ -239,9 +267,11 @@ async def get_param_registry_endpoint(engine: str = "llama_cpp"):
239267 if active and active .get ("version" ):
240268 entry = get_version_entry (store , engine , active ["version" ])
241269
242- return registry_payload_from_entry (
270+ payload = registry_payload_from_entry (
243271 engine , entry , studio , has_active_engine = has_active
244272 )
273+ _param_registry_cache [cache_key ] = (payload , now )
274+ return payload
245275
246276
247277@router .get ("" )
@@ -803,15 +833,16 @@ async def update_model_projector(
803833 }
804834
805835
806- @router .get ("/{model_id:path}/limits" )
807- async def get_model_limits (model_id : str ):
836+ _limits_cache : Dict [str , tuple ] = {}
837+ _LIMITS_CACHE_TTL = 300.0
838+
839+
840+ def _compute_model_limits (model : Dict [str , Any ]) -> Dict [str , Optional [int ]]:
808841 """
809842 Return model limits in an engine-agnostic way. For GGUF models with a manifest
810843 entry, uses the GGUF manifest; for safetensors, uses the safetensors manifest.
811844 Otherwise falls back to the Hugging Face model card (config.json / model info).
812845 """
813- store = get_store ()
814- model = _get_model_or_404 (store , model_id )
815846 hf_id = model .get ("huggingface_id" )
816847 if not hf_id :
817848 return {"max_context_length" : None , "layer_count" : None }
@@ -828,7 +859,9 @@ async def get_model_limits(model_id: str):
828859
829860 if max_ctx is None or layer_count is None :
830861 try :
831- details = await get_model_details (hf_id )
862+ from backend .huggingface import _get_model_details_blocking
863+
864+ details = _get_model_details_blocking (hf_id )
832865 config = details .get ("config" ) or {}
833866 if max_ctx is None :
834867 hf_max = details .get ("model_max_length" ) or config .get (
@@ -840,15 +873,27 @@ async def get_model_limits(model_id: str):
840873 for key in ("num_hidden_layers" , "n_layer" , "num_layers" ):
841874 val = config .get (key )
842875 if isinstance (val , (int , float )) and val > 0 :
843- layer_count = (
844- int (val ) + 1
845- ) # + output head for n_gpu_layers hint
876+ layer_count = int (val ) + 1
846877 break
847878 except Exception :
848879 pass
849880 return {"max_context_length" : max_ctx , "layer_count" : layer_count }
850881
851882
883+ @router .get ("/{model_id:path}/limits" )
884+ async def get_model_limits (model_id : str ):
885+ now = time .monotonic ()
886+ cached = _limits_cache .get (model_id )
887+ if cached and now - cached [1 ] < _LIMITS_CACHE_TTL :
888+ return cached [0 ]
889+
890+ store = get_store ()
891+ model = _get_model_or_404 (store , model_id )
892+ payload = await asyncio .to_thread (_compute_model_limits , model )
893+ _limits_cache [model_id ] = (payload , now )
894+ return payload
895+
896+
852897@router .get ("/{model_id:path}/config" )
853898async def get_model_config (model_id : str ):
854899 """Get model's llama.cpp configuration"""
0 commit comments