"""共享路径和配置工具""" import os import sys import json def find_project_root(): """向上查找项目根目录(包含 data/ 目录的最顶层)""" # 从当前脚本位置开始 script_dir = os.path.dirname(os.path.abspath(__file__)) # 向上查找,找到包含 data/ 目录的目录 d = script_dir for _ in range(5): # 最多向上5级 if os.path.isdir(os.path.join(d, "data")): return d parent = os.path.dirname(d) if parent == d: break d = parent # 如果找不到,假设项目根在 scripts/ 的上一级 return os.path.dirname(os.path.dirname(script_dir)) def find_dws(): """查找 dws CLI""" import shutil # 1. 环境变量 env = os.environ.get("DWS_PATH") if env and os.path.isfile(env): return env # 2. 项目 tools/ 目录 root = find_project_root() local = os.path.join(root, "tools", "dws.exe") if os.path.isfile(local): return local # 3. 悟空内置 candidates = [ os.path.expanduser(r"~\.real\.bin\dws\bin\dws.exe"), r"C:\Program Files\Wukong\0.9.51-26052503\bin\dws.exe", ] for p in candidates: if os.path.isfile(p): return p # 4. PATH found = shutil.which("dws") if found: return found print("ERROR: 找不到 dws CLI,请设置 DWS_PATH 环境变量或安装悟空", file=sys.stderr) sys.exit(1) def find_lark_cli(): """查找 lark-cli""" import shutil root = find_project_root() ext = ".exe" if os.name == "nt" else "" local = os.path.join(root, "tools", "lark-cli", "lark-cli" + ext) if os.path.isfile(local): return local found = shutil.which("lark-cli") if found: return found print("ERROR: 找不到 lark-cli,请运行 npm install -g @larksuite/cli", file=sys.stderr) sys.exit(1) def load_groups(): """读取群配置,优先使用 data/group_config.json,失败时返回默认群。""" default = { "dc战略问题研究院": "cidoUneRB4Db8TAXaTrKxkQAw==", "创新组": "cidMuM+itt5PeY7xNSWsv3M0g==", "天龙计划X小游戏矩阵": "cid/Vb3hSjdv4sIIs8Fp7sC4g==", } path = os.path.join(find_project_root(), "data", "group_config.json") if not os.path.isfile(path): return default try: with open(path, "r", encoding="utf-8") as f: raw = json.load(f).get("groups", {}) groups = {} for name, value in raw.items(): if isinstance(value, dict): cid = value.get("cid") or value.get("id") else: cid = value if cid: groups[name] = cid return groups or default except Exception as e: print(f"WARN: 读取群配置失败,使用默认配置: {e}", file=sys.stderr) return default def normalize_messages(messages): """兼容 list 和按群 dict 两种历史消息文件格式。""" if isinstance(messages, dict): return messages grouped = {} if not isinstance(messages, list): return grouped for msg in messages: if not isinstance(msg, dict): continue group = msg.get("group") or msg.get("groupName") or msg.get("openConversationId") or "未分组" grouped.setdefault(group, []).append(msg) return grouped # 常用路径 PROJECT_ROOT = find_project_root() DATA_DIR = os.path.join(PROJECT_ROOT, "data") RAW_DIR = os.path.join(DATA_DIR, "raw-messages") LINKS_DIR = os.path.join(DATA_DIR, "links") OUTPUT_DIR = os.path.join(PROJECT_ROOT, "output") DOCS_DIR = os.path.join(OUTPUT_DIR, "feishu-docs") REPORTS_DIR = os.path.join(OUTPUT_DIR, "reports") DOWNLOAD_DIR = os.path.join(OUTPUT_DIR, "downloaded-files") OBSIDIAN_DIR = os.path.join(OUTPUT_DIR, "obsidian-vault") KG_DIR = os.path.join(OUTPUT_DIR, "knowledge-graph")