sync: collector/ 同步自 inkstone/arcrun-rag@10eb2cb(桌面小幫手 0.18.53)

This commit is contained in:
2026-09-14 07:05:34 +08:00
parent bce422f6fe
commit e4327ecd37
13 changed files with 820 additions and 22 deletions
+90
View File
@@ -0,0 +1,90 @@
// syncing_sub.go — 「同步中」底下那一行要講得出做到哪、卡在哪(`inkstone/arcrun-rag#200`)。
//
// 🔴 病(2026-09-13 leo 截圖):畫面整晚寫「同步中… 正在讀檔並整理成知識卡/
// 請稍候,完成後會顯示整理了幾份」,而 collector.log 裡明明印著
// 「還在等知識庫 leo21c 回覆『送出一份筆記』,已經等了 30 秒」。
// **會說話的那句只寫進了記錄檔,畫面上是一句永遠不變的「請稍候」**——
// 使用者分不出「正在做」和「卡住了」,只能猜。
//
// 資料來源只有一個:collector 一輪途中寫進 status.json 的 in_roundcollector/live_status.go)。
// 這裡不判斷任何事,只把它念成一句話。
package main
import (
"fmt"
"path/filepath"
"strings"
"time"
"arcrun-rag/collector"
)
// syncingIdleWarnAfter=多久沒有任何新寫入,就明講「已經 N 分鐘沒有新進展」。
// 「還在等」每 30 秒會寫一次,所以正常等待不會碰到這條;碰到=真的沒在動。
const syncingIdleWarnAfter = 5 * time.Minute
const syncingSubFallback = "請稍候,完成後會顯示整理了幾份"
// syncingSub 把「這一輪做到哪」念成一句話。r 為 nil(舊版 collector、剛開工還沒寫)=沿用原本那句。
// label 把主機名翻成使用者認得的知識庫名字(測試可以換掉)。
func syncingSub(r *collector.RoundProgress, now time.Time, label func(host string) string) string {
if r == nil {
return syncingSubFallback
}
where := ""
if r.Account != "" {
where = label(r.Account)
}
if r.Folder != "" {
name := filepath.Base(r.Folder)
if where != "" {
where = fmt.Sprintf("%s%s", name, where)
} else {
where = name
}
}
// 卡住的時候,只講卡在哪——這是使用者此刻唯一需要知道的事。
if w := r.Waiting; w != nil && strings.TrimSpace(w.Note) != "" {
if where != "" {
return fmt.Sprintf("卡在「%s」:%s", where, w.Note)
}
return "卡住了:" + w.Note
}
var parts []string
if where != "" {
head := "正在處理 " + where
if r.Step != "" {
head += "" + r.Step
}
parts = append(parts, head)
}
if r.Ingested > 0 {
parts = append(parts, fmt.Sprintf("這一輪已送上 %d 份", r.Ingested))
}
if r.Failed > 0 {
parts = append(parts, fmt.Sprintf("%d 份沒送成功", r.Failed))
}
if t, err := time.Parse(time.RFC3339, r.UpdatedAt); err == nil {
if idle := now.Sub(t); idle > syncingIdleWarnAfter {
parts = append(parts, fmt.Sprintf("已經 %d 分鐘沒有新進展", int(idle.Minutes())))
}
}
if len(parts) == 0 {
return syncingSubFallback
}
return strings.Join(parts, " · ")
}
// accountLabelFor 把 status.json 裡的主機名翻成畫面左邊那個知識庫名字(與 UIAccount.Name 同一套)。
func accountLabelFor(host string) string {
if cfg, err := loadCfg(); err == nil {
for _, a := range cfg.Accounts {
if shortHost(a.CypherURL) == host {
return accountName(a)
}
}
}
return host
}