env_config.py 5.16 KB
"""
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 环境默认加 "<env>_" 前缀,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
    # Embedding 缓存 key 前缀,例如 "embedding"
    'embedding_cache_prefix': os.getenv('REDIS_EMBEDDING_CACHE_PREFIX', 'embedding'),
}

# 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', 6006))
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}'
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()