Spaces:
Sleeping
Sleeping
File size: 8,245 Bytes
9e9b194 e7d96ab 9e9b194 e7d96ab 9e9b194 e7d96ab 9e9b194 e7d96ab 9e9b194 e7d96ab 5c70d5b e7d96ab 0f1355e 5c70d5b 0f1355e 5c70d5b 0f1355e 127229f 4c91160 127229f 0f1355e e7d96ab 0f1355e e7d96ab 5c70d5b e7d96ab 0f1355e e7d96ab 5c70d5b 9e9b194 d01fcae 9e9b194 0f1355e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | import gradio as gr
import os
import logging
import base64
import tempfile
import subprocess
from mermaid_renderer import MermaidRenderer
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Initialize the renderer
renderer = None
try:
renderer = MermaidRenderer()
logging.info("MermaidRenderer initialized successfully.")
except RuntimeError as e:
logging.critical(f"Failed to initialize MermaidRenderer: {e}")
renderer = None
def render_mermaid(mermaid_code, output_format="png", theme="default"):
"""
Render Mermaid code and return the image file path.
"""
if renderer is None:
return None, "Error: Mermaid rendering service is unavailable."
if not mermaid_code.strip():
return None, "Mermaid code cannot be empty."
try:
output_path, input_path = renderer.render(mermaid_code, output_format, theme)
# Clean up input file immediately
if input_path and os.path.exists(input_path):
try:
os.unlink(input_path)
except OSError:
pass
return output_path, f"Successfully rendered {output_format.upper()} with {theme} theme"
except Exception as e:
logging.error(f"Rendering failed: {e}")
return None, f"Error: {str(e)}"
# Default Mermaid code
default_mermaid_code = """graph TD
A[Start] --> B{Is it?};
B -- Yes --> C[OK];
C --> D[End];
B -- No --> E[Really?];
E --> C;"""
# Create Gradio interface
with gr.Blocks(title="Mermaid Diagram Renderer", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🧜♀️ Mermaid Diagram Renderer")
gr.Markdown("Enter Mermaid code below and generate beautiful diagrams!")
with gr.Row():
with gr.Column():
mermaid_input = gr.Textbox(
label="Mermaid Code",
placeholder="Enter your Mermaid diagram code here...",
lines=15,
value=default_mermaid_code
)
with gr.Row():
format_dropdown = gr.Dropdown(
choices=["png", "svg", "pdf"],
value="png",
label="Output Format"
)
theme_dropdown = gr.Dropdown(
choices=["default", "forest", "dark", "neutral"],
value="default",
label="Theme"
)
render_btn = gr.Button("Render Diagram", variant="primary")
with gr.Column():
rendered_image = gr.Image(label="Diagram Preview", show_label=True, show_download_button=False)
output_image = gr.File(label="Download Diagram")
status_text = gr.Textbox(label="Status", interactive=False)
# Connect the function
def render_mermaid_with_preview(mermaid_code, output_format="png", theme="default"):
"""
Render Mermaid code and return the image for preview and download.
"""
if renderer is None:
return None, None, "Error: Mermaid rendering service is unavailable."
if not mermaid_code.strip():
return None, None, "Mermaid code cannot be empty."
try:
output_path, input_path = renderer.render(mermaid_code, output_format, theme)
# Clean up input file immediately
if input_path and os.path.exists(input_path):
try:
os.unlink(input_path)
except OSError:
pass
# Only preview PNG or SVG
if output_format in ["png", "svg"]:
preview_path = output_path
else:
preview_path = None
# Check for Mermaid syntax errors in SVG or PNG output
status_message = f"Successfully rendered {output_format.upper()} with {theme} theme"
if output_format == "svg" and output_path and os.path.exists(output_path):
try:
with open(output_path, "r", encoding="utf-8") as f:
svg_content = f.read()
# Look for common error indicators in the SVG output
if "SyntaxError" in svg_content or "Parse error" in svg_content or "Error:" in svg_content:
# Extract the error message (simple heuristic)
import re
error_lines = re.findall(r'>([^<>]*Error[^<>]*)<', svg_content)
error_text = error_lines[0] if error_lines else "Mermaid syntax error"
status_message = f"Error: {error_text}"
except Exception as svg_err:
logging.warning(f"Could not check SVG for errors: {svg_err}")
elif output_format == "png" and output_path and os.path.exists(output_path):
try:
from PIL import Image
import pytesseract
img = Image.open(output_path)
ocr_text = pytesseract.image_to_string(img)
if "Syntax error" in ocr_text or "Parse error" in ocr_text or "Error" in ocr_text:
# Extract the error message (simple heuristic)
lines = [line for line in ocr_text.splitlines() if "error" in line.lower()]
error_text = lines[0] if lines else "Mermaid syntax error"
status_message = f"Error: {error_text}"
except Exception as png_err:
logging.warning(f"Could not OCR PNG for errors: {png_err}")
# Gather dependency versions for debugging
import platform
dep_versions = []
try:
import gradio
dep_versions.append(f"gradio {gradio.__version__}")
except Exception:
dep_versions.append("gradio N/A")
try:
import pytesseract
dep_versions.append(f"pytesseract {pytesseract.__version__}")
except Exception:
dep_versions.append("pytesseract N/A")
try:
from PIL import __version__ as pillow_version
dep_versions.append(f"Pillow {pillow_version}")
except Exception:
dep_versions.append("Pillow N/A")
try:
node_ver = subprocess.run(["node", "--version"], capture_output=True, text=True)
dep_versions.append(f"Node.js {node_ver.stdout.strip()}")
except Exception:
dep_versions.append("Node.js N/A")
try:
mmdc_ver = subprocess.run(["mmdc", "--version"], capture_output=True, text=True)
dep_versions.append(f"mmdc {mmdc_ver.stdout.strip()}")
except Exception:
dep_versions.append("mmdc N/A")
dep_versions.append(f"Python {platform.python_version()}")
dep_info = " | ".join(dep_versions)
status_message = f"{status_message}\n\nDependencies: {dep_info}"
return preview_path, output_path, status_message
except Exception as e:
logging.error(f"Rendering failed: {e}")
return None, None, f"Error: {str(e)}"
render_btn.click(
fn=render_mermaid_with_preview,
inputs=[mermaid_input, format_dropdown, theme_dropdown],
outputs=[rendered_image, output_image, status_text]
)
# Auto-render on load
demo.load(
fn=render_mermaid_with_preview,
inputs=[mermaid_input, format_dropdown, theme_dropdown],
outputs=[rendered_image, output_image, status_text]
)
gr.Markdown(
"""
---
<sub>
This version is a simplified version of <a href="https://github.com/chunhualiao/mermaid-rendering" target="_blank">https://github.com/chunhualiao/mermaid-rendering</a>.<br>
The full version has more control of previewed diagrams, such as zoom and pan operations.
</sub>
""",
elem_id="footnote",
)
if __name__ == "__main__":
demo.launch()
|