-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathconfig.py
More file actions
140 lines (120 loc) · 4.86 KB
/
Copy pathconfig.py
File metadata and controls
140 lines (120 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import base64
from loguru import logger
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
from pathlib import Path
from typing import Dict, List, Optional, Set
class Settings(BaseSettings):
"""Application settings."""
model_config = SettingsConfigDict(case_sensitive=True, env_file=".env", extra="ignore", env_prefix="")
# Configuration
HOST_PATH: Path = (
"." # This is used to fully qualify relative paths for Docker code execution container volume mounts
)
HOST_CONFIG_PATH: Path = Path("config") # Base directory for configuration files
LOG_LEVEL: str = "INFO" # Log level for logging
LOG_SERIALIZE: bool = False # Whether to serialize log messages to JSON
@property
def CONFIG_PATH_ABS(self) -> Path:
"""Full path to the configuration directory."""
return self.HOST_CONFIG_PATH if self.HOST_CONFIG_PATH.is_absolute() else self.HOST_PATH / self.HOST_CONFIG_PATH
# API settings
PORT: int = 8000 # Port exposed from the container
API_PREFIX: str = "/v1" # API prefix
# JWT auth (LibreChat code-API tokens); auth is disabled when no public key is set
CODEAPI_JWT_PUBLIC_KEY: Optional[str] = None # PEM, "\n"-escaped newlines allowed
CODEAPI_JWT_PUBLIC_KEY_BASE64: Optional[str] = None # base64-encoded PEM alternative
CODEAPI_JWT_ISSUER: str = "librechat"
CODEAPI_JWT_AUDIENCE: str = "codeapi"
CODEAPI_JWT_ALGORITHMS: List[str] = ["EdDSA", "RS256"]
CODEAPI_JWT_LEEWAY: int = 30 # seconds of clock-skew tolerance
@property
def JWT_PUBLIC_KEY_PEM(self) -> Optional[str]:
"""Resolved public key PEM, or None when JWT auth is unconfigured."""
if self.CODEAPI_JWT_PUBLIC_KEY:
return self.CODEAPI_JWT_PUBLIC_KEY.replace("\\n", "\n").strip()
if self.CODEAPI_JWT_PUBLIC_KEY_BASE64:
return base64.b64decode(self.CODEAPI_JWT_PUBLIC_KEY_BASE64).decode("utf-8").strip()
return None
# Code execution sandbox settings
SANDBOX_MAX_EXECUTION_TIME: int = 300 # Docker container execution time limit in seconds
# File management
FILE_MAX_UPLOAD_SIZE: int = 10 * 1024 * 1024 # 10MB
FILE_MAX_BATCH_COUNT: int = 20 # Maximum number of files per upload request
FILE_ALLOWED_EXTENSIONS: Set[str] = {
# Programming languages
"py",
"c",
"cpp",
"java",
"php",
"rb",
"js",
"ts",
# Documents
"txt",
"md",
"html",
"css",
"tex",
"json",
"csv",
"xml",
"docx",
"xlsx",
"pptx",
"pdf",
# Data formats
"ipynb",
"yml",
"yaml",
# Archives
"zip",
"tar",
# Images
"jpg",
"jpeg",
"png",
"gif",
}
HOST_FILE_UPLOAD_PATH: Path = Path("uploads") # Base directory for uploaded files
@property
def HOST_FILE_UPLOAD_PATH_ABS(self) -> Path:
"""Full path to the file upload directory. Absolute path is required for Docker volume mounts."""
return (
self.HOST_FILE_UPLOAD_PATH
if self.HOST_FILE_UPLOAD_PATH.is_absolute()
else self.HOST_PATH / self.HOST_FILE_UPLOAD_PATH
)
# File cleanup settings
CLEANUP_RUN_INTERVAL: int = 3600 # How often to run the cleanup in seconds
CLEANUP_FILE_MAX_AGE: int = 86400 # How old files can be before they are deleted in seconds
PY_CONTAINER_IMAGE: str = "jupyter/scipy-notebook:latest"
R_CONTAINER_IMAGE: str = "jupyter/r-notebook:latest"
BASH_CONTAINER_IMAGE: str = "jupyter/scipy-notebook:latest"
# Node 24 (LTS) runs TypeScript natively via type stripping, so one image covers both
JS_CONTAINER_IMAGE: str = "node:24-slim"
TS_CONTAINER_IMAGE: str = "node:24-slim"
@property
def LANGUAGE_CONTAINERS(self) -> Dict[str, str]:
"""Map language codes to container images."""
return {
"py": self.PY_CONTAINER_IMAGE,
"r": self.R_CONTAINER_IMAGE,
"bash": self.BASH_CONTAINER_IMAGE,
"js": self.JS_CONTAINER_IMAGE,
"ts": self.TS_CONTAINER_IMAGE,
}
# Docker execution settings
MAX_CONCURRENT_CONTAINERS: int = 10 # Maximum number of concurrent Docker containers
CONTAINER_MEMORY_LIMIT_MB: int = 512 # Memory limit for Docker containers in MB
CONTAINER_CPU_LIMIT: float = 1.0 # CPU limit for Docker containers (number of cores)
CONTAINER_PIDS_LIMIT: int = 256 # Max processes per container (fork bomb protection)
# Docker network settings
DOCKER_NETWORK_ENABLED: bool = False # Whether Docker containers have network access
@lru_cache()
def get_settings() -> Settings:
"""Get cached settings instance."""
settings = Settings()
logger.info(f"Settings: {settings.HOST_FILE_UPLOAD_PATH_ABS}")
return settings