Unverified Commit 67bed54f authored by charli117's avatar charli117 Committed by GitHub

Mermaid front end rendering (#1166)

Co-authored-by: luowei <glpat-EjySCyNjWiLqAED-YmwM>
parent 562a5712
......@@ -210,6 +210,44 @@ demo_model_templates = {
}),
user_input_form=None
)
},
{
'name': 'AI Graph Generator',
'icon': '',
'icon_background': '',
'description': 'According to the user\'s stated requirements, mermaid code blocks are generated by AI, and the code blocks are rendered into corresponding SVG vector drawings.',
'mode': 'chat',
'model_config': AppModelConfig(
provider='openai',
model_id='gpt-3.5-turbo',
configs={
'introduction': 'Warm reminder: Click 👍 for correct reply and 👎 for inaccurate reply, which will help me further improve myself and greatly improve the accuracy of reply to similar questions. Hello, please tell me about your image generation needs: ',
'prompt_template': "You will play as a mermaid graphics generator, generating code blocks that conform to mermaid format requirements based on user scenario descriptions. \n\n[Note]\n\n- Output mermaid code blocks only, no other explanation. \nLet\'s think step by step.\n",
'prompt_variables': [],
'completion_params': {
'max_token': 300,
'temperature': 0.8,
'top_p': 0.9,
'presence_penalty': 0.1,
'frequency_penalty': 0.1,
}
},
opening_statement='Warm reminder: Click 👍 for correct reply and 👎 for inaccurate reply, which will help me further improve myself and greatly improve the accuracy of reply to similar questions. Hello, please tell me about your image generation needs: ',
suggested_questions=None,
pre_prompt="You will play as a mermaid graphics generator, generating code blocks that conform to mermaid format requirements based on user scenario descriptions. \n\n[Note]\n\n- Output mermaid code blocks only, no other explanation. \nLet\'s think step by step.\n",
model=json.dumps({
"provider": "openai",
"name": "gpt-3.5-turbo",
"completion_params": {
"max_tokens": 300,
"temperature": 0.8,
"top_p": 0.9,
"presence_penalty": 0.1,
"frequency_penalty": 0.1
}
}),
user_input_form=None
)
}
],
......@@ -328,6 +366,44 @@ demo_model_templates = {
}),
user_input_form=None
)
},
{
'name': 'AI 图形生成器',
'icon': '',
'icon_background': '',
'description': '根据用户陈述需求利用AI生成mermaid代码块,将代码块渲染成对应SVG矢量图。',
'mode': 'chat',
'model_config': AppModelConfig(
provider='openai',
model_id='gpt-3.5-turbo',
configs={
'introduction': ' 温馨提醒:对正确的回复点击 👍赞同、不准确的回复点击 👎反对,将有助我进一步自我完善,大幅提高同类型问题回复的准确性。\n你好,请告诉我您的图像生成需求:',
'prompt_template': "你将扮演mermaid图形生成器,根据用户场景描述生成符合mermaid格式要求的代码块。\n\n[注意事项]\n\n- 仅输出mermaid代码块,不做其他解释。\nLet\'s think step by step.\n",
'prompt_variables': [],
'completion_params': {
'max_token': 1024,
'temperature': 0.8,
'top_p': 0.9,
'presence_penalty': 0.1,
'frequency_penalty': 0.1,
}
},
opening_statement=' 温馨提醒:对正确的回复点击 👍赞同、不准确的回复点击 👎反对,将有助我进一步自我完善,大幅提高同类型问题回复的准确性。\n你好,请告诉我您的图像生成需求:',
suggested_questions=None,
pre_prompt="你将扮演mermaid图形生成器,根据用户场景描述生成符合mermaid格式要求的代码块。\n\n[注意事项]\n\n- 仅输出mermaid代码块,不做其他解释。\nLet\'s think step by step.\n",
model=json.dumps({
"provider": "openai",
"name": "gpt-3.5-turbo",
"completion_params": {
"max_tokens": 1024,
"temperature": 0.8,
"top_p": 0.9,
"presence_penalty": 0.1,
"frequency_penalty": 0.1
}
}),
user_input_form=None
)
}
],
}
......@@ -33,7 +33,6 @@ class UniversalChatApi(UniversalChatResource):
args = parser.parse_args()
app_model_config = app_model.app_model_config
app_model_config
# update app model config
args['model_config'] = app_model_config.to_dict()
......
......@@ -139,7 +139,7 @@ const NewAppDialog = ({ show, onSuccess, onClose }: NewAppDialogProps) => {
</div>
{isWithTemplate
? (
<ul className='grid grid-cols-2 gap-4'>
<ul className='grid grid-cols-3 gap-4'>
{templates?.data?.map((template, index) => (
<li
key={index}
......
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
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
.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,12 +106,23 @@ export function Markdown(props: { content: string }) {
}}
>
<div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
<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>
<SyntaxHighlighter
</div>
{ (language === 'mermaid' && isSVG)
? (<Flowchart PrimitiveCode={String(children).replace(/\n$/, '')} />)
: (<SyntaxHighlighter
{...props}
style={atelierHeathLight}
customStyle={{
......@@ -112,7 +134,7 @@ export function Markdown(props: { content: string }) {
PreTag="div"
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
</SyntaxHighlighter>)}
</div>
)
: (
......
<?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>
\ No newline at end of file
<?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>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -44,6 +44,7 @@
"katex": "^0.16.7",
"lamejs": "1.2.0",
"lodash-es": "^4.17.21",
"mermaid": "10.4.0",
"negotiator": "^0.6.3",
"next": "13.3.1",
"qs": "^6.11.1",
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment