91 lines
3.0 KiB
Go
91 lines
3.0 KiB
Go
// syncing_sub.go — 「同步中」底下那一行要講得出做到哪、卡在哪(`inkstone/arcrun-rag#200`)。
|
||
//
|
||
// 🔴 病(2026-09-13 leo 截圖):畫面整晚寫「同步中… 正在讀檔並整理成知識卡/
|
||
// 請稍候,完成後會顯示整理了幾份」,而 collector.log 裡明明印著
|
||
// 「還在等知識庫 leo21c 回覆『送出一份筆記』,已經等了 30 秒」。
|
||
// **會說話的那句只寫進了記錄檔,畫面上是一句永遠不變的「請稍候」**——
|
||
// 使用者分不出「正在做」和「卡住了」,只能猜。
|
||
//
|
||
// 資料來源只有一個:collector 一輪途中寫進 status.json 的 in_round(collector/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
|
||
}
|