完整实现方案Flask 3.0 mistune 2.0 mermaid 10.9 渲染 Markdown 中的 mermaid 图表以下是基于 Flask 3.0、mistune 2.0 和 mermaid 10.9 的完整可运行方案逻辑参考server.js支持上传.md/.txt文件.txt需符合 CSV 格式自动转换为 mermaid 流程图Markdown 语法渲染含代码块、链接、排版等mermaid 图表渲染支持横向/纵向流程图完整的错误处理和页面交互一、项目结构mermaid-markdown-render/ ├── app.py # Flask 后端核心代码 ├── static/ │ ├── index.html # 前端上传页面 │ └── mermaid.min.js # mermaid 10.9 核心库需手动下载 ├── test1.md # 测试用 Markdown 文件含 Mermaid └── test1.txt # 测试用 CSV 格式文本文件二、核心依赖安装pipinstallflask3.0.3mistune2.0.5 python-multipart0.0.6三、文件内容实现1. 后端核心app.py# -*- coding: utf-8 -*-fromflaskimportFlask,request,send_fileimportmistuneimportosfromdatetimeimportdatetimefromwerkzeug.utilsimportsecure_filename# 修复核心显式配置静态目录 # static_folder指定静态文件存放目录相对路径# static_url_path前端访问静态文件的 URL 路径默认 /static可自定义appFlask(__name__,static_folderstatic,# 显式指定静态文件夹为 staticstatic_url_path/static# 前端通过 /static/xxx 访问文件如 /static/mermaid.min.js)app.config[UPLOAD_FOLDER]uploadsapp.config[MAX_CONTENT_LENGTH]5*1024*1024# 5MB 限制app.config[ALLOWED_EXTENSIONS]{md,txt}# 创建上传文件夹若不存在os.makedirs(app.config[UPLOAD_FOLDER],exist_okTrue)# 配置 mistune 渲染器支持 MermaidclassMermaidRenderer(mistune.HTMLRenderer):自定义渲染器处理 Mermaid 代码块defblock_code(self,code,langNone):# 识别 mermaid 代码块iflangandlang.lower()mermaid:returnfdiv classmermaid{code}/div# 其他代码块使用默认渲染returnsuper().block_code(code,lang)# 初始化 mistune 解析器仅保留 2.0.5 兼容的内置插件markdown_parsermistune.create_markdown(rendererMermaidRenderer(),plugins[strikethrough,# 支持 ~~删除线~~2.0.5 内置兼容footnotes,# 支持脚注2.0.5 内置兼容table,# 支持表格2.0.5 内置兼容])# 核心工具函数CSV → Mermaid 转换参考 server.jsdefvalidate_and_convert_csv_to_mermaid(file_name,content): 校验 .txt 文件CSV 格式并转换为 Mermaid 流程图 :param file_name: 文件名 :param content: 文件内容 :return: dict {valid: 布尔值, content: 转换后内容/错误信息} # 统一换行符 拆分行过滤空行normalized_contentcontent.replace(\r\n,\n).replace(\r,\n)lines[line.strip()forlineinnormalized_content.split(\n)ifline.strip()]# 校验空文件ifnotlines:return{valid:False,content:.txt 文本文件格式错误空文件}# 校验首行格式必须是 source,target,weightfirst_linelines[0]iffirst_line!source,target,weight:return{valid:False,content:.txt 文本文件格式错误首行需为 source,target,weight}# 生成 Mermaid 横向流程图graph LR可改为 graph TD 纵向mermaid_contentgraph LR\n# 处理数据行跳过首行forline_num,lineinenumerate(lines[1:],start2):parts[item.strip()foriteminline.split(,)]iflen(parts)2:# 至少需要 source 和 targetcontinuesource,targetparts[0],parts[1]weightparts[2]iflen(parts)3andparts[2]else# 节点名加前缀避免冲突显示时用原始名称source_nodefnode_{source}target_nodefnode_{target}# 权重标签有则显示无则不显示weight_labelf|{weight}|ifweightelse# 拼接 Mermaid 语法mermaid_contentf{source_node}[\{source}\] --{weight_label}{target_node}[\{target}\]\n# 包装为 Markdown 格式含标题和转换时间final_mdf#{file_name}转换为 Mermaid 关系图\n\n\fmermaid\n{mermaid_content}\n\n\n\f 转换时间{datetime.now().strftime(%Y-%m-%d %H:%M:%S)}return{valid:True,content:final_md}# 路由定义 app.route(/)defindex():首页返回文件上传页面使用静态文件路由# 修复使用 url_for 生成静态文件的绝对路径避免路径错误returnsend_file(os.path.join(app.static_folder,index.html))app.route(/upload-md,methods[POST])defupload_and_render():处理文件上传、转换、渲染try:# 1. 校验是否上传文件ifmdFilenotinrequest.files:returnrender_error(上传失败,请选择要上传的文件)filerequest.files[mdFile]filenamesecure_filename(file.filename)# 2. 校验文件名避免空文件名iffilename:returnrender_error(上传失败,文件名不能为空)# 3. 校验文件类型file_extos.path.splitext(filename)[1].lower()[1:]# 获取扩展名不含.iffile_extnotinapp.config[ALLOWED_EXTENSIONS]:returnrender_error(上传失败,仅支持 .md 或 .txt 格式的文件)# 4. 读取文件内容UTF-8 编码file_contentfile.read().decode(utf-8)render_contentfile_content# 5. 处理 .txt 文件CSV 格式转换为 Mermaidiffile_exttxt:convert_resultvalidate_and_convert_csv_to_mermaid(filename,file_content)ifnotconvert_result[valid]:returnrender_error(处理失败,convert_result[content])render_contentconvert_result[content]# 6. 渲染 Markdown含 Mermaid 代码块rendered_htmlmarkdown_parser(render_content)# 7. 读取前端模板并替换内容使用 app.static_folder 确保路径正确withopen(os.path.join(app.static_folder,index.html),r,encodingutf-8)asf:index_templatef.read()final_htmlindex_template.replace(div idmarkdown-content/div,rendered_html)returnfinal_htmlexceptExceptionase:print(f服务器异常{str(e)})returnrender_error(服务器出错,文件处理出错请稍后重试)defrender_error(title,message):生成错误页面error_htmlf !DOCTYPE html html langzh-CN head meta charsetUTF-8 title{title}/title style body {{ font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 0 20px; }} .error-box {{ border: 1px solid #dc3545; border-radius: 8px; padding: 20px; background-color: #f8d7da; }} h1 {{ color: #dc3545; }} a {{ color: #007bff; text-decoration: none; }} a:hover {{ text-decoration: underline; }} /style /head body div classerror-box h1{title}/h1 p{message}/p a href/返回上传页面/a /div /body /html returnerror_html,400if格式inmessageor上传inmessageelse500# 启动服务 if__name____main__:app.run(debugTrue,port8000)2. 前端页面static/index.html!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8titleMarkdown Mermaid 渲染工具/titlestyle*{margin:0;padding:0;box-sizing:border-box;}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;max-width:1200px;margin:0 auto;padding:20px;}.upload-container{margin:30px 0;padding:20px;border:2px dashed #ccc;border-radius:8px;}.upload-container h2{margin-bottom:15px;color:#333;}.btn-upload{padding:10px 20px;background-color:#007bff;color:white;border:none;border-radius:4px;cursor:pointer;}.btn-upload:hover{background-color:#0056b3;}#markdown-content{margin-top:30px;line-height:1.8;}#markdown-content h1, h2, h3{margin:20px 0 10px;color:#2c3e50;}#markdown-content code{background-color:#f8f9fa;padding:2px 4px;border-radius:4px;}#markdown-content pre{background-color:#f8f9fa;padding:15px;border-radius:8px;overflow-x:auto;margin:10px 0;}#markdown-content table{border-collapse:collapse;width:100%;margin:15px 0;}#markdown-content th, td{border:1px solid #ddd;padding:8px;text-align:left;}#markdown-content th{background-color:#f2f2f2;}#markdown-content blockquote{border-left:4px solid #ccc;padding:0 15px;color:#666;margin:10px 0;}.mermaid{margin:20px 0;}/* Mermaid 图表间距 *//style!-- 引入 Mermaid 10.9 核心库本地文件需手动下载 --scriptsrc/static/mermaid.min.js/scriptscript// 初始化 Mermaid配置渲染主题和样式mermaid.initialize({startOnLoad:true,// 页面加载完成后自动渲染theme:default,// 可选default/neutral/dark/forestthemeVariables:{primaryColor:#e2f0ff,lineColor:#007bff,fontSize:14px}});/script/headbodyh1 Markdown Mermaid 渲染工具/h1divclassupload-containerh2上传文件/h2formaction/upload-mdmethodpostenctypemultipart/form-datainputtypefilenamemdFileaccept.md,.txtrequiredbuttontypesubmitclassbtn-upload上传并渲染/button/formpstylemargin-top:10px;color:#666;支持格式.mdMarkdown 文件可直接包含 Mermaid 代码块、.txtCSV 格式需符合 source,target,weight 表头/p/div!-- Markdown 渲染结果将插入到这里 --dividmarkdown-content/div/body/html3. 测试文件test1.md含 Mermaid 代码块### 测试 Markdown 中的 Mermaid 图表 这是一个直接在 Markdown 中编写的 Mermaid 流程图 mermaid graph LR A[用户] -- B[上传文件] B -- C{文件类型} C --|.md| D[直接渲染 Markdown] C --|.txt| E[转换为 Mermaid] D -- F[显示结果] E -- F表格支持测试功能支持情况Markdown 渲染✅Mermaid 图表✅CSV → Mermaid✅代码块高亮✅备注本文件可直接上传测试 Mermaid 渲染功能#### 4. 测试文件test1.txtCSV 格式自动转换 txt source,target,weight 张三,李四,10000 李四,王五,9000 王五,刘大哥,8000 刘大哥,张三,5000 刘大哥,李四,3000 刘大哥,王五,2000四、关键步骤说明1. Mermaid 库下载需手动下载mermaid.min.js 10.9并放入static目录下载地址https://cdn.jsdelivr.net/npm/mermaid10.9.5/dist/mermaid.min.js直接右键保存文件到static文件夹即可2. 核心逻辑对应参考 server.jsserver.js 功能Flask 实现对应Express 静态文件目录Flask 自动识别 static 目录multer 文件上传Flask request.files secure_filenamemarkdown-it 渲染 Mermaid 插件mistune 自定义渲染器MermaidRendererCSV → Mermaid 转换函数validate_and_convert_csv_to_mermaid逻辑完全对齐错误处理自定义 render_error 函数返回错误页面端口监听app.run(port8000)3. Mermaid 渲染原理Markdown 中的 Mermaid 代码块mermaid ...被MermaidRenderer识别为div classmermaid.../div前端页面引入mermaid.min.js后mermaid.initialize()会自动扫描页面中所有classmermaid的元素将 Mermaid 语法转换为 SVG 图表并渲染到页面五、运行和测试步骤安装依赖执行pip install flask3.0.3 mistune2.0.5 python-multipart0.0.6下载mermaid.min.js 10.9放入static目录启动服务python app.py访问页面浏览器打开http://localhost:8000测试场景上传test1.md直接渲染 Markdown 和 Mermaid 图表上传test1.txt自动转换为 Mermaid 流程图并渲染上传其他格式文件提示“仅支持 .md 或 .txt 格式”上传格式错误的 .txt提示格式错误信息六、扩展功能可选支持更多 Mermaid 图表类型如饼图、时序图只需在 Markdown 中编写对应 Mermaid 语法自定义 Mermaid 主题修改mermaid.initialize()中的theme和themeVariables支持文件下载在渲染结果页面添加“下载 Markdown”按钮代码块高亮引入 Prism.js 或 Highlight.js 对代码块进行语法高亮该方案完全基于指定版本实现逻辑与server.js一致可直接运行并满足 Markdown mermaid 渲染需求。