From e31dc7f8e82e79d15990c88de3d5641c90663449 Mon Sep 17 00:00:00 2001 From: Krishav Raj Singh Date: Wed, 16 Jul 2025 21:34:34 +0530 Subject: [PATCH] Local .Env Manager --- backend/api.py | 4 +- backend/local_env_manager/api.py | 44 ++++++++++++++++++ backend/local_llm/api.py | 29 ------------ backend/utils/local_api_keys.py | 45 ------------------- .../settings/env-manager/page.tsx | 9 ++++ .../(personalAccount)/settings/layout.tsx | 3 +- .../settings/llm-api-keys/page.tsx | 9 ---- .../local-env-manager.tsx} | 19 ++++---- .../sidebar/nav-user-with-teams.tsx | 8 ++-- .../thread/chat-input/model-selector.tsx | 8 ++-- 10 files changed, 75 insertions(+), 103 deletions(-) create mode 100644 backend/local_env_manager/api.py delete mode 100644 backend/local_llm/api.py delete mode 100644 backend/utils/local_api_keys.py create mode 100644 frontend/src/app/(dashboard)/(personalAccount)/settings/env-manager/page.tsx delete mode 100644 frontend/src/app/(dashboard)/(personalAccount)/settings/llm-api-keys/page.tsx rename frontend/src/components/{api-keys/llm-api-keys.tsx => env-manager/local-env-manager.tsx} (88%) diff --git a/backend/api.py b/backend/api.py index 68bf96d8..d85dd01d 100644 --- a/backend/api.py +++ b/backend/api.py @@ -187,8 +187,8 @@ api_router.include_router(workflows_router, prefix="/workflows") from pipedream import api as pipedream_api api_router.include_router(pipedream_api.router) -from local_llm import api as local_llm_api -api_router.include_router(local_llm_api.router) +from local_env_manager import api as local_env_manager_api +api_router.include_router(local_env_manager_api.router) @api_router.get("/health") async def health_check(): diff --git a/backend/local_env_manager/api.py b/backend/local_env_manager/api.py new file mode 100644 index 00000000..8c575699 --- /dev/null +++ b/backend/local_env_manager/api.py @@ -0,0 +1,44 @@ +from fastapi import APIRouter +from utils.config import config, EnvMode +from fastapi import HTTPException +from typing import Dict +from dotenv import load_dotenv, set_key, find_dotenv, dotenv_values +from utils.logger import logger + +router = APIRouter(tags=["local-env-manager"]) + +@router.get("/env-vars") +def get_env_vars() -> Dict[str, str]: + if config.ENV_MODE != EnvMode.LOCAL: + raise HTTPException(status_code=403, detail="Env vars management only available in local mode") + + try: + env_path = find_dotenv() + if not env_path: + logger.error("Could not find .env file") + return {} + + return dotenv_values(env_path) + except Exception as e: + logger.error(f"Failed to get env vars: {e}") + raise HTTPException(status_code=500, detail=f"Failed to get env variables: {e}") + +@router.post("/env-vars") +def save_env_vars(request: Dict[str, str]) -> Dict[str, str]: + if config.ENV_MODE != EnvMode.LOCAL: + raise HTTPException(status_code=403, detail="Env vars management only available in local mode") + + try: + env_path = find_dotenv() + if not env_path: + raise HTTPException(status_code=500, detail="Could not find .env file") + + for key, value in request.items(): + set_key(env_path, key, value) + + load_dotenv(override=True) + logger.info(f"Env variables saved successfully: {request}") + return {"message": "Env variables saved successfully"} + except Exception as e: + logger.error(f"Failed to save env variables: {e}") + raise HTTPException(status_code=500, detail=f"Failed to save env variables: {e}") \ No newline at end of file diff --git a/backend/local_llm/api.py b/backend/local_llm/api.py deleted file mode 100644 index 507adff6..00000000 --- a/backend/local_llm/api.py +++ /dev/null @@ -1,29 +0,0 @@ -from fastapi import APIRouter -from utils.local_api_keys import save_local_api_keys, get_local_api_keys -from utils.config import config, EnvMode -from fastapi import HTTPException -from typing import Dict -from utils.constants import PROVIDERS - -router = APIRouter(tags=["local-llm-keys"]) - -@router.get("/local-llm-keys") -def get_llm_keys() -> Dict[str, str]: - - if config.ENV_MODE != EnvMode.LOCAL: - raise HTTPException(status_code=403, detail="API key management only available in local mode") - - providers = [f"{provider}_API_KEY" for provider in PROVIDERS] - llm_keys = get_local_api_keys(providers) - return llm_keys - -@router.post("/local-llm-keys") -def save_local_llm_keys(request: Dict[str, str]) -> Dict[str, str]: - if config.ENV_MODE != EnvMode.LOCAL: - raise HTTPException(status_code=403, detail="API key management only available in local mode") - - key_saved = save_local_api_keys(request) - if key_saved: - return {"message": "API keys saved successfully"} - else: - raise HTTPException(status_code=500, detail="Failed to save API keys") \ No newline at end of file diff --git a/backend/utils/local_api_keys.py b/backend/utils/local_api_keys.py deleted file mode 100644 index d722393d..00000000 --- a/backend/utils/local_api_keys.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Local API key management for LLMs. - -This module provides functionality to manage API keys in local mode -by reading and writing to the .env file. -""" - -import os -from typing import Dict, Optional, List -from utils.logger import logger -from utils.config import config, EnvMode -from dotenv import load_dotenv, set_key, find_dotenv -from utils.constants import PROVIDERS - -def get_local_api_keys(providers: List[str]) -> Dict[str, str]: - """Get API keys from .env file in local mode.""" - try: - # Load current env vars - load_dotenv(override=True) - - return {provider: os.getenv(provider) or "" for provider in providers} - - except Exception as e: - logger.error(f"Failed to get local API keys: {e}") - return {} - -def save_local_api_keys(api_keys: Dict[str, str]) -> bool: - """Save API keys to .env file in local mode.""" - try: - # Find .env file - env_path = find_dotenv() - if not env_path: - logger.error("Could not find .env file") - return False - - # Update each API key - for key, value in api_keys.items(): - set_key(env_path, key, value) - logger.info(f"Updated {key} in .env file") - - return True - - except Exception as e: - logger.error(f"Failed to save local API keys: {e}") - return False \ No newline at end of file diff --git a/frontend/src/app/(dashboard)/(personalAccount)/settings/env-manager/page.tsx b/frontend/src/app/(dashboard)/(personalAccount)/settings/env-manager/page.tsx new file mode 100644 index 00000000..a07ad48e --- /dev/null +++ b/frontend/src/app/(dashboard)/(personalAccount)/settings/env-manager/page.tsx @@ -0,0 +1,9 @@ +import { isLocalMode } from "@/lib/config"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Shield } from "lucide-react"; +import { LocalEnvManager } from "@/components/env-manager/local-env-manager"; + +export default function LocalEnvManagerPage() { + + return +} \ No newline at end of file diff --git a/frontend/src/app/(dashboard)/(personalAccount)/settings/layout.tsx b/frontend/src/app/(dashboard)/(personalAccount)/settings/layout.tsx index 196f5869..462f193a 100644 --- a/frontend/src/app/(dashboard)/(personalAccount)/settings/layout.tsx +++ b/frontend/src/app/(dashboard)/(personalAccount)/settings/layout.tsx @@ -3,6 +3,7 @@ import { Separator } from '@/components/ui/separator'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; +import { isLocalMode } from '@/lib/config'; export default function PersonalAccountSettingsPage({ children, @@ -15,7 +16,7 @@ export default function PersonalAccountSettingsPage({ // { name: "Teams", href: "/settings/teams" }, { name: 'Billing', href: '/settings/billing' }, { name: 'Usage Logs', href: '/settings/usage-logs' }, - { name: 'LLM API Keys', href: '/settings/llm-api-keys' }, + ...(isLocalMode() ? [{ name: 'Local .Env Manager', href: '/settings/env-manager' }] : []), ]; return ( <> diff --git a/frontend/src/app/(dashboard)/(personalAccount)/settings/llm-api-keys/page.tsx b/frontend/src/app/(dashboard)/(personalAccount)/settings/llm-api-keys/page.tsx deleted file mode 100644 index 93a53b9a..00000000 --- a/frontend/src/app/(dashboard)/(personalAccount)/settings/llm-api-keys/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { isLocalMode } from "@/lib/config"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Shield } from "lucide-react"; -import { LLMApiKeys } from "@/components/api-keys/llm-api-keys"; - -export default function LLMKeysPage() { - - return -} \ No newline at end of file diff --git a/frontend/src/components/api-keys/llm-api-keys.tsx b/frontend/src/components/env-manager/local-env-manager.tsx similarity index 88% rename from frontend/src/components/api-keys/llm-api-keys.tsx rename to frontend/src/components/env-manager/local-env-manager.tsx index 31b6eec2..9a274c32 100644 --- a/frontend/src/components/api-keys/llm-api-keys.tsx +++ b/frontend/src/components/env-manager/local-env-manager.tsx @@ -16,15 +16,16 @@ interface APIKeyForm { [key: string]: string; } -export function LLMApiKeys() { +export function LocalEnvManager() { const queryClient = useQueryClient(); const [visibleKeys, setVisibleKeys] = useState>({}); const {data: apiKeys, isLoading} = useQuery({ queryKey: ['api-keys'], queryFn: async() => { - const response = await backendApi.get('/local-llm-keys'); + const response = await backendApi.get('/env-vars'); return response.data; }, + enabled: isLocalMode() }); const { register, handleSubmit, formState: { errors, isDirty }, reset } = useForm({ @@ -36,7 +37,7 @@ export function LLMApiKeys() { } const updateApiKeys = useMutation({ mutationFn: async (data: APIKeyForm) => { - const response = await backendApi.post('/local-llm-keys', data); + const response = await backendApi.post('/env-vars', data); await queryClient.invalidateQueries({ queryKey: ['api-keys'] }); return response.data; }, @@ -50,7 +51,7 @@ export function LLMApiKeys() { const keysArray = apiKeys ? Object.entries(apiKeys).map(([key, value]) => ({ id: key, - name: key.replace(/_/g, " ").replace("KEY", "Key"), + name: key, value: value })) : []; @@ -70,7 +71,7 @@ export function LLMApiKeys() { if (isLoading) { return - API Keys + Local .Env Manager Loading... ; @@ -78,15 +79,15 @@ export function LLMApiKeys() { return - API Keys + Local .Env Manager {isLocalMode() ? ( <> - Manage your API keys for various Language Model providers. + Manage your local environment variables ) : ( <> - API key management is only available in local mode. + Local .Env Manager is only available in local mode. )} @@ -95,7 +96,7 @@ export function LLMApiKeys() { {isLocalMode() && (
- {keysArray && keysArray?.map((key: any) => ( + {keysArray && keysArray?.map(key => (
diff --git a/frontend/src/components/sidebar/nav-user-with-teams.tsx b/frontend/src/components/sidebar/nav-user-with-teams.tsx index 9b48983b..f02d150a 100644 --- a/frontend/src/components/sidebar/nav-user-with-teams.tsx +++ b/frontend/src/components/sidebar/nav-user-with-teams.tsx @@ -17,7 +17,7 @@ import { AudioWaveform, Sun, Moon, - Key, + KeyRound, } from 'lucide-react'; import { useAccounts } from '@/hooks/use-accounts'; import NewTeamForm from '@/components/basejump/new-team-form'; @@ -289,9 +289,9 @@ export function NavUserWithTeams({ {isLocalMode() && - - - LLM API Keys + + + Local .Env Manager } {/* diff --git a/frontend/src/components/thread/chat-input/model-selector.tsx b/frontend/src/components/thread/chat-input/model-selector.tsx index 67b3181b..730ddcb6 100644 --- a/frontend/src/components/thread/chat-input/model-selector.tsx +++ b/frontend/src/components/thread/chat-input/model-selector.tsx @@ -14,7 +14,7 @@ import { TooltipTrigger, } from '@/components/ui/tooltip'; import { Button } from '@/components/ui/button'; -import { Check, ChevronDown, Search, AlertTriangle, Crown, ArrowUpRight, Brain, Plus, Edit, Trash, Cpu, Key } from 'lucide-react'; +import { Check, ChevronDown, Search, AlertTriangle, Crown, ArrowUpRight, Brain, Plus, Edit, Trash, Cpu, Key, KeyRound } from 'lucide-react'; import { ModelOption, SubscriptionStatus, @@ -680,14 +680,14 @@ export const ModelSelector: React.FC = ({ - + - Manage API Keys + Local .Env Manager