import { AutoChart, BackEndChartType, getChartType } from '@/components/chart'; import { formatSql } from '@/utils'; import { LinkOutlined, ReadOutlined, SyncOutlined } from '@ant-design/icons'; import { Datum } from '@antv/ava'; import { GPTVis, withDefaultChartCode } from '@antv/gpt-vis'; import { Image, Table, Tabs, TabsProps, Tag } from 'antd'; import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import ReferencesContent from './ReferencesContent'; import VisAppLink from './VisAppLink'; import VisChatLink from './VisChatLink'; import VisResponse from './VisResponse'; import AgentMessages from './agent-messages'; import AgentPlans from './agent-plans'; import { CodePreview } from './code-preview'; import VisChart from './vis-chart'; import VisCode from './vis-code'; import VisConvertError from './vis-convert-error'; import VisDashboard from './vis-dashboard'; import VisPlugin from './vis-plugin'; type MarkdownComponent = Parameters['0']['components']; const customeTags: (keyof JSX.IntrinsicElements)[] = ['custom-view', 'chart-view', 'references', 'summary']; function matchCustomeTagValues(context: string) { const matchValues = customeTags.reduce((acc, tagName) => { // eslint-disable-next-line no-useless-escape const tagReg = new RegExp(`<${tagName}[^>]*\/?>`, 'gi'); context = context.replace(tagReg, matchVal => { acc.push(matchVal); return ''; }); return acc; }, []); return { context, matchValues }; } const codeComponents = { /** * @description * Custom code block rendering, which can be used to render custom components in the code block. * Is it defined in gpt-vis, and the default rendering contains `vis-chart`. */ code: withDefaultChartCode({ languageRenderers: { 'agent-plans': ({ className, children }) => { const content = String(children); /** * @description * In some cases, tags are nested within code syntax, * so it is necessary to extract the tags present in the code block and render them separately. */ const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'agent-messages': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-convert-error': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-dashboard': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-db-chart': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-plugin': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-code': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-app-link': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, 'vis-api-response': ({ className, children }) => { const content = String(children); const lang = className?.replace('language-', '') || 'javascript'; try { const data = JSON.parse(content) as Parameters[0]['data']; return ; } catch { return ; } }, }, defaultRenderer({ node, className, children, style, ...props }) { const content = String(children); const lang = className?.replace('language-', '') || ''; const { context, matchValues } = matchCustomeTagValues(content); return ( <> {lang ? ( ) : ( {children} )} {matchValues.join('\n')} ); }, }), }; const basicComponents: MarkdownComponent = { ...codeComponents, ul({ children }) { return
    {children}
; }, ol({ children }) { return
    {children}
; }, li({ children, ordered }) { return (
  • {children}
  • ); }, table({ children }) { return ( {children}
    ); }, thead({ children }) { return {children}; }, th({ children }) { return {children}; }, td({ children }) { return {children}; }, h1({ children }) { return

    {children}

    ; }, h2({ children }) { return

    {children}

    ; }, h3({ children }) { return

    {children}

    ; }, h4({ children }) { return

    {children}

    ; }, a({ children, href }) { return ( ); }, img({ src, alt }) { return (
    {alt}} color='processing'> Image Loading... } fallback='/pictures/fallback.png' />
    ); }, blockquote({ children }) { return (
    {children}
    ); }, button({ children, className, ...restProps }) { if (className === 'chat-link') { const msg = (restProps as any)?.['data-msg']; return {children}; } return ( ); }, }; const returnSqlVal = (val: string) => { const punctuationMap: any = { ',': ',', '。': '.', '?': '?', '!': '!', ':': ':', ';': ';', '“': '"', '”': '"', '‘': "'", '’': "'", '(': '(', ')': ')', '【': '[', '】': ']', '《': '<', '》': '>', '—': '-', '、': ',', '…': '...', }; const regex = new RegExp(Object.keys(punctuationMap).join('|'), 'g'); return val.replace(regex, match => punctuationMap[match]); }; const extraComponents: MarkdownComponent = { 'chart-view': function ({ content, children }) { let data: { data: Datum[]; type: BackEndChartType; sql: string; }; try { data = JSON.parse(content as string); } catch (e) { console.log(e, content); data = { type: 'response_table', sql: '', data: [], }; } const columns = data?.data?.[0] ? Object.keys(data?.data?.[0])?.map(item => { return { title: item, dataIndex: item, key: item, }; }) : []; const ChartItem = { key: 'chart', label: 'Chart', children: , }; const SqlItem = { key: 'sql', label: 'SQL', children: , }; const DataItem = { key: 'data', label: 'Data', children: , }; const TabItems: TabsProps['items'] = data?.type === 'response_table' ? [DataItem, SqlItem] : [ChartItem, SqlItem, DataItem]; return (
    {children}
    ); }, references: function ({ children }) { if (children) { try { const referenceData = JSON.parse(children as string); const references = referenceData.references; return ; } catch { return null; } } }, summary: function ({ children }) { return (

    Document Summary

    {children}
    ); }, }; const markdownComponents = { ...basicComponents, ...extraComponents, }; export default markdownComponents;