import { useState, useEffect } from 'react' import { useNavigate } from '@tanstack/react-router' import { Sparkles, ArrowRight, CheckCircle2, SkipForward, Bot, User, Smile, Settings, Key, } from 'lucide-react' import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' import { Progress } from '@/components/ui/progress' import { ScrollArea } from '@/components/ui/scroll-area' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog' import { cn } from '@/lib/utils' import { APP_NAME } from '@/lib/version' import { useToast } from '@/hooks/use-toast' import type { SetupStep, BotBasicConfig, PersonalityConfig, EmojiConfig, OtherBasicConfig, SiliconFlowConfig, } from './setup/types' import { BotBasicForm, PersonalityForm, EmojiForm, OtherBasicForm, SiliconFlowForm, } from './setup/StepForms' import { loadBotBasicConfig, loadPersonalityConfig, loadEmojiConfig, loadOtherBasicConfig, loadSiliconFlowConfig, saveBotBasicConfig, savePersonalityConfig, saveEmojiConfig, saveOtherBasicConfig, saveSiliconFlowConfig, completeSetup, } from './setup/api' import { RestartProvider, useRestart } from '@/lib/restart-context' import { RestartOverlay } from '@/components/restart-overlay' // 主导出组件:包装 RestartProvider export function SetupPage() { return ( ) } // 内部实现组件 function SetupPageContent() { const navigate = useNavigate() const { toast } = useToast() const { triggerRestart } = useRestart() const [currentStep, setCurrentStep] = useState(0) const [isCompleting, setIsCompleting] = useState(false) const [isSaving, setIsSaving] = useState(false) const [isLoading, setIsLoading] = useState(true) // 步骤1:Bot基础信息 const [botBasic, setBotBasic] = useState({ qq_account: 0, nickname: '', alias_names: [], }) // 步骤2:人格配置 const [personality, setPersonality] = useState({ personality: '是一个女大学生,现在在读大二,会刷贴吧。', reply_style: '请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。', interest: '对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题', plan_style: '1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用\n2.如果相同的内容已经被执行,请不要重复执行\n3.请控制你的发言频率,不要太过频繁的发言\n4.如果有人对你感到厌烦,请减少回复\n5.如果有人对你进行攻击,或者情绪激动,请你以合适的方法应对', private_plan_style: '1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用\n2.如果相同的内容已经被执行,请不要重复执行\n3.某句话如果已经被回复过,不要重复回复', }) // 步骤3:表情包配置 const [emoji, setEmoji] = useState({ emoji_chance: 0.4, max_reg_num: 40, do_replace: true, check_interval: 10, steal_emoji: true, content_filtration: false, filtration_prompt: '符合公序良俗', }) // 步骤4:其他基础配置 const [otherBasic, setOtherBasic] = useState({ enable_tool: true, all_global: true, }) // 步骤5:硅基流动API配置 const [siliconFlow, setSiliconFlow] = useState({ api_key: '', }) const steps: SetupStep[] = [ { id: 'bot-basic', title: 'Bot基础', description: '配置机器人的基本信息', icon: Bot, }, { id: 'personality', title: '人格配置', description: '定义机器人的性格和说话风格', icon: User, }, { id: 'emoji', title: '表情包', description: '配置表情包相关设置', icon: Smile, }, { id: 'other', title: '其他设置', description: '工具、情绪系统等配置', icon: Settings, }, { id: 'siliconflow', title: 'API配置', description: '配置硅基流动API密钥', icon: Key, }, ] const progress = ((currentStep + 1) / steps.length) * 100 // 加载现有配置 useEffect(() => { const loadConfigs = async () => { try { setIsLoading(true) // 并行加载所有配置 const [bot, personality, emoji, other, silicon] = await Promise.all([ loadBotBasicConfig(), loadPersonalityConfig(), loadEmojiConfig(), loadOtherBasicConfig(), loadSiliconFlowConfig(), ]) setBotBasic(bot) setPersonality(personality) setEmoji(emoji) setOtherBasic(other) setSiliconFlow(silicon) } catch (error) { toast({ title: '加载配置失败', description: error instanceof Error ? error.message : '无法加载现有配置,将使用默认值', variant: 'destructive', }) } finally { setIsLoading(false) } } loadConfigs() }, [toast]) // 保存当前步骤配置 const saveCurrentStep = async () => { setIsSaving(true) try { switch (currentStep) { case 0: // Bot基础 await saveBotBasicConfig(botBasic) break case 1: // 人格配置 await savePersonalityConfig(personality) break case 2: // 表情包 await saveEmojiConfig(emoji) break case 3: // 其他设置 await saveOtherBasicConfig(otherBasic) break case 4: // 硅基流动API await saveSiliconFlowConfig(siliconFlow) break } toast({ title: '保存成功', description: `${steps[currentStep].title}配置已保存`, }) return true } catch (error) { toast({ title: '保存失败', description: error instanceof Error ? error.message : '未知错误', variant: 'destructive', }) return false } finally { setIsSaving(false) } } const handleNext = async () => { // 保存当前步骤 const saved = await saveCurrentStep() if (!saved) return // 进入下一步 if (currentStep < steps.length - 1) { setCurrentStep(currentStep + 1) } } const handlePrevious = () => { if (currentStep > 0) { setCurrentStep(currentStep - 1) } } const handleComplete = async () => { setIsCompleting(true) try { // 1. 保存最后一步的配置(硅基流动API Key) const saved = await saveCurrentStep() if (!saved) { setIsCompleting(false) return } // 2. 标记设置完成 await completeSetup() toast({ title: '配置完成', description: '麦麦正在重启以应用新配置...', }) // 3. 触发麦麦重启(使用新的重启组件) await triggerRestart() } catch (error) { toast({ title: '配置失败', description: error instanceof Error ? error.message : '未知错误', variant: 'destructive', }) } finally { setIsCompleting(false) } } const handleSkip = async () => { try { await completeSetup() navigate({ to: '/' }) } catch (error) { toast({ title: '跳过失败', description: error instanceof Error ? error.message : '未知错误', variant: 'destructive', }) } } // 渲染当前步骤的表单 const renderStepForm = () => { switch (currentStep) { case 0: return case 1: return ( ) case 2: return case 3: return case 4: return default: return null } } return ( {/* 重启遮罩层 */} {/* 背景装饰 */} {/* 加载状态 */} {isLoading ? ( 加载配置中... 正在读取现有配置 ) : ( <> {/* 主要内容 */} {/* 头部 */} 首次配置向导 让我们一起完成 {APP_NAME} 的初始配置 {/* 进度条 */} 步骤 {currentStep + 1} / {steps.length} {Math.round(progress)}% {/* 步骤指示器 */} {steps.map((step, index) => { const Icon = step.icon return ( {/* 连接线 */} {index < steps.length - 1 && ( )} {/* 步骤圆圈 */} {index < currentStep ? ( ) : ( )} {/* 步骤标题 */} {step.title} ) })} {/* 步骤内容卡片 */} {steps[currentStep].title} {steps[currentStep].description} {/* 表单内容 */} {renderStepForm()} {/* 操作按钮 */} 上一步 跳过向导 确认跳过配置向导 您可以随时在系统设置中重新进入配置向导。确定要跳过吗? 取消 确认跳过 {currentStep === steps.length - 1 ? ( {isCompleting || isSaving ? ( <> {isSaving ? '保存中...' : '完成中...'} > ) : ( <> 完成配置 > )} ) : ( {isSaving ? ( <> 保存中... > ) : ( <> 下一步 > )} )} {/* 页脚提示 */} 您可以随时在设置中修改这些配置 > )} ) }
加载配置中...
正在读取现有配置
让我们一起完成 {APP_NAME} 的初始配置
{steps[currentStep].description}
您可以随时在设置中修改这些配置