From 1196f409d86bc61e7596eb274840244a62ce84ba Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Wed, 29 Jul 2026 14:58:19 +0800
Subject: [PATCH] feat: config priority over env vars, export LoadConfig, add review feature

---
 internal/llm/client.go |   98 +++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 87 insertions(+), 11 deletions(-)

diff --git a/internal/llm/client.go b/internal/llm/client.go
index 5ffd7e2..883cc63 100644
--- a/internal/llm/client.go
+++ b/internal/llm/client.go
@@ -70,19 +70,20 @@
 
 // SearchCandidate 搜索候选
 type SearchCandidate struct {
-	Title string  `json:"title"`
-	Path  string  `json:"path"`
-	Score float64 `json:"score"`
+	Title   string  `json:"title"`
+	Path    string  `json:"path"`
+	Score   float64 `json:"score"`
+	Content string  `json:"content,omitempty"` // 文件内容(截取前5000字)
 }
 
 // NewClient 创建 LLM 客户端
 func NewClient() *Client {
-	config := loadConfig()
+	config := LoadConfig()
 	return &Client{config: config, usePrimary: true}
 }
 
-// loadConfig 加载配置文件
-func loadConfig() Config {
+// LoadConfig 加载配置文件(导出供其他包使用)
+func LoadConfig() Config {
 	var config Config
 
 	// 配置文件路径
@@ -193,17 +194,25 @@
 }
 
 // GenerateMergeHint 生成合并指示
-func (c *Client) GenerateMergeHint(draftContent string, candidates []SearchCandidate) (*MergeHint, error) {
+func (c *Client) GenerateMergeHint(draftContent string, candidates []SearchCandidate, dirStructure string) (*MergeHint, error) {
 	prompt := fmt.Sprintf(`你是一个知识库管理助手。请判断以下草稿与哪些知识库文档相关。
+
+## 知识库目录结构
+%s
 
 ## 草稿内容
 %s
 
 ## 候选文档(Top 3)
-`, draftContent)
+`, dirStructure, draftContent)
 
 	for i, cand := range candidates {
-		prompt += fmt.Sprintf("%d. 标题: %s, 路径: %s, 相关度: %.2f\n", i+1, cand.Title, cand.Path, cand.Score)
+		prompt += fmt.Sprintf("### %d. %s\n", i+1, cand.Title)
+		prompt += fmt.Sprintf("- 路径: %s\n", cand.Path)
+		prompt += fmt.Sprintf("- 相关度: %.2f\n\n", cand.Score)
+		if cand.Content != "" {
+			prompt += fmt.Sprintf("**文档内容**:\n```\n%s\n```\n\n", cand.Content)
+		}
 	}
 
 	prompt += `
@@ -213,7 +222,7 @@
 {
   "recommendation": {
     "action": "merge|new|split",
-    "target": "目标路径(如果 action=merge)",
+    "target": "目标路径(如果 action=merge,必须是上述目录结构中存在的目录)",
     "reason": "判断理由",
     "confidence": "high|medium|low"
   },
@@ -228,11 +237,16 @@
 
 判断标准:
 - action=merge: 草稿内容与某个候选文档高度相关,应该合并
-- action=new: 草稿内容是全新的,应该新建文档
+- action=new: 草稿内容是全新的,应该新建文档(target 填写建议的目录路径)
 - action=split: 草稿内容包含多个独立主题,应该拆分
 - confidence=high: 判断很确定
 - confidence=medium: 判断比较确定
 - confidence=low: 判断不太确定
+
+分类原则:
+- 平台专属内容放对应平台目录下(如电子秤平台/智能枪/)
+- 多平台共用的硬件知识放 共有硬件/ 下
+- 跨平台通用知识放 通用/通用/
 
 只输出 JSON,不要其他内容。`
 
@@ -249,6 +263,68 @@
 	return &result, nil
 }
 
+// GenerateReviewPreview 生成审阅预览概要(3句话概括目标FAQ)
+func (c *Client) GenerateReviewPreview(targetTitle, targetContent string) (string, error) {
+	// 截取前2000字符作为上下文
+	contentPreview := targetContent
+	if len(contentPreview) > 2000 {
+		contentPreview = contentPreview[:2000] + "..."
+	}
+
+	prompt := fmt.Sprintf(`请用3句话概括以下知识库文档的核心内容,帮助用户快速了解这个文档讲的是什么:
+
+## 文档标题
+%s
+
+## 文档内容(部分)
+%s
+
+要求:
+1. 第一句:这个文档解决什么问题/讲什么主题
+2. 第二句:核心内容/关键要点
+3. 第三句:适用场景/使用条件
+
+直接输出3句话,不要编号,不要其他内容。`, targetTitle, contentPreview)
+
+	response, err := c.callLLMWithRetry(prompt)
+	if err != nil {
+		return "", err
+	}
+
+	return strings.TrimSpace(response), nil
+}
+
+// ClassifyDocuments 分类文档
+func (c *Client) ClassifyDocuments(prompt string) (string, error) {
+	response, err := c.callLLMWithRetry(prompt)
+	if err != nil {
+		return "", err
+	}
+
+	// 解析 JSON
+	var result []struct {
+		Path        string  `json:"path"`
+		Platform    string  `json:"platform"`
+		Device      string  `json:"device"`
+		ContentType string  `json:"content_type"`
+		Confidence  float64 `json:"confidence"`
+	}
+
+	if err := parseJSON(response, &result); err != nil {
+		return "", fmt.Errorf("解析 LLM 响应失败: %w", err)
+	}
+
+	// 转换回 JSON 字符串
+	jsonBytes, err := json.Marshal(result)
+	if err != nil {
+		return "", err
+	}
+
+	return string(jsonBytes), nil
+}
+
+// ClassifyDocuments 分类文档
+
 // callLLMWithRetry 带重试的 LLM 调用
 func (c *Client) callLLMWithRetry(prompt string) (string, error) {
 	// 第一次尝试

--
Gitblit v1.9.1