Files
leaudit-platform-frontend/app/components/dify-dataset-manager/document-detail.tsx
T

248 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
Input,
Button,
InputNumber,
Checkbox,
Select,
Card,
Empty,
Spin,
Divider,
Tooltip,
} from 'antd';
import {
QuestionCircleOutlined,
ReloadOutlined,
EyeOutlined,
} from '@ant-design/icons';
import { useDocumentDetail } from '~/hooks/dify-dataset-manager/document-detail';
import type { DocumentDetailProps } from '~/types/dify-dataset-manager/document-detail';
/**
* 文档详情组件
* 显示文档的分段设置,支持修改并重新处理
*/
export default function DocumentDetail({
datasetId,
document,
}: DocumentDetailProps) {
const {
settings,
previewSegments,
previewLoading,
showPreview,
saving,
updateSettings,
handleReset,
handlePreview,
handleSaveAndProcess,
} = useDocumentDetail(datasetId, document);
if (!document) {
return (
<div className="document-detail-empty">
<Empty description="请选择一个文档" />
</div>
);
}
return (
<div className="document-detail-page">
<div className="document-detail-content">
{/* 左侧设置区域 */}
<div className="settings-panel">
{/* 分段设置 */}
<div className="settings-section">
<h3 className="section-title"></h3>
{/* 分块模式 */}
<div className="setting-item mode-selector">
<div className="mode-option active">
<div className="mode-icon">
<i className="ri-text-spacing"></i>
</div>
<div className="mode-info">
<span className="mode-name"></span>
<span className="mode-desc"></span>
</div>
</div>
</div>
{/* 分段标识符 */}
<div className="setting-item">
<label className="setting-label">
<Tooltip title="系统会在遇到指定分隔符时自动分段,默认值为 \n\n(按段落分段)">
<QuestionCircleOutlined className="help-icon" />
</Tooltip>
</label>
<Input
value={settings.separator}
onChange={(e) => updateSettings('separator', e.target.value)}
placeholder="\n\n"
className="setting-input"
/>
</div>
{/* 分段最大长度 */}
<div className="setting-item">
<label className="setting-label">
<Tooltip title="指定每个分段允许的最大字符数,超过此限制系统会强制分段">
<QuestionCircleOutlined className="help-icon" />
</Tooltip>
</label>
<div className="setting-input-with-suffix">
<InputNumber
value={settings.maxTokens}
onChange={(value) => updateSettings('maxTokens', value || 500)}
min={100}
max={4000}
className="setting-input-number"
/>
<span className="input-suffix">characters</span>
</div>
</div>
</div>
<Divider />
{/* 文本预处理规则 */}
<div className="settings-section">
<h3 className="section-title"></h3>
<div className="checkbox-group">
<Checkbox
checked={settings.removeExtraSpaces}
onChange={(e) => updateSettings('removeExtraSpaces', e.target.checked)}
>
</Checkbox>
<Checkbox
checked={settings.removeUrlsEmails}
onChange={(e) => updateSettings('removeUrlsEmails', e.target.checked)}
>
URL
</Checkbox>
</div>
</div>
<Divider />
{/* Q&A 分段 */}
<div className="settings-section">
<div className="qa-segment-row">
<Checkbox
checked={settings.useQASegment}
onChange={(e) => updateSettings('useQASegment', e.target.checked)}
>
使 Q&A
</Checkbox>
<Select
value={settings.qaLanguage}
onChange={(value) => updateSettings('qaLanguage', value)}
disabled={!settings.useQASegment}
style={{ width: 120 }}
options={[
{ value: 'Chinese', label: 'Chinese' },
{ value: 'English', label: 'English' },
{ value: 'Japanese', label: 'Japanese' },
{ value: 'Korean', label: 'Korean' },
]}
/>
</div>
</div>
{/* 操作按钮 */}
<div className="settings-actions">
<Button
icon={<EyeOutlined />}
onClick={handlePreview}
loading={previewLoading}
>
</Button>
<Button
icon={<ReloadOutlined />}
onClick={handleReset}
>
</Button>
</div>
<Divider />
{/* 保存并处理按钮 */}
<div className="save-actions">
<Button
type="primary"
onClick={handleSaveAndProcess}
loading={saving}
block
>
</Button>
<Button block style={{ marginTop: 8 }}>
</Button>
</div>
</div>
{/* 右侧预览区域 */}
<div className="preview-panel">
<Card
title={
<div className="preview-header">
<span></span>
<Select
value={document.name}
style={{ width: 200 }}
disabled
options={[{ value: document.name, label: document.name }]}
/>
<span className="segment-count">
{showPreview ? `${previewSegments.length} 段块` : '0 段块'}
</span>
</div>
}
className="preview-card"
>
{previewLoading ? (
<div className="preview-loading">
<Spin size="large" />
<div className="loading-text">...</div>
</div>
) : !showPreview ? (
<div className="preview-empty">
<div className="empty-icon">
<EyeOutlined />
</div>
<p>"预览块"</p>
</div>
) : previewSegments.length === 0 ? (
<Empty description="暂无分段数据" />
) : (
<div className="preview-segments">
{previewSegments.map((segment, index) => (
<div key={segment.id} className="segment-item">
<div className="segment-header">
<span className="segment-index">#{index + 1}</span>
<span className="segment-chars">
{segment.word_count}
</span>
</div>
<div className="segment-content">
{segment.content}
</div>
</div>
))}
</div>
)}
</Card>
</div>
</div>
</div>
);
}