2026-08-17 21:25:46 +08:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
"""OPC 智能园区后端 —— 全局配置(backend/.env 可覆盖,未配置时用默认值)"""
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent # backend/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _load_dotenv(path):
|
|
|
|
|
|
"""极简 .env 解析:KEY=VALUE,支持 # 注释与引号"""
|
|
|
|
|
|
if not Path(path).exists():
|
|
|
|
|
|
return
|
|
|
|
|
|
for raw in Path(path).read_text("utf-8").splitlines():
|
|
|
|
|
|
line = raw.strip()
|
|
|
|
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
|
|
|
|
continue
|
|
|
|
|
|
key, _, value = line.partition("=")
|
|
|
|
|
|
key = key.strip()
|
|
|
|
|
|
value = value.strip().strip('"').strip("'")
|
|
|
|
|
|
if key and key not in os.environ:
|
|
|
|
|
|
os.environ[key] = value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_load_dotenv(BASE_DIR / ".env")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _env(key, default):
|
|
|
|
|
|
return os.getenv(key, default)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Settings:
|
|
|
|
|
|
# ---- HTTP ----
|
|
|
|
|
|
HOST = _env("DPM_HOST", _env("FASTAPI_HOST", "0.0.0.0"))
|
|
|
|
|
|
PORT = int(_env("DPM_PORT", _env("FASTAPI_PORT", "8000")))
|
|
|
|
|
|
|
|
|
|
|
|
# ---- 数据目录 ----
|
|
|
|
|
|
MEDIA_DIR = Path(_env("DPM_MEDIA_DIR", str(BASE_DIR / "media")))
|
|
|
|
|
|
DATA_FILE = Path(_env("DPM_DATA_FILE", str(BASE_DIR / "data.json")))
|
|
|
|
|
|
DIST_DIR = Path(_env("DPM_DIST_DIR", str(BASE_DIR.parent / "dist"))) # 前端构建产物(可选托管)
|
|
|
|
|
|
|
|
|
|
|
|
# ---- MQTT(优先使用 .env 中的局域网 Broker 配置) ----
|
|
|
|
|
|
MQTT_ENABLED = _env("DPM_MQTT_ENABLED", "1") == "1"
|
2026-08-18 09:05:23 +08:00
|
|
|
|
MQTT_HOST = _env("DPM_MQTT_HOST", _env("MQTT_BROKER_HOST", "192.168.1.9"))
|
2026-08-17 21:25:46 +08:00
|
|
|
|
MQTT_PORT = int(_env("DPM_MQTT_PORT", _env("MQTT_BROKER_PORT", "1883")))
|
|
|
|
|
|
MQTT_USERNAME = _env("DPM_MQTT_USERNAME", _env("MQTT_USERNAME", "")) or None
|
|
|
|
|
|
MQTT_PASSWORD = _env("DPM_MQTT_PASSWORD", _env("MQTT_PASSWORD", "")) or None
|
|
|
|
|
|
MQTT_CLIENT_ID = _env("DPM_MQTT_CLIENT_ID", "dpm-backend")
|
|
|
|
|
|
# 前端 WebSocket 接入地址(默认按 .env 的 broker 主机 + EMQX 常规 ws 端口)
|
|
|
|
|
|
MQTT_WS_URL = _env(
|
|
|
|
|
|
"DPM_MQTT_WS",
|
|
|
|
|
|
f"ws://{_env('MQTT_PUBLIC_HOST', _env('MQTT_BROKER_HOST', 'localhost'))}:8083/mqtt",
|
|
|
|
|
|
)
|
|
|
|
|
|
MQTT_TICK_INTERVAL = float(_env("DPM_MQTT_TICK_INTERVAL", "2.2"))
|
|
|
|
|
|
|
|
|
|
|
|
# ---- 主题 ----
|
|
|
|
|
|
TOPIC_COMMAND = _env("DPM_TOPIC_COMMAND", "opc/display/command")
|
|
|
|
|
|
TOPIC_TICK = _env("DPM_TOPIC_TICK", "opc/dashboard/tick")
|
|
|
|
|
|
TOPIC_ACK = _env("DPM_TOPIC_ACK", "opc/display/ack")
|
2026-08-17 21:54:23 +08:00
|
|
|
|
TOPIC_HEARTBEAT = _env("DPM_TOPIC_HEARTBEAT", "opc/display/heartbeat")
|
|
|
|
|
|
SCREEN_TTL = float(_env("DPM_SCREEN_TTL", "30")) # 大屏心跳过期秒数
|
2026-08-17 21:25:46 +08:00
|
|
|
|
|
|
|
|
|
|
# ---- 阿里云 DashScope(LLM + 语音识别) ----
|
|
|
|
|
|
DASHSCOPE_API_KEY = _env("DASHSCOPE_API_KEY", "")
|
|
|
|
|
|
LLM_MODEL = _env("DPM_LLM_MODEL", "qwen-plus") # 通义千问
|
|
|
|
|
|
ASR_MODEL = _env("DPM_ASR_MODEL", "paraformer-realtime-v2") # 流式语音识别
|
|
|
|
|
|
LLM_BASE_URL = _env("DPM_LLM_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1")
|
|
|
|
|
|
ASR_TIMEOUT = float(_env("DPM_ASR_TIMEOUT", "30"))
|
|
|
|
|
|
|
2026-08-17 21:30:44 +08:00
|
|
|
|
# ---- 管理后台 ----
|
|
|
|
|
|
ADMIN_SECRET = _env("DPM_ADMIN_SECRET", "dpm-admin-secret-change-me")
|
|
|
|
|
|
|
2026-08-18 01:37:48 +08:00
|
|
|
|
# ---- s2s 实时语音栈(VAD本地 + 云ASR/LLM/TTS) ----
|
|
|
|
|
|
S2S_ENABLED = _env("DPM_S2S_ENABLED", "0") == "1"
|
|
|
|
|
|
S2S_HOST = _env("DPM_S2S_HOST", "0.0.0.0")
|
|
|
|
|
|
S2S_PORT = int(_env("DPM_S2S_PORT", "8765"))
|
|
|
|
|
|
S2S_NUM_PIPELINES = int(_env("DPM_S2S_NUM_PIPELINES", "1"))
|
|
|
|
|
|
S2S_STT_MODEL = _env("DPM_S2S_STT_MODEL", "qwen3-asr-flash-realtime")
|
|
|
|
|
|
S2S_LLM_MODEL = _env("DPM_S2S_LLM_MODEL", "qwen-plus")
|
|
|
|
|
|
S2S_TTS_MODEL = _env("DPM_S2S_TTS_MODEL", "qwen3-tts-flash-realtime")
|
|
|
|
|
|
S2S_TTS_VOICE = _env("DPM_S2S_TTS_VOICE", "Cherry")
|
|
|
|
|
|
S2S_BUILD_RETRIES = int(_env("DPM_S2S_BUILD_RETRIES", "4"))
|
|
|
|
|
|
S2S_BUILD_RETRY_DELAY = float(_env("DPM_S2S_BUILD_RETRY_DELAY", "10"))
|
|
|
|
|
|
S2S_LOG_LEVEL = _env("DPM_S2S_LOG_LEVEL", "INFO").upper()
|
2026-08-18 07:47:25 +08:00
|
|
|
|
# 对外可访问的 s2s 实时语音 WS 地址(供 /api/config 下发;DPM_VOICE_WS 可显式覆盖)
|
|
|
|
|
|
S2S_WS_URL = _env(
|
|
|
|
|
|
"DPM_VOICE_WS",
|
|
|
|
|
|
f"ws://{_env('MQTT_PUBLIC_HOST', _env('MQTT_BROKER_HOST', 'localhost'))}:8765/v1/realtime",
|
|
|
|
|
|
)
|
2026-08-18 02:28:55 +08:00
|
|
|
|
# 语音助手基础提示词(.env 设 DPM_S2S_INSTRUCTIONS 可覆盖;知识库内容由 rag 自动拼接)
|
|
|
|
|
|
S2S_INSTRUCTIONS = _env(
|
|
|
|
|
|
"DPM_S2S_INSTRUCTIONS",
|
2026-08-18 08:31:53 +08:00
|
|
|
|
"你是昆小创,昆明市大学生创业园的专属智能语音助手。可用工具:get_park_overview(园区实时数据)、"
|
2026-08-18 02:28:55 +08:00
|
|
|
|
"query_companies(企业名录)、control_display(大屏控制)、get_time(时间)。"
|
|
|
|
|
|
"涉及园区数据/企业/大屏控制时务必调用工具获取准确信息。请用简洁专业的中文回答,不超过三句话。",
|
|
|
|
|
|
)
|
2026-08-18 01:37:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-08-17 21:25:46 +08:00
|
|
|
|
|
|
|
|
|
|
settings = Settings()
|