use once_cell::sync::Lazy; use std::env; use std::sync::RwLock; pub static RUNTIME_CACHE_ENABLED: Lazy> = Lazy::new(|| { let initial = env::var("MONGODB_CACHE_ENABLED") .unwrap_or_else(|_| "true".to_string()) .parse() .unwrap_or(true); RwLock::new(initial) }); pub fn get_cache_enabled() -> bool { *RUNTIME_CACHE_ENABLED.read().unwrap() } pub fn set_cache_enabled(enabled: bool) { *RUNTIME_CACHE_ENABLED.write().unwrap() = enabled; tracing::info!("Cache enabled set to: {}", enabled); } // Switch 1: watcher detects new file → auto-register pub static RUNTIME_WATCHER_AUTO_REGISTER: Lazy> = Lazy::new(|| RwLock::new(false)); pub fn get_watcher_auto_register() -> bool { *RUNTIME_WATCHER_AUTO_REGISTER.read().unwrap() } pub fn set_watcher_auto_register(enabled: bool) { *RUNTIME_WATCHER_AUTO_REGISTER.write().unwrap() = enabled; tracing::info!("Watcher auto-register set to: {}", enabled); } // Switch 2: register → auto-trigger processing pipeline pub static RUNTIME_AUTO_PIPELINE_ENABLED: Lazy> = Lazy::new(|| RwLock::new(false)); pub fn get_auto_pipeline_enabled() -> bool { *RUNTIME_AUTO_PIPELINE_ENABLED.read().unwrap() } pub fn set_auto_pipeline_enabled(enabled: bool) { *RUNTIME_AUTO_PIPELINE_ENABLED.write().unwrap() = enabled; tracing::info!("Auto-pipeline enabled set to: {}", enabled); } pub static DATABASE_URL: Lazy = Lazy::new(|| { env::var("DATABASE_URL") .unwrap_or_else(|_| "postgres://accusys@localhost:5432/momentry".to_string()) }); pub static MONGODB_URL: Lazy = Lazy::new(|| { env::var("MONGODB_URL").unwrap_or_else(|_| "mongodb://localhost:27017".to_string()) }); pub static REDIS_URL: Lazy = Lazy::new(|| { env::var("REDIS_URL").unwrap_or_else(|_| { let password = env::var("REDIS_PASSWORD").unwrap_or_else(|_| "accusys".to_string()); // Format: redis://[:password]@host:port (use default user) format!("redis://default:{}@localhost:6379", password) }) }); pub static REDIS_PASSWORD: Lazy = Lazy::new(|| env::var("REDIS_PASSWORD").unwrap_or_else(|_| "accusys".to_string())); pub static OUTPUT_DIR: Lazy = Lazy::new(|| { env::var("MOMENTRY_OUTPUT_DIR").unwrap_or_else(|_| "/Users/accusys/momentry/output".to_string()) }); pub static BACKUP_DIR: Lazy = Lazy::new(|| { env::var("MOMENTRY_BACKUP_DIR") .unwrap_or_else(|_| "/Users/accusys/momentry/backup/momentry".to_string()) }); pub static PYTHON_PATH: Lazy = Lazy::new(|| { env::var("MOMENTRY_PYTHON_PATH").unwrap_or_else(|_| "/opt/homebrew/bin/python3.11".to_string()) }); pub static SCRIPTS_DIR: Lazy = Lazy::new(|| { env::var("MOMENTRY_SCRIPTS_DIR") .unwrap_or_else(|_| "/Users/accusys/momentry_core_0.1/scripts".to_string()) }); pub static LOG_LEVEL: Lazy = Lazy::new(|| { env::var("RUST_LOG") .or_else(|_| env::var("MOMENTRY_LOG_LEVEL")) .unwrap_or_else(|_| "info".to_string()) }); pub static MEDIA_BASE_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_MEDIA_BASE_URL") .unwrap_or_else(|_| "https://wp.momentry.ddns.net".to_string()) }); pub static STORAGE_ROOT: Lazy = Lazy::new(|| { env::var("MOMENTRY_STORAGE_ROOT") .unwrap_or_else(|_| "/Users/accusys/momentry/var/sftpgo/data".to_string()) }); pub static SERVE_BASE_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_SERVE_BASE_URL") .unwrap_or_else(|_| "https://m5wp.momentry.ddns.net/files".to_string()) }); pub static SERVER_PORT: Lazy = Lazy::new(|| { env::var("MOMENTRY_SERVER_PORT") .unwrap_or_else(|_| "3002".to_string()) .parse() .unwrap_or(3002) }); pub static REDIS_KEY_PREFIX: Lazy = Lazy::new(|| env::var("MOMENTRY_REDIS_PREFIX").unwrap_or_else(|_| "momentry:".to_string())); pub static DATABASE_SCHEMA: Lazy = Lazy::new(|| env::var("DATABASE_SCHEMA").unwrap_or_else(|_| "public".to_string())); pub static SYSTEM_TIMEZONE: Lazy = Lazy::new(|| { if let Ok(tz) = env::var("MOMENTRY_TIMEZONE") { if !tz.is_empty() { return tz; } } if let Ok(tz) = env::var("TZ") { if !tz.is_empty() { return tz; } } // macOS: /etc/localtime → /var/db/timezone/zoneinfo/Asia/Taipei // Linux: /etc/localtime → /usr/share/zoneinfo/Asia/Taipei if let Ok(path) = std::fs::read_link("/etc/localtime") { let s = path.to_string_lossy(); for prefix in &["/usr/share/zoneinfo/", "/var/db/timezone/zoneinfo/"] { if let Some(tz) = s.strip_prefix(prefix) { return tz.to_string(); } } } "Asia/Taipei".to_string() }); pub static MONGODB_DATABASE: Lazy = Lazy::new(|| env::var("MONGODB_DATABASE").unwrap_or_else(|_| "momentry".to_string())); pub static QDRANT_COLLECTION: Lazy = Lazy::new(|| env::var("QDRANT_COLLECTION").unwrap_or_else(|_| "momentry_rule1".to_string())); pub mod processor { use super::*; pub static ASR_TIMEOUT_SECS: Lazy = Lazy::new(|| { env::var("MOMENTRY_ASR_TIMEOUT") .unwrap_or_else(|_| "3600".to_string()) .parse() .unwrap_or(3600) }); pub static CUT_TIMEOUT_SECS: Lazy = Lazy::new(|| { env::var("MOMENTRY_CUT_TIMEOUT") .unwrap_or_else(|_| "3600".to_string()) .parse() .unwrap_or(3600) }); pub static DEFAULT_TIMEOUT_SECS: Lazy = Lazy::new(|| { env::var("MOMENTRY_DEFAULT_TIMEOUT") .unwrap_or_else(|_| "7200".to_string()) .parse() .unwrap_or(7200) }); pub static FORCE_RETRY: Lazy = Lazy::new(|| { env::var("MOMENTRY_FORCE_RETRY") .map(|v| v == "true" || v == "1") .unwrap_or(false) }); } pub mod cache { use super::*; pub static MONGODB_CACHE_ENABLED: Lazy = Lazy::new(|| { env::var("MONGODB_CACHE_ENABLED") .unwrap_or_else(|_| "true".to_string()) .parse() .unwrap_or(true) }); pub static MONGODB_CACHE_TTL_VIDEOS: Lazy = Lazy::new(|| { env::var("MONGODB_CACHE_TTL_VIDEOS") .unwrap_or_else(|_| "300".to_string()) .parse() .unwrap_or(300) }); pub static MONGODB_CACHE_TTL_SEARCH: Lazy = Lazy::new(|| { env::var("MONGODB_CACHE_TTL_SEARCH") .unwrap_or_else(|_| "300".to_string()) .parse() .unwrap_or(300) }); pub static MONGODB_CACHE_TTL_HYBRID_SEARCH: Lazy = Lazy::new(|| { env::var("MONGODB_CACHE_TTL_HYBRID_SEARCH") .unwrap_or_else(|_| "600".to_string()) .parse() .unwrap_or(600) }); pub static MONGODB_CACHE_TTL_VIDEO_META: Lazy = Lazy::new(|| { env::var("MONGODB_CACHE_TTL_VIDEO_META") .unwrap_or_else(|_| "3600".to_string()) .parse() .unwrap_or(3600) }); pub static REDIS_CACHE_TTL_HEALTH: Lazy = Lazy::new(|| { env::var("REDIS_CACHE_TTL_HEALTH") .unwrap_or_else(|_| "30".to_string()) .parse() .unwrap_or(30) }); pub static REDIS_CACHE_TTL_VIDEO_META: Lazy = Lazy::new(|| { env::var("REDIS_CACHE_TTL_VIDEO_META") .unwrap_or_else(|_| "3600".to_string()) .parse() .unwrap_or(3600) }); } pub mod llm { use super::*; /// Chat / function-calling LLM endpoint (agents/search, translation, etc.) /// Default: http://127.0.0.1:8082/v1/chat/completions pub static CHAT_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_CHAT_URL") .or_else(|_| env::var("MOMENTRY_LLM_SUMMARY_URL")) .or_else(|_| env::var("MOMENTRY_LLM_URL")) .unwrap_or_else(|_| "http://127.0.0.1:8082/v1/chat/completions".to_string()) }); pub static CHAT_MODEL: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_CHAT_MODEL") .or_else(|_| env::var("MOMENTRY_LLM_SUMMARY_MODEL")) .or_else(|_| env::var("MOMENTRY_LLM_MODEL")) .unwrap_or_else(|_| "google_gemma-4-26B-A4B-it-Q5_K_M.gguf".to_string()) }); /// Vision LLM endpoint (frame analysis, OCR). Can be same as CHAT_URL or different. /// Default: falls back to CHAT_URL pub static VISION_URL: Lazy = Lazy::new(|| env::var("MOMENTRY_LLM_VISION_URL").unwrap_or_else(|_| CHAT_URL.clone())); pub static VISION_MODEL: Lazy = Lazy::new(|| env::var("MOMENTRY_LLM_VISION_MODEL").unwrap_or_else(|_| CHAT_MODEL.clone())); /// Text summary LLM endpoint (5W1H, story). Can be same as CHAT_URL or different. pub static SUMMARY_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_SUMMARY_URL") .ok() .or_else(|| Some(CHAT_URL.clone())) .unwrap() }); pub static SUMMARY_MODEL: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_SUMMARY_MODEL") .ok() .or_else(|| Some(CHAT_MODEL.clone())) .unwrap() }); pub static SUMMARY_TIMEOUT_SECS: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_SUMMARY_TIMEOUT") .unwrap_or_else(|_| "120".to_string()) .parse() .unwrap_or(120) }); pub static SUMMARY_ENABLED: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_SUMMARY_ENABLED") .map(|v| v == "true" || v == "1") .unwrap_or(true) }); pub static CHAT_TIMEOUT_SECS: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_CHAT_TIMEOUT") .unwrap_or_else(|_| "120".to_string()) .parse() .unwrap_or(120) }); } /// Ollama embedding endpoint (vector embeddings for text sync). pub static OLLAMA_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_OLLAMA_URL").unwrap_or_else(|_| "http://127.0.0.1:11434".to_string()) }); /// Text embedding server (comic-embed or alternative). pub static EMBED_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_EMBED_URL").unwrap_or_else(|_| "http://127.0.0.1:11436".to_string()) }); /// LLM health endpoint. pub static LLM_HEALTH_URL: Lazy = Lazy::new(|| { env::var("MOMENTRY_LLM_HEALTH_URL").unwrap_or_else(|_| { let chat = llm::CHAT_URL.clone(); chat.trim_end_matches("/v1/chat/completions").to_string() + "/health" }) }); pub static SFTPGO_BASE_URL: Lazy = Lazy::new(|| { env::var("SFTPGO_BASE_URL").unwrap_or_else(|_| "http://127.0.0.1:8080".to_string()) }); pub static JWT_SECRET: Lazy = Lazy::new(|| { env::var("JWT_SECRET").unwrap_or_else(|_| "momentry_default_jwt_secret_change_me".to_string()) }); pub mod tmdb { use super::*; pub static API_KEY: Lazy> = Lazy::new(|| env::var("TMDB_API_KEY").ok()); pub static PROBE_ENABLED: Lazy = Lazy::new(|| { env::var("MOMENTRY_TMDB_PROBE_ENABLED") .map(|v| v == "true" || v == "1") .unwrap_or(false) }); }