sayou-visualizer 0.0.11__py3-none-any.whl → 0.1.0__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,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
+ ]
@@ -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
@@ -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 (No Parents logic)
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").lower()
185
-
186
- # Type Check
187
- cy_type = "unknown"
188
- if "file" in n_cls:
189
- cy_type = "file"
190
- elif "class" in n_cls:
191
- cy_type = "class"
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": code_text,
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": edge.get("type", "relates"),
230
- "label": edge.get("type", "").split(":")[-1],
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").lower()
32
-
33
- group = "Chunk"
34
- color = "#4a69bd"
35
- val = 3
36
-
37
- if "file" in n_cls or "package" in n_cls:
38
- group = "Document"
39
- color = "#00d2d3" # Cyan
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
- # [2] Edge data processing
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 = "import" in e_type or "calls" in e_type
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sayou-visualizer
3
- Version: 0.0.11
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.9
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.3.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 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**.
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 separates the logic of **Observation** (Tracer) from **Presentation** (Renderer), allowing you to debug complex pipelines and visualize data lineage without modifying your core logic.
233
+ It serves two distinct purposes: **Pipeline Telemetry** (Debugging flow) and **Knowledge Rendering** (Showcasing data topology).
234
234
 
235
- ## 💡 Core Philosophy
235
+ ---
236
236
 
237
- **"Trace the Process, Render the Insight."**
237
+ ## 1. Architecture & Role
238
238
 
239
- Observability should not be an afterthought. We decouple the responsibility into two roles:
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
- 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.
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. **Renderer (Painter)**: The "Canvas". It takes the recorded graph and generates human-readable artifacts (e.g., Interactive HTML, Static Images).
262
+ ## 2. Available Strategies
244
263
 
245
- This separation enables a Non-intrusive Monitoring experience, where visualization is just a plug-and-play feature.
264
+ `sayou-visualizer` offers specialized views depending on who is looking at the data.
246
265
 
247
- ## 📦 Installation
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
- ## ⚡ Quick Start
280
+ ---
281
+
282
+ ## 4. Usage
254
283
 
255
- The `VisualizerPipeline` acts as a facade, easily attaching to other pipelines to generate reports.
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.connector.pipeline import ConnectorPipeline
259
- from sayou.visualizer.pipeline import VisualizerPipeline
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
- def main():
262
- connector = ConnectorPipeline()
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
- viz = VisualizerPipeline()
265
- viz.attach_to(connector)
326
+ connector = ConnectorPipeline()
266
327
 
267
- print("🚀 Running Pipeline...")
268
- iterator = connector.run("http://example.com")
269
- for packet in iterator:
270
- print(f"Processed: {packet.task.uri}")
328
+ viz = VisualizerPipeline()
329
+ viz.attach_to(connector)
271
330
 
272
- print("🎨 Generating Report...")
273
- viz.report("examples/pipeline_flow.html")
331
+ connector.process(source="https://news.daum.net/tech", strategy="web")
274
332
 
275
- if __name__ == "__main__":
276
- main()
333
+ viz.report("pipeline_trace.html")
277
334
  ```
278
335
 
279
- ## 🔑 Key Concepts
336
+ ---
280
337
 
281
- ### Tracers
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
- ### Renderers
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
- ## 🤝 Contributing
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
- We welcome contributions for new Renderers (e.g., `MatplotlibRenderer`, `StreamlitRenderer`) or specialized Tracers for new components!
346
+ ---
291
347
 
292
- ## 📜 License
348
+ ## 6. License
293
349
 
294
- Apache 2.0 License © 2025 Sayouzone
350
+ Apache 2.0 License © 2026 **Sayouzone**
@@ -1,14 +1,15 @@
1
1
  sayou/visualizer/__init__.py,sha256=DRv-5qzP6nal7qXVf7Zl67CQx3Kf3mTZhlLKl-vs_G0,82
2
- sayou/visualizer/pipeline.py,sha256=LduZlz5jGqTfzRRuv3W-IFfj1VxjjTkXAwXL6zs-yQE,4116
2
+ sayou/visualizer/pipeline.py,sha256=NWeIwQqp6ctP-xnhYEPdRwcLQ0RkYSmGRX-my_898GE,4116
3
3
  sayou/visualizer/core/exceptions.py,sha256=Mk5UtIfim7i9688c4qAKP7kB1GpLPM29t94HbQM9fhw,99
4
4
  sayou/visualizer/core/schemas.py,sha256=qn44BINevFZF_ALBhh20DS4GyMo5HV3UzqY4UTh_p3A,381
5
+ sayou/visualizer/core/styles.py,sha256=ZyMqzu9Xk-TY1xpkHeGZb0qkElG7MyHyYEpqFWXig2U,6285
5
6
  sayou/visualizer/interfaces/base_renderer.py,sha256=orllTXlqM4-wDemOWbcZX8zF708KOdWFgoqZh8MeAzE,760
6
- sayou/visualizer/renderer/analytic_kg_renderer.py,sha256=I5ccv7JUCGvPE79c2d1O-XuYwrK3fxk9qj4Xzyx_WLg,16404
7
+ sayou/visualizer/renderer/analytic_kg_renderer.py,sha256=5lNhllAe4WLf3-vc_Gg1DEpRbKWGCFBEvAwZGpncRWU,11246
7
8
  sayou/visualizer/renderer/pyvis_renderer.py,sha256=2HKv_qAKKNHMKLwC7xoIn3EZ5oFLpgds7LPgK4EeXfA,2408
8
- sayou/visualizer/renderer/showcase_kg_renderer.py,sha256=_K9GjAPuKzA-BKbJYDK0Ku0U8tThusuqgwAwhdtaprU,11643
9
+ sayou/visualizer/renderer/showcase_kg_renderer.py,sha256=P1OoKOsmAJFdP1weWWOD6EIINY_prfB135j5PFQ9a4E,11489
9
10
  sayou/visualizer/tracer/graph_tracer.py,sha256=j0dqd0_67ZnQCNjn5siKHXXsXasWim9olYqUQA2jKxk,3638
10
11
  sayou/visualizer/tracer/rich_tracer.py,sha256=ik7J1P7AMTN47lkjMLE7iTlRuksUpwSKluvWdpY6kdQ,2406
11
12
  sayou/visualizer/tracer/websocket_tracer.py,sha256=OZLg4jTfuxp6IwDacmAACKZ_0FirZFhyLysqh9QyrJA,1626
12
- sayou_visualizer-0.0.11.dist-info/METADATA,sha256=0wlBaqJxYAqGoTx4B7vRusfBxQIwSKJFnrt36ad74bw,16681
13
- sayou_visualizer-0.0.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
- sayou_visualizer-0.0.11.dist-info/RECORD,,
13
+ sayou_visualizer-0.1.0.dist-info/METADATA,sha256=kFw0i1bXdB4Oah8nPKCHadjrWYvWvX7raUyfMlS-UEU,17805
14
+ sayou_visualizer-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
15
+ sayou_visualizer-0.1.0.dist-info/RECORD,,