= ({
className={contentOpacity}
/>
{images.length > 0 && }
+ {
+ summary && (
+
+ )
+ }
{isGeneralMode && (
{keywords?.map(keyword => )}
diff --git a/web/app/components/datasets/documents/detail/completed/segment-detail.tsx b/web/app/components/datasets/documents/detail/completed/segment-detail.tsx
index dada6f2fe7..e35e7ebef1 100644
--- a/web/app/components/datasets/documents/detail/completed/segment-detail.tsx
+++ b/web/app/components/datasets/documents/detail/completed/segment-detail.tsx
@@ -25,6 +25,7 @@ import Dot from './common/dot'
import Keywords from './common/keywords'
import RegenerationModal from './common/regeneration-modal'
import { SegmentIndexTag } from './common/segment-index-tag'
+import SummaryText from './common/summary-text'
import { useSegmentListContext } from './index'
type ISegmentDetailProps = {
@@ -35,6 +36,7 @@ type ISegmentDetailProps = {
a: string,
k: string[],
attachments: FileEntity[],
+ summary?: string,
needRegenerate?: boolean,
) => void
onCancel: () => void
@@ -57,6 +59,7 @@ const SegmentDetail: FC = ({
const { t } = useTranslation()
const [question, setQuestion] = useState(isEditMode ? segInfo?.content || '' : segInfo?.sign_content || '')
const [answer, setAnswer] = useState(segInfo?.answer || '')
+ const [summary, setSummary] = useState(segInfo?.summary || '')
const [attachments, setAttachments] = useState(() => {
return segInfo?.attachments?.map(item => ({
id: uuid4(),
@@ -91,8 +94,8 @@ const SegmentDetail: FC = ({
}, [onCancel])
const handleSave = useCallback(() => {
- onUpdate(segInfo?.id || '', question, answer, keywords, attachments)
- }, [onUpdate, segInfo?.id, question, answer, keywords, attachments])
+ onUpdate(segInfo?.id || '', question, answer, keywords, attachments, summary, false)
+ }, [onUpdate, segInfo?.id, question, answer, keywords, attachments, summary])
const handleRegeneration = useCallback(() => {
setShowRegenerationModal(true)
@@ -111,8 +114,8 @@ const SegmentDetail: FC = ({
}, [onCancel, onModalStateChange])
const onConfirmRegeneration = useCallback(() => {
- onUpdate(segInfo?.id || '', question, answer, keywords, attachments, true)
- }, [onUpdate, segInfo?.id, question, answer, keywords, attachments])
+ onUpdate(segInfo?.id || '', question, answer, keywords, attachments, summary, true)
+ }, [onUpdate, segInfo?.id, question, answer, keywords, attachments, summary])
const onAttachmentsChange = useCallback((attachments: FileEntity[]) => {
setAttachments(attachments)
@@ -197,6 +200,11 @@ const SegmentDetail: FC = ({
value={attachments}
onChange={onAttachmentsChange}
/>
+ setSummary(summary)}
+ disabled={!isEditMode}
+ />
{isECOIndexing && (
{
const { t } = useTranslation()
- const { segment, score, child_chunks, files } = payload
+ const { segment, score, child_chunks, files, summary } = payload
const { position, content, sign_content, keywords, document, answer } = segment
const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0)
const extension = document.name.split('.').slice(-1)[0] as FileAppearanceTypeEnum
@@ -104,11 +105,14 @@ const ChunkDetailModal = ({
{/* Mask */}
- {(showImages || showKeywords) && (
+ {(showImages || showKeywords || !!summary) && (
{showImages && (
)}
+ {!!summary && (
+
+ )}
{showKeywords && (
{t(`${i18nPrefix}keyword`, { ns: 'datasetHitTesting' })}
diff --git a/web/app/components/datasets/hit-testing/components/result-item.tsx b/web/app/components/datasets/hit-testing/components/result-item.tsx
index 41c77e3cb9..bb3ac8453d 100644
--- a/web/app/components/datasets/hit-testing/components/result-item.tsx
+++ b/web/app/components/datasets/hit-testing/components/result-item.tsx
@@ -7,6 +7,7 @@ import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Markdown } from '@/app/components/base/markdown'
+import SummaryLabel from '@/app/components/datasets/documents/detail/completed/common/summary-label'
import Tag from '@/app/components/datasets/documents/detail/completed/common/tag'
import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
import { cn } from '@/utils/classnames'
@@ -25,7 +26,7 @@ const ResultItem = ({
payload,
}: ResultItemProps) => {
const { t } = useTranslation()
- const { segment, score, child_chunks, files } = payload
+ const { segment, score, child_chunks, files, summary } = payload
const data = segment
const { position, word_count, content, sign_content, keywords, document } = data
const isParentChildRetrieval = !!(child_chunks && child_chunks.length > 0)
@@ -98,6 +99,9 @@ const ResultItem = ({
))}
)}
+ {summary && (
+
+ )}
{/* Foot */}
diff --git a/web/app/components/datasets/settings/form/index.tsx b/web/app/components/datasets/settings/form/index.tsx
index 5fbaefade7..32dde39e97 100644
--- a/web/app/components/datasets/settings/form/index.tsx
+++ b/web/app/components/datasets/settings/form/index.tsx
@@ -2,7 +2,7 @@
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { Member } from '@/models/common'
-import type { IconInfo } from '@/models/datasets'
+import type { IconInfo, SummaryIndexSetting as SummaryIndexSettingType } from '@/models/datasets'
import type { AppIconType, RetrievalConfig } from '@/types/app'
import { RiAlertFill } from '@remixicon/react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
@@ -33,6 +33,7 @@ import RetrievalSettings from '../../external-knowledge-base/create/RetrievalSet
import ChunkStructure from '../chunk-structure'
import IndexMethod from '../index-method'
import PermissionSelector from '../permission-selector'
+import SummaryIndexSetting from '../summary-index-setting'
import { checkShowMultiModalTip } from '../utils'
const rowClass = 'flex gap-x-1'
@@ -76,6 +77,12 @@ const Form = () => {
model: '',
},
)
+ const [summaryIndexSetting, setSummaryIndexSetting] = useState(currentDataset?.summary_index_setting)
+ const summaryIndexSettingRef = useRef(currentDataset?.summary_index_setting)
+ const handleSummaryIndexSettingChange = useCallback((payload: SummaryIndexSettingType) => {
+ setSummaryIndexSetting({ ...summaryIndexSettingRef.current, ...payload })
+ summaryIndexSettingRef.current = { ...summaryIndexSettingRef.current, ...payload }
+ }, [])
const { data: rerankModelList } = useModelList(ModelTypeEnum.rerank)
const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
const { data: membersData } = useMembers()
@@ -167,6 +174,7 @@ const Form = () => {
},
}),
keyword_number: keywordNumber,
+ summary_index_setting: summaryIndexSetting,
},
} as any
if (permission === DatasetPermission.partialMembers) {
@@ -348,6 +356,23 @@ const Form = () => {
)}
+ {
+ indexMethod === IndexingType.QUALIFIED
+ && [ChunkingMode.text, ChunkingMode.parentChild].includes(currentDataset?.doc_form as ChunkingMode)
+ && (
+ <>
+
+
+ >
+ )
+ }
{/* Retrieval Method Config */}
{currentDataset?.provider === 'external'
? (
diff --git a/web/app/components/datasets/settings/summary-index-setting.tsx b/web/app/components/datasets/settings/summary-index-setting.tsx
new file mode 100644
index 0000000000..b79f8ffe0c
--- /dev/null
+++ b/web/app/components/datasets/settings/summary-index-setting.tsx
@@ -0,0 +1,228 @@
+import type { ChangeEvent } from 'react'
+import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import type { SummaryIndexSetting as SummaryIndexSettingType } from '@/models/datasets'
+import {
+ memo,
+ useCallback,
+ useMemo,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import Switch from '@/app/components/base/switch'
+import Textarea from '@/app/components/base/textarea'
+import Tooltip from '@/app/components/base/tooltip'
+import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
+import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
+
+type SummaryIndexSettingProps = {
+ entry?: 'knowledge-base' | 'dataset-settings' | 'create-document'
+ summaryIndexSetting?: SummaryIndexSettingType
+ onSummaryIndexSettingChange?: (payload: SummaryIndexSettingType) => void
+ readonly?: boolean
+}
+const SummaryIndexSetting = ({
+ entry = 'knowledge-base',
+ summaryIndexSetting,
+ onSummaryIndexSettingChange,
+ readonly = false,
+}: SummaryIndexSettingProps) => {
+ const { t } = useTranslation()
+ const {
+ data: textGenerationModelList,
+ } = useModelList(ModelTypeEnum.textGeneration)
+ const summaryIndexModelConfig = useMemo(() => {
+ if (!summaryIndexSetting?.model_name || !summaryIndexSetting?.model_provider_name)
+ return undefined
+
+ return {
+ providerName: summaryIndexSetting?.model_provider_name,
+ modelName: summaryIndexSetting?.model_name,
+ }
+ }, [summaryIndexSetting?.model_name, summaryIndexSetting?.model_provider_name])
+
+ const handleSummaryIndexEnableChange = useCallback((value: boolean) => {
+ onSummaryIndexSettingChange?.({
+ enable: value,
+ })
+ }, [onSummaryIndexSettingChange])
+
+ const handleSummaryIndexModelChange = useCallback((model: DefaultModel) => {
+ onSummaryIndexSettingChange?.({
+ model_provider_name: model.provider,
+ model_name: model.model,
+ })
+ }, [onSummaryIndexSettingChange])
+
+ const handleSummaryIndexPromptChange = useCallback((e: ChangeEvent) => {
+ onSummaryIndexSettingChange?.({
+ summary_prompt: e.target.value,
+ })
+ }, [onSummaryIndexSettingChange])
+
+ if (entry === 'knowledge-base') {
+ return (
+
+
+
+ {t('form.summaryAutoGen', { ns: 'datasetSettings' })}
+
+
+
+
+
+ {
+ summaryIndexSetting?.enable && (
+
+
+ {t('form.summaryModel', { ns: 'datasetSettings' })}
+
+
+
+ {t('form.summaryInstructions', { ns: 'datasetSettings' })}
+
+
+
+ )
+ }
+
+ )
+ }
+
+ if (entry === 'dataset-settings') {
+ return (
+
+
+
+
+ {t('form.summaryAutoGen', { ns: 'datasetSettings' })}
+
+
+
+
+
+ {
+ summaryIndexSetting?.enable ? t('list.status.enabled', { ns: 'datasetDocuments' }) : t('list.status.disabled', { ns: 'datasetDocuments' })
+ }
+
+
+ {
+ summaryIndexSetting?.enable && t('form.summaryAutoGenTip', { ns: 'datasetSettings' })
+ }
+ {
+ !summaryIndexSetting?.enable && t('form.summaryAutoGenEnableTip', { ns: 'datasetSettings' })
+ }
+
+
+
+ {
+ summaryIndexSetting?.enable && (
+ <>
+
+
+
+ {t('form.summaryModel', { ns: 'datasetSettings' })}
+
+
+
+
+
+
+
+
+
+ {t('form.summaryInstructions', { ns: 'datasetSettings' })}
+
+
+
+
+
+
+ >
+ )
+ }
+
+ )
+ }
+
+ return (
+
+
+
+
+ {t('form.summaryAutoGen', { ns: 'datasetSettings' })}
+
+
+ {
+ summaryIndexSetting?.enable && (
+ <>
+
+
+ {t('form.summaryModel', { ns: 'datasetSettings' })}
+
+
+
+
+
+ {t('form.summaryInstructions', { ns: 'datasetSettings' })}
+
+
+
+ >
+ )
+ }
+
+ )
+}
+export default memo(SummaryIndexSetting)
diff --git a/web/app/components/rag-pipeline/components/chunk-card-list/chunk-card.tsx b/web/app/components/rag-pipeline/components/chunk-card-list/chunk-card.tsx
index 9891fd9a47..756417d163 100644
--- a/web/app/components/rag-pipeline/components/chunk-card-list/chunk-card.tsx
+++ b/web/app/components/rag-pipeline/components/chunk-card-list/chunk-card.tsx
@@ -1,10 +1,11 @@
-import type { QAChunk } from './types'
+import type { GeneralChunk, ParentChildChunk, QAChunk } from './types'
import type { ParentMode } from '@/models/datasets'
import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Dot from '@/app/components/datasets/documents/detail/completed/common/dot'
import SegmentIndexTag from '@/app/components/datasets/documents/detail/completed/common/segment-index-tag'
+import SummaryLabel from '@/app/components/datasets/documents/detail/completed/common/summary-label'
import { PreviewSlice } from '@/app/components/datasets/formatted-text/flavours/preview-slice'
import { ChunkingMode } from '@/models/datasets'
import { formatNumber } from '@/utils/format'
@@ -14,7 +15,7 @@ import { QAItemType } from './types'
type ChunkCardProps = {
chunkType: ChunkingMode
parentMode?: ParentMode
- content: string | string[] | QAChunk
+ content: ParentChildChunk | QAChunk | GeneralChunk
positionId?: string | number
wordCount: number
}
@@ -33,7 +34,7 @@ const ChunkCard = (props: ChunkCardProps) => {
const contentElement = useMemo(() => {
if (chunkType === ChunkingMode.parentChild) {
- return (content as string[]).map((child, index) => {
+ return (content as ParentChildChunk).child_contents.map((child, index) => {
const indexForLabel = index + 1
return (
{
)
}
- return content as string
+ return (content as GeneralChunk).content
+ }, [content, chunkType])
+
+ const summaryElement = useMemo(() => {
+ if (chunkType === ChunkingMode.parentChild) {
+ return (content as ParentChildChunk).parent_summary
+ }
+ if (chunkType === ChunkingMode.text) {
+ return (content as GeneralChunk).summary
+ }
+ return null
}, [content, chunkType])
return (
@@ -73,6 +84,7 @@ const ChunkCard = (props: ChunkCardProps) => {
)}
{contentElement}
+ {summaryElement && }
)
}
diff --git a/web/app/components/rag-pipeline/components/chunk-card-list/index.spec.tsx b/web/app/components/rag-pipeline/components/chunk-card-list/index.spec.tsx
index e665cf134e..470942eeb3 100644
--- a/web/app/components/rag-pipeline/components/chunk-card-list/index.spec.tsx
+++ b/web/app/components/rag-pipeline/components/chunk-card-list/index.spec.tsx
@@ -10,13 +10,13 @@ import { QAItemType } from './types'
// Test Data Factories
// =============================================================================
-const createGeneralChunks = (overrides: string[] = []): GeneralChunks => {
+const createGeneralChunks = (overrides: GeneralChunks = []): GeneralChunks => {
if (overrides.length > 0)
return overrides
return [
- 'This is the first chunk of text content.',
- 'This is the second chunk with different content.',
- 'Third chunk here with more text.',
+ { content: 'This is the first chunk of text content.' },
+ { content: 'This is the second chunk with different content.' },
+ { content: 'Third chunk here with more text.' },
]
}
@@ -152,7 +152,7 @@ describe('ChunkCard', () => {
render(
,
@@ -196,7 +196,7 @@ describe('ChunkCard', () => {
,
@@ -218,7 +218,7 @@ describe('ChunkCard', () => {
,
@@ -234,7 +234,7 @@ describe('ChunkCard', () => {
,
@@ -250,7 +250,7 @@ describe('ChunkCard', () => {
render(
,
@@ -268,7 +268,7 @@ describe('ChunkCard', () => {
render(
,
@@ -283,7 +283,7 @@ describe('ChunkCard', () => {
render(
,
@@ -299,7 +299,7 @@ describe('ChunkCard', () => {
,
@@ -317,7 +317,7 @@ describe('ChunkCard', () => {
render(
,
@@ -332,7 +332,7 @@ describe('ChunkCard', () => {
render(
,
@@ -347,7 +347,7 @@ describe('ChunkCard', () => {
render(
,
@@ -366,7 +366,7 @@ describe('ChunkCard', () => {
,
@@ -380,7 +380,7 @@ describe('ChunkCard', () => {
,
@@ -395,7 +395,7 @@ describe('ChunkCard', () => {
const { rerender } = render(
,
@@ -408,7 +408,7 @@ describe('ChunkCard', () => {
rerender(
,
@@ -424,7 +424,7 @@ describe('ChunkCard', () => {
const { rerender } = render(
,
@@ -458,7 +458,7 @@ describe('ChunkCard', () => {
,
@@ -495,7 +495,7 @@ describe('ChunkCard', () => {
render(
,
@@ -510,7 +510,7 @@ describe('ChunkCard', () => {
render(
,
@@ -546,9 +546,9 @@ describe('ChunkCardList', () => {
)
// Assert
- expect(screen.getByText(chunks[0])).toBeInTheDocument()
- expect(screen.getByText(chunks[1])).toBeInTheDocument()
- expect(screen.getByText(chunks[2])).toBeInTheDocument()
+ expect(screen.getByText(chunks[0].content)).toBeInTheDocument()
+ expect(screen.getByText(chunks[1].content)).toBeInTheDocument()
+ expect(screen.getByText(chunks[2].content)).toBeInTheDocument()
})
it('should render parent-child chunks correctly', () => {
@@ -594,7 +594,10 @@ describe('ChunkCardList', () => {
describe('Memoization - chunkList', () => {
it('should extract chunks from GeneralChunks for text mode', () => {
// Arrange
- const chunks: GeneralChunks = ['Chunk 1', 'Chunk 2']
+ const chunks: GeneralChunks = [
+ { content: 'Chunk 1' },
+ { content: 'Chunk 2' },
+ ]
// Act
render(
@@ -653,7 +656,7 @@ describe('ChunkCardList', () => {
it('should update chunkList when chunkInfo changes', () => {
// Arrange
- const initialChunks = createGeneralChunks(['Initial chunk'])
+ const initialChunks = createGeneralChunks([{ content: 'Initial chunk' }])
const { rerender } = render(
{
expect(screen.getByText('Initial chunk')).toBeInTheDocument()
// Act - update chunks
- const updatedChunks = createGeneralChunks(['Updated chunk'])
+ const updatedChunks = createGeneralChunks([{ content: 'Updated chunk' }])
rerender(
{
describe('Word Count Calculation', () => {
it('should calculate word count for text chunks using string length', () => {
// Arrange - "Hello" has 5 characters
- const chunks = createGeneralChunks(['Hello'])
+ const chunks = createGeneralChunks([{ content: 'Hello' }])
// Act
render(
@@ -747,7 +750,11 @@ describe('ChunkCardList', () => {
describe('Position ID', () => {
it('should assign 1-based position IDs to chunks', () => {
// Arrange
- const chunks = createGeneralChunks(['First', 'Second', 'Third'])
+ const chunks = createGeneralChunks([
+ { content: 'First' },
+ { content: 'Second' },
+ { content: 'Third' },
+ ])
// Act
render(
@@ -768,7 +775,7 @@ describe('ChunkCardList', () => {
describe('Custom className', () => {
it('should apply custom className to container', () => {
// Arrange
- const chunks = createGeneralChunks(['Test'])
+ const chunks = createGeneralChunks([{ content: 'Test' }])
// Act
const { container } = render(
@@ -785,7 +792,7 @@ describe('ChunkCardList', () => {
it('should merge custom className with default classes', () => {
// Arrange
- const chunks = createGeneralChunks(['Test'])
+ const chunks = createGeneralChunks([{ content: 'Test' }])
// Act
const { container } = render(
@@ -805,7 +812,7 @@ describe('ChunkCardList', () => {
it('should render without className prop', () => {
// Arrange
- const chunks = createGeneralChunks(['Test'])
+ const chunks = createGeneralChunks([{ content: 'Test' }])
// Act
const { container } = render(
@@ -860,7 +867,7 @@ describe('ChunkCardList', () => {
it('should not use parentMode for text type', () => {
// Arrange
- const chunks = createGeneralChunks(['Text'])
+ const chunks = createGeneralChunks([{ content: 'Text' }])
// Act
render(
@@ -937,7 +944,7 @@ describe('ChunkCardList', () => {
it('should handle single item in chunks', () => {
// Arrange
- const chunks = createGeneralChunks(['Single chunk'])
+ const chunks = createGeneralChunks([{ content: 'Single chunk' }])
// Act
render(
@@ -954,7 +961,7 @@ describe('ChunkCardList', () => {
it('should handle large number of chunks', () => {
// Arrange
- const chunks = Array.from({ length: 100 }, (_, i) => `Chunk number ${i + 1}`)
+ const chunks = Array.from({ length: 100 }, (_, i) => ({ content: `Chunk number ${i + 1}` }))
// Act
render(
@@ -975,8 +982,11 @@ describe('ChunkCardList', () => {
describe('Key Generation', () => {
it('should generate unique keys for chunks', () => {
// Arrange - chunks with same content
- const chunks = createGeneralChunks(['Same content', 'Same content', 'Same content'])
-
+ const chunks = createGeneralChunks([
+ { content: 'Same content' },
+ { content: 'Same content' },
+ { content: 'Same content' },
+ ])
// Act
const { container } = render(
{
it('should render complete text chunking workflow', () => {
// Arrange
const textChunks = createGeneralChunks([
- 'First paragraph of the document.',
- 'Second paragraph with more information.',
- 'Final paragraph concluding the content.',
+ { content: 'First paragraph of the document.' },
+ { content: 'Second paragraph with more information.' },
+ { content: 'Final paragraph concluding the content.' },
])
// Act
@@ -1104,7 +1114,7 @@ describe('ChunkCardList Integration', () => {
describe('Type Switching', () => {
it('should handle switching from text to QA type', () => {
// Arrange
- const textChunks = createGeneralChunks(['Text content'])
+ const textChunks = createGeneralChunks([{ content: 'Text content' }])
const qaChunks = createQAChunks()
const { rerender } = render(
@@ -1132,7 +1142,7 @@ describe('ChunkCardList Integration', () => {
it('should handle switching from text to parent-child type', () => {
// Arrange
- const textChunks = createGeneralChunks(['Simple text'])
+ const textChunks = createGeneralChunks([{ content: 'Simple text' }])
const parentChildChunks = createParentChildChunks()
const { rerender } = render(
diff --git a/web/app/components/rag-pipeline/components/chunk-card-list/index.tsx b/web/app/components/rag-pipeline/components/chunk-card-list/index.tsx
index 3b1f2533b4..176298b2e8 100644
--- a/web/app/components/rag-pipeline/components/chunk-card-list/index.tsx
+++ b/web/app/components/rag-pipeline/components/chunk-card-list/index.tsx
@@ -1,4 +1,4 @@
-import type { ChunkInfo, GeneralChunks, ParentChildChunk, ParentChildChunks, QAChunk, QAChunks } from './types'
+import type { ChunkInfo, GeneralChunk, GeneralChunks, ParentChildChunk, ParentChildChunks, QAChunk, QAChunks } from './types'
import type { ParentMode } from '@/models/datasets'
import { useMemo } from 'react'
import { ChunkingMode } from '@/models/datasets'
@@ -21,13 +21,13 @@ export const ChunkCardList = (props: ChunkCardListProps) => {
if (chunkType === ChunkingMode.parentChild)
return (chunkInfo as ParentChildChunks).parent_child_chunks
return (chunkInfo as QAChunks).qa_chunks
- }, [chunkInfo])
+ }, [chunkInfo, chunkType])
- const getWordCount = (seg: string | ParentChildChunk | QAChunk) => {
+ const getWordCount = (seg: GeneralChunk | ParentChildChunk | QAChunk) => {
if (chunkType === ChunkingMode.parentChild)
- return (seg as ParentChildChunk).parent_content.length
+ return (seg as ParentChildChunk).parent_content?.length
if (chunkType === ChunkingMode.text)
- return (seg as string).length
+ return (seg as GeneralChunk).content.length
return (seg as QAChunk).question.length + (seg as QAChunk).answer.length
}
@@ -41,7 +41,7 @@ export const ChunkCardList = (props: ChunkCardListProps) => {
key={`${chunkType}-${index}`}
chunkType={chunkType}
parentMode={parentMode}
- content={chunkType === ChunkingMode.parentChild ? (seg as ParentChildChunk).child_contents : (seg as string | QAChunk)}
+ content={seg}
wordCount={wordCount}
positionId={index + 1}
/>
diff --git a/web/app/components/rag-pipeline/components/chunk-card-list/types.ts b/web/app/components/rag-pipeline/components/chunk-card-list/types.ts
index 0a5e594b47..6117855b3b 100644
--- a/web/app/components/rag-pipeline/components/chunk-card-list/types.ts
+++ b/web/app/components/rag-pipeline/components/chunk-card-list/types.ts
@@ -1,8 +1,12 @@
-export type GeneralChunks = string[]
-
+export type GeneralChunk = {
+ content: string
+ summary?: string
+}
+export type GeneralChunks = GeneralChunk[]
export type ParentChildChunk = {
child_contents: string[]
parent_content: string
+ parent_summary?: string
parent_mode: string
}
diff --git a/web/app/components/rag-pipeline/components/panel/test-run/index.spec.tsx b/web/app/components/rag-pipeline/components/panel/test-run/index.spec.tsx
index 93423f9e10..972468588a 100644
--- a/web/app/components/rag-pipeline/components/panel/test-run/index.spec.tsx
+++ b/web/app/components/rag-pipeline/components/panel/test-run/index.spec.tsx
@@ -1,8 +1,8 @@
+import type { GeneralChunks } from '@/app/components/rag-pipeline/components/chunk-card-list/types'
import type { WorkflowRunningData } from '@/app/components/workflow/types'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
import { ChunkingMode } from '@/models/datasets'
-
import Header from './header'
// Import components after mocks
import TestRunPanel from './index'
@@ -836,7 +836,7 @@ describe('formatPreviewChunks', () => {
it('should limit to RAG_PIPELINE_PREVIEW_CHUNK_NUM chunks', () => {
const manyChunks = Array.from({ length: 10 }, (_, i) => `chunk${i}`)
const outputs = createMockGeneralOutputs(manyChunks)
- const result = formatPreviewChunks(outputs) as string[]
+ const result = formatPreviewChunks(outputs) as GeneralChunks
// RAG_PIPELINE_PREVIEW_CHUNK_NUM is mocked to 5
expect(result).toHaveLength(5)
diff --git a/web/app/components/rag-pipeline/components/panel/test-run/result/result-preview/utils.ts b/web/app/components/rag-pipeline/components/panel/test-run/result/result-preview/utils.ts
index 9ac0de4d48..de3666224f 100644
--- a/web/app/components/rag-pipeline/components/panel/test-run/result/result-preview/utils.ts
+++ b/web/app/components/rag-pipeline/components/panel/test-run/result/result-preview/utils.ts
@@ -5,13 +5,17 @@ import { ChunkingMode } from '@/models/datasets'
type GeneralChunkPreview = {
content: string
+ summary?: string
}
const formatGeneralChunks = (outputs: any) => {
const chunkInfo: GeneralChunks = []
const chunks = outputs.preview as GeneralChunkPreview[]
chunks.slice(0, RAG_PIPELINE_PREVIEW_CHUNK_NUM).forEach((chunk) => {
- chunkInfo.push(chunk.content)
+ chunkInfo.push({
+ content: chunk.content,
+ summary: chunk.summary,
+ })
})
return chunkInfo
@@ -20,6 +24,7 @@ const formatGeneralChunks = (outputs: any) => {
type ParentChildChunkPreview = {
content: string
child_chunks: string[]
+ summary?: string
}
const formatParentChildChunks = (outputs: any, parentMode: ParentMode) => {
@@ -32,6 +37,7 @@ const formatParentChildChunks = (outputs: any, parentMode: ParentMode) => {
chunks.slice(0, RAG_PIPELINE_PREVIEW_CHUNK_NUM).forEach((chunk) => {
chunkInfo.parent_child_chunks?.push({
parent_content: chunk.content,
+ parent_summary: chunk.summary,
child_contents: chunk.child_chunks,
parent_mode: parentMode,
})
diff --git a/web/app/components/workflow/nodes/knowledge-base/hooks/use-config.ts b/web/app/components/workflow/nodes/knowledge-base/hooks/use-config.ts
index f2a27d338e..f26df2c3ee 100644
--- a/web/app/components/workflow/nodes/knowledge-base/hooks/use-config.ts
+++ b/web/app/components/workflow/nodes/knowledge-base/hooks/use-config.ts
@@ -1,6 +1,7 @@
import type {
KnowledgeBaseNodeType,
RerankingModel,
+ SummaryIndexSetting,
} from '../types'
import type { ValueSelector } from '@/app/components/workflow/types'
import { produce } from 'immer'
@@ -246,6 +247,16 @@ export const useConfig = (id: string) => {
})
}, [handleNodeDataUpdate])
+ const handleSummaryIndexSettingChange = useCallback((summaryIndexSetting: SummaryIndexSetting) => {
+ const nodeData = getNodeData()
+ handleNodeDataUpdate({
+ summary_index_setting: {
+ ...nodeData?.data.summary_index_setting,
+ ...summaryIndexSetting,
+ },
+ })
+ }, [handleNodeDataUpdate, getNodeData])
+
return {
handleChunkStructureChange,
handleIndexMethodChange,
@@ -260,5 +271,6 @@ export const useConfig = (id: string) => {
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
handleInputVariableChange,
+ handleSummaryIndexSettingChange,
}
}
diff --git a/web/app/components/workflow/nodes/knowledge-base/panel.tsx b/web/app/components/workflow/nodes/knowledge-base/panel.tsx
index ec99145d86..0a275645a8 100644
--- a/web/app/components/workflow/nodes/knowledge-base/panel.tsx
+++ b/web/app/components/workflow/nodes/knowledge-base/panel.tsx
@@ -7,6 +7,7 @@ import {
useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
+import SummaryIndexSetting from '@/app/components/datasets/settings/summary-index-setting'
import { checkShowMultiModalTip } from '@/app/components/datasets/settings/utils'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
@@ -51,6 +52,7 @@ const Panel: FC> = ({
handleScoreThresholdChange,
handleScoreThresholdEnabledChange,
handleInputVariableChange,
+ handleSummaryIndexSettingChange,
} = useConfig(id)
const filterVar = useCallback((variable: Var) => {
@@ -167,6 +169,22 @@ const Panel: FC> = ({
+ {
+ data.indexing_technique === IndexMethodEnum.QUALIFIED
+ && [ChunkStructureEnum.general, ChunkStructureEnum.parent_child].includes(data.chunk_structure)
+ && (
+ <>
+
+
+
+
+ >
+ )
+ }
+ preview: Array<{ content: string, child_chunks: string[], summary?: string }>
qa_preview?: QA[]
}
@@ -262,6 +270,7 @@ export type ProcessRuleResponse = {
mode: ProcessMode
rules: Rules
limits: Limits
+ summary_index_setting?: SummaryIndexSetting
}
export type Rules = {
@@ -392,6 +401,7 @@ export type InitialDocumentDetail = {
total_segments?: number
doc_form: ChunkingMode
doc_language: string
+ summary_index_status?: string
}
export type SimpleDocumentDetail = InitialDocumentDetail & {
@@ -425,6 +435,7 @@ export type DocumentReq = {
doc_form: ChunkingMode
doc_language: string
process_rule: ProcessRule
+ summary_index_setting?: SummaryIndexSetting
}
export type CreateDocumentReq = DocumentReq & {
@@ -467,6 +478,7 @@ export type NotionPage = {
export type ProcessRule = {
mode: ProcessMode
rules: Rules
+ summary_index_setting?: SummaryIndexSetting
}
export type createDocumentResponse = {
@@ -575,6 +587,7 @@ export type SegmentDetailModel = {
error: string | null
stopped_at: number
answer?: string
+ summary?: string
child_chunks?: ChildChunkDetail[]
updated_at: number
attachments: Attachment[]
@@ -618,6 +631,7 @@ export type HitTesting = {
tsne_position: TsnePosition
child_chunks: HitTestingChildChunk[] | null
files: Attachment[]
+ summary?: string
}
export type ExternalKnowledgeBaseHitTesting = {
@@ -697,6 +711,7 @@ export type RelatedAppResponse = {
export type SegmentUpdater = {
content: string
answer?: string
+ summary?: string
keywords?: string[]
regenerate_child_chunks?: boolean
attachment_ids?: string[]
@@ -778,6 +793,7 @@ export enum DocumentActionType {
archive = 'archive',
unArchive = 'un_archive',
delete = 'delete',
+ summary = 'summary',
}
export type UpdateDocumentBatchParams = {
diff --git a/web/service/knowledge/use-document.ts b/web/service/knowledge/use-document.ts
index 1f1fc7a219..74c9a77bcf 100644
--- a/web/service/knowledge/use-document.ts
+++ b/web/service/knowledge/use-document.ts
@@ -107,6 +107,18 @@ export const useSyncDocument = () => {
})
}
+export const useDocumentSummary = () => {
+ return useMutation({
+ mutationFn: ({ datasetId, documentIds, documentId }: UpdateDocumentBatchParams) => {
+ return post(`/datasets/${datasetId}/documents/generate-summary`, {
+ body: {
+ document_list: documentId ? [documentId] : documentIds!,
+ },
+ })
+ },
+ })
+}
+
export const useSyncWebsite = () => {
return useMutation({
mutationFn: ({ datasetId, documentId }: UpdateDocumentBatchParams) => {
diff --git a/web/tsconfig.json b/web/tsconfig.json
index efa5247d13..45d7fa7871 100644
--- a/web/tsconfig.json
+++ b/web/tsconfig.json
@@ -2,7 +2,7 @@
"compilerOptions": {
"incremental": true,
"target": "es2022",
- "jsx": "react-jsx",
+ "jsx": "preserve",
"lib": [
"dom",
"dom.iterable",
@@ -19,7 +19,10 @@
]
},
"resolveJsonModule": true,
- "types": ["vitest/globals", "node"],
+ "types": [
+ "vitest/globals",
+ "node"
+ ],
"allowJs": true,
"strict": true,
"noEmit": true,