diff --git a/web/app/components/evaluation/components/batch-test-panel.tsx b/web/app/components/evaluation/components/batch-test-panel.tsx deleted file mode 100644 index 2d95abf86d..0000000000 --- a/web/app/components/evaluation/components/batch-test-panel.tsx +++ /dev/null @@ -1,179 +0,0 @@ -'use client' - -import type { EvaluationResourceProps } from '../types' -import { useRef } from 'react' -import { useTranslation } from 'react-i18next' -import Badge from '@/app/components/base/badge' -import Button from '@/app/components/base/button' -import { toast } from '@/app/components/base/ui/toast' -import { cn } from '@/utils/classnames' -import { getEvaluationMockConfig } from '../mock' -import { isEvaluationRunnable, useEvaluationResource, useEvaluationStore } from '../store' -import { TAB_CLASS_NAME } from '../utils' - -const BatchTestPanel = ({ - resourceType, - resourceId, -}: EvaluationResourceProps) => { - const { t } = useTranslation('evaluation') - const config = getEvaluationMockConfig(resourceType) - const requirementFields = config.fieldOptions - .filter(field => field.id.includes('.input.') || field.group.toLowerCase().includes('input')) - .slice(0, 4) - const displayedRequirementFields = requirementFields.length > 0 ? requirementFields : config.fieldOptions.slice(0, 4) - const tabLabels = { - 'input-fields': t('batch.tabs.input-fields'), - 'history': t('batch.tabs.history'), - } - const statusLabels = { - running: t('batch.status.running'), - success: t('batch.status.success'), - failed: t('batch.status.failed'), - } - const resource = useEvaluationResource(resourceType, resourceId) - const setBatchTab = useEvaluationStore(state => state.setBatchTab) - const setUploadedFileName = useEvaluationStore(state => state.setUploadedFileName) - const runBatchTest = useEvaluationStore(state => state.runBatchTest) - const fileInputRef = useRef(null) - const isRunnable = isEvaluationRunnable(resource) - const isPanelReady = !!resource.judgeModelId && resource.metrics.length > 0 - - const handleDownloadTemplate = () => { - const content = ['case_id,input,expected', '1,Example input,Example output'].join('\n') - const link = document.createElement('a') - link.href = `data:text/csv;charset=utf-8,${encodeURIComponent(content)}` - link.download = config.templateFileName - link.click() - } - - const handleRun = () => { - if (!isRunnable) { - toast.warning(t('batch.validation')) - return - } - - runBatchTest(resourceType, resourceId) - } - - return ( -
-
-
{t('batch.title')}
-
{t('batch.description')}
-
-
-
-
-
-
-
- {(['input-fields', 'history'] as const).map(tab => ( - - ))} -
-
-
- {resource.activeBatchTab === 'input-fields' && ( -
-
-
{t('batch.requirementsTitle')}
-
{t('batch.requirementsDescription')}
-
- {displayedRequirementFields.map(field => ( -
-
- {field.label} -
-
- {field.type} -
-
- ))} -
-
-
- - { - const file = event.target.files?.[0] - setUploadedFileName(resourceType, resourceId, file?.name ?? null) - }} - /> - {isPanelReady && ( - - )} -
- {!isRunnable && ( -
- {t('batch.validation')} -
- )} - -
- )} - {resource.activeBatchTab === 'history' && ( -
- {resource.batchRecords.length === 0 && ( -
- {t('batch.emptyHistory')} -
- )} - {resource.batchRecords.map(record => ( -
-
-
-
{record.summary}
-
{record.fileName}
-
- - {record.status === 'running' - ? ( - - - ) - : statusLabels[record.status]} - -
-
{record.startedAt}
-
- ))} -
- )} -
-
- ) -} - -export default BatchTestPanel diff --git a/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx b/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx new file mode 100644 index 0000000000..728b3e6c99 --- /dev/null +++ b/web/app/components/evaluation/components/batch-test-panel/history-tab.tsx @@ -0,0 +1,49 @@ +import type { BatchTestRecord } from '../../types' +import { useTranslation } from 'react-i18next' +import Badge from '@/app/components/base/badge' + +type HistoryTabProps = { + batchRecords: BatchTestRecord[] +} + +const HistoryTab = ({ batchRecords }: HistoryTabProps) => { + const { t } = useTranslation('evaluation') + const statusLabels = { + running: t('batch.status.running'), + success: t('batch.status.success'), + failed: t('batch.status.failed'), + } + + return ( +
+ {batchRecords.length === 0 && ( +
+ {t('batch.emptyHistory')} +
+ )} + {batchRecords.map(record => ( +
+
+
+
{record.summary}
+
{record.fileName}
+
+ + {record.status === 'running' + ? ( + + + ) + : statusLabels[record.status]} + +
+
{record.startedAt}
+
+ ))} +
+ ) +} + +export default HistoryTab diff --git a/web/app/components/evaluation/components/batch-test-panel/index.tsx b/web/app/components/evaluation/components/batch-test-panel/index.tsx new file mode 100644 index 0000000000..818f83e5d5 --- /dev/null +++ b/web/app/components/evaluation/components/batch-test-panel/index.tsx @@ -0,0 +1,85 @@ +'use client' + +import type { BatchTestTab, EvaluationResourceProps } from '../../types' +import { useTranslation } from 'react-i18next' +import { cn } from '@/utils/classnames' +import { getEvaluationMockConfig } from '../../mock' +import { isEvaluationRunnable, useEvaluationResource, useEvaluationStore } from '../../store' +import { TAB_CLASS_NAME } from '../../utils' +import HistoryTab from './history-tab' +import InputFieldsTab from './input-fields-tab' + +const BATCH_TABS: BatchTestTab[] = ['input-fields', 'history'] + +const BatchTestPanel = ({ + resourceType, + resourceId, +}: EvaluationResourceProps) => { + const { t } = useTranslation('evaluation') + const config = getEvaluationMockConfig(resourceType) + const requirementFields = config.fieldOptions + .filter(field => field.id.includes('.input.') || field.group.toLowerCase().includes('input')) + .slice(0, 4) + const displayedRequirementFields = requirementFields.length > 0 ? requirementFields : config.fieldOptions.slice(0, 4) + const tabLabels: Record = { + 'input-fields': t('batch.tabs.input-fields'), + 'history': t('batch.tabs.history'), + } + const resource = useEvaluationResource(resourceType, resourceId) + const setBatchTab = useEvaluationStore(state => state.setBatchTab) + const setUploadedFileName = useEvaluationStore(state => state.setUploadedFileName) + const runBatchTest = useEvaluationStore(state => state.runBatchTest) + const isRunnable = isEvaluationRunnable(resource) + const isPanelReady = !!resource.judgeModelId && resource.metrics.length > 0 + + const handleRun = () => runBatchTest(resourceType, resourceId) + + return ( +
+
+
{t('batch.title')}
+
{t('batch.description')}
+
+
+
+
+
+
+
+ {BATCH_TABS.map(tab => ( + + ))} +
+
+
+ {resource.activeBatchTab === 'input-fields' && ( + setUploadedFileName(resourceType, resourceId, uploadedFileName)} + /> + )} + {resource.activeBatchTab === 'history' && } +
+
+ ) +} + +export default BatchTestPanel diff --git a/web/app/components/evaluation/components/batch-test-panel/input-fields-tab.tsx b/web/app/components/evaluation/components/batch-test-panel/input-fields-tab.tsx new file mode 100644 index 0000000000..e43da15e9e --- /dev/null +++ b/web/app/components/evaluation/components/batch-test-panel/input-fields-tab.tsx @@ -0,0 +1,103 @@ +import type { EvaluationFieldOption } from '../../types' +import { useRef } from 'react' +import { useTranslation } from 'react-i18next' +import Button from '@/app/components/base/button' +import { toast } from '@/app/components/base/ui/toast' + +type InputFieldsTabProps = { + requirementFields: EvaluationFieldOption[] + templateFileName: string + uploadedFileName: string | null + isPanelReady: boolean + isRunnable: boolean + onRun: () => void + onUploadFileNameChange: (uploadedFileName: string | null) => void +} + +const InputFieldsTab = ({ + requirementFields, + templateFileName, + uploadedFileName, + isPanelReady, + isRunnable, + onRun, + onUploadFileNameChange, +}: InputFieldsTabProps) => { + const { t } = useTranslation('evaluation') + const fileInputRef = useRef(null) + + const handleDownloadTemplate = () => { + const content = ['case_id,input,expected', '1,Example input,Example output'].join('\n') + const link = document.createElement('a') + link.href = `data:text/csv;charset=utf-8,${encodeURIComponent(content)}` + link.download = templateFileName + link.click() + } + + const handleRun = () => { + if (!isRunnable) { + toast.warning(t('batch.validation')) + return + } + + onRun() + } + + return ( +
+
+
{t('batch.requirementsTitle')}
+
{t('batch.requirementsDescription')}
+
+ {requirementFields.map(field => ( +
+
+ {field.label} +
+
+ {field.type} +
+
+ ))} +
+
+
+ + { + const file = event.target.files?.[0] + onUploadFileNameChange(file?.name ?? null) + }} + /> + {isPanelReady && ( + + )} +
+ {!isRunnable && ( +
+ {t('batch.validation')} +
+ )} + +
+ ) +} + +export default InputFieldsTab