-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathknowledge_graph.html
More file actions
237 lines (229 loc) · 42 KB
/
Copy pathknowledge_graph.html
File metadata and controls
237 lines (229 loc) · 42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>RepoCourse · 知识关系图谱</title>
<style>
html, body { margin:0; height:100%; overflow:hidden; background:#ffffff;
font-family:"Segoe UI","Microsoft YaHei",sans-serif; }
#svg { width:100vw; height:100vh; display:block; cursor:grab; }
#svg.dragging { cursor:grabbing; }
.edge { stroke:#c7a5e6; stroke-width:1.4; pointer-events:none; }
.edge.hubedge { stroke:#d8c4ee; stroke-width:1.2; }
.node-label { fill:#111; font-size:11px; user-select:none; pointer-events:none; }
.dim { opacity:.16; }
#legend { position:fixed; left:16px; bottom:14px; font-size:12px; color:#555;
background:rgba(255,255,255,.94); border:1px solid #eee; border-radius:10px; padding:10px 14px; }
#legend span { margin-right:12px; }
#legend i { display:inline-block; width:10px; height:10px; border-radius:50%; margin-right:4px; }
#stats { position:fixed; right:16px; top:14px; font-size:12px; color:#777;
background:rgba(255,255,255,.94); border:1px solid #eee; border-radius:10px; padding:8px 12px; }
#btn { position:fixed; right:16px; bottom:14px; font-size:12px; color:#555; background:#fff;
border:1px solid #ddd; border-radius:8px; padding:6px 12px; cursor:pointer; }
#btn:hover { background:#f5f0ff; }
</style>
</head>
<body>
<svg id="svg"></svg>
<div id="legend">
<span><i style="background:#8a2be2"></i>项目</span>
<span><i style="background:#7c3aed"></i>我的技能</span>
<span><i style="background:#4b5563"></i>技术</span>
<span><i style="background:#9ca3af"></i>文件</span>
<span><i style="background:#d1d5db"></i>知识点</span>
</div>
<div id="stats"></div>
<div id="btn">重新布局</div>
<script>
var DATA = {"version": 1, "project": "ai-project-reviewer", "generated_at": "2026-08-15T18:37:22", "stats": {"total_nodes": 130, "total_relations": 142, "file": 11, "tech": 27, "topic": 75, "skill": 17}, "nodes": [{"id": "file:apr/digest.py", "kind": "file", "name": "apr/digest.py", "properties": {}}, {"id": "file:apr/knowledge/knowledge.py", "kind": "file", "name": "apr/knowledge/knowledge.py", "properties": {"ai_contribution": 0.0, "ai_classification": "疑似人工"}}, {"id": "file:knowledge_graph-mindmap.md", "kind": "file", "name": "knowledge_graph-mindmap.md", "properties": {"ai_contribution": 0.0, "ai_classification": "疑似人工"}}, {"id": "file:learning_plan.json", "kind": "file", "name": "learning_plan.json", "properties": {}}, {"id": "file:tests/test_blindspot.py", "kind": "file", "name": "tests/test_blindspot.py", "properties": {"ai_contribution": 0.0, "ai_classification": "疑似人工"}}, {"id": "file:tests/test_coach.py", "kind": "file", "name": "tests/test_coach.py", "properties": {"ai_contribution": 0.0, "ai_classification": "疑似人工"}}, {"id": "file:tests/test_event_bridge.py", "kind": "file", "name": "tests/test_event_bridge.py", "properties": {}}, {"id": "file:tests/test_knowledge.py", "kind": "file", "name": "tests/test_knowledge.py", "properties": {"ai_contribution": 0.0, "ai_classification": "疑似人工"}}, {"id": "file:tests/test_learning_canvas.py", "kind": "file", "name": "tests/test_learning_canvas.py", "properties": {}}, {"id": "file:tests/test_learning_report.py", "kind": "file", "name": "tests/test_learning_report.py", "properties": {}}, {"id": "file:tests/test_report_route.py", "kind": "file", "name": "tests/test_report_route.py", "properties": {}}, {"id": "skill:AI Agent", "kind": "skill", "name": "AI Agent", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:AI Agent工程", "kind": "skill", "name": "AI Agent工程", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:C", "kind": "skill", "name": "C", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:Docker", "kind": "skill", "name": "Docker", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:Git", "kind": "skill", "name": "Git", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:HTML/CSS", "kind": "skill", "name": "HTML/CSS", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:Java", "kind": "skill", "name": "Java", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:JavaScript", "kind": "skill", "name": "JavaScript", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:Java后端开发", "kind": "skill", "name": "Java后端开发", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:MCP", "kind": "skill", "name": "MCP", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:MySQL", "kind": "skill", "name": "MySQL", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:Python", "kind": "skill", "name": "Python", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.9, "mastery_percent": 36}}, {"id": "skill:Redis", "kind": "skill", "name": "Redis", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:Spring Boot", "kind": "skill", "name": "Spring Boot", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:Spring生态", "kind": "skill", "name": "Spring生态", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "skill:Vue", "kind": "skill", "name": "Vue", "properties": {"claimed_level": "beginner", "level": "beginner", "confidence": 0.39, "mastery_percent": 16}}, {"id": "skill:数据库设计", "kind": "skill", "name": "数据库设计", "properties": {"level": "beginner", "confidence": 0.35, "claimed_level": null, "mastery_percent": 14}}, {"id": "tech:AI Agent", "kind": "tech", "name": "AI Agent", "properties": {"from_profile": true}}, {"id": "tech:C", "kind": "tech", "name": "C", "properties": {"from_profile": true}}, {"id": "tech:Django", "kind": "tech", "name": "Django", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Elasticsearch", "kind": "tech", "name": "Elasticsearch", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:FastAPI", "kind": "tech", "name": "FastAPI", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Git", "kind": "tech", "name": "Git", "properties": {"from_profile": true}}, {"id": "tech:HTML/CSS", "kind": "tech", "name": "HTML/CSS", "properties": {"from_profile": true}}, {"id": "tech:JSON", "kind": "tech", "name": "JSON", "properties": {"file_count": 1}}, {"id": "tech:JWT", "kind": "tech", "name": "JWT", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Java", "kind": "tech", "name": "Java", "properties": {"from_profile": true}}, {"id": "tech:JavaScript", "kind": "tech", "name": "JavaScript", "properties": {"from_profile": true}}, {"id": "tech:Kafka", "kind": "tech", "name": "Kafka", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Markdown", "kind": "tech", "name": "Markdown", "properties": {"file_count": 3}}, {"id": "tech:MongoDB", "kind": "tech", "name": "MongoDB", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:MyBatis", "kind": "tech", "name": "MyBatis", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:MySQL", "kind": "tech", "name": "MySQL", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Python", "kind": "tech", "name": "Python", "properties": {"file_count": 67}}, {"id": "tech:REST API", "kind": "tech", "name": "REST API", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:React", "kind": "tech", "name": "React", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Redis", "kind": "tech", "name": "Redis", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Spring", "kind": "tech", "name": "Spring", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:Spring Boot", "kind": "tech", "name": "Spring Boot", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:TOML", "kind": "tech", "name": "TOML", "properties": {"file_count": 1}}, {"id": "tech:Vue", "kind": "tech", "name": "Vue", "properties": {"avg_ai_contribution": 0.0}}, {"id": "tech:YAML", "kind": "tech", "name": "YAML", "properties": {"file_count": 1}}, {"id": "tech:example", "kind": "tech", "name": "example", "properties": {"file_count": 2}}, {"id": "tech:other", "kind": "tech", "name": "other", "properties": {"file_count": 3}}, {"id": "topic:AOP", "kind": "topic", "name": "AOP", "properties": {}}, {"id": "topic:Actuator", "kind": "topic", "name": "Actuator", "properties": {}}, {"id": "topic:Admin", "kind": "topic", "name": "Admin", "properties": {}}, {"id": "topic:Agent", "kind": "topic", "name": "Agent", "properties": {"from_profile": true}}, {"id": "topic:Bean 生命周期", "kind": "topic", "name": "Bean 生命周期", "properties": {}}, {"id": "topic:CRUD", "kind": "topic", "name": "CRUD", "properties": {"from_profile": true}}, {"id": "topic:Controller", "kind": "topic", "name": "Controller", "properties": {"from_profile": true}}, {"id": "topic:DSL 查询", "kind": "topic", "name": "DSL 查询", "properties": {}}, {"id": "topic:HTTP 语义", "kind": "topic", "name": "HTTP 语义", "properties": {}}, {"id": "topic:Hooks", "kind": "topic", "name": "Hooks", "properties": {}}, {"id": "topic:IO", "kind": "topic", "name": "IO", "properties": {"from_profile": true}}, {"id": "topic:IoC/DI", "kind": "topic", "name": "IoC/DI", "properties": {}}, {"id": "topic:Key 设计", "kind": "topic", "name": "Key 设计", "properties": {}}, {"id": "topic:MTV 架构", "kind": "topic", "name": "MTV 架构", "properties": {}}, {"id": "topic:ORM", "kind": "topic", "name": "ORM", "properties": {}}, {"id": "topic:Prompt", "kind": "topic", "name": "Prompt", "properties": {"from_profile": true}}, {"id": "topic:Pydantic", "kind": "topic", "name": "Pydantic", "properties": {}}, {"id": "topic:REST API", "kind": "topic", "name": "REST API", "properties": {"from_profile": true}}, {"id": "topic:SQL 优化", "kind": "topic", "name": "SQL 优化", "properties": {}}, {"id": "topic:SQL 映射", "kind": "topic", "name": "SQL 映射", "properties": {}}, {"id": "topic:Service", "kind": "topic", "name": "Service", "properties": {"from_profile": true}}, {"id": "topic:Tool Calling", "kind": "topic", "name": "Tool Calling", "properties": {"from_profile": true}}, {"id": "topic:Vite", "kind": "topic", "name": "Vite", "properties": {"from_profile": true}}, {"id": "topic:Vue 3", "kind": "topic", "name": "Vue 3", "properties": {"from_profile": true}}, {"id": "topic:add", "kind": "topic", "name": "add", "properties": {"from_profile": true}}, {"id": "topic:branch", "kind": "topic", "name": "branch", "properties": {"from_profile": true}}, {"id": "topic:clone", "kind": "topic", "name": "clone", "properties": {"from_profile": true}}, {"id": "topic:commit", "kind": "topic", "name": "commit", "properties": {"from_profile": true}}, {"id": "topic:push", "kind": "topic", "name": "push", "properties": {"from_profile": true}}, {"id": "topic:一级/二级缓存", "kind": "topic", "name": "一级/二级缓存", "properties": {}}, {"id": "topic:上下文管理", "kind": "topic", "name": "上下文管理", "properties": {"from_profile": true}}, {"id": "topic:中间件", "kind": "topic", "name": "中间件", "properties": {}}, {"id": "topic:事务", "kind": "topic", "name": "事务", "properties": {}}, {"id": "topic:事务管理", "kind": "topic", "name": "事务管理", "properties": {}}, {"id": "topic:令牌结构", "kind": "topic", "name": "令牌结构", "properties": {}}, {"id": "topic:依赖注入", "kind": "topic", "name": "依赖注入", "properties": {}}, {"id": "topic:倒排索引", "kind": "topic", "name": "倒排索引", "properties": {}}, {"id": "topic:函数", "kind": "topic", "name": "函数", "properties": {"from_profile": true}}, {"id": "topic:分区与偏移", "kind": "topic", "name": "分区与偏移", "properties": {}}, {"id": "topic:分词", "kind": "topic", "name": "分词", "properties": {}}, {"id": "topic:分页", "kind": "topic", "name": "分页", "properties": {}}, {"id": "topic:刷新机制", "kind": "topic", "name": "刷新机制", "properties": {}}, {"id": "topic:动态 SQL", "kind": "topic", "name": "动态 SQL", "properties": {}}, {"id": "topic:变量", "kind": "topic", "name": "变量", "properties": {"from_profile": true}}, {"id": "topic:响应式", "kind": "topic", "name": "响应式", "properties": {}}, {"id": "topic:基础SQL", "kind": "topic", "name": "基础SQL", "properties": {"from_profile": true}}, {"id": "topic:基础状态与事件", "kind": "topic", "name": "基础状态与事件", "properties": {"from_profile": true}}, {"id": "topic:基础语法", "kind": "topic", "name": "基础语法", "properties": {"from_profile": true}}, {"id": "topic:基础项目开发", "kind": "topic", "name": "基础项目开发", "properties": {"from_profile": true}}, {"id": "topic:异常", "kind": "topic", "name": "异常", "properties": {"from_profile": true}}, {"id": "topic:异步", "kind": "topic", "name": "异步", "properties": {}}, {"id": "topic:文件处理", "kind": "topic", "name": "文件处理", "properties": {"from_profile": true}}, {"id": "topic:文档模型", "kind": "topic", "name": "文档模型", "properties": {}}, {"id": "topic:条件与循环", "kind": "topic", "name": "条件与循环", "properties": {"from_profile": true}}, {"id": "topic:消息可靠性", "kind": "topic", "name": "消息可靠性", "properties": {}}, {"id": "topic:状态码", "kind": "topic", "name": "状态码", "properties": {}}, {"id": "topic:状态管理", "kind": "topic", "name": "状态管理", "properties": {}}, {"id": "topic:生产者/消费者", "kind": "topic", "name": "生产者/消费者", "properties": {}}, {"id": "topic:签名验证", "kind": "topic", "name": "签名验证", "properties": {}}, {"id": "topic:索引", "kind": "topic", "name": "索引", "properties": {}}, {"id": "topic:组件", "kind": "topic", "name": "组件", "properties": {"from_profile": true}}, {"id": "topic:缓存", "kind": "topic", "name": "缓存", "properties": {}}, {"id": "topic:缓存穿透/击穿/雪崩", "kind": "topic", "name": "缓存穿透/击穿/雪崩", "properties": {}}, {"id": "topic:聚合查询", "kind": "topic", "name": "聚合查询", "properties": {}}, {"id": "topic:自动配置", "kind": "topic", "name": "自动配置", "properties": {}}, {"id": "topic:虚拟 DOM", "kind": "topic", "name": "虚拟 DOM", "properties": {}}, {"id": "topic:表设计", "kind": "topic", "name": "表设计", "properties": {"from_profile": true}}, {"id": "topic:资源设计", "kind": "topic", "name": "资源设计", "properties": {}}, {"id": "topic:起步依赖", "kind": "topic", "name": "起步依赖", "properties": {}}, {"id": "topic:路由", "kind": "topic", "name": "路由", "properties": {}}, {"id": "topic:过期策略", "kind": "topic", "name": "过期策略", "properties": {}}, {"id": "topic:配置管理", "kind": "topic", "name": "配置管理", "properties": {}}, {"id": "topic:集合", "kind": "topic", "name": "集合", "properties": {"from_profile": true}}, {"id": "topic:面向对象", "kind": "topic", "name": "面向对象", "properties": {"from_profile": true}}, {"id": "topic:项目结构", "kind": "topic", "name": "项目结构", "properties": {"from_profile": true}}], "relations": [{"source": "file:apr/knowledge/knowledge.py", "target": "tech:Django", "kind": "uses", "detail": "检测到 django、settings.py、urlpatterns、ModelAdmin", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Elasticsearch", "kind": "uses", "detail": "检测到 ElasticsearchRestTemplate、RestHighLevelClient、elasticsearch", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:FastAPI", "kind": "uses", "detail": "检测到 FastAPI(、fastapi、APIRouter、Depends(", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:JWT", "kind": "uses", "detail": "检测到 Jwt、jwt、JsonWebToken、JJWT、@PreAuthorize", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Kafka", "kind": "uses", "detail": "检测到 KafkaTemplate、@KafkaListener、KafkaProducer、kafka-python", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:MongoDB", "kind": "uses", "detail": "检测到 MongoTemplate、mongodb、pymongo、MongoRepository、mongoengine", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:MyBatis", "kind": "uses", "detail": "检测到 SqlSessionFactory、mybatis、@Mapper、Mapper.xml", "confidence": 0.9}, {"source": "file:knowledge_graph-mindmap.md", "target": "tech:MySQL", "kind": "uses", "detail": "检测到 MyBatis", "confidence": 0.9}, {"source": "file:knowledge_graph-mindmap.md", "target": "tech:Markdown", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:learning_plan.json", "target": "tech:MySQL", "kind": "uses", "detail": "检测到 MyBatis", "confidence": 0.9}, {"source": "file:learning_plan.json", "target": "tech:JSON", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:MySQL", "kind": "uses", "detail": "检测到 JdbcTemplate、DataSource、jdbc:mysql、MyBatis、@Mapper", "confidence": 0.9}, {"source": "file:knowledge_graph-mindmap.md", "target": "tech:REST API", "kind": "uses", "detail": "检测到 FastAPI", "confidence": 0.9}, {"source": "file:learning_plan.json", "target": "tech:REST API", "kind": "uses", "detail": "检测到 FastAPI", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:REST API", "kind": "uses", "detail": "检测到 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@RequestMapping", "confidence": 0.9}, {"source": "file:apr/digest.py", "target": "tech:React", "kind": "uses", "detail": "检测到 jsx", "confidence": 0.9}, {"source": "file:apr/digest.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:React", "kind": "uses", "detail": "检测到 useState、useEffect、ReactDOM、createRoot、jsx", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate、StringRedisTemplate、Redisson、redisTemplate、@Cacheable", "confidence": 0.9}, {"source": "file:tests/test_blindspot.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_blindspot.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_coach.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_coach.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_event_bridge.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_event_bridge.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_knowledge.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate、redisTemplate", "confidence": 0.9}, {"source": "file:tests/test_knowledge.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_learning_canvas.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_learning_canvas.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_learning_report.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_learning_report.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:tests/test_report_route.py", "target": "tech:Redis", "kind": "uses", "detail": "检测到 RedisTemplate", "confidence": 0.9}, {"source": "file:tests/test_report_route.py", "target": "tech:Python", "kind": "written-in", "detail": "语言归属", "confidence": 1.0}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Spring", "kind": "uses", "detail": "检测到 @RestController、@Controller、@Service、@Autowired、@Component", "confidence": 0.9}, {"source": "file:tests/test_blindspot.py", "target": "tech:Spring", "kind": "uses", "detail": "检测到 @Service", "confidence": 0.9}, {"source": "file:tests/test_knowledge.py", "target": "tech:Spring", "kind": "uses", "detail": "检测到 @Service", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Spring Boot", "kind": "uses", "detail": "检测到 @SpringBootApplication、spring-boot-starter、SpringBootApplication", "confidence": 0.9}, {"source": "file:apr/knowledge/knowledge.py", "target": "tech:Vue", "kind": "uses", "detail": "检测到 createApp、<script setup>、ref(、reactive(、useRouter", "confidence": 0.9}, {"source": "tech:Django", "target": "topic:MTV 架构", "kind": "covers", "detail": "Django 核心知识点", "confidence": 1.0}, {"source": "tech:Django", "target": "topic:ORM", "kind": "covers", "detail": "Django 核心知识点", "confidence": 1.0}, {"source": "tech:Django", "target": "topic:中间件", "kind": "covers", "detail": "Django 核心知识点", "confidence": 1.0}, {"source": "tech:Django", "target": "topic:Admin", "kind": "covers", "detail": "Django 核心知识点", "confidence": 1.0}, {"source": "tech:Elasticsearch", "target": "topic:倒排索引", "kind": "covers", "detail": "Elasticsearch 核心知识点", "confidence": 1.0}, {"source": "tech:Elasticsearch", "target": "topic:DSL 查询", "kind": "covers", "detail": "Elasticsearch 核心知识点", "confidence": 1.0}, {"source": "tech:Elasticsearch", "target": "topic:分词", "kind": "covers", "detail": "Elasticsearch 核心知识点", "confidence": 1.0}, {"source": "tech:FastAPI", "target": "topic:路由", "kind": "covers", "detail": "FastAPI 核心知识点", "confidence": 1.0}, {"source": "tech:FastAPI", "target": "topic:依赖注入", "kind": "covers", "detail": "FastAPI 核心知识点", "confidence": 1.0}, {"source": "tech:FastAPI", "target": "topic:Pydantic", "kind": "covers", "detail": "FastAPI 核心知识点", "confidence": 1.0}, {"source": "tech:FastAPI", "target": "topic:异步", "kind": "covers", "detail": "FastAPI 核心知识点", "confidence": 1.0}, {"source": "tech:JWT", "target": "topic:令牌结构", "kind": "covers", "detail": "JWT 核心知识点", "confidence": 1.0}, {"source": "tech:JWT", "target": "topic:签名验证", "kind": "covers", "detail": "JWT 核心知识点", "confidence": 1.0}, {"source": "tech:JWT", "target": "topic:刷新机制", "kind": "covers", "detail": "JWT 核心知识点", "confidence": 1.0}, {"source": "tech:Kafka", "target": "topic:生产者/消费者", "kind": "covers", "detail": "Kafka 核心知识点", "confidence": 1.0}, {"source": "tech:Kafka", "target": "topic:分区与偏移", "kind": "covers", "detail": "Kafka 核心知识点", "confidence": 1.0}, {"source": "tech:Kafka", "target": "topic:消息可靠性", "kind": "covers", "detail": "Kafka 核心知识点", "confidence": 1.0}, {"source": "tech:MongoDB", "target": "topic:文档模型", "kind": "covers", "detail": "MongoDB 核心知识点", "confidence": 1.0}, {"source": "tech:MongoDB", "target": "topic:聚合查询", "kind": "covers", "detail": "MongoDB 核心知识点", "confidence": 1.0}, {"source": "tech:MongoDB", "target": "topic:索引", "kind": "covers", "detail": "MongoDB 核心知识点", "confidence": 1.0}, {"source": "tech:MyBatis", "target": "topic:SQL 映射", "kind": "covers", "detail": "MyBatis 核心知识点", "confidence": 1.0}, {"source": "tech:MyBatis", "target": "topic:动态 SQL", "kind": "covers", "detail": "MyBatis 核心知识点", "confidence": 1.0}, {"source": "tech:MyBatis", "target": "topic:一级/二级缓存", "kind": "covers", "detail": "MyBatis 核心知识点", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:表设计", "kind": "covers", "detail": "MySQL 核心知识点", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:索引", "kind": "covers", "detail": "MySQL 核心知识点", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:SQL 优化", "kind": "covers", "detail": "MySQL 核心知识点", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:事务", "kind": "covers", "detail": "MySQL 核心知识点", "confidence": 1.0}, {"source": "tech:REST API", "target": "topic:资源设计", "kind": "covers", "detail": "REST API 核心知识点", "confidence": 1.0}, {"source": "tech:REST API", "target": "topic:HTTP 语义", "kind": "covers", "detail": "REST API 核心知识点", "confidence": 1.0}, {"source": "tech:REST API", "target": "topic:状态码", "kind": "covers", "detail": "REST API 核心知识点", "confidence": 1.0}, {"source": "tech:REST API", "target": "topic:分页", "kind": "covers", "detail": "REST API 核心知识点", "confidence": 1.0}, {"source": "tech:React", "target": "topic:组件", "kind": "covers", "detail": "React 核心知识点", "confidence": 1.0}, {"source": "tech:React", "target": "topic:Hooks", "kind": "covers", "detail": "React 核心知识点", "confidence": 1.0}, {"source": "tech:React", "target": "topic:虚拟 DOM", "kind": "covers", "detail": "React 核心知识点", "confidence": 1.0}, {"source": "tech:React", "target": "topic:状态管理", "kind": "covers", "detail": "React 核心知识点", "confidence": 1.0}, {"source": "tech:Redis", "target": "topic:缓存", "kind": "covers", "detail": "Redis 核心知识点", "confidence": 1.0}, {"source": "tech:Redis", "target": "topic:Key 设计", "kind": "covers", "detail": "Redis 核心知识点", "confidence": 1.0}, {"source": "tech:Redis", "target": "topic:过期策略", "kind": "covers", "detail": "Redis 核心知识点", "confidence": 1.0}, {"source": "tech:Redis", "target": "topic:缓存穿透/击穿/雪崩", "kind": "covers", "detail": "Redis 核心知识点", "confidence": 1.0}, {"source": "tech:Spring", "target": "topic:IoC/DI", "kind": "covers", "detail": "Spring 核心知识点", "confidence": 1.0}, {"source": "tech:Spring", "target": "topic:AOP", "kind": "covers", "detail": "Spring 核心知识点", "confidence": 1.0}, {"source": "tech:Spring", "target": "topic:Bean 生命周期", "kind": "covers", "detail": "Spring 核心知识点", "confidence": 1.0}, {"source": "tech:Spring", "target": "topic:事务管理", "kind": "covers", "detail": "Spring 核心知识点", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:自动配置", "kind": "covers", "detail": "Spring Boot 核心知识点", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:起步依赖", "kind": "covers", "detail": "Spring Boot 核心知识点", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:配置管理", "kind": "covers", "detail": "Spring Boot 核心知识点", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:Actuator", "kind": "covers", "detail": "Spring Boot 核心知识点", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:响应式", "kind": "covers", "detail": "Vue 核心知识点", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:组件", "kind": "covers", "detail": "Vue 核心知识点", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:路由", "kind": "covers", "detail": "Vue 核心知识点", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:状态管理", "kind": "covers", "detail": "Vue 核心知识点", "confidence": 1.0}, {"source": "tech:C", "target": "skill:C", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:C", "target": "topic:基础语法", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:C", "target": "topic:变量", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:C", "target": "topic:条件与循环", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:C", "target": "topic:函数", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Python", "target": "skill:Python", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:Python", "target": "topic:基础语法", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Python", "target": "topic:函数", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Python", "target": "topic:文件处理", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Python", "target": "topic:基础项目开发", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Git", "target": "skill:Git", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:Git", "target": "topic:clone", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Git", "target": "topic:add", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Git", "target": "topic:commit", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Git", "target": "topic:push", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Git", "target": "topic:branch", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:HTML/CSS", "target": "skill:HTML/CSS", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:JavaScript", "target": "skill:JavaScript", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:Vue", "target": "skill:Vue", "kind": "user-claims", "detail": "档案自评 basic", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:Vue 3", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:Vite", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Vue", "target": "topic:基础状态与事件", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Java", "target": "skill:Java", "kind": "user-claims", "detail": "档案自评 beginner", "confidence": 1.0}, {"source": "tech:Java", "target": "topic:基础语法", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Java", "target": "topic:面向对象", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Java", "target": "topic:集合", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Java", "target": "topic:异常", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Java", "target": "topic:IO", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "skill:Spring Boot", "kind": "user-claims", "detail": "档案自评 beginner", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:项目结构", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:Controller", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:Service", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:Spring Boot", "target": "topic:REST API", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:MySQL", "target": "skill:MySQL", "kind": "user-claims", "detail": "档案自评 beginner", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:CRUD", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:MySQL", "target": "topic:基础SQL", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "skill:AI Agent", "kind": "user-claims", "detail": "档案自评 beginner", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "topic:Agent", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "topic:Tool Calling", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "topic:Prompt", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "topic:上下文管理", "kind": "covers", "detail": "来自技能档案主题", "confidence": 1.0}, {"source": "tech:AI Agent", "target": "skill:AI Agent", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:C", "target": "skill:C", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:Git", "target": "skill:Git", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:HTML/CSS", "target": "skill:HTML/CSS", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:Java", "target": "skill:Java", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:JavaScript", "target": "skill:JavaScript", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:MySQL", "target": "skill:MySQL", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:Python", "target": "skill:Python", "kind": "assessed", "detail": "掌握程度 36%(判定 beginner,置信度 90%)", "confidence": 0.9}, {"source": "tech:Redis", "target": "skill:Redis", "kind": "assessed", "detail": "掌握程度 14%(判定 beginner,置信度 35%)", "confidence": 0.35}, {"source": "tech:Spring Boot", "target": "skill:Spring Boot", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}, {"source": "tech:Vue", "target": "skill:Vue", "kind": "assessed", "detail": "掌握程度 16%(判定 beginner,置信度 39%)", "confidence": 0.39}]};
var W = window.innerWidth, H = window.innerHeight;
var svg = document.getElementById('svg');
var NS = 'http://www.w3.org/2000/svg';
var viewport = document.createElementNS(NS, 'g');
svg.appendChild(viewport);
// ---- 数据:hub(项目) + 数据节点;hub 到文件的派生连线(不改数据模型)----
var SIZE = { hub:20, file:7, tech:10, topic:6, skill:12 };
var COLOR = { hub:'#8a2be2', file:'#9ca3af', tech:'#4b5563', topic:'#d1d5db', skill:'#7c3aed' };
var byId = {}, nodes = [], fileIds = [];
DATA.nodes.forEach(function (n) { byId[n.id] = n; });
DATA.nodes.forEach(function (n) {
if (n.kind === 'file') fileIds.push(n.id);
if (n.kind === 'file' || n.kind === 'tech' || n.kind === 'topic' || n.kind === 'skill') {
nodes.push({ id:n.id, kind:n.kind, name:n.name, props:n.properties || {} });
}
});
var hubId = 'hub';
nodes.push({ id:hubId, kind:'hub', name: DATA.project || '项目', props:{} });
byId[hubId] = { id:hubId, name:nodes[nodes.length-1].name };
var edges = [];
DATA.relations.forEach(function (r) {
if (byId[r.source] && byId[r.target]) edges.push({ s:r.source, t:r.target, hub:false });
});
fileIds.forEach(function (f) { edges.push({ s:hubId, t:f, hub:true }); });
// ---- 力导向模拟 ----
var sim = {};
nodes.forEach(function (n) {
var ang = Math.random() * Math.PI * 2, rr = 60 + Math.random() * 150;
sim[n.id] = { x:W/2 + rr * Math.cos(ang), y:H/2 + rr * Math.sin(ang), vx:0, vy:0, fx:null, fy:null };
});
function step() {
var ids = Object.keys(sim), i, j, a, b, dx, dy, d, f;
for (i = 0; i < ids.length; i++) {
for (j = i + 1; j < ids.length; j++) {
a = sim[ids[i]]; b = sim[ids[j]];
dx = a.x - b.x; dy = a.y - b.y;
d = Math.sqrt(dx * dx + dy * dy) || 1;
f = Math.min(900, 26000 / (d * d));
a.vx += dx / d * f; a.vy += dy / d * f;
b.vx -= dx / d * f; b.vy -= dy / d * f;
}
}
edges.forEach(function (e) {
a = sim[e.s]; b = sim[e.t];
if (!a || !b) return;
dx = b.x - a.x; dy = b.y - a.y;
d = Math.sqrt(dx * dx + dy * dy) || 1;
f = (d - 95) * 0.03;
a.vx += dx / d * f; a.vy += dy / d * f;
b.vx -= dx / d * f; b.vy -= dy / d * f;
});
ids.forEach(function (k) {
var p = sim[k];
if (p.fx !== null) { p.x = p.fx; p.y = p.fy; p.vx = 0; p.vy = 0; return; }
p.vx += (W / 2 - p.x) * 0.0012;
p.vy += (H / 2 - p.y) * 0.0012;
p.vx *= 0.86; p.vy *= 0.86;
p.x += p.vx; p.y += p.vy;
});
}
// ---- 渲染 ----
var edgeEls = [], nodeEls = {};
function build() {
viewport.innerHTML = '';
edgeEls = [];
edges.forEach(function (e) {
var line = document.createElementNS(NS, 'line');
line.setAttribute('class', e.hub ? 'edge hubedge' : 'edge');
line.dataset.s = e.s; line.dataset.t = e.t;
viewport.appendChild(line);
edgeEls.push(line);
});
nodes.forEach(function (n) {
var g = document.createElementNS(NS, 'g');
g.dataset.id = n.id;
var c = document.createElementNS(NS, 'circle');
c.setAttribute('r', SIZE[n.kind]);
c.setAttribute('fill', COLOR[n.kind]);
if (n.kind === 'hub') { c.setAttribute('stroke', '#6d1fb8'); c.setAttribute('stroke-width', 3); }
c.style.cursor = 'pointer';
g.appendChild(c);
var label = n.name;
if (n.kind === 'skill' && n.props.mastery_percent !== null
&& n.props.mastery_percent !== undefined) {
label = label + ' ' + n.props.mastery_percent + '%';
}
if (n.kind === 'file' && n.props.ai_contribution !== null
&& n.props.ai_contribution !== undefined) {
label = label + ' [AI ' + Math.round(n.props.ai_contribution * 100) + '%]';
}
var t = document.createElementNS(NS, 'text');
t.setAttribute('class', 'node-label');
t.setAttribute('text-anchor', 'middle');
t.setAttribute('dy', SIZE[n.kind] + 13);
t.textContent = label;
g.appendChild(t);
viewport.appendChild(g);
nodeEls[n.id] = g;
bindNode(n, g, c);
});
}
// ---- 交互:拖拽节点 / 平移画布 / 缩放 / 悬停与点击高亮 ----
var tx = 0, ty = 0, scale = 1;
function applyView() {
viewport.setAttribute('transform', 'translate(' + tx + ',' + ty + ') scale(' + scale + ')');
}
svg.addEventListener('wheel', function (ev) {
ev.preventDefault();
scale = Math.min(3, Math.max(0.25, scale * (ev.deltaY < 0 ? 1.1 : 0.9)));
applyView();
}, { passive:false });
var panning = false, px = 0, py = 0;
svg.addEventListener('pointerdown', function (ev) {
if (ev.target === svg) { panning = true; px = ev.clientX - tx; py = ev.clientY - ty; svg.classList.add('dragging'); }
});
window.addEventListener('pointermove', function (ev) {
if (panning) { tx = ev.clientX - px; ty = ev.clientY - py; applyView(); }
});
window.addEventListener('pointerup', function () { panning = false; svg.classList.remove('dragging'); });
var draggingId = null, focusId = null;
var neighborsOf = {};
edges.forEach(function (e) {
(neighborsOf[e.s] = neighborsOf[e.s] || []).push(e.t);
(neighborsOf[e.t] = neighborsOf[e.t] || []).push(e.s);
});
function highlight(id) {
var keep = null;
if (id) {
keep = {}; keep[id] = true;
(neighborsOf[id] || []).forEach(function (k) { keep[k] = true; });
}
Object.keys(nodeEls).forEach(function (k) {
if (!keep || keep[k]) nodeEls[k].classList.remove('dim'); else nodeEls[k].classList.add('dim');
});
edgeEls.forEach(function (el) {
if (!keep || (keep[el.dataset.s] && keep[el.dataset.t])) el.classList.remove('dim');
else el.classList.add('dim');
});
}
function bindNode(n, g, c) {
c.addEventListener('pointerdown', function (ev) {
ev.stopPropagation();
draggingId = n.id;
});
window.addEventListener('pointermove', function (ev) {
if (draggingId !== n.id) return;
sim[n.id].fx = (ev.clientX - tx) / scale;
sim[n.id].fy = (ev.clientY - ty) / scale;
});
window.addEventListener('pointerup', function () {
if (draggingId === n.id) draggingId = null;
});
g.addEventListener('mouseenter', function () { if (!focusId) highlight(n.id); });
g.addEventListener('mouseleave', function () { if (!focusId) highlight(null); });
g.addEventListener('click', function (ev) {
ev.stopPropagation();
focusId = (focusId === n.id) ? null : n.id;
highlight(focusId);
});
}
document.getElementById('btn').addEventListener('click', function () {
Object.keys(sim).forEach(function (k) {
var ang = Math.random() * Math.PI * 2, rr = 60 + Math.random() * 150;
sim[k].x = W/2 + rr * Math.cos(ang);
sim[k].y = H/2 + rr * Math.sin(ang);
sim[k].vx = 0; sim[k].vy = 0; sim[k].fx = null; sim[k].fy = null;
});
});
document.getElementById('stats').textContent = '节点 ' + nodes.length
+ ' / 关系 ' + edges.length + ' | ' + (DATA.project || '');
function frame() {
step();
nodes.forEach(function (n) {
var g = nodeEls[n.id];
if (!g) return;
g.setAttribute('transform', 'translate(' + sim[n.id].x + ',' + sim[n.id].y + ')');
});
edgeEls.forEach(function (el) {
var a = sim[el.dataset.s], b = sim[el.dataset.t];
if (!a || !b) return;
el.setAttribute('x1', a.x); el.setAttribute('y1', a.y);
el.setAttribute('x2', b.x); el.setAttribute('y2', b.y);
});
requestAnimationFrame(frame);
}
build();
frame();
</script>
</body>
</html>