feat: display chunk type in chunk editor and dialog (#12086)

### What problem does this PR solve?

Display chunk type in chunk editor and dialog, may be one of below:
- Image
- Table
- Text

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
Jimmy Ben Klieve
2025-12-22 16:45:47 +08:00
committed by GitHub
parent 5d391fb1f9
commit b42b5fcf65
7 changed files with 83 additions and 37 deletions

View File

@ -1,11 +1,10 @@
import { api_host } from '@/utils/api';
import classNames from 'classnames';
import React from 'react';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
interface IImage {
interface IImage extends React.ImgHTMLAttributes<HTMLImageElement> {
id: string;
className?: string;
onClick?(): void;
t?: string | number;
}

View File

@ -116,12 +116,15 @@ export interface ITenantInfo {
tts_id: string;
}
export type ChunkDocType = 'image' | 'table';
export interface IChunk {
available_int: number; // Whether to enable, 0: not enabled, 1: enabled
chunk_id: string;
content_with_weight: string;
doc_id: string;
doc_name: string;
doc_type_kwd?: ChunkDocType;
image_id: string;
important_kwd?: string[];
question_kwd?: string[]; // keywords

View File

@ -604,6 +604,12 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
'The document being parsed cannot be deleted',
},
chunk: {
type: 'Type',
docType: {
image: 'Image',
table: 'Table',
text: 'Text',
},
chunk: 'Chunk',
bulk: 'Bulk',
selectAll: 'Select all',

View File

@ -4,6 +4,8 @@
}
.imagePreview {
width: 100%;
height: 100%;
max-width: 50vw;
max-height: 50vh;
object-fit: contain;

View File

@ -2,17 +2,19 @@ import Image from '@/components/image';
import { useTheme } from '@/components/theme-provider';
import { Card } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover';
import { Switch } from '@/components/ui/switch';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { IChunk } from '@/interfaces/database/knowledge';
import { cn } from '@/lib/utils';
import { CheckedState } from '@radix-ui/react-checkbox';
import classNames from 'classnames';
import DOMPurify from 'dompurify';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ChunkTextMode } from '../../constant';
import styles from './index.less';
@ -39,6 +41,7 @@ const ChunkCard = ({
textMode,
t: imageCacheKey,
}: IProps) => {
const { t } = useTranslation();
const available = Number(item.available_int);
const [enabled, setEnabled] = useState(false);
const { theme } = useTheme();
@ -63,51 +66,59 @@ const ChunkCard = ({
useEffect(() => {
setEnabled(available === 1);
}, [available]);
const [open, setOpen] = useState<boolean>(false);
return (
<Card
className={classNames(styles.chunkCard, {
className={classNames('relative flex-none', styles.chunkCard, {
[`${theme === 'dark' ? styles.cardSelectedDark : styles.cardSelected}`]:
selected,
})}
>
<span
className="
absolute top-0 right-0 px-4 py-1
leading-none text-xs text-text-disabled
bg-bg-card rounded-bl-2xl rounded-tr-lg
border-l-0.5 border-b-0.5 border-border-button"
>
{t(
`chunk.docType.${item.doc_type_kwd ? String(item.doc_type_kwd).toLowerCase() : 'text'}`,
)}
</span>
<div className="flex items-start justify-between gap-2">
<Checkbox onCheckedChange={handleCheck} checked={checked}></Checkbox>
{/* Using <Tooltip> instead of <Popover> to avoid flickering when hovering over the image */}
{item.image_id && (
<Popover open={open}>
<PopoverTrigger
asChild
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
>
<div>
<Tooltip>
<TooltipTrigger>
<Image
t={imageCacheKey}
id={item.image_id}
className={styles.image}
/>
</div>
</PopoverTrigger>
<PopoverContent
</TooltipTrigger>
<TooltipContent
className="p-0"
align={'start'}
side={'right'}
sideOffset={-20}
tabIndex={-1}
>
<div>
<Image
t={imageCacheKey}
id={item.image_id}
className={styles.imagePreview}
></Image>
</div>
</PopoverContent>
</Popover>
/>
</TooltipContent>
</Tooltip>
)}
<section
onDoubleClick={handleContentDoubleClick}
onClick={handleContentClick}
className={styles.content}
className={cn(styles.content, 'mt-2')}
>
<div
dangerouslySetInnerHTML={{
@ -118,7 +129,8 @@ const ChunkCard = ({
})}
></div>
</section>
<div>
<div className="mt-2">
<Switch
checked={enabled}
onCheckedChange={onChange}

View File

@ -15,6 +15,7 @@ import {
HoverCardContent,
HoverCardTrigger,
} from '@/components/ui/hover-card';
import { Input } from '@/components/ui/input';
import { Modal } from '@/components/ui/modal/modal';
import Space from '@/components/ui/space';
import { Switch } from '@/components/ui/switch';
@ -76,6 +77,7 @@ const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
const { removeChunk } = useDeleteChunkByIds();
const { data } = useFetchChunk(chunkId);
const { t } = useTranslation();
const isEditMode = !!chunkId;
const isTagParser = parserId === 'tag';
const onSubmit = useCallback(
@ -144,6 +146,28 @@ const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
)}
/>
{/* Do not display the type field in create mode */}
{isEditMode && (
<FormField
control={form.control}
name="doc_type_kwd"
render={({ field }) => (
<FormItem>
<FormLabel>{t(`chunk.type`)}</FormLabel>
<FormControl>
<Input
type="text"
value={t(
`chunk.docType.${field.value ? String(field.value).toLowerCase() : 'text'}`,
)}
readOnly
/>
</FormControl>
</FormItem>
)}
/>
)}
<FormField
control={form.control}
name="image"

View File

@ -45,7 +45,7 @@ export default (props: ICheckboxSetProps) => {
}, [selectedChunkIds]);
return (
<div className="flex gap-[40px] py-4 px-2">
<div className="flex gap-[40px] py-4 px-2 h-14">
<div className="flex items-center gap-3 cursor-pointer text-muted-foreground hover:text-text-primary">
<Checkbox
id="all_chunks_checkbox"