export function formatFieldLabel(field) { const key = String(field?.key || '').trim() const label = String(field?.display || field?.label || '').trim() if (!key) return label || '-' if (!label || label === key) return key return label.includes(`[${key}]`) ? label : `${label}[${key}]` } export function buildResultFields(result, fields = []) { const values = result?.field_values && typeof result.field_values === 'object' ? result.field_values : {} return Object.entries(values).slice(0, 8).map(([key, value]) => ({ key, label: formatFieldLabel(fields.find((field) => field.key === key) || { key }), value: Array.isArray(value) ? value.join('、') : String(value ?? '-') })) } export function buildRecognizedFieldRows(result, fields = []) { const rows = Array.isArray(result?.recognized_fields) ? result.recognized_fields : [] return rows.slice(0, 12).map((field, index) => ({ key: String(field?.key || `field-${index}`), label: formatFieldLabel( fields.find((item) => item.key === field?.key) || { key: field?.key, label: field?.label } ), source: formatRecognitionSource(field?.source), value: formatDebugValue(field?.value) })) } export function buildEvidenceItems(result, fields = []) { const evidence = result?.evidence && typeof result.evidence === 'object' ? result.evidence : {} const items = [] if (Array.isArray(evidence.failed_conditions)) { evidence.failed_conditions.slice(0, 3).forEach((condition) => { const left = Array.isArray(condition.left_values) ? condition.left_values.join('、') : '-' const right = Array.isArray(condition.right_values) ? condition.right_values.join('、') : '-' items.push(`${formatFieldName(condition.left, fields)}:${left};${formatFieldName(condition.right, fields)}:${right}`) }) } if (Array.isArray(evidence.missing_fields)) { evidence.missing_fields.slice(0, 5).forEach((field) => { items.push(`${formatFieldName(field, fields)} 缺失`) }) } if (Array.isArray(evidence.keyword_hits)) { items.push(`命中关键词:${evidence.keyword_hits.join('、')}`) } if (evidence.condition_summary) { items.push(String(evidence.condition_summary)) } return [...new Set(items)].slice(0, 5) } export function buildTraceItems(result, fields = []) { const steps = Array.isArray(result?.trace?.steps) ? result.trace.steps : [] return steps.slice(0, 6).map((step, index) => { const title = String(step?.title || step?.node_id || `判断 ${index + 1}`).trim() const status = step?.result ? '成立' : '不成立' const inputs = step?.inputs && typeof step.inputs === 'object' ? Object.entries(step.inputs).slice(0, 3).map(([key, value]) => `${formatFieldName(key, fields)}=${formatDebugValue(value)}`).join(';') : '' return inputs ? `${title}:${status};${inputs}` : `${title}:${status}` }) } export function buildDocumentBrief(document) { const fields = Array.isArray(document?.document_fields) ? document.document_fields : [] if (fields.length) { return fields.slice(0, 6).map((field) => `${field.label}:${field.value}`).join(';') } return String(document?.summary || document?.text || '未提取到结构化字段').slice(0, 120) } export function formatDocumentMeta(document) { const labels = [ document?.document_type_label || '', document?.scene_label || '', document?.avg_score ? `置信度 ${Math.round(Number(document.avg_score) * 100)}%` : '' ].filter(Boolean) return labels.join(' · ') || '未分类' } export function resolveFileStatusLabel(file) { return file.statusText || { pending: '待发送', recognizing: '识别中', recognized: '已识别', failed: '识别失败' }[file.status] || '待识别' } export function trimDebugText(text, maxLength = 800) { const value = String(text || '').replace(/\s+/g, ' ').trim() if (!value) return '' return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value } function formatRecognitionSource(source) { return { manual: '手动输入', ocr: 'OCR结构字段', inferred: '文本推断', model_refined: '模型过滤' }[String(source || '').trim()] || '未标注来源' } function formatDebugValue(value) { if (Array.isArray(value)) return value.map((item) => String(item ?? '')).filter(Boolean).join('、') || '-' if (value && typeof value === 'object') return JSON.stringify(value) return String(value ?? '-') } function formatFieldName(key, fields) { return formatFieldLabel(fields.find((field) => field.key === key) || { key }) }