1616console = Console ()
1717
1818
19+ def _get_env_file () -> Path :
20+ """
21+ Get .env file path (lightweight - no heavy imports).
22+
23+ Returns:
24+ Path to .env file - EXE directory if frozen, else current working directory
25+ """
26+ if getattr (sys , "frozen" , False ):
27+ # Running as PyInstaller EXE - use EXE's directory
28+ return Path (sys .executable ).parent / ".env"
29+ # Running as script - use current working directory
30+ return Path .cwd () / ".env"
31+
32+
1933def clear_screen ():
2034 """
2135 Cross-platform terminal clear that works robustly on both
@@ -74,7 +88,7 @@ def update(self, **kwargs):
7488 @staticmethod
7589 def update_proxy_api_key (new_key : str ):
7690 """Update PROXY_API_KEY in .env only"""
77- env_file = Path . cwd () / ".env"
91+ env_file = _get_env_file ()
7892 set_key (str (env_file ), "PROXY_API_KEY" , new_key )
7993 load_dotenv (dotenv_path = env_file , override = True )
8094
@@ -85,7 +99,7 @@ class SettingsDetector:
8599 @staticmethod
86100 def _load_local_env () -> dict :
87101 """Load environment variables from local .env file only"""
88- env_file = Path . cwd () / ".env"
102+ env_file = _get_env_file ()
89103 env_dict = {}
90104 if not env_file .exists ():
91105 return env_dict
@@ -107,7 +121,7 @@ def _load_local_env() -> dict:
107121
108122 @staticmethod
109123 def get_all_settings () -> dict :
110- """Returns comprehensive settings overview"""
124+ """Returns comprehensive settings overview (includes provider_settings which triggers heavy imports) """
111125 return {
112126 "credentials" : SettingsDetector .detect_credentials (),
113127 "custom_bases" : SettingsDetector .detect_custom_api_bases (),
@@ -117,6 +131,17 @@ def get_all_settings() -> dict:
117131 "provider_settings" : SettingsDetector .detect_provider_settings (),
118132 }
119133
134+ @staticmethod
135+ def get_basic_settings () -> dict :
136+ """Returns basic settings overview without provider_settings (avoids heavy imports)"""
137+ return {
138+ "credentials" : SettingsDetector .detect_credentials (),
139+ "custom_bases" : SettingsDetector .detect_custom_api_bases (),
140+ "model_definitions" : SettingsDetector .detect_model_definitions (),
141+ "concurrency_limits" : SettingsDetector .detect_concurrency_limits (),
142+ "model_filters" : SettingsDetector .detect_model_filters (),
143+ }
144+
120145 @staticmethod
121146 def detect_credentials () -> dict :
122147 """Detect API keys and OAuth credentials"""
@@ -260,7 +285,7 @@ def __init__(self):
260285 self .console = Console ()
261286 self .config = LauncherConfig ()
262287 self .running = True
263- self .env_file = Path . cwd () / ".env"
288+ self .env_file = _get_env_file ()
264289 # Load .env file to ensure environment variables are available
265290 load_dotenv (dotenv_path = self .env_file , override = True )
266291
@@ -277,8 +302,8 @@ def show_main_menu(self):
277302 """Display main menu and handle selection"""
278303 clear_screen ()
279304
280- # Detect all settings
281- settings = SettingsDetector .get_all_settings ()
305+ # Detect basic settings (excludes provider_settings to avoid heavy imports)
306+ settings = SettingsDetector .get_basic_settings ()
282307 credentials = settings ["credentials" ]
283308 custom_bases = settings ["custom_bases" ]
284309
@@ -363,18 +388,17 @@ def show_main_menu(self):
363388 self .console .print ("━" * 70 )
364389 provider_count = len (credentials )
365390 custom_count = len (custom_bases )
366- provider_settings = settings .get ("provider_settings" , {})
391+
392+ self .console .print (f" Providers: { provider_count } configured" )
393+ self .console .print (f" Custom Providers: { custom_count } configured" )
394+ # Note: provider_settings detection is deferred to avoid heavy imports on startup
367395 has_advanced = bool (
368396 settings ["model_definitions" ]
369397 or settings ["concurrency_limits" ]
370398 or settings ["model_filters" ]
371- or provider_settings
372399 )
373-
374- self .console .print (f" Providers: { provider_count } configured" )
375- self .console .print (f" Custom Providers: { custom_count } configured" )
376400 self .console .print (
377- f" Advanced Settings: { 'Active (view in menu 4)' if has_advanced else 'None' } "
401+ f" Advanced Settings: { 'Active (view in menu 4)' if has_advanced else 'None (view menu 4 for details) ' } "
378402 )
379403
380404 # Show menu
@@ -418,7 +442,7 @@ def show_main_menu(self):
418442 elif choice == "4" :
419443 self .show_provider_settings_menu ()
420444 elif choice == "5" :
421- load_dotenv (dotenv_path = Path . cwd () / ".env" , override = True )
445+ load_dotenv (dotenv_path = _get_env_file () , override = True )
422446 self .config = LauncherConfig () # Reload config
423447 self .console .print ("\n [green]✅ Configuration reloaded![/green]" )
424448 elif choice == "6" :
@@ -659,13 +683,14 @@ def show_provider_settings_menu(self):
659683 """Display provider/advanced settings (read-only + launch tool)"""
660684 clear_screen ()
661685
662- settings = SettingsDetector .get_all_settings ()
686+ # Use basic settings to avoid heavy imports - provider_settings deferred to Settings Tool
687+ settings = SettingsDetector .get_basic_settings ()
688+
663689 credentials = settings ["credentials" ]
664690 custom_bases = settings ["custom_bases" ]
665691 model_defs = settings ["model_definitions" ]
666692 concurrency = settings ["concurrency_limits" ]
667693 filters = settings ["model_filters" ]
668- provider_settings = settings .get ("provider_settings" , {})
669694
670695 self .console .print (
671696 Panel .fit (
@@ -740,23 +765,13 @@ def show_provider_settings_menu(self):
740765 status = " + " .join (status_parts ) if status_parts else "None"
741766 self .console .print (f" • { provider :15} ✅ { status } " )
742767
743- # Provider-Specific Settings
768+ # Provider-Specific Settings (deferred to Settings Tool to avoid heavy imports)
744769 self .console .print ()
745770 self .console .print ("[bold]🔬 Provider-Specific Settings[/bold]" )
746771 self .console .print ("━" * 70 )
747- try :
748- from proxy_app .settings_tool import PROVIDER_SETTINGS_MAP
749- except ImportError :
750- from .settings_tool import PROVIDER_SETTINGS_MAP
751- for provider in PROVIDER_SETTINGS_MAP .keys ():
752- display_name = provider .replace ("_" , " " ).title ()
753- modified = provider_settings .get (provider , 0 )
754- if modified > 0 :
755- self .console .print (
756- f" • { display_name :20} [yellow]{ modified } setting{ 's' if modified > 1 else '' } modified[/yellow]"
757- )
758- else :
759- self .console .print (f" • { display_name :20} [dim]using defaults[/dim]" )
772+ self .console .print (
773+ " [dim]Launch Settings Tool to view/configure provider-specific settings[/dim]"
774+ )
760775
761776 # Actions
762777 self .console .print ()
@@ -823,15 +838,31 @@ def launch_credential_tool(self):
823838 # Run the tool with from_launcher=True to skip duplicate loading screen
824839 run_credential_tool (from_launcher = True )
825840 # Reload environment after credential tool
826- load_dotenv (dotenv_path = Path . cwd () / ".env" , override = True )
841+ load_dotenv (dotenv_path = _get_env_file () , override = True )
827842
828843 def launch_settings_tool (self ):
829844 """Launch settings configuration tool"""
830- from proxy_app .settings_tool import run_settings_tool
845+ import time
846+
847+ clear_screen ()
848+
849+ self .console .print ("━" * 70 )
850+ self .console .print ("Advanced Settings Configuration Tool" )
851+ self .console .print ("━" * 70 )
852+
853+ _start_time = time .time ()
854+
855+ with self .console .status ("Initializing settings tool..." , spinner = "dots" ):
856+ from proxy_app .settings_tool import run_settings_tool
857+
858+ _elapsed = time .time () - _start_time
859+ self .console .print (f"✓ Settings tool ready in { _elapsed :.2f} s" )
860+
861+ time .sleep (0.3 )
831862
832863 run_settings_tool ()
833864 # Reload environment after settings tool
834- load_dotenv (dotenv_path = Path . cwd () / ".env" , override = True )
865+ load_dotenv (dotenv_path = _get_env_file () , override = True )
835866
836867 def show_about (self ):
837868 """Display About page with project information"""
@@ -919,9 +950,9 @@ def run_proxy(self):
919950 )
920951
921952 ensure_env_defaults ()
922- load_dotenv (dotenv_path = Path . cwd () / ".env" , override = True )
953+ load_dotenv (dotenv_path = _get_env_file () , override = True )
923954 run_credential_tool ()
924- load_dotenv (dotenv_path = Path . cwd () / ".env" , override = True )
955+ load_dotenv (dotenv_path = _get_env_file () , override = True )
925956
926957 # Check again after credential tool
927958 if not os .getenv ("PROXY_API_KEY" ):
0 commit comments