sayou-visualizer 0.0.11__tar.gz → 0.0.12__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.0.12}/PKG-INFO +1 -1
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/pyproject.toml +1 -1
- sayou_visualizer-0.0.12/src/sayou/visualizer/core/styles.py +223 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/renderer/analytic_kg_renderer.py +17 -185
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/renderer/showcase_kg_renderer.py +36 -39
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/.gitignore +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/README.md +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/examples/quick_start.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/examples/quick_start_ws_client.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/examples/quick_start_ws_server.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/__init__.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/core/exceptions.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/core/schemas.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/interfaces/base_renderer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/pipeline.py +1 -1
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/renderer/pyvis_renderer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/graph_tracer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/rich_tracer.py +0 -0
- {sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/websocket_tracer.py +0 -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
|
|
|
File without changes
|
|
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.0.12}/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.0.12}/src/sayou/visualizer/renderer/pyvis_renderer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/graph_tracer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/rich_tracer.py
RENAMED
|
File without changes
|
{sayou_visualizer-0.0.11 → sayou_visualizer-0.0.12}/src/sayou/visualizer/tracer/websocket_tracer.py
RENAMED
|
File without changes
|