import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Brain, Save, RefreshCw, CheckCircle, AlertCircle, SlidersHorizontal } from 'lucide-react'; import { adminApi } from '@/services/adminApi'; interface AIModelConfig { provider: 'openai' | 'anthropic' | 'local' | 'custom'; model: string; apiKey: string; apiUrl: string; temperature: number; maxTokens: number; enabled: boolean; } interface MomentumConfig { calculationPeriod: number; weightPriceChange: number; weightVolume: number; weightTechnical: number; thresholdStrong: number; thresholdWeak: number; } export default function AIConfig() { const [aiConfig, setAiConfig] = useState({ provider: 'openai', model: 'gpt-4', apiKey: '', apiUrl: 'https://api.openai.com/v1', temperature: 0.7, maxTokens: 2000, enabled: true, }); const [momentumConfig, setMomentumConfig] = useState({ calculationPeriod: 20, weightPriceChange: 0.4, weightVolume: 0.3, weightTechnical: 0.3, thresholdStrong: 80, thresholdWeak: 40, }); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [saveStatus, setSaveStatus] = useState<'idle' | 'success' | 'error'>('idle'); const [testing, setTesting] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); useEffect(() => { fetchConfig(); }, []); const fetchConfig = async () => { setLoading(true); try { const [aiData, momentumData] = await Promise.allSettled([ adminApi.getAIConfig().catch(() => null), adminApi.getMomentumConfig().catch(() => null), ]); if (aiData.status === 'fulfilled' && aiData.value) { setAiConfig(prev => ({ ...prev, ...aiData.value })); } if (momentumData.status === 'fulfilled' && momentumData.value) { setMomentumConfig(momentumData.value); } } catch (error) { console.error('Failed to fetch config:', error); } finally { setLoading(false); } }; const handleSave = async () => { setSaving(true); setSaveStatus('idle'); try { await Promise.all([ adminApi.updateAIConfig({ provider: aiConfig.provider, model: aiConfig.model, apiKey: aiConfig.apiKey || undefined, apiUrl: aiConfig.apiUrl, temperature: aiConfig.temperature, maxTokens: aiConfig.maxTokens, enabled: aiConfig.enabled, }), adminApi.updateMomentumConfig(momentumConfig), ]); setSaveStatus('success'); setTimeout(() => setSaveStatus('idle'), 3000); } catch (error: any) { setSaveStatus('error'); } finally { setSaving(false); } }; const handleTestConnection = async () => { setTesting(true); setTestResult(null); try { const result = await adminApi.testAIConnection(); setTestResult(result); } catch (error: any) { setTestResult({ success: false, message: error.message || '连接测试失败' }); } finally { setTesting(false); } }; const modelOptions = { openai: ['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo'], anthropic: ['claude-3-opus', 'claude-3-sonnet', 'claude-3-haiku'], local: ['llama2-7b', 'llama2-13b', 'chatglm3-6b'], custom: ['custom-model'], }; if (loading) { return (
); } return (
{/* Header */}

AI模型配置

配置AI分析模型和动量计算参数

{/* Test Result */} {testResult && ( {testResult.success ? ( ) : ( )} {testResult.message} )} {/* Save Status */} {saveStatus !== 'idle' && ( {saveStatus === 'success' ? ( <> 配置保存成功! ) : ( <> 保存失败,请重试。 )} )}
{/* AI Provider Config */}

AI 服务提供商

{/* Enable/Disable */}
启用 AI 分析
{/* Provider */}
{/* Model */}
{/* API Key */}
setAiConfig(prev => ({ ...prev, apiKey: e.target.value }))} placeholder="输入 API Key" className="w-full bg-[#0a0a0a] border border-[#2a2a2a] rounded-lg px-4 py-2.5 text-white placeholder-[#666] outline-none focus:border-[#ff6b35]" />
{/* API URL */}
setAiConfig(prev => ({ ...prev, apiUrl: e.target.value }))} placeholder="https://api.example.com/v1" className="w-full bg-[#0a0a0a] border border-[#2a2a2a] rounded-lg px-4 py-2.5 text-white placeholder-[#666] outline-none focus:border-[#ff6b35]" />
{/* Temperature */}
setAiConfig(prev => ({ ...prev, temperature: parseFloat(e.target.value) }))} className="w-full accent-[#ff6b35]" />
精确 平衡 创意
{/* Max Tokens */}
setAiConfig(prev => ({ ...prev, maxTokens: parseInt(e.target.value) }))} min="100" max="8000" className="w-full bg-[#0a0a0a] border border-[#2a2a2a] rounded-lg px-4 py-2.5 text-white outline-none focus:border-[#ff6b35]" />
{/* Momentum Calculation Config */}

动量计算参数

{/* Calculation Period */}
setMomentumConfig(prev => ({ ...prev, calculationPeriod: parseInt(e.target.value) }))} className="w-full accent-[#ff6b35]" />
{/* Weight Settings */}

权重配置

setMomentumConfig(prev => ({ ...prev, weightPriceChange: parseFloat(e.target.value) }))} className="w-full accent-[#ff6b35]" />
setMomentumConfig(prev => ({ ...prev, weightVolume: parseFloat(e.target.value) }))} className="w-full accent-[#ff6b35]" />
setMomentumConfig(prev => ({ ...prev, weightTechnical: parseFloat(e.target.value) }))} className="w-full accent-[#ff6b35]" />
{/* Threshold Settings */}

阈值配置

setMomentumConfig(prev => ({ ...prev, thresholdStrong: parseInt(e.target.value) }))} className="w-full accent-[#ff6b35]" />
setMomentumConfig(prev => ({ ...prev, thresholdWeak: parseInt(e.target.value) }))} className="w-full accent-[#ff6b35]" />
); }