diff --git a/lightrag/api/config.py b/lightrag/api/config.py index bacf1b7f..8a000f59 100644 --- a/lightrag/api/config.py +++ b/lightrag/api/config.py @@ -5,7 +5,12 @@ Configs for the LightRAG API. import os import argparse import logging +from dotenv import load_dotenv +# use the .env that is inside the current folder +# allows to use different .env file for each lightrag instance +# the OS environment variables take precedence over the .env file +load_dotenv(dotenv_path=".env", override=False) class OllamaServerInfos: # Constants for emulated Ollama model information @@ -297,6 +302,11 @@ def parse_args() -> argparse.Namespace: # Select Document loading tool (DOCLING, DEFAULT) args.document_loading_engine = get_env_value("DOCUMENT_LOADING_ENGINE", "DEFAULT") + + # Add environment variables that were previously read directly + args.cors_origins = get_env_value("CORS_ORIGINS", "*") + args.summary_language = get_env_value("SUMMARY_LANGUAGE", "en") + args.whitelist_paths = get_env_value("WHITELIST_PATHS", "/health,/api/*") # For JWT Auth args.auth_accounts = get_env_value("AUTH_ACCOUNTS", "") diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index c3837539..84390afc 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -167,10 +167,10 @@ def create_app(args): app = FastAPI(**app_kwargs) def get_cors_origins(): - """Get allowed origins from environment variable + """Get allowed origins from global_args Returns a list of allowed origins, defaults to ["*"] if not set """ - origins_str = os.getenv("CORS_ORIGINS", "*") + origins_str = global_args.cors_origins if origins_str == "*": return ["*"] return [origin.strip() for origin in origins_str.split(",")] @@ -321,6 +321,9 @@ def create_app(args): # namespace_prefix=args.namespace_prefix, auto_manage_storages_states=False, max_parallel_insert=args.max_parallel_insert, + addon_params={ + "language": args.summary_language + }, ) else: # azure_openai rag = LightRAG( @@ -351,6 +354,9 @@ def create_app(args): # namespace_prefix=args.namespace_prefix, auto_manage_storages_states=False, max_parallel_insert=args.max_parallel_insert, + addon_params={ + "language": args.summary_language + }, ) # Add routes diff --git a/lightrag/api/run_with_gunicorn.py b/lightrag/api/run_with_gunicorn.py index 065a12a1..95b12ab3 100644 --- a/lightrag/api/run_with_gunicorn.py +++ b/lightrag/api/run_with_gunicorn.py @@ -7,14 +7,9 @@ import os import sys import signal import pipmaster as pm -from lightrag.api.utils_api import parse_args, display_splash_screen, check_env_file +from lightrag.api.utils_api import display_splash_screen, check_env_file from lightrag.kg.shared_storage import initialize_share_data, finalize_share_data -from dotenv import load_dotenv - -# use the .env that is inside the current folder -# allows to use different .env file for each lightrag instance -# the OS environment variables take precedence over the .env file -load_dotenv(dotenv_path=".env", override=False) +from .config import global_args def check_and_install_dependencies(): @@ -59,20 +54,17 @@ def main(): signal.signal(signal.SIGINT, signal_handler) # Ctrl+C signal.signal(signal.SIGTERM, signal_handler) # kill command - # Parse all arguments using parse_args - args = parse_args(is_uvicorn_mode=False) - # Display startup information - display_splash_screen(args) + display_splash_screen(global_args) print("šŸš€ Starting LightRAG with Gunicorn") - print(f"šŸ”„ Worker management: Gunicorn (workers={args.workers})") + print(f"šŸ”„ Worker management: Gunicorn (workers={global_args.workers})") print("šŸ” Preloading app: Enabled") print("šŸ“ Note: Using Gunicorn's preload feature for shared data initialization") print("\n\n" + "=" * 80) print("MAIN PROCESS INITIALIZATION") print(f"Process ID: {os.getpid()}") - print(f"Workers setting: {args.workers}") + print(f"Workers setting: {global_args.workers}") print("=" * 80 + "\n") # Import Gunicorn's StandaloneApplication @@ -128,31 +120,31 @@ def main(): # Set configuration variables in gunicorn_config, prioritizing command line arguments gunicorn_config.workers = ( - args.workers if args.workers else int(os.getenv("WORKERS", 1)) + global_args.workers if global_args.workers else int(os.getenv("WORKERS", 1)) ) # Bind configuration prioritizes command line arguments - host = args.host if args.host != "0.0.0.0" else os.getenv("HOST", "0.0.0.0") - port = args.port if args.port != 9621 else int(os.getenv("PORT", 9621)) + host = global_args.host if global_args.host != "0.0.0.0" else os.getenv("HOST", "0.0.0.0") + port = global_args.port if global_args.port != 9621 else int(os.getenv("PORT", 9621)) gunicorn_config.bind = f"{host}:{port}" # Log level configuration prioritizes command line arguments gunicorn_config.loglevel = ( - args.log_level.lower() - if args.log_level + global_args.log_level.lower() + if global_args.log_level else os.getenv("LOG_LEVEL", "info") ) # Timeout configuration prioritizes command line arguments gunicorn_config.timeout = ( - args.timeout if args.timeout * 2 else int(os.getenv("TIMEOUT", 150 * 2)) + global_args.timeout if global_args.timeout * 2 else int(os.getenv("TIMEOUT", 150 * 2)) ) # Keepalive configuration gunicorn_config.keepalive = int(os.getenv("KEEPALIVE", 5)) # SSL configuration prioritizes command line arguments - if args.ssl or os.getenv("SSL", "").lower() in ( + if global_args.ssl or os.getenv("SSL", "").lower() in ( "true", "1", "yes", @@ -160,12 +152,12 @@ def main(): "on", ): gunicorn_config.certfile = ( - args.ssl_certfile - if args.ssl_certfile + global_args.ssl_certfile + if global_args.ssl_certfile else os.getenv("SSL_CERTFILE") ) gunicorn_config.keyfile = ( - args.ssl_keyfile if args.ssl_keyfile else os.getenv("SSL_KEYFILE") + global_args.ssl_keyfile if global_args.ssl_keyfile else os.getenv("SSL_KEYFILE") ) # Set configuration options from the module @@ -190,13 +182,13 @@ def main(): # Import the application from lightrag.api.lightrag_server import get_application - return get_application(args) + return get_application(global_args) # Create the application app = GunicornApp("") # Force workers to be an integer and greater than 1 for multi-process mode - workers_count = int(args.workers) + workers_count = int(global_args.workers) if workers_count > 1: # Set a flag to indicate we're in the main process os.environ["LIGHTRAG_MAIN_PROCESS"] = "1" diff --git a/lightrag/api/utils_api.py b/lightrag/api/utils_api.py index f2a51d3c..2bdc8d07 100644 --- a/lightrag/api/utils_api.py +++ b/lightrag/api/utils_api.py @@ -10,12 +10,10 @@ from ascii_colors import ASCIIColors from lightrag.api import __api_version__ as api_version from lightrag import __version__ as core_version from fastapi import HTTPException, Security, Request, status -from dotenv import load_dotenv from fastapi.security import APIKeyHeader, OAuth2PasswordBearer from starlette.status import HTTP_403_FORBIDDEN from .auth import auth_handler -from .config import ollama_server_infos -from ..prompt import PROMPTS +from .config import ollama_server_infos, global_args def check_env_file(): @@ -36,14 +34,8 @@ def check_env_file(): return True -# use the .env that is inside the current folder -# allows to use different .env file for each lightrag instance -# the OS environment variables take precedence over the .env file -load_dotenv(dotenv_path=".env", override=False) - -# Get whitelist paths from environment variable, only once during initialization -default_whitelist = "/health,/api/*" -whitelist_paths = os.getenv("WHITELIST_PATHS", default_whitelist).split(",") +# Get whitelist paths from global_args, only once during initialization +whitelist_paths = global_args.whitelist_paths.split(",") # Pre-compile path matching patterns whitelist_patterns: List[Tuple[str, bool]] = [] @@ -195,7 +187,7 @@ def display_splash_screen(args: argparse.Namespace) -> None: ASCIIColors.white(" ā”œā”€ Workers: ", end="") ASCIIColors.yellow(f"{args.workers}") ASCIIColors.white(" ā”œā”€ CORS Origins: ", end="") - ASCIIColors.yellow(f"{os.getenv('CORS_ORIGINS', '*')}") + ASCIIColors.yellow(f"{args.cors_origins}") ASCIIColors.white(" ā”œā”€ SSL Enabled: ", end="") ASCIIColors.yellow(f"{args.ssl}") if args.ssl: @@ -252,10 +244,9 @@ def display_splash_screen(args: argparse.Namespace) -> None: ASCIIColors.yellow(f"{args.embedding_dim}") # RAG Configuration - summary_language = os.getenv("SUMMARY_LANGUAGE", PROMPTS["DEFAULT_LANGUAGE"]) ASCIIColors.magenta("\nāš™ļø RAG Configuration:") ASCIIColors.white(" ā”œā”€ Summary Language: ", end="") - ASCIIColors.yellow(f"{summary_language}") + ASCIIColors.yellow(f"{args.summary_language}") ASCIIColors.white(" ā”œā”€ Max Parallel Insert: ", end="") ASCIIColors.yellow(f"{args.max_parallel_insert}") ASCIIColors.white(" ā”œā”€ Max Embed Tokens: ", end="")