Spaces:
Paused
Paused
Mirrowel
commited on
Commit
·
e8d627c
1
Parent(s):
2e16e7e
feat(auth): add interactive API key setup supporting 70+ providers
Browse filesRefactors the credential setup utility to integrate support for standard API keys alongside existing OAuth providers.
Key changes:
- The main menu is updated to allow selection between OAuth credential setup and API key setup.
- Implements `setup_api_key` to interactively guide the user through selecting from a list of recognized LiteLLM providers.
- API keys are automatically saved to the project's `.env` file, utilizing key indexing (e.g., `OPENAI_API_KEY_1`) to support multiple keys per provider.
- Introduces `ensure_env_defaults` to automatically initialize the `.env` file and set essential default values like `PROXY_API_KEY`.
- setup_env.bat +0 -121
- src/rotator_library/credential_tool.py +180 -23
setup_env.bat
DELETED
|
@@ -1,121 +0,0 @@
|
|
| 1 |
-
@echo off
|
| 2 |
-
setlocal enabledelayedexpansion
|
| 3 |
-
|
| 4 |
-
REM --- Configuration ---
|
| 5 |
-
set "ENV_FILE=.env"
|
| 6 |
-
set "DEFAULT_PROXY_KEY=VerysecretKey"
|
| 7 |
-
|
| 8 |
-
REM --- Provider Name to Variable Name Mapping ---
|
| 9 |
-
set "provider_count=0"
|
| 10 |
-
set "provider_list[1]=Gemini" & set "provider_vars[1]=GEMINI" & set /a provider_count+=1
|
| 11 |
-
set "provider_list[2]=OpenRouter" & set "provider_vars[2]=OPENROUTER" & set /a provider_count+=1
|
| 12 |
-
set "provider_list[3]=Chutes" & set "provider_vars[3]=CHUTES" & set /a provider_count+=1
|
| 13 |
-
set "provider_list[4]=Nvidia" & set "provider_vars[4]=NVIDIA_NIM" & set /a provider_count+=1
|
| 14 |
-
set "provider_list[5]=OpenAI" & set "provider_vars[5]=OPENAI" & set /a provider_count+=1
|
| 15 |
-
set "provider_list[6]=Anthropic" & set "provider_vars[6]=ANTHROPIC" & set /a provider_count+=1
|
| 16 |
-
set "provider_list[7]=Mistral" & set "provider_vars[7]=MISTRAL" & set /a provider_count+=1
|
| 17 |
-
set "provider_list[8]=Groq" & set "provider_vars[8]=GROQ" & set /a provider_count+=1
|
| 18 |
-
set "provider_list[9]=Cohere" & set "provider_vars[9]=COHERE" & set /a provider_count+=1
|
| 19 |
-
set "provider_list[10]=Bedrock" & set "provider_vars[10]=BEDROCK" & set /a provider_count+=1
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
:main
|
| 23 |
-
cls
|
| 24 |
-
echo =================================================================
|
| 25 |
-
echo Welcome to the API Key Setup for Your Proxy Server
|
| 26 |
-
echo =================================================================
|
| 27 |
-
echo.
|
| 28 |
-
echo This script will help you set up your .env file.
|
| 29 |
-
echo.
|
| 30 |
-
|
| 31 |
-
REM --- Ensure .env file exists and has PROXY_API_KEY ---
|
| 32 |
-
if not exist "%ENV_FILE%" (
|
| 33 |
-
echo Creating a new %ENV_FILE% file for you...
|
| 34 |
-
echo PROXY_API_KEY="%DEFAULT_PROXY_KEY%" > "%ENV_FILE%"
|
| 35 |
-
echo.
|
| 36 |
-
) else (
|
| 37 |
-
findstr /C:"PROXY_API_KEY=" "%ENV_FILE%" >nul
|
| 38 |
-
if errorlevel 1 (
|
| 39 |
-
echo Adding the default proxy key to your .env file...
|
| 40 |
-
echo.>> "%ENV_FILE%"
|
| 41 |
-
echo PROXY_API_KEY="%DEFAULT_PROXY_KEY%" >> "%ENV_FILE%"
|
| 42 |
-
echo.
|
| 43 |
-
)
|
| 44 |
-
)
|
| 45 |
-
|
| 46 |
-
:get_provider
|
| 47 |
-
echo -----------------------------------------------------------------
|
| 48 |
-
echo Please choose a provider to add an API key for:
|
| 49 |
-
echo -----------------------------------------------------------------
|
| 50 |
-
echo.
|
| 51 |
-
for /L %%i in (1,1,%provider_count%) do (
|
| 52 |
-
echo %%i. !provider_list[%%i]!
|
| 53 |
-
)
|
| 54 |
-
echo.
|
| 55 |
-
set /p "choice=Type the number of the provider and press Enter: "
|
| 56 |
-
|
| 57 |
-
REM --- Validate Provider Choice ---
|
| 58 |
-
set "VAR_NAME="
|
| 59 |
-
set "provider_choice="
|
| 60 |
-
if %choice% GTR 0 if %choice% LEQ %provider_count% (
|
| 61 |
-
set "VAR_NAME=!provider_vars[%choice%]!"
|
| 62 |
-
set "provider_choice=!provider_list[%choice%]!"
|
| 63 |
-
)
|
| 64 |
-
|
| 65 |
-
if not defined VAR_NAME (
|
| 66 |
-
cls
|
| 67 |
-
echo =================================================================
|
| 68 |
-
echo INVALID SELECTION! Please try again.
|
| 69 |
-
echo =================================================================
|
| 70 |
-
echo.
|
| 71 |
-
pause
|
| 72 |
-
goto :get_provider
|
| 73 |
-
)
|
| 74 |
-
|
| 75 |
-
set "API_VAR_BASE=%VAR_NAME%_API_KEY"
|
| 76 |
-
|
| 77 |
-
:get_key
|
| 78 |
-
echo.
|
| 79 |
-
echo -----------------------------------------------------------------
|
| 80 |
-
set /p "api_key=Enter the API key for %provider_choice%: "
|
| 81 |
-
if not defined api_key (
|
| 82 |
-
echo You must enter an API key.
|
| 83 |
-
goto :get_key
|
| 84 |
-
)
|
| 85 |
-
echo -----------------------------------------------------------------
|
| 86 |
-
echo.
|
| 87 |
-
|
| 88 |
-
REM --- Find the next available key number ---
|
| 89 |
-
set /a key_index=1
|
| 90 |
-
:find_next_key
|
| 91 |
-
findstr /R /C:"^%API_VAR_BASE%_%key_index% *=" "%ENV_FILE%" >nul
|
| 92 |
-
if %errorlevel% equ 0 (
|
| 93 |
-
set /a key_index+=1
|
| 94 |
-
goto :find_next_key
|
| 95 |
-
)
|
| 96 |
-
|
| 97 |
-
REM --- Append the new key to the .env file ---
|
| 98 |
-
echo Adding your key to %ENV_FILE%...
|
| 99 |
-
echo %API_VAR_BASE%_%key_index%="%api_key%" >> "%ENV_FILE%"
|
| 100 |
-
echo.
|
| 101 |
-
echo Successfully added %provider_choice% API key as %API_VAR_BASE%_%key_index%!
|
| 102 |
-
echo.
|
| 103 |
-
|
| 104 |
-
:ask_another
|
| 105 |
-
set /p "another=Do you want to add another key? (yes/no): "
|
| 106 |
-
if /i "%another%"=="yes" (
|
| 107 |
-
goto :main
|
| 108 |
-
)
|
| 109 |
-
if /i "%another%"=="y" (
|
| 110 |
-
goto :main
|
| 111 |
-
)
|
| 112 |
-
|
| 113 |
-
cls
|
| 114 |
-
echo =================================================================
|
| 115 |
-
echo Setup Complete! Your .env file is ready.
|
| 116 |
-
echo =================================================================
|
| 117 |
-
echo.
|
| 118 |
-
echo You can now run the proxy server.
|
| 119 |
-
echo.
|
| 120 |
-
pause
|
| 121 |
-
exit /b
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/rotator_library/credential_tool.py
CHANGED
|
@@ -4,8 +4,10 @@ import asyncio
|
|
| 4 |
import json
|
| 5 |
import re
|
| 6 |
from pathlib import Path
|
|
|
|
| 7 |
|
| 8 |
from .provider_factory import get_provider_auth_class, get_available_providers
|
|
|
|
| 9 |
from rich.console import Console
|
| 10 |
from rich.panel import Panel
|
| 11 |
from rich.prompt import Prompt
|
|
@@ -13,9 +15,138 @@ from rich.text import Text
|
|
| 13 |
|
| 14 |
OAUTH_BASE_DIR = Path.cwd() / "oauth_creds"
|
| 15 |
OAUTH_BASE_DIR.mkdir(exist_ok=True)
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
console = Console()
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
async def setup_new_credential(provider_name: str):
|
| 20 |
"""
|
| 21 |
Interactively sets up a new OAuth credential for a given provider.
|
|
@@ -66,39 +197,65 @@ async def setup_new_credential(provider_name: str):
|
|
| 66 |
|
| 67 |
async def main():
|
| 68 |
"""
|
| 69 |
-
An interactive CLI tool to add new
|
| 70 |
"""
|
|
|
|
| 71 |
console.print(Panel("[bold cyan]Interactive Credential Setup[/bold cyan]", title="--- API Key Proxy ---", expand=False))
|
| 72 |
|
| 73 |
while True:
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
console.print(Panel(provider_text, title="Available Providers", style="bold blue"))
|
| 81 |
-
|
| 82 |
-
choice = Prompt.ask(
|
| 83 |
-
Text.from_markup("[bold]Please select a provider or type [red]'q'[/red] to quit[/bold]"),
|
| 84 |
-
choices=[str(i + 1) for i in range(len(available_providers))] + ["q"],
|
| 85 |
show_choices=False
|
| 86 |
)
|
| 87 |
|
| 88 |
-
if
|
| 89 |
break
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
console.print("\n" + "="*50 + "\n")
|
| 103 |
|
| 104 |
def run_credential_tool():
|
|
|
|
| 4 |
import json
|
| 5 |
import re
|
| 6 |
from pathlib import Path
|
| 7 |
+
from dotenv import set_key, get_key
|
| 8 |
|
| 9 |
from .provider_factory import get_provider_auth_class, get_available_providers
|
| 10 |
+
from .providers import PROVIDER_PLUGINS
|
| 11 |
from rich.console import Console
|
| 12 |
from rich.panel import Panel
|
| 13 |
from rich.prompt import Prompt
|
|
|
|
| 15 |
|
| 16 |
OAUTH_BASE_DIR = Path.cwd() / "oauth_creds"
|
| 17 |
OAUTH_BASE_DIR.mkdir(exist_ok=True)
|
| 18 |
+
# Use a direct path to the .env file in the project root
|
| 19 |
+
ENV_FILE = Path.cwd() / ".env"
|
| 20 |
+
|
| 21 |
|
| 22 |
console = Console()
|
| 23 |
|
| 24 |
+
def ensure_env_defaults():
|
| 25 |
+
"""
|
| 26 |
+
Ensures the .env file exists and contains essential default values like PROXY_API_KEY.
|
| 27 |
+
"""
|
| 28 |
+
if not ENV_FILE.is_file():
|
| 29 |
+
ENV_FILE.touch()
|
| 30 |
+
console.print(f"Creating a new [bold yellow]{ENV_FILE.name}[/bold yellow] file...")
|
| 31 |
+
|
| 32 |
+
# Check for PROXY_API_KEY, similar to setup_env.bat
|
| 33 |
+
if get_key(str(ENV_FILE), "PROXY_API_KEY") is None:
|
| 34 |
+
default_key = "VerysecretKey"
|
| 35 |
+
console.print(f"Adding default [bold cyan]PROXY_API_KEY[/bold cyan] to [bold yellow]{ENV_FILE.name}[/bold yellow]...")
|
| 36 |
+
set_key(str(ENV_FILE), "PROXY_API_KEY", default_key)
|
| 37 |
+
|
| 38 |
+
async def setup_api_key():
|
| 39 |
+
"""
|
| 40 |
+
Interactively sets up a new API key for a provider.
|
| 41 |
+
"""
|
| 42 |
+
console.print(Panel("[bold cyan]API Key Setup[/bold cyan]", expand=False))
|
| 43 |
+
|
| 44 |
+
# Verified list of LiteLLM providers with their friendly names and API key variables
|
| 45 |
+
LITELLM_PROVIDERS = {
|
| 46 |
+
"OpenAI": "OPENAI_API_KEY", "Anthropic": "ANTHROPIC_API_KEY",
|
| 47 |
+
"Google AI Studio (Gemini)": "GEMINI_API_KEY", "Azure OpenAI": "AZURE_API_KEY",
|
| 48 |
+
"Vertex AI": "GOOGLE_API_KEY", "AWS Bedrock": "AWS_ACCESS_KEY_ID",
|
| 49 |
+
"Cohere": "COHERE_API_KEY", "Mistral AI": "MISTRAL_API_KEY",
|
| 50 |
+
"Codestral (Mistral)": "CODESTRAL_API_KEY", "Groq": "GROQ_API_KEY",
|
| 51 |
+
"Perplexity": "PERPLEXITYAI_API_KEY", "xAI": "XAI_API_KEY",
|
| 52 |
+
"Together AI": "TOGETHERAI_API_KEY", "Fireworks AI": "FIREWORKS_AI_API_KEY",
|
| 53 |
+
"Replicate": "REPLICATE_API_KEY", "Hugging Face": "HUGGINGFACE_API_KEY",
|
| 54 |
+
"Anyscale": "ANYSCALE_API_KEY", "NVIDIA NIM": "NVIDIA_NIM_API_KEY",
|
| 55 |
+
"Deepseek": "DEEPSEEK_API_KEY", "AI21": "AI21_API_KEY",
|
| 56 |
+
"Cerebras": "CEREBRAS_API_KEY", "Moonshot": "MOONSHOT_API_KEY",
|
| 57 |
+
"Ollama": "OLLAMA_API_KEY", "Xinference": "XINFERENCE_API_KEY",
|
| 58 |
+
"Infinity": "INFINITY_API_KEY", "OpenRouter": "OPENROUTER_API_KEY",
|
| 59 |
+
"Deepinfra": "DEEPINFRA_API_KEY", "Cloudflare": "CLOUDFLARE_API_KEY",
|
| 60 |
+
"Baseten": "BASETEN_API_KEY", "Modal": "MODAL_API_KEY",
|
| 61 |
+
"Databricks": "DATABRICKS_API_KEY", "AWS SageMaker": "AWS_ACCESS_KEY_ID",
|
| 62 |
+
"IBM watsonx.ai": "WATSONX_APIKEY", "Predibase": "PREDIBASE_API_KEY",
|
| 63 |
+
"Clarifai": "CLARIFAI_API_KEY", "NLP Cloud": "NLP_CLOUD_API_KEY",
|
| 64 |
+
"Voyage AI": "VOYAGE_API_KEY", "Jina AI": "JINA_API_KEY",
|
| 65 |
+
"Hyperbolic": "HYPERBOLIC_API_KEY", "Morph": "MORPH_API_KEY",
|
| 66 |
+
"Lambda AI": "LAMBDA_API_KEY", "Novita AI": "NOVITA_API_KEY",
|
| 67 |
+
"Aleph Alpha": "ALEPH_ALPHA_API_KEY", "SambaNova": "SAMBANOVA_API_KEY",
|
| 68 |
+
"FriendliAI": "FRIENDLI_TOKEN", "Galadriel": "GALADRIEL_API_KEY",
|
| 69 |
+
"CompactifAI": "COMPACTIFAI_API_KEY", "Lemonade": "LEMONADE_API_KEY",
|
| 70 |
+
"GradientAI": "GRADIENTAI_API_KEY", "Featherless AI": "FEATHERLESS_AI_API_KEY",
|
| 71 |
+
"Nebius AI Studio": "NEBIUS_API_KEY", "Dashscope (Qwen)": "DASHSCOPE_API_KEY",
|
| 72 |
+
"Bytez": "BYTEZ_API_KEY", "Oracle OCI": "OCI_API_KEY",
|
| 73 |
+
"DataRobot": "DATAROBOT_API_KEY", "OVHCloud": "OVHCLOUD_API_KEY",
|
| 74 |
+
"Volcengine": "VOLCENGINE_API_KEY", "Snowflake": "SNOWFLAKE_API_KEY",
|
| 75 |
+
"Nscale": "NSCALE_API_KEY", "Recraft": "RECRAFT_API_KEY",
|
| 76 |
+
"v0": "V0_API_KEY", "Vercel": "VERCEL_AI_GATEWAY_API_KEY",
|
| 77 |
+
"Topaz": "TOPAZ_API_KEY", "ElevenLabs": "ELEVENLABS_API_KEY",
|
| 78 |
+
"Deepgram": "DEEPGRAM_API_KEY", "Custom API": "CUSTOM_API_KEY",
|
| 79 |
+
"GitHub Models": "GITHUB_TOKEN", "GitHub Copilot": "GITHUB_COPILOT_API_KEY",
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
# Discover custom providers and add them to the list
|
| 83 |
+
oauth_providers = {'gemini_cli', 'qwen_code'}
|
| 84 |
+
discovered_providers = {
|
| 85 |
+
p.replace('_', ' ').title(): p.upper() + "_API_KEY"
|
| 86 |
+
for p in PROVIDER_PLUGINS.keys()
|
| 87 |
+
if p not in oauth_providers and p.replace('_', ' ').title() not in LITELLM_PROVIDERS
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
combined_providers = {**LITELLM_PROVIDERS, **discovered_providers}
|
| 91 |
+
provider_display_list = sorted(combined_providers.keys())
|
| 92 |
+
|
| 93 |
+
provider_text = Text()
|
| 94 |
+
for i, provider_name in enumerate(provider_display_list):
|
| 95 |
+
provider_text.append(f" {i + 1}. {provider_name}\n")
|
| 96 |
+
|
| 97 |
+
console.print(Panel(provider_text, title="Available Providers for API Key", style="bold blue"))
|
| 98 |
+
|
| 99 |
+
choice = Prompt.ask(
|
| 100 |
+
Text.from_markup("[bold]Please select a provider or type [red]'b'[/red] to go back[/bold]"),
|
| 101 |
+
choices=[str(i + 1) for i in range(len(provider_display_list))] + ["b"],
|
| 102 |
+
show_choices=False
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
if choice.lower() == 'b':
|
| 106 |
+
return
|
| 107 |
+
|
| 108 |
+
try:
|
| 109 |
+
choice_index = int(choice) - 1
|
| 110 |
+
if 0 <= choice_index < len(provider_display_list):
|
| 111 |
+
display_name = provider_display_list[choice_index]
|
| 112 |
+
api_var_base = combined_providers[display_name]
|
| 113 |
+
|
| 114 |
+
api_key = Prompt.ask(f"Enter the API key for {display_name}")
|
| 115 |
+
|
| 116 |
+
# Special handling for AWS
|
| 117 |
+
if display_name in ["AWS Bedrock", "AWS SageMaker"]:
|
| 118 |
+
console.print(Panel(
|
| 119 |
+
Text.from_markup(
|
| 120 |
+
"This provider requires both an Access Key ID and a Secret Access Key.\n"
|
| 121 |
+
f"The key you entered will be saved as [bold yellow]{api_var_base}_1[/bold yellow].\n"
|
| 122 |
+
"Please manually add the [bold cyan]AWS_SECRET_ACCESS_KEY_1[/bold cyan] to your .env file."
|
| 123 |
+
),
|
| 124 |
+
title="[bold yellow]Additional Step Required[/bold yellow]",
|
| 125 |
+
border_style="yellow"
|
| 126 |
+
))
|
| 127 |
+
|
| 128 |
+
key_index = 1
|
| 129 |
+
while True:
|
| 130 |
+
key_name = f"{api_var_base}_{key_index}"
|
| 131 |
+
if ENV_FILE.is_file():
|
| 132 |
+
with open(ENV_FILE, "r") as f:
|
| 133 |
+
if not any(line.startswith(f"{key_name}=") for line in f):
|
| 134 |
+
break
|
| 135 |
+
else:
|
| 136 |
+
break
|
| 137 |
+
key_index += 1
|
| 138 |
+
|
| 139 |
+
key_name = f"{api_var_base}_{key_index}"
|
| 140 |
+
set_key(str(ENV_FILE), key_name, api_key)
|
| 141 |
+
|
| 142 |
+
success_text = Text.from_markup(f"Successfully added {display_name} API key as [bold yellow]'{key_name}'[/bold yellow].")
|
| 143 |
+
console.print(Panel(success_text, style="bold green", title="Success"))
|
| 144 |
+
|
| 145 |
+
else:
|
| 146 |
+
console.print("[bold red]Invalid choice. Please try again.[/bold red]")
|
| 147 |
+
except ValueError:
|
| 148 |
+
console.print("[bold red]Invalid input. Please enter a number or 'b'.[/bold red]")
|
| 149 |
+
|
| 150 |
async def setup_new_credential(provider_name: str):
|
| 151 |
"""
|
| 152 |
Interactively sets up a new OAuth credential for a given provider.
|
|
|
|
| 197 |
|
| 198 |
async def main():
|
| 199 |
"""
|
| 200 |
+
An interactive CLI tool to add new credentials.
|
| 201 |
"""
|
| 202 |
+
ensure_env_defaults()
|
| 203 |
console.print(Panel("[bold cyan]Interactive Credential Setup[/bold cyan]", title="--- API Key Proxy ---", expand=False))
|
| 204 |
|
| 205 |
while True:
|
| 206 |
+
console.print(Panel(
|
| 207 |
+
Text.from_markup("1. Add OAuth Credential\n2. Add API Key"),
|
| 208 |
+
title="Choose credential type",
|
| 209 |
+
style="bold blue"
|
| 210 |
+
))
|
| 211 |
|
| 212 |
+
setup_type = Prompt.ask(
|
| 213 |
+
Text.from_markup("[bold]Please select an option or type [red]'q'[/red] to quit[/bold]"),
|
| 214 |
+
choices=["1", "2", "q"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
show_choices=False
|
| 216 |
)
|
| 217 |
|
| 218 |
+
if setup_type.lower() == 'q':
|
| 219 |
break
|
| 220 |
|
| 221 |
+
if setup_type == "1":
|
| 222 |
+
available_providers = get_available_providers()
|
| 223 |
+
oauth_friendly_names = {
|
| 224 |
+
"gemini_cli": "Gemini CLI (OAuth)",
|
| 225 |
+
"qwen_code": "Qwen Code (OAuth)"
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
provider_text = Text()
|
| 229 |
+
for i, provider in enumerate(available_providers):
|
| 230 |
+
display_name = oauth_friendly_names.get(provider, provider.replace('_', ' ').title())
|
| 231 |
+
provider_text.append(f" {i + 1}. {display_name}\n")
|
| 232 |
+
|
| 233 |
+
console.print(Panel(provider_text, title="Available Providers for OAuth", style="bold blue"))
|
| 234 |
+
|
| 235 |
+
choice = Prompt.ask(
|
| 236 |
+
Text.from_markup("[bold]Please select a provider or type [red]'b'[/red] to go back[/bold]"),
|
| 237 |
+
choices=[str(i + 1) for i in range(len(available_providers))] + ["b"],
|
| 238 |
+
show_choices=False
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
if choice.lower() == 'b':
|
| 242 |
+
continue
|
| 243 |
+
|
| 244 |
+
try:
|
| 245 |
+
choice_index = int(choice) - 1
|
| 246 |
+
if 0 <= choice_index < len(available_providers):
|
| 247 |
+
provider_name = available_providers[choice_index]
|
| 248 |
+
display_name = oauth_friendly_names.get(provider_name, provider_name.replace('_', ' ').title())
|
| 249 |
+
console.print(f"\nStarting OAuth setup for [bold cyan]{display_name}[/bold cyan]...")
|
| 250 |
+
await setup_new_credential(provider_name)
|
| 251 |
+
else:
|
| 252 |
+
console.print("[bold red]Invalid choice. Please try again.[/bold red]")
|
| 253 |
+
except ValueError:
|
| 254 |
+
console.print("[bold red]Invalid input. Please enter a number or 'b'.[/bold red]")
|
| 255 |
+
|
| 256 |
+
elif setup_type == "2":
|
| 257 |
+
await setup_api_key()
|
| 258 |
+
|
| 259 |
console.print("\n" + "="*50 + "\n")
|
| 260 |
|
| 261 |
def run_credential_tool():
|