/** * Admin Settings Page - Enhanced with API Configuration */ import React, { useState, useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { adminAPI } from '../api/client' import { useAuth } from '../context/AuthContext' import { Settings, Save, Loader, Key, Link as LinkIcon, Eye, EyeOff, ArrowLeft } from 'lucide-react' import toast from 'react-hot-toast' export const AdminSettings = () => { const { user } = useAuth() const navigate = useNavigate() const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [showApiKeys, setShowApiKeys] = useState({ openai: false, anthropic: false, qwen: false, gemini: false }) const [config, setConfig] = useState({ allow_registration: true, max_upload_size_mb: 10, max_daily_uploads: 20, ai_provider: 'gemini', // OpenAI openai_api_key: '', openai_base_url: 'https://api.openai.com/v1', openai_model: 'gpt-4o-mini', // Anthropic anthropic_api_key: '', anthropic_model: 'claude-3-haiku-20240307', // Qwen qwen_api_key: '', qwen_base_url: 'https://dashscope.aliyuncs.com/compatible-mode/v1', qwen_model: 'qwen-plus', // Gemini gemini_api_key: '', gemini_base_url: '', gemini_model: 'gemini-2.0-flash-exp' }) useEffect(() => { loadConfig() }, []) const loadConfig = async () => { try { const response = await adminAPI.getConfig() setConfig(response.data) } catch (error) { console.error('Failed to load config:', error) toast.error('加载配置失败') } finally { setLoading(false) } } const handleSave = async () => { setSaving(true) try { await adminAPI.updateConfig(config) toast.success('配置保存成功!') } catch (error) { console.error('Failed to save config:', error) toast.error('保存配置失败') } finally { setSaving(false) } } const handleChange = (key, value) => { setConfig({ ...config, [key]: value }) } const toggleApiKeyVisibility = (provider) => { setShowApiKeys({ ...showApiKeys, [provider]: !showApiKeys[provider] }) } // Get complete API endpoint URL const getCompleteEndpoint = (provider) => { const endpoints = { openai: '/chat/completions', anthropic: '/messages', qwen: '/chat/completions' } let baseUrl = '' if (provider === 'openai') { baseUrl = config.openai_base_url || 'https://api.openai.com/v1' } else if (provider === 'anthropic') { baseUrl = 'https://api.anthropic.com/v1' } else if (provider === 'qwen') { baseUrl = config.qwen_base_url || 'https://dashscope.aliyuncs.com/compatible-mode/v1' } // Remove trailing slash baseUrl = baseUrl.replace(/\/$/, '') return `${baseUrl}${endpoints[provider]}` } if (loading) { return (
) } return (
{/* Header */}

系统设置

管理员:{user?.username}

{/* Content */}
{/* Basic Settings */}

基础设置

{/* Allow Registration */}

允许用户注册

关闭后新用户无法注册

{/* Max Upload Size */}
handleChange('max_upload_size_mb', parseInt(e.target.value))} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" />

建议:5-20 MB

{/* Max Daily Uploads */}
handleChange('max_daily_uploads', parseInt(e.target.value))} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent" />

建议:10-50 次

{/* AI Provider */}

选择后在下方配置对应的 API 密钥。Gemini 支持原生 PDF 解析

{/* OpenAI Configuration */}

OpenAI 配置

{config.ai_provider === 'openai' && ( 当前使用 )}
{/* Text-only warning */}

⚠️ OpenAI 仅支持文本解析,不支持 PDF 原生理解。PDF 文件将通过文本提取处理,可能丢失格式和图片信息。

{/* API Key */}
handleChange('openai_api_key', e.target.value)} placeholder="sk-proj-..." className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

从 https://platform.openai.com/api-keys 获取

{/* Base URL */}
handleChange('openai_base_url', e.target.value)} placeholder="https://api.openai.com/v1" className="w-full pl-10 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

完整 endpoint: {getCompleteEndpoint('openai')}

{/* Model */}
handleChange('openai_model', e.target.value)} placeholder="gpt-4o-mini" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

可输入自定义模型名称,或从建议中选择

{/* Anthropic Configuration */}

Anthropic 配置

{config.ai_provider === 'anthropic' && ( 当前使用 )}
{/* Text-only warning */}

⚠️ Anthropic 仅支持文本解析,不支持 PDF 原生理解。PDF 文件将通过文本提取处理,可能丢失格式和图片信息。

{/* API Key */}
handleChange('anthropic_api_key', e.target.value)} placeholder="sk-ant-..." className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

从 https://console.anthropic.com/settings/keys 获取

{/* Base URL (fixed for Anthropic) */}

完整 endpoint: {getCompleteEndpoint('anthropic')}

{/* Model */}
handleChange('anthropic_model', e.target.value)} placeholder="claude-3-haiku-20240307" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

可输入自定义模型名称,或从建议中选择

{/* Qwen Configuration */}

通义千问 配置

{config.ai_provider === 'qwen' && ( 当前使用 )}
{/* Text-only warning */}

⚠️ 通义千问 仅支持文本解析,不支持 PDF 原生理解。PDF 文件将通过文本提取处理,可能丢失格式和图片信息。

{/* API Key */}
handleChange('qwen_api_key', e.target.value)} placeholder="sk-..." className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

从 https://dashscope.console.aliyun.com/apiKey 获取

{/* Base URL */}
handleChange('qwen_base_url', e.target.value)} placeholder="https://dashscope.aliyuncs.com/compatible-mode/v1" className="w-full pl-10 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

完整 endpoint: {getCompleteEndpoint('qwen')}

{/* Model */}
handleChange('qwen_model', e.target.value)} placeholder="qwen-plus" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

可输入自定义模型名称,或从建议中选择

{/* Gemini Configuration */}

Google Gemini 配置

{config.ai_provider === 'gemini' && ( 当前使用 )}
{/* PDF support highlight */}

✅ Gemini 支持原生 PDF 理解,可直接处理 PDF 文件(最多 1000 页),完整保留图片、表格、公式等内容。

{/* API Key */}
handleChange('gemini_api_key', e.target.value)} placeholder="AIza..." className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

从 https://aistudio.google.com/apikey 获取

{/* Base URL (optional) */}
handleChange('gemini_base_url', e.target.value)} placeholder="https://generativelanguage.googleapis.com(留空使用默认)" className="w-full pl-10 px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

可配置自定义代理或中转服务(支持 Key 轮训等)。留空则使用 Google 官方 API

{/* Model */}
handleChange('gemini_model', e.target.value)} placeholder="gemini-2.0-flash-exp" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent font-mono text-sm" />

可输入自定义模型名称,或从建议中选择

{/* Save Button */}
) } export default AdminSettings