Spaces:
Sleeping
Sleeping
File size: 6,805 Bytes
7131bbe fc9f64b 7131bbe fc9f64b 7131bbe 347a4d6 74ee21a 347a4d6 74ee21a 347a4d6 7131bbe 347a4d6 7131bbe fc9f64b 347a4d6 7131bbe 347a4d6 7131bbe fc9f64b 347a4d6 7131bbe 347a4d6 7131bbe fc9f64b 347a4d6 74ee21a 347a4d6 14a02b9 74ee21a 347a4d6 74ee21a 347a4d6 14a02b9 347a4d6 74ee21a 7131bbe 347a4d6 74ee21a 347a4d6 7131bbe 74ee21a 7131bbe fc9f64b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | """Runtime configuration loaded from environment variables."""
from __future__ import annotations
import os
import re
from dataclasses import dataclass
from typing import Mapping
from urllib.parse import urlparse
class ConfigurationError(RuntimeError):
"""Raised when an explicitly requested integration is not configured."""
GENBLAZE_PROVIDER_ALIASES = {
"gmi": "gmicloud",
"gmicloud": "gmicloud",
"gmi-cloud": "gmicloud",
"openai": "openai",
"dalle": "openai",
"dall-e": "openai",
"local": "local",
"local-image": "local",
}
GENBLAZE_PROVIDER_MODULES = {
"gmicloud": ("genblaze_gmicloud",),
"openai": ("genblaze_openai",),
"local": (),
}
def _env(env: Mapping[str, str], key: str, default: str = "") -> str:
return env.get(key, default).strip()
def _env_int(env: Mapping[str, str], key: str, default: int) -> int:
value = env.get(key, "").strip()
if not value:
return default
try:
return int(value)
except ValueError as exc:
raise ConfigurationError(f"{key} must be an integer") from exc
def normalize_genblaze_provider(value: str) -> str:
provider = (value or "gmicloud").strip().lower().replace("_", "-")
return GENBLAZE_PROVIDER_ALIASES.get(provider, provider)
@dataclass(frozen=True)
class Settings:
storage_backend: str = "local"
generation_backend: str = "mock"
storage_root: str = "var/storage"
b2_endpoint_url: str = ""
b2_bucket: str = ""
b2_key_id: str = ""
b2_application_key: str = ""
b2_public_base_url: str = ""
b2_region: str = ""
genblaze_provider: str = "gmicloud"
genblaze_base_url: str = ""
genblaze_api_key: str = ""
genblaze_image_model: str = ""
genblaze_aspect_ratio: str = "16:9"
genblaze_timeout_seconds: int = 180
gmi_api_key: str = ""
openai_api_key: str = ""
@classmethod
def from_env(cls, env: Mapping[str, str] | None = None) -> "Settings":
source = os.environ if env is None else env
return cls(
storage_backend=_env(source, "PROOFFRAME_STORAGE_BACKEND", "local").lower(),
generation_backend=_env(source, "PROOFFRAME_GENERATION_BACKEND", "mock").lower(),
storage_root=_env(source, "PROOFFRAME_STORAGE_ROOT", "var/storage"),
b2_endpoint_url=_env(source, "B2_ENDPOINT_URL") or _env(source, "B2_S3_ENDPOINT_URL"),
b2_bucket=_env(source, "B2_BUCKET"),
b2_key_id=_env(source, "B2_KEY_ID"),
b2_application_key=_env(source, "B2_APPLICATION_KEY") or _env(source, "B2_APP_KEY"),
b2_public_base_url=_env(source, "B2_PUBLIC_BASE_URL"),
b2_region=_env(source, "B2_REGION")
or _region_from_b2_endpoint(
_env(source, "B2_ENDPOINT_URL") or _env(source, "B2_S3_ENDPOINT_URL")
),
genblaze_provider=normalize_genblaze_provider(
_env(source, "GENBLAZE_PROVIDER", "gmicloud")
),
genblaze_base_url=_env(source, "GENBLAZE_BASE_URL") or _env(source, "GMI_BASE_URL"),
genblaze_api_key=_env(source, "GENBLAZE_API_KEY"),
genblaze_image_model=_env(source, "GENBLAZE_IMAGE_MODEL"),
genblaze_aspect_ratio=_env(source, "GENBLAZE_ASPECT_RATIO", "16:9"),
genblaze_timeout_seconds=_env_int(source, "GENBLAZE_TIMEOUT_SECONDS", 180),
gmi_api_key=_env(source, "GMI_API_KEY"),
openai_api_key=_env(source, "OPENAI_API_KEY"),
)
def require_b2(self) -> None:
missing = [
key
for key, value in {
"B2_ENDPOINT_URL": self.b2_endpoint_url,
"B2_BUCKET": self.b2_bucket,
"B2_KEY_ID": self.b2_key_id,
"B2_APPLICATION_KEY or B2_APP_KEY": self.b2_application_key,
}.items()
if not value
]
if missing:
raise ConfigurationError(
"B2 storage was requested but required environment variables are missing: "
+ ", ".join(missing)
)
def b2_region_for_backblaze(self) -> str:
return self.b2_region or _region_from_b2_endpoint(self.b2_endpoint_url)
def genblaze_provider_modules(self) -> tuple[str, ...]:
return GENBLAZE_PROVIDER_MODULES.get(self.genblaze_provider, ())
def genblaze_provider_supported(self) -> bool:
return self.genblaze_provider in GENBLAZE_PROVIDER_MODULES
def genblaze_provider_requires_key(self) -> bool:
return self.genblaze_provider != "local"
def genblaze_provider_key(self) -> str:
if self.genblaze_provider == "gmicloud":
return self.genblaze_api_key or self.gmi_api_key
if self.genblaze_provider == "openai":
return self.openai_api_key
if self.genblaze_provider == "local":
return ""
return ""
def genblaze_key_remediation(self) -> str:
if self.genblaze_provider == "local":
return "GENBLAZE_PROVIDER=local does not require a provider API key."
if self.genblaze_provider == "openai":
return "Set OPENAI_API_KEY for GENBLAZE_PROVIDER=openai."
return "Set GENBLAZE_API_KEY or GMI_API_KEY for GENBLAZE_PROVIDER=gmicloud."
def genblaze_configured(self) -> bool:
return bool(
self.genblaze_provider_supported()
and self.genblaze_image_model
and (not self.genblaze_provider_requires_key() or self.genblaze_provider_key())
)
def require_genblaze(self) -> None:
if self.genblaze_provider not in GENBLAZE_PROVIDER_MODULES:
raise ConfigurationError(
"Unsupported Genblaze provider: "
f"{self.genblaze_provider}. Use GENBLAZE_PROVIDER=gmicloud, openai, or local."
)
missing = [
key
for key, value in {
**(
{self.genblaze_key_remediation(): self.genblaze_provider_key()}
if self.genblaze_provider_requires_key()
else {}
),
"GENBLAZE_IMAGE_MODEL": self.genblaze_image_model,
}.items()
if not value
]
if missing:
raise ConfigurationError(
"Genblaze generation was requested but required environment variables are missing: "
+ ", ".join(missing)
)
def _region_from_b2_endpoint(endpoint_url: str) -> str:
if not endpoint_url:
return ""
parsed = urlparse(endpoint_url if "://" in endpoint_url else f"https://{endpoint_url}")
host = parsed.netloc or parsed.path
match = re.match(r"^s3[.-]([a-z0-9-]+)\.backblazeb2\.com$", host)
return match.group(1) if match else ""
|