AIUnderstandingPanel.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { Button, Empty, Space, Tooltip, Typography } from 'antd'
  2. import { ThunderboltOutlined } from '@ant-design/icons'
  3. import type { AIUnderstandingVO } from '../api/types'
  4. import { ACTIVE_PARENT_BTN_STYLE, DISABLED_PARENT_BTN_STYLE } from './DeconstructTree'
  5. const { Paragraph, Text } = Typography
  6. interface Props {
  7. data: AIUnderstandingVO | null
  8. loading?: boolean
  9. /** 后端字典: 仅当对应 configCode 在字典里时, "以此召回"按钮才生效 */
  10. configCodes: Record<string, string>
  11. onRecallByText: (text: string, configCodeOverride?: string) => void
  12. }
  13. /**
  14. * 字段 → configCode 映射
  15. * 4 个 RESULT_LOG_* 维度对应内容理解的 4 行
  16. */
  17. const ROW_CODE: Array<{ label: string; field: keyof AIUnderstandingVO; code: string }> = [
  18. { label: '内容选题', field: 'contentTopic', code: 'RESULT_LOG_TOPIC' },
  19. { label: '视频主题', field: 'videoTheme', code: 'RESULT_LOG_THEME' },
  20. { label: '视频关键词', field: 'videoKeywords', code: 'RESULT_LOG_KEYWORDS' },
  21. { label: '视频口播', field: 'videoNarration', code: 'RESULT_LOG_NARRATION' },
  22. ]
  23. /**
  24. * 视频内容理解-旧 (RESULT_LOG_* 维度)
  25. *
  26. * 数据源: video:detail Redis (loghubods.video_dimension_detail_add_column 同步而来)
  27. * 视频口播 字段不在 ODPS 维度表里, 始终为 null → 按钮 disabled
  28. */
  29. export default function AIUnderstandingPanel({ data, loading, configCodes, onRecallByText }: Props) {
  30. if (loading) return <div>加载中...</div>
  31. if (!data) return <Empty description="准备中" image={Empty.PRESENTED_IMAGE_SIMPLE} />
  32. const rows = ROW_CODE.map(({ label, field, code }) => ({
  33. label,
  34. code,
  35. value: ((data[field] as string | undefined | null) ?? '').toString().trim(),
  36. }))
  37. if (rows.every((r) => !r.value)) {
  38. return <Empty description="该视频AI理解结果为空" />
  39. }
  40. return (
  41. <Space direction="vertical" size={8} style={{ width: '100%' }}>
  42. {rows.map(({ label, value, code }) => {
  43. const dictHas = code in configCodes
  44. const supported = dictHas && !!value
  45. const tip = !dictHas
  46. ? `当前未启用"${label}"维度向量召回 (${code} 不在后端字典)`
  47. : !value
  48. ? '该字段无内容,无法召回'
  49. : ''
  50. const btn = supported ? (
  51. <Button
  52. type="primary"
  53. icon={<ThunderboltOutlined />}
  54. onClick={() => onRecallByText(value, code)}
  55. style={ACTIVE_PARENT_BTN_STYLE}
  56. >
  57. 以此召回
  58. </Button>
  59. ) : (
  60. <Tooltip title={tip}>
  61. <Button disabled icon={<ThunderboltOutlined />} style={DISABLED_PARENT_BTN_STYLE}>
  62. 以此召回
  63. </Button>
  64. </Tooltip>
  65. )
  66. return (
  67. <div
  68. key={label}
  69. style={{
  70. display: 'flex',
  71. alignItems: 'center',
  72. gap: 12,
  73. padding: '8px 12px',
  74. border: value ? '1px solid #ffd591' : '1px solid #e8e8e8',
  75. background: value ? '#fff7e6' : '#fafafa',
  76. borderRadius: 6,
  77. }}
  78. >
  79. <Text strong style={{ minWidth: 76, fontSize: 12, color: '#d46b08', flexShrink: 0 }}>
  80. {label}
  81. </Text>
  82. <div style={{ flex: 1, minWidth: 0, fontSize: 13 }}>
  83. {value ? (
  84. <Paragraph
  85. style={{ marginBottom: 0 }}
  86. ellipsis={{ rows: 3, tooltip: value }}
  87. >
  88. {value}
  89. </Paragraph>
  90. ) : (
  91. <Text type="secondary">-</Text>
  92. )}
  93. </div>
  94. {btn}
  95. </div>
  96. )
  97. })}
  98. {data.dt && (
  99. <Text type="secondary" style={{ fontSize: 11 }}>
  100. 数据分区: {data.dt}
  101. </Text>
  102. )}
  103. </Space>
  104. )
  105. }