wuenlp_tools.config
1from __future__ import annotations 2 3import json 4import os 5from dataclasses import dataclass 6from pathlib import Path 7from typing import Any, Dict, Optional, Union 8 9from wuenlp_tools.utils import _UserPath 10 11__all__ = [ 12 "APIConfig", 13 "api_config", 14 "set_api_base_url", 15 "get_api_base_url", 16 "get_endpoint_url", 17 "LightLLMProxyConfig", 18 "LocalLLMConfig", 19 "WUENLP_DATA_DIR", 20 "read_llm_config", 21 "write_llm_config", 22 "get_lightllm_config", 23 "get_local_llm_config", 24 "get_pull_lock_dir", 25 "get_litellm_metadata", 26 "configure_lightllm_proxy", 27 "show_lightllm_status", 28 "get_ssc_repo_root", 29 "get_ssc_scene_model_path", 30 "get_ssc_suspense_model_root", 31 "read_ssc_config", 32 "write_ssc_config", 33] 34 35 36class APIConfig: 37 """Global configuration for WueNLP API endpoints.""" 38 39 _instance: Optional["APIConfig"] = None 40 41 def __init__(self): 42 self._base_url: str = os.getenv( 43 "WUENLP_API_BASE_URL", "https://wuenlp-api.professor-x.de" 44 ) 45 46 @classmethod 47 def get_instance(cls) -> "APIConfig": 48 """Get singleton instance of APIConfig.""" 49 if cls._instance is None: 50 cls._instance = cls() 51 return cls._instance 52 53 @property 54 def base_url(self) -> str: 55 """Get the base URL for WueNLP API.""" 56 return self._base_url 57 58 @base_url.setter 59 def base_url(self, value: str) -> None: 60 """Set the base URL for WueNLP API.""" 61 if value.endswith("/"): 62 value = value.rstrip("/") 63 self._base_url = value 64 65 def get_endpoint_url(self, endpoint: str) -> str: 66 """Get full URL for a specific endpoint.""" 67 if not endpoint.startswith("/"): 68 endpoint = "/" + endpoint 69 if not endpoint.endswith("/"): 70 endpoint = endpoint + "/" 71 return f"{self._base_url}{endpoint}" 72 73 74# Global instance 75api_config = APIConfig.get_instance() 76 77 78def set_api_base_url(url: str) -> None: 79 """Set the global API base URL.""" 80 api_config.base_url = url 81 82 83def get_api_base_url() -> str: 84 """Get the global API base URL.""" 85 return api_config.base_url 86 87 88def get_endpoint_url(endpoint: str) -> str: 89 """Get full URL for a specific endpoint.""" 90 return api_config.get_endpoint_url(endpoint) 91 92 93# LLM Configuration 94WUENLP_DATA_DIR = _UserPath.home() / ".local/share/wuenlp-tools" 95LLM_CONFIG_PATH = WUENLP_DATA_DIR / "llm_config.json" 96DEFAULT_PULL_LOCK_DIR = WUENLP_DATA_DIR / "pull-locks" 97PROJECT_LLM_CONFIG_CANDIDATES = ( 98 ".wuenlp_llm_config.json", 99 "wuenlp_llm_config.json", 100) 101 102 103@dataclass 104class LightLLMProxyConfig: 105 enabled: bool = False 106 base_url: str = "http://localhost:8080/v1/" 107 model_prefixes: Optional[Dict[str, str]] = None 108 109 def __post_init__(self): 110 if self.model_prefixes is None: 111 self.model_prefixes = { 112 "openai": "openai/", 113 "openrouter": "openrouter/", 114 "ollama": "ollama/", 115 "local": "ollama/", 116 } 117 118 119@dataclass 120class LocalLLMConfig: 121 base_url: Optional[str] = None 122 port: Union[str, int] = "auto" 123 auto_pull: bool = True 124 manage_process: Union[str, bool] = "auto" 125 pull_lock_dir: Optional[str] = None 126 127 128def read_llm_config() -> dict: 129 """Read LLM config from JSON file. Returns empty dict if file doesn't exist.""" 130 if os.path.isfile(LLM_CONFIG_PATH): 131 try: 132 with open(LLM_CONFIG_PATH, "r") as f: 133 return json.load(f) 134 except json.JSONDecodeError: 135 return {} 136 return {} 137 138 139def write_llm_config(config: dict): 140 """Write the LLM config dictionary to the JSON file.""" 141 os.makedirs(os.path.dirname(LLM_CONFIG_PATH), exist_ok=True) 142 with open(LLM_CONFIG_PATH, "w") as f: 143 json.dump(config, f, indent=2) 144 145 146def get_lightllm_config() -> LightLLMProxyConfig: 147 """Get LightLLM proxy configuration.""" 148 config = read_llm_config() 149 proxy_config = config.get("lightllm_proxy", {}) 150 return LightLLMProxyConfig(**proxy_config) 151 152 153def get_local_llm_config() -> LocalLLMConfig: 154 """Get local Ollama configuration.""" 155 config = read_llm_config() 156 local_config = config.get("local_llm", {}) 157 return LocalLLMConfig(**local_config) 158 159 160def get_pull_lock_dir() -> Path: 161 """Directory for cross-job Ollama pull locks.""" 162 env_dir = os.environ.get("WUENLP_PULL_LOCK_DIR") 163 if env_dir: 164 return Path(os.path.expanduser(env_dir)) 165 166 cfg = get_local_llm_config() 167 if cfg.pull_lock_dir: 168 return Path(os.path.expanduser(cfg.pull_lock_dir)) 169 170 ollama_models = os.environ.get("OLLAMA_MODELS") 171 if ollama_models and _is_slurm(): 172 return Path(os.path.expanduser(ollama_models)) / ".wuenlp-pull-locks" 173 174 return DEFAULT_PULL_LOCK_DIR 175 176 177def _is_slurm() -> bool: 178 return bool(os.environ.get("SLURM_JOB_ID")) 179 180 181def _read_project_llm_config() -> dict: 182 """ 183 Read project-level LLM config from the current working directory. 184 185 The first existing file from PROJECT_LLM_CONFIG_CANDIDATES is used. 186 Returns an empty dict if no file is found or if parsing fails. 187 """ 188 cwd = os.getcwd() 189 for filename in PROJECT_LLM_CONFIG_CANDIDATES: 190 candidate = os.path.join(cwd, filename) 191 if os.path.isfile(candidate): 192 try: 193 with open(candidate, "r") as f: 194 return json.load(f) 195 except json.JSONDecodeError: 196 return {} 197 return {} 198 199 200def get_litellm_metadata() -> Dict[str, Any]: 201 """ 202 Get merged LiteLLM metadata configuration. 203 204 Order of precedence (later overrides earlier): 205 1. System-level config at LLM_CONFIG_PATH, key "litellm_metadata" 206 2. Project-level config in the current working directory 207 (".wuenlp_llm_config.json" or "wuenlp_llm_config.json"), 208 key "litellm_metadata" 209 210 This is intended for generic tags/metadata that should end up in LiteLLM logs. 211 """ 212 system_config = read_llm_config() 213 system_meta = system_config.get("litellm_metadata", {}) or {} 214 215 project_config = _read_project_llm_config() 216 project_meta = project_config.get("litellm_metadata", {}) or {} 217 218 merged: Dict[str, Any] = {} 219 merged.update(system_meta) 220 merged.update(project_meta) 221 return merged 222 223 224def configure_lightllm_proxy(): 225 """Interactive configuration helper for LightLLM proxy settings.""" 226 print("🔧 LightLLM Proxy Configuration") 227 print("=" * 40) 228 229 # Load current config 230 current_config = read_llm_config() 231 current_proxy = current_config.get("lightllm_proxy", {}) 232 233 print( 234 f"\nCurrent status: {'ENABLED' if current_proxy.get('enabled', False) else 'DISABLED'}" 235 ) 236 if current_proxy.get("base_url"): 237 print(f"Current proxy URL: {current_proxy['base_url']}") 238 239 # Ask if user wants to enable/disable 240 while True: 241 enable_input = input("\nEnable LightLLM proxy? [y/n]: ").strip().lower() 242 if enable_input in ["y", "yes", "true", "1"]: 243 enabled = True 244 break 245 elif enable_input in ["n", "no", "false", "0"]: 246 enabled = False 247 break 248 else: 249 print("Please enter 'y' for yes or 'n' for no") 250 251 if not enabled: 252 # Disable proxy 253 new_config = current_config.copy() 254 new_config["lightllm_proxy"] = {"enabled": False} 255 write_llm_config(new_config) 256 print("✅ LightLLM proxy disabled") 257 return 258 259 # Configure proxy settings 260 print("\n📝 Configuring proxy settings...") 261 262 # Base URL 263 current_url = current_proxy.get("base_url", "http://localhost:8080/v1/") 264 base_url = input(f"Proxy base URL [{current_url}]: ").strip() 265 if not base_url: 266 base_url = current_url 267 268 # Ensure URL ends with /v1/ 269 if not base_url.endswith("/"): 270 base_url += "/" 271 if not base_url.endswith("v1/"): 272 if base_url.endswith("/"): 273 base_url += "v1/" 274 else: 275 base_url += "/v1/" 276 277 # Model prefixes 278 current_prefixes = current_proxy.get( 279 "model_prefixes", 280 {"openai": "openai/", "openrouter": "openrouter/", "ollama": "ollama/"}, 281 ) 282 283 print("\n🏷️ Configure model prefixes (press Enter to keep current):") 284 285 model_prefixes = {} 286 for provider in ["openai", "openrouter", "ollama"]: 287 current_prefix = current_prefixes.get(provider, f"{provider}/") 288 prefix = input(f"{provider.capitalize()} prefix [{current_prefix}]: ").strip() 289 if not prefix: 290 prefix = current_prefix 291 model_prefixes[provider] = prefix 292 293 # Build final config 294 new_proxy_config = { 295 "enabled": True, 296 "base_url": base_url, 297 "model_prefixes": model_prefixes, 298 } 299 300 new_config = current_config.copy() 301 new_config["lightllm_proxy"] = new_proxy_config 302 303 # Show summary 304 print("\n📋 Configuration Summary:") 305 print(" Status: ENABLED") 306 print(f" Base URL: {base_url}") 307 print(" Model prefixes:") 308 for provider, prefix in model_prefixes.items(): 309 print(f" {provider}: {prefix}") 310 311 # Confirm and save 312 while True: 313 confirm = input("\nSave this configuration? [y/n]: ").strip().lower() 314 if confirm in ["y", "yes"]: 315 write_llm_config(new_config) 316 print(f"✅ Configuration saved to {LLM_CONFIG_PATH}") 317 318 # Check for API key 319 from wuenlp_tools.keys import LIGHTLLM_API_KEY 320 321 try: 322 # This will prompt for the key if not set 323 key_check = str(LIGHTLLM_API_KEY) 324 if key_check: 325 print("✅ LightLLM API key is configured") 326 else: 327 print("⚠️ No LightLLM API key set (may not be required)") 328 except Exception: 329 print("⚠️ No LightLLM API key set (may not be required)") 330 331 print("\n🎉 LightLLM proxy configuration complete!") 332 print(f" All LLM requests will now be routed through: {base_url}") 333 break 334 elif confirm in ["n", "no"]: 335 print("❌ Configuration cancelled") 336 break 337 else: 338 print("Please enter 'y' to save or 'n' to cancel") 339 340 341def show_lightllm_status(): 342 """Display current LightLLM proxy configuration status.""" 343 config = get_lightllm_config() 344 345 print("🔍 LightLLM Proxy Status") 346 print("=" * 25) 347 348 if config.enabled: 349 print("✅ Status: ENABLED") 350 print(f"🌐 Base URL: {config.base_url}") 351 print("🏷️ Model prefixes:") 352 if config.model_prefixes: 353 for provider, prefix in config.model_prefixes.items(): 354 print(f" {provider}: {prefix}") 355 356 # Check API key 357 from wuenlp_tools.keys import LIGHTLLM_API_KEY 358 359 try: 360 key_check = str(LIGHTLLM_API_KEY) 361 key_status = "SET" if key_check else "NOT SET" 362 except Exception: 363 key_status = "NOT SET" 364 print(f"🔑 API Key: {key_status}") 365 366 else: 367 print("❌ Status: DISABLED") 368 print("💡 Run configure_lightllm_proxy() to enable") 369 370 371from wuenlp_tools.ssc_config import ( # noqa: E402 372 get_ssc_repo_root, 373 get_ssc_scene_model_path, 374 get_ssc_suspense_model_root, 375 read_ssc_config, 376 write_ssc_config, 377)
37class APIConfig: 38 """Global configuration for WueNLP API endpoints.""" 39 40 _instance: Optional["APIConfig"] = None 41 42 def __init__(self): 43 self._base_url: str = os.getenv( 44 "WUENLP_API_BASE_URL", "https://wuenlp-api.professor-x.de" 45 ) 46 47 @classmethod 48 def get_instance(cls) -> "APIConfig": 49 """Get singleton instance of APIConfig.""" 50 if cls._instance is None: 51 cls._instance = cls() 52 return cls._instance 53 54 @property 55 def base_url(self) -> str: 56 """Get the base URL for WueNLP API.""" 57 return self._base_url 58 59 @base_url.setter 60 def base_url(self, value: str) -> None: 61 """Set the base URL for WueNLP API.""" 62 if value.endswith("/"): 63 value = value.rstrip("/") 64 self._base_url = value 65 66 def get_endpoint_url(self, endpoint: str) -> str: 67 """Get full URL for a specific endpoint.""" 68 if not endpoint.startswith("/"): 69 endpoint = "/" + endpoint 70 if not endpoint.endswith("/"): 71 endpoint = endpoint + "/" 72 return f"{self._base_url}{endpoint}"
Global configuration for WueNLP API endpoints.
47 @classmethod 48 def get_instance(cls) -> "APIConfig": 49 """Get singleton instance of APIConfig.""" 50 if cls._instance is None: 51 cls._instance = cls() 52 return cls._instance
Get singleton instance of APIConfig.
54 @property 55 def base_url(self) -> str: 56 """Get the base URL for WueNLP API.""" 57 return self._base_url
Get the base URL for WueNLP API.
66 def get_endpoint_url(self, endpoint: str) -> str: 67 """Get full URL for a specific endpoint.""" 68 if not endpoint.startswith("/"): 69 endpoint = "/" + endpoint 70 if not endpoint.endswith("/"): 71 endpoint = endpoint + "/" 72 return f"{self._base_url}{endpoint}"
Get full URL for a specific endpoint.
Global configuration for WueNLP API endpoints.
79def set_api_base_url(url: str) -> None: 80 """Set the global API base URL.""" 81 api_config.base_url = url
Set the global API base URL.
84def get_api_base_url() -> str: 85 """Get the global API base URL.""" 86 return api_config.base_url
Get the global API base URL.
89def get_endpoint_url(endpoint: str) -> str: 90 """Get full URL for a specific endpoint.""" 91 return api_config.get_endpoint_url(endpoint)
Get full URL for a specific endpoint.
104@dataclass 105class LightLLMProxyConfig: 106 enabled: bool = False 107 base_url: str = "http://localhost:8080/v1/" 108 model_prefixes: Optional[Dict[str, str]] = None 109 110 def __post_init__(self): 111 if self.model_prefixes is None: 112 self.model_prefixes = { 113 "openai": "openai/", 114 "openrouter": "openrouter/", 115 "ollama": "ollama/", 116 "local": "ollama/", 117 }
bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
120@dataclass 121class LocalLLMConfig: 122 base_url: Optional[str] = None 123 port: Union[str, int] = "auto" 124 auto_pull: bool = True 125 manage_process: Union[str, bool] = "auto" 126 pull_lock_dir: Optional[str] = None
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
Path whose repr uses ~ instead of the expanded home directory.
129def read_llm_config() -> dict: 130 """Read LLM config from JSON file. Returns empty dict if file doesn't exist.""" 131 if os.path.isfile(LLM_CONFIG_PATH): 132 try: 133 with open(LLM_CONFIG_PATH, "r") as f: 134 return json.load(f) 135 except json.JSONDecodeError: 136 return {} 137 return {}
Read LLM config from JSON file. Returns empty dict if file doesn't exist.
140def write_llm_config(config: dict): 141 """Write the LLM config dictionary to the JSON file.""" 142 os.makedirs(os.path.dirname(LLM_CONFIG_PATH), exist_ok=True) 143 with open(LLM_CONFIG_PATH, "w") as f: 144 json.dump(config, f, indent=2)
Write the LLM config dictionary to the JSON file.
147def get_lightllm_config() -> LightLLMProxyConfig: 148 """Get LightLLM proxy configuration.""" 149 config = read_llm_config() 150 proxy_config = config.get("lightllm_proxy", {}) 151 return LightLLMProxyConfig(**proxy_config)
Get LightLLM proxy configuration.
154def get_local_llm_config() -> LocalLLMConfig: 155 """Get local Ollama configuration.""" 156 config = read_llm_config() 157 local_config = config.get("local_llm", {}) 158 return LocalLLMConfig(**local_config)
Get local Ollama configuration.
161def get_pull_lock_dir() -> Path: 162 """Directory for cross-job Ollama pull locks.""" 163 env_dir = os.environ.get("WUENLP_PULL_LOCK_DIR") 164 if env_dir: 165 return Path(os.path.expanduser(env_dir)) 166 167 cfg = get_local_llm_config() 168 if cfg.pull_lock_dir: 169 return Path(os.path.expanduser(cfg.pull_lock_dir)) 170 171 ollama_models = os.environ.get("OLLAMA_MODELS") 172 if ollama_models and _is_slurm(): 173 return Path(os.path.expanduser(ollama_models)) / ".wuenlp-pull-locks" 174 175 return DEFAULT_PULL_LOCK_DIR
Directory for cross-job Ollama pull locks.
201def get_litellm_metadata() -> Dict[str, Any]: 202 """ 203 Get merged LiteLLM metadata configuration. 204 205 Order of precedence (later overrides earlier): 206 1. System-level config at LLM_CONFIG_PATH, key "litellm_metadata" 207 2. Project-level config in the current working directory 208 (".wuenlp_llm_config.json" or "wuenlp_llm_config.json"), 209 key "litellm_metadata" 210 211 This is intended for generic tags/metadata that should end up in LiteLLM logs. 212 """ 213 system_config = read_llm_config() 214 system_meta = system_config.get("litellm_metadata", {}) or {} 215 216 project_config = _read_project_llm_config() 217 project_meta = project_config.get("litellm_metadata", {}) or {} 218 219 merged: Dict[str, Any] = {} 220 merged.update(system_meta) 221 merged.update(project_meta) 222 return merged
Get merged LiteLLM metadata configuration.
Order of precedence (later overrides earlier):
- System-level config at LLM_CONFIG_PATH, key "litellm_metadata"
- Project-level config in the current working directory (".wuenlp_llm_config.json" or "wuenlp_llm_config.json"), key "litellm_metadata"
This is intended for generic tags/metadata that should end up in LiteLLM logs.
225def configure_lightllm_proxy(): 226 """Interactive configuration helper for LightLLM proxy settings.""" 227 print("🔧 LightLLM Proxy Configuration") 228 print("=" * 40) 229 230 # Load current config 231 current_config = read_llm_config() 232 current_proxy = current_config.get("lightllm_proxy", {}) 233 234 print( 235 f"\nCurrent status: {'ENABLED' if current_proxy.get('enabled', False) else 'DISABLED'}" 236 ) 237 if current_proxy.get("base_url"): 238 print(f"Current proxy URL: {current_proxy['base_url']}") 239 240 # Ask if user wants to enable/disable 241 while True: 242 enable_input = input("\nEnable LightLLM proxy? [y/n]: ").strip().lower() 243 if enable_input in ["y", "yes", "true", "1"]: 244 enabled = True 245 break 246 elif enable_input in ["n", "no", "false", "0"]: 247 enabled = False 248 break 249 else: 250 print("Please enter 'y' for yes or 'n' for no") 251 252 if not enabled: 253 # Disable proxy 254 new_config = current_config.copy() 255 new_config["lightllm_proxy"] = {"enabled": False} 256 write_llm_config(new_config) 257 print("✅ LightLLM proxy disabled") 258 return 259 260 # Configure proxy settings 261 print("\n📝 Configuring proxy settings...") 262 263 # Base URL 264 current_url = current_proxy.get("base_url", "http://localhost:8080/v1/") 265 base_url = input(f"Proxy base URL [{current_url}]: ").strip() 266 if not base_url: 267 base_url = current_url 268 269 # Ensure URL ends with /v1/ 270 if not base_url.endswith("/"): 271 base_url += "/" 272 if not base_url.endswith("v1/"): 273 if base_url.endswith("/"): 274 base_url += "v1/" 275 else: 276 base_url += "/v1/" 277 278 # Model prefixes 279 current_prefixes = current_proxy.get( 280 "model_prefixes", 281 {"openai": "openai/", "openrouter": "openrouter/", "ollama": "ollama/"}, 282 ) 283 284 print("\n🏷️ Configure model prefixes (press Enter to keep current):") 285 286 model_prefixes = {} 287 for provider in ["openai", "openrouter", "ollama"]: 288 current_prefix = current_prefixes.get(provider, f"{provider}/") 289 prefix = input(f"{provider.capitalize()} prefix [{current_prefix}]: ").strip() 290 if not prefix: 291 prefix = current_prefix 292 model_prefixes[provider] = prefix 293 294 # Build final config 295 new_proxy_config = { 296 "enabled": True, 297 "base_url": base_url, 298 "model_prefixes": model_prefixes, 299 } 300 301 new_config = current_config.copy() 302 new_config["lightllm_proxy"] = new_proxy_config 303 304 # Show summary 305 print("\n📋 Configuration Summary:") 306 print(" Status: ENABLED") 307 print(f" Base URL: {base_url}") 308 print(" Model prefixes:") 309 for provider, prefix in model_prefixes.items(): 310 print(f" {provider}: {prefix}") 311 312 # Confirm and save 313 while True: 314 confirm = input("\nSave this configuration? [y/n]: ").strip().lower() 315 if confirm in ["y", "yes"]: 316 write_llm_config(new_config) 317 print(f"✅ Configuration saved to {LLM_CONFIG_PATH}") 318 319 # Check for API key 320 from wuenlp_tools.keys import LIGHTLLM_API_KEY 321 322 try: 323 # This will prompt for the key if not set 324 key_check = str(LIGHTLLM_API_KEY) 325 if key_check: 326 print("✅ LightLLM API key is configured") 327 else: 328 print("⚠️ No LightLLM API key set (may not be required)") 329 except Exception: 330 print("⚠️ No LightLLM API key set (may not be required)") 331 332 print("\n🎉 LightLLM proxy configuration complete!") 333 print(f" All LLM requests will now be routed through: {base_url}") 334 break 335 elif confirm in ["n", "no"]: 336 print("❌ Configuration cancelled") 337 break 338 else: 339 print("Please enter 'y' to save or 'n' to cancel")
Interactive configuration helper for LightLLM proxy settings.
342def show_lightllm_status(): 343 """Display current LightLLM proxy configuration status.""" 344 config = get_lightllm_config() 345 346 print("🔍 LightLLM Proxy Status") 347 print("=" * 25) 348 349 if config.enabled: 350 print("✅ Status: ENABLED") 351 print(f"🌐 Base URL: {config.base_url}") 352 print("🏷️ Model prefixes:") 353 if config.model_prefixes: 354 for provider, prefix in config.model_prefixes.items(): 355 print(f" {provider}: {prefix}") 356 357 # Check API key 358 from wuenlp_tools.keys import LIGHTLLM_API_KEY 359 360 try: 361 key_check = str(LIGHTLLM_API_KEY) 362 key_status = "SET" if key_check else "NOT SET" 363 except Exception: 364 key_status = "NOT SET" 365 print(f"🔑 API Key: {key_status}") 366 367 else: 368 print("❌ Status: DISABLED") 369 print("💡 Run configure_lightllm_proxy() to enable")
Display current LightLLM proxy configuration status.
40def read_ssc_config() -> dict[str, Any]: 41 """Read merged SSC config: user file, then project file in cwd (project wins).""" 42 merged: dict[str, Any] = {} 43 if os.path.isfile(SSC_CONFIG_PATH): 44 try: 45 with open(SSC_CONFIG_PATH, encoding="utf-8") as f: 46 merged.update(json.load(f)) 47 except json.JSONDecodeError: 48 pass 49 for filename in PROJECT_SSC_CONFIG_CANDIDATES: 50 candidate = os.path.join(os.getcwd(), filename) 51 if os.path.isfile(candidate): 52 try: 53 with open(candidate, encoding="utf-8") as f: 54 merged.update(json.load(f)) 55 except json.JSONDecodeError: 56 pass 57 break 58 return merged
Read merged SSC config: user file, then project file in cwd (project wins).