Spaces:
Runtime error
Runtime error
| import os | |
| from dataclasses import dataclass | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| TEMPLATE_ROOT = Path(__file__).resolve().parents[1] | |
| load_dotenv(TEMPLATE_ROOT / ".env.example", override=False) | |
| load_dotenv(TEMPLATE_ROOT / ".env", override=True) | |
| def env_bool(name, default=False): | |
| value = os.getenv(name) | |
| if value is None: | |
| return default | |
| return value.strip().lower() in {"1", "true", "yes", "on"} | |
| def env_csv(name, default): | |
| raw_value = os.getenv(name) | |
| if raw_value is None: | |
| raw_value = os.getenv("SUPABASE_REQUEST_EVENT", default) | |
| return tuple(item.strip() for item in raw_value.split(",") if item.strip()) | |
| def mount_child_path(mount_path, child_name): | |
| return f"{mount_path.rstrip('/')}/{child_name.lstrip('/')}" | |
| class Settings: | |
| supabase_url: str | |
| supabase_key: str | |
| inbox_topic: str | |
| request_events: tuple[str, ...] | |
| response_event: str | |
| inbox_private: bool | |
| response_private: bool | |
| realtime_vsn: str | |
| broadcast_self: bool | |
| reply_channel_template: str | |
| heartbeat_seconds: int | |
| reconnect_seconds: int | |
| hang_after_worker_start: bool | |
| log_level: str | |
| model_bucket_id: str | |
| model_bucket_mount_path: str | |
| protexa_instruction_repo_id: str | |
| protexa_instruction_model_dir: str | |
| def from_env(cls): | |
| model_mount_path = os.getenv("MODEL_BUCKET_MOUNT_PATH", "/models") | |
| return cls( | |
| supabase_url=os.getenv("SUPABASE_URL", "").rstrip("/"), | |
| supabase_key=os.getenv("SUPABASE_SERVICE_KEY") or os.getenv("SUPABASE_ANON_KEY", ""), | |
| inbox_topic=os.getenv("SUPABASE_SPACE_INBOX_TOPIC", "space-a"), | |
| request_events=env_csv("SUPABASE_REQUEST_EVENTS", "*"), | |
| response_event=os.getenv("SUPABASE_RESPONSE_EVENT", "message"), | |
| inbox_private=env_bool("SUPABASE_SPACE_INBOX_PRIVATE", True), | |
| response_private=env_bool("SUPABASE_USER_CHANNEL_PRIVATE", True), | |
| realtime_vsn=os.getenv("SUPABASE_REALTIME_VSN", "2.0.0"), | |
| broadcast_self=env_bool("SUPABASE_BROADCAST_SELF", True), | |
| reply_channel_template=os.getenv("SUPABASE_REPLY_CHANNEL_TEMPLATE", "user-{user_id}"), | |
| heartbeat_seconds=int(os.getenv("SUPABASE_HEARTBEAT_SECONDS", "20")), | |
| reconnect_seconds=int(os.getenv("SUPABASE_RECONNECT_SECONDS", "5")), | |
| hang_after_worker_start=env_bool("SPACE_HANG_AFTER_WORKER_START", True), | |
| log_level=os.getenv("LOG_LEVEL", "INFO").upper(), | |
| model_bucket_id=os.getenv("MODEL_BUCKET_ID", "admincybers2/protexa-model-space"), | |
| model_bucket_mount_path=model_mount_path, | |
| protexa_instruction_repo_id=os.getenv( | |
| "PROTEXA_INSTRUCTION_REPO_ID", | |
| "admincybers2/protexa_instruction", | |
| ), | |
| protexa_instruction_model_dir=os.getenv( | |
| "PROTEXA_INSTRUCTION_MODEL_DIR", | |
| mount_child_path(model_mount_path, "protexa_instruction"), | |
| ), | |
| ) | |
| def require_supabase(self): | |
| if not self.supabase_url: | |
| raise RuntimeError("SUPABASE_URL is required") | |
| if not self.supabase_key: | |
| raise RuntimeError("SUPABASE_SERVICE_KEY or SUPABASE_ANON_KEY is required") | |
| def accepts_request_event(self, event): | |
| return "*" in self.request_events or event in self.request_events | |