sayou-visualizer 0.0.11__tar.gz → 0.1.0__tar.gz
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.
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/PKG-INFO +96 -40
- sayou_visualizer-0.1.0/README.md +127 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/pyproject.toml +5 -5
- sayou_visualizer-0.1.0/src/sayou/visualizer/core/styles.py +223 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/renderer/analytic_kg_renderer.py +17 -185
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/renderer/showcase_kg_renderer.py +36 -39
- sayou_visualizer-0.0.11/README.md +0 -71
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/.gitignore +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/examples/quick_start.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/examples/quick_start_ws_client.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/examples/quick_start_ws_server.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/__init__.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/core/exceptions.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/core/schemas.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/interfaces/base_renderer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/pipeline.py +1 -1
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/renderer/pyvis_renderer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/graph_tracer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/rich_tracer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/websocket_tracer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sayou-visualizer
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Visualizer components for the Sayou Data Platform
|
|
5
5
|
Project-URL: Homepage, https://www.sayouzone.com/
|
|
6
6
|
Project-URL: Documentation, https://sayouzone.github.io/sayou-fabric/
|
|
@@ -209,15 +209,15 @@ License: Apache License
|
|
|
209
209
|
limitations under the License.
|
|
210
210
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
211
211
|
Classifier: Operating System :: OS Independent
|
|
212
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
213
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
214
212
|
Classifier: Programming Language :: Python :: 3.11
|
|
213
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
214
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
215
215
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
216
|
-
Requires-Python: >=3.
|
|
216
|
+
Requires-Python: >=3.11
|
|
217
217
|
Requires-Dist: networkx==3.2.1
|
|
218
218
|
Requires-Dist: pyvis==0.3.2
|
|
219
219
|
Requires-Dist: rich==14.2.0
|
|
220
|
-
Requires-Dist: sayou-core~=0.
|
|
220
|
+
Requires-Dist: sayou-core~=0.4.0
|
|
221
221
|
Requires-Dist: websocket-client==1.9.0
|
|
222
222
|
Description-Content-Type: text/markdown
|
|
223
223
|
|
|
@@ -228,67 +228,123 @@ Description-Content-Type: text/markdown
|
|
|
228
228
|
|
|
229
229
|
**The Interactive Observability Engine for Sayou Fabric.**
|
|
230
230
|
|
|
231
|
-
`sayou-visualizer` provides
|
|
231
|
+
`sayou-visualizer` provides transparency to the "Black Box" of data pipelines. It transforms invisible execution logs and complex graph data structures into intuitive, interactive **3D Holographic Knowledge Graphs**.
|
|
232
232
|
|
|
233
|
-
It
|
|
233
|
+
It serves two distinct purposes: **Pipeline Telemetry** (Debugging flow) and **Knowledge Rendering** (Showcasing data topology).
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
---
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
## 1. Architecture & Role
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
The Visualizer operates as a separate layer that can attach to a running pipeline (Tracer) or read static data (Renderer) to generate HTML artifacts.
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
```mermaid
|
|
242
|
+
graph LR
|
|
243
|
+
Data[Pipeline / JSON] --> Pipeline[Visualizer Pipeline]
|
|
244
|
+
|
|
245
|
+
subgraph Renderers
|
|
246
|
+
Tracer[DAG Tracer]
|
|
247
|
+
Analyst[Analyst KG View]
|
|
248
|
+
Showcase[Showcase 3D View]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
Pipeline --> Renderers
|
|
252
|
+
Renderers --> HTML[Interactive HTML]
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 1.1. Core Features
|
|
256
|
+
* **Non-Intrusive Monitoring**: Attaches to any Sayou pipeline via the callback system to visualize execution flow without modifying code.
|
|
257
|
+
* **Deterministic Layout**: Uses physics-based rendering (Cytoscape/Force-Graph) to reveal clusters and outliers in your data.
|
|
258
|
+
* **Interactive Inspection**: Click on nodes to inspect raw attributes, source code, or relationships in real-time.
|
|
259
|
+
|
|
260
|
+
---
|
|
242
261
|
|
|
243
|
-
2.
|
|
262
|
+
## 2. Available Strategies
|
|
244
263
|
|
|
245
|
-
|
|
264
|
+
`sayou-visualizer` offers specialized views depending on who is looking at the data.
|
|
246
265
|
|
|
247
|
-
|
|
266
|
+
| Strategy Key | Target Audience | Description |
|
|
267
|
+
| :--- | :--- | :--- |
|
|
268
|
+
| **`tracer`** | Data Engineer | Visualizes the **Pipeline Execution Flow** (DAG). Shows which components triggered which tasks. |
|
|
269
|
+
| **`analyst`** | QA / Researcher | **2D Analytic View**. Focuses on strict schema validation, attribute inspection, and debugging specific relationships. |
|
|
270
|
+
| **`showcase`** | Stakeholder | **3D Holographic View**. A visually stunning, high-performance renderer for presenting the scale and topology of the Knowledge Graph. |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 3. Installation
|
|
248
275
|
|
|
249
276
|
```bash
|
|
250
277
|
pip install sayou-visualizer
|
|
251
278
|
```
|
|
252
279
|
|
|
253
|
-
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 4. Usage
|
|
254
283
|
|
|
255
|
-
The `VisualizerPipeline`
|
|
284
|
+
The `VisualizerPipeline` is the entry point. You can use it to render existing graph files or attach it to live pipelines.
|
|
285
|
+
|
|
286
|
+
### Case A: Rendering a Knowledge Graph (3D Showcase)
|
|
287
|
+
|
|
288
|
+
Visualizes the output of `sayou-assembler` as an interactive 3D galaxy.
|
|
256
289
|
|
|
257
290
|
```python
|
|
258
|
-
from sayou.
|
|
259
|
-
|
|
291
|
+
from sayou.visualizer import VisualizerPipeline
|
|
292
|
+
|
|
293
|
+
viz = VisualizerPipeline()
|
|
294
|
+
|
|
295
|
+
kg_file_path = "./output/graph_data.json"
|
|
296
|
+
|
|
297
|
+
viz.process(
|
|
298
|
+
source=kg_file_path,
|
|
299
|
+
destination="./output/report_showcase.html",
|
|
300
|
+
strategy="showcase"
|
|
301
|
+
)
|
|
260
302
|
|
|
261
|
-
|
|
262
|
-
|
|
303
|
+
print("Report generated. Open 'report_showcase.html' in your browser.")
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Case B: Debugging Graph Data (2D Analyst)
|
|
307
|
+
|
|
308
|
+
Generates a detailed 2D view for inspecting node attributes and edge types.
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
viz.process(
|
|
312
|
+
source=kg_file_path,
|
|
313
|
+
destination="./output/report_analyst.html",
|
|
314
|
+
strategy="analyst"
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Case C: Pipeline Tracing (Live Monitoring)
|
|
319
|
+
|
|
320
|
+
Attaches to a running Connector pipeline to visualize the crawling process.
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
from sayou.connector import ConnectorPipeline
|
|
324
|
+
from sayou.visualizer import VisualizerPipeline
|
|
263
325
|
|
|
264
|
-
|
|
265
|
-
viz.attach_to(connector)
|
|
326
|
+
connector = ConnectorPipeline()
|
|
266
327
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
for packet in iterator:
|
|
270
|
-
print(f"Processed: {packet.task.uri}")
|
|
328
|
+
viz = VisualizerPipeline()
|
|
329
|
+
viz.attach_to(connector)
|
|
271
330
|
|
|
272
|
-
|
|
273
|
-
viz.report("examples/pipeline_flow.html")
|
|
331
|
+
connector.process(source="https://news.daum.net/tech", strategy="web")
|
|
274
332
|
|
|
275
|
-
|
|
276
|
-
main()
|
|
333
|
+
viz.report("pipeline_trace.html")
|
|
277
334
|
```
|
|
278
335
|
|
|
279
|
-
|
|
336
|
+
---
|
|
280
337
|
|
|
281
|
-
|
|
282
|
-
* **`GraphTracer`**: Listens to pipeline events and constructs a `NetworkX` Directed Acyclic Graph (DAG) in real-time. It distinguishes between Components (Generator/Fetcher) and Data (Tasks).
|
|
338
|
+
## 5. Configuration Keys
|
|
283
339
|
|
|
284
|
-
|
|
285
|
-
* **`PyVisRenderer`**: Converts the internal graph into an interactive HTML file powered by `Vis.js`. Features physics-based layout and modern dark UI.
|
|
286
|
-
* **`RichRenderer`** (_Planned_): Displays a tree-structure summary directly in the console using the `Rich` library.
|
|
340
|
+
Customize the visual appearance via the `config` dictionary.
|
|
287
341
|
|
|
288
|
-
|
|
342
|
+
* **`showcase`**: `node_color_by` (e.g., class), `particle_speed`, `background_color`.
|
|
343
|
+
* **`analyst`**: `layout_algorithm` (dagre/concentric), `show_attributes` (bool).
|
|
344
|
+
* **`tracer`**: `include_data_payload` (bool), `max_events`.
|
|
289
345
|
|
|
290
|
-
|
|
346
|
+
---
|
|
291
347
|
|
|
292
|
-
##
|
|
348
|
+
## 6. License
|
|
293
349
|
|
|
294
|
-
Apache 2.0 License ©
|
|
350
|
+
Apache 2.0 License © 2026 **Sayouzone**
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# sayou-visualizer
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/sayou-visualizer/)
|
|
4
|
+
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
5
|
+
|
|
6
|
+
**The Interactive Observability Engine for Sayou Fabric.**
|
|
7
|
+
|
|
8
|
+
`sayou-visualizer` provides transparency to the "Black Box" of data pipelines. It transforms invisible execution logs and complex graph data structures into intuitive, interactive **3D Holographic Knowledge Graphs**.
|
|
9
|
+
|
|
10
|
+
It serves two distinct purposes: **Pipeline Telemetry** (Debugging flow) and **Knowledge Rendering** (Showcasing data topology).
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Architecture & Role
|
|
15
|
+
|
|
16
|
+
The Visualizer operates as a separate layer that can attach to a running pipeline (Tracer) or read static data (Renderer) to generate HTML artifacts.
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
graph LR
|
|
20
|
+
Data[Pipeline / JSON] --> Pipeline[Visualizer Pipeline]
|
|
21
|
+
|
|
22
|
+
subgraph Renderers
|
|
23
|
+
Tracer[DAG Tracer]
|
|
24
|
+
Analyst[Analyst KG View]
|
|
25
|
+
Showcase[Showcase 3D View]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Pipeline --> Renderers
|
|
29
|
+
Renderers --> HTML[Interactive HTML]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 1.1. Core Features
|
|
33
|
+
* **Non-Intrusive Monitoring**: Attaches to any Sayou pipeline via the callback system to visualize execution flow without modifying code.
|
|
34
|
+
* **Deterministic Layout**: Uses physics-based rendering (Cytoscape/Force-Graph) to reveal clusters and outliers in your data.
|
|
35
|
+
* **Interactive Inspection**: Click on nodes to inspect raw attributes, source code, or relationships in real-time.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Available Strategies
|
|
40
|
+
|
|
41
|
+
`sayou-visualizer` offers specialized views depending on who is looking at the data.
|
|
42
|
+
|
|
43
|
+
| Strategy Key | Target Audience | Description |
|
|
44
|
+
| :--- | :--- | :--- |
|
|
45
|
+
| **`tracer`** | Data Engineer | Visualizes the **Pipeline Execution Flow** (DAG). Shows which components triggered which tasks. |
|
|
46
|
+
| **`analyst`** | QA / Researcher | **2D Analytic View**. Focuses on strict schema validation, attribute inspection, and debugging specific relationships. |
|
|
47
|
+
| **`showcase`** | Stakeholder | **3D Holographic View**. A visually stunning, high-performance renderer for presenting the scale and topology of the Knowledge Graph. |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install sayou-visualizer
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 4. Usage
|
|
60
|
+
|
|
61
|
+
The `VisualizerPipeline` is the entry point. You can use it to render existing graph files or attach it to live pipelines.
|
|
62
|
+
|
|
63
|
+
### Case A: Rendering a Knowledge Graph (3D Showcase)
|
|
64
|
+
|
|
65
|
+
Visualizes the output of `sayou-assembler` as an interactive 3D galaxy.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from sayou.visualizer import VisualizerPipeline
|
|
69
|
+
|
|
70
|
+
viz = VisualizerPipeline()
|
|
71
|
+
|
|
72
|
+
kg_file_path = "./output/graph_data.json"
|
|
73
|
+
|
|
74
|
+
viz.process(
|
|
75
|
+
source=kg_file_path,
|
|
76
|
+
destination="./output/report_showcase.html",
|
|
77
|
+
strategy="showcase"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
print("Report generated. Open 'report_showcase.html' in your browser.")
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Case B: Debugging Graph Data (2D Analyst)
|
|
84
|
+
|
|
85
|
+
Generates a detailed 2D view for inspecting node attributes and edge types.
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
viz.process(
|
|
89
|
+
source=kg_file_path,
|
|
90
|
+
destination="./output/report_analyst.html",
|
|
91
|
+
strategy="analyst"
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Case C: Pipeline Tracing (Live Monitoring)
|
|
96
|
+
|
|
97
|
+
Attaches to a running Connector pipeline to visualize the crawling process.
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from sayou.connector import ConnectorPipeline
|
|
101
|
+
from sayou.visualizer import VisualizerPipeline
|
|
102
|
+
|
|
103
|
+
connector = ConnectorPipeline()
|
|
104
|
+
|
|
105
|
+
viz = VisualizerPipeline()
|
|
106
|
+
viz.attach_to(connector)
|
|
107
|
+
|
|
108
|
+
connector.process(source="https://news.daum.net/tech", strategy="web")
|
|
109
|
+
|
|
110
|
+
viz.report("pipeline_trace.html")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 5. Configuration Keys
|
|
116
|
+
|
|
117
|
+
Customize the visual appearance via the `config` dictionary.
|
|
118
|
+
|
|
119
|
+
* **`showcase`**: `node_color_by` (e.g., class), `particle_speed`, `background_color`.
|
|
120
|
+
* **`analyst`**: `layout_algorithm` (dagre/concentric), `show_attributes` (bool).
|
|
121
|
+
* **`tracer`**: `include_data_payload` (bool), `max_events`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 6. License
|
|
126
|
+
|
|
127
|
+
Apache 2.0 License © 2026 **Sayouzone**
|
|
@@ -7,24 +7,24 @@ build-backend = "hatchling.build"
|
|
|
7
7
|
# -----------------
|
|
8
8
|
[project]
|
|
9
9
|
name = "sayou-visualizer"
|
|
10
|
-
version = "0.0
|
|
10
|
+
version = "0.1.0"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Sayouzone", email = "contact@sayouzone.com" },
|
|
13
13
|
]
|
|
14
14
|
description = "Visualizer components for the Sayou Data Platform"
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
license = { file = "../../LICENSE" }
|
|
17
|
-
requires-python = ">=3.
|
|
17
|
+
requires-python = ">=3.11"
|
|
18
18
|
classifiers = [
|
|
19
|
-
"Programming Language :: Python :: 3.9",
|
|
20
|
-
"Programming Language :: Python :: 3.10",
|
|
21
19
|
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
22
|
"License :: OSI Approved :: Apache Software License",
|
|
23
23
|
"Operating System :: OS Independent",
|
|
24
24
|
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
25
25
|
]
|
|
26
26
|
dependencies = [
|
|
27
|
-
"sayou-core ~= 0.
|
|
27
|
+
"sayou-core ~= 0.4.0",
|
|
28
28
|
"networkx == 3.2.1",
|
|
29
29
|
"pyvis == 0.3.2",
|
|
30
30
|
"rich == 14.2.0",
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
from sayou.core.ontology import SayouClass
|
|
2
|
+
|
|
3
|
+
HIDDEN_ATTR_PREFIXES = ["sayou:", "meta:", "schema:"]
|
|
4
|
+
|
|
5
|
+
# =========================================================
|
|
6
|
+
# 1. 3D Showcase Styles (Original Design Restored)
|
|
7
|
+
# =========================================================
|
|
8
|
+
SHOWCASE_STYLE_MAP = {
|
|
9
|
+
"default": {"group": "Chunk", "color": "#4a69bd", "val": 3},
|
|
10
|
+
# [Original Design Colors]
|
|
11
|
+
SayouClass.FILE: {"group": "Document", "color": "#00d2d3", "val": 20}, # Cyan
|
|
12
|
+
SayouClass.CLASS: {"group": "Header", "color": "#ff6b81", "val": 12}, # Pink
|
|
13
|
+
SayouClass.METHOD: {"group": "Code", "color": "#feca57", "val": 6}, # Gold
|
|
14
|
+
SayouClass.FUNCTION: {"group": "Code", "color": "#feca57", "val": 6}, # Gold
|
|
15
|
+
SayouClass.LIBRARY: {"group": "Library", "color": "#2ed573", "val": 10}, # Green
|
|
16
|
+
# [New] YouTube Domain (Compatible Theme)
|
|
17
|
+
SayouClass.VIDEO: {"group": "Video", "color": "#e84118", "val": 40}, # Deep Red
|
|
18
|
+
SayouClass.VIDEO_SEGMENT: {
|
|
19
|
+
"group": "Segment",
|
|
20
|
+
"color": "#dcdde1",
|
|
21
|
+
"val": 4,
|
|
22
|
+
}, # Gray
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# 동적 크기 계산 규칙
|
|
26
|
+
DYNAMIC_SIZING_RULES = {
|
|
27
|
+
SayouClass.VIDEO_SEGMENT: {
|
|
28
|
+
"attr_start": "sayou:startTime",
|
|
29
|
+
"attr_end": "sayou:endTime",
|
|
30
|
+
"base_val": 4,
|
|
31
|
+
"scale_factor": 0.5,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# =========================================================
|
|
36
|
+
# 2. 2D Analyst Styles (Original Design + Interactions Restored)
|
|
37
|
+
# =========================================================
|
|
38
|
+
ANALYST_TYPE_MAPPING = {
|
|
39
|
+
SayouClass.FILE: "file",
|
|
40
|
+
SayouClass.CLASS: "class",
|
|
41
|
+
SayouClass.METHOD: "method",
|
|
42
|
+
SayouClass.FUNCTION: "function",
|
|
43
|
+
SayouClass.LIBRARY: "library",
|
|
44
|
+
SayouClass.CODE_BLOCK: "code_block",
|
|
45
|
+
SayouClass.VIDEO: "video",
|
|
46
|
+
SayouClass.VIDEO_SEGMENT: "segment",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ANALYST_STYLE_SHEET = [
|
|
50
|
+
# [Global]
|
|
51
|
+
{
|
|
52
|
+
"selector": "node",
|
|
53
|
+
"style": {
|
|
54
|
+
"label": "data(label)",
|
|
55
|
+
"color": "#ecf0f1",
|
|
56
|
+
"font-size": "10px",
|
|
57
|
+
"text-valign": "center",
|
|
58
|
+
"text-halign": "center",
|
|
59
|
+
"text-wrap": "wrap",
|
|
60
|
+
"text-max-width": "100px",
|
|
61
|
+
"background-color": "#95a5a6",
|
|
62
|
+
"border-width": 1,
|
|
63
|
+
"border-color": "#7f8c8d",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
# [Original Node Shapes/Colors]
|
|
67
|
+
{
|
|
68
|
+
"selector": "node[type='file']",
|
|
69
|
+
"style": {
|
|
70
|
+
"shape": "rectangle",
|
|
71
|
+
"background-color": "#2c3e50",
|
|
72
|
+
"width": 60,
|
|
73
|
+
"height": 60,
|
|
74
|
+
"font-size": "12px",
|
|
75
|
+
"font-weight": "bold",
|
|
76
|
+
"border-width": 2,
|
|
77
|
+
"border-color": "#00d2d3",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"selector": "node[type='class']",
|
|
82
|
+
"style": {
|
|
83
|
+
"shape": "diamond",
|
|
84
|
+
"background-color": "#8e44ad",
|
|
85
|
+
"width": 40,
|
|
86
|
+
"height": 40,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"selector": "node[type='method'], node[type='function']",
|
|
91
|
+
"style": {
|
|
92
|
+
"shape": "ellipse",
|
|
93
|
+
"background-color": "#e67e22",
|
|
94
|
+
"width": 25,
|
|
95
|
+
"height": 25,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"selector": "node[type='code_block']",
|
|
100
|
+
"style": {
|
|
101
|
+
"shape": "round-rectangle",
|
|
102
|
+
"background-color": "#7f8c8d",
|
|
103
|
+
"width": 15,
|
|
104
|
+
"height": 15,
|
|
105
|
+
"label": "",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"selector": "node[type='library']",
|
|
110
|
+
"style": {
|
|
111
|
+
"shape": "hexagon",
|
|
112
|
+
"background-color": "#16a085",
|
|
113
|
+
"width": 50,
|
|
114
|
+
"height": 50,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
# [New YouTube Nodes]
|
|
118
|
+
{
|
|
119
|
+
"selector": "node[type='video']",
|
|
120
|
+
"style": {
|
|
121
|
+
"shape": "rectangle",
|
|
122
|
+
"background-color": "#c0392b",
|
|
123
|
+
"width": 80,
|
|
124
|
+
"height": 80,
|
|
125
|
+
"border-width": 4,
|
|
126
|
+
"border-color": "#e74c3c",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"selector": "node[type='segment']",
|
|
131
|
+
"style": {
|
|
132
|
+
"shape": "round-rectangle",
|
|
133
|
+
"background-color": "#bdc3c7",
|
|
134
|
+
"width": 40,
|
|
135
|
+
"height": 20,
|
|
136
|
+
"color": "#2c3e50",
|
|
137
|
+
"font-size": "8px",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
# [Original Edges]
|
|
141
|
+
{
|
|
142
|
+
"selector": "edge",
|
|
143
|
+
"style": {
|
|
144
|
+
"width": 1,
|
|
145
|
+
"curve-style": "bezier",
|
|
146
|
+
"opacity": 0.6,
|
|
147
|
+
"arrow-scale": 1,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"selector": "edge[edgeType='sayou:contains']",
|
|
152
|
+
"style": {
|
|
153
|
+
"line-color": "#7f8c8d",
|
|
154
|
+
"target-arrow-shape": "circle",
|
|
155
|
+
"line-style": "dashed",
|
|
156
|
+
"width": 1.5,
|
|
157
|
+
"opacity": 0.7,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"selector": "edge[edgeType='sayou:imports']",
|
|
162
|
+
"style": {
|
|
163
|
+
"line-color": "#00d2d3",
|
|
164
|
+
"target-arrow-shape": "triangle",
|
|
165
|
+
"line-style": "dashed",
|
|
166
|
+
"width": 2,
|
|
167
|
+
"opacity": 0.9,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"selector": "edge[edgeType='sayou:inherits']",
|
|
172
|
+
"style": {
|
|
173
|
+
"line-color": "#ff6b6b",
|
|
174
|
+
"target-arrow-shape": "triangle",
|
|
175
|
+
"width": 3,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"selector": "edge[edgeType='sayou:next']",
|
|
180
|
+
"style": {
|
|
181
|
+
"line-color": "#f39c12",
|
|
182
|
+
"target-arrow-shape": "triangle",
|
|
183
|
+
"width": 2,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
# =========================================================
|
|
187
|
+
# [CRITICAL FIX] Restored Interaction Styles
|
|
188
|
+
# =========================================================
|
|
189
|
+
{
|
|
190
|
+
"selector": ".highlighted",
|
|
191
|
+
"style": {
|
|
192
|
+
"background-color": "#f1c40f",
|
|
193
|
+
"line-color": "#f1c40f",
|
|
194
|
+
"target-arrow-color": "#f1c40f",
|
|
195
|
+
"opacity": 1,
|
|
196
|
+
"z-index": 999,
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"selector": ".faded",
|
|
201
|
+
"style": {"opacity": 0.05, "label": ""},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"selector": ".found",
|
|
205
|
+
"style": {
|
|
206
|
+
"border-width": 4,
|
|
207
|
+
"border-color": "#e056fd",
|
|
208
|
+
"background-color": "#e056fd",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"selector": "node.no-label",
|
|
213
|
+
"style": {
|
|
214
|
+
"text-opacity": 0,
|
|
215
|
+
"text-background-opacity": 0,
|
|
216
|
+
"text-border-opacity": 0,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"selector": "edge.hidden-edge",
|
|
221
|
+
"style": {"display": "none"},
|
|
222
|
+
},
|
|
223
|
+
]
|
|
@@ -3,6 +3,8 @@ import os
|
|
|
3
3
|
|
|
4
4
|
from sayou.core.base_component import BaseComponent
|
|
5
5
|
|
|
6
|
+
from ..core.styles import ANALYST_STYLE_SHEET, ANALYST_TYPE_MAPPING
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class AnalyticKGRenderer(BaseComponent):
|
|
8
10
|
"""
|
|
@@ -15,158 +17,7 @@ class AnalyticKGRenderer(BaseComponent):
|
|
|
15
17
|
|
|
16
18
|
component_name = "AnalyticKGRenderer"
|
|
17
19
|
|
|
18
|
-
STYLE_SHEET =
|
|
19
|
-
# [Global Nodes]
|
|
20
|
-
{
|
|
21
|
-
"selector": "node",
|
|
22
|
-
"style": {
|
|
23
|
-
"label": "data(label)",
|
|
24
|
-
"color": "#ecf0f1",
|
|
25
|
-
"font-size": "10px",
|
|
26
|
-
"text-valign": "center",
|
|
27
|
-
"text-halign": "center",
|
|
28
|
-
"text-wrap": "wrap",
|
|
29
|
-
"text-max-width": "100px",
|
|
30
|
-
"background-color": "#95a5a6",
|
|
31
|
-
"border-width": 1,
|
|
32
|
-
"border-color": "#7f8c8d",
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
# [File Node]
|
|
36
|
-
{
|
|
37
|
-
"selector": "node[type='file']",
|
|
38
|
-
"style": {
|
|
39
|
-
"shape": "rectangle",
|
|
40
|
-
"background-color": "#2c3e50",
|
|
41
|
-
"width": 60,
|
|
42
|
-
"height": 60,
|
|
43
|
-
"font-size": "12px",
|
|
44
|
-
"font-weight": "bold",
|
|
45
|
-
"border-width": 2,
|
|
46
|
-
"border-color": "#00d2d3",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
# [Class Node]
|
|
50
|
-
{
|
|
51
|
-
"selector": "node[type='class']",
|
|
52
|
-
"style": {
|
|
53
|
-
"shape": "diamond",
|
|
54
|
-
"background-color": "#8e44ad",
|
|
55
|
-
"width": 40,
|
|
56
|
-
"height": 40,
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
# [Method/Function]
|
|
60
|
-
{
|
|
61
|
-
"selector": "node[type='method'], node[type='function']",
|
|
62
|
-
"style": {
|
|
63
|
-
"shape": "ellipse",
|
|
64
|
-
"background-color": "#e67e22",
|
|
65
|
-
"width": 25,
|
|
66
|
-
"height": 25,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
# [Code Chunk]
|
|
70
|
-
{
|
|
71
|
-
"selector": "node[type='code_block']",
|
|
72
|
-
"style": {
|
|
73
|
-
"shape": "round-rectangle",
|
|
74
|
-
"background-color": "#7f8c8d",
|
|
75
|
-
"width": 15,
|
|
76
|
-
"height": 15,
|
|
77
|
-
"label": "",
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
# [Package/Library]
|
|
81
|
-
{
|
|
82
|
-
"selector": "node[type='library'], node[type='package']",
|
|
83
|
-
"style": {
|
|
84
|
-
"shape": "hexagon",
|
|
85
|
-
"background-color": "#16a085",
|
|
86
|
-
"width": 50,
|
|
87
|
-
"height": 50,
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
# [Edges]
|
|
91
|
-
{
|
|
92
|
-
"selector": "edge",
|
|
93
|
-
"style": {
|
|
94
|
-
"width": 1,
|
|
95
|
-
"curve-style": "bezier",
|
|
96
|
-
"opacity": 0.6,
|
|
97
|
-
"arrow-scale": 1,
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
# 1. Structure Line (contains) -> Gray Dashed Line (Skeleton)
|
|
101
|
-
{
|
|
102
|
-
"selector": "edge[edgeType='sayou:contains']",
|
|
103
|
-
"style": {
|
|
104
|
-
"line-color": "#7f8c8d",
|
|
105
|
-
"target-arrow-color": "#7f8c8d",
|
|
106
|
-
"target-arrow-shape": "circle",
|
|
107
|
-
"width": 1.5,
|
|
108
|
-
"line-style": "dashed",
|
|
109
|
-
"opacity": 0.7,
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
# 2. Logic Line (imports) -> Cyan Dashed Line (Flow)
|
|
113
|
-
{
|
|
114
|
-
"selector": "edge[edgeType='sayou:imports']",
|
|
115
|
-
"style": {
|
|
116
|
-
"line-color": "#00d2d3",
|
|
117
|
-
"target-arrow-color": "#00d2d3",
|
|
118
|
-
"target-arrow-shape": "triangle",
|
|
119
|
-
"line-style": "dashed",
|
|
120
|
-
"width": 2,
|
|
121
|
-
"opacity": 0.9,
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
# 3. Inheritance Line (inherits) -> Red Solid Line
|
|
125
|
-
{
|
|
126
|
-
"selector": "edge[edgeType='sayou:inherits']",
|
|
127
|
-
"style": {
|
|
128
|
-
"line-color": "#ff6b6b",
|
|
129
|
-
"target-arrow-color": "#ff6b6b",
|
|
130
|
-
"target-arrow-shape": "triangle",
|
|
131
|
-
"width": 3,
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
# [Interaction]
|
|
135
|
-
{
|
|
136
|
-
"selector": ".highlighted",
|
|
137
|
-
"style": {
|
|
138
|
-
"background-color": "#f1c40f",
|
|
139
|
-
"line-color": "#f1c40f",
|
|
140
|
-
"target-arrow-color": "#f1c40f",
|
|
141
|
-
"opacity": 1,
|
|
142
|
-
"z-index": 999,
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"selector": ".faded",
|
|
147
|
-
"style": {"opacity": 0.05, "label": ""},
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"selector": ".found",
|
|
151
|
-
"style": {
|
|
152
|
-
"border-width": 4,
|
|
153
|
-
"border-color": "#e056fd",
|
|
154
|
-
"background-color": "#e056fd",
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"selector": "node.no-label",
|
|
159
|
-
"style": {
|
|
160
|
-
"text-opacity": 0,
|
|
161
|
-
"text-background-opacity": 0,
|
|
162
|
-
"text-border-opacity": 0,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"selector": "edge.hidden-edge",
|
|
167
|
-
"style": {"display": "none"},
|
|
168
|
-
},
|
|
169
|
-
]
|
|
20
|
+
STYLE_SHEET = ANALYST_STYLE_SHEET
|
|
170
21
|
|
|
171
22
|
def render(self, json_path: str, output_path: str = "sayou_analyst_view.html"):
|
|
172
23
|
if not os.path.exists(json_path):
|
|
@@ -177,57 +28,38 @@ class AnalyticKGRenderer(BaseComponent):
|
|
|
177
28
|
|
|
178
29
|
elements = []
|
|
179
30
|
|
|
180
|
-
# 1. Nodes
|
|
31
|
+
# 1. Nodes Processing
|
|
181
32
|
for node in raw_data.get("nodes", []):
|
|
182
33
|
node_id = node.get("node_id")
|
|
183
34
|
attrs = node.get("attributes", {})
|
|
184
|
-
n_cls = node.get("node_class", "unknown")
|
|
185
|
-
|
|
186
|
-
#
|
|
187
|
-
cy_type = "unknown"
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
elif "method" in n_cls:
|
|
193
|
-
cy_type = "method"
|
|
194
|
-
elif "function" in n_cls:
|
|
195
|
-
cy_type = "function"
|
|
196
|
-
elif "library" in n_cls:
|
|
197
|
-
cy_type = "library"
|
|
198
|
-
elif "code" in n_cls:
|
|
199
|
-
cy_type = "code_block"
|
|
200
|
-
|
|
201
|
-
# Labeling
|
|
202
|
-
label = attrs.get("label") or node.get("friendly_name") or node_id
|
|
203
|
-
if cy_type == "file":
|
|
204
|
-
label = os.path.basename(attrs.get("sayou:filePath", label))
|
|
205
|
-
elif cy_type == "class":
|
|
206
|
-
label = attrs.get("meta:class_name", label)
|
|
207
|
-
elif cy_type in ["method", "function"]:
|
|
208
|
-
label = attrs.get("function_name", label)
|
|
209
|
-
|
|
210
|
-
# Code Text
|
|
211
|
-
code_text = attrs.get("schema:text", "")
|
|
35
|
+
n_cls = node.get("node_class", "unknown")
|
|
36
|
+
|
|
37
|
+
# [Pure Config Lookup]
|
|
38
|
+
cy_type = ANALYST_TYPE_MAPPING.get(n_cls, "unknown")
|
|
39
|
+
|
|
40
|
+
# [No Logic] Builder가 준 라벨을 그대로 사용
|
|
41
|
+
label = node.get("friendly_name") or attrs.get("label") or node_id
|
|
42
|
+
|
|
212
43
|
cy_data = {
|
|
213
44
|
"id": node_id,
|
|
214
45
|
"label": label,
|
|
215
46
|
"type": cy_type,
|
|
216
|
-
"code":
|
|
47
|
+
"code": attrs.get("schema:text", ""),
|
|
217
48
|
"meta": attrs,
|
|
218
49
|
}
|
|
219
50
|
elements.append({"group": "nodes", "data": cy_data})
|
|
220
51
|
|
|
221
|
-
# 2. Edges
|
|
52
|
+
# 2. Edges Processing
|
|
222
53
|
for edge in raw_data.get("edges", []):
|
|
54
|
+
e_type = edge.get("type", "relates")
|
|
223
55
|
elements.append(
|
|
224
56
|
{
|
|
225
57
|
"group": "edges",
|
|
226
58
|
"data": {
|
|
227
59
|
"source": edge.get("source"),
|
|
228
60
|
"target": edge.get("target"),
|
|
229
|
-
"edgeType":
|
|
230
|
-
"label":
|
|
61
|
+
"edgeType": e_type,
|
|
62
|
+
"label": e_type.split(":")[-1],
|
|
231
63
|
},
|
|
232
64
|
}
|
|
233
65
|
)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
|
|
3
4
|
from sayou.core.base_component import BaseComponent
|
|
4
5
|
|
|
6
|
+
from ..core.styles import HIDDEN_ATTR_PREFIXES, SHOWCASE_STYLE_MAP
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
class ShowcaseKGRenderer(BaseComponent):
|
|
7
10
|
"""
|
|
@@ -15,6 +18,7 @@ class ShowcaseKGRenderer(BaseComponent):
|
|
|
15
18
|
|
|
16
19
|
def render(self, json_path: str, output_path: str = "sayou_showcase_3d.html"):
|
|
17
20
|
if not os.path.exists(json_path):
|
|
21
|
+
self._log(f"❌ File not found: {json_path}", level="error")
|
|
18
22
|
return
|
|
19
23
|
|
|
20
24
|
with open(json_path, "r", encoding="utf-8") as f:
|
|
@@ -24,64 +28,44 @@ class ShowcaseKGRenderer(BaseComponent):
|
|
|
24
28
|
links = []
|
|
25
29
|
existing_ids = set()
|
|
26
30
|
|
|
31
|
+
# 1. Nodes Processing
|
|
27
32
|
for node in raw_data.get("nodes", []):
|
|
28
33
|
node_id = node.get("node_id")
|
|
34
|
+
if not node_id:
|
|
35
|
+
continue
|
|
29
36
|
existing_ids.add(node_id)
|
|
37
|
+
|
|
30
38
|
attrs = node.get("attributes", {})
|
|
31
|
-
n_cls = node.get("node_class", "unknown")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
val =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
val = 20
|
|
41
|
-
elif "class" in n_cls:
|
|
42
|
-
group = "Header"
|
|
43
|
-
color = "#ff6b81" # Pink
|
|
44
|
-
val = 12
|
|
45
|
-
elif "method" in n_cls or "function" in n_cls:
|
|
46
|
-
group = "Code"
|
|
47
|
-
color = "#feca57" # Gold
|
|
48
|
-
val = 6
|
|
49
|
-
elif "library" in n_cls:
|
|
50
|
-
group = "Library"
|
|
51
|
-
color = "#2ed573" # Green
|
|
52
|
-
val = 10
|
|
53
|
-
|
|
54
|
-
label = attrs.get("label") or node.get("friendly_name") or node_id
|
|
55
|
-
if group == "Document":
|
|
56
|
-
label = os.path.basename(attrs.get("sayou:filePath", label))
|
|
57
|
-
|
|
58
|
-
clean_attrs = {}
|
|
59
|
-
for k, v in attrs.items():
|
|
60
|
-
if isinstance(v, str) and len(v) > 200:
|
|
61
|
-
clean_attrs[k] = v[:200] + "..."
|
|
62
|
-
elif not k.startswith("sayou:"):
|
|
63
|
-
clean_attrs[k] = v
|
|
39
|
+
n_cls = node.get("node_class", "unknown")
|
|
40
|
+
|
|
41
|
+
style = SHOWCASE_STYLE_MAP.get(n_cls, SHOWCASE_STYLE_MAP["default"])
|
|
42
|
+
|
|
43
|
+
val = attrs.get("val", style["val"])
|
|
44
|
+
|
|
45
|
+
label = node.get("friendly_name") or attrs.get("label") or node_id
|
|
46
|
+
|
|
47
|
+
clean_attrs = self._clean_attributes(attrs)
|
|
64
48
|
|
|
65
49
|
nodes.append(
|
|
66
50
|
{
|
|
67
51
|
"id": node_id,
|
|
68
52
|
"label": label,
|
|
69
|
-
"group": group,
|
|
70
|
-
"color": color,
|
|
53
|
+
"group": style["group"],
|
|
54
|
+
"color": style["color"],
|
|
71
55
|
"val": val,
|
|
72
56
|
"attributes": clean_attrs,
|
|
73
57
|
}
|
|
74
58
|
)
|
|
75
59
|
|
|
76
|
-
#
|
|
60
|
+
# 2. Edges Processing
|
|
77
61
|
for edge in raw_data.get("edges", []):
|
|
78
62
|
src = edge.get("source")
|
|
79
63
|
tgt = edge.get("target")
|
|
80
|
-
|
|
81
64
|
if src in existing_ids and tgt in existing_ids:
|
|
82
65
|
e_type = edge.get("type", "relates")
|
|
83
|
-
is_import =
|
|
84
|
-
|
|
66
|
+
is_import = any(
|
|
67
|
+
k in e_type for k in ["import", "calls", "next", "contains"]
|
|
68
|
+
)
|
|
85
69
|
links.append(
|
|
86
70
|
{
|
|
87
71
|
"source": src,
|
|
@@ -95,6 +79,19 @@ class ShowcaseKGRenderer(BaseComponent):
|
|
|
95
79
|
self._generate_html(graph_data, output_path)
|
|
96
80
|
self._log(f"✅ Final Visual Showcase generated at: {output_path}")
|
|
97
81
|
|
|
82
|
+
def _clean_attributes(self, attrs):
|
|
83
|
+
"""설정 파일 기반 속성 정제"""
|
|
84
|
+
clean = {}
|
|
85
|
+
for k, v in attrs.items():
|
|
86
|
+
if any(k.startswith(prefix) for prefix in HIDDEN_ATTR_PREFIXES):
|
|
87
|
+
continue
|
|
88
|
+
s = str(v)
|
|
89
|
+
if len(s) > 200:
|
|
90
|
+
clean[k] = s[:200] + "..."
|
|
91
|
+
else:
|
|
92
|
+
clean[k] = v
|
|
93
|
+
return clean
|
|
94
|
+
|
|
98
95
|
def _generate_html(self, graph_data, output_path):
|
|
99
96
|
json_str = json.dumps(graph_data)
|
|
100
97
|
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# sayou-visualizer
|
|
2
|
-
|
|
3
|
-
[](https://pypi.org/project/sayou-visualizer/)
|
|
4
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
5
|
-
|
|
6
|
-
**The Interactive Observability Engine for Sayou Fabric.**
|
|
7
|
-
|
|
8
|
-
`sayou-visualizer` provides a transparent layer to monitor and visualize the execution flow of Sayou components. By attaching to any pipeline, it transforms invisible execution logs into intuitive, interactive **HTML Knowledge Graphs**.
|
|
9
|
-
|
|
10
|
-
It separates the logic of **Observation** (Tracer) from **Presentation** (Renderer), allowing you to debug complex pipelines and visualize data lineage without modifying your core logic.
|
|
11
|
-
|
|
12
|
-
## 💡 Core Philosophy
|
|
13
|
-
|
|
14
|
-
**"Trace the Process, Render the Insight."**
|
|
15
|
-
|
|
16
|
-
Observability should not be an afterthought. We decouple the responsibility into two roles:
|
|
17
|
-
|
|
18
|
-
1. **Tracer (Recorder)**: The "Camera". It silently observes events (`on_start`, `on_finish`) from the pipeline via the Callback system and builds an internal graph structure.
|
|
19
|
-
|
|
20
|
-
2. **Renderer (Painter)**: The "Canvas". It takes the recorded graph and generates human-readable artifacts (e.g., Interactive HTML, Static Images).
|
|
21
|
-
|
|
22
|
-
This separation enables a Non-intrusive Monitoring experience, where visualization is just a plug-and-play feature.
|
|
23
|
-
|
|
24
|
-
## 📦 Installation
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
pip install sayou-visualizer
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## ⚡ Quick Start
|
|
31
|
-
|
|
32
|
-
The `VisualizerPipeline` acts as a facade, easily attaching to other pipelines to generate reports.
|
|
33
|
-
|
|
34
|
-
```python
|
|
35
|
-
from sayou.connector.pipeline import ConnectorPipeline
|
|
36
|
-
from sayou.visualizer.pipeline import VisualizerPipeline
|
|
37
|
-
|
|
38
|
-
def main():
|
|
39
|
-
connector = ConnectorPipeline()
|
|
40
|
-
|
|
41
|
-
viz = VisualizerPipeline()
|
|
42
|
-
viz.attach_to(connector)
|
|
43
|
-
|
|
44
|
-
print("🚀 Running Pipeline...")
|
|
45
|
-
iterator = connector.run("http://example.com")
|
|
46
|
-
for packet in iterator:
|
|
47
|
-
print(f"Processed: {packet.task.uri}")
|
|
48
|
-
|
|
49
|
-
print("🎨 Generating Report...")
|
|
50
|
-
viz.report("examples/pipeline_flow.html")
|
|
51
|
-
|
|
52
|
-
if __name__ == "__main__":
|
|
53
|
-
main()
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## 🔑 Key Concepts
|
|
57
|
-
|
|
58
|
-
### Tracers
|
|
59
|
-
* **`GraphTracer`**: Listens to pipeline events and constructs a `NetworkX` Directed Acyclic Graph (DAG) in real-time. It distinguishes between Components (Generator/Fetcher) and Data (Tasks).
|
|
60
|
-
|
|
61
|
-
### Renderers
|
|
62
|
-
* **`PyVisRenderer`**: Converts the internal graph into an interactive HTML file powered by `Vis.js`. Features physics-based layout and modern dark UI.
|
|
63
|
-
* **`RichRenderer`** (_Planned_): Displays a tree-structure summary directly in the console using the `Rich` library.
|
|
64
|
-
|
|
65
|
-
## 🤝 Contributing
|
|
66
|
-
|
|
67
|
-
We welcome contributions for new Renderers (e.g., `MatplotlibRenderer`, `StreamlitRenderer`) or specialized Tracers for new components!
|
|
68
|
-
|
|
69
|
-
## 📜 License
|
|
70
|
-
|
|
71
|
-
Apache 2.0 License © 2025 Sayouzone
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/interfaces/base_renderer.py
RENAMED
|
File without changes
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from sayou.core.base_component import BaseComponent
|
|
2
2
|
|
|
3
3
|
from .renderer.analytic_kg_renderer import AnalyticKGRenderer
|
|
4
|
-
from .renderer.showcase_kg_renderer import ShowcaseKGRenderer
|
|
5
4
|
from .renderer.pyvis_renderer import PyVisRenderer
|
|
5
|
+
from .renderer.showcase_kg_renderer import ShowcaseKGRenderer
|
|
6
6
|
from .tracer.graph_tracer import GraphTracer
|
|
7
7
|
from .tracer.rich_tracer import RichConsoleTracer
|
|
8
8
|
from .tracer.websocket_tracer import WebSocketTracer
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/renderer/pyvis_renderer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/graph_tracer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/rich_tracer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.1.0}/src/sayou/visualizer/tracer/websocket_tracer.py
RENAMED
|
File without changes
|