MogensR commited on
Commit
061fd49
·
1 Parent(s): 1d4a4dd

Update app_config.py

Browse files
Files changed (1) hide show
  1. app_config.py +213 -38
app_config.py CHANGED
@@ -1,14 +1,17 @@
1
  """
2
- Application Configuration Module
3
  Centralizes all application configuration and environment variable handling
4
 
5
  Note: Named 'app_config.py' to avoid conflicts with existing 'Configs/' folder
6
  """
7
 
8
  import os
9
- from dataclasses import dataclass, asdict
10
- from typing import Dict, Any, Optional
 
11
  import logging
 
 
12
 
13
  logger = logging.getLogger(__name__)
14
 
@@ -17,16 +20,23 @@ class ProcessingConfig:
17
  """
18
  Main processing configuration with environment variable defaults
19
  """
 
 
 
 
20
  # Frame processing settings
21
  keyframe_interval: int = int(os.getenv('KEYFRAME_INTERVAL', '5'))
22
  frame_skip: int = int(os.getenv('FRAME_SKIP', '1'))
23
 
24
  # Memory management
25
  memory_cleanup_interval: int = int(os.getenv('MEMORY_CLEANUP_INTERVAL', '30'))
 
26
 
27
  # Video constraints
28
  max_video_length: int = int(os.getenv('MAX_VIDEO_LENGTH', '300')) # seconds
29
  max_video_resolution: str = os.getenv('MAX_VIDEO_RESOLUTION', '1920x1080')
 
 
30
 
31
  # Quality settings
32
  quality_preset: str = os.getenv('QUALITY_PRESET', 'balanced')
@@ -34,56 +44,82 @@ class ProcessingConfig:
34
  # Model settings
35
  sam2_model_size: str = os.getenv('SAM2_MODEL_SIZE', 'large') # tiny, small, base, large
36
  matanyone_precision: str = os.getenv('MATANYONE_PRECISION', 'fp32') # fp16, fp32
 
37
 
38
  # Processing settings
39
  temporal_consistency: bool = os.getenv('TEMPORAL_CONSISTENCY', 'true').lower() == 'true'
40
  edge_refinement: bool = os.getenv('EDGE_REFINEMENT', 'true').lower() == 'true'
 
 
41
 
42
  # Output settings
 
43
  output_format: str = os.getenv('OUTPUT_FORMAT', 'mp4')
44
  output_quality: str = os.getenv('OUTPUT_QUALITY', 'high') # low, medium, high
 
45
  preserve_audio: bool = os.getenv('PRESERVE_AUDIO', 'true').lower() == 'true'
46
 
47
  # Cache settings
48
- model_cache_dir: str = os.getenv('MODEL_CACHE_DIR', '/tmp/model_cache')
49
- temp_dir: str = os.getenv('TEMP_DIR', '/tmp')
50
  cleanup_temp_files: bool = os.getenv('CLEANUP_TEMP_FILES', 'true').lower() == 'true'
 
51
 
52
  # Performance settings
53
  max_concurrent_processes: int = int(os.getenv('MAX_CONCURRENT_PROCESSES', '1'))
54
  gpu_memory_fraction: float = float(os.getenv('GPU_MEMORY_FRACTION', '0.8'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  # Debug settings
57
  debug_mode: bool = os.getenv('DEBUG_MODE', 'false').lower() == 'true'
58
  save_intermediate_results: bool = os.getenv('SAVE_INTERMEDIATE_RESULTS', 'false').lower() == 'true'
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  def __post_init__(self):
61
  """Validate configuration after initialization"""
62
  self._validate_config()
63
  self._create_directories()
 
64
  if self.debug_mode:
65
  self._log_config()
66
 
67
  def _validate_config(self):
68
  """Validate configuration values"""
69
  # Validate frame settings
70
- if self.keyframe_interval < 1:
71
- logger.warning(f"keyframe_interval must be >= 1, got {self.keyframe_interval}. Setting to 1.")
72
- self.keyframe_interval = 1
73
-
74
- if self.frame_skip < 1:
75
- logger.warning(f"frame_skip must be >= 1, got {self.frame_skip}. Setting to 1.")
76
- self.frame_skip = 1
77
 
78
  # Validate memory settings
79
- if self.memory_cleanup_interval < 1:
80
- logger.warning(f"memory_cleanup_interval must be >= 1, got {self.memory_cleanup_interval}. Setting to 10.")
81
- self.memory_cleanup_interval = 10
82
 
83
  # Validate video constraints
84
- if self.max_video_length < 1:
85
- logger.warning(f"max_video_length must be >= 1, got {self.max_video_length}. Setting to 60.")
86
- self.max_video_length = 60
87
 
88
  # Validate resolution format
89
  if 'x' not in self.max_video_resolution:
@@ -108,48 +144,115 @@ def _validate_config(self):
108
  self.matanyone_precision = 'fp32'
109
 
110
  # Validate output settings
111
- valid_formats = ['mp4', 'avi', 'mov', 'webm']
112
  if self.output_format not in valid_formats:
113
  logger.warning(f"Invalid output format: {self.output_format}. Setting to 'mp4'.")
114
  self.output_format = 'mp4'
115
 
116
- valid_qualities = ['low', 'medium', 'high']
117
  if self.output_quality not in valid_qualities:
118
  logger.warning(f"Invalid output quality: {self.output_quality}. Setting to 'high'.")
119
  self.output_quality = 'high'
120
 
121
  # Validate performance settings
122
- if self.max_concurrent_processes < 1:
123
- logger.warning(f"max_concurrent_processes must be >= 1, got {self.max_concurrent_processes}. Setting to 1.")
124
- self.max_concurrent_processes = 1
 
 
 
 
 
 
 
125
 
126
- if not (0.1 <= self.gpu_memory_fraction <= 1.0):
127
- logger.warning(f"gpu_memory_fraction must be between 0.1 and 1.0, got {self.gpu_memory_fraction}. Setting to 0.8.")
128
- self.gpu_memory_fraction = 0.8
129
 
130
  def _create_directories(self):
131
  """Create necessary directories if they don't exist"""
132
- import os
133
- directories = [self.model_cache_dir, self.temp_dir]
 
 
 
 
 
 
 
134
 
135
  for directory in directories:
136
  try:
137
- os.makedirs(directory, exist_ok=True)
138
  logger.debug(f"Ensured directory exists: {directory}")
139
  except Exception as e:
140
  logger.error(f"Failed to create directory {directory}: {e}")
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  def _log_config(self):
143
  """Log current configuration in debug mode"""
144
- logger.info("=== Processing Configuration ===")
145
- for key, value in asdict(self).items():
 
 
 
 
 
 
 
 
 
146
  logger.info(f"{key}: {value}")
147
- logger.info("===============================")
148
 
149
  def to_dict(self) -> Dict[str, Any]:
150
  """Convert configuration to dictionary"""
151
  return asdict(self)
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  def get_quality_settings(self) -> Dict[str, Any]:
154
  """Get quality-specific settings based on preset"""
155
  quality_maps = {
@@ -158,28 +261,36 @@ def get_quality_settings(self) -> Dict[str, Any]:
158
  'frame_skip': max(self.frame_skip, 2),
159
  'edge_refinement': False,
160
  'temporal_consistency': False,
161
- 'model_precision': 'fp16'
 
 
162
  },
163
  'balanced': {
164
  'keyframe_interval': self.keyframe_interval,
165
  'frame_skip': self.frame_skip,
166
  'edge_refinement': True,
167
  'temporal_consistency': True,
168
- 'model_precision': 'fp32'
 
 
169
  },
170
  'high': {
171
  'keyframe_interval': max(self.keyframe_interval // 2, 1),
172
  'frame_skip': 1,
173
  'edge_refinement': True,
174
  'temporal_consistency': True,
175
- 'model_precision': 'fp32'
 
 
176
  },
177
  'ultra': {
178
  'keyframe_interval': 1,
179
  'frame_skip': 1,
180
  'edge_refinement': True,
181
  'temporal_consistency': True,
182
- 'model_precision': 'fp32'
 
 
183
  }
184
  }
185
 
@@ -194,6 +305,23 @@ def get_resolution_limits(self) -> tuple[int, int]:
194
  logger.error(f"Invalid resolution format: {self.max_video_resolution}")
195
  return 1920, 1080
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  def is_high_performance_mode(self) -> bool:
198
  """Check if configuration is set for high performance"""
199
  return (
@@ -203,13 +331,42 @@ def is_high_performance_mode(self) -> bool:
203
  self.keyframe_interval <= 3
204
  )
205
 
206
- def get_memory_limits(self) -> Dict[str, float]:
207
  """Get memory-related limits"""
208
  return {
209
  'gpu_memory_fraction': self.gpu_memory_fraction,
210
  'cleanup_interval': self.memory_cleanup_interval,
211
- 'max_concurrent': self.max_concurrent_processes
 
 
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  # Singleton instance for application-wide use
215
  _config_instance: Optional[ProcessingConfig] = None
@@ -243,4 +400,22 @@ def update_config(**kwargs) -> ProcessingConfig:
243
 
244
  # Re-validate after updates
245
  _config_instance._validate_config()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  return _config_instance
 
1
  """
2
+ BackgroundFX Pro Configuration Module
3
  Centralizes all application configuration and environment variable handling
4
 
5
  Note: Named 'app_config.py' to avoid conflicts with existing 'Configs/' folder
6
  """
7
 
8
  import os
9
+ from dataclasses import dataclass, asdict, field
10
+ from typing import Dict, Any, Optional, List
11
+ from pathlib import Path
12
  import logging
13
+ import json
14
+ import yaml
15
 
16
  logger = logging.getLogger(__name__)
17
 
 
20
  """
21
  Main processing configuration with environment variable defaults
22
  """
23
+ # Application info
24
+ app_name: str = "BackgroundFX Pro"
25
+ version: str = "2.0.0"
26
+
27
  # Frame processing settings
28
  keyframe_interval: int = int(os.getenv('KEYFRAME_INTERVAL', '5'))
29
  frame_skip: int = int(os.getenv('FRAME_SKIP', '1'))
30
 
31
  # Memory management
32
  memory_cleanup_interval: int = int(os.getenv('MEMORY_CLEANUP_INTERVAL', '30'))
33
+ memory_threshold_mb: int = int(os.getenv('MEMORY_THRESHOLD_MB', '1024'))
34
 
35
  # Video constraints
36
  max_video_length: int = int(os.getenv('MAX_VIDEO_LENGTH', '300')) # seconds
37
  max_video_resolution: str = os.getenv('MAX_VIDEO_RESOLUTION', '1920x1080')
38
+ min_video_fps: int = int(os.getenv('MIN_VIDEO_FPS', '15'))
39
+ max_video_fps: int = int(os.getenv('MAX_VIDEO_FPS', '60'))
40
 
41
  # Quality settings
42
  quality_preset: str = os.getenv('QUALITY_PRESET', 'balanced')
 
44
  # Model settings
45
  sam2_model_size: str = os.getenv('SAM2_MODEL_SIZE', 'large') # tiny, small, base, large
46
  matanyone_precision: str = os.getenv('MATANYONE_PRECISION', 'fp32') # fp16, fp32
47
+ model_device: str = os.getenv('MODEL_DEVICE', 'auto') # auto, cuda, cpu
48
 
49
  # Processing settings
50
  temporal_consistency: bool = os.getenv('TEMPORAL_CONSISTENCY', 'true').lower() == 'true'
51
  edge_refinement: bool = os.getenv('EDGE_REFINEMENT', 'true').lower() == 'true'
52
+ mask_blur_radius: int = int(os.getenv('MASK_BLUR_RADIUS', '5'))
53
+ confidence_threshold: float = float(os.getenv('CONFIDENCE_THRESHOLD', '0.85'))
54
 
55
  # Output settings
56
+ output_dir: str = os.getenv('OUTPUT_DIR', 'outputs')
57
  output_format: str = os.getenv('OUTPUT_FORMAT', 'mp4')
58
  output_quality: str = os.getenv('OUTPUT_QUALITY', 'high') # low, medium, high
59
+ output_codec: str = os.getenv('OUTPUT_CODEC', 'h264')
60
  preserve_audio: bool = os.getenv('PRESERVE_AUDIO', 'true').lower() == 'true'
61
 
62
  # Cache settings
63
+ model_cache_dir: str = os.getenv('MODEL_CACHE_DIR', 'models/cache')
64
+ temp_dir: str = os.getenv('TEMP_DIR', 'temp')
65
  cleanup_temp_files: bool = os.getenv('CLEANUP_TEMP_FILES', 'true').lower() == 'true'
66
+ cache_size_limit_gb: float = float(os.getenv('CACHE_SIZE_LIMIT_GB', '10.0'))
67
 
68
  # Performance settings
69
  max_concurrent_processes: int = int(os.getenv('MAX_CONCURRENT_PROCESSES', '1'))
70
  gpu_memory_fraction: float = float(os.getenv('GPU_MEMORY_FRACTION', '0.8'))
71
+ batch_size: int = int(os.getenv('BATCH_SIZE', '4'))
72
+ num_workers: int = int(os.getenv('NUM_WORKERS', '4'))
73
+
74
+ # API settings
75
+ api_enabled: bool = os.getenv('API_ENABLED', 'false').lower() == 'true'
76
+ api_host: str = os.getenv('API_HOST', '0.0.0.0')
77
+ api_port: int = int(os.getenv('API_PORT', '8000'))
78
+ api_key: Optional[str] = os.getenv('API_KEY', None)
79
+
80
+ # Web UI settings
81
+ gradio_server_name: str = os.getenv('GRADIO_SERVER_NAME', '0.0.0.0')
82
+ gradio_server_port: int = int(os.getenv('GRADIO_SERVER_PORT', '7860'))
83
+ gradio_share: bool = os.getenv('GRADIO_SHARE', 'false').lower() == 'true'
84
+ gradio_auth: Optional[str] = os.getenv('GRADIO_AUTH', None) # username:password
85
 
86
  # Debug settings
87
  debug_mode: bool = os.getenv('DEBUG_MODE', 'false').lower() == 'true'
88
  save_intermediate_results: bool = os.getenv('SAVE_INTERMEDIATE_RESULTS', 'false').lower() == 'true'
89
+ log_level: str = os.getenv('LOG_LEVEL', 'INFO')
90
+ profile_performance: bool = os.getenv('PROFILE_PERFORMANCE', 'false').lower() == 'true'
91
+
92
+ # Feature flags
93
+ enable_two_stage: bool = os.getenv('ENABLE_TWO_STAGE', 'true').lower() == 'true'
94
+ enable_preview_modes: bool = os.getenv('ENABLE_PREVIEW_MODES', 'true').lower() == 'true'
95
+ enable_batch_processing: bool = os.getenv('ENABLE_BATCH_PROCESSING', 'false').lower() == 'true'
96
+
97
+ # Legacy compatibility
98
+ legacy_mode: bool = os.getenv('LEGACY_MODE', 'true').lower() == 'true'
99
+ legacy_configs_dir: str = os.getenv('LEGACY_CONFIGS_DIR', 'Configs')
100
 
101
  def __post_init__(self):
102
  """Validate configuration after initialization"""
103
  self._validate_config()
104
  self._create_directories()
105
+ self._setup_logging()
106
  if self.debug_mode:
107
  self._log_config()
108
 
109
  def _validate_config(self):
110
  """Validate configuration values"""
111
  # Validate frame settings
112
+ self.keyframe_interval = max(1, self.keyframe_interval)
113
+ self.frame_skip = max(1, self.frame_skip)
 
 
 
 
 
114
 
115
  # Validate memory settings
116
+ self.memory_cleanup_interval = max(1, self.memory_cleanup_interval)
117
+ self.memory_threshold_mb = max(256, self.memory_threshold_mb)
 
118
 
119
  # Validate video constraints
120
+ self.max_video_length = max(1, self.max_video_length)
121
+ self.min_video_fps = max(1, min(self.min_video_fps, 60))
122
+ self.max_video_fps = max(self.min_video_fps, min(self.max_video_fps, 120))
123
 
124
  # Validate resolution format
125
  if 'x' not in self.max_video_resolution:
 
144
  self.matanyone_precision = 'fp32'
145
 
146
  # Validate output settings
147
+ valid_formats = ['mp4', 'avi', 'mov', 'webm', 'mkv']
148
  if self.output_format not in valid_formats:
149
  logger.warning(f"Invalid output format: {self.output_format}. Setting to 'mp4'.")
150
  self.output_format = 'mp4'
151
 
152
+ valid_qualities = ['low', 'medium', 'high', 'ultra']
153
  if self.output_quality not in valid_qualities:
154
  logger.warning(f"Invalid output quality: {self.output_quality}. Setting to 'high'.")
155
  self.output_quality = 'high'
156
 
157
  # Validate performance settings
158
+ self.max_concurrent_processes = max(1, self.max_concurrent_processes)
159
+ self.gpu_memory_fraction = max(0.1, min(1.0, self.gpu_memory_fraction))
160
+ self.batch_size = max(1, self.batch_size)
161
+ self.num_workers = max(0, self.num_workers)
162
+
163
+ # Validate API settings
164
+ self.api_port = max(1024, min(65535, self.api_port))
165
+
166
+ # Validate confidence threshold
167
+ self.confidence_threshold = max(0.0, min(1.0, self.confidence_threshold))
168
 
169
+ # Validate cache size
170
+ self.cache_size_limit_gb = max(0.1, self.cache_size_limit_gb)
 
171
 
172
  def _create_directories(self):
173
  """Create necessary directories if they don't exist"""
174
+ directories = [
175
+ self.model_cache_dir,
176
+ self.temp_dir,
177
+ self.output_dir,
178
+ Path(self.output_dir) / 'masks',
179
+ Path(self.output_dir) / 'greenscreen',
180
+ Path(self.output_dir) / 'final',
181
+ Path(self.output_dir) / 'two_stage'
182
+ ]
183
 
184
  for directory in directories:
185
  try:
186
+ Path(directory).mkdir(parents=True, exist_ok=True)
187
  logger.debug(f"Ensured directory exists: {directory}")
188
  except Exception as e:
189
  logger.error(f"Failed to create directory {directory}: {e}")
190
 
191
+ def _setup_logging(self):
192
+ """Setup logging based on configuration"""
193
+ log_levels = {
194
+ 'DEBUG': logging.DEBUG,
195
+ 'INFO': logging.INFO,
196
+ 'WARNING': logging.WARNING,
197
+ 'ERROR': logging.ERROR,
198
+ 'CRITICAL': logging.CRITICAL
199
+ }
200
+
201
+ level = log_levels.get(self.log_level.upper(), logging.INFO)
202
+ logging.getLogger().setLevel(level)
203
+
204
  def _log_config(self):
205
  """Log current configuration in debug mode"""
206
+ logger.info("=" * 60)
207
+ logger.info(f"{self.app_name} v{self.version} Configuration")
208
+ logger.info("=" * 60)
209
+ config_dict = self.to_dict()
210
+ # Hide sensitive information
211
+ if config_dict.get('api_key'):
212
+ config_dict['api_key'] = '***hidden***'
213
+ if config_dict.get('gradio_auth'):
214
+ config_dict['gradio_auth'] = '***hidden***'
215
+
216
+ for key, value in config_dict.items():
217
  logger.info(f"{key}: {value}")
218
+ logger.info("=" * 60)
219
 
220
  def to_dict(self) -> Dict[str, Any]:
221
  """Convert configuration to dictionary"""
222
  return asdict(self)
223
 
224
+ def to_json(self, filepath: Optional[str] = None) -> str:
225
+ """Export configuration to JSON"""
226
+ config_dict = self.to_dict()
227
+ if filepath:
228
+ with open(filepath, 'w') as f:
229
+ json.dump(config_dict, f, indent=2)
230
+ logger.info(f"Configuration saved to {filepath}")
231
+ return json.dumps(config_dict, indent=2)
232
+
233
+ def to_yaml(self, filepath: Optional[str] = None) -> str:
234
+ """Export configuration to YAML"""
235
+ config_dict = self.to_dict()
236
+ if filepath:
237
+ with open(filepath, 'w') as f:
238
+ yaml.dump(config_dict, f, default_flow_style=False)
239
+ logger.info(f"Configuration saved to {filepath}")
240
+ return yaml.dump(config_dict, default_flow_style=False)
241
+
242
+ @classmethod
243
+ def from_json(cls, filepath: str) -> 'ProcessingConfig':
244
+ """Load configuration from JSON file"""
245
+ with open(filepath, 'r') as f:
246
+ config_dict = json.load(f)
247
+ return cls(**config_dict)
248
+
249
+ @classmethod
250
+ def from_yaml(cls, filepath: str) -> 'ProcessingConfig':
251
+ """Load configuration from YAML file"""
252
+ with open(filepath, 'r') as f:
253
+ config_dict = yaml.safe_load(f)
254
+ return cls(**config_dict)
255
+
256
  def get_quality_settings(self) -> Dict[str, Any]:
257
  """Get quality-specific settings based on preset"""
258
  quality_maps = {
 
261
  'frame_skip': max(self.frame_skip, 2),
262
  'edge_refinement': False,
263
  'temporal_consistency': False,
264
+ 'model_precision': 'fp16',
265
+ 'batch_size': min(self.batch_size * 2, 16),
266
+ 'output_quality_params': '-preset ultrafast -crf 28'
267
  },
268
  'balanced': {
269
  'keyframe_interval': self.keyframe_interval,
270
  'frame_skip': self.frame_skip,
271
  'edge_refinement': True,
272
  'temporal_consistency': True,
273
+ 'model_precision': 'fp32',
274
+ 'batch_size': self.batch_size,
275
+ 'output_quality_params': '-preset medium -crf 23'
276
  },
277
  'high': {
278
  'keyframe_interval': max(self.keyframe_interval // 2, 1),
279
  'frame_skip': 1,
280
  'edge_refinement': True,
281
  'temporal_consistency': True,
282
+ 'model_precision': 'fp32',
283
+ 'batch_size': max(self.batch_size // 2, 1),
284
+ 'output_quality_params': '-preset slow -crf 18'
285
  },
286
  'ultra': {
287
  'keyframe_interval': 1,
288
  'frame_skip': 1,
289
  'edge_refinement': True,
290
  'temporal_consistency': True,
291
+ 'model_precision': 'fp32',
292
+ 'batch_size': 1,
293
+ 'output_quality_params': '-preset veryslow -crf 15'
294
  }
295
  }
296
 
 
305
  logger.error(f"Invalid resolution format: {self.max_video_resolution}")
306
  return 1920, 1080
307
 
308
+ def get_output_params(self) -> Dict[str, str]:
309
+ """Get FFmpeg output parameters based on settings"""
310
+ quality_settings = self.get_quality_settings()
311
+ codec_map = {
312
+ 'h264': 'libx264',
313
+ 'h265': 'libx265',
314
+ 'vp9': 'libvpx-vp9',
315
+ 'av1': 'libaom-av1'
316
+ }
317
+
318
+ return {
319
+ 'codec': codec_map.get(self.output_codec, 'libx264'),
320
+ 'quality': quality_settings['output_quality_params'],
321
+ 'format': self.output_format,
322
+ 'audio': '-c:a copy' if self.preserve_audio else '-an'
323
+ }
324
+
325
  def is_high_performance_mode(self) -> bool:
326
  """Check if configuration is set for high performance"""
327
  return (
 
331
  self.keyframe_interval <= 3
332
  )
333
 
334
+ def get_memory_limits(self) -> Dict[str, Any]:
335
  """Get memory-related limits"""
336
  return {
337
  'gpu_memory_fraction': self.gpu_memory_fraction,
338
  'cleanup_interval': self.memory_cleanup_interval,
339
+ 'max_concurrent': self.max_concurrent_processes,
340
+ 'threshold_mb': self.memory_threshold_mb,
341
+ 'cache_size_gb': self.cache_size_limit_gb
342
  }
343
+
344
+ def validate_for_production(self) -> List[str]:
345
+ """Validate configuration for production deployment"""
346
+ warnings = []
347
+
348
+ if self.debug_mode:
349
+ warnings.append("Debug mode is enabled in production")
350
+
351
+ if self.save_intermediate_results:
352
+ warnings.append("Intermediate results saving is enabled (disk usage)")
353
+
354
+ if not self.cleanup_temp_files:
355
+ warnings.append("Temp file cleanup is disabled (disk usage)")
356
+
357
+ if self.gradio_share:
358
+ warnings.append("Gradio share is enabled (security risk)")
359
+
360
+ if not self.api_key and self.api_enabled:
361
+ warnings.append("API is enabled without authentication")
362
+
363
+ if self.gpu_memory_fraction > 0.9:
364
+ warnings.append("GPU memory fraction is very high (>90%)")
365
+
366
+ if self.max_concurrent_processes > 4:
367
+ warnings.append("High concurrent processes may cause instability")
368
+
369
+ return warnings
370
 
371
  # Singleton instance for application-wide use
372
  _config_instance: Optional[ProcessingConfig] = None
 
400
 
401
  # Re-validate after updates
402
  _config_instance._validate_config()
403
+ return _config_instance
404
+
405
+ def load_config_from_file(filepath: str) -> ProcessingConfig:
406
+ """Load configuration from file (JSON or YAML)"""
407
+ global _config_instance
408
+
409
+ file_path = Path(filepath)
410
+ if not file_path.exists():
411
+ raise FileNotFoundError(f"Configuration file not found: {filepath}")
412
+
413
+ if file_path.suffix.lower() in ['.json']:
414
+ _config_instance = ProcessingConfig.from_json(filepath)
415
+ elif file_path.suffix.lower() in ['.yaml', '.yml']:
416
+ _config_instance = ProcessingConfig.from_yaml(filepath)
417
+ else:
418
+ raise ValueError(f"Unsupported configuration file format: {file_path.suffix}")
419
+
420
+ logger.info(f"Configuration loaded from {filepath}")
421
  return _config_instance