Adjust MongoDB mock connector and update database structure. Enhance sidebar, data platform, and AI analysis tools. Clean up unnecessary code and update development docs. #VERCEL_SKIP Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
1157 lines
47 KiB
TypeScript
1157 lines
47 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from "react"
|
||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Input } from "@/components/ui/input"
|
||
import { Label } from "@/components/ui/label"
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||
import { Switch } from "@/components/ui/switch"
|
||
import { Checkbox } from "@/components/ui/checkbox"
|
||
import { Badge } from "@/components/ui/badge"
|
||
import { Separator } from "@/components/ui/separator"
|
||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||
import {
|
||
Brain,
|
||
Lightbulb,
|
||
BarChart,
|
||
PieChart,
|
||
Users,
|
||
Tag,
|
||
Play,
|
||
Settings,
|
||
Search,
|
||
Filter,
|
||
Copy,
|
||
Check,
|
||
Zap,
|
||
Plus,
|
||
Download,
|
||
} from "lucide-react"
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogFooter,
|
||
} from "@/components/ui/dialog"
|
||
import { useToast } from "@/components/ui/use-toast"
|
||
import { Textarea } from "@/components/ui/textarea"
|
||
|
||
interface AIAnalysisTask {
|
||
id: string
|
||
name: string
|
||
type: string
|
||
status: "pending" | "running" | "completed" | "failed"
|
||
progress: number
|
||
createdAt: string
|
||
completedAt: string | null
|
||
dataSource: string
|
||
parameters: Record<string, any>
|
||
result: any | null
|
||
}
|
||
|
||
interface AIModel {
|
||
id: string
|
||
name: string
|
||
provider: string
|
||
type: string
|
||
capabilities: string[]
|
||
apiEndpoint: string
|
||
apiKey: string
|
||
status: "active" | "inactive"
|
||
}
|
||
|
||
export function AIAnalysisTools() {
|
||
const { toast } = useToast()
|
||
const [activeTab, setActiveTab] = useState("analysis-tasks")
|
||
const [isCreatingTask, setIsCreatingTask] = useState(false)
|
||
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null)
|
||
const [isAddingModel, setIsAddingModel] = useState(false)
|
||
const [copiedText, setCopiedText] = useState<string | null>(null)
|
||
|
||
// 模拟AI分析任务
|
||
const [aiTasks, setAiTasks] = useState<AIAnalysisTask[]>([
|
||
{
|
||
id: "task-1",
|
||
name: "用户行为分析",
|
||
type: "behavior-analysis",
|
||
status: "completed",
|
||
progress: 100,
|
||
createdAt: "2023-07-20 10:15",
|
||
completedAt: "2023-07-20 10:25",
|
||
dataSource: "行为分析平台",
|
||
parameters: {
|
||
userSegment: "高价值用户",
|
||
timeRange: "近30天",
|
||
analysisDepth: "深度",
|
||
},
|
||
result: {
|
||
summary: "高价值用户在过去30天内主要活跃在晚间时段,偏好浏览科技和旅游类内容,平均会话时长较长。",
|
||
insights: [
|
||
"用户主要在晚上9点至11点活跃",
|
||
"科技类内容点击率高于平均水平58%",
|
||
"平均会话时长为8.5分钟,高于普通用户3.2分钟",
|
||
"移动端访问占比87%,其中iOS设备占65%",
|
||
],
|
||
recommendations: [
|
||
"在晚间时段推送个性化内容",
|
||
"增加科技和旅游类内容的推荐权重",
|
||
"针对长会话时长优化页面加载速度",
|
||
"优化iOS端用户体验",
|
||
],
|
||
},
|
||
},
|
||
{
|
||
id: "task-2",
|
||
name: "用户分群自动发现",
|
||
type: "segment-discovery",
|
||
status: "completed",
|
||
progress: 100,
|
||
createdAt: "2023-07-19 14:30",
|
||
completedAt: "2023-07-19 15:10",
|
||
dataSource: "用户数据库",
|
||
parameters: {
|
||
clusteringMethod: "K-Means",
|
||
features: ["消费行为", "活跃度", "内容偏好"],
|
||
maxClusters: 8,
|
||
},
|
||
result: {
|
||
summary: "系统自动发现了5个明显的用户分群,其中包括高消费低活跃、高活跃低消费等特征明显的群体。",
|
||
clusters: [
|
||
{
|
||
name: "高消费科技爱好者",
|
||
size: 12500,
|
||
characteristics: ["高消费", "科技内容偏好", "中等活跃度"],
|
||
},
|
||
{
|
||
name: "活跃社交用户",
|
||
size: 28900,
|
||
characteristics: ["高活跃度", "社交内容偏好", "中等消费"],
|
||
},
|
||
{
|
||
name: "奢侈品偶尔购买者",
|
||
size: 8700,
|
||
characteristics: ["低活跃度", "高单次消费", "奢侈品偏好"],
|
||
},
|
||
{
|
||
name: "日常必需品购买者",
|
||
size: 45600,
|
||
characteristics: ["高频次低金额消费", "中等活跃度", "生活类内容偏好"],
|
||
},
|
||
{
|
||
name: "休眠用户",
|
||
size: 15400,
|
||
characteristics: ["极低活跃度", "低消费", "无明显内容偏好"],
|
||
},
|
||
],
|
||
},
|
||
},
|
||
{
|
||
id: "task-3",
|
||
name: "用户流失预测",
|
||
type: "churn-prediction",
|
||
status: "running",
|
||
progress: 65,
|
||
createdAt: "2023-07-21 09:45",
|
||
completedAt: null,
|
||
dataSource: "用户数据库 & 行为分析平台",
|
||
parameters: {
|
||
predictionHorizon: "30天",
|
||
modelType: "随机森林",
|
||
features: ["活跃度", "消费频率", "客服交互", "产品使用情况"],
|
||
},
|
||
result: null,
|
||
},
|
||
{
|
||
id: "task-4",
|
||
name: "营销策略生成",
|
||
type: "strategy-generation",
|
||
status: "pending",
|
||
progress: 0,
|
||
createdAt: "2023-07-21 10:30",
|
||
completedAt: null,
|
||
dataSource: "用户画像 & 行为分析",
|
||
parameters: {
|
||
targetSegment: "流失风险用户",
|
||
campaignGoal: "提高留存率",
|
||
budgetConstraint: "中等",
|
||
channelPreference: ["短信", "应用内推送", "邮件"],
|
||
},
|
||
result: null,
|
||
},
|
||
{
|
||
id: "task-5",
|
||
name: "自动标签生成",
|
||
type: "tag-generation",
|
||
status: "completed",
|
||
progress: 100,
|
||
createdAt: "2023-07-18 11:20",
|
||
completedAt: "2023-07-18 12:05",
|
||
dataSource: "用户数据库 & 行为分析平台",
|
||
parameters: {
|
||
tagCategories: ["兴趣", "消费习惯", "活跃模式"],
|
||
minConfidence: 0.7,
|
||
maxTagsPerUser: 10,
|
||
},
|
||
result: {
|
||
summary: "系统为85%的用户生成了新标签,平均每用户5.3个标签。",
|
||
tagCategories: [
|
||
{
|
||
name: "兴趣标签",
|
||
count: 28,
|
||
coverage: "92%",
|
||
examples: ["科技爱好者", "旅游达人", "美食家", "运动健身"],
|
||
},
|
||
{
|
||
name: "消费习惯",
|
||
count: 15,
|
||
coverage: "88%",
|
||
examples: ["奢侈品偏好", "理性消费", "冲动购物", "价格敏感"],
|
||
},
|
||
{
|
||
name: "活跃模式",
|
||
count: 12,
|
||
coverage: "95%",
|
||
examples: ["工作时间活跃", "夜间活跃", "周末活跃", "低频高质"],
|
||
},
|
||
],
|
||
},
|
||
},
|
||
])
|
||
|
||
// 模拟AI模型
|
||
const [aiModels, setAiModels] = useState<AIModel[]>([
|
||
{
|
||
id: "model-1",
|
||
name: "GPT-4",
|
||
provider: "OpenAI",
|
||
type: "大语言模型",
|
||
capabilities: ["文本生成", "内容分析", "情感分析", "摘要生成"],
|
||
apiEndpoint: "https://api.openai.com/v1/chat/completions",
|
||
apiKey: "sk-***********",
|
||
status: "active",
|
||
},
|
||
{
|
||
id: "model-2",
|
||
name: "Claude 2",
|
||
provider: "Anthropic",
|
||
type: "大语言模型",
|
||
capabilities: ["文本生成", "内容分析", "代码生成", "问答"],
|
||
apiEndpoint: "https://api.anthropic.com/v1/complete",
|
||
apiKey: "sk-ant-***********",
|
||
status: "active",
|
||
},
|
||
{
|
||
id: "model-3",
|
||
name: "MCP SERVER AI",
|
||
provider: "内部服务",
|
||
type: "专用分析模型",
|
||
capabilities: ["用户行为分析", "分群发现", "标签生成", "预测模型"],
|
||
apiEndpoint: "https://mcp.example.com/api/analyze",
|
||
apiKey: "mcp-***********",
|
||
status: "active",
|
||
},
|
||
{
|
||
id: "model-4",
|
||
name: "DALL-E 3",
|
||
provider: "OpenAI",
|
||
type: "图像生成模型",
|
||
capabilities: ["图像生成", "图像编辑", "风格迁移"],
|
||
apiEndpoint: "https://api.openai.com/v1/images/generations",
|
||
apiKey: "sk-***********",
|
||
status: "inactive",
|
||
},
|
||
])
|
||
|
||
// 模拟分析模板
|
||
const analysisTemplates = [
|
||
{
|
||
id: "template-1",
|
||
name: "用户行为分析",
|
||
description: "分析用户的行为模式、偏好和习惯",
|
||
type: "behavior-analysis",
|
||
parameters: {
|
||
userSegment: "所有用户",
|
||
timeRange: "近30天",
|
||
analysisDepth: "标准",
|
||
},
|
||
},
|
||
{
|
||
id: "template-2",
|
||
name: "用户分群发现",
|
||
description: "自动发现数据中的用户分群",
|
||
type: "segment-discovery",
|
||
parameters: {
|
||
clusteringMethod: "K-Means",
|
||
features: ["消费行为", "活跃度", "内容偏好"],
|
||
maxClusters: 8,
|
||
},
|
||
},
|
||
{
|
||
id: "template-3",
|
||
name: "用户流失预测",
|
||
description: "预测未来可能流失的用户",
|
||
type: "churn-prediction",
|
||
parameters: {
|
||
predictionHorizon: "30天",
|
||
modelType: "随机森林",
|
||
features: ["活跃度", "消费频率", "客服交互", "产品使用情况"],
|
||
},
|
||
},
|
||
{
|
||
id: "template-4",
|
||
name: "营销策略生成",
|
||
description: "为特定用户分群生成营销策略",
|
||
type: "strategy-generation",
|
||
parameters: {
|
||
targetSegment: "流失风险用户",
|
||
campaignGoal: "提高留存率",
|
||
budgetConstraint: "中等",
|
||
channelPreference: ["短信", "应用内推送", "邮件"],
|
||
},
|
||
},
|
||
{
|
||
id: "template-5",
|
||
name: "自动标签生成",
|
||
description: "基于用户数据自动生成用户标签",
|
||
type: "tag-generation",
|
||
parameters: {
|
||
tagCategories: ["兴趣", "消费习惯", "活跃模式"],
|
||
minConfidence: 0.7,
|
||
maxTagsPerUser: 10,
|
||
},
|
||
},
|
||
]
|
||
|
||
const getStatusBadge = (status: string) => {
|
||
switch (status) {
|
||
case "pending":
|
||
return <Badge className="bg-gray-100 text-gray-800">等待中</Badge>
|
||
case "running":
|
||
return <Badge className="bg-blue-100 text-blue-800">运行中</Badge>
|
||
case "completed":
|
||
return <Badge className="bg-green-100 text-green-800">已完成</Badge>
|
||
case "failed":
|
||
return <Badge className="bg-red-100 text-red-800">失败</Badge>
|
||
case "active":
|
||
return <Badge className="bg-green-100 text-green-800">已启用</Badge>
|
||
case "inactive":
|
||
return <Badge className="bg-gray-100 text-gray-800">已禁用</Badge>
|
||
default:
|
||
return <Badge>未知</Badge>
|
||
}
|
||
}
|
||
|
||
const getTaskTypeIcon = (type: string) => {
|
||
switch (type) {
|
||
case "behavior-analysis":
|
||
return <Users className="h-5 w-5 text-blue-500" />
|
||
case "segment-discovery":
|
||
return <PieChart className="h-5 w-5 text-purple-500" />
|
||
case "churn-prediction":
|
||
return <BarChart className="h-5 w-5 text-orange-500" />
|
||
case "strategy-generation":
|
||
return <Lightbulb className="h-5 w-5 text-yellow-500" />
|
||
case "tag-generation":
|
||
return <Tag className="h-5 w-5 text-green-500" />
|
||
default:
|
||
return <Brain className="h-5 w-5" />
|
||
}
|
||
}
|
||
|
||
const selectedTask = selectedTaskId ? aiTasks.find((task) => task.id === selectedTaskId) : null
|
||
|
||
const handleCopyText = (text: string) => {
|
||
navigator.clipboard.writeText(text)
|
||
setCopiedText(text)
|
||
toast({
|
||
title: "已复制到剪贴板",
|
||
description: "文本已成功复制到剪贴板",
|
||
})
|
||
setTimeout(() => setCopiedText(null), 2000)
|
||
}
|
||
|
||
const toggleModelStatus = (id: string) => {
|
||
setAiModels(
|
||
aiModels.map((model) => {
|
||
if (model.id === id) {
|
||
return {
|
||
...model,
|
||
status: model.status === "active" ? "inactive" : "active",
|
||
}
|
||
}
|
||
return model
|
||
}),
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
<div className="flex justify-between items-center">
|
||
<h2 className="text-2xl font-bold">AI分析工具</h2>
|
||
<div className="flex items-center gap-2">
|
||
<Button variant="outline">
|
||
<Settings className="mr-2 h-4 w-4" />
|
||
AI设置
|
||
</Button>
|
||
<Button onClick={() => setIsCreatingTask(true)}>
|
||
<Brain className="mr-2 h-4 w-4" />
|
||
创建分析任务
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
|
||
<TabsList>
|
||
<TabsTrigger value="analysis-tasks">分析任务</TabsTrigger>
|
||
<TabsTrigger value="ai-models">AI模型</TabsTrigger>
|
||
<TabsTrigger value="templates">分析模板</TabsTrigger>
|
||
<TabsTrigger value="settings">AI设置</TabsTrigger>
|
||
</TabsList>
|
||
|
||
<TabsContent value="analysis-tasks" className="space-y-4">
|
||
<Card>
|
||
<CardHeader>
|
||
<div className="flex justify-between items-center">
|
||
<CardTitle>AI分析任务</CardTitle>
|
||
<div className="flex items-center gap-2">
|
||
<div className="relative">
|
||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||
<Input type="text" placeholder="搜索任务..." className="pl-8 w-[200px]" />
|
||
</div>
|
||
<Select defaultValue="all">
|
||
<SelectTrigger className="w-[150px]">
|
||
<Filter className="mr-2 h-4 w-4" />
|
||
<SelectValue placeholder="任务状态" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">所有状态</SelectItem>
|
||
<SelectItem value="pending">等待中</SelectItem>
|
||
<SelectItem value="running">运行中</SelectItem>
|
||
<SelectItem value="completed">已完成</SelectItem>
|
||
<SelectItem value="failed">失败</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="rounded-md border">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead className="w-[50px]">类型</TableHead>
|
||
<TableHead>任务名称</TableHead>
|
||
<TableHead>数据源</TableHead>
|
||
<TableHead>创建时间</TableHead>
|
||
<TableHead>状态</TableHead>
|
||
<TableHead>进度</TableHead>
|
||
<TableHead className="text-right">操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{aiTasks.map((task) => (
|
||
<TableRow key={task.id}>
|
||
<TableCell>{getTaskTypeIcon(task.type)}</TableCell>
|
||
<TableCell className="font-medium">{task.name}</TableCell>
|
||
<TableCell>{task.dataSource}</TableCell>
|
||
<TableCell>{task.createdAt}</TableCell>
|
||
<TableCell>{getStatusBadge(task.status)}</TableCell>
|
||
<TableCell>
|
||
<div className="w-full bg-gray-200 rounded-full h-2.5">
|
||
<div
|
||
className={`h-2.5 rounded-full ${
|
||
task.status === "completed"
|
||
? "bg-green-600"
|
||
: task.status === "running"
|
||
? "bg-blue-600"
|
||
: task.status === "failed"
|
||
? "bg-red-600"
|
||
: "bg-gray-400"
|
||
}`}
|
||
style={{ width: `${task.progress}%` }}
|
||
></div>
|
||
</div>
|
||
</TableCell>
|
||
<TableCell className="text-right">
|
||
<Button variant="ghost" size="sm" onClick={() => setSelectedTaskId(task.id)}>
|
||
查看详情
|
||
</Button>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="ai-models" className="space-y-4">
|
||
<Card>
|
||
<CardHeader>
|
||
<div className="flex justify-between items-center">
|
||
<CardTitle>AI模型管理</CardTitle>
|
||
<Button onClick={() => setIsAddingModel(true)}>添加模型</Button>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="rounded-md border">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead>模型名称</TableHead>
|
||
<TableHead>提供商</TableHead>
|
||
<TableHead>类型</TableHead>
|
||
<TableHead>能力</TableHead>
|
||
<TableHead>API端点</TableHead>
|
||
<TableHead>状态</TableHead>
|
||
<TableHead className="text-right">操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{aiModels.map((model) => (
|
||
<TableRow key={model.id}>
|
||
<TableCell className="font-medium">{model.name}</TableCell>
|
||
<TableCell>{model.provider}</TableCell>
|
||
<TableCell>{model.type}</TableCell>
|
||
<TableCell>
|
||
<div className="flex flex-wrap gap-1">
|
||
{model.capabilities.slice(0, 2).map((capability, index) => (
|
||
<Badge key={index} variant="outline">
|
||
{capability}
|
||
</Badge>
|
||
))}
|
||
{model.capabilities.length > 2 && (
|
||
<Badge variant="outline">+{model.capabilities.length - 2}</Badge>
|
||
)}
|
||
</div>
|
||
</TableCell>
|
||
<TableCell className="max-w-[200px] truncate">{model.apiEndpoint}</TableCell>
|
||
<TableCell>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch
|
||
checked={model.status === "active"}
|
||
onCheckedChange={() => toggleModelStatus(model.id)}
|
||
aria-label="Toggle model"
|
||
/>
|
||
<span>{getStatusBadge(model.status)}</span>
|
||
</div>
|
||
</TableCell>
|
||
<TableCell className="text-right">
|
||
<div className="flex justify-end space-x-2">
|
||
<Button variant="ghost" size="sm">
|
||
编辑
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
测试
|
||
</Button>
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>MCP SERVER配置</CardTitle>
|
||
<CardDescription>配置MCP SERVER AI工具的分析参数</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="space-y-4">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="mcp-server-url">服务器地址</Label>
|
||
<Input id="mcp-server-url" defaultValue="https://mcp.example.com/api" />
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="mcp-api-key">API密钥</Label>
|
||
<Input id="mcp-api-key" type="password" defaultValue="••••••••••••••••" />
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="mcp-model">AI模型选择</Label>
|
||
<Select defaultValue="gpt-4">
|
||
<SelectTrigger id="mcp-model">
|
||
<SelectValue placeholder="选择AI模型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="gpt-4">GPT-4</SelectItem>
|
||
<SelectItem value="gpt-3.5-turbo">GPT-3.5 Turbo</SelectItem>
|
||
<SelectItem value="claude-2">Claude 2</SelectItem>
|
||
<SelectItem value="llama-2">Llama 2</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label>分析能力配置</Label>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="behavior-analysis" defaultChecked />
|
||
<Label htmlFor="behavior-analysis">行为分析</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="segment-discovery" defaultChecked />
|
||
<Label htmlFor="segment-discovery">分群发现</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="churn-prediction" defaultChecked />
|
||
<Label htmlFor="churn-prediction">流失预测</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="tag-generation" defaultChecked />
|
||
<Label htmlFor="tag-generation">标签生成</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="strategy-generation" defaultChecked />
|
||
<Label htmlFor="strategy-generation">策略生成</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Switch id="content-generation" defaultChecked />
|
||
<Label htmlFor="content-generation">内容生成</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex justify-end">
|
||
<Button>保存MCP配置</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="templates" className="space-y-4">
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{analysisTemplates.map((template) => (
|
||
<Card key={template.id} className="border shadow-sm">
|
||
<CardHeader>
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-2">
|
||
{getTaskTypeIcon(template.type)}
|
||
<CardTitle className="text-lg">{template.name}</CardTitle>
|
||
</div>
|
||
<Button variant="ghost" size="icon">
|
||
<Settings className="h-4 w-4" />
|
||
</Button>
|
||
</div>
|
||
<CardDescription>{template.description}</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">默认参数</h4>
|
||
<div className="text-sm">
|
||
{Object.entries(template.parameters).map(([key, value]) => (
|
||
<div key={key} className="flex justify-between py-1 border-b border-dashed border-gray-200">
|
||
<span className="text-muted-foreground">{key}:</span>
|
||
<span className="font-medium">
|
||
{Array.isArray(value) ? value.join(", ") : value.toString()}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="mt-4 flex justify-end">
|
||
<Button onClick={() => setIsCreatingTask(true)}>
|
||
<Play className="mr-2 h-4 w-4" />
|
||
使用模板
|
||
</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
))}
|
||
|
||
<Card className="border shadow-sm border-dashed">
|
||
<CardContent className="p-6 flex flex-col items-center justify-center h-full">
|
||
<div className="rounded-full bg-muted p-3 mb-4">
|
||
<Plus className="h-6 w-6 text-muted-foreground" />
|
||
</div>
|
||
<h3 className="text-lg font-medium mb-2">创建新模板</h3>
|
||
<p className="text-sm text-muted-foreground text-center mb-4">创建自定义分析模板,保存常用的分析配置</p>
|
||
<Button variant="outline">创建模板</Button>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
<TabsContent value="settings" className="space-y-4">
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle>AI分析设置</CardTitle>
|
||
<CardDescription>配置AI分析的全局设置</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="space-y-4">
|
||
<div className="space-y-2">
|
||
<div className="flex items-center justify-between">
|
||
<Label htmlFor="enable-ai">启用AI分析</Label>
|
||
<Switch id="enable-ai" defaultChecked />
|
||
</div>
|
||
<p className="text-sm text-muted-foreground">关闭后,所有AI分析功能将暂停</p>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="default-model">默认AI模型</Label>
|
||
<Select defaultValue="model-3">
|
||
<SelectTrigger id="default-model">
|
||
<SelectValue placeholder="选择默认模型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{aiModels
|
||
.filter((model) => model.status === "active")
|
||
.map((model) => (
|
||
<SelectItem key={model.id} value={model.id}>
|
||
{model.name} ({model.provider})
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="analysis-concurrency">并发分析任务数</Label>
|
||
<Select defaultValue="3">
|
||
<SelectTrigger id="analysis-concurrency">
|
||
<SelectValue placeholder="选择并发任务数" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="1">1</SelectItem>
|
||
<SelectItem value="3">3</SelectItem>
|
||
<SelectItem value="5">5</SelectItem>
|
||
<SelectItem value="10">10</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
<p className="text-sm text-muted-foreground">设置同时执行的AI分析任务数量,数值越大系统负载越高</p>
|
||
</div>
|
||
|
||
<Separator />
|
||
|
||
<div className="space-y-2">
|
||
<Label>数据访问权限</Label>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="access-user-db" defaultChecked />
|
||
<Label htmlFor="access-user-db">用户数据库</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="access-transaction" defaultChecked />
|
||
<Label htmlFor="access-transaction">交易系统</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="access-behavior" defaultChecked />
|
||
<Label htmlFor="access-behavior">行为分析平台</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="access-user-value" defaultChecked />
|
||
<Label htmlFor="access-user-value">用户价值模型</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label>数据处理设置</Label>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="anonymize-data" defaultChecked />
|
||
<Label htmlFor="anonymize-data">数据匿名化</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="cache-results" defaultChecked />
|
||
<Label htmlFor="cache-results">缓存分析结果</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="auto-update" defaultChecked />
|
||
<Label htmlFor="auto-update">自动更新分析</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="save-history" defaultChecked />
|
||
<Label htmlFor="save-history">保存分析历史</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label>通知设置</Label>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="notify-completion" defaultChecked />
|
||
<Label htmlFor="notify-completion">分析完成通知</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="notify-error" defaultChecked />
|
||
<Label htmlFor="notify-error">错误通知</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="notify-insight" defaultChecked />
|
||
<Label htmlFor="notify-insight">重要洞察通知</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2">
|
||
<Checkbox id="notify-email" defaultChecked />
|
||
<Label htmlFor="notify-email">邮件通知</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex justify-end">
|
||
<Button>保存设置</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</TabsContent>
|
||
</Tabs>
|
||
|
||
{/* 任务详情对话框 */}
|
||
<Dialog open={!!selectedTaskId} onOpenChange={(open) => !open && setSelectedTaskId(null)}>
|
||
<DialogContent className="sm:max-w-[700px]">
|
||
<DialogHeader>
|
||
<DialogTitle>分析任务详情</DialogTitle>
|
||
<DialogDescription>查看AI分析任务的详细信息和结果</DialogDescription>
|
||
</DialogHeader>
|
||
{selectedTask && (
|
||
<div className="space-y-4 py-4">
|
||
<div className="flex items-center gap-4">
|
||
{getTaskTypeIcon(selectedTask.type)}
|
||
<div>
|
||
<h3 className="font-medium text-lg">{selectedTask.name}</h3>
|
||
<p className="text-sm text-muted-foreground">
|
||
{selectedTask.dataSource} | 创建于 {selectedTask.createdAt}
|
||
</p>
|
||
</div>
|
||
<div className="ml-auto">{getStatusBadge(selectedTask.status)}</div>
|
||
</div>
|
||
|
||
<Separator />
|
||
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">分析参数</h4>
|
||
<div className="grid grid-cols-2 gap-2">
|
||
{Object.entries(selectedTask.parameters).map(([key, value]) => (
|
||
<div key={key} className="flex justify-between py-1 border-b border-dashed border-gray-200">
|
||
<span className="text-sm text-muted-foreground">{key}:</span>
|
||
<span className="text-sm font-medium">
|
||
{Array.isArray(value) ? value.join(", ") : value.toString()}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{selectedTask.status === "running" && (
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between items-center">
|
||
<h4 className="text-sm font-medium">分析进度</h4>
|
||
<span className="text-sm font-medium">{selectedTask.progress}%</span>
|
||
</div>
|
||
<div className="w-full bg-gray-200 rounded-full h-2.5">
|
||
<div
|
||
className="bg-blue-600 h-2.5 rounded-full"
|
||
style={{ width: `${selectedTask.progress}%` }}
|
||
></div>
|
||
</div>
|
||
<p className="text-xs text-muted-foreground">
|
||
正在处理数据...预计剩余时间: {Math.round((100 - selectedTask.progress) / 10)} 分钟
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{selectedTask.result && (
|
||
<div className="space-y-4">
|
||
<Separator />
|
||
|
||
<div className="space-y-2">
|
||
<div className="flex justify-between items-center">
|
||
<h4 className="text-sm font-medium">分析摘要</h4>
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={() => handleCopyText(selectedTask.result.summary)}
|
||
className="h-7"
|
||
>
|
||
{copiedText === selectedTask.result.summary ? (
|
||
<Check className="h-3 w-3 mr-1" />
|
||
) : (
|
||
<Copy className="h-3 w-3 mr-1" />
|
||
)}
|
||
复制
|
||
</Button>
|
||
</div>
|
||
<div className="p-3 bg-muted rounded-md text-sm">{selectedTask.result.summary}</div>
|
||
</div>
|
||
|
||
{selectedTask.result.insights && (
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">关键洞察</h4>
|
||
<div className="space-y-1">
|
||
{selectedTask.result.insights.map((insight: string, index: number) => (
|
||
<div key={index} className="flex items-start gap-2">
|
||
<Lightbulb className="h-4 w-4 text-yellow-500 mt-0.5" />
|
||
<p className="text-sm">{insight}</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{selectedTask.result.recommendations && (
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">建议</h4>
|
||
<div className="space-y-1">
|
||
{selectedTask.result.recommendations.map((recommendation: string, index: number) => (
|
||
<div key={index} className="flex items-start gap-2">
|
||
<Zap className="h-4 w-4 text-blue-500 mt-0.5" />
|
||
<p className="text-sm">{recommendation}</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{selectedTask.result.clusters && (
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">发现的用户分群</h4>
|
||
<div className="rounded-md border">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead>分群名称</TableHead>
|
||
<TableHead>用户数</TableHead>
|
||
<TableHead>特征</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{selectedTask.result.clusters.map((cluster: any, index: number) => (
|
||
<TableRow key={index}>
|
||
<TableCell className="font-medium">{cluster.name}</TableCell>
|
||
<TableCell>{cluster.size.toLocaleString()}</TableCell>
|
||
<TableCell>
|
||
<div className="flex flex-wrap gap-1">
|
||
{cluster.characteristics.map((char: string, charIndex: number) => (
|
||
<Badge key={charIndex} variant="outline">
|
||
{char}
|
||
</Badge>
|
||
))}
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{selectedTask.result.tagCategories && (
|
||
<div className="space-y-2">
|
||
<h4 className="text-sm font-medium">生成的标签分类</h4>
|
||
<div className="rounded-md border">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead>分类名称</TableHead>
|
||
<TableHead>标签数量</TableHead>
|
||
<TableHead>覆盖率</TableHead>
|
||
<TableHead>示例标签</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{selectedTask.result.tagCategories.map((category: any, index: number) => (
|
||
<TableRow key={index}>
|
||
<TableCell className="font-medium">{category.name}</TableCell>
|
||
<TableCell>{category.count}</TableCell>
|
||
<TableCell>{category.coverage}</TableCell>
|
||
<TableCell>
|
||
<div className="flex flex-wrap gap-1">
|
||
{category.examples.map((example: string, exampleIndex: number) => (
|
||
<Badge key={exampleIndex} variant="outline">
|
||
{example}
|
||
</Badge>
|
||
))}
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setSelectedTaskId(null)}>
|
||
关闭
|
||
</Button>
|
||
{selectedTask?.status === "completed" && (
|
||
<Button>
|
||
<Download className="mr-2 h-4 w-4" />
|
||
下载报告
|
||
</Button>
|
||
)}
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* 添加模型对话框 */}
|
||
<Dialog open={isAddingModel} onOpenChange={setIsAddingModel}>
|
||
<DialogContent className="sm:max-w-[500px]">
|
||
<DialogHeader>
|
||
<DialogTitle>添加AI模型</DialogTitle>
|
||
<DialogDescription>配置新的AI模型连接</DialogDescription>
|
||
</DialogHeader>
|
||
<div className="grid gap-4 py-4">
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="model-name" className="text-right">
|
||
模型名称
|
||
</Label>
|
||
<Input id="model-name" className="col-span-3" placeholder="例如:GPT-4" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="model-provider" className="text-right">
|
||
提供商
|
||
</Label>
|
||
<Input id="model-provider" className="col-span-3" placeholder="例如:OpenAI" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="model-type" className="text-right">
|
||
模型类型
|
||
</Label>
|
||
<Select>
|
||
<SelectTrigger id="model-type" className="col-span-3">
|
||
<SelectValue placeholder="选择模型类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="llm">大语言模型</SelectItem>
|
||
<SelectItem value="image-gen">图像生成模型</SelectItem>
|
||
<SelectItem value="custom">专用分析模型</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="api-endpoint" className="text-right">
|
||
API端点
|
||
</Label>
|
||
<Input id="api-endpoint" className="col-span-3" placeholder="例如:https://api.openai.com/v1/chat" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="api-key" className="text-right">
|
||
API密钥
|
||
</Label>
|
||
<Input id="api-key" type="password" className="col-span-3" placeholder="输入API密钥" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-start gap-4">
|
||
<Label htmlFor="capabilities" className="text-right pt-2">
|
||
能力
|
||
</Label>
|
||
<Textarea id="capabilities" className="col-span-3" placeholder="例如:文本生成, 内容分析" rows={3} />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<div className="text-right">
|
||
<Label htmlFor="model-status">启用模型</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2 col-span-3">
|
||
<Switch id="model-status" defaultChecked />
|
||
<Label htmlFor="model-status">立即启用此模型</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setIsAddingModel(false)}>
|
||
取消
|
||
</Button>
|
||
<Button onClick={() => setIsAddingModel(false)}>添加模型</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* 创建分析任务对话框 */}
|
||
<Dialog open={isCreatingTask} onOpenChange={setIsCreatingTask}>
|
||
<DialogContent className="sm:max-w-[600px]">
|
||
<DialogHeader>
|
||
<DialogTitle>创建新的分析任务</DialogTitle>
|
||
<DialogDescription>选择分析类型并配置参数</DialogDescription>
|
||
</DialogHeader>
|
||
<div className="grid gap-4 py-4">
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="task-name" className="text-right">
|
||
任务名称
|
||
</Label>
|
||
<Input id="task-name" className="col-span-3" placeholder="例如:高价值用户流失预测" />
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="task-type" className="text-right">
|
||
分析类型
|
||
</Label>
|
||
<Select>
|
||
<SelectTrigger id="task-type" className="col-span-3">
|
||
<SelectValue placeholder="选择分析类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="behavior-analysis">用户行为分析</SelectItem>
|
||
<SelectItem value="segment-discovery">用户分群自动发现</SelectItem>
|
||
<SelectItem value="churn-prediction">用户流失预测</SelectItem>
|
||
<SelectItem value="strategy-generation">营销策略生成</SelectItem>
|
||
<SelectItem value="tag-generation">自动标签生成</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<Label htmlFor="task-datasource" className="text-right">
|
||
数据源
|
||
</Label>
|
||
<Select>
|
||
<SelectTrigger id="task-datasource" className="col-span-3">
|
||
<SelectValue placeholder="选择数据源" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">所有数据源</SelectItem>
|
||
<SelectItem value="user-db">用户数据库</SelectItem>
|
||
<SelectItem value="transaction">交易系统</SelectItem>
|
||
<SelectItem value="behavior">行为分析平台</SelectItem>
|
||
<SelectItem value="user-value">用户价值模型</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-start gap-4">
|
||
<Label htmlFor="task-parameters" className="text-right pt-2">
|
||
分析参数
|
||
</Label>
|
||
<Textarea
|
||
id="task-parameters"
|
||
className="col-span-3"
|
||
placeholder="输入JSON格式的分析参数,例如:{ 'userSegment': '高价值用户', 'timeRange': '近30天' }"
|
||
rows={5}
|
||
/>
|
||
</div>
|
||
<div className="grid grid-cols-4 items-center gap-4">
|
||
<div className="text-right">
|
||
<Label htmlFor="schedule-task">定期运行</Label>
|
||
</div>
|
||
<div className="flex items-center space-x-2 col-span-3">
|
||
<Switch id="schedule-task" />
|
||
<Label htmlFor="schedule-task">定期执行此任务</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => setIsCreatingTask(false)}>
|
||
取消
|
||
</Button>
|
||
<Button onClick={() => setIsCreatingTask(false)}>
|
||
<Play className="mr-2 h-4 w-4" />
|
||
创建任务
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
</div>
|
||
)
|
||
}
|