From d0852e9b457ac9e0da1ed7a0de93469ba42167b8 Mon Sep 17 00:00:00 2001 From: richblack Date: Thu, 6 Aug 2026 22:02:32 +0800 Subject: [PATCH] =?UTF-8?q?v0.18.19=EF=BC=9A=E5=A4=B1=E6=95=97=E8=A8=8A?= =?UTF-8?q?=E6=81=AF=E6=94=B9=E6=88=90=E4=BA=BA=E8=A9=B1=EF=BC=88leo?= =?UTF-8?q?=EF=BC=9A=E3=80=8C=E9=80=99=E5=80=8B=E9=8C=AF=E8=AA=A4=E8=A8=8A?= =?UTF-8?q?=E6=81=AF=E6=88=91=E7=9C=9F=E7=9A=84=E7=9C=8B=E4=B8=8D=E6=87=82?= =?UTF-8?q?=E3=80=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.18.18 雖然把失敗檔案列出來了,但寫的是 「上次失敗(第 5 次),5h38m38s 後重試(上面是自動重試的排程,真正的原因是前一次失敗)」 ——**那是我寫給自己看的**:只是把 collector 的原文轉貼、再補一句解釋為什麼看起來怪。 使用者要的是三件事:**現在怎樣、為什麼、我要不要做什麼**。 ## 改法 - 解析退避訊息取出「試幾次/多久後再試/原因」,重新組成人話 - **有原因**時以原因為主、排程放後面補充(他要判斷的是原因) - **沒有原因**時(舊版失敗的檔案沒存 LastError)誠實說: 「已經自動試過 5 次都沒成功,約 5 小時後會再試一次。這個檔是在舊版失敗的, 當時沒有記下原因;如果一直沒好,把紀錄檔傳給我們。」 - 時間不再精確到秒(`5h38m38s` → 「約 5 小時」)——使用者要的是量級不是秒數 ## 實測輸出(三種情境都印出來看過) 舊:上次失敗(第 5 次),5h38m38s 後重試(上面是自動重試的排程…) 新:已經自動試過 5 次都沒成功,約 5 小時後會再試一次。這個檔是在舊版失敗的… 新:今天的免費 AI 額度用完了 ⇒ 明天會自動恢復,這些檔案會自己補上,你不用做什麼。 新:這份 PDF 看起來是掃描的圖片 ⇒ 需要先做文字辨識(OCR),或換一份有文字的版本。 --- cmd/arcrun-app/.version-source.json | 3 +- cmd/arcrun-app/app.go | 53 +++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/cmd/arcrun-app/.version-source.json b/cmd/arcrun-app/.version-source.json index 5aacbec..384b84a 100644 --- a/cmd/arcrun-app/.version-source.json +++ b/cmd/arcrun-app/.version-source.json @@ -1,5 +1,6 @@ { "_algo": 2, "v0.18.17": "cb6e53a052b87482", - "v0.18.18": "a495451d9d9da78a" + "v0.18.18": "a495451d9d9da78a", + "v0.18.19": "b754d7ff97396794" } diff --git a/cmd/arcrun-app/app.go b/cmd/arcrun-app/app.go index 941337a..c880ff4 100644 --- a/cmd/arcrun-app/app.go +++ b/cmd/arcrun-app/app.go @@ -23,8 +23,10 @@ import ( "os" "os/exec" "path/filepath" + "regexp" runtime2 "runtime" "sort" + "strconv" "strings" "time" @@ -278,6 +280,39 @@ type UIFailItem struct { // maxFailShown=最多列幾份(多了會洗版;總數仍照實講)。 const maxFailShown = 8 +// parseRetryMessage 從退避訊息裡取出「試了幾次、多久後再試、原因是什麼」。 +// 格式來源=collector 的 retrySkipReason()。解析失敗就回 ok=false,由呼叫端原樣顯示。 +func parseRetryMessage(raw string) (n int, wait, reason string, ok bool) { + m := retryMsgRe.FindStringSubmatch(raw) + if m == nil { + return 0, "", "", false + } + n, _ = strconv.Atoi(m[1]) + wait = humanizeDuration(m[2]) + if i := strings.Index(raw, "|原因:"); i >= 0 { + reason = raw[i+len("|原因:"):] + } + return n, wait, reason, true +} + +var retryMsgRe = regexp.MustCompile(`上次失敗(第 (\d+) 次),([0-9hms.]+) 後重試`) + +// humanizeDuration 把 `5h38m38s` 講成「5 小時」——使用者不需要精確到秒。 +func humanizeDuration(d string) string { + dur, err := time.ParseDuration(d) + if err != nil { + return d + } + switch { + case dur >= time.Hour: + return fmt.Sprintf("%d 小時", int(dur.Hours())) + case dur >= time.Minute: + return fmt.Sprintf("%d 分鐘", int(dur.Minutes())) + default: + return "不到 1 分鐘" + } +} + // humanizeFailure 把 collector 的技術錯誤翻成使用者看得懂、而且**知道要不要行動**的一句話。 // // 🔴 leo 2026-08-06 實測,兩個真實案例(從他 Windows 的 collector.log 挖出來的): @@ -298,8 +333,22 @@ func humanizeFailure(raw string) string { return "這份 PDF 看起來是掃描的圖片,沒有文字可以讀 ⇒ 需要先做文字辨識(OCR),或換一份有文字的版本。" case strings.Contains(raw, "尚未支援的檔案格式"): return "這種檔案格式還讀不了 ⇒ 先另存成 PDF 或 Word(.docx)再放回同一個資料夾。" - case strings.Contains(raw, "後重試"): - return raw + "(上面是自動重試的排程,真正的原因是前一次失敗)" + } + + // 退避訊息:collector 給的是「上次失敗(第 5 次),5h38m38s 後重試|原因:…」。 + // + // 🔴 leo 2026-08-06:「**這個錯誤訊息我真的看不懂,明白說比較好**」 + // ——我原本只是把原文轉貼、再加一句「上面是自動重試的排程」,那是寫給我自己看的。 + // 使用者要的是三件事:**現在怎樣、為什麼、我要不要做什麼**。 + if n, wait, reason, ok := parseRetryMessage(raw); ok { + if reason != "" { + // 有原因就以原因為主,排程放後面當補充(他真正需要判斷的是原因) + return humanizeFailure(reason) + + fmt.Sprintf("(已經自動試過 %d 次,約 %s後會再試一次)", n, wait) + } + return fmt.Sprintf("已經自動試過 %d 次都沒成功,約 %s後會再試一次。"+ + "這個檔是在舊版失敗的,當時沒有記下原因;如果一直沒好,"+ + "到「版本與更新」旁邊把紀錄檔傳給我們。", n, wait) } return raw }