"""项目路径与环境变量加载。""" from __future__ import annotations import os import sys from pathlib import Path from dotenv import load_dotenv ROOT = Path(__file__).resolve().parent.parent BOT_DIR = ROOT / "bot" OUTPUT_DIR = ROOT / "output" LOG_DIR = ROOT / "logs" CACHE_DIR = ROOT / ".cache" SNAPSHOT_FILE = CACHE_DIR / "last-report.json" # 企微 webhook markdown.content 硬上限 WECOM_MARKDOWN_LIMIT = 4096 def wecom_chunk_bytes() -> int: """单条企微 markdown 消息字节上限。""" chunk = env_int("DAILY_WECOM_CHUNK_BYTES", -1) if chunk < 0: chunk = env_int("DAILY_WECOM_MAX_BYTES", WECOM_MARKDOWN_LIMIT) return min(chunk, WECOM_MARKDOWN_LIMIT) def wecom_skill_desc_limit() -> int: """企微 Skills 榜单条简介建议字数。""" return env_int("DAILY_WECOM_SKILL_DESC_LIMIT", 56) def full_desc_limit() -> int: """完整版早报摘要长度;0 表示不截断。""" return env_int("DAILY_FULL_DESC_LIMIT", 0) def news_summary_limit() -> int: return env_int("DAILY_FULL_NEWS_SUMMARY_LIMIT", 0) def wecom_max_bytes() -> int: """兼容旧配置名。""" return wecom_chunk_bytes() load_dotenv(ROOT / ".env") load_dotenv(ROOT / ".env.local", override=True) def ensure_bot_on_path() -> None: bot = str(BOT_DIR) if bot not in sys.path: sys.path.insert(0, bot) def _clean_env_value(raw: str | None) -> str | None: if raw is None: return None value = raw.strip() if not value: return None # .env 行内注释(未加引号时 python-dotenv 不会自动去掉) if " #" in value: value = value.split(" #", 1)[0].rstrip() return value or None def env(key: str, default: str | None = None) -> str | None: return _clean_env_value(os.getenv(key, default)) def env_int(key: str, default: int) -> int: raw = env(key) if not raw: return default try: return int(raw) except ValueError: return default