mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-08 03:25:06 +08:00
Feat: Images referenced in chat messages are displayed as a carousel at the bottom of the message. #12076 (#12207)
### What problem does this PR solve? Feat: Images referenced in chat messages are displayed as a carousel at the bottom of the message. #12076 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Docagg } from '@/interfaces/database/chat';
|
||||
import { middleEllipsis } from '@/utils/common-util';
|
||||
import FileIcon from '../file-icon';
|
||||
import NewDocumentLink from '../new-document-link';
|
||||
|
||||
@ -17,7 +18,7 @@ export function ReferenceDocumentList({ list }: { list: Docagg[] }) {
|
||||
link={item.url}
|
||||
className="text-text-sub-title-invert"
|
||||
>
|
||||
{item.doc_name}
|
||||
{middleEllipsis(item.doc_name)}
|
||||
</NewDocumentLink>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
import Image from '@/components/image';
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from '@/components/ui/carousel';
|
||||
import { IReferenceChunk } from '@/interfaces/database/chat';
|
||||
import { useResponsive } from 'ahooks';
|
||||
import { useMemo } from 'react';
|
||||
import { extractNumbersFromMessageContent } from './utils';
|
||||
|
||||
type IProps = {
|
||||
referenceChunks: IReferenceChunk[];
|
||||
messageContent: string;
|
||||
};
|
||||
|
||||
function ImageCarousel({
|
||||
imageIds,
|
||||
hideButtons,
|
||||
}: {
|
||||
hideButtons?: boolean;
|
||||
imageIds: string[];
|
||||
}) {
|
||||
return (
|
||||
<Carousel
|
||||
className="w-full"
|
||||
opts={{
|
||||
align: 'start',
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{imageIds.map((imageId, index) => (
|
||||
<CarouselItem key={index} className="md:basis-1/2 2xl:basis-1/6">
|
||||
<Image
|
||||
id={imageId}
|
||||
className="h-40 w-full"
|
||||
label={`Fig. ${(index + 1).toString()}`}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
{!hideButtons && (
|
||||
<>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</>
|
||||
)}
|
||||
</Carousel>
|
||||
);
|
||||
}
|
||||
|
||||
export function ReferenceImageList({
|
||||
referenceChunks,
|
||||
messageContent,
|
||||
}: IProps) {
|
||||
const imageIds = useMemo(() => {
|
||||
return referenceChunks
|
||||
.filter((_, idx) =>
|
||||
extractNumbersFromMessageContent(messageContent).includes(idx),
|
||||
)
|
||||
.map((chunk) => chunk.image_id);
|
||||
}, [messageContent, referenceChunks]);
|
||||
const imageCount = imageIds.length;
|
||||
|
||||
const responsive = useResponsive();
|
||||
|
||||
const { isMd, is2xl } = useMemo(() => {
|
||||
return {
|
||||
isMd: responsive.md,
|
||||
is2xl: responsive['2xl'],
|
||||
};
|
||||
}, [responsive]);
|
||||
|
||||
// If there are few images, hide the previous/next buttons.
|
||||
const hideButtons = is2xl ? imageCount <= 6 : isMd ? imageCount <= 2 : false;
|
||||
|
||||
if (imageCount === 0) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return <ImageCarousel imageIds={imageIds} hideButtons={hideButtons} />;
|
||||
}
|
||||
16
web/src/components/next-message-item/utils.ts
Normal file
16
web/src/components/next-message-item/utils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { currentReg } from '@/utils/chat';
|
||||
|
||||
export const extractNumbersFromMessageContent = (content: string) => {
|
||||
const matches = content.match(currentReg);
|
||||
if (matches) {
|
||||
const list = matches
|
||||
.map((match) => {
|
||||
const numMatch = match.match(/\[ID:(\d+)\]/);
|
||||
return numMatch ? parseInt(numMatch[1], 10) : null;
|
||||
})
|
||||
.filter((num) => num !== null) as number[];
|
||||
|
||||
return list;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
Reference in New Issue
Block a user