mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-23 23:16:58 +08:00
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:
@ -1,11 +1,10 @@
|
|||||||
import { api_host } from '@/utils/api';
|
import { api_host } from '@/utils/api';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import React from 'react';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
||||||
|
|
||||||
interface IImage {
|
interface IImage extends React.ImgHTMLAttributes<HTMLImageElement> {
|
||||||
id: string;
|
id: string;
|
||||||
className?: string;
|
|
||||||
onClick?(): void;
|
|
||||||
t?: string | number;
|
t?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -116,12 +116,15 @@ export interface ITenantInfo {
|
|||||||
tts_id: string;
|
tts_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ChunkDocType = 'image' | 'table';
|
||||||
|
|
||||||
export interface IChunk {
|
export interface IChunk {
|
||||||
available_int: number; // Whether to enable, 0: not enabled, 1: enabled
|
available_int: number; // Whether to enable, 0: not enabled, 1: enabled
|
||||||
chunk_id: string;
|
chunk_id: string;
|
||||||
content_with_weight: string;
|
content_with_weight: string;
|
||||||
doc_id: string;
|
doc_id: string;
|
||||||
doc_name: string;
|
doc_name: string;
|
||||||
|
doc_type_kwd?: ChunkDocType;
|
||||||
image_id: string;
|
image_id: string;
|
||||||
important_kwd?: string[];
|
important_kwd?: string[];
|
||||||
question_kwd?: string[]; // keywords
|
question_kwd?: string[]; // keywords
|
||||||
|
|||||||
@ -604,6 +604,12 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
'The document being parsed cannot be deleted',
|
'The document being parsed cannot be deleted',
|
||||||
},
|
},
|
||||||
chunk: {
|
chunk: {
|
||||||
|
type: 'Type',
|
||||||
|
docType: {
|
||||||
|
image: 'Image',
|
||||||
|
table: 'Table',
|
||||||
|
text: 'Text',
|
||||||
|
},
|
||||||
chunk: 'Chunk',
|
chunk: 'Chunk',
|
||||||
bulk: 'Bulk',
|
bulk: 'Bulk',
|
||||||
selectAll: 'Select all',
|
selectAll: 'Select all',
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.imagePreview {
|
.imagePreview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
max-width: 50vw;
|
max-width: 50vw;
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
|||||||
@ -2,17 +2,19 @@ import Image from '@/components/image';
|
|||||||
import { useTheme } from '@/components/theme-provider';
|
import { useTheme } from '@/components/theme-provider';
|
||||||
import { Card } from '@/components/ui/card';
|
import { Card } from '@/components/ui/card';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from '@/components/ui/popover';
|
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@/components/ui/tooltip';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
import { CheckedState } from '@radix-ui/react-checkbox';
|
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { ChunkTextMode } from '../../constant';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ const ChunkCard = ({
|
|||||||
textMode,
|
textMode,
|
||||||
t: imageCacheKey,
|
t: imageCacheKey,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const available = Number(item.available_int);
|
const available = Number(item.available_int);
|
||||||
const [enabled, setEnabled] = useState(false);
|
const [enabled, setEnabled] = useState(false);
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
@ -63,51 +66,59 @@ const ChunkCard = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEnabled(available === 1);
|
setEnabled(available === 1);
|
||||||
}, [available]);
|
}, [available]);
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={classNames(styles.chunkCard, {
|
className={classNames('relative flex-none', styles.chunkCard, {
|
||||||
[`${theme === 'dark' ? styles.cardSelectedDark : styles.cardSelected}`]:
|
[`${theme === 'dark' ? styles.cardSelectedDark : styles.cardSelected}`]:
|
||||||
selected,
|
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">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<Checkbox onCheckedChange={handleCheck} checked={checked}></Checkbox>
|
<Checkbox onCheckedChange={handleCheck} checked={checked}></Checkbox>
|
||||||
|
|
||||||
|
{/* Using <Tooltip> instead of <Popover> to avoid flickering when hovering over the image */}
|
||||||
{item.image_id && (
|
{item.image_id && (
|
||||||
<Popover open={open}>
|
<Tooltip>
|
||||||
<PopoverTrigger
|
<TooltipTrigger>
|
||||||
asChild
|
<Image
|
||||||
onMouseEnter={() => setOpen(true)}
|
t={imageCacheKey}
|
||||||
onMouseLeave={() => setOpen(false)}
|
id={item.image_id}
|
||||||
>
|
className={styles.image}
|
||||||
<div>
|
/>
|
||||||
<Image
|
</TooltipTrigger>
|
||||||
t={imageCacheKey}
|
<TooltipContent
|
||||||
id={item.image_id}
|
|
||||||
className={styles.image}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent
|
|
||||||
className="p-0"
|
className="p-0"
|
||||||
align={'start'}
|
align={'start'}
|
||||||
side={'right'}
|
side={'right'}
|
||||||
sideOffset={-20}
|
sideOffset={-20}
|
||||||
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<div>
|
<Image
|
||||||
<Image
|
t={imageCacheKey}
|
||||||
t={imageCacheKey}
|
id={item.image_id}
|
||||||
id={item.image_id}
|
className={styles.imagePreview}
|
||||||
className={styles.imagePreview}
|
/>
|
||||||
></Image>
|
</TooltipContent>
|
||||||
</div>
|
</Tooltip>
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<section
|
<section
|
||||||
onDoubleClick={handleContentDoubleClick}
|
onDoubleClick={handleContentDoubleClick}
|
||||||
onClick={handleContentClick}
|
onClick={handleContentClick}
|
||||||
className={styles.content}
|
className={cn(styles.content, 'mt-2')}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
@ -118,7 +129,8 @@ const ChunkCard = ({
|
|||||||
})}
|
})}
|
||||||
></div>
|
></div>
|
||||||
</section>
|
</section>
|
||||||
<div>
|
|
||||||
|
<div className="mt-2">
|
||||||
<Switch
|
<Switch
|
||||||
checked={enabled}
|
checked={enabled}
|
||||||
onCheckedChange={onChange}
|
onCheckedChange={onChange}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
HoverCardContent,
|
HoverCardContent,
|
||||||
HoverCardTrigger,
|
HoverCardTrigger,
|
||||||
} from '@/components/ui/hover-card';
|
} from '@/components/ui/hover-card';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
import { Modal } from '@/components/ui/modal/modal';
|
import { Modal } from '@/components/ui/modal/modal';
|
||||||
import Space from '@/components/ui/space';
|
import Space from '@/components/ui/space';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
@ -76,6 +77,7 @@ const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
|
|||||||
const { removeChunk } = useDeleteChunkByIds();
|
const { removeChunk } = useDeleteChunkByIds();
|
||||||
const { data } = useFetchChunk(chunkId);
|
const { data } = useFetchChunk(chunkId);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const isEditMode = !!chunkId;
|
||||||
|
|
||||||
const isTagParser = parserId === 'tag';
|
const isTagParser = parserId === 'tag';
|
||||||
const onSubmit = useCallback(
|
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
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="image"
|
name="image"
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export default (props: ICheckboxSetProps) => {
|
|||||||
}, [selectedChunkIds]);
|
}, [selectedChunkIds]);
|
||||||
|
|
||||||
return (
|
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">
|
<div className="flex items-center gap-3 cursor-pointer text-muted-foreground hover:text-text-primary">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="all_chunks_checkbox"
|
id="all_chunks_checkbox"
|
||||||
|
|||||||
Reference in New Issue
Block a user