"use client"; import { useMemo, useState } from "react"; import useSWR from "swr"; import { Loader2, Plus, Sparkles } from "lucide-react"; import { toast } from "sonner"; import { fetcher } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { agentService } from "@/services/agents"; import type { AgentPreset } from "@/types/agent"; import { AgentPresetCard } from "@/components/agents/AgentPresetCard"; import { AgentPresetDialog } from "@/components/agents/AgentPresetDialog"; interface AgentPresetPanelProps { selectedPresetId?: string | null; onSelectPreset: (presetId: string | null) => void; } export function AgentPresetPanel({ selectedPresetId, onSelectPreset, }: AgentPresetPanelProps) { const [keyword, setKeyword] = useState(""); const [categoryFilters, setCategoryFilters] = useState({ productCategory: "", audienceTag: "", usageScenario: "", brand: "", }); const [showCreateDialog, setShowCreateDialog] = useState(false); const [editingPreset, setEditingPreset] = useState(null); const { data: siteSettingsData } = useSWR<{ agentCategoryTreeConfig?: { productCategories?: string[]; audienceTags?: string[]; usageScenarios?: string[]; brands?: string[]; }; agentSecondaryTypeConfig?: { image?: string[]; video?: string[]; text?: string[]; }; }>("/api/site-settings", fetcher); const { data, isLoading, mutate } = useSWR( ["agent-presets"], async () => { const result = await agentService.getPresets({ scope: "all", sort: "latest", }); if (!result.success || !result.data) { throw new Error(result.error || "获取智能体失败"); } return result.data; } ); const categoryTreeConfig = useMemo( () => ({ productCategories: siteSettingsData?.agentCategoryTreeConfig?.productCategories || [], audienceTags: siteSettingsData?.agentCategoryTreeConfig?.audienceTags || [], usageScenarios: siteSettingsData?.agentCategoryTreeConfig?.usageScenarios || [], brands: siteSettingsData?.agentCategoryTreeConfig?.brands || [], }), [siteSettingsData?.agentCategoryTreeConfig] ); const secondaryTypeConfig = useMemo( () => ({ image: siteSettingsData?.agentSecondaryTypeConfig?.image || [], video: siteSettingsData?.agentSecondaryTypeConfig?.video || [], text: siteSettingsData?.agentSecondaryTypeConfig?.text || [], }), [siteSettingsData?.agentSecondaryTypeConfig] ); const filteredPublicPresets = useMemo(() => { return (data?.public || []).filter((preset) => { const path = preset.categoryPath || {}; const matchedKeyword = !keyword.trim() || preset.name.toLowerCase().includes(keyword.trim().toLowerCase()) || [ path.productCategory, path.audienceTag, path.usageScenario, path.brand, ] .filter(Boolean) .join(" ") .toLowerCase() .includes(keyword.trim().toLowerCase()); const matchedCategory = (!categoryFilters.productCategory || path.productCategory === categoryFilters.productCategory) && (!categoryFilters.audienceTag || path.audienceTag === categoryFilters.audienceTag) && (!categoryFilters.usageScenario || path.usageScenario === categoryFilters.usageScenario) && (!categoryFilters.brand || path.brand === categoryFilters.brand); return matchedCategory && matchedKeyword; }); }, [categoryFilters, data?.public, keyword]); const filteredPrivatePresets = useMemo(() => { return (data?.private || []).filter((preset) => { const matchedKeyword = !keyword.trim() || preset.name.toLowerCase().includes(keyword.trim().toLowerCase()) || String(preset.category?.name || "") .toLowerCase() .includes(keyword.trim().toLowerCase()); return matchedKeyword; }); }, [data?.private, keyword]); const handleForkPreset = async (preset: AgentPreset) => { const result = await agentService.forkPreset(preset.id, `${preset.name}(副本)`); if (!result.success || !result.data) { toast.error(result.error || "复制智能体失败"); return; } toast.success("已另存为我的智能体"); await mutate(); onSelectPreset(result.data.id); }; const handleDeletePreset = async (preset: AgentPreset) => { if (!window.confirm(`确定删除智能体「${preset.name}」吗?`)) { return; } const result = await agentService.deletePreset(preset.id); if (!result.success) { toast.error(result.error || "删除智能体失败"); return; } toast.success("智能体已删除"); if (selectedPresetId === preset.id) { onSelectPreset(null); } await mutate(); }; return ( <>
智能体
选择智能体后,右侧对话框会按其要求显示上传槽位
setKeyword(event.target.value)} />
公共智能体
{isLoading ? (
) : filteredPublicPresets.length > 0 ? (
{filteredPublicPresets.map((preset) => ( ))}
) : (
暂无公共智能体
)}
我的智能体
{isLoading ? null : filteredPrivatePresets.length > 0 ? (
{filteredPrivatePresets.map((preset) => ( ))}
) : (
还没有私有智能体,先新建一个吧
)}
{ if (!nextOpen) { setShowCreateDialog(false); setEditingPreset(null); return; } setShowCreateDialog(true); }} categoryTreeConfig={categoryTreeConfig} secondaryTypeConfig={secondaryTypeConfig} initialPreset={editingPreset} onSaved={async (preset) => { await mutate(); onSelectPreset(preset.id); setEditingPreset(null); setShowCreateDialog(false); }} /> ); }