CoolFace
Apppublic

Rhinox13/chatapi

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
config.py184 linesDownload Raw Back to core
1from __future__ import annotations
2
3import os
4from dataclasses import dataclass
5from pathlib import Path
6from typing import Any
7
8
9def _repo_root() -> Path:
10    return Path(__file__).resolve().parents[1]
11
12
13def _parse_env_file(path: Path) -> dict[str, str]:
14    values: dict[str, str] = {}
15    if not path.exists():
16        return values
17    for raw_line in path.read_text(encoding="utf-8").splitlines():
18        line = raw_line.strip()
19        if not line or line.startswith("#") or "=" not in line:
20            continue
21        key, value = line.split("=", 1)
22        key = key.strip()
23        value = value.strip().strip('"').strip("'")
24        if key and key not in os.environ:
25            values[key] = value
26    return values
27
28
29def _load_env_files() -> None:
30    candidates = [
31        _repo_root() / ".env",
32        _repo_root() / "backend" / ".env",
33    ]
34    external_env_file = os.environ.get("CHATAPI_ENV_FILE", "").strip()
35    if external_env_file:
36        candidates.append(Path(external_env_file).expanduser())
37    merged: dict[str, str] = {}
38    for candidate in candidates:
39        merged.update(_parse_env_file(candidate))
40    for key, value in merged.items():
41        os.environ.setdefault(key, value)
42
43
44_load_env_files()
45
46
47def _first_non_empty(*keys: str, default: str = "") -> str:
48    for key in keys:
49        value = os.environ.get(key, "").strip()
50        if value:
51            return value
52    return default
53
54
55def _split_csv(raw: str) -> list[str]:
56    return [item.strip() for item in raw.split(",") if item.strip()]
57
58
59@dataclass(frozen=True)
60class Settings:
61    admin_username: str
62    admin_password: str
63    session_secret: str
64    data_dir: Path
65    db_path: Path
66    uploads_img_dir: Path
67    cors_origins: list[str]
68    host: str
69    port: int
70    debug: bool
71    tls_cert_file: Path | None
72    tls_key_file: Path | None
73    web_dist_dir: Path | None
74    smtp_host: str
75    smtp_port: int
76    smtp_username: str
77    smtp_password: str
78    email_from: str
79    smtp_use_tls: bool
80    resend_api_key: str
81    brevo_api_key: str
82    brevo_from_name: str
83    tencentcloud_secret_id: str
84    tencentcloud_secret_key: str
85    tencentcloud_ses_region: str
86    tencentcloud_template_id: str
87    geetest_captcha_id: str
88    geetest_captcha_key: str
89    geetest_api_server: str
90
91    @classmethod
92    def from_env(cls) -> "Settings":
93        repo_root = _repo_root()
94        data_dir = Path(_first_non_empty("CHATAPI_DATA_DIR", "DATA_DIR", default=str(repo_root / "data")))
95        if not data_dir.is_absolute():
96            data_dir = (repo_root / data_dir).resolve()
97        db_path = Path(_first_non_empty("CHATAPI_DB_PATH", default=str(data_dir / "chatapi.sqlite3")))
98        if not db_path.is_absolute():
99            db_path = (repo_root / db_path).resolve()
100        uploads_img_dir = data_dir / "uploads" / "imgs"
101        cors_raw = _first_non_empty(
102            "CHATAPI_CORS_ORIGINS",
103            "CORS_ORIGINS",
104            default="http://localhost:5173,http://127.0.0.1:5173",
105        )
106        tls_cert_raw = _first_non_empty(
107            "CHATAPI_TLS_CERT_FILE",
108            "TLS_CERT_FILE",
109            default="",
110        )
111        tls_key_raw = _first_non_empty(
112            "CHATAPI_TLS_KEY_FILE",
113            "TLS_KEY_FILE",
114            default="",
115        )
116        web_dist_raw = _first_non_empty(
117            "CHATAPI_WEB_DIST_DIR",
118            "WEB_DIST_DIR",
119            default="",
120        )
121
122        def _resolve_optional_path(raw: str) -> Path | None:
123            if not raw:
124                return None
125            path = Path(raw)
126            if not path.is_absolute():
127                path = (repo_root / path).resolve()
128            return path
129
130        return cls(
131            admin_username=_first_non_empty("CHATAPI_ADMIN_USERNAME", "CHATAPI_USERNAME", "ADMIN_USERNAME", default="admin"),
132            admin_password=_first_non_empty("CHATAPI_ADMIN_PASSWORD", "CHATAPI_PASSWORD", "ADMIN_PASSWORD", default="change-me"),
133            session_secret=_first_non_empty(
134                "CHATAPI_SESSION_SECRET",
135                "ADMIN_SESSION_SECRET",
136                default="",
137            ),
138            data_dir=data_dir,
139            db_path=db_path,
140            uploads_img_dir=uploads_img_dir,
141            cors_origins=_split_csv(cors_raw),
142            host=_first_non_empty("CHATAPI_HOST", "BACKEND_HOST", default="0.0.0.0"),
143            port=int(_first_non_empty("CHATAPI_PORT", "BACKEND_PORT", default="5000")),
144            debug=_first_non_empty("CHATAPI_DEBUG", "FLASK_DEBUG", default="0") == "1",
145            tls_cert_file=_resolve_optional_path(tls_cert_raw),
146            tls_key_file=_resolve_optional_path(tls_key_raw),
147            web_dist_dir=_resolve_optional_path(web_dist_raw),
148            smtp_host=_first_non_empty("CHATAPI_SMTP_HOST", "SMTP_HOST", default=""),
149            smtp_port=int(_first_non_empty("CHATAPI_SMTP_PORT", "SMTP_PORT", default="587")),
150            smtp_username=_first_non_empty("CHATAPI_SMTP_USERNAME", "SMTP_USERNAME", default=""),
151            smtp_password=_first_non_empty("CHATAPI_SMTP_PASSWORD", "SMTP_PASSWORD", default=""),
152            email_from=_first_non_empty("CHATAPI_EMAIL_FROM", default=""),
153            smtp_use_tls=_first_non_empty("CHATAPI_SMTP_USE_TLS", "SMTP_USE_TLS", default="1") == "1",
154            resend_api_key=_first_non_empty("CHATAPI_RESEND_API_KEY", "RESEND_API_KEY", default=""),
155            brevo_api_key=_first_non_empty("CHATAPI_BREVO_API_KEY", "BREVO_API_KEY", default=""),
156            brevo_from_name=_first_non_empty("CHATAPI_BREVO_FROM_NAME", "BREVO_FROM_NAME", default="ChatAPI"),
157            tencentcloud_secret_id=_first_non_empty(
158                "CHATAPI_TENCENTCLOUD_SECRET_ID",
159                "TENCENTCLOUD_SECRET_ID",
160                default="",
161            ),
162            tencentcloud_secret_key=_first_non_empty(
163                "CHATAPI_TENCENTCLOUD_SECRET_KEY",
164                "TENCENTCLOUD_SECRET_KEY",
165                default="",
166            ),
167            tencentcloud_ses_region=_first_non_empty(
168                "CHATAPI_TENCENTCLOUD_SES_REGION",
169                "TENCENTCLOUD_SES_REGION",
170                default="ap-guangzhou",
171            ),
172            tencentcloud_template_id=_first_non_empty(
173                "CHATAPI_TENCENTCLOUD_TEMPLATE_ID",
174                "TENCENTCLOUD_TEMPLATE_ID",
175                default="",
176            ),
177            geetest_captcha_id=_first_non_empty("CHATAPI_GEETEST_CAPTCHA_ID", "GEETEST_CAPTCHA_ID", default=""),
178            geetest_captcha_key=_first_non_empty("CHATAPI_GEETEST_CAPTCHA_KEY", "GEETEST_CAPTCHA_KEY", default=""),
179            geetest_api_server=_first_non_empty("CHATAPI_GEETEST_API_SERVER", "GEETEST_API_SERVER", default="http://gcaptcha4.geetest.com"),
180        )
181
182
183settings = Settings.from_env()
184