Spaces:
Running
Running
import { useState, useEffect } from "react"; | |
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; | |
import { Button } from "@/components/ui/button"; | |
import { Input } from "@/components/ui/input"; | |
import { Label } from "@/components/ui/label"; | |
import { toast } from "sonner"; | |
// API key configuration | |
interface ApiKeyConfig { | |
name: string; | |
key: string; | |
storageKey: string; | |
label: string; | |
placeholder: string; | |
} | |
// Available API keys configuration | |
const API_KEYS_CONFIG: ApiKeyConfig[] = [ | |
{ | |
name: "OpenAI", | |
key: "openai", | |
storageKey: "OPENAI_API_KEY", | |
label: "OpenAI API Key", | |
placeholder: "sk-..." | |
}, | |
{ | |
name: "Anthropic", | |
key: "anthropic", | |
storageKey: "ANTHROPIC_API_KEY", | |
label: "Anthropic API Key", | |
placeholder: "sk-ant-..." | |
}, | |
{ | |
name: "Groq", | |
key: "groq", | |
storageKey: "GROQ_API_KEY", | |
label: "Groq API Key", | |
placeholder: "gsk_..." | |
}, | |
{ | |
name: "XAI", | |
key: "xai", | |
storageKey: "XAI_API_KEY", | |
label: "XAI API Key", | |
placeholder: "xai-..." | |
} | |
]; | |
interface ApiKeyManagerProps { | |
open: boolean; | |
onOpenChange: (open: boolean) => void; | |
} | |
export function ApiKeyManager({ open, onOpenChange }: ApiKeyManagerProps) { | |
// State to store API keys | |
const [apiKeys, setApiKeys] = useState<Record<string, string>>({}); | |
// Load API keys from localStorage on initial mount | |
useEffect(() => { | |
const storedKeys: Record<string, string> = {}; | |
API_KEYS_CONFIG.forEach(config => { | |
const value = localStorage.getItem(config.storageKey); | |
if (value) { | |
storedKeys[config.key] = value; | |
} | |
}); | |
setApiKeys(storedKeys); | |
}, []); | |
// Update API key in state | |
const handleApiKeyChange = (key: string, value: string) => { | |
setApiKeys(prev => ({ | |
...prev, | |
[key]: value | |
})); | |
}; | |
// Save API keys to localStorage | |
const handleSaveApiKeys = () => { | |
try { | |
API_KEYS_CONFIG.forEach(config => { | |
const value = apiKeys[config.key]; | |
if (value && value.trim()) { | |
localStorage.setItem(config.storageKey, value.trim()); | |
} else { | |
localStorage.removeItem(config.storageKey); | |
} | |
}); | |
toast.success("API keys saved successfully"); | |
onOpenChange(false); | |
} catch (error) { | |
console.error("Error saving API keys:", error); | |
toast.error("Failed to save API keys"); | |
} | |
}; | |
// Clear all API keys | |
const handleClearApiKeys = () => { | |
try { | |
API_KEYS_CONFIG.forEach(config => { | |
localStorage.removeItem(config.storageKey); | |
}); | |
setApiKeys({}); | |
toast.success("All API keys cleared"); | |
} catch (error) { | |
console.error("Error clearing API keys:", error); | |
toast.error("Failed to clear API keys"); | |
} | |
}; | |
return ( | |
<Dialog open={open} onOpenChange={onOpenChange}> | |
<DialogContent className="sm:max-w-[500px]"> | |
<DialogHeader> | |
<DialogTitle>API Key Settings</DialogTitle> | |
<DialogDescription> | |
Enter your own API keys for different AI providers. Keys are stored securely in your browser's local storage. | |
</DialogDescription> | |
</DialogHeader> | |
<div className="grid gap-4 py-4"> | |
{API_KEYS_CONFIG.map(config => ( | |
<div key={config.key} className="grid gap-2"> | |
<Label htmlFor={config.key}>{config.label}</Label> | |
<Input | |
id={config.key} | |
type="password" | |
value={apiKeys[config.key] || ""} | |
onChange={(e) => handleApiKeyChange(config.key, e.target.value)} | |
placeholder={config.placeholder} | |
/> | |
</div> | |
))} | |
</div> | |
<DialogFooter className="flex justify-between sm:justify-between"> | |
<Button | |
variant="destructive" | |
onClick={handleClearApiKeys} | |
> | |
Clear All Keys | |
</Button> | |
<div className="flex gap-2"> | |
<Button | |
variant="outline" | |
onClick={() => onOpenChange(false)} | |
> | |
Cancel | |
</Button> | |
<Button onClick={handleSaveApiKeys}> | |
Save Keys | |
</Button> | |
</div> | |
</DialogFooter> | |
</DialogContent> | |
</Dialog> | |
); | |
} |