From 7d1bda958cac42d9a2e88047696759ddd41ab8f1 Mon Sep 17 00:00:00 2001 From: Dallas98 <990259227@qq.com> Date: Tue, 31 Mar 2026 16:26:45 +0800 Subject: [PATCH 01/10] feat: add export functionality for synthesis tasks with format selection --- .../components/SynthesisTaskTab.tsx | 111 +++++- .../src/pages/SynthesisTask/synthesis-api.ts | 22 ++ .../generation/interface/generation_api.py | 84 +++++ .../module/generation/schema/generation.py | 22 ++ .../generation/service/chunk_processor.py | 109 ++++++ .../generation/service/data_exporter.py | 184 +++++++++ .../generation/service/export_service.py | 7 + .../module/generation/service/qa_generator.py | 349 ++++++++++++++++++ 8 files changed, 887 insertions(+), 1 deletion(-) create mode 100644 runtime/datamate-python/app/module/generation/service/chunk_processor.py create mode 100644 runtime/datamate-python/app/module/generation/service/data_exporter.py create mode 100644 runtime/datamate-python/app/module/generation/service/qa_generator.py diff --git a/frontend/src/pages/SynthesisTask/components/SynthesisTaskTab.tsx b/frontend/src/pages/SynthesisTask/components/SynthesisTaskTab.tsx index 12716aae3..1fe82cb90 100644 --- a/frontend/src/pages/SynthesisTask/components/SynthesisTaskTab.tsx +++ b/frontend/src/pages/SynthesisTask/components/SynthesisTaskTab.tsx @@ -5,6 +5,7 @@ import { ArrowUp, ArrowDown, Sparkles, + Download, } from "lucide-react"; import { FolderOpenOutlined, DeleteOutlined, EyeOutlined, ExperimentOutlined } from "@ant-design/icons"; import { Link, useNavigate } from "react-router"; @@ -15,6 +16,8 @@ import { querySynthesisTasksUsingGet, deleteSynthesisTaskByIdUsingDelete, archiveSynthesisTaskToDatasetUsingPost, + getExportFormatsUsingGet, + exportSynthesisDataUsingPost, } from "@/pages/SynthesisTask/synthesis-api"; import { createDatasetUsingPost } from "@/pages/DataManagement/dataset.api"; import { createEvaluationTaskUsingPost } from "@/pages/DataEvaluation/evaluation.api"; @@ -68,8 +71,13 @@ export default function SynthesisTaskTab() { const [evalLoading, setEvalLoading] = useState(false); const [models, setModels] = useState([]); const [modelLoading, setModelLoading] = useState(false); + const [exportModalVisible, setExportModalVisible] = useState(false); + const [currentExportTask, setCurrentExportTask] = useState(null); + const [exportFormats, setExportFormats] = useState<{type: string; name: string; extension: string}[]>([]); + const [exportLoading, setExportLoading] = useState(false); const [evalForm] = Form.useForm(); + const [exportForm] = Form.useForm(); // 获取任务列表 const loadTasks = async () => { @@ -103,6 +111,24 @@ export default function SynthesisTaskTab() { // eslint-disable-next-line }, [searchQuery, filterStatus, page, pageSize]); + // 加载导出格式列表 + useEffect(() => { + const loadExportFormats = async () => { + try { + const res = await getExportFormatsUsingGet(); + setExportFormats(res?.data?.data || []); + } catch (e) { + console.error("Failed to load export formats", e); + setExportFormats([ + { type: "alpaca", name: "Alpaca", extension: ".jsonl" }, + { type: "sharegpt", name: "ShareGPT", extension: ".jsonl" }, + { type: "raw", name: "原始格式", extension: ".jsonl" }, + ]); + } + }; + loadExportFormats(); + }, []); + // 类型映射 const typeMap: Record = { QA: t('synthesisTask.home.typeMap.qa'), @@ -210,7 +236,7 @@ export default function SynthesisTaskTab() { title: t('synthesisTask.home.columns.actions'), key: "actions", fixed: "right" as const, - width: 120, + width: 160, render: (_: unknown, task: SynthesisTask) => (
@@ -221,6 +247,14 @@ export default function SynthesisTaskTab() { icon={} /> + +
+ + ), + okText: t('synthesisTask.actions.archive'), + cancelText: t('synthesisTask.actions.cancel'), + onOk: () => { + const format = (window as unknown as { __archiveFormat?: string }).__archiveFormat || "alpaca"; + handleArchiveTask(task, format); + }, + }); + }; + const openEvalModal = (task: SynthesisTask) => { setCurrentEvalTask(task); setEvalModalVisible(true); @@ -375,47 +362,6 @@ export default function SynthesisTaskTab() { } }; - const openExportModal = (task: SynthesisTask) => { - setCurrentExportTask(task); - setExportModalVisible(true); - exportForm.setFieldsValue({ - format: "alpaca", - }); - }; - - const handleExport = async () => { - if (!currentExportTask) return; - try { - const values = await exportForm.validateFields(); - setExportLoading(true); - - const res = await exportSynthesisDataUsingPost(currentExportTask.id, { - format: values.format, - }); - - const result = res?.data?.data || res?.data; - if (result?.file_paths?.length > 0) { - message.success( - t('synthesisTask.messages.exportSuccess', { - count: result.total_records, - format: values.format, - }) - ); - } else { - message.warning(t('synthesisTask.messages.exportNoData')); - } - setExportModalVisible(false); - setCurrentExportTask(null); - exportForm.resetFields(); - } catch (error) { - const err = error as { errorFields?: unknown; response?: { data?: { message?: string } } }; - if (err?.errorFields) return; - message.error(err?.response?.data?.message || t('synthesisTask.messages.exportFailed')); - } finally { - setExportLoading(false); - } - }; - const chatModelOptions = models .filter((m) => m.type === "CHAT") .map((m) => ({ @@ -617,40 +563,6 @@ export default function SynthesisTaskTab() { )} - - { - setExportModalVisible(false); - setCurrentExportTask(null); - exportForm.resetFields(); - }} - onOk={handleExport} - confirmLoading={exportLoading} - okText={t('synthesisTask.home.modal.export')} - cancelText={t('synthesisTask.actions.cancel')} - > -
- - { - (window as unknown as { __archiveFormat?: string }).__archiveFormat = value; - }} - /> - - - ), - okText: t('synthesisTask.actions.archive'), - cancelText: t('synthesisTask.actions.cancel'), - onOk: () => { - const format = (window as unknown as { __archiveFormat?: string }).__archiveFormat || "alpaca"; - handleArchiveTask(task, format); - }, - }); + setCurrentArchiveTask(task); + setArchiveFormat("alpaca"); + setArchiveModalVisible(true); + }; + + const handleArchiveConfirm = async () => { + if (!currentArchiveTask) return; + setArchiveModalVisible(false); + await handleArchiveTask(currentArchiveTask, archiveFormat); }; const openEvalModal = (task: SynthesisTask) => { @@ -485,6 +468,37 @@ export default function SynthesisTaskTab() { /> + { + setArchiveModalVisible(false); + setCurrentArchiveTask(null); + }} + onOk={handleArchiveConfirm} + okText={t('synthesisTask.actions.archive')} + cancelText={t('synthesisTask.actions.cancel')} + > +
+

{t('synthesisTask.home.confirm.archiveContent', { name: currentArchiveTask?.name })}

+
+ 导出格式: +