ai_xiaopei
9 days ago ac966af3d126d59081d119e05ba02f946257f669
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
package cmd
 
import (
    "fmt"
    "os"
 
    "github.com/aisim/kb-cli/internal/draft"
    "github.com/aisim/kb-cli/internal/index"
    "github.com/spf13/cobra"
)
 
var draftCmd = &cobra.Command{
    Use:   "draft",
    Short: "草稿管理",
    Long:  `kb-cli draft create # 创建草稿(AI 生成 tags + 合并指示)`,
}
 
var draftCreateCmd = &cobra.Command{
    Use:   "create",
    Short: "创建草稿",
    Long:  `# draft create - 创建草稿
kb-cli draft create --type <类型> --title <标题> --content-file <文件> [--source <来源>] [--force] # 创建草稿,自动提取 tags 并生成合并指示`,
    RunE: runDraftCreate,
}
 
var tagsCmd = &cobra.Command{
    Use:   "tags",
    Short: "标签管理",
    Long:  `kb-cli tags rebuild # 批量重建现有文档的 tags`,
}
 
var tagsRebuildCmd = &cobra.Command{
    Use:   "rebuild",
    Short: "批量重建 tags",
    Long:  `# tags rebuild - 批量重建 tags
kb-cli tags rebuild [--vault <路径>] [--limit <数量>] [--dry-run] # 使用 LLM 重新提取现有文档的 tags`,
    RunE: runTagsRebuild,
}
 
var (
    draftType       string
    draftTitle      string
    draftContentFile string
    draftSource     string
    draftForce      bool
    tagsLimit       int
    tagsDryRun      bool
)
 
func init() {
    // draft create 命令
    draftCreateCmd.Flags().StringVar(&draftType, "type", "", "草稿类型(售后/产品/运营/行业/TAPD)")
    draftCreateCmd.Flags().StringVar(&draftTitle, "title", "", "草稿标题")
    draftCreateCmd.Flags().StringVar(&draftContentFile, "content-file", "", "草稿内容文件路径")
    draftCreateCmd.Flags().StringVar(&draftSource, "source", "", "来源标识")
    draftCreateCmd.Flags().BoolVar(&draftForce, "force", false, "强制创建(跳过重复检查)")
    draftCreateCmd.MarkFlagRequired("type")
    draftCreateCmd.MarkFlagRequired("title")
    draftCreateCmd.MarkFlagRequired("content-file")
 
    draftCmd.AddCommand(draftCreateCmd)
 
    // tags rebuild 命令
    tagsRebuildCmd.Flags().IntVar(&tagsLimit, "limit", 0, "限制处理文档数量(0=全部)")
    tagsRebuildCmd.Flags().BoolVar(&tagsDryRun, "dry-run", false, "仅预览,不实际更新")
 
    tagsCmd.AddCommand(tagsRebuildCmd)
 
    rootCmd.AddCommand(draftCmd)
    rootCmd.AddCommand(tagsCmd)
}
 
func runDraftCreate(cmd *cobra.Command, args []string) error {
    // 读取内容文件
    content, err := os.ReadFile(draftContentFile)
    if err != nil {
        return fmt.Errorf("读取内容文件失败: %w", err)
    }
 
    if len(content) == 0 {
        return fmt.Errorf("内容文件为空")
    }
 
    // 打开索引
    store, err := index.Open(dbPath)
    if err != nil {
        return fmt.Errorf("打开索引失败: %w", err)
    }
    defer store.Close()
 
    // 创建草稿录入器
    intake := draft.NewIntake(vaultPath, store)
 
    // 创建草稿
    if err := intake.CreateDraft(draftType, draftTitle, string(content), draftSource, draftForce); err != nil {
        return fmt.Errorf("创建草稿失败: %w", err)
    }
 
    return nil
}
 
func runTagsRebuild(cmd *cobra.Command, args []string) error {
    // 打开索引
    store, err := index.Open(dbPath)
    if err != nil {
        return fmt.Errorf("打开索引失败: %w", err)
    }
    defer store.Close()
 
    // 创建草稿录入器
    intake := draft.NewIntake(vaultPath, store)
 
    // 重建 tags
    if err := intake.RebuildTags(tagsLimit, tagsDryRun); err != nil {
        return fmt.Errorf("重建 tags 失败: %w", err)
    }
 
    return nil
}