| | |
| | | |
| | | _REGISTRY: Optional[Dict[str, Any]] = None |
| | | _VOICE_INDEX: Optional[list] = None |
| | | _REGISTRY_PATH: Optional[str] = None |
| | | _REGISTRY_MTIME: Optional[float] = None |
| | | |
| | | _BUNDLED_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "apps.json") |
| | | _MENU_PRIO = 0 |
| | |
| | | _RESERVED_PRIO = 4 |
| | | |
| | | |
| | | def _load_registry() -> Dict[str, Any]: |
| | | candidates = [ |
| | | def _registry_candidates() -> list: |
| | | return [ |
| | | os.path.join(get_project_dir(), "data", "apps.json"), |
| | | _BUNDLED_PATH, |
| | | ] |
| | | for path in candidates: |
| | | |
| | | |
| | | def _file_mtime(path: str) -> Optional[float]: |
| | | try: |
| | | return os.path.getmtime(path) |
| | | except OSError: |
| | | return None |
| | | |
| | | |
| | | def _load_registry() -> Dict[str, Any]: |
| | | global _REGISTRY_PATH, _REGISTRY_MTIME |
| | | for path in _registry_candidates(): |
| | | if not os.path.isfile(path): |
| | | continue |
| | | try: |
| | | with open(path, "r", encoding="utf-8") as f: |
| | | data = json.load(f) |
| | | if isinstance(data, dict) and data.get("apps"): |
| | | _REGISTRY_PATH = path |
| | | _REGISTRY_MTIME = _file_mtime(path) |
| | | logger.bind(tag=TAG).info(f"已加载 App 注册表: {path}") |
| | | return data |
| | | except Exception as e: |
| | | logger.bind(tag=TAG).error(f"加载 App 注册表失败 {path}: {e}") |
| | | _REGISTRY_PATH = None |
| | | _REGISTRY_MTIME = None |
| | | logger.bind(tag=TAG).warning("未找到 apps.json,使用内置最小注册表") |
| | | return { |
| | | "default_app_id": "chat", |
| | |
| | | |
| | | |
| | | def get_registry() -> Dict[str, Any]: |
| | | global _REGISTRY |
| | | global _REGISTRY, _VOICE_INDEX |
| | | if _REGISTRY is None: |
| | | _REGISTRY = _load_registry() |
| | | return _REGISTRY |
| | | if _REGISTRY_PATH: |
| | | top = next((item for item in _registry_candidates() if os.path.isfile(item)), None) |
| | | mtime = _file_mtime(_REGISTRY_PATH) |
| | | if top != _REGISTRY_PATH or (mtime is not None and mtime != _REGISTRY_MTIME): |
| | | _REGISTRY = _load_registry() |
| | | _VOICE_INDEX = None |
| | | return _REGISTRY |
| | | |
| | | |