From 09c2a03cefa687832257d3b816da50db3cfcc0f2 Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Sat, 25 Jul 2026 23:48:11 +0800
Subject: [PATCH] feat: 实现输出格式化
---
internal/graph/builder.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/internal/graph/builder.go b/internal/graph/builder.go
new file mode 100644
index 0000000..9b5ca4e
--- /dev/null
+++ b/internal/graph/builder.go
@@ -0,0 +1,96 @@
+package graph
+
+import (
+ "github.com/aisim/kb-cli/internal/vault"
+)
+
+// BuildGraph 从文件元数据构建知识图谱
+func BuildGraph(files []*vault.FileMeta) *Graph {
+ g := &Graph{}
+
+ // 标签/实体 -> 虚拟节点 ID 映射
+ labelToID := make(map[string]int64)
+ nextVirtualID := int64(1000000) // 虚拟节点从 1000000 开始
+
+ getOrCreateVirtualNode := func(label string) int64 {
+ if id, ok := labelToID[label]; ok {
+ return id
+ }
+ id := nextVirtualID
+ nextVirtualID++
+ labelToID[label] = id
+ return id
+ }
+
+ for i, f := range files {
+ node := &Node{
+ ID: int64(i + 1),
+ Path: f.Path,
+ Title: f.Title,
+ Section: f.Section,
+ Tags: f.Tags,
+ Entities: f.Entities,
+ Wikilinks: f.Wikilinks,
+ Content: f.Content,
+ }
+ g.Nodes = append(g.Nodes, node)
+
+ // 创建 tag 边
+ for _, tag := range f.Tags {
+ virtualID := getOrCreateVirtualNode("tag:" + tag)
+ g.Edges = append(g.Edges, &Edge{
+ FromNode: node.ID,
+ ToNode: virtualID,
+ Relation: "tag",
+ Label: tag,
+ })
+ }
+
+ // 创建 entity 边
+ for _, entity := range f.Entities {
+ virtualID := getOrCreateVirtualNode("entity:" + entity)
+ g.Edges = append(g.Edges, &Edge{
+ FromNode: node.ID,
+ ToNode: virtualID,
+ Relation: "entity",
+ Label: entity,
+ })
+ }
+ }
+
+ // 创建 wikilink 边(文件间链接)
+ pathToID := make(map[string]int64)
+ for _, n := range g.Nodes {
+ pathToID[n.Path] = n.ID
+ }
+
+ for _, n := range g.Nodes {
+ for _, link := range n.Wikilinks {
+ // 尝试匹配目标文件(模糊匹配:链接文本可能只是标题的一部分)
+ for _, target := range g.Nodes {
+ if matchesWikilink(target, link) {
+ g.Edges = append(g.Edges, &Edge{
+ FromNode: n.ID,
+ ToNode: target.ID,
+ Relation: "wikilink",
+ Label: link,
+ })
+ break
+ }
+ }
+ }
+ }
+
+ return g
+}
+
+// matchesWikilink 检查文件是否匹配 wikilink
+func matchesWikilink(node *Node, link string) bool {
+ // 精确匹配标题
+ if node.Title == link {
+ return true
+ }
+ // 匹配文件名(不含扩展名和编号前缀)
+ // 例如:[[充装规格配置]] 匹配 "知识/002-充装规格配置.md"
+ return false // 简化版,后续可扩展
+}
--
Gitblit v1.9.1