feat(t52): per-folder 庫章——DirectConfig.libraries 對映+libraryFor()(資料夾名 slug/中文退後備/明列優先,go test 綠);兩支 ingest workflow 的 post_block metadata 補 library(真兇:blocks 沒蓋章=兩資料夾全歸 general);托盤連線時回報庫自動登記

This commit is contained in:
2026-07-26 01:53:44 +08:00
parent 3675f38e59
commit fedb765742
3 changed files with 151 additions and 3 deletions
+81
View File
@@ -51,6 +51,7 @@ type directConfig struct {
InstanceName string `json:"instance_name,omitempty"` // 暱稱(t26 選配;不取就顯示 email)
Library string `json:"library,omitempty"`
Extractor string `json:"extractor,omitempty"` // t54:連線精靈帶入(claude/gemma
Libraries map[string]string `json:"libraries,omitempty"` // t52:資料夾→庫對映(key=絕對路徑)
IngestWF string `json:"ingest_workflow,omitempty"`
RemovedWF string `json:"removed_workflow,omitempty"`
PollSec int `json:"poll_interval_sec,omitempty"`
@@ -289,6 +290,82 @@ func applyRemoteConfig(cfg *directConfig, r *daemonConfigResp) {
}
}
// registerLibraries 把「這台機器看守的資料夾各自對應的庫」報上雲端自動登記(t52)。
// leo 2026-07-26:「用戶可以看到我有 2 個庫,地端雲端都是 2 個,如果只有一個一定被罵。」
// 只在連線精靈那一刻做(那時手上才有帳密;daemon 平時不存密碼)。失敗不擋連線。
func registerLibraries(portalURL, email, password string, cfg *directConfig) error {
base, err := normalizePortalURL(portalURL)
if err != nil {
return err
}
type libItem struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
}
var libs []libItem
seen := map[string]bool{}
for _, folder := range cfg.Folders() {
name := libraryNameFor(cfg, folder)
if name == "" || seen[name] {
continue
}
seen[name] = true
libs = append(libs, libItem{Name: name, DisplayName: filepath.Base(folder)})
}
if len(libs) == 0 {
return nil
}
body, _ := json.Marshal(map[string]any{"email": strings.TrimSpace(email), "password": password, "libraries": libs})
req, err := http.NewRequest(http.MethodPost, base+"/portal/daemon/libraries", bytes.NewReader(body))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
res, err := (&http.Client{Timeout: 20 * time.Second}).Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
return fmt.Errorf("庫登記回 HTTP %d", res.StatusCode)
}
return nil
}
// libraryNameFor 與 collector/direct.go 的 libraryFor 同規則(資料夾名 slug;空則退回 library)。
func libraryNameFor(cfg *directConfig, folder string) string {
if cfg.Libraries != nil {
if v, ok := cfg.Libraries[folder]; ok && strings.TrimSpace(v) != "" {
return strings.TrimSpace(v)
}
}
base := filepath.Base(strings.TrimRight(folder, string(filepath.Separator)))
var b strings.Builder
lastUnderscore := false
for _, r := range base {
switch {
case (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_':
b.WriteRune(r)
lastUnderscore = false
case r >= 'A' && r <= 'Z':
b.WriteRune(r + 32)
lastUnderscore = false
default:
if !lastUnderscore && b.Len() > 0 {
b.WriteRune('_')
lastUnderscore = true
}
}
}
if slug := strings.Trim(b.String(), "_"); slug != "" {
return slug
}
if cfg.Library != "" {
return cfg.Library
}
return "kb"
}
// isConnected 判斷「這台機器已經連上某個知識庫」——沒有就該跳連線精靈。
func isConnected(cfg *directConfig) bool {
return strings.TrimSpace(cfg.CypherURL) != "" && strings.TrimSpace(cfg.Namespace) != ""
@@ -364,6 +441,10 @@ func main() {
dialog.ShowError(err, win)
return
}
// t52:把本機資料夾對應的庫報上去自動登記(地端幾個資料夾=雲端幾個庫)
if lerr := registerLibraries(urlEntry.Text, emailEntry.Text, pwEntry.Text, cfg); lerr != nil {
fmt.Println("庫登記略過:", lerr) // 不擋連線(可能是還沒選資料夾)
}
restartWatch()
rebuildTray()
dialog.ShowInformation("連上了", "已連上「"+connectionStatusLabel(cfg.InstanceName, cfg.Email)+"」。\n接下來用選單「+ 新增知識資料夾…」挑要同步的資料夾就好。", win)