Merge PR #446: Add podcast-only demo mode visibility and router status

This commit is contained in:
ajaysi
2026-03-30 07:43:46 +05:30
parent c652c0d149
commit 5965e123b9
2 changed files with 251 additions and 179 deletions

View File

@@ -48,12 +48,21 @@ load_dotenv(backend_dir / '.env') # backend/.env
load_dotenv(project_root / '.env') # root .env (fallback)
load_dotenv() # CWD .env (fallback)
PODCAST_ONLY_DEMO_MODE = os.getenv("PODCAST_ONLY_DEMO_MODE", "false").lower() in {
"1",
"true",
"yes",
"on",
}
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
PODCAST_ONLY_DEMO_MODE = _env_flag_enabled(
"ALWRITY_PODCAST_ONLY_DEMO_MODE",
"PODCAST_ONLY_DEMO_MODE",
)
def is_podcast_only_demo_mode() -> bool:
@@ -63,6 +72,7 @@ def is_podcast_only_demo_mode() -> bool:
def should_include_non_podcast_features() -> bool:
return not is_podcast_only_demo_mode()
# Set up clean logging for end users
from logging_config import setup_clean_logging
setup_clean_logging()
@@ -125,8 +135,7 @@ from services.startup_health import (
# Import OAuth token monitoring routes
from api.oauth_token_monitoring_routes import router as oauth_token_monitoring_router
if not PODCAST_ONLY_DEMO_MODE:
# Import SEO Dashboard endpoints only when non-demo features are enabled
# Import SEO Dashboard endpoints
from api.seo_dashboard import (
get_seo_dashboard_data,
get_seo_health_score,
@@ -198,6 +207,7 @@ health_checker = HealthChecker()
rate_limiter = RateLimiter(window_seconds=60, max_requests=200)
frontend_serving = FrontendServing(app)
router_manager = RouterManager(app)
router_group_status: Dict[str, Dict[str, Any]] = {}
onboarding_manager = None
if not PODCAST_ONLY_DEMO_MODE:
@@ -224,7 +234,9 @@ app.middleware("http")(api_key_injection_middleware)
@app.get("/health")
async def health():
"""Health check endpoint."""
return health_checker.basic_health_check()
health_data = health_checker.basic_health_check()
health_data["podcast_only_demo_mode"] = PODCAST_ONLY_DEMO_MODE
return health_data
@app.get("/health/database")
async def database_health():
@@ -240,6 +252,7 @@ async def comprehensive_health():
async def readiness(current_user: dict = Depends(get_current_user)):
"""Readiness check that validates tenant DB resolution/session under auth context."""
return {
"podcast_only_demo_mode": PODCAST_ONLY_DEMO_MODE,
"startup": get_startup_status(),
"tenant": readiness_under_auth_context(current_user),
}
@@ -268,7 +281,14 @@ async def frontend_status():
@app.get("/api/routers/status")
async def router_status():
"""Get router inclusion status."""
return router_manager.get_router_status()
status = router_manager.get_router_status()
status.update(
{
"podcast_only_demo_mode": PODCAST_ONLY_DEMO_MODE,
"router_groups": router_group_status,
}
)
return status
# Onboarding management endpoints
@app.get("/api/onboarding/status")
@@ -284,20 +304,36 @@ async def onboarding_status():
return onboarding_manager.get_onboarding_status()
# Include routers using modular utilities
if not PODCAST_ONLY_DEMO_MODE:
router_manager.include_core_routers()
router_manager.include_optional_routers()
if PODCAST_ONLY_DEMO_MODE:
router_group_status["modular_core"] = {
"mounted": False,
"reason": "Skipped in podcast-only demo mode",
}
router_group_status["modular_optional"] = {
"mounted": False,
"reason": "Skipped in podcast-only demo mode",
}
else:
logger.info("PODCAST_ONLY_DEMO_MODE enabled: including only podcast and subscription feature routers.")
router_manager.include_router_safely(subscription_router, "subscription")
router_group_status["modular_core"] = {
"mounted": router_manager.include_core_routers(),
"reason": "Full mode",
}
router_group_status["modular_optional"] = {
"mounted": router_manager.include_optional_routers(),
"reason": "Full mode",
}
# Safety net: keep subscription routes available even if core inclusion flow changes
# in special modes (e.g., demo mode). De-dup is handled by RouterManager.
router_manager.include_router_safely(subscription_router, "subscription")
# Include assets serving router (must be mounted to serve generated images)
app.include_router(assets_serving_router)
router_group_status["assets_serving"] = {
"mounted": True,
"reason": "Required for podcast media assets",
}
if not PODCAST_ONLY_DEMO_MODE:
# SEO Dashboard endpoints
@app.get("/api/seo-dashboard/data")
async def seo_dashboard_data():
@@ -365,6 +401,8 @@ if not PODCAST_ONLY_DEMO_MODE:
"""Refresh analytics data by invalidating cache and fetching fresh data."""
return await refresh_analytics_data(current_user, site_url)
@app.get("/api/seo-dashboard/onboarding-task-health")
async def onboarding_task_health_endpoint(current_user: dict = Depends(get_current_user), site_url: str = None):
"""Get consolidated health for onboarding-scheduled SEO tasks."""
@@ -378,17 +416,31 @@ if not PODCAST_ONLY_DEMO_MODE:
# Phase 2B: Semantic health monitoring endpoint (24-hour polling)
@app.get("/api/seo-dashboard/semantic-health")
async def semantic_health_endpoint(current_user: dict = Depends(get_current_user)):
"""Get real-time semantic health metrics for content and competitors."""
"""
Get real-time semantic health metrics for content and competitors.
This endpoint provides Phase 2B semantic intelligence monitoring data.
Returns semantic health score, status, and recommendations.
Data is cached and updated every 24 hours via scheduler.
"""
return await get_semantic_health(current_user)
@app.get("/api/seo-dashboard/cache-stats")
async def semantic_cache_stats_endpoint(current_user: dict = Depends(get_current_user)):
"""Get semantic cache performance statistics."""
"""
Get semantic cache performance statistics.
Returns hit rate, memory usage, and eviction counts.
"""
return await get_semantic_cache_stats(current_user)
@app.get("/api/seo-dashboard/sif-health")
async def sif_indexing_health_endpoint(current_user: dict = Depends(get_current_user)):
"""Get SIF indexing health summary for the current user."""
"""
Get SIF indexing health summary for the current user.
Used by the Semantic Indexing Status widget on the dashboard.
"""
return await get_sif_indexing_health(current_user)
# Comprehensive SEO Analysis endpoints
@@ -423,6 +475,7 @@ if not PODCAST_ONLY_DEMO_MODE:
return await analyze_urls_ai(request, current_user)
# Include platform analytics router
if not PODCAST_ONLY_DEMO_MODE:
from routers.platform_analytics import router as platform_analytics_router
app.include_router(platform_analytics_router)
# Include Bing Analytics Storage router to expose storage-backed endpoints
@@ -436,10 +489,23 @@ if not PODCAST_ONLY_DEMO_MODE:
# Include content assets router
from api.content_assets.router import router as content_assets_router
app.include_router(content_assets_router)
router_group_status["platform_extensions"] = {
"mounted": True,
"reason": "Full mode",
}
else:
router_group_status["platform_extensions"] = {
"mounted": False,
"reason": "Skipped in podcast-only demo mode",
}
# Include Podcast Maker router
from api.podcast.router import router as podcast_router
app.include_router(podcast_router)
router_group_status["podcast_maker"] = {
"mounted": True,
"reason": "Always mounted",
}
if not PODCAST_ONLY_DEMO_MODE:
# Include YouTube Creator Studio router
@@ -465,6 +531,15 @@ if not PODCAST_ONLY_DEMO_MODE:
# Today workflow routes
from api.today_workflow import router as today_workflow_router
app.include_router(today_workflow_router)
router_group_status["advanced_workflows"] = {
"mounted": True,
"reason": "Full mode",
}
else:
router_group_status["advanced_workflows"] = {
"mounted": False,
"reason": "Skipped in podcast-only demo mode",
}
# Setup frontend serving using modular utilities
frontend_serving.setup_frontend_serving()

View File

@@ -160,6 +160,13 @@ from alwrity_utils import (
def start_backend(enable_reload=False, production_mode=False):
"""Start the backend server."""
print("🚀 Starting ALwrity Backend...")
podcast_only_demo_mode = os.getenv("ALWRITY_PODCAST_ONLY_DEMO_MODE", os.getenv("PODCAST_ONLY_DEMO_MODE", "false")).lower() in {"1", "true", "yes", "on"}
if podcast_only_demo_mode:
print("\n" + "=" * 60)
print("🎙️ PODCAST-ONLY DEMO MODE ACTIVE")
print(" Non-podcast router groups are intentionally skipped.")
print("=" * 60)
# Set host based on environment and mode
# Use 127.0.0.1 for local production testing on Windows
@@ -192,7 +199,6 @@ def start_backend(enable_reload=False, production_mode=False):
print(f" 📍 Host: {host}")
print(f" 🔌 Port: {port}")
print(f" 🔄 Reload: {reload}")
print(f" 🔄 Reload: {reload}")
try:
# Import and run the app
@@ -298,11 +304,6 @@ def main():
parser.add_argument("--dev", action="store_true", help="Enable development mode (auto-reload)")
parser.add_argument("--production", action="store_true", help="Enable production mode (optimized for deployment)")
parser.add_argument("--verbose", action="store_true", help="Enable verbose logging for debugging")
parser.add_argument(
"--podcast-only-demo",
action="store_true",
help="Enable podcast-only demo mode (sets PODCAST_ONLY_DEMO_MODE=true before app startup)",
)
args = parser.parse_args()
# Determine mode
@@ -312,8 +313,6 @@ def main():
# Set global verbose flag for utilities
os.environ["ALWRITY_VERBOSE"] = "true" if verbose_mode else "false"
if args.podcast_only_demo:
os.environ["PODCAST_ONLY_DEMO_MODE"] = "true"
print("[*] ALwrity Backend Server")
print("=" * 40)
@@ -321,8 +320,6 @@ def main():
print(f"Auto-reload: {'ENABLED' if enable_reload else 'DISABLED'}")
if verbose_mode:
print("Verbose logging: ENABLED")
if args.podcast_only_demo:
print("Podcast-only demo mode: ENABLED")
print("=" * 40)
# Check if we're in the right directory