mermaid-trace 0.4.1__py3-none-any.whl → 0.6.0.post0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,406 @@
1
+ """
2
+ Enhanced Web Server for MermaidTrace.
3
+
4
+ This module provides a robust, real-time preview server using FastAPI and Server-Sent Events (SSE).
5
+ It monitors .mmd files and pushes updates to the browser instantly.
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+ import json
11
+ from pathlib import Path
12
+ from typing import AsyncGenerator, Set, Any
13
+
14
+ try:
15
+ from fastapi import FastAPI, Request, HTTPException
16
+ from fastapi.responses import HTMLResponse, StreamingResponse
17
+ import uvicorn
18
+
19
+ HAS_SERVER_DEPS = True
20
+ except ImportError:
21
+ HAS_SERVER_DEPS = False
22
+
23
+ try:
24
+ from watchdog.observers import Observer
25
+ from watchdog.events import FileSystemEventHandler
26
+
27
+ HAS_WATCHDOG = True
28
+ except ImportError:
29
+ HAS_WATCHDOG = False
30
+
31
+ app = FastAPI(title="MermaidTrace Preview Server")
32
+
33
+
34
+ # Global state to manage connected clients for SSE
35
+ class ConnectionManager:
36
+ def __init__(self) -> None:
37
+ self.active_connections: Set[asyncio.Queue[dict[str, Any]]] = set()
38
+
39
+ async def subscribe(self) -> asyncio.Queue[dict[str, Any]]:
40
+ queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue()
41
+ self.active_connections.add(queue)
42
+ return queue
43
+
44
+ def unsubscribe(self, queue: asyncio.Queue[dict[str, Any]]) -> None:
45
+ self.active_connections.remove(queue)
46
+
47
+ async def broadcast(self, data: dict[str, Any]) -> None:
48
+ for queue in self.active_connections:
49
+ await queue.put(data)
50
+
51
+
52
+ manager = ConnectionManager()
53
+
54
+ # HTML Template with enhanced UI
55
+ HTML_TEMPLATE = """
56
+ <!DOCTYPE html>
57
+ <html lang="en">
58
+ <head>
59
+ <meta charset="UTF-8">
60
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
61
+ <title>MermaidTrace Master Preview</title>
62
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
63
+ <script src="https://cdn.jsdelivr.net/npm/svg-pan-zoom@3.6.1/dist/svg-pan-zoom.min.js"></script>
64
+ <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
65
+ <style>
66
+ body { background-color: #f8fafc; }
67
+ .mermaid { background: white; }
68
+ #diagram-container {
69
+ height: calc(100vh - 10rem);
70
+ overflow: hidden;
71
+ position: relative;
72
+ background-image: radial-gradient(#e2e8f0 1px, transparent 1px);
73
+ background-size: 20px 20px;
74
+ display: flex;
75
+ flex-direction: column;
76
+ }
77
+ #svg-wrapper {
78
+ flex: 1;
79
+ width: 100%;
80
+ height: 100%;
81
+ cursor: grab;
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ }
86
+ #svg-wrapper:active { cursor: grabbing; }
87
+ .sidebar-item:hover { background-color: #e2e8f0; }
88
+ .sidebar-item.active { background-color: #3b82f6; color: white; }
89
+ /* Ensure mermaid SVG doesn't have max-width constraints */
90
+ #mermaid-graph {
91
+ width: 100%;
92
+ height: 100%;
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: center;
96
+ }
97
+ #mermaid-graph svg {
98
+ max-width: none !important;
99
+ max-height: none !important;
100
+ }
101
+ </style>
102
+ </head>
103
+ <body class="flex flex-col h-screen">
104
+ <!-- Header -->
105
+ <header class="bg-white border-b border-gray-200 px-6 py-4 flex justify-between items-center shadow-sm">
106
+ <div class="flex items-center space-x-3">
107
+ <div class="bg-blue-600 text-white p-2 rounded-lg">
108
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
109
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
110
+ </svg>
111
+ </div>
112
+ <h1 class="text-xl font-bold text-gray-800">MermaidTrace <span class="text-blue-600">Master</span></h1>
113
+ </div>
114
+ <div class="flex items-center space-x-4">
115
+ <span id="status-badge" class="px-3 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Live Connected</span>
116
+ <button onclick="resetZoom()" class="text-gray-600 hover:text-blue-600 transition">
117
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path></svg>
118
+ </button>
119
+ <button onclick="downloadSVG()" class="text-gray-600 hover:text-blue-600 transition">
120
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
121
+ </button>
122
+ </div>
123
+ </header>
124
+
125
+ <div class="flex flex-1 overflow-hidden">
126
+ <!-- Sidebar -->
127
+ <aside class="w-64 bg-white border-r border-gray-200 overflow-y-auto hidden md:block">
128
+ <div class="p-4 border-b border-gray-100">
129
+ <h2 class="text-xs font-semibold text-gray-500 uppercase tracking-wider">Trace Files</h2>
130
+ </div>
131
+ <nav id="file-list" class="p-2 space-y-1">
132
+ <!-- File items will be injected here -->
133
+ </nav>
134
+ </aside>
135
+
136
+ <!-- Main Content -->
137
+ <main class="flex-1 flex flex-col p-6 overflow-hidden">
138
+ <div class="mb-4 flex justify-between items-end">
139
+ <div>
140
+ <h2 id="current-filename" class="text-2xl font-bold text-gray-900">Select a file</h2>
141
+ <p id="last-updated" class="text-sm text-gray-500 mt-1">Ready to visualize</p>
142
+ </div>
143
+ </div>
144
+
145
+ <div id="diagram-container" class="flex-1 bg-white rounded-xl shadow-inner border border-gray-200 overflow-hidden">
146
+ <div id="svg-wrapper">
147
+ <div class="mermaid" id="mermaid-graph">
148
+ sequenceDiagram
149
+ Note over Server, Client: Waiting for trace data...
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </main>
154
+ </div>
155
+
156
+ <script>
157
+ let panZoomInstance = null;
158
+ let currentFile = null;
159
+
160
+ function initMermaid() {
161
+ if (typeof mermaid === 'undefined') {
162
+ console.log("Waiting for mermaid...");
163
+ setTimeout(initMermaid, 100);
164
+ return;
165
+ }
166
+
167
+ mermaid.initialize({
168
+ startOnLoad: false,
169
+ theme: 'default',
170
+ securityLevel: 'loose',
171
+ useMaxWidth: false,
172
+ sequence: {
173
+ showSequenceNumbers: true,
174
+ useMaxWidth: false,
175
+ bottomMarginAdjustment: 1
176
+ }
177
+ });
178
+
179
+ // Initialize
180
+ updateFileList();
181
+ }
182
+
183
+ async function loadFile(filename) {
184
+ if (!filename) return;
185
+ currentFile = filename;
186
+
187
+ // Update active state in sidebar
188
+ document.querySelectorAll('.sidebar-item').forEach(el => {
189
+ if (el.dataset.filename === filename) el.classList.add('active');
190
+ else el.classList.remove('active');
191
+ });
192
+
193
+ try {
194
+ const response = await fetch(`/api/file?name=${encodeURIComponent(filename)}`);
195
+ const data = await response.json();
196
+
197
+ document.getElementById('current-filename').textContent = filename;
198
+ renderDiagram(data.content);
199
+ updateTimestamp();
200
+ } catch (err) {
201
+ console.error("Failed to load file:", err);
202
+ }
203
+ }
204
+
205
+ async function renderDiagram(content) {
206
+ const graphDiv = document.getElementById('mermaid-graph');
207
+ graphDiv.removeAttribute('data-processed');
208
+ // Clean up previous SVG before rendering new one
209
+ graphDiv.innerHTML = content;
210
+
211
+ try {
212
+ const { svg } = await mermaid.render('mermaid-svg-' + Date.now(), content);
213
+ graphDiv.innerHTML = svg;
214
+ setupPanZoom();
215
+ } catch (err) {
216
+ console.error("Mermaid render error:", err);
217
+ }
218
+ }
219
+
220
+ function setupPanZoom() {
221
+ if (panZoomInstance) {
222
+ panZoomInstance.destroy();
223
+ panZoomInstance = null;
224
+ }
225
+ const svg = document.querySelector('#mermaid-graph svg');
226
+ if (svg) {
227
+ // Ensure SVG takes up all available space for the pan-zoom container
228
+ svg.style.width = '100%';
229
+ svg.style.height = '100%';
230
+ svg.style.maxWidth = 'none';
231
+ svg.style.maxHeight = 'none';
232
+
233
+ // Clear explicit width/height attributes that might conflict with 'fit'
234
+ svg.removeAttribute('width');
235
+ svg.removeAttribute('height');
236
+
237
+ panZoomInstance = svgPanZoom(svg, {
238
+ zoomEnabled: true,
239
+ controlIconsEnabled: false,
240
+ fit: true,
241
+ center: true,
242
+ minZoom: 0.1,
243
+ maxZoom: 20,
244
+ zoomScaleSensitivity: 0.2
245
+ });
246
+
247
+ // Auto fit on window resize
248
+ window.addEventListener('resize', () => {
249
+ if (panZoomInstance) {
250
+ panZoomInstance.resize();
251
+ panZoomInstance.fit();
252
+ panZoomInstance.center();
253
+ }
254
+ });
255
+ }
256
+ }
257
+
258
+ function resetZoom() {
259
+ if (panZoomInstance) {
260
+ panZoomInstance.fit();
261
+ panZoomInstance.center();
262
+ }
263
+ }
264
+
265
+ function updateTimestamp() {
266
+ const now = new Date();
267
+ document.getElementById('last-updated').textContent = `Last updated: ${now.toLocaleTimeString()}`;
268
+ }
269
+
270
+ async function updateFileList() {
271
+ const response = await fetch('/api/files');
272
+ const files = await response.json();
273
+ const list = document.getElementById('file-list');
274
+ list.innerHTML = '';
275
+
276
+ files.forEach(f => {
277
+ const item = document.createElement('a');
278
+ item.href = "#";
279
+ item.className = `sidebar-item block px-3 py-2 text-sm font-medium rounded-md transition ${f === currentFile ? 'active' : 'text-gray-700'}`;
280
+ item.dataset.filename = f;
281
+ item.textContent = f;
282
+ item.onclick = (e) => {
283
+ e.preventDefault();
284
+ loadFile(f);
285
+ };
286
+ list.appendChild(item);
287
+ });
288
+
289
+ if (!currentFile && files.length > 0) {
290
+ loadFile(files[0]);
291
+ }
292
+ }
293
+
294
+ // SSE Connection for real-time updates
295
+ const eventSource = new EventSource("/events");
296
+ eventSource.onmessage = (event) => {
297
+ const data = JSON.parse(event.data);
298
+ if (data.type === "update" && data.filename === currentFile) {
299
+ console.log("File update received:", data.filename);
300
+ loadFile(data.filename);
301
+ } else if (data.type === "refresh_list") {
302
+ updateFileList();
303
+ }
304
+ };
305
+
306
+ eventSource.onerror = () => {
307
+ document.getElementById('status-badge').className = "px-3 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800";
308
+ document.getElementById('status-badge').textContent = "Connection Lost";
309
+ };
310
+
311
+ // Start Initialization
312
+ initMermaid();
313
+
314
+ function downloadSVG() {
315
+ const svg = document.querySelector('#diagram-container svg');
316
+ if (!svg) return;
317
+ const serializer = new XMLSerializer();
318
+ let source = serializer.serializeToString(svg);
319
+ if(!source.match(/^<svg[^>]+xmlns="http\\:\\/\\/www\\.w3\\.org\\/2000\\/svg"/)){
320
+ source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
321
+ }
322
+ if(!source.match(/^<svg[^>]+xmlns\\:xlink="http\\:\\/\\/www\\.w3\\.org\\/1999\\/xlink"/)){
323
+ source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
324
+ }
325
+ source = '<?xml version="1.0" standalone="no"?>\\r\\n' + source;
326
+ const url = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
327
+ const link = document.createElement("a");
328
+ link.href = url;
329
+ link.download = `${currentFile || 'diagram'}.svg`;
330
+ link.click();
331
+ }
332
+ </script>
333
+ </body>
334
+ </html>
335
+ """
336
+
337
+ # Global directory to watch
338
+ watch_dir: Path = Path(".")
339
+
340
+
341
+ @app.get("/", response_class=HTMLResponse)
342
+ async def get_index() -> str:
343
+ return HTML_TEMPLATE
344
+
345
+
346
+ @app.get("/api/files")
347
+ async def list_files() -> list[str]:
348
+ files = sorted([f.name for f in watch_dir.glob("*.mmd")])
349
+ return files
350
+
351
+
352
+ @app.get("/api/file")
353
+ async def get_file_content(name: str) -> dict[str, str]:
354
+ file_path = watch_dir / name
355
+ if not file_path.exists() or not str(file_path).endswith(".mmd"):
356
+ raise HTTPException(status_code=404, detail="File not found")
357
+ return {"content": file_path.read_text(encoding="utf-8")}
358
+
359
+
360
+ @app.get("/events")
361
+ async def sse_endpoint(request: Request) -> StreamingResponse:
362
+ async def event_generator() -> AsyncGenerator[str, None]:
363
+ queue = await manager.subscribe()
364
+ try:
365
+ while True:
366
+ if await request.is_disconnected():
367
+ break
368
+ data = await queue.get()
369
+ yield f"data: {json.dumps(data)}\\n\\n"
370
+ finally:
371
+ manager.unsubscribe(queue)
372
+
373
+ return StreamingResponse(event_generator(), media_type="text/event-stream")
374
+
375
+
376
+ def run_server(directory: str, port: int = 8000) -> None:
377
+ global watch_dir
378
+ watch_dir = Path(directory).resolve()
379
+
380
+ if not HAS_SERVER_DEPS:
381
+ print("Error: FastAPI, Uvicorn are required for the enhanced server.")
382
+ print("Install them with: pip install fastapi uvicorn")
383
+ return
384
+
385
+ # Start Watchdog
386
+ if HAS_WATCHDOG:
387
+
388
+ class Handler(FileSystemEventHandler):
389
+ def on_modified(self, event: Any) -> None:
390
+ if not event.is_directory and event.src_path.endswith(".mmd"):
391
+ filename = os.path.basename(event.src_path)
392
+ asyncio.run(
393
+ manager.broadcast({"type": "update", "filename": filename})
394
+ )
395
+
396
+ def on_created(self, event: Any) -> None:
397
+ if not event.is_directory and event.src_path.endswith(".mmd"):
398
+ asyncio.run(manager.broadcast({"type": "refresh_list"}))
399
+
400
+ observer = Observer()
401
+ observer.schedule(Handler(), str(watch_dir), recursive=False)
402
+ observer.start()
403
+ print(f"[*] Watching directory: {watch_dir}")
404
+
405
+ print(f"[*] Starting Master Preview Server at http://localhost:{port}")
406
+ uvicorn.run(app, host="0.0.0.0", port=port, log_level="error")
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.4
2
+ Name: mermaid-trace
3
+ Version: 0.6.0.post0
4
+ Summary: Visualize your Python code execution flow as Mermaid Sequence Diagrams.
5
+ Project-URL: Documentation, https://github.com/xt765/mermaid-trace#readme
6
+ Project-URL: Changelog, https://github.com/xt765/mermaid-trace/blob/main/docs/en/CHANGELOG.md
7
+ Project-URL: Issues, https://github.com/xt765/mermaid-trace/issues
8
+ Project-URL: Source, https://github.com/xt765/mermaid-trace
9
+ Author-email: xt765 <xt765@foxmail.com>
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 xt765
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: asyncio,logging,mermaid,mermaid-trace,sequence-diagram,trace,visualization
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Programming Language :: Python :: Implementation :: CPython
43
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
44
+ Classifier: Topic :: Software Development :: Debuggers
45
+ Classifier: Topic :: System :: Logging
46
+ Requires-Python: >=3.10
47
+ Requires-Dist: typing-extensions>=4.0.0
48
+ Requires-Dist: watchdog>=2.0.0
49
+ Provides-Extra: all
50
+ Requires-Dist: fastapi>=0.100.0; extra == 'all'
51
+ Requires-Dist: langchain-core>=0.1.0; extra == 'all'
52
+ Provides-Extra: dev
53
+ Requires-Dist: fastapi>=0.100.0; extra == 'dev'
54
+ Requires-Dist: httpx; extra == 'dev'
55
+ Requires-Dist: langchain-core>=0.1.0; extra == 'dev'
56
+ Requires-Dist: mypy; extra == 'dev'
57
+ Requires-Dist: pytest; extra == 'dev'
58
+ Requires-Dist: pytest-asyncio; extra == 'dev'
59
+ Requires-Dist: pytest-cov; extra == 'dev'
60
+ Requires-Dist: ruff; extra == 'dev'
61
+ Provides-Extra: fastapi
62
+ Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
63
+ Provides-Extra: langchain
64
+ Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
65
+ Description-Content-Type: text/markdown
66
+
67
+ # MermaidTrace: Visualize Your Python Code Logic
68
+
69
+ **Stop drowning in cryptic logs. One line of code to transform complex execution logic into clear Mermaid sequence diagrams.**
70
+
71
+ 🌐 **Language**: [English](README.md) | [中文](README_CN.md)
72
+
73
+ [![CSDN Blog](https://img.shields.io/badge/CSDN-玄同765-orange?style=flat-square&logo=csdn)](https://blog.csdn.net/Yunyi_Chi)
74
+ [![GitHub](https://img.shields.io/badge/GitHub-mermaid--trace-black?style=flat-square&logo=github)](https://github.com/xt765/mermaid-trace)
75
+ [![Gitee](https://img.shields.io/badge/Gitee-mermaid--trace-red?style=flat-square&logo=gitee)](https://gitee.com/xt765/mermaid-trace)
76
+ [![PyPI version](https://img.shields.io/pypi/v/mermaid-trace.svg?style=flat-square&color=blue)](https://pypi.org/project/mermaid-trace/)
77
+ [![Python Versions](https://img.shields.io/pypi/pyversions/mermaid-trace.svg?style=flat-square&color=blue)](https://pypi.org/project/mermaid-trace/)
78
+ [![License](https://img.shields.io/github/license/xt765/mermaid-trace?style=flat-square)](LICENSE)
79
+ [![CI Status](https://img.shields.io/github/actions/workflow/status/xt765/mermaid-trace/ci.yml?style=flat-square&label=CI)](https://github.com/xt765/mermaid-trace/actions/workflows/ci.yml)
80
+ [![Codecov](https://img.shields.io/codecov/c/github/xt765/mermaid-trace?style=flat-square&logo=codecov)](https://codecov.io/gh/xt765/mermaid-trace)
81
+
82
+ ---
83
+
84
+ ## ⚡️ Understand MermaidTrace in 5 Seconds
85
+
86
+ #### 1. Original Code (15+ lines)
87
+ ```python
88
+ @trace(source="User", target="OrderSys")
89
+ def create_order(user_id, items):
90
+ # Complex business logic
91
+ if not check_inventory(items):
92
+ return "Out of Stock"
93
+
94
+ # Nested logic calls
95
+ price = calculate_price(items)
96
+ discount = get_discount(user_id)
97
+ final = price - discount
98
+
99
+ # External service interactions
100
+ res = pay_service.process(final)
101
+ if res.success:
102
+ update_stock(items)
103
+ send_notif(user_id)
104
+ return "Success"
105
+ return "Failed"
106
+ ```
107
+
108
+ #### 2. Auto-Generated Sequence Diagram
109
+ ```mermaid
110
+ sequenceDiagram
111
+ autonumber
112
+ User->>OrderSys: create_order(user_id, items)
113
+ activate OrderSys
114
+ OrderSys->>Inventory: check_inventory(items)
115
+ Inventory-->>OrderSys: True
116
+ OrderSys->>Pricing: calculate_price(items)
117
+ Pricing-->>OrderSys: 100.0
118
+ OrderSys->>UserDB: get_discount(user_id)
119
+ UserDB-->>OrderSys: 5.0
120
+ OrderSys->>PayService: process(95.0)
121
+ activate PayService
122
+ PayService-->>OrderSys: success
123
+ deactivate PayService
124
+ OrderSys->>Inventory: update_stock(items)
125
+ OrderSys->>Notification: send_notif(user_id)
126
+ OrderSys-->>User: "Success"
127
+ deactivate OrderSys
128
+ ```
129
+
130
+ ---
131
+
132
+ ## 🚀 Dynamic Demo & Online Tryout
133
+
134
+ ### 🎬 Quick Demo
135
+
136
+ ![MermaidTrace Master Preview](docs/images/master_preview.png)
137
+
138
+ *(Master Preview: Multi-file browsing, live-reload, and interactive pan/zoom)*
139
+
140
+ ```mermaid
141
+ sequenceDiagram
142
+ participant CLI as mermaid-trace CLI
143
+ participant App as Python App
144
+ participant Web as Live Preview
145
+
146
+ Note over CLI, Web: Enable Live Preview Mode
147
+ CLI->>Web: Start HTTP Server (localhost:8000)
148
+ App->>App: Run Logic (with @trace decorator)
149
+ App->>App: Auto-update flow.mmd
150
+ Web->>Web: File Change Detected (Hot Reload)
151
+ Web-->>CLI: Render Latest Diagram
152
+ ```
153
+ *(From adding decorators to browser live preview in 10 seconds)*
154
+
155
+ ### 🛠️ Try Online (Google Colab)
156
+
157
+ No local setup required. Experience core features in your browser:
158
+
159
+ [![Open In Colab](https://img.shields.io/badge/Colab-Open%20in%20Colab-blue?style=flat&logo=google-colab&logoColor=white)](https://colab.research.google.com/github/xt765/mermaid-trace/blob/main/examples/MermaidTrace_Demo.ipynb)
160
+
161
+ ---
162
+
163
+ ## 🎯 Why MermaidTrace? (Use Cases)
164
+
165
+ ### 1. Master "Legacy" Codebases
166
+ **Pain**: Taking over a complex, undocumented legacy project with tangled function calls.
167
+ **Solution**: Add `@trace_class` or `@trace` to entry points and run the code once.
168
+ **Value**: Instantly generate a complete execution path map to understand the architecture.
169
+
170
+ ### 2. Automated Technical Docs
171
+ **Pain**: Manual sequence diagrams are time-consuming and quickly become outdated.
172
+ **Solution**: Integrate MermaidTrace during development.
173
+ **Value**: Diagrams stay 100% in sync with your code logic automatically.
174
+
175
+ ### 3. Debug Complex Recursion & Concurrency
176
+ **Pain**: Nested calls or async tasks produce interleaved logs that are impossible to read.
177
+ **Solution**: Use built-in async support and intelligent collapsing.
178
+ **Value**: Visualize recursion depth and concurrency flow to pinpoint logic bottlenecks.
179
+
180
+ ---
181
+
182
+ ## 🚀 Quick Start in 3 Steps
183
+
184
+ ### 1. Install
185
+ ```bash
186
+ pip install mermaid-trace
187
+ ```
188
+
189
+ ### 2. Add Decorators
190
+ ```python
191
+ from mermaid_trace import trace, configure_flow
192
+
193
+ # Configure output file
194
+ configure_flow("my_flow.mmd")
195
+
196
+ @trace(source="User", target="AuthService")
197
+ def login(username):
198
+ return verify_db(username)
199
+
200
+ @trace(source="AuthService", target="DB")
201
+ def verify_db(username):
202
+ return True
203
+
204
+ login("admin")
205
+ ```
206
+
207
+ ### 3. View Diagram
208
+
209
+ Run the built-in CLI tool to preview in real-time (with hot-reload):
210
+
211
+ ```bash
212
+ # Basic preview
213
+ mermaid-trace serve my_flow.mmd
214
+
215
+ # Master mode (Directory browsing, zoom, multi-file switching)
216
+ mermaid-trace serve . --master
217
+ # Or preview a specific file in Master mode
218
+ mermaid-trace serve .\mermaid_diagrams\examples\08-log-rotation.mmd --master
219
+ ```
220
+
221
+ ### 🔗 LangChain Integration
222
+ Visualize LLM chains, agents, and RAG retrieval with a single handler:
223
+ ```python
224
+ from mermaid_trace.integrations.langchain import MermaidTraceCallbackHandler
225
+
226
+ handler = MermaidTraceCallbackHandler(host_name="MyAIApp")
227
+ # Pass to any LangChain object
228
+ chain.invoke({"input": "..."}, config={"callbacks": [handler]})
229
+ ```
230
+
231
+ ---
232
+
233
+ ## ✨ Key Features
234
+
235
+ - **Decorator-Driven**: Simply add `@trace` or `@trace_interaction` to functions.
236
+ - **Auto-Instrumentation**: Use `@trace_class` to trace a whole class at once.
237
+ - **Third-Party Patching**: Use `patch_object` to trace calls inside external libraries.
238
+ - **Async Support**: Seamlessly works with `asyncio` coroutines and concurrency.
239
+ - **Enhanced Web UI**: Interactive preview server with file browsing, auto-reload, and pan/zoom support (use `--master`).
240
+ - **Intelligent Collapsing**: Automatically collapses repetitive calls and identifies loops.
241
+ - **FastAPI Integration**: Middleware for zero-config HTTP request tracing.
242
+ - **LangChain Integration**: Callback Handler for LLM chains and agent visualization.
243
+ - **Detailed Exceptions**: Captures full stack traces for errors, displayed in the diagram.
244
+
245
+ ---
246
+
247
+ ## 📚 Documentation
248
+
249
+ ### Core Documentation
250
+
251
+ [User Guide](docs/en/USER_GUIDE.md) · [API Reference](docs/en/API.md) · [Contributing Guidelines](docs/en/CONTRIBUTING.md) · [Changelog](docs/en/CHANGELOG.md) · [License](LICENSE)
252
+
253
+ ### Code Comment Documents
254
+
255
+ | Category | Links |
256
+ | :--- | :--- |
257
+ | **Core Modules** | [Context](docs/en/code_comments/src/mermaid_trace/core/context.md) · [Decorators](docs/en/code_comments/src/mermaid_trace/core/decorators.md) · [Events](docs/en/code_comments/src/mermaid_trace/core/events.md) · [Formatter](docs/en/code_comments/src/mermaid_trace/core/formatter.md) |
258
+ | **Handlers** | [Async Handler](docs/en/code_comments/src/mermaid_trace/handlers/async_handler.md) · [Mermaid Handler](docs/en/code_comments/src/mermaid_trace/handlers/mermaid_handler.md) |
259
+ | **Integrations** | [FastAPI](docs/en/code_comments/src/mermaid_trace/integrations/fastapi.md) |
260
+ | **Others** | [init](docs/en/code_comments/src/mermaid_trace/__init__.md) · [CLI](docs/en/code_comments/src/mermaid_trace/cli.md) |
261
+
262
+ ---
263
+
264
+ ## 🤝 Contributing
265
+
266
+ We welcome contributions! Please see [CONTRIBUTING.md](docs/en/CONTRIBUTING.md) for details.
267
+
268
+ ---
269
+
270
+ ## 📄 License
271
+
272
+ MIT