Files
akmon/doc_bus/render_mermaid.py
2026-01-20 08:04:15 +08:00

111 lines
3.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Mermaid Diagram Renderer
Finds mermaid code blocks in a markdown file and converts them to PNG images.
"""
import re
import subprocess
import os
import sys
from pathlib import Path
def check_mmdc():
"""Check if mermaid-cli (mmdc) is installed."""
try:
subprocess.run(['mmdc', '--version'], check=True, capture_output=True)
return True
except (subprocess.CalledProcessError, FileNotFoundError):
print("'mermaid-cli' (mmdc) not found.")
print(" Please install it globally by running: npm install -g @mermaid-js/mermaid-cli")
print(" You need Node.js and npm installed first.")
return False
def render_mermaid_diagrams(md_file_path, output_dir='charts'):
"""
Renders all mermaid diagrams in a markdown file to PNG images.
The markdown file is updated in-place to link to the generated images.
"""
if not check_mmdc():
return False
md_path = Path(md_file_path)
if not md_path.exists():
print(f"❌ File not found: {md_file_path}")
return False
print(f"Processing Mermaid diagrams in: {md_path.name}")
# Create charts directory if it doesn't exist
charts_path = md_path.parent / output_dir
charts_path.mkdir(exist_ok=True)
with open(md_path, 'r', encoding='utf-8') as f:
content = f.read()
mermaid_blocks = re.findall(r'(```mermaid\n(.*?)\n```)', content, re.DOTALL)
if not mermaid_blocks:
print("No Mermaid diagrams found.")
return True
new_content = content
for i, (block, code) in enumerate(mermaid_blocks):
chart_filename = f"{md_path.stem}-mermaid-{i+1}.png"
output_image_path = charts_path / chart_filename
temp_mmd_path = charts_path / f"temp_{i}.mmd"
# Write mermaid code to a temporary file
with open(temp_mmd_path, 'w', encoding='utf-8') as f_temp:
f_temp.write(code)
# Run mmdc to convert to PNG
try:
cmd = [
'mmdc',
'-i', str(temp_mmd_path),
'-o', str(output_image_path),
'-b', 'transparent', # Transparent background
'--configFile', 'mermaid_config.json'
]
subprocess.run(cmd, check=True, capture_output=True)
print(f" ✅ Rendered {output_image_path.name}")
# Replace the mermaid block with an image link
image_link = f"![Mermaid Chart]({output_dir}/{chart_filename})"
new_content = new_content.replace(block, image_link, 1)
except subprocess.CalledProcessError as e:
print(f" ❌ Failed to render diagram {i+1}:")
print(e.stderr.decode('utf-8', 'ignore'))
finally:
# Clean up temporary file
if temp_mmd_path.exists():
os.remove(temp_mmd_path)
# Write the updated content back to the markdown file
with open(md_path, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"Updated {md_path.name} with image links.")
return True
def main():
"""Main function to process all specified markdown files."""
markdown_files = [
'rongzi_deepseek.md'
]
all_successful = True
for md_file in markdown_files:
if not render_mermaid_diagrams(md_file):
all_successful = False
if not all_successful:
sys.exit(1)
if __name__ == '__main__':
# This allows running the script on its own to process all relevant files
main()