mirror of
https://github.com/langgenius/dify.git
synced 2026-04-05 20:22:39 +08:00
feat(web): evaluation layout
This commit is contained in:
@@ -17,6 +17,10 @@ const BatchTestPanel = ({
|
||||
}: 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'),
|
||||
@@ -32,6 +36,7 @@ const BatchTestPanel = ({
|
||||
const runBatchTest = useEvaluationStore(state => state.runBatchTest)
|
||||
const fileInputRef = useRef<HTMLInputElement>(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')
|
||||
@@ -51,24 +56,27 @@ const BatchTestPanel = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col border-l border-divider-subtle bg-components-card-bg">
|
||||
<div className="border-b border-divider-subtle p-5">
|
||||
<div className="flex items-center gap-2 text-text-primary system-md-semibold">
|
||||
<span aria-hidden="true" className="i-ri-flask-line h-5 w-5" />
|
||||
{t('batch.title')}
|
||||
<div className="flex h-full min-h-0 flex-col bg-background-default">
|
||||
<div className="px-6 py-4">
|
||||
<div className="text-text-primary system-xl-semibold">{t('batch.title')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-sm-regular">{t('batch.description')}</div>
|
||||
<div className="mt-4 rounded-xl border border-divider-subtle bg-components-card-bg p-3">
|
||||
<div className="flex items-start gap-3">
|
||||
<span aria-hidden="true" className="i-ri-alert-fill mt-0.5 h-4 w-4 shrink-0 text-text-warning" />
|
||||
<div className="text-text-tertiary system-xs-regular">{t('batch.noticeDescription')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 rounded-xl border border-divider-subtle bg-background-default-subtle p-3">
|
||||
<div className="text-text-primary system-sm-semibold">{t('batch.noticeTitle')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-xs-regular">{t('batch.noticeDescription')}</div>
|
||||
</div>
|
||||
<div className="mt-4 flex rounded-xl border border-divider-subtle bg-background-default-subtle p-1">
|
||||
</div>
|
||||
<div className="border-b border-divider-subtle px-6">
|
||||
<div className="flex gap-4">
|
||||
{(['input-fields', 'history'] as const).map(tab => (
|
||||
<button
|
||||
key={tab}
|
||||
type="button"
|
||||
className={cn(
|
||||
TAB_CLASS_NAME,
|
||||
resource.activeBatchTab === tab ? 'bg-components-card-bg text-text-primary shadow-xs' : 'text-text-tertiary',
|
||||
'flex-none rounded-none border-b-2 border-transparent px-0 pb-2.5 pt-2 uppercase',
|
||||
resource.activeBatchTab === tab ? 'border-text-accent-secondary text-text-primary' : 'text-text-tertiary',
|
||||
)}
|
||||
onClick={() => setBatchTab(resourceType, resourceId, tab)}
|
||||
>
|
||||
@@ -77,22 +85,27 @@ const BatchTestPanel = ({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto p-5">
|
||||
<div className={cn('min-h-0 flex-1 overflow-y-auto px-6 py-4', !isPanelReady && 'opacity-50')}>
|
||||
{resource.activeBatchTab === 'input-fields' && (
|
||||
<div className="space-y-5">
|
||||
<div>
|
||||
<div className="mb-2 text-text-secondary system-xs-medium-uppercase">{t('batch.requirementsTitle')}</div>
|
||||
<div className="space-y-2">
|
||||
{config.batchRequirements.map(requirement => (
|
||||
<div key={requirement} className="flex gap-2 text-text-tertiary system-sm-regular">
|
||||
<span className="mt-1 h-1.5 w-1.5 rounded-full bg-text-quaternary" />
|
||||
<span>{requirement}</span>
|
||||
<div className="text-text-primary system-md-semibold">{t('batch.requirementsTitle')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-xs-regular">{t('batch.requirementsDescription')}</div>
|
||||
<div className="mt-3 rounded-xl bg-background-section p-3">
|
||||
{displayedRequirementFields.map(field => (
|
||||
<div key={field.id} className="flex items-center py-1">
|
||||
<div className="rounded px-1 py-0.5 text-text-tertiary system-xs-medium">
|
||||
{field.label}
|
||||
</div>
|
||||
<div className="text-[10px] leading-3 text-text-quaternary">
|
||||
{field.type}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Button variant="secondary" className="w-full justify-center" onClick={handleDownloadTemplate}>
|
||||
<Button variant="secondary" className="w-full justify-center" disabled={!isPanelReady} onClick={handleDownloadTemplate}>
|
||||
<span aria-hidden="true" className="i-ri-download-line mr-1 h-4 w-4" />
|
||||
{t('batch.downloadTemplate')}
|
||||
</Button>
|
||||
@@ -106,15 +119,17 @@ const BatchTestPanel = ({
|
||||
setUploadedFileName(resourceType, resourceId, file?.name ?? null)
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full flex-col items-center justify-center rounded-2xl border border-dashed border-divider-subtle bg-background-default-subtle px-4 py-6 text-center hover:border-components-button-secondary-border"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-file-upload-line h-5 w-5 text-text-tertiary" />
|
||||
<div className="mt-2 text-text-primary system-sm-semibold">{t('batch.uploadTitle')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-xs-regular">{resource.uploadedFileName ?? t('batch.uploadHint')}</div>
|
||||
</button>
|
||||
{isPanelReady && (
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full flex-col items-center justify-center rounded-xl border border-dashed border-divider-subtle bg-background-default-subtle px-4 py-6 text-center hover:border-components-button-secondary-border"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-file-upload-line h-5 w-5 text-text-tertiary" />
|
||||
<div className="mt-2 text-text-primary system-sm-semibold">{t('batch.uploadTitle')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-xs-regular">{resource.uploadedFileName ?? t('batch.uploadHint')}</div>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{!isRunnable && (
|
||||
<div className="rounded-xl border border-divider-subtle bg-background-default-subtle px-3 py-2 text-text-tertiary system-xs-regular">
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import type { EvaluationResourceProps } from '../types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../store'
|
||||
import ConditionGroup from './condition-group'
|
||||
import SectionHeader from './section-header'
|
||||
import { InlineSectionHeader } from './section-header'
|
||||
|
||||
const ConditionsSection = ({
|
||||
resourceType,
|
||||
@@ -14,24 +14,18 @@ const ConditionsSection = ({
|
||||
const { t } = useTranslation('evaluation')
|
||||
const resource = useEvaluationResource(resourceType, resourceId)
|
||||
const addConditionGroup = useEvaluationStore(state => state.addConditionGroup)
|
||||
const canAddCondition = resource.metrics.length > 0
|
||||
|
||||
return (
|
||||
<section className="rounded-2xl border border-divider-subtle bg-components-card-bg p-5">
|
||||
<SectionHeader
|
||||
<section className="max-w-[700px] py-4">
|
||||
<InlineSectionHeader
|
||||
title={t('conditions.title')}
|
||||
description={t('conditions.description')}
|
||||
action={(
|
||||
<Button variant="secondary" onClick={() => addConditionGroup(resourceType, resourceId)}>
|
||||
<span aria-hidden="true" className="i-ri-add-line mr-1 h-4 w-4" />
|
||||
{t('conditions.addGroup')}
|
||||
</Button>
|
||||
)}
|
||||
tooltip={t('conditions.description')}
|
||||
/>
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="mt-2 space-y-4">
|
||||
{resource.conditions.length === 0 && (
|
||||
<div className="rounded-2xl border border-dashed border-divider-subtle px-4 py-10 text-center">
|
||||
<div className="text-text-primary system-sm-semibold">{t('conditions.emptyTitle')}</div>
|
||||
<div className="mt-1 text-text-tertiary system-sm-regular">{t('conditions.emptyDescription')}</div>
|
||||
<div className="rounded-xl bg-background-section px-3 py-3 text-text-tertiary system-xs-regular">
|
||||
{t('conditions.emptyDescription')}
|
||||
</div>
|
||||
)}
|
||||
{resource.conditions.map((group, index) => (
|
||||
@@ -43,6 +37,18 @@ const ConditionsSection = ({
|
||||
index={index}
|
||||
/>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'inline-flex items-center text-text-accent system-sm-medium',
|
||||
!canAddCondition && 'cursor-not-allowed text-components-button-secondary-accent-text-disabled',
|
||||
)}
|
||||
disabled={!canAddCondition}
|
||||
onClick={() => addConditionGroup(resourceType, resourceId)}
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-add-line mr-1 h-4 w-4" />
|
||||
{t('conditions.addCondition')}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ const JudgeModelSelector = ({
|
||||
modelList={modelList}
|
||||
onSelect={model => setJudgeModel(resourceType, resourceId, encodeModelSelection(model.provider, model.model))}
|
||||
showDeprecatedWarnIcon
|
||||
triggerClassName="h-11"
|
||||
triggerClassName="h-8 w-full rounded-lg"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import Button from '@/app/components/base/button'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../store'
|
||||
import CustomMetricEditor from './custom-metric-editor'
|
||||
import MetricSelector from './metric-selector'
|
||||
import SectionHeader from './section-header'
|
||||
import { InlineSectionHeader } from './section-header'
|
||||
|
||||
const MetricSection = ({
|
||||
resourceType,
|
||||
@@ -16,17 +16,27 @@ const MetricSection = ({
|
||||
const { t } = useTranslation('evaluation')
|
||||
const resource = useEvaluationResource(resourceType, resourceId)
|
||||
const removeMetric = useEvaluationStore(state => state.removeMetric)
|
||||
const hasMetrics = resource.metrics.length > 0
|
||||
|
||||
return (
|
||||
<section className="rounded-2xl border border-divider-subtle bg-components-card-bg p-5">
|
||||
<SectionHeader
|
||||
<section className="max-w-[700px] py-4">
|
||||
<InlineSectionHeader
|
||||
title={t('metrics.title')}
|
||||
description={t('metrics.description')}
|
||||
action={<MetricSelector resourceType={resourceType} resourceId={resourceId} />}
|
||||
tooltip={t('metrics.description')}
|
||||
/>
|
||||
<div className="mt-4 space-y-3">
|
||||
<div className="mt-2 space-y-3">
|
||||
{!hasMetrics && (
|
||||
<div className="flex items-center gap-5 rounded-xl bg-background-section px-3 py-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-md">
|
||||
<span aria-hidden="true" className="i-ri-bar-chart-horizontal-line h-6 w-6 text-text-primary" />
|
||||
</div>
|
||||
<div className="text-text-tertiary system-xs-regular">
|
||||
{t('metrics.description')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{resource.metrics.map(metric => (
|
||||
<div key={metric.id} className="rounded-2xl border border-divider-subtle p-4">
|
||||
<div key={metric.id} className="rounded-xl border border-divider-subtle bg-components-card-bg p-4">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-text-primary system-sm-semibold">{metric.label}</div>
|
||||
@@ -55,6 +65,11 @@ const MetricSection = ({
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<MetricSelector
|
||||
resourceType={resourceType}
|
||||
resourceId={resourceId}
|
||||
triggerStyle="text"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -16,10 +16,19 @@ import { cn } from '@/utils/classnames'
|
||||
import { getEvaluationMockConfig } from '../mock'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../store'
|
||||
|
||||
type MetricSelectorProps = EvaluationResourceProps & {
|
||||
triggerVariant?: 'primary' | 'warning' | 'secondary' | 'secondary-accent' | 'ghost' | 'ghost-accent' | 'tertiary'
|
||||
triggerClassName?: string
|
||||
triggerStyle?: 'button' | 'text'
|
||||
}
|
||||
|
||||
const MetricSelector = ({
|
||||
resourceType,
|
||||
resourceId,
|
||||
}: EvaluationResourceProps) => {
|
||||
triggerVariant = 'secondary',
|
||||
triggerClassName,
|
||||
triggerStyle = 'button',
|
||||
}: MetricSelectorProps) => {
|
||||
const { t } = useTranslation('evaluation')
|
||||
const config = getEvaluationMockConfig(resourceType)
|
||||
const metricGroupLabels = {
|
||||
@@ -90,10 +99,23 @@ const MetricSelector = ({
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={handleOpenChange}>
|
||||
<PopoverTrigger className="btn btn-medium btn-secondary inline-flex items-center">
|
||||
<span aria-hidden="true" className="i-ri-add-line mr-1 h-4 w-4" />
|
||||
{t('metrics.add')}
|
||||
</PopoverTrigger>
|
||||
<PopoverTrigger
|
||||
render={(
|
||||
triggerStyle === 'text'
|
||||
? (
|
||||
<button type="button" className={cn('inline-flex items-center text-text-accent system-sm-medium', triggerClassName)}>
|
||||
<span aria-hidden="true" className="i-ri-add-line mr-1 h-4 w-4" />
|
||||
{t('metrics.add')}
|
||||
</button>
|
||||
)
|
||||
: (
|
||||
<Button variant={triggerVariant} className={triggerClassName}>
|
||||
<span aria-hidden="true" className="i-ri-add-line mr-1 h-4 w-4" />
|
||||
{t('metrics.add')}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
/>
|
||||
<PopoverContent popupClassName="w-[360px] p-3">
|
||||
<div className="space-y-3">
|
||||
<Input
|
||||
|
||||
@@ -1,23 +1,72 @@
|
||||
'use client'
|
||||
|
||||
import type { ReactNode } from 'react'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type SectionHeaderProps = {
|
||||
title: string
|
||||
description: string
|
||||
description?: ReactNode
|
||||
action?: ReactNode
|
||||
className?: string
|
||||
titleClassName?: string
|
||||
descriptionClassName?: string
|
||||
}
|
||||
|
||||
type InlineSectionHeaderProps = {
|
||||
title: string
|
||||
tooltip?: ReactNode
|
||||
action?: ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
const SectionHeader = ({
|
||||
title,
|
||||
description,
|
||||
action,
|
||||
className,
|
||||
titleClassName,
|
||||
descriptionClassName,
|
||||
}: SectionHeaderProps) => {
|
||||
return (
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className={cn('flex flex-wrap items-start justify-between gap-3', className)}>
|
||||
<div>
|
||||
<div className={cn('text-text-primary system-md-semibold', titleClassName)}>{title}</div>
|
||||
{description && <div className={cn('mt-1 text-text-tertiary system-sm-regular', descriptionClassName)}>{description}</div>}
|
||||
</div>
|
||||
{action}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const InlineSectionHeader = ({
|
||||
title,
|
||||
tooltip,
|
||||
action,
|
||||
className,
|
||||
}: InlineSectionHeaderProps) => {
|
||||
return (
|
||||
<div className={cn('flex flex-wrap items-center justify-between gap-3', className)}>
|
||||
<div className="flex min-h-6 items-center gap-1">
|
||||
<div className="text-text-primary system-md-semibold">{title}</div>
|
||||
<div className="mt-1 text-text-tertiary system-sm-regular">{description}</div>
|
||||
{tooltip && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={(
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-4 w-4 items-center justify-center text-text-quaternary transition-colors hover:text-text-tertiary"
|
||||
aria-label={title}
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-information-line h-3.5 w-3.5" />
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
<TooltipContent>
|
||||
{tooltip}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
{action}
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
import type { EvaluationResourceProps } from './types'
|
||||
import { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import BatchTestPanel from './components/batch-test-panel'
|
||||
import ConditionsSection from './components/conditions-section'
|
||||
import JudgeModelSelector from './components/judge-model-selector'
|
||||
import MetricSection from './components/metric-section'
|
||||
import SectionHeader from './components/section-header'
|
||||
import SectionHeader, { InlineSectionHeader } from './components/section-header'
|
||||
import { useEvaluationStore } from './store'
|
||||
|
||||
const Evaluation = ({
|
||||
@@ -15,6 +16,8 @@ const Evaluation = ({
|
||||
resourceId,
|
||||
}: EvaluationResourceProps) => {
|
||||
const { t } = useTranslation('evaluation')
|
||||
const { t: tCommon } = useTranslation('common')
|
||||
const docLink = useDocLink()
|
||||
const ensureResource = useEvaluationStore(state => state.ensureResource)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -22,22 +25,41 @@ const Evaluation = ({
|
||||
}, [ensureResource, resourceId, resourceType])
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col bg-background-body xl:flex-row">
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-4 py-5 xl:px-8">
|
||||
<div className="mx-auto max-w-5xl space-y-6">
|
||||
<SectionHeader title={t('title')} description={t('description')} />
|
||||
<section className="rounded-2xl border border-divider-subtle bg-components-card-bg p-5">
|
||||
<SectionHeader title={t('judgeModel.title')} description={t('judgeModel.description')} />
|
||||
<div className="mt-4 max-w-[360px]">
|
||||
<div className="flex h-full min-h-0 flex-col bg-background-default xl:flex-row">
|
||||
<div className="min-h-0 flex-1 overflow-y-auto">
|
||||
<div className="mx-auto flex min-h-full max-w-[748px] flex-col px-6 py-4">
|
||||
<SectionHeader
|
||||
title={t('title')}
|
||||
description={(
|
||||
<>
|
||||
{t('description')}
|
||||
{' '}
|
||||
<a
|
||||
className="text-text-accent"
|
||||
href={docLink()}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{tCommon('operation.learnMore')}
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
descriptionClassName="max-w-[700px]"
|
||||
/>
|
||||
<section className="max-w-[700px] py-4">
|
||||
<InlineSectionHeader title={t('judgeModel.title')} tooltip={t('judgeModel.description')} />
|
||||
<div className="mt-1.5">
|
||||
<JudgeModelSelector resourceType={resourceType} resourceId={resourceId} />
|
||||
</div>
|
||||
</section>
|
||||
<div className="max-w-[700px] border-b border-divider-subtle" />
|
||||
<MetricSection resourceType={resourceType} resourceId={resourceId} />
|
||||
<div className="max-w-[700px] border-b border-divider-subtle" />
|
||||
<ConditionsSection resourceType={resourceType} resourceId={resourceId} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-[420px] shrink-0 xl:h-auto xl:w-[360px]">
|
||||
<div className="h-[420px] shrink-0 border-t border-divider-subtle xl:h-auto xl:w-[450px] xl:border-l xl:border-t-0">
|
||||
<BatchTestPanel resourceType={resourceType} resourceId={resourceId} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"batch.description": "Execute batch evaluations and track performance history.",
|
||||
"batch.downloadTemplate": "Download Excel Template",
|
||||
"batch.emptyHistory": "No test history yet.",
|
||||
"batch.noticeDescription": "Download the template, upload your cases, then run a local mock batch test.",
|
||||
"batch.noticeDescription": "Configuration incomplete. Select the Judge Model and Metrics on the left to generate your batch test template.",
|
||||
"batch.noticeTitle": "Quick start",
|
||||
"batch.requirementsDescription": "The input variables required to run this batch test. Ensure your uploaded dataset matches these fields.",
|
||||
"batch.requirementsTitle": "Data requirements",
|
||||
"batch.run": "Run Test",
|
||||
"batch.status.failed": "Failed",
|
||||
@@ -19,7 +21,7 @@
|
||||
"conditions.boolean.false": "False",
|
||||
"conditions.boolean.true": "True",
|
||||
"conditions.description": "Define additional rules for when results should pass or fail.",
|
||||
"conditions.emptyDescription": "Start with a condition group to define evaluation gates.",
|
||||
"conditions.emptyDescription": "Add metrics above to configure pass/fail thresholds.",
|
||||
"conditions.emptyTitle": "No conditions yet",
|
||||
"conditions.fieldPlaceholder": "Select field",
|
||||
"conditions.groupLabel": "Group {{index}}",
|
||||
@@ -44,7 +46,7 @@
|
||||
"conditions.selectValue": "Choose a value",
|
||||
"conditions.title": "Judgment Conditions",
|
||||
"conditions.valuePlaceholder": "Enter a value",
|
||||
"description": "Configure judge models, metrics, and batch tests for this resource.",
|
||||
"description": "Configure automated testing to grade your application's performance.",
|
||||
"judgeModel.description": "Choose the model used to score your evaluation results.",
|
||||
"judgeModel.title": "Judge Model",
|
||||
"metrics.add": "Add Metric",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"batch.description": "执行批量评测并追踪性能历史。",
|
||||
"batch.downloadTemplate": "下载 Excel 模板",
|
||||
"batch.emptyHistory": "还没有测试历史。",
|
||||
"batch.noticeDescription": "先下载模板,再上传测试集,然后运行本地模拟批量测试。",
|
||||
"batch.noticeDescription": "配置尚未完成。请先在左侧选择判定模型和指标,以生成批量测试模板。",
|
||||
"batch.noticeTitle": "快速开始",
|
||||
"batch.requirementsDescription": "运行此批量测试所需的输入变量。请确保上传的数据集包含这些字段。",
|
||||
"batch.requirementsTitle": "数据要求",
|
||||
"batch.run": "运行测试",
|
||||
"batch.status.failed": "失败",
|
||||
@@ -19,7 +21,7 @@
|
||||
"conditions.boolean.false": "否",
|
||||
"conditions.boolean.true": "是",
|
||||
"conditions.description": "定义额外规则,决定结果何时通过或失败。",
|
||||
"conditions.emptyDescription": "从一个条件组开始,定义评测门槛。",
|
||||
"conditions.emptyDescription": "请先添加上方指标,再配置通过 / 失败阈值。",
|
||||
"conditions.emptyTitle": "还没有条件",
|
||||
"conditions.fieldPlaceholder": "选择字段",
|
||||
"conditions.groupLabel": "条件组 {{index}}",
|
||||
@@ -44,7 +46,7 @@
|
||||
"conditions.selectValue": "选择值",
|
||||
"conditions.title": "判定条件",
|
||||
"conditions.valuePlaceholder": "输入值",
|
||||
"description": "为当前资源配置判定模型、评测指标和批量测试。",
|
||||
"description": "配置自动化测试,对应用表现进行评分。",
|
||||
"judgeModel.description": "选择用于打分和判定评测结果的模型。",
|
||||
"judgeModel.title": "判定模型",
|
||||
"metrics.add": "添加指标",
|
||||
|
||||
Reference in New Issue
Block a user