""" Centralized configuration management for saas-search. Loads configuration from environment variables and .env file. This module provides a single point for loading .env and setting defaults. All configuration variables are exported directly - no need for getter functions. """ import os from pathlib import Path from dotenv import load_dotenv # Load .env file from project root PROJECT_ROOT = Path(__file__).parent.parent load_dotenv(PROJECT_ROOT / '.env') # Elasticsearch Configuration ES_CONFIG = { 'host': os.getenv('ES_HOST', 'http://localhost:9200'), 'username': os.getenv('ES_USERNAME'), 'password': os.getenv('ES_PASSWORD'), } # Runtime environment & index namespace # RUNTIME_ENV: 当前运行环境,建议使用 prod / uat / test / dev 等枚举值 RUNTIME_ENV = os.getenv('RUNTIME_ENV', 'prod') # ES_INDEX_NAMESPACE: 用于按环境隔离索引的命名空间前缀,例如 "uat_" / "test_" # 为空字符串时表示不加前缀(通常是 prod 环境) ES_INDEX_NAMESPACE = os.getenv('ES_INDEX_NAMESPACE') if ES_INDEX_NAMESPACE is None: # 未显式配置时,非 prod 环境默认加 "_" 前缀,prod 环境默认不加前缀 ES_INDEX_NAMESPACE = '' if RUNTIME_ENV == 'prod' else f'{RUNTIME_ENV}_' # Redis Configuration REDIS_CONFIG = { 'host': os.getenv('REDIS_HOST', 'localhost'), 'port': int(os.getenv('REDIS_PORT', 6479)), 'snapshot_db': int(os.getenv('REDIS_SNAPSHOT_DB', 0)), 'password': os.getenv('REDIS_PASSWORD'), 'socket_timeout': int(os.getenv('REDIS_SOCKET_TIMEOUT', 1)), 'socket_connect_timeout': int(os.getenv('REDIS_SOCKET_CONNECT_TIMEOUT', 1)), 'retry_on_timeout': os.getenv('REDIS_RETRY_ON_TIMEOUT', 'False').lower() == 'true', 'cache_expire_days': int(os.getenv('REDIS_CACHE_EXPIRE_DAYS', 360*2)), # 6 months 'translation_cache_expire_days': int(os.getenv('REDIS_TRANSLATION_CACHE_EXPIRE_DAYS', 360*2)), 'translation_cache_prefix': os.getenv('REDIS_TRANSLATION_CACHE_PREFIX', 'trans'), } # DeepL API Key DEEPL_AUTH_KEY = os.getenv('DEEPL_AUTH_KEY') # DashScope API Key (for Qwen models) DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY') # API Service Configuration API_HOST = os.getenv('API_HOST', '0.0.0.0') API_PORT = int(os.getenv('API_PORT', 6002)) # Indexer service INDEXER_HOST = os.getenv('INDEXER_HOST', '0.0.0.0') INDEXER_PORT = int(os.getenv('INDEXER_PORT', 6004)) # Optional dependent services EMBEDDING_HOST = os.getenv('EMBEDDING_HOST', '127.0.0.1') EMBEDDING_PORT = int(os.getenv('EMBEDDING_PORT', 6005)) TRANSLATION_HOST = os.getenv('TRANSLATION_HOST', '127.0.0.1') TRANSLATION_PORT = int(os.getenv('TRANSLATION_PORT', os.getenv('TRANSLATOR_PORT', 6006))) TRANSLATION_PROVIDER = os.getenv('TRANSLATION_PROVIDER', 'direct') TRANSLATION_MODEL = os.getenv('TRANSLATION_MODEL', 'qwen') RERANKER_HOST = os.getenv('RERANKER_HOST', '127.0.0.1') RERANKER_PORT = int(os.getenv('RERANKER_PORT', 6007)) RERANK_PROVIDER = os.getenv('RERANK_PROVIDER', 'http') # API_BASE_URL: 如果未设置,根据API_HOST构建(0.0.0.0使用localhost) API_BASE_URL = os.getenv('API_BASE_URL') if not API_BASE_URL: API_BASE_URL = f'http://localhost:{API_PORT}' if API_HOST == '0.0.0.0' else f'http://{API_HOST}:{API_PORT}' INDEXER_BASE_URL = os.getenv('INDEXER_BASE_URL') or ( f'http://localhost:{INDEXER_PORT}' if INDEXER_HOST == '0.0.0.0' else f'http://{INDEXER_HOST}:{INDEXER_PORT}' ) EMBEDDING_SERVICE_URL = os.getenv('EMBEDDING_SERVICE_URL') or f'http://{EMBEDDING_HOST}:{EMBEDDING_PORT}' TRANSLATION_SERVICE_URL = os.getenv('TRANSLATION_SERVICE_URL') or f'http://{TRANSLATION_HOST}:{TRANSLATION_PORT}' RERANKER_SERVICE_URL = os.getenv('RERANKER_SERVICE_URL') or f'http://{RERANKER_HOST}:{RERANKER_PORT}/rerank' # Model IDs / paths TEXT_MODEL_DIR = os.getenv('TEXT_MODEL_DIR', os.getenv('TEXT_MODEL_ID', 'Qwen/Qwen3-Embedding-0.6B')) IMAGE_MODEL_DIR = os.getenv('IMAGE_MODEL_DIR', '/data/tw/models/cn-clip') # Cache Directory CACHE_DIR = os.getenv('CACHE_DIR', '.cache') # MySQL Database Configuration (Shoplazza) DB_CONFIG = { 'host': os.getenv('DB_HOST'), 'port': int(os.getenv('DB_PORT', 3306)) if os.getenv('DB_PORT') else 3306, 'database': os.getenv('DB_DATABASE'), 'username': os.getenv('DB_USERNAME'), 'password': os.getenv('DB_PASSWORD'), } def print_config(): """Print current configuration (with sensitive data masked).""" print("=" * 60) print("saas-search Configuration") print("=" * 60) print("\nElasticsearch:") print(f" Host: {ES_CONFIG['host']}") print(f" Username: {ES_CONFIG['username']}") print(f" Password: {'*' * 10 if ES_CONFIG['password'] else 'None'}") print("\nRedis:") print(f" Host: {REDIS_CONFIG['host']}") print(f" Port: {REDIS_CONFIG['port']}") print(f" Password: {'*' * 10 if REDIS_CONFIG['password'] else 'None'}") print("\nDeepL:") print(f" API Key: {'*' * 10 if DEEPL_AUTH_KEY else 'None (translation disabled)'}") print("\nAPI Service:") print(f" Host: {API_HOST}") print(f" Port: {API_PORT}") print("\nModels:") print(f" Text Model: {TEXT_MODEL_DIR}") print(f" Image Model: {IMAGE_MODEL_DIR}") print("\nCache:") print(f" Cache Directory: {CACHE_DIR}") print("\nMySQL Database:") print(f" Host: {DB_CONFIG['host']}") print(f" Port: {DB_CONFIG['port']}") print(f" Database: {DB_CONFIG['database']}") print(f" Username: {DB_CONFIG['username']}") print(f" Password: {'*' * 10 if DB_CONFIG['password'] else 'None'}") print("=" * 60) if __name__ == "__main__": print_config()