mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-10 11:26:52 +08:00
Mermaid front end rendering (#1166)
Co-authored-by: luowei <glpat-EjySCyNjWiLqAED-YmwM>
This commit is contained in:
100
web/app/components/app/chat/mermaid/index.tsx
Normal file
100
web/app/components/app/chat/mermaid/index.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import mermaid from 'mermaid'
|
||||
import { t } from 'i18next'
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
let mermaidAPI: any
|
||||
mermaidAPI = null
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'default',
|
||||
flowchart: {
|
||||
htmlLabels: true,
|
||||
useMaxWidth: true,
|
||||
},
|
||||
})
|
||||
mermaidAPI = mermaid.mermaidAPI
|
||||
}
|
||||
|
||||
const style = {
|
||||
minWidth: '480px',
|
||||
height: 'auto',
|
||||
overflow: 'auto',
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Flowchart = React.forwardRef((props: {
|
||||
PrimitiveCode: string
|
||||
}, ref) => {
|
||||
const [svgCode, setSvgCode] = useState(null)
|
||||
const chartId = useRef(`flowchart_${CryptoJS.MD5(props.PrimitiveCode).toString()}`)
|
||||
const [isRender, setIsRender] = useState(true)
|
||||
|
||||
const renderFlowchart = async (PrimitiveCode: string) => {
|
||||
try {
|
||||
const cachedSvg: any = localStorage.getItem(chartId.current)
|
||||
if (cachedSvg) {
|
||||
setSvgCode(cachedSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && mermaidAPI) {
|
||||
const svgGraph = await mermaidAPI.render(chartId.current, PrimitiveCode)
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
const base64Svg: any = await svgToBase64(svgGraph.svg)
|
||||
localStorage.setItem(chartId.current, base64Svg)
|
||||
setSvgCode(base64Svg)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
localStorage.clear()
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
console.error(error.toString())
|
||||
}
|
||||
}
|
||||
|
||||
const svgToBase64 = (svgGraph: string) => {
|
||||
const svgBytes = new TextEncoder().encode(svgGraph)
|
||||
const blob = new Blob([svgBytes], { type: 'image/svg+xml;charset=utf-8' })
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onloadend = () => resolve(reader.result)
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
}
|
||||
|
||||
const handleReRender = () => {
|
||||
setIsRender(false)
|
||||
setSvgCode(null)
|
||||
localStorage.removeItem(chartId.current)
|
||||
setTimeout(() => {
|
||||
setIsRender(true)
|
||||
renderFlowchart(props.PrimitiveCode)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setIsRender(false)
|
||||
setTimeout(() => {
|
||||
setIsRender(true)
|
||||
renderFlowchart(props.PrimitiveCode)
|
||||
}, 100)
|
||||
}, [props.PrimitiveCode])
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
<div ref={ref}>
|
||||
{
|
||||
isRender && <div id={chartId.current} className="mermaid" style={style}>{svgCode && (<img src={svgCode} style={{ width: '100%', height: 'auto' }} alt="Mermaid chart" />)}</div>
|
||||
}
|
||||
<button onClick={handleReRender}>{t('appApi.merMaind.rerender')}</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default Flowchart
|
||||
23
web/app/components/app/chat/svg/index.tsx
Normal file
23
web/app/components/app/chat/svg/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from 'react'
|
||||
import s from './style.module.css'
|
||||
|
||||
type ISVGBtnProps = {
|
||||
isSVG: boolean
|
||||
setIsSVG: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
const SVGBtn = ({
|
||||
isSVG,
|
||||
setIsSVG,
|
||||
}: ISVGBtnProps) => {
|
||||
return (
|
||||
<div
|
||||
className={'box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer'}
|
||||
onClick={() => { setIsSVG(prevIsSVG => !prevIsSVG) }}
|
||||
>
|
||||
<div className={`w-6 h-6 rounded-md hover:bg-gray-50 ${s.svgIcon} ${isSVG ? s.svgIconed : ''}`}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SVGBtn
|
||||
11
web/app/components/app/chat/svg/style.module.css
Normal file
11
web/app/components/app/chat/svg/style.module.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.svgIcon {
|
||||
background-image: url(~@/app/components/develop/secret-key/assets/svg.svg);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.svgIconed {
|
||||
background-image: url(~@/app/components/develop/secret-key/assets/svged.svg);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@@ -8,18 +8,28 @@ import SyntaxHighlighter from 'react-syntax-highlighter'
|
||||
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
|
||||
import type { RefObject } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import cn from 'classnames'
|
||||
import CopyBtn from '@/app/components/app/chat/copy-btn'
|
||||
import SVGBtn from '@/app/components/app/chat/svg'
|
||||
import Flowchart from '@/app/components/app/chat/mermaid'
|
||||
import s from '@/app/components/app/chat/style.module.css'
|
||||
|
||||
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
||||
const capitalizationLanguageNameMap: Record<string, string> = {
|
||||
sql: 'SQL',
|
||||
javascript: 'JavaScript',
|
||||
java: 'Java',
|
||||
typescript: 'TypeScript',
|
||||
vbscript: 'VBScript',
|
||||
css: 'CSS',
|
||||
html: 'HTML',
|
||||
xml: 'XML',
|
||||
php: 'PHP',
|
||||
python: 'Python',
|
||||
yaml: 'Yaml',
|
||||
mermaid: 'Mermaid',
|
||||
markdown: 'MarkDown',
|
||||
makefile: 'MakeFile',
|
||||
}
|
||||
const getCorrectCapitalizationLanguageName = (language: string) => {
|
||||
if (!language)
|
||||
@@ -73,6 +83,7 @@ const useLazyLoad = (ref: RefObject<Element>): boolean => {
|
||||
|
||||
export function Markdown(props: { content: string }) {
|
||||
const [isCopied, setIsCopied] = useState(false)
|
||||
const [isSVG, setIsSVG] = useState(false)
|
||||
return (
|
||||
<div className="markdown-body">
|
||||
<ReactMarkdown
|
||||
@@ -95,24 +106,35 @@ export function Markdown(props: { content: string }) {
|
||||
}}
|
||||
>
|
||||
<div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
|
||||
<CopyBtn
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
isPlain
|
||||
/>
|
||||
<div style={{ display: 'flex' }}>
|
||||
{language === 'mermaid'
|
||||
&& <SVGBtn
|
||||
isSVG={isSVG}
|
||||
setIsSVG={setIsSVG}
|
||||
/>
|
||||
}
|
||||
<CopyBtn
|
||||
className={cn(s.copyBtn, 'mr-1')}
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
isPlain
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...props}
|
||||
style={atelierHeathLight}
|
||||
customStyle={{
|
||||
paddingLeft: 12,
|
||||
backgroundColor: '#fff',
|
||||
}}
|
||||
language={match[1]}
|
||||
showLineNumbers
|
||||
PreTag="div"
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
{ (language === 'mermaid' && isSVG)
|
||||
? (<Flowchart PrimitiveCode={String(children).replace(/\n$/, '')} />)
|
||||
: (<SyntaxHighlighter
|
||||
{...props}
|
||||
style={atelierHeathLight}
|
||||
customStyle={{
|
||||
paddingLeft: 12,
|
||||
backgroundColor: '#fff',
|
||||
}}
|
||||
language={match[1]}
|
||||
showLineNumbers
|
||||
PreTag="div"
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>)}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
|
||||
1
web/app/components/develop/secret-key/assets/svg.svg
Normal file
1
web/app/components/develop/secret-key/assets/svg.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694177685288" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4415" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M192 384h640a42.666667 42.666667 0 0 1 42.666667 42.666667v362.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H192v106.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h725.333334a21.333333 21.333333 0 0 0 21.333333-21.333333V308.821333L949.909333 298.666667h-126.528A98.048 98.048 0 0 1 725.333333 200.618667V72.661333L716.714667 64H213.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v298.666667zM128 832H42.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V426.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h85.333333V85.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h530.026667L1024 282.453333V938.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-106.666667z m61.376-364.885333c-27.434667 0-49.898667 6.528-67.712 19.968-19.221333 13.824-28.501333 33.024-28.501333 57.216s9.621333 42.624 29.226666 55.296c7.466667 4.608 27.093333 12.288 58.432 23.04 28.138667 9.216 44.522667 15.36 49.514667 18.048 15.68 8.448 23.872 19.968 23.872 34.56 0 11.52-5.696 20.352-16.384 27.264-10.688 6.528-25.664 9.984-44.181333 9.984-21.013333 0-36.352-4.224-46.314667-11.904-11.050667-8.832-17.813333-23.808-20.672-44.544H85.333333c1.792 34.944 13.546667 60.288 34.922667 76.416 17.450667 13.056 42.026667 19.584 73.386667 19.584 32.426667 0 57.706667-7.296 75.52-21.12 17.813333-14.208 26.730667-33.792 26.730666-58.368 0-25.344-11.050667-44.928-33.130666-59.136-9.984-6.144-32.064-15.36-66.624-26.88-23.509333-8.064-38.122667-13.824-43.477334-16.896-12.096-6.912-17.813333-16.512-17.813333-28.032 0-13.056 4.992-22.656 15.68-28.416 8.554667-4.992 20.672-7.296 36.693333-7.296 18.538667 0 32.789333 3.456 42.048 11.136 9.258667 7.296 16.021333 19.584 19.584 36.48h41.344c-2.496-29.952-12.821333-52.224-30.656-66.432-16.725333-13.44-40.256-19.968-70.186666-19.968z m118.976 5.376L398.848 746.666667h50.24l90.496-274.176h-45.226667l-69.845333 223.488h-1.066667l-69.845333-223.488h-45.226667z m368.405333-5.376c-37.76 0-67.690667 13.824-89.792 42.24-21.013333 26.496-31.36 60.288-31.36 101.376 0 40.704 10.346667 74.112 31.36 99.84 22.442667 27.648 53.802667 41.472 94.421334 41.472 22.805333 0 43.093333-3.072 61.632-9.216A143.829333 143.829333 0 0 0 789.333333 716.714667V600.746667h-109.013333v38.4h67.328v56.448c-8.533333 5.376-17.450667 9.6-27.434667 12.672a123.285333 123.285333 0 0 1-34.197333 4.608c-30.997333 0-53.802667-9.216-68.416-27.648-13.525333-17.28-20.309333-42.24-20.309333-74.496 0-33.792 7.488-59.52 22.826666-77.952 13.866667-17.664 32.768-26.112 56.64-26.112 19.221333 0 34.901333 4.224 46.656 13.056 11.413333 8.832 19.242667 21.888 22.826667 39.552h42.026667c-4.629333-30.72-16.042667-53.376-34.197334-68.736-18.88-15.744-44.544-23.424-77.312-23.424z" fill="#8a8a8a" p-id="4416"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
1
web/app/components/develop/secret-key/assets/svged.svg
Normal file
1
web/app/components/develop/secret-key/assets/svged.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1694177378730" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4206" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M192 384h640a42.666667 42.666667 0 0 1 42.666667 42.666667v362.666666a42.666667 42.666667 0 0 1-42.666667 42.666667H192v106.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h725.333334a21.333333 21.333333 0 0 0 21.333333-21.333333V308.821333L949.909333 298.666667h-126.528A98.048 98.048 0 0 1 725.333333 200.618667V72.661333L716.714667 64H213.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v298.666667zM128 832H42.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V426.666667a42.666667 42.666667 0 0 1 42.666667-42.666667h85.333333V85.333333a85.333333 85.333333 0 0 1 85.333333-85.333333h530.026667L1024 282.453333V938.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-106.666667z m61.376-364.885333c-27.434667 0-49.898667 6.528-67.712 19.968-19.221333 13.824-28.501333 33.024-28.501333 57.216s9.621333 42.624 29.226666 55.296c7.466667 4.608 27.093333 12.288 58.432 23.04 28.138667 9.216 44.522667 15.36 49.514667 18.048 15.68 8.448 23.872 19.968 23.872 34.56 0 11.52-5.696 20.352-16.384 27.264-10.688 6.528-25.664 9.984-44.181333 9.984-21.013333 0-36.352-4.224-46.314667-11.904-11.050667-8.832-17.813333-23.808-20.672-44.544H85.333333c1.792 34.944 13.546667 60.288 34.922667 76.416 17.450667 13.056 42.026667 19.584 73.386667 19.584 32.426667 0 57.706667-7.296 75.52-21.12 17.813333-14.208 26.730667-33.792 26.730666-58.368 0-25.344-11.050667-44.928-33.130666-59.136-9.984-6.144-32.064-15.36-66.624-26.88-23.509333-8.064-38.122667-13.824-43.477334-16.896-12.096-6.912-17.813333-16.512-17.813333-28.032 0-13.056 4.992-22.656 15.68-28.416 8.554667-4.992 20.672-7.296 36.693333-7.296 18.538667 0 32.789333 3.456 42.048 11.136 9.258667 7.296 16.021333 19.584 19.584 36.48h41.344c-2.496-29.952-12.821333-52.224-30.656-66.432-16.725333-13.44-40.256-19.968-70.186666-19.968z m118.976 5.376L398.848 746.666667h50.24l90.496-274.176h-45.226667l-69.845333 223.488h-1.066667l-69.845333-223.488h-45.226667z m368.405333-5.376c-37.76 0-67.690667 13.824-89.792 42.24-21.013333 26.496-31.36 60.288-31.36 101.376 0 40.704 10.346667 74.112 31.36 99.84 22.442667 27.648 53.802667 41.472 94.421334 41.472 22.805333 0 43.093333-3.072 61.632-9.216A143.829333 143.829333 0 0 0 789.333333 716.714667V600.746667h-109.013333v38.4h67.328v56.448c-8.533333 5.376-17.450667 9.6-27.434667 12.672a123.285333 123.285333 0 0 1-34.197333 4.608c-30.997333 0-53.802667-9.216-68.416-27.648-13.525333-17.28-20.309333-42.24-20.309333-74.496 0-33.792 7.488-59.52 22.826666-77.952 13.866667-17.664 32.768-26.112 56.64-26.112 19.221333 0 34.901333 4.224 46.656 13.056 11.413333 8.832 19.242667 21.888 22.826667 39.552h42.026667c-4.629333-30.72-16.042667-53.376-34.197334-68.736-18.88-15.744-44.544-23.424-77.312-23.424z" fill="#1A8EF7" p-id="4207"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
Reference in New Issue
Block a user