Spaces:
Paused
Paused
| """Resolve Space-specific runtime defaults for Hermes containers.""" | |
| from __future__ import annotations | |
| import os | |
| import shlex | |
| import sys | |
| from collections.abc import Mapping, Sequence | |
| from pathlib import Path | |
| SPACE_WEB_ARGS = ["dashboard", "--host", "0.0.0.0", "--port", "7860", "--no-open"] | |
| DEFAULT_HERMES_HOME = "/opt/data" | |
| SPACE_HERMES_HOME = "/data/hermes" | |
| DEFAULT_API_SERVER_PORT = "8642" | |
| DEFAULT_API_SERVER_UPSTREAM_HOST = "127.0.0.1" | |
| API_SERVER_PORT_PATHS = ( | |
| ("platforms", "api_server", "extra", "port"), | |
| ("platforms", "api_server", "port"), | |
| ("api_server", "extra", "port"), | |
| ("api_server", "port"), | |
| ) | |
| def is_hf_space(env: Mapping[str, str]) -> bool: | |
| return bool(env.get("SPACE_ID") or env.get("SPACE_HOST")) | |
| def resolve_hermes_home(env: Mapping[str, str]) -> str: | |
| current = env.get("HERMES_HOME") or DEFAULT_HERMES_HOME | |
| if is_hf_space(env) and current == DEFAULT_HERMES_HOME: | |
| return SPACE_HERMES_HOME | |
| return current | |
| def resolve_default_command(env: Mapping[str, str], argv: Sequence[str]) -> list[str]: | |
| if argv: | |
| return list(argv) | |
| if is_hf_space(env): | |
| return SPACE_WEB_ARGS.copy() | |
| return [] | |
| def resolve_hermes_command( | |
| env: Mapping[str, str], | |
| argv: Sequence[str], | |
| executable: str = "hermes", | |
| ) -> list[str]: | |
| return [executable, *resolve_default_command(env, argv)] | |
| def _resolve_config_path(env: Mapping[str, str]) -> Path: | |
| return Path(resolve_hermes_home(env)) / "config.yaml" | |
| def _strip_inline_comment(text: str) -> str: | |
| quote: str | None = None | |
| result: list[str] = [] | |
| for char in text: | |
| if char in {"'", '"'}: | |
| if quote == char: | |
| quote = None | |
| elif quote is None: | |
| quote = char | |
| if char == "#" and quote is None: | |
| break | |
| result.append(char) | |
| return "".join(result).rstrip() | |
| def _parse_scalar(text: str) -> str | None: | |
| value = _strip_inline_comment(text).strip() | |
| if not value: | |
| return None | |
| if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}: | |
| return value[1:-1] | |
| return value | |
| def _read_yaml_path_value(text: str, target_paths: Sequence[tuple[str, ...]]) -> str | None: | |
| stack: list[tuple[int, str]] = [] | |
| for raw_line in text.splitlines(): | |
| line = raw_line.rstrip() | |
| stripped = line.lstrip(" ") | |
| if not stripped or stripped.startswith("#") or stripped.startswith("-"): | |
| continue | |
| indent = len(line) - len(stripped) | |
| key, separator, remainder = stripped.partition(":") | |
| if not separator: | |
| continue | |
| while stack and indent <= stack[-1][0]: | |
| stack.pop() | |
| path = tuple(part for _, part in stack) + (key.strip(),) | |
| value = _parse_scalar(remainder) | |
| if path in target_paths and value is not None: | |
| return value | |
| if value is None: | |
| stack.append((indent, key.strip())) | |
| return None | |
| def _config_api_server_port(env: Mapping[str, str]) -> str | None: | |
| config_path = _resolve_config_path(env) | |
| try: | |
| config_text = config_path.read_text(encoding="utf-8") | |
| except OSError: | |
| return None | |
| value = _read_yaml_path_value(config_text, API_SERVER_PORT_PATHS) | |
| if value is None: | |
| return None | |
| try: | |
| port = int(value, 10) | |
| except ValueError: | |
| return None | |
| if 0 < port <= 65535: | |
| return str(port) | |
| return None | |
| def resolve_api_server_port(env: Mapping[str, str]) -> str: | |
| explicit = (env.get("API_SERVER_PORT") or "").strip() | |
| if explicit: | |
| return explicit | |
| return _config_api_server_port(env) or DEFAULT_API_SERVER_PORT | |
| def resolve_api_server_upstream(env: Mapping[str, str]) -> str: | |
| explicit = (env.get("UPSTREAM") or "").strip() | |
| if explicit: | |
| return explicit | |
| return f"http://{DEFAULT_API_SERVER_UPSTREAM_HOST}:{resolve_api_server_port(env)}" | |
| def _command_string(env: Mapping[str, str], argv: Sequence[str]) -> str: | |
| executable = env.get("HERMES_EXECUTABLE", "hermes") | |
| return shlex.join(resolve_hermes_command(env, argv, executable=executable)) | |
| def main(argv: Sequence[str] | None = None) -> int: | |
| argv = list(sys.argv[1:] if argv is None else argv) | |
| env = os.environ | |
| if not argv or argv[0] == "home": | |
| print(resolve_hermes_home(env)) | |
| return 0 | |
| if argv[0] == "command": | |
| print(_command_string(env, argv[1:])) | |
| return 0 | |
| if argv[0] == "api-server-port": | |
| print(resolve_api_server_port(env)) | |
| return 0 | |
| if argv[0] == "api-server-upstream": | |
| print(resolve_api_server_upstream(env)) | |
| return 0 | |
| if argv[0] == "exec": | |
| print_only = False | |
| args = argv[1:] | |
| if args and args[0] == "--print-only": | |
| print_only = True | |
| args = args[1:] | |
| command = resolve_hermes_command( | |
| env, | |
| args, | |
| executable=env.get("HERMES_EXECUTABLE", "hermes"), | |
| ) | |
| if print_only: | |
| print(shlex.join(command)) | |
| return 0 | |
| os.execvpe(command[0], command, dict(env)) | |
| prog = os.path.basename(sys.argv[0] or "space_runtime.py") | |
| raise SystemExit( | |
| f"Usage: {prog} [home|command|api-server-port|api-server-upstream|exec [--print-only] [args...]]" | |
| ) | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |