支持自动加载.env并补充环境变量模板

- 为 configuration.py 增加项目根目录 .env 自动加载能力,启动时无需再手动 export\n- 新增 .env.example,补齐数据库、Redis、邮件、LLM 与后台 secret 等完整环境变量模板\n- 更新 .gitignore 与 README,明确 .env 的使用方式与优先级说明
This commit is contained in:
liuwei
2026-04-30 15:49:37 +08:00
parent c6d72cbb69
commit 97fc6dc2a4
4 changed files with 112 additions and 5 deletions

57
.env.example Normal file
View File

@@ -0,0 +1,57 @@
# ABOT 生产环境示例配置
# 使用方式:
# 1. 复制为 `.env`
# 2. 按实际情况替换敏感值
# 3. 直接启动 `python main.py`,程序会自动加载该文件
ABOT_ENVIRONMENT=production
ABOT_PLUGIN_DIR=plugins
ABOT_DB_POOL_NAME=wechat_boot_pool
ABOT_DB_POOL_SIZE=10
ABOT_DB_HOST=127.0.0.1
ABOT_DB_PORT=3306
ABOT_DB_USER=root
ABOT_DB_PASSWORD=please_change_me
ABOT_DB_NAME=message_archive
ABOT_DB_CHARSET=utf8mb4
ABOT_REDIS_HOST=127.0.0.1
ABOT_REDIS_PORT=6379
ABOT_REDIS_PASSWORD=
ABOT_REDIS_DB=0
ABOT_EMAIL_SMTP_SERVER=smtp.163.com
ABOT_EMAIL_SMTP_PORT=465
ABOT_EMAIL_SENDER=
ABOT_EMAIL_PASSWORD=
ABOT_EMAIL_ALERT_RECIPIENT=
ABOT_GLANCES_HOST=127.0.0.1
ABOT_GLANCES_PORT=61208
ABOT_WX_ADMIN=admin
ABOT_LLM_DEFAULT_BACKEND=dify_workflow_chat
ABOT_LLM_DIFY_API_BASE_URL=http://127.0.0.1:8080/v1
ABOT_LLM_DIFY_WORKFLOW_CHAT_API_KEY=
ABOT_LLM_DIFY_MEMBER_CONTEXT_API_KEY=
ABOT_LLM_DIFY_MESSAGE_SUMMARY_API_KEY=
ABOT_LLM_DIFY_DOUYU_REPORT_API_KEY=
ABOT_LLM_DIFY_GLOBAL_NEWS_API_KEY=
ABOT_LLM_DIFY_AUTO_REPLY_API_KEY=
ABOT_LLM_GAME_TASK_API_URL=https://api.example.com/v1/chat/completions
ABOT_LLM_GAME_TASK_API_KEY=
ABOT_LLM_GAME_TASK_MODEL=doubao-1-5-lite-32k-250115
ABOT_LLM_AUTO_REPLY_API_BASE_URL=https://api.example.com/v1
ABOT_LLM_AUTO_REPLY_API_KEY=
ABOT_LLM_AUTO_REPLY_MODEL=gpt-5.4
ABOT_LLM_IMAGE_API_BASE_URL=https://api.example.com/v1
ABOT_LLM_IMAGE_API_KEY=
ABOT_LLM_IMAGE_MODEL=gpt-image-1
# 可选:若希望后台登录会话在重启后保持稳定,建议显式配置。
ABOT_DASHBOARD_SECRET_KEY=

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.*
!.gitignore
!.env.example
!.github/
*pyc

View File

@@ -126,18 +126,16 @@ sudo apt-get install -y fonts-noto-color-emoji fonts-noto-cjk fonts-wqy-microhei
### 1. 配置文件
推荐先复制 `config.example.yaml` 为 `config.yaml`,再通过环境变量注入敏感信息
推荐先复制 `config.example.yaml` 为 `config.yaml`,再在项目根目录放置 `.env` 文件。程序启动时会自动加载该文件,不需要每次手动 `export`
```bash
# Linux / Mac
cp config.example.yaml config.yaml
export ABOT_DB_PASSWORD="你的数据库密码"
export ABOT_LLM_DIFY_WORKFLOW_CHAT_API_KEY="你的 Dify Key"
cp .env.example .env
# Windows PowerShell
Copy-Item config.example.yaml config.yaml
$env:ABOT_DB_PASSWORD="你的数据库密码"
$env:ABOT_LLM_DIFY_WORKFLOW_CHAT_API_KEY="你的 Dify Key"
Copy-Item .env.example .env
```
`config.yaml` 现已支持 `${ENV_NAME}` / `${ENV_NAME:默认值}` 两种写法:
@@ -145,6 +143,8 @@ $env:ABOT_LLM_DIFY_WORKFLOW_CHAT_API_KEY="你的 Dify Key"
- `${ABOT_DB_PASSWORD}`:必须由环境变量提供,否则启动时报错
- `${ABOT_DB_HOST:127.0.0.1}`:若环境变量缺失,则回退默认值
如果项目根目录存在 `.env`,系统会先自动加载该文件,再执行 `config.yaml` 占位符解析。
启动时系统会自动执行配置完整性检查,并在日志中输出脱敏后的配置快照。包含以下主要配置项:
#### 数据库配置

View File

@@ -42,6 +42,11 @@ class Config(object):
def __init__(self, config_path: str = None) -> None:
self.project_dir = os.path.dirname(os.path.abspath(__file__))
self.config_path = config_path or os.path.join(self.project_dir, "config.yaml")
# 启动阶段优先尝试自动加载项目根目录下的 `.env`
# 1. 用户只需要把 `.env` 放到线上目录,不必每次手动 export
# 2. 这里刻意保持“已有系统环境变量优先”,避免覆盖运维层显式注入的值;
# 3. 不额外引入第三方依赖,保持部署门槛尽量低。
self._load_local_env_file(os.path.join(self.project_dir, ".env"))
self.raw_config = {}
self.resolved_config = {}
self.unresolved_placeholders = []
@@ -54,6 +59,50 @@ class Config(object):
yconfig = yaml.safe_load(fp) or {}
return yconfig
@staticmethod
def _strip_optional_quotes(value: str) -> str:
"""去掉 `.env` 中常见的首尾引号。"""
text = str(value or "").strip()
if len(text) >= 2 and text[0] == text[-1] and text[0] in {"'", '"'}:
return text[1:-1]
return text
def _load_local_env_file(self, env_path: str) -> None:
"""从本地 `.env` 文件加载环境变量。"""
if not os.path.exists(env_path):
return
try:
with open(env_path, "r", encoding="utf-8") as env_file:
for raw_line in env_file:
line = str(raw_line or "").strip()
if not line or line.startswith("#"):
continue
# 兼容 `export KEY=value` 写法,方便 Linux 用户直接复用 shell 风格文件。
if line.startswith("export "):
line = line[len("export "):].strip()
if "=" not in line:
continue
key, value = line.split("=", 1)
key = str(key or "").strip()
value = self._strip_optional_quotes(value)
if not key:
continue
# `.env` 只在“当前进程还没有这个变量”时兜底注入:
# 1. 显式传入的系统环境变量优先级更高;
# 2. 这样本地调试和线上运维都可以覆盖 `.env` 默认值;
# 3. 也避免启动时误把运维平台上的密钥覆盖掉。
if key not in os.environ:
os.environ[key] = value
except Exception:
# `.env` 自动加载属于增强能力,不应因为格式问题直接把启动打死。
# 真正的必填项缺失会在后续 validate 阶段给出明确错误。
return
def _resolve_env_placeholders_in_string(self, raw_value: str, path: str) -> str:
"""解析字符串中的环境变量占位符。"""