Consolidate on ALWRITY_ENABLED_FEATURES - remove all legacy support
Backend: - Remove all legacy env var fallbacks (ALWRITY_FEATURE_PROFILE, ALWRITY_ROUTER_PROFILE, etc) - Remove get_active_profile() from start_alwrity_backend.py - Remove _env_flag_enabled() from app.py - Use ALWRITY_ENABLED_FEATURES as single source of truth Frontend: - demoMode.ts now uses only REACT_APP_ENABLED_FEATURES - Removed all legacy fallback keys (app_mode, demo_mode, podcast_only_demo_mode) Usage: ALWRITY_ENABLED_FEATURES=podcast # Podcast only ALWRITY_ENABLED_FEATURES=all # All features (default)
This commit is contained in:
@@ -9,10 +9,8 @@ from typing import Iterable, Tuple
|
||||
from .feature_registry import FEATURE_GROUPS, PROFILE_GROUP_MAP
|
||||
|
||||
|
||||
# Consolidated env var - supports both old and new format
|
||||
ENV_FEATURE_PROFILE = "ALWRITY_ENABLED_FEATURES"
|
||||
ENV_FEATURE_PROFILE_LEGACY = "ALWRITY_FEATURE_TO_ENABLE"
|
||||
DEFAULT_PROFILE = "all"
|
||||
ENV_ENABLED_FEATURES = "ALWRITY_ENABLED_FEATURES"
|
||||
DEFAULT_FEATURES = "all"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -24,31 +22,31 @@ class ExpandedFeatureProfile:
|
||||
|
||||
|
||||
class UnknownFeatureProfileError(ValueError):
|
||||
"""Raised when ALWRITY_ENABLED_FEATURES contains unknown profile values."""
|
||||
"""Raised when ALWRITY_ENABLED_FEATURES contains unknown feature values."""
|
||||
|
||||
|
||||
def _get_env_value() -> str:
|
||||
"""Get the feature profile value from environment - new var takes precedence."""
|
||||
return os.getenv(ENV_FEATURE_PROFILE) or os.getenv(ENV_FEATURE_PROFILE_LEGACY) or DEFAULT_PROFILE
|
||||
"""Get the enabled features value from environment."""
|
||||
return os.getenv(ENV_ENABLED_FEATURES) or DEFAULT_FEATURES
|
||||
|
||||
|
||||
def _normalize_values(raw_value: str | None) -> Tuple[str, ...]:
|
||||
if not raw_value or not raw_value.strip():
|
||||
return (DEFAULT_PROFILE,)
|
||||
return (DEFAULT_FEATURES,)
|
||||
|
||||
normalized = tuple(
|
||||
value.strip().lower()
|
||||
for value in raw_value.split(",")
|
||||
if value.strip()
|
||||
)
|
||||
return normalized or (DEFAULT_PROFILE,)
|
||||
return normalized or (DEFAULT_FEATURES,)
|
||||
|
||||
|
||||
def parse_feature_profiles(raw_value: str | None = None) -> Tuple[str, ...]:
|
||||
"""Parse and validate profile names from env/raw input.
|
||||
"""Parse and validate feature names from env/raw input.
|
||||
|
||||
Supports comma-separated profile names, e.g. `core,podcast`.
|
||||
Raises UnknownFeatureProfileError when any profile is not registered.
|
||||
Supports comma-separated feature names, e.g. `podcast,core`.
|
||||
Raises UnknownFeatureProfileError when any feature is not registered.
|
||||
"""
|
||||
|
||||
selected_profiles = _normalize_values(raw_value if raw_value is not None else _get_env_value())
|
||||
@@ -58,7 +56,7 @@ def parse_feature_profiles(raw_value: str | None = None) -> Tuple[str, ...]:
|
||||
supported = ", ".join(sorted(set(PROFILE_GROUP_MAP.keys()) | set(FEATURE_GROUPS.keys())))
|
||||
unknown_display = ", ".join(unknown)
|
||||
raise UnknownFeatureProfileError(
|
||||
f"Unknown {ENV_FEATURE_PROFILE} value(s): {unknown_display}. Supported profiles: {supported}."
|
||||
f"Unknown {ENV_ENABLED_FEATURES} value(s): {unknown_display}. Supported: {supported}."
|
||||
)
|
||||
|
||||
return selected_profiles
|
||||
|
||||
@@ -89,8 +89,6 @@ class RouterManager:
|
||||
- "all" - enable all features (default)
|
||||
- comma-separated: "podcast,blog-writer,youtube"
|
||||
- single feature: "podcast"
|
||||
|
||||
DEPRECATED: ALWRITY_FEATURE_PROFILE, ALWRITY_ROUTER_PROFILE, ALWRITY_FEATURE_TO_ENABLE
|
||||
"""
|
||||
env_value = os.getenv("ALWRITY_ENABLED_FEATURES", "all").strip().lower()
|
||||
|
||||
|
||||
@@ -49,16 +49,6 @@ load_dotenv(project_root / '.env') # root .env (fallback)
|
||||
load_dotenv() # CWD .env (fallback)
|
||||
|
||||
|
||||
def _env_flag_enabled(*env_names: str) -> bool:
|
||||
"""Return True when any provided env var is set to a truthy value."""
|
||||
truthy_values = {"1", "true", "yes", "on"}
|
||||
for env_name in env_names:
|
||||
value = os.getenv(env_name)
|
||||
if value and value.strip().lower() in truthy_values:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_enabled_features() -> set:
|
||||
"""Get enabled features from ALWRITY_ENABLED_FEATURES env var.
|
||||
|
||||
@@ -66,8 +56,6 @@ def get_enabled_features() -> set:
|
||||
- "all" - enable all features (default)
|
||||
- comma-separated: "podcast,core"
|
||||
- single feature: "podcast"
|
||||
|
||||
DEPRECATED: ALWRITY_FEATURE_PROFILE, ALWRITY_ROUTER_PROFILE, ALWRITY_FEATURE_TO_ENABLE
|
||||
"""
|
||||
env_value = os.getenv("ALWRITY_ENABLED_FEATURES", "all").strip().lower()
|
||||
|
||||
@@ -78,26 +66,18 @@ def get_enabled_features() -> set:
|
||||
|
||||
|
||||
def is_podcast_only_demo_mode() -> bool:
|
||||
"""Check if podcast-only mode is enabled via new or legacy flags."""
|
||||
# First check the new consolidated flag
|
||||
"""Check if podcast-only mode is enabled."""
|
||||
enabled = get_enabled_features()
|
||||
if "podcast" in enabled and "all" not in enabled:
|
||||
return True
|
||||
|
||||
# Fall back to legacy flags for backwards compatibility
|
||||
return _env_flag_enabled(
|
||||
"ALWRITY_PODCAST_ONLY_DEMO_MODE",
|
||||
"PODCAST_ONLY_DEMO_MODE"
|
||||
)
|
||||
return "podcast" in enabled and "all" not in enabled
|
||||
|
||||
|
||||
def should_include_non_podcast_features() -> bool:
|
||||
"""Check if non-podcast features should be included."""
|
||||
enabled = get_enabled_features()
|
||||
return "all" in enabled or "core" in enabled or "blog-writer" in enabled
|
||||
return "all" in enabled or "core" in enabled
|
||||
|
||||
|
||||
# Legacy constant for backwards compatibility - prefer using get_enabled_features()
|
||||
# Legacy constant for backwards compatibility
|
||||
PODCAST_ONLY_DEMO_MODE = is_podcast_only_demo_mode()
|
||||
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ def get_enabled_features() -> set:
|
||||
- "all" - enable all features (default)
|
||||
- comma-separated: "podcast,blog-writer,youtube"
|
||||
- single feature: "podcast"
|
||||
|
||||
DEPRECATED: ALWRITY_FEATURE_PROFILE, ALWRITY_ROUTER_PROFILE, ALWRITY_FEATURE_TO_ENABLE
|
||||
"""
|
||||
env_value = os.getenv("ALWRITY_ENABLED_FEATURES", "all").strip().lower()
|
||||
|
||||
@@ -44,14 +42,6 @@ def get_enabled_features() -> set:
|
||||
return {f.strip() for f in env_value.split(",") if f.strip()}
|
||||
|
||||
|
||||
def get_active_profile() -> str:
|
||||
"""Legacy function - use get_enabled_features() instead."""
|
||||
enabled = get_enabled_features()
|
||||
if "all" in enabled:
|
||||
return "all"
|
||||
return list(enabled)[0] if enabled else "all"
|
||||
|
||||
|
||||
def should_bootstrap_linguistic_models() -> bool:
|
||||
"""Decide whether to bootstrap linguistic models based on enabled features."""
|
||||
enabled_features = get_enabled_features()
|
||||
@@ -220,10 +210,11 @@ def bootstrap_local_llm_models() -> BootstrapResult:
|
||||
BOOTSTRAP_RESULTS = []
|
||||
|
||||
if __name__ == "__main__":
|
||||
profile = get_active_profile()
|
||||
os.environ["ALWRITY_ACTIVE_PROFILE"] = profile
|
||||
enabled_features = get_enabled_features()
|
||||
features_str = ",".join(sorted(enabled_features))
|
||||
os.environ["ALWRITY_ENABLED_FEATURES"] = features_str
|
||||
|
||||
print(f"\n📋 Active profile: {profile}")
|
||||
print(f"\n📋 Enabled features: {features_str}")
|
||||
|
||||
if should_bootstrap_linguistic_models():
|
||||
result = bootstrap_linguistic_models()
|
||||
@@ -240,11 +231,11 @@ if __name__ == "__main__":
|
||||
else:
|
||||
verbose = os.getenv("ALWRITY_VERBOSE", "false").lower() == "true"
|
||||
if verbose:
|
||||
print("⏭️ Skipping local LLM model bootstrap (profile-gated)")
|
||||
BOOTSTRAP_RESULTS.append(BootstrapResult(name="local_llm_models", success=True, skipped=True, reason="profile_gated"))
|
||||
print("⏭️ Skipping local LLM model bootstrap (feature-gated)")
|
||||
BOOTSTRAP_RESULTS.append(BootstrapResult(name="local_llm_models", success=True, skipped=True, reason="feature_gated"))
|
||||
|
||||
summary = {
|
||||
"active_profile": profile,
|
||||
"enabled_features": features_str,
|
||||
"bootstraps": [asdict(r) for r in BOOTSTRAP_RESULTS]
|
||||
}
|
||||
os.environ["ALWRITY_BOOTSTRAP_SUMMARY"] = json.dumps(summary)
|
||||
|
||||
Reference in New Issue
Block a user