From ac966af3d126d59081d119e05ba02f946257f669 Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Sun, 26 Jul 2026 23:22:36 +0800
Subject: [PATCH] fix: 移除所有help中的等号格式

---
 cmd/graph.go |  240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 240 insertions(+), 0 deletions(-)

diff --git a/cmd/graph.go b/cmd/graph.go
new file mode 100644
index 0000000..337552b
--- /dev/null
+++ b/cmd/graph.go
@@ -0,0 +1,240 @@
+package cmd
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/aisim/kb-cli/internal/graph"
+	"github.com/aisim/kb-cli/internal/index"
+	"github.com/spf13/cobra"
+)
+
+var graphCmd = &cobra.Command{
+	Use:   "graph",
+	Short: "知识图谱查询与管理",
+}
+
+var graphStatsCmd = &cobra.Command{
+	Use:   "stats",
+	Short: "查看知识图谱统计信息",
+	Long:  `kb-cli graph stats [--json] # 查看知识图谱统计信息(节点数、边数、关系类型分布)`,
+	RunE:  runGraphStats,
+}
+
+var graphQueryCmd = &cobra.Command{
+	Use:   "query <关键词>",
+	Short: "查询节点的关联关系",
+	Long:  `kb-cli graph query <关键词> [--relation <类型>] [--depth <深度>] [--json] # 查询节点的关联关系`,
+	Args:  cobra.ExactArgs(1),
+	RunE:  runGraphQuery,
+}
+
+var graphRelatedCmd = &cobra.Command{
+	Use:   "related <关键词>",
+	Short: "查找与关键词相关的所有节点",
+	Long:  `kb-cli graph related <关键词> [--top N] [--json] # 查找与关键词相关的所有节点`,
+	Args:  cobra.ExactArgs(1),
+	RunE:  runGraphRelated,
+}
+
+var (
+	graphRelation string
+	graphDepth    int
+	graphJSON     bool
+	graphTopN     int
+)
+
+func init() {
+	rootCmd.AddCommand(graphCmd)
+	graphCmd.AddCommand(graphStatsCmd)
+	graphCmd.AddCommand(graphQueryCmd)
+	graphCmd.AddCommand(graphRelatedCmd)
+
+	// graph stats flags
+	graphStatsCmd.Flags().BoolVar(&graphJSON, "json", false, "JSON 格式输出")
+
+	// graph query flags
+	graphQueryCmd.Flags().StringVar(&graphRelation, "relation", "", "关系类型(tag/entity/wikilink)")
+	graphQueryCmd.Flags().IntVar(&graphDepth, "depth", 1, "查询深度(1-3)")
+	graphQueryCmd.Flags().BoolVar(&graphJSON, "json", false, "JSON 格式输出")
+
+	// graph related flags
+	graphRelatedCmd.Flags().IntVar(&graphTopN, "top", 10, "返回前 N 条结果")
+	graphRelatedCmd.Flags().BoolVar(&graphJSON, "json", false, "JSON 格式输出")
+}
+
+func runGraphStats(cmd *cobra.Command, args []string) error {
+	// 打开索引
+	store, err := index.Open(dbPath)
+	if err != nil {
+		return fmt.Errorf("打开索引失败: %w", err)
+	}
+	defer store.Close()
+
+	// 获取节点数和边数
+	nodeCount, err := store.NodeCount()
+	if err != nil {
+		return fmt.Errorf("获取节点数失败: %w", err)
+	}
+
+	edgeCount, err := store.EdgeCount()
+	if err != nil {
+		return fmt.Errorf("获取边数失败: %w", err)
+	}
+
+	// 获取关系类型分布
+	relationStats, err := store.GetRelationStats()
+	if err != nil {
+		return fmt.Errorf("获取关系统计失败: %w", err)
+	}
+
+	if graphJSON {
+		stats := map[string]interface{}{
+			"node_count": nodeCount,
+			"edge_count": edgeCount,
+			"relations":  relationStats,
+		}
+		data, err := json.MarshalIndent(stats, "", "  ")
+		if err != nil {
+			return err
+		}
+		fmt.Println(string(data))
+	} else {
+		fmt.Printf("知识图谱统计:\n")
+		fmt.Printf("  节点数: %d\n", nodeCount)
+		fmt.Printf("  边数: %d\n", edgeCount)
+		fmt.Printf("\n关系类型分布:\n")
+		for rel, count := range relationStats {
+			fmt.Printf("  %-12s %d\n", rel, count)
+		}
+	}
+
+	return nil
+}
+
+func runGraphQuery(cmd *cobra.Command, args []string) error {
+	keyword := args[0]
+
+	// 打开索引
+	store, err := index.Open(dbPath)
+	if err != nil {
+		return fmt.Errorf("打开索引失败: %w", err)
+	}
+	defer store.Close()
+
+	// 查找匹配关键词的节点
+	nodes, err := store.FindNodesByKeyword(keyword)
+	if err != nil {
+		return fmt.Errorf("查找节点失败: %w", err)
+	}
+
+	if len(nodes) == 0 {
+		fmt.Println("未找到匹配的节点")
+		return nil
+	}
+
+	// 查询每个节点的关联关系
+	var results []QueryResult
+	for _, node := range nodes {
+		edges, err := store.GetNodeEdges(node.ID, graphRelation, graphDepth)
+		if err != nil {
+			return fmt.Errorf("查询关联失败: %w", err)
+		}
+
+		results = append(results, QueryResult{
+			Node:  node,
+			Edges: edges,
+		})
+	}
+
+	if graphJSON {
+		data, err := json.MarshalIndent(results, "", "  ")
+		if err != nil {
+			return err
+		}
+		fmt.Println(string(data))
+	} else {
+		for _, r := range results {
+			fmt.Printf("\n节点: %s (%s)\n", r.Node.Title, r.Node.Path)
+			if len(r.Edges) == 0 {
+				fmt.Println("  无关联关系")
+				continue
+			}
+
+			// 按关系类型分组
+			grouped := make(map[string][]string)
+			for _, edge := range r.Edges {
+				grouped[edge.Relation] = append(grouped[edge.Relation], edge.Label)
+			}
+
+			for rel, labels := range grouped {
+				fmt.Printf("  [%s]\n", rel)
+				for _, label := range labels {
+					fmt.Printf("    - %s\n", label)
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+func runGraphRelated(cmd *cobra.Command, args []string) error {
+	keyword := args[0]
+
+	// 打开索引
+	store, err := index.Open(dbPath)
+	if err != nil {
+		return fmt.Errorf("打开索引失败: %w", err)
+	}
+	defer store.Close()
+
+	// 查找相关节点
+	related, err := store.FindRelatedNodes(keyword, graphTopN)
+	if err != nil {
+		return fmt.Errorf("查找相关节点失败: %w", err)
+	}
+
+	if len(related) == 0 {
+		fmt.Println("未找到相关节点")
+		return nil
+	}
+
+	if graphJSON {
+		data, err := json.MarshalIndent(related, "", "  ")
+		if err != nil {
+			return err
+		}
+		fmt.Println(string(data))
+	} else {
+		fmt.Printf("与 '%s' 相关的节点:\n\n", keyword)
+		for i, r := range related {
+			fmt.Printf("%d. %s\n", i+1, r.Title)
+			fmt.Printf("   路径: %s\n", r.Path)
+			fmt.Printf("   板块: %s\n", r.Section)
+			fmt.Printf("   关联度: %d\n", r.Relevance)
+			if len(r.Tags) > 0 {
+				fmt.Printf("   标签: %v\n", r.Tags)
+			}
+			fmt.Println()
+		}
+	}
+
+	return nil
+}
+
+// QueryResult 查询结果
+type QueryResult struct {
+	Node  *graph.Node  `json:"node"`
+	Edges []*graph.Edge `json:"edges"`
+}
+
+// RelatedNode 相关节点
+type RelatedNode struct {
+	ID        int64    `json:"id"`
+	Path      string   `json:"path"`
+	Title     string   `json:"title"`
+	Section   string   `json:"section"`
+	Tags      []string `json:"tags"`
+	Relevance int      `json:"relevance"`
+}

--
Gitblit v1.9.1