Files
DataMate/frontend/src/pages/SynthesisTask/CreateTask.tsx
chenghh-9609 e8e2c1a96b refactor: 修复标签管理功能、优化数据选择项显示、屏蔽开发中功能 (#12)
* refactor: clean up tag management and dataset handling, update API endpoints

* feat: add showTime prop to DevelopmentInProgress component across multiple pages

* refactor: update component styles and improve layout with new utility classes
2025-10-22 16:09:03 +08:00

1251 lines
51 KiB
TypeScript

import { useState } from "react";
import type { Dataset } from "@/pages/DataManagement/dataset.model";
import {
Steps,
Card,
Select,
Input,
Checkbox,
Button,
Badge,
Divider,
Radio,
Form,
message,
} from "antd";
import {
Eye,
Trash2,
Settings,
ArrowLeft,
ArrowRight,
Play,
Edit,
Copy,
Save,
RefreshCw,
ChevronDown,
ChevronRight,
Search,
CheckCircle,
Code,
X,
MoreHorizontal,
Activity,
MessageSquare,
Brain,
} from "lucide-react";
import { Link, useNavigate } from "react-router";
import DevelopmentInProgress from "@/components/DevelopmentInProgress";
const { TextArea } = Input;
export default function SynthesisTaskCreate() {
return <DevelopmentInProgress showTime="2025.11.30" />;
const navigate = useNavigate();
const [form] = Form.useForm();
const [searchQuery, setSearchQuery] = useState("");
const [createStep, setCreateStep] = useState(1);
const [selectedFiles, setSelectedFiles] = useState<string[]>([]);
const [datasets] = useState<Dataset[]>([]);
const [files] = useState<File[]>([]);
const [selectedSynthesisTypes, setSelectedSynthesisTypes] = useState<
string[]
>(["qa_judge"]);
const [showDebugCard, setShowDebugCard] = useState(false);
const [debugStepId, setDebugStepId] = useState<string | null>(null);
const [expandedTypes, setExpandedTypes] = useState<string[]>([
"qa",
"distillation",
]);
// 表单数据
const [formValues, setFormValues] = useState({
name: "",
sourceDataset: "",
targetCount: 1000,
description: "",
executionMode: "immediate",
scheduleStrategy: "",
outputPath: "",
enableQualityCheck: false,
enableNotification: false,
});
const synthesisTypes = [
{
id: "qa",
name: "生成问答对",
icon: MessageSquare,
count: 14,
expanded: true,
description: "基于文本生成各类问答对",
children: [
{
id: "qa_judge",
name: "文字生成问答对_判断题",
count: 1,
description: "生成判断题形式的问答对",
},
{
id: "qa_choice",
name: "文字生成问答对_选择题",
count: 0,
description: "生成多选题形式的问答对",
},
{
id: "qa_fill",
name: "文字生成问答对_填空题",
count: 0,
description: "生成填空题形式的问答对",
},
{
id: "qa_short",
name: "相关文本描述问答对_金融领域",
count: 0,
description: "金融领域的专业问答对",
},
],
},
{
id: "distillation",
name: "生成蒸馏",
icon: Brain,
count: 6,
expanded: true,
description: "知识蒸馏数据生成",
children: [
{
id: "dist_text",
name: "相关文本生成蒸馏",
count: 0,
description: "基于文本的知识蒸馏",
},
{
id: "dist_qa",
name: "问答数据",
count: 0,
description: "问答形式的蒸馏数据",
},
{
id: "dist_instruct",
name: "相关指令生成蒸馏问题_few-shot",
count: 0,
description: "Few-shot指令蒸馏",
},
{
id: "dist_summary",
name: "问答数据为基础蒸馏",
count: 0,
description: "基于问答数据的蒸馏",
},
{
id: "dist_reasoning",
name: "问答数据为基础高质量",
count: 0,
description: "高质量推理数据蒸馏",
},
],
},
];
const toggleTypeExpansion = (typeId: string) => {
setExpandedTypes((prev) =>
prev.includes(typeId)
? prev.filter((id) => id !== typeId)
: [...prev, typeId]
);
};
const handleSynthesisTypeSelect = (typeId: string) => {
setSelectedSynthesisTypes((prev) => {
if (prev.includes(typeId)) {
return prev.filter((id) => id !== typeId);
} else {
return [...prev, typeId];
}
});
};
const handleValuesChange = (_, allValues) => {
setFormValues({ ...formValues, ...allValues });
};
const handleSelectAllFiles = () => {
const filteredFiles = files.filter((file) =>
file.name.toLowerCase().includes(searchQuery.toLowerCase())
);
if (selectedFiles.length === filteredFiles.length) {
setSelectedFiles([]);
} else {
setSelectedFiles(filteredFiles.map((file) => file.id));
}
};
const handleRemoveSelectedFile = (fileId: string) => {
setSelectedFiles(selectedFiles.filter((id) => id !== fileId));
};
const handleCreateTask = async () => {
try {
const values = await form.validateFields();
if (
!values.name ||
!values.sourceDataset ||
selectedFiles.length === 0 ||
selectedSynthesisTypes.length === 0 ||
!values.outputPath ||
!values.targetCount ||
(values.executionMode === "scheduled" && !values.scheduleStrategy)
) {
message.error("请填写所有必填项");
return;
}
const newTask: SynthesisTask = {
id: Date.now(),
name: values.name,
type: selectedSynthesisTypes[0].includes("qa") ? "qa" : "distillation",
status: values.executionMode === "immediate" ? "pending" : "paused",
progress: 0,
sourceDataset: values.sourceDataset,
targetCount: values.targetCount,
generatedCount: 0,
createdAt: new Date().toISOString().split("T")[0],
template: "自动生成模板",
estimatedTime: "预计 30 分钟",
};
setTasks([newTask, ...tasks]);
setShowCreateTask(false);
setCreateStep(1);
// Reset form
form.resetFields();
setSelectedFiles([]);
// Auto-start simulation if immediate execution
if (values.executionMode === "immediate") {
setTimeout(() => {
setTasks((prev) =>
prev.map((task) =>
task.id === newTask.id ? { ...task, status: "running" } : task
)
);
const interval = setInterval(() => {
setTasks((prev) =>
prev.map((task) => {
if (task.id === newTask.id && task.status === "running") {
const newProgress = Math.min(
task.progress + Math.random() * 8 + 2,
100
);
const isCompleted = newProgress >= 100;
return {
...task,
progress: newProgress,
generatedCount: Math.floor(
(newProgress / 100) * task.targetCount
),
status: isCompleted ? "completed" : "running",
estimatedTime: isCompleted
? "已完成"
: `剩余 ${Math.ceil((100 - newProgress) / 10)} 分钟`,
};
}
return task;
})
);
}, 1000);
setTimeout(() => clearInterval(interval), 12000);
}, 1000);
}
} catch {
// 校验失败
}
};
const renderCreateTaskPage = () => {
if (createStep === 1) {
return (
<Card className="overflow-y-auto p-2">
<Form
form={form}
layout="vertical"
initialValues={formValues}
onValuesChange={handleValuesChange}
autoComplete="off"
>
<h2 className="font-medium text-gray-900 text-lg mb-2"></h2>
<Form.Item
label="任务名称"
name="name"
rules={[{ required: true, message: "请输入任务名称" }]}
>
<Input placeholder="输入任务名称" className="h-9 text-sm" />
</Form.Item>
<Form.Item
label="目标生成数量"
name="targetCount"
rules={[{ required: true, message: "请输入目标生成数量" }]}
>
<Input
type="number"
min={1}
placeholder="输入目标生成数量"
className="h-9 text-sm"
/>
</Form.Item>
<Form.Item label="任务描述" name="description">
<TextArea
placeholder="描述任务的目的和要求(可选)"
rows={3}
className="resize-none text-sm"
/>
</Form.Item>
<Form.Item
label="源数据集"
name="sourceDataset"
rules={[{ required: true, message: "请选择数据集" }]}
>
<Select
className="w-full"
placeholder="选择数据集"
options={datasets.map((dataset) => ({
label: (
<div key={dataset.id}>
<div className="flex flex-col py-1">
<span className="font-medium text-sm">
{dataset.name}
</span>
<span className="text-xs text-gray-500">
{dataset.type} {dataset.total} {dataset.size}
</span>
</div>
</div>
),
value: dataset.id,
}))}
/>
</Form.Item>
{form.getFieldValue("sourceDataset") && (
<div className="space-y-2">
<span className="text-sm font-semibold text-gray-700">
</span>
<div className="grid grid-cols-2 gap-4">
{/* 文件选择区域 */}
<Card className="border-gray-200">
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="relative flex-1">
<Search className="w-3 h-3 absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400" />
<Input
placeholder="搜索文件..."
className="pl-7 h-8 text-sm"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Button
onClick={handleSelectAllFiles}
className="ml-2 text-xs"
type="default"
>
{selectedFiles.length ===
files.filter((file) =>
file.name
.toLowerCase()
.includes(searchQuery.toLowerCase())
).length
? "取消全选"
: "全选"}
</Button>
</div>
<div className="space-y-1">
{files
.filter((file) =>
file.name
.toLowerCase()
.includes(searchQuery.toLowerCase())
)
.map((file) => (
<div
key={file.id}
className="flex items-center space-x-2 p-2 hover:bg-gray-50 rounded"
>
<Checkbox
checked={selectedFiles.includes(file.id)}
onChange={(e) => {
if (e.target.checked) {
setSelectedFiles([
...selectedFiles,
file.id,
]);
} else {
setSelectedFiles(
selectedFiles.filter(
(id) => id !== file.id
)
);
}
}}
/>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-gray-900 truncate">
{file.name}
</p>
<p className="text-xs text-gray-500">
{file.size} {file.type}
</p>
</div>
</div>
))}
</div>
</div>
</Card>
{/* 已选文件列表 */}
<Card className="border-gray-200">
<div className="flex items-center justify-between">
<span className="text-sm font-medium"></span>
<Badge count={selectedFiles.length} className="text-xs" />
</div>
<div className="space-y-1">
{selectedFiles.length === 0 ? (
<div className="text-center py-4 text-xs text-gray-500">
</div>
) : (
selectedFiles.map((fileId) => {
const file = files.find((f) => f.id === fileId);
if (!file) return null;
return (
<div
key={fileId}
className="flex items-center justify-between p-2 bg-blue-50 rounded border border-blue-200"
>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-blue-900 truncate">
{file.name}
</p>
<p className="text-xs text-blue-600">
{file.size} {file.type}
</p>
</div>
<Button
type="text"
onClick={() => handleRemoveSelectedFile(fileId)}
className="p-1 h-6 w-6 hover:bg-blue-100"
>
<X className="w-3 h-3" />
</Button>
</div>
);
})
)}
</div>
</Card>
</div>
</div>
)}
<h2 className="font-medium text-gray-900 text-lg mt-6 mb-2">
</h2>
<div className="grid grid-cols-2 gap-6">
<div className="space-y-4">
<Form.Item
label="执行方式"
name="executionMode"
rules={[{ required: true, message: "请选择执行方式" }]}
>
<Radio.Group
options={[
{ label: "立即执行", value: "immediate" },
{ label: "周期执行", value: "scheduled" },
]}
optionType="button"
buttonStyle="solid"
/>
</Form.Item>
{form.getFieldValue("executionMode") === "scheduled" && (
<Form.Item
label="执行策略"
name="scheduleStrategy"
rules={[{ required: true, message: "请选择执行策略" }]}
>
<Select
placeholder="选择执行策略"
options={[
{ label: "每日执行", value: "daily" },
{ label: "每周执行", value: "weekly" },
{ label: "每月执行", value: "monthly" },
{ label: "自定义周期", value: "custom" },
]}
/>
</Form.Item>
)}
</div>
<div className="space-y-4">
<Form.Item
label="存放路径"
name="outputPath"
rules={[{ required: true, message: "请输入存放路径" }]}
>
<Input
placeholder="输入结果存放路径,如:/data/synthesis/output"
className="h-9 text-sm"
/>
</Form.Item>
<p className="text-xs text-gray-500">
</p>
<Form.Item name="enableQualityCheck" valuePropName="checked">
<Checkbox>
</Checkbox>
</Form.Item>
<Form.Item name="enableNotification" valuePropName="checked">
<Checkbox>
</Checkbox>
</Form.Item>
</div>
</div>
<Divider />
<div className="flex gap-2 justify-end">
<Button onClick={() => navigate("/data/synthesis/task")}>
</Button>
<Button
type="primary"
onClick={() => {
form
.validateFields()
.then(() => setCreateStep(2))
.catch(() => {});
}}
disabled={
!form.getFieldValue("name") ||
!form.getFieldValue("sourceDataset") ||
selectedFiles.length === 0 ||
!form.getFieldValue("targetCount")
}
>
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</div>
</Form>
</Card>
);
}
if (createStep === 2) {
return (
<div className="">
<div className="grid grid-cols-12 gap-6 min-h-[500px]">
{/* 左侧合成指令 */}
<div className="col-span-4 space-y-4">
<Card className="shadow-sm border-0 bg-white">
<h1 className="text-base"></h1>
<div className="space-y-3 mb-4">
<div className="relative">
<Search className="w-3 h-3 absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400" />
<Input
placeholder="搜索名称、分类搜索"
className="pl-7 text-xs h-8"
/>
</div>
</div>
<div className="space-y-2">
{synthesisTypes.map((type) => {
return (
<div key={type.id} className="space-y-1">
<div
className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded-lg cursor-pointer transition-colors"
onClick={() => toggleTypeExpansion(type.id)}
>
<div className="w-5 h-5 bg-green-500 rounded-lg flex items-center justify-center shadow-sm">
{expandedTypes.includes(type.id) ? (
<ChevronDown className="w-3 h-3 text-white" />
) : (
<ChevronRight className="w-3 h-3 text-white" />
)}
</div>
<span className="font-medium text-xs">
{type.name}({type.count})
</span>
</div>
{expandedTypes.includes(type.id) && (
<div className="ml-7 space-y-1">
{type.children.map((child) => (
<div
key={child.id}
className={`flex items-center gap-2 p-2 rounded-lg cursor-pointer text-xs transition-colors ${
selectedSynthesisTypes.includes(child.id)
? "bg-blue-50 text-blue-700 border border-blue-200"
: "hover:bg-gray-50"
}`}
onClick={() =>
handleSynthesisTypeSelect(child.id)
}
>
<Checkbox
checked={selectedSynthesisTypes.includes(
child.id
)}
onChange={() =>
handleSynthesisTypeSelect(child.id)
}
/>
<span className="flex-1">{child.name}</span>
<span className="text-gray-400">
({child.count})
</span>
</div>
))}
</div>
)}
</div>
);
})}
</div>
</Card>
</div>
{/* 右侧合成编排 */}
<div className="col-span-8">
<Card className="h-full shadow-sm border-0 bg-white">
<div className="flex items-center justify-between">
<h1>({selectedSynthesisTypes.length})</h1>
<div className="flex items-center gap-2">
<Button className="hover:bg-white text-xs" type="default">
<RefreshCw className="w-3 h-3 mr-1" />
</Button>
<Button className="hover:bg-white text-xs" type="default">
<Eye className="w-3 h-3 mr-1" />
</Button>
</div>
</div>
<div className="space-y-4">
{/* 开始节点 */}
<div className="relative">
<Card className="border-green-200 bg-green-50 shadow-sm">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-green-500 text-white rounded-full flex items-center justify-center text-xs font-medium shadow-lg">
</div>
<span className="font-medium text-sm"></span>
</div>
</Card>
</div>
{/* 合成步骤 */}
{selectedSynthesisTypes.map((typeId, index) => {
const typeInfo = synthesisTypes
.flatMap((t) => t.children)
.find((c) => c.id === typeId);
if (!typeInfo) return null;
return (
<div key={typeId} className="relative">
<div className="absolute -top-4 left-4 w-px h-4 bg-gray-300"></div>
<Card className="border-blue-200 bg-blue-50 shadow-sm">
<div className="flex items-start gap-3">
<div className="w-8 h-8 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs font-medium shadow-lg">
{index + 1}
</div>
<div className="flex-1 space-y-3">
<div className="flex items-center justify-between">
<span className="font-medium text-sm">
{typeInfo.name}
</span>
<div className="flex items-center gap-1">
<Button
className="hover:bg-white p-1"
type="text"
>
<Copy className="w-3 h-3" />
</Button>
<Button
className="hover:bg-white p-1"
type="text"
>
<Edit className="w-3 h-3" />
</Button>
<Button
className="hover:bg-white p-1"
type="text"
>
<Trash2 className="w-3 h-3" />
</Button>
<Button
className="hover:bg-white p-1"
type="text"
>
<MoreHorizontal className="w-3 h-3" />
</Button>
</div>
</div>
<div className="text-xs text-gray-600 bg-white p-2 rounded-lg border">
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<span className="text-xs font-medium text-gray-600">
</span>
<Select
defaultValue="未选择"
options={[
{ label: "GPT-4", value: "gpt-4" },
{ label: "GPT-3.5", value: "gpt-3.5" },
]}
></Select>
</div>
<div>
<span className="text-xs font-medium text-gray-600">
</span>
<Button
className="h-7 w-full mt-1 bg-white hover:bg-gray-50 text-xs"
type="default"
onClick={() => {
setDebugStepId(typeId);
setShowDebugCard(true);
}}
>
</Button>
</div>
</div>
<div>
<span className="text-xs font-medium text-gray-600">
</span>
<div className="text-xs text-gray-500 mt-1 bg-white p-2 rounded border">
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<span className="text-xs font-medium text-gray-600">
</span>
<div className="flex items-center gap-1 mt-1">
<Badge className="text-xs bg-white border border-gray-200">
text
</Badge>
</div>
</div>
<div>
<span className="text-xs font-medium text-gray-600">
</span>
<div className="flex items-center gap-1 mt-1">
<Badge className="text-xs bg-blue-100 text-blue-800">
answer
</Badge>
<Badge className="text-xs bg-blue-100 text-blue-800">
question
</Badge>
</div>
</div>
</div>
</div>
</div>
</Card>
</div>
);
})}
{/* 结束节点 */}
<div className="relative">
<div className="absolute -top-4 left-4 w-px h-4 bg-gray-300"></div>
<Card className="border-gray-200 bg-gray-50 shadow-sm">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-gray-500 text-white rounded-full flex items-center justify-center text-xs font-medium shadow-lg">
</div>
<span className="font-medium text-sm"></span>
</div>
</Card>
</div>
</div>
<div className="flex justify-between pt-4 border-t">
<Button
onClick={() => setCreateStep(1)}
className="px-4 py-2 text-sm"
type="default"
>
<ArrowLeft className="w-4 h-4 mr-2" />
</Button>
<Button
onClick={handleCreateTask}
disabled={
!form.getFieldValue("name") ||
!form.getFieldValue("sourceDataset") ||
selectedFiles.length === 0 ||
selectedSynthesisTypes.length === 0 ||
!form.getFieldValue("outputPath") ||
!form.getFieldValue("targetCount") ||
(form.getFieldValue("executionMode") === "scheduled" &&
!form.getFieldValue("scheduleStrategy"))
}
className="px-6 py-2 text-sm font-semibold bg-purple-600 hover:bg-purple-700 shadow-lg"
type="primary"
>
<Play className="w-4 h-4 mr-2" />
</Button>
</div>
</Card>
</div>
</div>
{/* Debug Card */}
{showDebugCard && debugStepId && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<Card className="w-full max-w-4xl max-h-[90vh] overflow-hidden shadow-2xl">
<div className="flex items-center justify-between">
<div>
<Settings className="w-4 h-4" />
-{" "}
{
synthesisTypes
.flatMap((t) => t.children)
.find((c) => c.id === debugStepId)?.name
}
</div>
<Button
onClick={() => {
setShowDebugCard(false);
setDebugStepId(null);
}}
className="hover:bg-white"
>
<X className="w-4 h-4" />
</Button>
</div>
<div className="grid grid-cols-2 h-[70vh]">
{/* Left Panel - Configuration */}
<div className="border-r bg-gray-50 p-4 overflow-y-auto">
<div className="space-y-4">
<div>
<h4 className="font-semibold text-base mb-3 flex items-center gap-2">
<Settings className="w-4 h-4" />
</h4>
<div className="space-y-3">
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<Select
defaultValue="gpt-4"
options={[
{ label: "gpt-4", value: "GPT-4" },
{
label: "gpt-3.5-turbo",
value: "GPT-3.5 Turbo",
},
{ label: "claude-3", value: "Claude-3" },
]}
></Select>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
Temperature
</span>
<div className="flex items-center gap-2">
<Input
type="number"
defaultValue="0.7"
min="0"
max="2"
step="0.1"
className="h-8 text-sm"
/>
<span className="text-xs text-gray-500">
0.0-2.0
</span>
</div>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
Max Tokens
</span>
<Input
type="number"
defaultValue="1000"
min="1"
max="4000"
className="h-8 text-sm"
/>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">Top P</span>
<div className="flex items-center gap-2">
<Input
type="number"
defaultValue="1.0"
min="0"
max="1"
step="0.1"
className="h-8 text-sm"
/>
<span className="text-xs text-gray-500">
0.0-1.0
</span>
</div>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
Frequency Penalty
</span>
<div className="flex items-center gap-2">
<Input
type="number"
defaultValue="0.0"
min="-2"
max="2"
step="0.1"
className="h-8 text-sm"
/>
<span className="text-xs text-gray-500">
-2.0-2.0
</span>
</div>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
Presence Penalty
</span>
<div className="flex items-center gap-2">
<Input
type="number"
defaultValue="0.0"
min="-2"
max="2"
step="0.1"
className="h-8 text-sm"
/>
<span className="text-xs text-gray-500">
-2.0-2.0
</span>
</div>
</div>
</div>
</div>
<Divider />
<div>
<h4 className="font-semibold text-base mb-3 flex items-center gap-2">
<Code className="w-4 h-4" />
</h4>
<div className="space-y-3">
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<TextArea
defaultValue="你是一个专业的数据合成助手,请根据给定的文本内容生成高质量的判断题。"
rows={2}
className="resize-none text-xs"
/>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<TextArea
defaultValue={`根据给定的文本内容,生成一个判断题。
文本内容:{text}
请按照以下格式生成:
1. 判断题:[基于文本内容的判断题]
2. 答案:[对/错]
3. 解释:[简要解释为什么这个答案是正确的]
要求:
- 判断题应该基于文本的核心内容
- 答案必须明确且有依据
- 解释要简洁清晰`}
rows={8}
className="resize-none text-xs font-mono"
/>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<div className="flex flex-wrap gap-1">
<Badge className="bg-blue-50 text-blue-700 text-xs">
text
</Badge>
</div>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<div className="flex flex-wrap gap-1">
<Badge className="bg-green-50 text-green-700 text-xs">
question
</Badge>
<Badge className="bg-green-50 text-green-700 text-xs">
answer
</Badge>
<Badge className="bg-green-50 text-green-700 text-xs">
explanation
</Badge>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Right Panel - Testing */}
<div className="p-4 overflow-y-auto">
<div className="space-y-4">
<div>
<h4 className="font-semibold text-base mb-3 flex items-center gap-2">
<Play className="w-4 h-4" />
</h4>
<div className="space-y-3">
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<TextArea
placeholder="输入测试文本内容..."
defaultValue="人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。"
rows={4}
className="resize-none text-xs"
/>
</div>
<div className="flex gap-2">
<Button className="flex-1 bg-orange-500 hover:bg-orange-600 text-sm">
<Play className="w-3 h-3 mr-1" />
</Button>
<Button className="text-sm bg-transparent">
<RefreshCw className="w-3 h-3 mr-1" />
</Button>
</div>
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<div className="bg-gray-50 border rounded-lg p-3 min-h-[150px]">
<div className="space-y-2 text-xs">
<div>
<span className="font-medium text-gray-700">
</span>
<span className="text-gray-900">
</span>
</div>
<div>
<span className="font-medium text-gray-700">
</span>
<Badge className="ml-1 bg-green-100 text-green-800 text-xs">
</Badge>
</div>
<div>
<span className="font-medium text-gray-700">
</span>
<span className="text-gray-900">
</span>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-3 text-xs">
<div className="space-y-1">
<span className="text-gray-500"></span>
<span className="font-semibold">1.2</span>
</div>
<div className="space-y-1">
<span className="text-gray-500">Token消耗</span>
<span className="font-semibold">156 tokens</span>
</div>
<div className="space-y-1">
<span className="text-gray-500"></span>
<span className="font-semibold text-green-600">
100%
</span>
</div>
<div className="space-y-1">
<span className="text-gray-500"></span>
<span className="font-semibold text-blue-600">
95
</span>
</div>
</div>
</div>
</div>
<Divider />
<div>
<h4 className="font-semibold text-base mb-3 flex items-center gap-2">
<Activity className="w-4 h-4" />
</h4>
<div className="space-y-3">
<div className="space-y-1">
<span className="text-xs font-medium">
</span>
<Select
defaultValue="10"
options={[
{ label: "5", value: "5个样本" },
{ label: "10", value: "10个样本" },
{ label: "20", value: "20个样本" },
{ label: "50", value: "50个样本" },
]}
></Select>
</div>
<Button className="w-full bg-transparent text-sm">
<Activity className="w-3 h-3 mr-1" />
</Button>
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
<div className="flex items-center gap-2 mb-2">
<CheckCircle className="w-3 h-3 text-blue-600" />
<span className="text-xs font-medium text-blue-800">
</span>
</div>
<div className="grid grid-cols-2 gap-3 text-xs">
<div>
<span className="text-blue-600">
</span>
<span className="font-semibold text-blue-800">
9/10
</span>
</div>
<div>
<span className="text-blue-600">
</span>
<span className="font-semibold text-blue-800">
92
</span>
</div>
<div>
<span className="text-blue-600">
</span>
<span className="font-semibold text-blue-800">
1.4
</span>
</div>
<div>
<span className="text-blue-600"></span>
<span className="font-semibold text-blue-800">
1,420 tokens
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="border-t p-4 bg-gray-50">
<div className="flex justify-between">
<Button className="text-sm bg-transparent">
<Save className="w-3 h-3 mr-1" />
</Button>
<div className="flex gap-2">
<Button
onClick={() => {
setShowDebugCard(false);
setDebugStepId(null);
}}
className="text-sm"
>
</Button>
<Button className="bg-orange-500 hover:bg-orange-600 text-sm">
<CheckCircle className="w-3 h-3 mr-1" />
</Button>
</div>
</div>
</div>
</Card>
</div>
)}
</div>
);
}
};
return (
<div className="min-h-screen bg-gray-50">
<div className="p-6">
{/* Header */}
<div className="flex justify-between items-center mb-2">
<div className="flex items-center">
<Link to="/data/synthesis/task">
<Button type="text">
<ArrowLeft className="w-4 h-4 mr-1" />
</Button>
</Link>
<h1 className="text-xl font-bold bg-clip-text"></h1>
</div>
<Steps
current={createStep - 1}
size="small"
items={[{ title: "基本信息" }, { title: "算子编排" }]}
style={{ width: "50%", marginLeft: "auto" }}
/>
</div>
{renderCreateTaskPage()}
</div>
</div>
);
}