"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { Progress } from "@/components/ui/progress" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Brain, Zap, Database, ArrowRight, CheckCircle2, Loader2, Play, Settings, RefreshCw, Sparkles, Target, Tags, FileText, AlertCircle, } from "lucide-react" // AI标签引擎任务接口 interface EngineTask { id: string name: string description: string sourceDb: string sourceCollection: string status: 'idle' | 'analyzing' | 'tagging' | 'completed' | 'error' progress: number steps: { name: string status: 'pending' | 'running' | 'completed' | 'error' result?: string }[] stats: { totalRecords: number analyzedRecords: number taggedRecords: number newTags: number } } // 字段映射规则 interface FieldMapping { sourceField: string targetField: string transformRule: string aiEnhance: boolean } // 动态生成引擎任务(从API加载) const generateDefaultTasks = (sources: any[]): EngineTask[] => { return sources.slice(0, 5).map((src, i) => ({ id: `engine_${i + 1}`, name: `${src.name || src.id}数据拆解`, description: `解析${src.database || src.name}数据,提取用户标签`, sourceDb: src.database || src.name, sourceCollection: src.collection || '用户资产统一视图', status: i === 0 ? 'completed' as const : 'idle' as const, progress: i === 0 ? 100 : 0, steps: [ { name: '数据源连接', status: i === 0 ? 'completed' as const : 'pending' as const, result: i === 0 ? `${(src.recordCount / 1000000).toFixed(0)}M条记录` : undefined }, { name: '字段分析', status: i === 0 ? 'completed' as const : 'pending' as const, result: i === 0 ? '识别字段完成' : undefined }, { name: 'AI拆解', status: i === 0 ? 'completed' as const : 'pending' as const, result: i === 0 ? '提取关键字段' : undefined }, { name: '标签生成', status: i === 0 ? 'completed' as const : 'pending' as const, result: i === 0 ? '生成用户标签' : undefined }, { name: '数据写入', status: i === 0 ? 'completed' as const : 'pending' as const, result: i === 0 ? '写入用户估值表' : undefined }, ], stats: { totalRecords: src.recordCount || 0, analyzedRecords: i === 0 ? src.recordCount || 0 : 0, taggedRecords: i === 0 ? Math.floor((src.recordCount || 0) * 0.95) : 0, newTags: i === 0 ? 5 : 0, } })) } // 默认任务(京东示例) const FALLBACK_TASKS: EngineTask[] = [ { id: 'engine_1', name: '腾讯QQ数据拆解', description: '解析QQ库数据,提取手机号关联并生成用户标签', sourceDb: 'KR_腾讯', sourceCollection: 'QQ+手机', status: 'completed', progress: 100, steps: [ { name: '数据源连接', status: 'completed', result: '705M条记录' }, { name: '字段分析', status: 'completed', result: '识别12个字段' }, { name: 'AI拆解', status: 'completed', result: '提取手机号、QQ号、地区' }, { name: '标签生成', status: 'completed', result: '生成3类标签' }, { name: '数据写入', status: 'completed', result: '写入用户估值表' }, ], stats: { totalRecords: 705000000, analyzedRecords: 705000000, taggedRecords: 680000000, newTags: 3, } }, { id: 'engine_2', name: '京东用户数据拆解', description: '解析京东电商数据,提取消费行为生成RFM标签', sourceDb: 'KR_京东', sourceCollection: 'users', status: 'analyzing', progress: 45, steps: [ { name: '数据源连接', status: 'completed', result: '142M条记录' }, { name: '字段分析', status: 'completed', result: '识别28个字段' }, { name: 'AI拆解', status: 'running', result: '分析消费行为...' }, { name: '标签生成', status: 'pending' }, { name: '数据写入', status: 'pending' }, ], stats: { totalRecords: 142000000, analyzedRecords: 63900000, taggedRecords: 0, newTags: 0, } }, { id: 'engine_3', name: '存客宝CRM数据拆解', description: '解析存客宝私域数据,提取客户画像', sourceDb: 'cunkebao_v3', sourceCollection: 'users', status: 'idle', progress: 0, steps: [ { name: '数据源连接', status: 'pending' }, { name: '字段分析', status: 'pending' }, { name: 'AI拆解', status: 'pending' }, { name: '标签生成', status: 'pending' }, { name: '数据写入', status: 'pending' }, ], stats: { totalRecords: 216000, analyzedRecords: 0, taggedRecords: 0, newTags: 0, } }, ] // 标准字段映射规则 const STANDARD_FIELD_MAPPINGS: FieldMapping[] = [ { sourceField: 'phone', targetField: 'phone', transformRule: '格式化为11位', aiEnhance: true }, { sourceField: 'qq', targetField: 'qq', transformRule: '提取纯数字', aiEnhance: false }, { sourceField: 'uid', targetField: 'weibo_uid', transformRule: '微博UID映射', aiEnhance: false }, { sourceField: 'name', targetField: 'name', transformRule: '姓名脱敏', aiEnhance: true }, { sourceField: 'province', targetField: 'province', transformRule: '省份标准化', aiEnhance: true }, { sourceField: 'city', targetField: 'city', transformRule: '城市标准化', aiEnhance: true }, { sourceField: 'gender', targetField: 'gender', transformRule: '性别标准化', aiEnhance: false }, { sourceField: 'amount', targetField: 'total_spend', transformRule: '金额汇总', aiEnhance: false }, { sourceField: 'last_active', targetField: 'recency', transformRule: 'R值计算', aiEnhance: true }, { sourceField: 'buy_count', targetField: 'frequency', transformRule: 'F值计算', aiEnhance: true }, { sourceField: 'total_amount', targetField: 'monetary', transformRule: 'M值计算', aiEnhance: true }, ] export default function AIEnginePage() { const [tasks, setTasks] = useState(FALLBACK_TASKS) const [selectedTask, setSelectedTask] = useState(null) const [showConfigDialog, setShowConfigDialog] = useState(false) const [activeTab, setActiveTab] = useState("tasks") const [loading, setLoading] = useState(true) // 从API加载真实数据源 useEffect(() => { setLoading(true) fetch('/api/data-sources') .then(res => res.json()) .then(data => { if (data.success && data.sources) { // 只取MongoDB数据源 const mongoSources = data.sources.filter((s: any) => s.type === 'mongodb' && s.recordCount > 0) if (mongoSources.length > 0) { setTasks(generateDefaultTasks(mongoSources)) } } }) .catch(console.error) .finally(() => setLoading(false)) }, []) const formatNumber = (num: number): string => { if (num >= 1000000000) return `${(num / 1000000000).toFixed(2)}B` if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M` if (num >= 1000) return `${(num / 1000).toFixed(0)}K` return num.toLocaleString() } const getStatusBadge = (status: string) => { switch (status) { case 'completed': return 已完成 case 'analyzing': case 'tagging': return 处理中 case 'error': return 错误 default: return 待执行 } } const getStepIcon = (status: string) => { switch (status) { case 'completed': return case 'running': return case 'error': return default: return
} } const runTask = (taskId: string) => { setTasks(tasks.map(t => t.id === taskId ? { ...t, status: 'analyzing' as const, steps: t.steps.map((s, i) => i === 0 ? { ...s, status: 'running' as const } : s) } : t)) } // 模拟进度更新 useEffect(() => { const interval = setInterval(() => { setTasks(prev => prev.map(t => { if (t.status === 'analyzing' || t.status === 'tagging') { const newProgress = Math.min(t.progress + Math.random() * 5, 100) const currentStepIndex = t.steps.findIndex(s => s.status === 'running') let newSteps = [...t.steps] if (newProgress > (currentStepIndex + 1) * 20 && currentStepIndex < t.steps.length - 1) { newSteps[currentStepIndex] = { ...newSteps[currentStepIndex], status: 'completed' } newSteps[currentStepIndex + 1] = { ...newSteps[currentStepIndex + 1], status: 'running' } } return { ...t, progress: newProgress, status: newProgress >= 100 ? 'completed' as const : t.status, steps: newProgress >= 100 ? t.steps.map(s => ({ ...s, status: 'completed' as const })) : newSteps, stats: { ...t.stats, analyzedRecords: Math.floor(t.stats.totalRecords * newProgress / 100), taggedRecords: newProgress >= 80 ? Math.floor(t.stats.totalRecords * (newProgress - 20) / 100) : 0, newTags: newProgress >= 60 ? 5 : 0, } } } return t })) }, 2000) return () => clearInterval(interval) }, []) return (
{/* 顶部标题 */}

AI标签引擎

数据接入后自动拆解字段,按用户资产标准生成标签

{/* 引擎说明卡片 */}

AI标签引擎工作流程

1. 数据源连接 2. 字段分析 3. AI拆解 4. 标签生成 5. 写入中台

引擎自动识别数据源字段,按照用户资产数字化标准进行拆解,生成RFM评分和用户标签,最终写入数据中台

{/* 标签页 */} 拆解任务 映射规则 执行日志 {/* 拆解任务列表 */} {tasks.map(task => (

{task.name}

{getStatusBadge(task.status)}

{task.description}

{task.sourceDb}.{task.sourceCollection}
{task.status === 'idle' && ( )}
{/* 进度条 */}
处理进度 {task.progress.toFixed(0)}%
{/* 步骤流程 */}
{task.steps.map((step, i) => (
{getStepIcon(step.status)} {step.name} {step.result && ( {step.result} )}
{i < task.steps.length - 1 && (
)}
))}
{/* 统计信息 */}
总记录: {formatNumber(task.stats.totalRecords)}
已分析: {formatNumber(task.stats.analyzedRecords)}
已打标: {formatNumber(task.stats.taggedRecords)}
新标签: {task.stats.newTags}
))} {/* 字段映射规则 */} 标准字段映射规则
{STANDARD_FIELD_MAPPINGS.map((mapping, i) => (
{mapping.sourceField} {mapping.targetField}
{mapping.transformRule} {mapping.aiEnhance && ( AI增强 )}
))}
{/* 执行日志 */} 执行日志
[2024-01-30 14:32:15] INFO: AI标签引擎启动
[2024-01-30 14:32:16] INFO: 连接数据源 KR_腾讯.qq_phone
[2024-01-30 14:32:18] INFO: 发现 705,000,000 条记录
[2024-01-30 14:32:20] WARN: 字段 'phone' 存在格式不统一,启用AI格式化
[2024-01-30 14:35:45] INFO: AI拆解完成,提取字段: phone, qq, province
[2024-01-30 14:40:12] INFO: 生成标签: 社交活跃度, 地域分布, QQ等级
[2024-01-30 14:45:30] INFO: 数据写入 KR.用户估值 完成
{/* 新建任务弹窗 */} 新建AI拆解任务 配置数据源和拆解规则