{"repo": "ahmadali0071/va-cd", "files": {"admin-panel/src/pages/ApiSettings.jsx": {"aa55182da05c2078587a920716769716698f1f94": {"t": 1785746562.0892217, "n": 27250, "h": "1309be46eec6ffed", "c": "import { useState, useEffect, useRef } from \"react\";\n\nconst API = \"/api/admin\";\n\nfunction call(path, options = {}) {\n const token = localStorage.getItem(\"admin_token\");\n return fetch(`${API}${path}`, {\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\", ...options.headers },\n ...options,\n }).then(r => r.ok ? r.json() : r.json().then(e => { throw new Error(e.error || \"Failed\"); }));\n}\n\nconst LLM_PROVIDERS = [\n { key: \"deepseek\", label: \"DeepSeek\", baseURL: \"https://api.deepseek.com/v1\" },\n { key: \"openai\", label: \"OpenAI\", baseURL: \"https://api.openai.com/v1\" },\n { key: \"groq\", label: \"Groq\", baseURL: \"https://api.groq.com/openai/v1\" },\n { key: \"anthropic\", label: \"Anthropic Claude\", baseURL: \"https://api.anthropic.com/v1\" },\n { key: \"gemini\", label: \"Google Gemini\", baseURL: \"https://generativelanguage.googleapis.com/v1beta\" },\n { key: \"mistral\", label: \"Mistral AI\", baseURL: \"https://api.mistral.ai/v1\" },\n { key: \"perplexity\", label: \"Perplexity\", baseURL: \"https://api.perplexity.ai\" },\n { key: \"xai\", label: \"xAI Grok\", baseURL: \"https://api.x.ai/v1\" },\n { key: \"together\", label: \"Together AI\", baseURL: \"https://api.together.xyz/v1\" },\n { key: \"fireworks\", label: \"Fireworks AI\", baseURL: \"https://api.fireworks.ai/inference/v1\" },\n { key: \"replicate\", label: \"Replicate\", baseURL: \"https://api.replicate.com/v1\" },\n { key: \"cohere\", label: \"Cohere\", baseURL: \"https://api.cohere.ai/v1\" },\n { key: \"custom\", label: \"Custom Provider\", baseURL: \"\" },\n];\n\nconst ALL_MODELS = [\n { name: \"deepseek-reasoner\", provider: \"deepseek\", label: \"DeepSeek R1\" },\n { name: \"deepseek-chat\", provider: \"deepseek\", label: \"DeepSeek V3\" },\n { name: \"gpt-4o\", provider: \"openai\", label: \"GPT-4o\" },\n { name: \"gpt-4o-mini\", provider: \"openai\", label: \"GPT-4o Mini\" },\n { name: \"gpt-4-turbo\", provider: \"openai\", label: \"GPT-4 Turbo\" },\n { name: \"gpt-4\", provider: \"openai\", label: \"GPT-4\" },\n { name: \"gpt-3.5-turbo\", provider: \"openai\", label: \"GPT-3.5 Turbo\" },\n { name: \"o1\", provider: \"openai\", label: \"OpenAI o1\" },\n { name: \"o1-mini\", provider: \"openai\", label: \"OpenAI o1 Mini\" },\n { name: \"o3-mini\", provider: \"openai\", label: \"OpenAI o3 Mini\" },\n { name: \"llama-3.3-70b-versatile\", provider: \"groq\", label: \"Llama 3.3 70B\" },\n { name: \"llama-3.1-8b-instant\", provider: \"groq\", label: \"Llama 3.1 8B\" },\n { name: \"mixtral-8x7b-32768\", provider: \"groq\", label: \"Mixtral 8x7B\" },\n { name: \"gemma2-9b-it\", provider: \"groq\", label: \"Gemma 2 9B\" },\n { name: \"claude-3-opus-20240229\", provider: \"anthropic\", label: \"Claude 3 Opus\" },\n { name: \"claude-3-sonnet-20240229\", provider: \"anthropic\", label: \"Claude 3 Sonnet\" },\n { name: \"claude-3-haiku-20240307\", provider: \"anthropic\", label: \"Claude 3 Haiku\" },\n { name: \"claude-3-5-sonnet-20240620\", provider: \"anthropic\", label: \"Claude 3.5 Sonnet\" },\n { name: \"claude-3-5-haiku-20241022\", provider: \"anthropic\", label: \"Claude 3.5 Haiku\" },\n { name: \"gemini-2.0-flash\", provider: \"gemini\", label: \"Gemini 2.0 Flash\" },\n { name: \"gemini-1.5-pro\", provider: \"gemini\", label: \"Gemini 1.5 Pro\" },\n { name: \"gemini-1.5-flash\", provider: \"gemini\", label: \"Gemini 1.5 Flash\" },\n { name: \"gemini-1.0-pro\", provider: \"gemini\", label: \"Gemini 1.0 Pro\" },\n { name: \"mistral-large-latest\", provider: \"mistral\", label: \"Mistral Large\" },\n { name: \"mistral-small-latest\", provider: \"mistral\", label: \"Mistral Small\" },\n { name: \"mistral-medium\", provider: \"mistral\", label: \"Mistral Medium\" },\n { name: \"codestral-latest\", provider: \"mistral\", label: \"Codestral\" },\n { name: \"sonar-reasoning\", provider: \"perplexity\", label: \"Sonar Reasoning\" },\n { name: \"sonar-pro\", provider: \"perplexity\", label: \"Sonar Pro\" },\n { name: \"sonar\", provider: \"perplexity\", label: \"Sonar\" },\n { name: \"grok-2-1212\", provider: \"xai\", label: \"Grok 2\" },\n { name: \"grok-2-vision-1212\", provider: \"xai\", label: \"Grok 2 Vision\" },\n { name: \"grok-beta\", provider: \"xai\", label: \"Grok Beta\" },\n { name: \"meta-llama/Llama-3.3-70B-Instruct-Turbo\", provider: \"together\", label: \"Llama 3.3 70B Turbo\" },\n { name: \"meta-llama/Llama-3.1-8B-Instruct-Turbo\", provider: \"together\", label: \"Llama 3.1 8B Turbo\" },\n { name: \"Qwen/Qwen2.5-72B-Instruct-Turbo\", provider: \"together\", label: \"Qwen 2.5 72B\" },\n { name: \"mistralai/Mixtral-8x22B-Instruct-v0.1\", provider: \"together\", label: \"Mixtral 8x22B\" },\n { name: \"deepseek-ai/DeepSeek-R1\", provider: \"together\", label: \"DeepSeek R1 (Together)\" },\n { name: \"accounts/fireworks/models/llama-v3p3-70b-instruct\", provider: \"fireworks\", label: \"Llama 3.3 70B (FW)\" },\n { name: \"accounts/fireworks/models/mixtral-8x22b-instruct\", provider: \"fireworks\", label: \"Mixtral 8x22B (FW)\" },\n { name: \"meta/meta-llama-3-70b-instruct\", provider: \"replicate\", label: \"Llama 3 70B (Rep)\" },\n { name: \"command-r-plus\", provider: \"cohere\", label: \"Command R+\" },\n { name: \"command-r\", provider: \"cohere\", label: \"Command R\" },\n { name: \"command\", provider: \"cohere\", label: \"Command\" },\n];\n\nconst TTS_PROVIDERS = [\n { key: \"polly\", label: \"Amazon Polly (Free)\" },\n { key: \"elevenlabs\", label: \"ElevenLabs (11 Labs)\" },\n { key: \"openai_tts\", label: \"OpenAI TTS\" },\n { key: \"deepgram_tts\", label: \"Deepgram Aura\" },\n { key: \"playht\", label: \"Play.ht\" },\n { key: \"google_tts\", label: \"Google Cloud TTS\" },\n { key: \"azure_tts\", label: \"Azure TTS\" },\n { key: \"custom\", label: \"Custom TTS\" },\n];\n\nconst ALL_VOICES = [\n { name: \"Polly.Joanna-Neural\", provider: \"polly\", label: \"Joanna (Female, Warm)\" },\n { name: \"Polly.Matthew-Neural\", provider: \"polly\", label: \"Matthew (Male, Friendly)\" },\n { name: \"Polly.Ruth-Neural\", provider: \"polly\", label: \"Ruth (Female, Professional)\" },\n { name: \"Polly.Amy-Neural\", provider: \"polly\", label: \"Amy (Female, British)\" },\n { name: \"Polly.Stephen-Neural\", provider: \"polly\", label: \"Stephen (Male, Deep)\" },\n { name: \"Polly.Salli-Neural\", provider: \"polly\", label: \"Salli (Female, US)\" },\n { name: \"Polly.Kimberly-Neural\", provider: \"polly\", label: \"Kimberly (Female, US)\" },\n { name: \"Polly.Kendra-Neural\", provider: \"polly\", label: \"Kendra (Female, US)\" },\n { name: \"Rachel\", provider: \"elevenlabs\", label: \"Rachel (Female, Warm)\" },\n { name: \"Adam\", provider: \"elevenlabs\", label: \"Adam (Male, Deep)\" },\n { name: \"Antoni\", provider: \"elevenlabs\", label: \"Antoni (Male, British)\" },\n { name: \"Bella\", provider: \"elevenlabs\", label: \"Bella (Female, Young)\" },\n { name: \"Domi\", provider: \"elevenlabs\", label: \"Domi (Female, Energetic)\" },\n { name: \"Elli\", provider: \"elevenlabs\", label: \"Elli (Female, Soft)\" },\n { name: \"Josh\", provider: \"elevenlabs\", label: \"Josh (Male, Casual)\" },\n { name: \"Arnold\", provider: \"elevenlabs\", label: \"Arnold (Male, Authoritative)\" },\n { name: \"alloy\", provider: \"openai_tts\", label: \"Alloy (Neutral)\" },\n { name: \"echo\", provider: \"openai_tts\", label: \"Echo (Male)\" },\n { name: \"fable\", provider: \"openai_tts\", label: \"Fable (British)\" },\n { name: \"onyx\", provider: \"openai_tts\", label: \"Onyx (Deep Male)\" },\n { name: \"nova\", provider: \"openai_tts\", label: \"Nova (Female)\" },\n { name: \"shimmer\", provider: \"openai_tts\", label: \"Shimmer (Soft Female)\" },\n { name: \"aura-asteria-en\", provider: \"deepgram_tts\", label: \"Asteria (Female, US)\" },\n { name: \"aura-luna-en\", provider: \"deepgram_tts\", label: \"Luna (Female, US)\" },\n { name: \"aura-stella-en\", provider: \"deepgram_tts\", label: \"Stella (Female, US)\" },\n { name: \"aura-athena-en\", provider: \"deepgram_tts\", label: \"Athena (Female, UK)\" },\n { name: \"aura-hera-en\", provider: \"deepgram_tts\", label: \"Hera (Female, US)\" },\n { name: \"aura-orion-en\", provider: \"deepgram_tts\", label: \"Orion (Male, US)\" },\n { name: \"aura-arcas-en\", provider: \"deepgram_tts\", label: \"Arcas (Male, US)\" },\n { name: \"en-US-Standard-C\", provider: \"google_tts\", label: \"Standard C (Female, US)\" },\n { name: \"en-US-Standard-D\", provider: \"google_tts\", label: \"Standard D (Male, US)\" },\n { name: \"en-US-Wavenet-C\", provider: \"google_tts\", label: \"Wavenet C (Female, US)\" },\n { name: \"en-US-Wavenet-D\", provider: \"google_tts\", label: \"Wavenet D (Male, US)\" },\n { name: \"en-US-Studio-O\", provider: \"google_tts\", label: \"Studio O (Female, US)\" },\n { name: \"en-GB-Wavenet-B\", provider: \"google_tts\", label: \"Wavenet B (Male, UK)\" },\n { name: \"en-US-AriaNeural\", provider: \"azure_tts\", label: \"Aria (Female, US)\" },\n { name: \"en-US-GuyNeural\", provider: \"azure_tts\", label: \"Guy (Male, US)\" },\n { name: \"en-US-JennyNeural\", provider: \"azure_tts\", label: \"Jenny (Female, US)\" },\n { name: \"en-GB-SoniaNeural\", provider: \"azure_tts\", label: \"Sonia (Female, UK)\" },\n { name: \"en-GB-RyanNeural\", provider: \"azure_tts\", label: \"Ryan (Male, UK)\" },\n];\n\nconst API_KEY_DEFS = [\n { key: \"deepseek_api_key\", label: \"DeepSeek\", category: \"llm\", provider: \"deepseek\" },\n { key: \"openai_api_key\", label: \"OpenAI\", category: \"llm\", provider: \"openai\" },\n { key: \"groq_api_key\", label: \"Groq\", category: \"llm\", provider: \"groq\" },\n { key: \"anthropic_api_key\", label: \"Claude\", category: \"llm\", provider: \"anthropic\" },\n { key: \"gemini_api_key\", label: \"Gemini\", category: \"llm\", provider: \"gemini\" },\n { key: \"mistral_api_key\", label: \"Mistral\", category: \"llm\", provider: \"mistral\" },\n { key: \"perplexity_api_key\", label: \"Perplexity\", category: \"llm\", provider: \"perplexity\" },\n { key: \"xai_api_key\", label: \"xAI Grok\", category: \"llm\", provider: \"xai\" },\n { key: \"together_api_key\", label: \"Together AI\", category: \"llm\", provider: \"together\" },\n { key: \"fireworks_api_key\", label: \"Fireworks AI\", category: \"llm\", provider: \"fireworks\" },\n { key: \"replicate_api_key\", label: \"Replicate\", category: \"llm\", provider: \"replicate\" },\n { key: \"cohere_api_key\", label: \"Cohere\", category: \"llm\", provider: \"cohere\" },\n { key: \"elevenlabs_api_key\", label: \"ElevenLabs\", category: \"voice\", provider: \"elevenlabs\" },\n { key: \"deepgram_api_key\", label: \"Deepgram\", category: \"stt\", provider: \"deepgram\" },\n { key: \"playht_api_key\", label: \"Play.ht\", category: \"voice\", provider: \"playht\" },\n { key: \"google_tts_api_key\", label: \"Google Cloud TTS\", category: \"voice\", provider: \"google_tts\" },\n { key: \"azure_tts_api_key\", label: \"Azure TTS\", category: \"voice\", provider: \"azure_tts\" },\n];\n\nfunction SearchInput({ value, onChange, items, placeholder, providerFilter }) {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(value || \"\");\n const ref = useRef(null);\n\n useEffect(() => { setSearch(value || \"\"); }, [value]);\n\n const filtered = (search?.length > 0)\n ? items.filter(m => {\n if (providerFilter && m.provider !== providerFilter) return false;\n return m.name.toLowerCase().includes(search.toLowerCase()) || m.label.toLowerCase().includes(search.toLowerCase());\n }).slice(0, 8)\n : (providerFilter \n ? items.filter(m => m.provider === providerFilter).slice(0, 6) \n : items.slice(0, 8));\n\n const exactMatch = filtered.find(m => m.name === search);\n\n return (\n
\n setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onChange={e => { setSearch(e.target.value); setOpen(true); onChange?.(e.target.value); }}\n onKeyDown={e => { if (e.key === \"Enter\") { onChange?.(search); setOpen(false); } }}\n />\n {open && (\n
\n {search?.length > 0 && filtered.length > 0 && filtered.map(m => (\n
{ setSearch(m.name); onChange?.(m.name); setOpen(false); }}\n style={{ padding: \"8px 14px\", cursor: \"pointer\", fontSize: 13, background: m.name === search ? \"#f0f0ff\" : \"transparent\", borderBottom: \"1px solid #f3f4f6\" }}>\n
{m.label}
\n
{m.name}
\n
\n ))}\n {!search?.length && filtered.map(m => (\n
{ setSearch(m.name); onChange?.(m.name); setOpen(false); }}\n style={{ padding: \"8px 14px\", cursor: \"pointer\", fontSize: 13, borderBottom: \"1px solid #f3f4f6\" }}>\n
{m.label}
\n
{m.name}
\n
\n ))}\n {!search?.length && (\n
Type to search or pick from above
\n )}\n {!exactMatch && search?.length > 1 && (\n
{ setSearch(search); onChange?.(search); setOpen(false); }}\n style={{ padding: \"10px 14px\", cursor: \"pointer\", fontSize: 12, background: \"#f0fdf4\", color: \"#16a34a\", borderTop: \"1px solid #bbf7d0\" }}>\n + Use \"{search}\" as custom\n
\n )}\n {search?.length > 0 && filtered.length === 0 && (\n
No matches found
\n )}\n
\n )}\n
\n );\n}\n\nexport default function ApiSettings() {\n const [settings, setSettings] = useState({});\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [msg, setMsg] = useState(\"\");\n const [err, setErr] = useState(\"\");\n const [editingKey, setEditingKey] = useState(null);\n const [editValue, setEditValue] = useState(\"\");\n\n useEffect(() => { load(); }, []);\n\n async function load() {\n setLoading(true);\n try { setSettings(await call(\"/apisettings\")); } catch (e) { setErr(e.message); }\n finally { setLoading(false); }\n }\n\n async function save(silent) {\n setSaving(true);\n if (!silent) { setMsg(\"\"); setErr(\"\"); }\n try {\n await call(\"/apisettings\", { method: \"PUT\", body: JSON.stringify(settings) });\n if (!silent) setMsg(\"Saved!\");\n } catch (e) { if (!silent) setErr(e.message); }\n finally { setSaving(false); }\n }\n\n const setVal = (k, v) => {\n const next = { ...settings, [k]: v };\n if (k === \"llm_provider\" && v !== \"custom\") {\n const defaultModel = ALL_MODELS.find(m => m.provider === v);\n if (defaultModel) next.llm_model = defaultModel.name;\n }\n if (k === \"tts_provider\" && v !== \"custom\") {\n const defaultVoice = ALL_VOICES.find(m => m.provider === v);\n if (defaultVoice) next.tts_voice = defaultVoice.name;\n }\n setSettings(next);\n };\n\n async function deleteKey(key) {\n if (!confirm(`Remove ${key}?`)) return;\n setSettings(s => ({ ...s, [key]: \"\" }));\n await save(true);\n load();\n }\n\n async function editKey(key) {\n setEditingKey(key);\n setEditValue(settings[key] || \"\");\n }\n\n async function saveKey() {\n setSettings(s => ({ ...s, [editingKey]: editValue }));\n setEditingKey(null);\n await save(true);\n load();\n }\n\n const activeKeys = API_KEY_DEFS.filter(d => (settings[d.key] || \"\").length > 8);\n const prov = settings.llm_provider || \"deepseek\";\n\n const s = {\n page: { padding: 32, maxWidth: 900 },\n title: { fontSize: 26, fontWeight: 800, color: \"#111827\", marginBottom: 4 },\n sub: { fontSize: 13, color: \"#6b7280\", marginBottom: 28 },\n card: { background: \"#fff\", borderRadius: 14, padding: 24, marginBottom: 18, boxShadow: \"0 1px 3px rgba(0,0,0,0.05)\", border: \"1px solid #f3f4f6\" },\n cardTitle: { fontSize: 15, fontWeight: 700, color: \"#111827\", marginBottom: 18, display: \"flex\", alignItems: \"center\", gap: 8 },\n sectionIcon: (bg) => ({ width: 32, height: 32, borderRadius: 10, background: bg, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", fontSize: 16 }),\n grid: { display: \"grid\", gridTemplateColumns: \"1fr 1fr\", gap: 16 },\n label: { fontSize: 12, fontWeight: 600, color: \"#4b5563\", marginBottom: 5, display: \"block\" },\n input: { width: \"100%\", padding: \"9px 14px\", borderRadius: 10, border: \"1.5px solid #e5e7eb\", fontSize: 13, outline: \"none\", background: \"#fafafa\" },\n select: { width: \"100%\", padding: \"9px 14px\", borderRadius: 10, border: \"1.5px solid #e5e7eb\", fontSize: 13, background: \"#fff\", cursor: \"pointer\" },\n btn: { padding: \"10px 22px\", borderRadius: 10, border: \"none\", cursor: \"pointer\", fontWeight: 600, fontSize: 13, transition: \"all 0.15s\" },\n btnPrimary: { background: \"#6366f1\", color: \"#fff\" },\n btnGreen: { background: \"#f0fdf4\", color: \"#16a34a\", border: \"1px solid #bbf7d0\" },\n btnRed: { background: \"#fef2f2\", color: \"#ef4444\", border: \"1px solid #fecaca\" },\n keyRow: { display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", padding: \"12px 16px\", borderRadius: 10, background: \"#f9fafb\", marginBottom: 8, border: \"1px solid #f3f4f6\" },\n badge: (active) => ({ display: \"inline-block\", padding: \"3px 10px\", borderRadius: 20, fontSize: 11, fontWeight: 700, background: active ? \"#d1fae5\" : \"#fee2e2\", color: active ? \"#065f46\" : \"#991b1b\" }),\n };\n\n if (loading) return
Loading...
;\n\n return (\n
\n

API Settings

\n

Configure LLM, voice, and API keys for the AI agent

\n\n {(msg || err) && (\n
\n {msg || err}\n
\n )}\n\n {/* LLM Provider */}\n
\n
\n 🧠 LLM Provider\n
\n
\n
\n \n p.key === prov)?.label || prov}\n onChange={v => {\n const match = LLM_PROVIDERS.find(p => p.label.toLowerCase() === v.toLowerCase() || p.key === v.toLowerCase());\n if (match) setVal(\"llm_provider\", match.key);\n else setVal(\"llm_provider\", v);\n }}\n items={LLM_PROVIDERS.map(p => ({ name: p.key, provider: p.key, label: p.label }))}\n providerFilter={null}\n placeholder=\"Search LLM provider...\"\n />\n
\n
\n \n setVal(\"llm_model\", v)}\n items={ALL_MODELS}\n providerFilter={prov !== \"custom\" ? prov : null}\n placeholder=\"Type to search models...\"\n />\n
\n {prov !== \"custom\" && (\n
\n \n
\n setVal(`${prov}_api_key`, e.target.value)} placeholder=\"sk-...\" />\n \n
\n
\n )}\n {prov === \"custom\" && (\n
\n
\n \n setVal(\"custom_llm_api_key\", e.target.value)} placeholder=\"sk-...\" />\n
\n
\n \n setVal(\"custom_llm_base_url\", e.target.value)} placeholder=\"https://api.together.xyz/v1\" />\n
\n
\n )}\n
\n
\n\n {/* TTS / Voice */}\n
\n
\n 🔊 Voice (TTS)\n
\n
\n
\n \n p.key === (settings.tts_provider || \"polly\"))?.label || settings.tts_provider || \"Amazon Polly (Free)\"}\n onChange={v => {\n const match = TTS_PROVIDERS.find(p => p.label.toLowerCase() === v.toLowerCase() || p.key === v.toLowerCase());\n if (match) setVal(\"tts_provider\", match.key);\n else setVal(\"tts_provider\", v);\n }}\n items={TTS_PROVIDERS.map(p => ({ name: p.key, provider: p.key, label: p.label }))}\n providerFilter={null}\n placeholder=\"Search TTS provider...\"\n />\n
\n
\n \n setVal(\"tts_voice\", v)}\n items={ALL_VOICES}\n providerFilter={(settings.tts_provider || \"polly\") !== \"custom\" ? (settings.tts_provider || \"polly\") : null}\n placeholder=\"Type to search voices...\"\n />\n
\n {(settings.tts_provider || \"polly\") !== \"polly\" && (\n
\n \n
\n {(() => {\n const ttsProv = settings.tts_provider || \"polly\";\n const keyMap = { elevenlabs: \"elevenlabs_api_key\", openai_tts: \"openai_api_key\", deepgram_tts: \"deepgram_api_key\", playht: \"playht_api_key\", google_tts: \"google_tts_api_key\", azure_tts: \"azure_tts_api_key\", custom: \"custom_tts_api_key\" };\n const key = keyMap[ttsProv] || \"custom_tts_api_key\";\n return (\n <>\n setVal(key, e.target.value)} placeholder=\"API key...\" />\n \n \n );\n })()}\n
\n
\n )}\n
\n
\n\n {/* Active API Keys */}\n
\n
\n 🔑 Active API Keys\n ({activeKeys.length} configured)\n
\n {activeKeys.length === 0 ? (\n
No API keys configured.
\n ) : (\n activeKeys.map(def => {\n const val = settings[def.key] || \"\";\n const last4 = `...${val.slice(-4)}`;\n return (\n
\n
\n {def.label}\n Active\n {last4}\n
\n
\n \n \n
\n
\n );\n })\n )}\n
\n\n {/* Add Keys */}\n
\n
\n âž• Add API Key\n
\n
\n {API_KEY_DEFS.filter(d => !activeKeys.find(a => a.key === d.key)).map(def => (\n
\n setVal(def.key, e.target.value)} />\n \n
\n ))}\n
\n
\n\n \n\n {editingKey && (\n
{ if (e.target === e.currentTarget) setEditingKey(null); }}>\n
\n

Edit {API_KEY_DEFS.find(d => d.key === editingKey)?.label || editingKey}

\n setEditValue(e.target.value)} placeholder=\"Enter new API key\" />\n
\n \n \n
\n
\n
\n )}\n
\n );\n}\n"}}, "saas-backend/.env.example": {"aa55182da05c2078587a920716769716698f1f94": {"t": 1785747116.8103685, "n": 1055, "h": "85d6c8f1ded4d246", "c": "# Server\nPORT=3000\nMONGODB_URI=mongodb+srv://:@cluster.mongodb.net/saas-appointment-agent\nJWT_SECRET=your_super_secret_jwt_key_change_this\nSTREAM_HOST=va.crossdigi.com\nPUBLIC_HOST=va.crossdigi.com\n\n# Admin Seed\nADMIN_SEED_EMAIL=admin@yourapp.com\nADMIN_SEED_PASSWORD=admin123change\n\n# Twilio\nTWILIO_ACCOUNT_SID=your_twilio_sid\nTWILIO_AUTH_TOKEN=your_twilio_auth_token\nTWILIO_PHONE_NUMBER=+13362217315\n\n# LLM API Keys (configure via Admin Panel)\nDEEPSEEK_API_KEY=sk-your-deepseek-key\nDEEPSEEK_MODEL=deepseek-reasoner\nOPENAI_API_KEY=sk-your-openai-key\nGROQ_API_KEY=gsk-your-groq-key\nANTHROPIC_API_KEY=sk-ant-your-anthropic-key\nGEMINI_API_KEY=AIza-your-gemini-key\nMISTRAL_API_KEY=your-mistral-key\nPERPLEXITY_API_KEY=pplx-your-perplexity-key\nXAI_API_KEY=xai-your-xai-key\n\n# STT / Voice\nDEEPGRAM_API_KEY=your-deepgram-key\nGOOGLE_STT_KEY=AIza-your-google-stt-key\nELEVENLABS_API_KEY=your-elevenlabs-key\n\n# Email\nRESEND_API_KEY=re_your_resend_key\nOWNER_EMAIL=admin@yourapp.com\nEMAIL_USER=your-email@gmail.com\nEMAIL_PASS=your-gmail-app-password\n"}}}}