import React, { useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import 'katex/dist/katex.min.css'; import RemarkMath from 'remark-math'; import RemarkBreaks from 'remark-breaks'; import RehypeKatex from 'rehype-katex'; import RemarkGfm from 'remark-gfm'; import styles from './index.module.scss'; import dynamic from 'next/dynamic'; import { Link, Button } from '@chakra-ui/react'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { useTranslation } from 'next-i18next'; import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants'; const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false }); const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false }); const MdImage = dynamic(() => import('./img/Image'), { ssr: false }); const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false }); const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false }); const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false }); export enum CodeClassName { guide = 'guide', questionGuide = 'questionGuide', mermaid = 'mermaid', echarts = 'echarts', quote = 'quote', files = 'files' } const Markdown = ({ source = '', showAnimation = false }: { source?: string; showAnimation?: boolean; }) => { const components = useMemo( () => ({ img: Image, pre: 'div', p: (pProps: any) =>

, code: Code, a: A }), [] ); const formatSource = source // .replace(/\\n/g, '\n') .replace(/(http[s]?:\/\/[^\s,。]+)([。,])/g, '$1 $2') .replace(/\n*(\[QUOTE SIGN\]\(.*\))/g, '$1'); return ( {formatSource} ); }; export default React.memo(Markdown); const Code = React.memo(function Code(e: any) { const { inline, className, children } = e; const match = /language-(\w+)/.exec(className || ''); const codeType = match?.[1]; const strChildren = String(children); const Component = useMemo(() => { if (codeType === CodeClassName.mermaid) { return ; } if (codeType === CodeClassName.guide) { return ; } if (codeType === CodeClassName.questionGuide) { return ; } if (codeType === CodeClassName.echarts) { return ; } return ( {children} ); }, [codeType, className, inline, match, children, strChildren]); return Component; }); const Image = React.memo(function Image({ src }: { src?: string }) { return ; }); const A = React.memo(function A({ children, ...props }: any) { const { t } = useTranslation(); // empty href link if (!props.href && typeof children?.[0] === 'string') { const text = useMemo(() => String(children), [children]); return ( ); } // quote link(未使用) if (children?.length === 1 && typeof children?.[0] === 'string') { const text = String(children); if (text === MARKDOWN_QUOTE_SIGN && props.href) { return ( getCollectionSourceAndOpen(props.href)} /> ); } } return {children}; });