Files
server-core/app/config.py
T
Pine b90539a013 feat(server): 统一登录+算力打通(port 阶段0-1)落地四层架构
- 登录:/auth/send-code·phone-login·wx-login·wx-phone(复用 RBAC 签发)
- 算力:services/compute_client(loopback :3000)+ /admin/compute/ping·provision
- /v1 relay 改走 compute-engine(前端不直连引擎)
- 模型:User 补 wx_openid/phone;仓储 async create+新方法
- 契约:api/schemas(auth/compute)Pydantic
2026-08-24 14:16:34 +08:00

135 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""全局配置:端口、数据目录、令牌有效期、认证开关。
所有路径/开关均可通过环境变量覆盖,便于部署和测试:
PINEAGENTS_DEMO_HOST / PINEAGENTS_DEMO_PORT 监听地址(默认 127.0.0.1:8090
PINEAGENTS_DEMO_DATA_DIR JSON 数据目录(默认 <项目根>/data
PINEAGENTS_DEMO_AUTH_ENABLED 认证开关(默认 true)
"""
from __future__ import annotations
import os
from pathlib import Path
# 项目根目录 = 本文件的上上级(app/config.py -> <根>
BASE_DIR = Path(__file__).resolve().parent.parent
# ---------------------------------------------------------------------------
# 数据目录(serverdata/ 统一承载所有资源:data/logs/files/keys/prompts/uploads
# ---------------------------------------------------------------------------
SERVERDATA_DIR = Path(
os.environ.get("PINEAGENTS_SERVERDATA_DIR", str(BASE_DIR / "serverdata")),
).resolve()
# 数据子目录(缺失自动创建,start.sh 亦负责初始化)
DATA_DIR = SERVERDATA_DIR / "data"
LOG_DIR = SERVERDATA_DIR / "logs"
FILES_DIR = SERVERDATA_DIR / "files"
KEYS_DIR = SERVERDATA_DIR / "keys"
PROMPTS_DIR = SERVERDATA_DIR / "prompts"
UPLOADS_DIR = SERVERDATA_DIR / "uploads"
for _d in (DATA_DIR, LOG_DIR, FILES_DIR, KEYS_DIR, PROMPTS_DIR, UPLOADS_DIR):
_d.mkdir(parents=True, exist_ok=True)
# 数据库连接(异步)。开发默认 SQLite+aiosqlite;生产用 MySQL+asyncmy(环境变量覆盖)。
# 示例 MySQLPINEAGENTS_DEMO_DATABASE_URL=mysql+asyncmy://user:pass@127.0.0.1:3306/opc?charset=utf8mb4
DATABASE_URL = os.environ.get(
"PINEAGENTS_DEMO_DATABASE_URL",
f"sqlite+aiosqlite:///{DATA_DIR / 'app.db'}",
)
# Redis(缓存/会话/限流/分布式锁),空则降级内存。
REDIS_URL = os.environ.get("REDIS_URL", "redis://127.0.0.1:6379/0")
# OSS 对象存储(aioboto3,兼容阿里云 OSS / MinIO);空则文件落 serverdata/uploads。
OSS_ENDPOINT = os.environ.get("OSS_ENDPOINT", "")
OSS_ACCESS_KEY = os.environ.get("OSS_ACCESS_KEY", "")
OSS_SECRET_KEY = os.environ.get("OSS_SECRET_KEY", "")
OSS_BUCKET = os.environ.get("OSS_BUCKET", "opc-files")
USERS_FILE = DATA_DIR / "users.json"
TOKENS_FILE = DATA_DIR / "tokens.json"
AGENTS_FILE = DATA_DIR / "agents.json"
# 智能体初始化 md 模板(镜像本地 md_files 结构;qa 已统一为 PineAgents 品牌)。
# 目录:<PROMPTS_DIR>/<lang>/*.md(通用)、<PROMPTS_DIR>/qa/<lang>/*.md、
# <PROMPTS_DIR>/local/<lang>/*.md
TEMPLATES_DIR = PROMPTS_DIR
# 首次启动时用于初始化 data/ 的种子数据(提交到仓库,数据可读)。
SEED_DIR = BASE_DIR / "data" / "seed"
SEED_USERS_FILE = SEED_DIR / "demo_users.json"
# ---------------------------------------------------------------------------
# 服务监听
# ---------------------------------------------------------------------------
HOST = os.environ.get("PINEAGENTS_DEMO_HOST", "127.0.0.1")
PORT = int(os.environ.get("PINEAGENTS_DEMO_PORT", "8090"))
# ---------------------------------------------------------------------------
# 认证与令牌
# ---------------------------------------------------------------------------
# 演示服务默认开启认证(PineAgents 主后端把 /auth/* 转发到本服务)。
AUTH_ENABLED = (
os.environ.get("PINEAGENTS_DEMO_AUTH_ENABLED", "true").strip().lower()
in ("true", "1", "yes")
)
# 令牌有效期(秒):默认 7 天;-1/0 表示永久(按 100 年封顶)。
DEFAULT_TOKEN_EXPIRY_SECONDS = 7 * 24 * 3600
PERMANENT_TOKEN_SECONDS = 100 * 365 * 24 * 3600
TOKEN_EXPIRY_MAX = PERMANENT_TOKEN_SECONDS
# ---------------------------------------------------------------------------
# JWT
# ---------------------------------------------------------------------------
JWT_SECRET = os.environ.get(
"PINEAGENTS_DEMO_JWT_SECRET",
"dev-insecure-change-me-0123456789abcdef",
)
JWT_ALGORITHM = os.environ.get("PINEAGENTS_DEMO_JWT_ALGORITHM", "HS256")
JWT_ACCESS_EXPIRY_SECONDS = DEFAULT_TOKEN_EXPIRY_SECONDS
# ---------------------------------------------------------------------------
# 算力引擎(compute-engine / new-api)管理接入(loopback,仅服务)
# 模型调用与额度/令牌/流水均经此引擎计量;前端不直连引擎。
# ---------------------------------------------------------------------------
COMPUTE_BASE_URL = os.environ.get(
"PINEAGENTS_COMPUTE_BASE_URL", "http://127.0.0.1:3000",
)
# new-api 系统访问令牌(管理 API 程序化调用用;非空则 /v1 中继走引擎)
COMPUTE_ADMIN_TOKEN = os.environ.get("PINEAGENTS_COMPUTE_ADMIN_TOKEN", "")
COMPUTE_TIMEOUT = float(os.environ.get("PINEAGENTS_COMPUTE_TIMEOUT", "10"))
COMPUTE_RETRIES = int(os.environ.get("PINEAGENTS_COMPUTE_RETRIES", "2"))
# ---------------------------------------------------------------------------
# 短信验证码(统一登录)
# ---------------------------------------------------------------------------
# stub = 仅打印验证码不真正发送(默认,便于联调);生产接阿里云/腾讯云短信。
SMS_PROVIDER = os.environ.get("PINEAGENTS_SMS_PROVIDER", "stub").strip().lower()
SMS_CODE_TTL_SECONDS = int(os.environ.get("PINEAGENTS_SMS_CODE_TTL_SECONDS", "300"))
SMS_RATE_LIMIT = int(os.environ.get("PINEAGENTS_SMS_RATE_LIMIT", "5"))
# ---------------------------------------------------------------------------
# 微信小程序登录(空 appid/secret 时把 code 直通当作 openid,便于无真实 appid 联调)
# ---------------------------------------------------------------------------
WECHAT_APPID = os.environ.get("PINEAGENTS_WECHAT_APPID", "")
WECHAT_SECRET = os.environ.get("PINEAGENTS_WECHAT_SECRET", "")
def resolve_token_expiry(expires_in: int | None) -> int:
"""把前端传来的 ``expires_in`` 归一化为秒数。
- None → 默认 7 天
- <= 0(含 -1/0)→ 永久(100 年)
- 其他 → 按最大值封顶
"""
if expires_in is None:
return DEFAULT_TOKEN_EXPIRY_SECONDS
if expires_in <= 0:
return PERMANENT_TOKEN_SECONDS
return min(expires_in, TOKEN_EXPIRY_MAX)