sayou-visualizer 0.0.11__py3-none-any.whl → 0.0.12__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.0.12
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/
@@ -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.0.12.dist-info/METADATA,sha256=l6O1MyvZrMebDZ5OGY9wbEJSVj2B7gUCiz_0wOVzTXA,16681
14
+ sayou_visualizer-0.0.12.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
15
+ sayou_visualizer-0.0.12.dist-info/RECORD,,