2026-02-05 13:56:39 +08:00
|
|
|
|
"""
|
|
|
|
|
|
配置管理
|
|
|
|
|
|
"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
import os
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class DatabaseConfig:
|
2026-02-05 13:56:39 +08:00
|
|
|
|
"""数据库配置"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
url: str = "sqlite:///./data/alert_platform.db"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
2026-02-09 17:47:35 +08:00
|
|
|
|
class COSConfig:
|
2026-03-02 13:33:28 +08:00
|
|
|
|
"""腾讯云 COS 存储配置(通过 CVM 角色认证,无需密钥)"""
|
2026-02-09 17:47:35 +08:00
|
|
|
|
region: str = "ap-beijing"
|
|
|
|
|
|
bucket: str = "" # 格式: bucketname-appid
|
|
|
|
|
|
upload_prefix: str = "alerts" # 对象 Key 前缀
|
|
|
|
|
|
presign_expire: int = 1800 # 预签名URL有效期(秒),默认30分钟
|
2026-03-02 13:33:28 +08:00
|
|
|
|
enabled: bool = False # 是否启用 COS
|
2026-02-02 09:40:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class AppConfig:
|
2026-02-05 13:56:39 +08:00
|
|
|
|
"""应用配置"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
host: str = "0.0.0.0"
|
|
|
|
|
|
port: int = 8000
|
|
|
|
|
|
debug: bool = True
|
2026-02-06 16:39:53 +08:00
|
|
|
|
dev_mode: bool = True # 开发模式:跳过认证验证,返回超级管理员权限
|
2026-02-02 09:40:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class AIModelConfig:
|
2026-02-05 13:56:39 +08:00
|
|
|
|
"""AI 模型配置"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
endpoint: str = ""
|
|
|
|
|
|
api_key: str = ""
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-06 13:35:40 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class VLMConfig:
|
|
|
|
|
|
"""VLM 视觉语言模型配置"""
|
|
|
|
|
|
api_key: str = ""
|
|
|
|
|
|
base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
|
|
|
|
model: str = "qwen3-vl-flash-2026-01-22"
|
|
|
|
|
|
timeout: int = 10
|
|
|
|
|
|
enabled: bool = False
|
|
|
|
|
|
enable_thinking: bool = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class WeChatConfig:
|
|
|
|
|
|
"""企微通知配置"""
|
|
|
|
|
|
corp_id: str = ""
|
|
|
|
|
|
agent_id: str = ""
|
|
|
|
|
|
secret: str = ""
|
|
|
|
|
|
token: str = ""
|
|
|
|
|
|
encoding_aes_key: str = ""
|
|
|
|
|
|
enabled: bool = False
|
2026-03-09 10:42:32 +08:00
|
|
|
|
test_uids: str = "" # 演示模式:逗号分隔的企微userid,如 "zhangsan,lisi"
|
2026-03-11 17:43:58 +08:00
|
|
|
|
service_base_url: str = "" # 公网地址,如 https://vsp.viewshanghai.com
|
|
|
|
|
|
group_chat_id: str = "" # 告警群聊ID(通过企微API创建或手动指定)
|
2026-03-09 10:42:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class AgentConfig:
|
2026-03-24 11:17:12 +08:00
|
|
|
|
"""交互Agent配置"""
|
2026-03-20 11:04:08 +08:00
|
|
|
|
vlm_api_key: str = ""
|
|
|
|
|
|
vlm_base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
2026-03-24 11:17:12 +08:00
|
|
|
|
vlm_model: str = "qwen3-vl-flash-2026-01-22" # 视觉模型(图片分析保留)
|
|
|
|
|
|
model: str = "qwen3.5-plus" # 文本模型(Function Calling)
|
2026-03-20 11:04:08 +08:00
|
|
|
|
vlm_timeout: int = 15
|
2026-03-24 11:17:12 +08:00
|
|
|
|
timeout: int = 30 # FC 多轮超时
|
2026-03-09 10:42:32 +08:00
|
|
|
|
enabled: bool = False
|
2026-03-06 13:35:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-12 16:34:54 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class WorkOrderConfig:
|
|
|
|
|
|
"""安保工单开放接口配置"""
|
|
|
|
|
|
base_url: str = "" # 工单系统地址,如 http://aiot-platform.viewsh.com:48080
|
|
|
|
|
|
app_id: str = "" # 应用ID
|
|
|
|
|
|
app_secret: str = "" # 应用密钥
|
2026-03-13 13:37:34 +08:00
|
|
|
|
tenant_id: str = "1" # 租户编号
|
2026-03-12 16:34:54 +08:00
|
|
|
|
timeout: int = 10 # 请求超时(秒)
|
|
|
|
|
|
enabled: bool = False
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-10 15:22:01 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class RedisConfig:
|
|
|
|
|
|
"""Redis 配置"""
|
|
|
|
|
|
host: str = "localhost"
|
|
|
|
|
|
port: int = 6379
|
|
|
|
|
|
password: str = ""
|
|
|
|
|
|
db: int = 0
|
|
|
|
|
|
max_connections: int = 50
|
|
|
|
|
|
decode_responses: bool = True
|
2026-02-05 13:56:39 +08:00
|
|
|
|
enabled: bool = True
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-23 16:50:07 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class EdgeAuthConfig:
|
|
|
|
|
|
"""Edge 设备认证配置"""
|
|
|
|
|
|
token: str = "" # 共享 Token,Edge 请求时携带 Authorization: Bearer {token}
|
|
|
|
|
|
enabled: bool = False # 是否启用 token 校验
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-24 17:43:52 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class DailyReportConfig:
|
|
|
|
|
|
"""日报配置"""
|
|
|
|
|
|
enabled: bool = False
|
|
|
|
|
|
send_hour: int = 9
|
|
|
|
|
|
send_minute: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-24 13:59:13 +08:00
|
|
|
|
@dataclass
|
|
|
|
|
|
class CameraNameConfig:
|
2026-03-24 13:38:45 +08:00
|
|
|
|
"""摄像头名称配置"""
|
2026-02-24 13:59:13 +08:00
|
|
|
|
wvp_api_base: str = "http://localhost:18080"
|
2026-03-02 13:33:28 +08:00
|
|
|
|
query_timeout: int = 15
|
2026-02-24 13:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-02-02 09:40:02 +08:00
|
|
|
|
class Settings(BaseModel):
|
2026-02-05 13:56:39 +08:00
|
|
|
|
"""全局配置"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
database: DatabaseConfig = DatabaseConfig()
|
2026-03-31 10:49:42 +08:00
|
|
|
|
iot_database_url: str = "" # IoT 平台数据库(跨库只读查询)
|
2026-02-09 17:47:35 +08:00
|
|
|
|
cos: COSConfig = COSConfig()
|
2026-02-02 09:40:02 +08:00
|
|
|
|
app: AppConfig = AppConfig()
|
|
|
|
|
|
ai_model: AIModelConfig = AIModelConfig()
|
2026-03-06 13:35:40 +08:00
|
|
|
|
vlm: VLMConfig = VLMConfig()
|
|
|
|
|
|
wechat: WeChatConfig = WeChatConfig()
|
2026-03-09 10:42:32 +08:00
|
|
|
|
agent: AgentConfig = AgentConfig()
|
2026-03-12 16:34:54 +08:00
|
|
|
|
work_order: WorkOrderConfig = WorkOrderConfig()
|
2026-02-10 15:22:01 +08:00
|
|
|
|
redis: RedisConfig = RedisConfig()
|
2026-03-24 17:43:52 +08:00
|
|
|
|
daily_report: DailyReportConfig = DailyReportConfig()
|
2026-02-24 13:59:13 +08:00
|
|
|
|
camera_name: CameraNameConfig = CameraNameConfig()
|
2026-03-23 16:50:07 +08:00
|
|
|
|
edge_auth: EdgeAuthConfig = EdgeAuthConfig()
|
2026-02-02 09:40:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load_settings() -> Settings:
|
2026-02-05 13:56:39 +08:00
|
|
|
|
"""从环境变量加载配置"""
|
2026-02-02 09:40:02 +08:00
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
load_dotenv()
|
|
|
|
|
|
|
|
|
|
|
|
return Settings(
|
|
|
|
|
|
database=DatabaseConfig(
|
|
|
|
|
|
url=os.getenv("DATABASE_URL", "sqlite:///./data/alert_platform.db"),
|
|
|
|
|
|
),
|
2026-03-31 10:49:42 +08:00
|
|
|
|
iot_database_url=os.getenv("IOT_DATABASE_URL", ""),
|
2026-02-09 17:47:35 +08:00
|
|
|
|
cos=COSConfig(
|
|
|
|
|
|
region=os.getenv("COS_REGION", "ap-beijing"),
|
|
|
|
|
|
bucket=os.getenv("COS_BUCKET", ""),
|
|
|
|
|
|
upload_prefix=os.getenv("COS_UPLOAD_PREFIX", "alerts"),
|
|
|
|
|
|
presign_expire=int(os.getenv("COS_PRESIGN_EXPIRE", "1800")),
|
|
|
|
|
|
enabled=os.getenv("COS_ENABLED", "false").lower() == "true",
|
2026-02-02 09:40:02 +08:00
|
|
|
|
),
|
|
|
|
|
|
app=AppConfig(
|
|
|
|
|
|
host=os.getenv("APP_HOST", "0.0.0.0"),
|
|
|
|
|
|
port=int(os.getenv("APP_PORT", "8000")),
|
|
|
|
|
|
debug=os.getenv("DEBUG", "true").lower() == "true",
|
2026-02-06 16:39:53 +08:00
|
|
|
|
dev_mode=os.getenv("DEV_MODE", "true").lower() == "true",
|
2026-02-02 09:40:02 +08:00
|
|
|
|
),
|
|
|
|
|
|
ai_model=AIModelConfig(
|
|
|
|
|
|
endpoint=os.getenv("AI_MODEL_ENDPOINT", ""),
|
|
|
|
|
|
api_key=os.getenv("AI_MODEL_API_KEY", ""),
|
|
|
|
|
|
),
|
2026-03-06 13:35:40 +08:00
|
|
|
|
vlm=VLMConfig(
|
|
|
|
|
|
api_key=os.getenv("DASHSCOPE_API_KEY", ""),
|
|
|
|
|
|
base_url=os.getenv("VLM_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"),
|
|
|
|
|
|
model=os.getenv("VLM_MODEL", "qwen3-vl-flash-2026-01-22"),
|
|
|
|
|
|
timeout=int(os.getenv("VLM_TIMEOUT", "10")),
|
|
|
|
|
|
enabled=os.getenv("VLM_ENABLED", "false").lower() == "true",
|
|
|
|
|
|
enable_thinking=os.getenv("VLM_ENABLE_THINKING", "false").lower() == "true",
|
|
|
|
|
|
),
|
|
|
|
|
|
wechat=WeChatConfig(
|
|
|
|
|
|
corp_id=os.getenv("WECHAT_CORP_ID", ""),
|
|
|
|
|
|
agent_id=os.getenv("WECHAT_AGENT_ID", ""),
|
|
|
|
|
|
secret=os.getenv("WECHAT_SECRET", ""),
|
|
|
|
|
|
token=os.getenv("WECHAT_TOKEN", ""),
|
|
|
|
|
|
encoding_aes_key=os.getenv("WECHAT_ENCODING_AES_KEY", ""),
|
|
|
|
|
|
enabled=os.getenv("WECHAT_ENABLED", "false").lower() == "true",
|
2026-03-09 10:42:32 +08:00
|
|
|
|
test_uids=os.getenv("WECHAT_TEST_UIDS", ""),
|
|
|
|
|
|
service_base_url=os.getenv("SERVICE_BASE_URL", ""),
|
2026-03-11 17:43:58 +08:00
|
|
|
|
group_chat_id=os.getenv("WECHAT_GROUP_CHAT_ID", ""),
|
2026-03-09 10:42:32 +08:00
|
|
|
|
),
|
|
|
|
|
|
agent=AgentConfig(
|
2026-03-20 11:04:08 +08:00
|
|
|
|
vlm_api_key=os.getenv("DASHSCOPE_API_KEY", ""),
|
|
|
|
|
|
vlm_base_url=os.getenv("AGENT_VLM_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"),
|
|
|
|
|
|
vlm_model=os.getenv("AGENT_VLM_MODEL", os.getenv("VLM_MODEL", "qwen3-vl-flash-2026-01-22")),
|
2026-03-24 11:17:12 +08:00
|
|
|
|
model=os.getenv("AGENT_MODEL", "qwen3.5-plus"),
|
2026-03-20 11:04:08 +08:00
|
|
|
|
vlm_timeout=int(os.getenv("AGENT_VLM_TIMEOUT", "15")),
|
2026-03-24 11:17:12 +08:00
|
|
|
|
timeout=int(os.getenv("AGENT_TIMEOUT", "30")),
|
2026-03-09 10:42:32 +08:00
|
|
|
|
enabled=os.getenv("AGENT_ENABLED", "false").lower() == "true",
|
2026-03-06 13:35:40 +08:00
|
|
|
|
),
|
2026-03-12 16:34:54 +08:00
|
|
|
|
work_order=WorkOrderConfig(
|
|
|
|
|
|
base_url=os.getenv("WORK_ORDER_BASE_URL", ""),
|
|
|
|
|
|
app_id=os.getenv("WORK_ORDER_APP_ID", ""),
|
|
|
|
|
|
app_secret=os.getenv("WORK_ORDER_APP_SECRET", ""),
|
2026-03-13 13:37:34 +08:00
|
|
|
|
tenant_id=os.getenv("WORK_ORDER_TENANT_ID", "1"),
|
2026-03-12 16:34:54 +08:00
|
|
|
|
timeout=int(os.getenv("WORK_ORDER_TIMEOUT", "10")),
|
|
|
|
|
|
enabled=os.getenv("WORK_ORDER_ENABLED", "false").lower() == "true",
|
|
|
|
|
|
),
|
2026-02-10 15:22:01 +08:00
|
|
|
|
redis=RedisConfig(
|
|
|
|
|
|
host=os.getenv("REDIS_HOST", "localhost"),
|
|
|
|
|
|
port=int(os.getenv("REDIS_PORT", "6379")),
|
|
|
|
|
|
password=os.getenv("REDIS_PASSWORD", ""),
|
|
|
|
|
|
db=int(os.getenv("REDIS_DB", "0")),
|
|
|
|
|
|
max_connections=int(os.getenv("REDIS_MAX_CONNECTIONS", "50")),
|
|
|
|
|
|
enabled=os.getenv("REDIS_ENABLED", "true").lower() == "true",
|
2026-02-05 13:56:39 +08:00
|
|
|
|
),
|
2026-02-24 13:59:13 +08:00
|
|
|
|
camera_name=CameraNameConfig(
|
|
|
|
|
|
wvp_api_base=os.getenv("WVP_API_BASE", "http://localhost:18080"),
|
2026-03-02 13:33:28 +08:00
|
|
|
|
query_timeout=int(os.getenv("CAMERA_QUERY_TIMEOUT", "15")),
|
2026-02-24 13:59:13 +08:00
|
|
|
|
),
|
2026-03-24 17:43:52 +08:00
|
|
|
|
daily_report=DailyReportConfig(
|
|
|
|
|
|
enabled=os.getenv("DAILY_REPORT_ENABLED", "false").lower() == "true",
|
|
|
|
|
|
send_hour=int(os.getenv("DAILY_REPORT_HOUR", "9")),
|
|
|
|
|
|
send_minute=int(os.getenv("DAILY_REPORT_MINUTE", "0")),
|
|
|
|
|
|
),
|
2026-03-23 16:50:07 +08:00
|
|
|
|
edge_auth=EdgeAuthConfig(
|
|
|
|
|
|
token=os.getenv("EDGE_AUTH_TOKEN", ""),
|
|
|
|
|
|
enabled=os.getenv("EDGE_AUTH_ENABLED", "false").lower() == "true",
|
|
|
|
|
|
),
|
2026-02-02 09:40:02 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
settings = load_settings()
|