Spaces:
Paused
Paused
Mirrowel
commited on
Commit
·
34e560e
1
Parent(s):
cf0afec
feat(auth): add interactive onboarding and credential setup with warnings
Browse files- add first-time onboarding checks in proxy_app/main.py to detect missing .env or PROXY_API_KEY and display a clear rich-powered onboarding message
- auto-launch the credential setup tool (ensure_env_defaults + run_credential_tool) and reload environment vars, with validation to prevent starting without PROXY_API_KEY
- add runtime warning when no provider credentials are configured so the proxy can start but not serve LLM requests
- change RotatingClient to log a warning instead of raising when no API keys or OAuth credentials are provided
- clear the console when the credential tool starts and exits for a cleaner interactive experience
src/proxy_app/main.py
CHANGED
|
@@ -337,6 +337,17 @@ async def lifespan(app: FastAPI):
|
|
| 337 |
)
|
| 338 |
client.background_refresher.start() # Start the background task
|
| 339 |
app.state.rotating_client = client
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
os.environ["LITELLM_LOG"] = "ERROR"
|
| 341 |
litellm.set_verbose = False
|
| 342 |
litellm.drop_params = True
|
|
@@ -747,6 +758,56 @@ async def token_count(
|
|
| 747 |
raise HTTPException(status_code=500, detail=str(e))
|
| 748 |
|
| 749 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 750 |
if args.add_credential:
|
| 751 |
# Import and call ensure_env_defaults to create .env and PROXY_API_KEY if needed
|
| 752 |
from rotator_library.credential_tool import ensure_env_defaults
|
|
@@ -755,8 +816,41 @@ if __name__ == "__main__":
|
|
| 755 |
load_dotenv(override=True)
|
| 756 |
run_credential_tool()
|
| 757 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 758 |
# Validate PROXY_API_KEY before starting the server
|
| 759 |
if not PROXY_API_KEY:
|
| 760 |
raise ValueError("PROXY_API_KEY environment variable not set. Please run with --add-credential to set up your environment.")
|
|
|
|
| 761 |
import uvicorn
|
| 762 |
uvicorn.run(app, host=args.host, port=args.port)
|
|
|
|
|
|
|
|
|
| 337 |
)
|
| 338 |
client.background_refresher.start() # Start the background task
|
| 339 |
app.state.rotating_client = client
|
| 340 |
+
|
| 341 |
+
# Warn if no provider credentials are configured
|
| 342 |
+
if not client.all_credentials:
|
| 343 |
+
logging.warning("=" * 70)
|
| 344 |
+
logging.warning("⚠️ NO PROVIDER CREDENTIALS CONFIGURED")
|
| 345 |
+
logging.warning("The proxy is running but cannot serve any LLM requests.")
|
| 346 |
+
logging.warning("Launch the credential tool to add API keys or OAuth credentials.")
|
| 347 |
+
logging.warning(" • Executable: Run with --add-credential flag")
|
| 348 |
+
logging.warning(" • Source: python src/proxy_app/main.py --add-credential")
|
| 349 |
+
logging.warning("=" * 70)
|
| 350 |
+
|
| 351 |
os.environ["LITELLM_LOG"] = "ERROR"
|
| 352 |
litellm.set_verbose = False
|
| 353 |
litellm.drop_params = True
|
|
|
|
| 758 |
raise HTTPException(status_code=500, detail=str(e))
|
| 759 |
|
| 760 |
if __name__ == "__main__":
|
| 761 |
+
# Define ENV_FILE for onboarding checks
|
| 762 |
+
ENV_FILE = Path.cwd() / ".env"
|
| 763 |
+
|
| 764 |
+
def needs_onboarding() -> bool:
|
| 765 |
+
"""
|
| 766 |
+
Check if the proxy needs onboarding (first-time setup).
|
| 767 |
+
Returns True if onboarding is needed, False otherwise.
|
| 768 |
+
"""
|
| 769 |
+
# Check 1: Does .env file exist?
|
| 770 |
+
if not ENV_FILE.is_file():
|
| 771 |
+
return True
|
| 772 |
+
|
| 773 |
+
# Check 2: Is PROXY_API_KEY set in environment?
|
| 774 |
+
if not PROXY_API_KEY:
|
| 775 |
+
return True
|
| 776 |
+
|
| 777 |
+
return False
|
| 778 |
+
|
| 779 |
+
def show_onboarding_message():
|
| 780 |
+
"""Display clear explanatory message for why onboarding is needed."""
|
| 781 |
+
console.clear() # Clear terminal for clean presentation
|
| 782 |
+
console.print(Panel.fit(
|
| 783 |
+
"[bold cyan]🚀 LLM API Key Proxy - First Time Setup[/bold cyan]",
|
| 784 |
+
border_style="cyan"
|
| 785 |
+
))
|
| 786 |
+
console.print("[bold yellow]⚠️ Configuration Required[/bold yellow]\n")
|
| 787 |
+
|
| 788 |
+
console.print("The proxy cannot start because:")
|
| 789 |
+
if not ENV_FILE.is_file():
|
| 790 |
+
console.print(" [red]❌ No .env file found[/red]")
|
| 791 |
+
else:
|
| 792 |
+
console.print(" [red]❌ PROXY_API_KEY is not set in .env[/red]")
|
| 793 |
+
|
| 794 |
+
console.print("\n[bold]Why this matters:[/bold]")
|
| 795 |
+
console.print(" • The .env file stores your proxy's authentication key")
|
| 796 |
+
console.print(" • The PROXY_API_KEY protects your proxy from unauthorized access")
|
| 797 |
+
console.print(" • Without it, the proxy cannot securely start")
|
| 798 |
+
|
| 799 |
+
console.print("\n[bold]What happens next:[/bold]")
|
| 800 |
+
console.print(" 1. We'll create a .env file with a default PROXY_API_KEY")
|
| 801 |
+
console.print(" 2. You can add LLM provider credentials (API keys or OAuth)")
|
| 802 |
+
console.print(" 3. The proxy will then start normally")
|
| 803 |
+
|
| 804 |
+
console.print("\n[bold yellow]⚠️ Important:[/bold yellow] While provider credentials are optional for startup,")
|
| 805 |
+
console.print(" the proxy won't do anything useful without them. See [bold cyan]README.md[/bold cyan]")
|
| 806 |
+
console.print(" for supported providers and setup instructions.\n")
|
| 807 |
+
|
| 808 |
+
console.input("[bold green]Press Enter to launch the credential setup tool...[/bold green]")
|
| 809 |
+
|
| 810 |
+
# Check if user explicitly wants to add credentials
|
| 811 |
if args.add_credential:
|
| 812 |
# Import and call ensure_env_defaults to create .env and PROXY_API_KEY if needed
|
| 813 |
from rotator_library.credential_tool import ensure_env_defaults
|
|
|
|
| 816 |
load_dotenv(override=True)
|
| 817 |
run_credential_tool()
|
| 818 |
else:
|
| 819 |
+
# Check if onboarding is needed
|
| 820 |
+
if needs_onboarding():
|
| 821 |
+
# Import console from rich for better messaging
|
| 822 |
+
from rich.console import Console
|
| 823 |
+
from rich.panel import Panel
|
| 824 |
+
console = Console()
|
| 825 |
+
|
| 826 |
+
# Show clear explanatory message
|
| 827 |
+
show_onboarding_message()
|
| 828 |
+
|
| 829 |
+
# Launch credential tool automatically
|
| 830 |
+
from rotator_library.credential_tool import ensure_env_defaults
|
| 831 |
+
ensure_env_defaults()
|
| 832 |
+
load_dotenv(override=True)
|
| 833 |
+
run_credential_tool()
|
| 834 |
+
|
| 835 |
+
# After credential tool exits, reload and re-check
|
| 836 |
+
load_dotenv(override=True)
|
| 837 |
+
# Re-read PROXY_API_KEY from environment
|
| 838 |
+
PROXY_API_KEY = os.getenv("PROXY_API_KEY")
|
| 839 |
+
|
| 840 |
+
# Verify onboarding is complete
|
| 841 |
+
if needs_onboarding():
|
| 842 |
+
console.print("\n[bold red]❌ Configuration incomplete.[/bold red]")
|
| 843 |
+
console.print("The proxy still cannot start. Please ensure PROXY_API_KEY is set in .env\n")
|
| 844 |
+
sys.exit(1)
|
| 845 |
+
else:
|
| 846 |
+
console.print("\n[bold green]✅ Configuration complete![/bold green]")
|
| 847 |
+
console.print("\nStarting proxy server...\n")
|
| 848 |
+
|
| 849 |
# Validate PROXY_API_KEY before starting the server
|
| 850 |
if not PROXY_API_KEY:
|
| 851 |
raise ValueError("PROXY_API_KEY environment variable not set. Please run with --add-credential to set up your environment.")
|
| 852 |
+
|
| 853 |
import uvicorn
|
| 854 |
uvicorn.run(app, host=args.host, port=args.port)
|
| 855 |
+
|
| 856 |
+
|
src/rotator_library/client.py
CHANGED
|
@@ -88,8 +88,8 @@ class RotatingClient:
|
|
| 88 |
}
|
| 89 |
|
| 90 |
if not api_keys and not oauth_credentials:
|
| 91 |
-
|
| 92 |
-
"No
|
| 93 |
)
|
| 94 |
|
| 95 |
self.api_keys = api_keys
|
|
|
|
| 88 |
}
|
| 89 |
|
| 90 |
if not api_keys and not oauth_credentials:
|
| 91 |
+
lib_logger.warning(
|
| 92 |
+
"No provider credentials configured. The client will be unable to make any API requests."
|
| 93 |
)
|
| 94 |
|
| 95 |
self.api_keys = api_keys
|
src/rotator_library/credential_tool.py
CHANGED
|
@@ -515,6 +515,7 @@ async def main():
|
|
| 515 |
"""
|
| 516 |
An interactive CLI tool to add new credentials.
|
| 517 |
"""
|
|
|
|
| 518 |
ensure_env_defaults()
|
| 519 |
console.print(Panel("[bold cyan]Interactive Credential Setup[/bold cyan]", title="--- API Key Proxy ---", expand=False))
|
| 520 |
|
|
@@ -593,5 +594,7 @@ async def main():
|
|
| 593 |
def run_credential_tool():
|
| 594 |
try:
|
| 595 |
asyncio.run(main())
|
|
|
|
| 596 |
except KeyboardInterrupt:
|
| 597 |
-
console.print("\n[bold yellow]Exiting setup.[/bold yellow]")
|
|
|
|
|
|
| 515 |
"""
|
| 516 |
An interactive CLI tool to add new credentials.
|
| 517 |
"""
|
| 518 |
+
console.clear() # Clear terminal when credential tool starts
|
| 519 |
ensure_env_defaults()
|
| 520 |
console.print(Panel("[bold cyan]Interactive Credential Setup[/bold cyan]", title="--- API Key Proxy ---", expand=False))
|
| 521 |
|
|
|
|
| 594 |
def run_credential_tool():
|
| 595 |
try:
|
| 596 |
asyncio.run(main())
|
| 597 |
+
console.clear() # Clear terminal when credential tool exits
|
| 598 |
except KeyboardInterrupt:
|
| 599 |
+
console.print("\n[bold yellow]Exiting setup.[/bold yellow]")
|
| 600 |
+
console.clear() # Clear terminal on keyboard interrupt too
|