150 lines
3.9 KiB
Python
150 lines
3.9 KiB
Python
|
|
import os
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Any, Dict, List, Optional
|
||
|
|
|
||
|
|
import yaml
|
||
|
|
from pydantic import BaseModel, Field
|
||
|
|
|
||
|
|
|
||
|
|
class DatabaseConfig(BaseModel):
|
||
|
|
dialect: str = "sqlite"
|
||
|
|
host: str = "localhost"
|
||
|
|
port: int = 3306
|
||
|
|
username: str = "root"
|
||
|
|
password: str = "password"
|
||
|
|
name: str = "security_monitor"
|
||
|
|
echo: bool = False
|
||
|
|
|
||
|
|
@property
|
||
|
|
def url(self) -> str:
|
||
|
|
if self.dialect == "sqlite":
|
||
|
|
return f"sqlite:///{self.name}.db"
|
||
|
|
return f"mysql+pymysql://{self.username}:{self.password}@{self.host}:{self.port}/{self.name}"
|
||
|
|
|
||
|
|
|
||
|
|
class ModelConfig(BaseModel):
|
||
|
|
engine_path: str = "models/yolo11n_fp16_480.engine"
|
||
|
|
pt_model_path: str = "models/yolo11n.pt"
|
||
|
|
imgsz: List[int] = [480, 480]
|
||
|
|
conf_threshold: float = 0.5
|
||
|
|
iou_threshold: float = 0.45
|
||
|
|
device: int = 0
|
||
|
|
batch_size: int = 8
|
||
|
|
half: bool = True
|
||
|
|
|
||
|
|
|
||
|
|
class StreamConfig(BaseModel):
|
||
|
|
buffer_size: int = 2
|
||
|
|
reconnect_delay: float = 3.0
|
||
|
|
timeout: float = 10.0
|
||
|
|
fps_limit: int = 30
|
||
|
|
|
||
|
|
|
||
|
|
class InferenceConfig(BaseModel):
|
||
|
|
queue_maxlen: int = 100
|
||
|
|
event_queue_maxlen: int = 1000
|
||
|
|
worker_threads: int = 4
|
||
|
|
|
||
|
|
|
||
|
|
class AlertConfig(BaseModel):
|
||
|
|
snapshot_path: str = "data/alerts"
|
||
|
|
cooldown_sec: int = 300
|
||
|
|
image_quality: int = 85
|
||
|
|
|
||
|
|
|
||
|
|
class ROIConfig(BaseModel):
|
||
|
|
default_types: List[str] = ["polygon", "line"]
|
||
|
|
max_points: int = 50
|
||
|
|
|
||
|
|
|
||
|
|
class WorkingHours(BaseModel):
|
||
|
|
start: List[int] = Field(default_factory=lambda: [8, 30])
|
||
|
|
end: List[int] = Field(default_factory=lambda: [17, 30])
|
||
|
|
|
||
|
|
|
||
|
|
class AlgorithmsConfig(BaseModel):
|
||
|
|
leave_post_threshold_sec: int = 360
|
||
|
|
leave_post_confirm_sec: int = 30
|
||
|
|
leave_post_return_sec: int = 5
|
||
|
|
intrusion_check_interval_sec: float = 1.0
|
||
|
|
intrusion_direction_sensitive: bool = False
|
||
|
|
|
||
|
|
|
||
|
|
class LoggingConfig(BaseModel):
|
||
|
|
level: str = "INFO"
|
||
|
|
format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||
|
|
file: str = "logs/app.log"
|
||
|
|
max_size: str = "100MB"
|
||
|
|
backup_count: int = 5
|
||
|
|
|
||
|
|
|
||
|
|
class MonitoringConfig(BaseModel):
|
||
|
|
enabled: bool = True
|
||
|
|
port: int = 9090
|
||
|
|
path: str = "/metrics"
|
||
|
|
|
||
|
|
|
||
|
|
class LLMConfig(BaseModel):
|
||
|
|
enabled: bool = False
|
||
|
|
api_key: str = ""
|
||
|
|
base_url: str = ""
|
||
|
|
model: str = "qwen-vl-max"
|
||
|
|
timeout: int = 30
|
||
|
|
|
||
|
|
|
||
|
|
class Config(BaseModel):
|
||
|
|
database: DatabaseConfig = Field(default_factory=DatabaseConfig)
|
||
|
|
model: ModelConfig = Field(default_factory=ModelConfig)
|
||
|
|
stream: StreamConfig = Field(default_factory=StreamConfig)
|
||
|
|
inference: InferenceConfig = Field(default_factory=InferenceConfig)
|
||
|
|
alert: AlertConfig = Field(default_factory=AlertConfig)
|
||
|
|
roi: ROIConfig = Field(default_factory=ROIConfig)
|
||
|
|
working_hours: List[WorkingHours] = Field(default_factory=lambda: [
|
||
|
|
WorkingHours(start=[8, 30], end=[11, 0]),
|
||
|
|
WorkingHours(start=[12, 0], end=[17, 30])
|
||
|
|
])
|
||
|
|
algorithms: AlgorithmsConfig = Field(default_factory=AlgorithmsConfig)
|
||
|
|
logging: LoggingConfig = Field(default_factory=LoggingConfig)
|
||
|
|
monitoring: MonitoringConfig = Field(default_factory=MonitoringConfig)
|
||
|
|
llm: LLMConfig = Field(default_factory=LLMConfig)
|
||
|
|
|
||
|
|
|
||
|
|
_config: Optional[Config] = None
|
||
|
|
|
||
|
|
|
||
|
|
def load_config(config_path: Optional[str] = None) -> Config:
|
||
|
|
"""加载配置文件"""
|
||
|
|
global _config
|
||
|
|
|
||
|
|
if _config is not None:
|
||
|
|
return _config
|
||
|
|
|
||
|
|
if config_path is None:
|
||
|
|
config_path = os.environ.get(
|
||
|
|
"CONFIG_PATH",
|
||
|
|
str(Path(__file__).parent / "config.yaml")
|
||
|
|
)
|
||
|
|
|
||
|
|
if os.path.exists(config_path):
|
||
|
|
with open(config_path, "r", encoding="utf-8") as f:
|
||
|
|
yaml_config = yaml.safe_load(f) or {}
|
||
|
|
else:
|
||
|
|
yaml_config = {}
|
||
|
|
|
||
|
|
_config = Config(**yaml_config)
|
||
|
|
return _config
|
||
|
|
|
||
|
|
|
||
|
|
def get_config() -> Config:
|
||
|
|
"""获取配置单例"""
|
||
|
|
if _config is None:
|
||
|
|
return load_config()
|
||
|
|
return _config
|
||
|
|
|
||
|
|
|
||
|
|
def reload_config(config_path: Optional[str] = None) -> Config:
|
||
|
|
"""重新加载配置"""
|
||
|
|
global _config
|
||
|
|
_config = None
|
||
|
|
return load_config(config_path)
|