首頁「沒被整理的檔案」修兩病:同一件事講兩次/不說是哪一個檔
leo 08-06 封測回報(附截圖+「他放一個 md 檔無法通過」)。
## ① 同一件事講兩次,而且「另外」前面沒有東西
截圖實況:
「看起來不是文件,所以跳過了。」 ← 底下是空的(非文件檔不逐檔點名)
「**另外**有 1 個不是文件的檔案(圖片、影片、壓縮檔之類)也沒有處理。」
真兇:app.go buildSkipped 的 else 分支先寫一句通用說明,
接著無條件再寫 Other 那句——後者的「另外」是為「兩種都有」寫的,
在「只有非文件檔」時就變成前面沒有東西可以「另外」。
解:該分支只講一句、自己帶數量,且不留 Other。「另外」只在兩種都有時出現。
## ② 只報總數=等於沒說(這才是 md 那題卡住的原因)
封測者放 .md 說「無法通過」,但畫面只寫「有 1 個不是文件的檔案」,
**沒說是哪一個** ⇒ 誰也判斷不出發生什麼事。
而 `.md` 明明在 allowedExt 白名單裡(scan.go:26),我在本機實測也一次就過:
"path":"arcrun-md-test.md","status":"ingested","http_status":200
⇒ 那個「1 個」必然不是他以為的那個檔(副檔名被 Windows 藏起來、存成別的格式…),
但沒有檔名就永遠查不出來。
解:scan 收集非文件檔的檔名(上限 5 個),一路帶到 status.json 與首頁。
「只報總數」在幾百張圖時是對的,在 1 個時是失職——少量就點名。
## 驗
· 兩支新測試釘住規則:只有非文件檔時不准出現第二句、不准出現「另外」;
兩種都有時「另外」才成立並帶數量
· 實際文案打出來看過(見下),不是只看測試綠
有 1 個檔案沒有被整理
看起來不是文件(圖片、影片、壓縮檔之類),所以跳過了。這是正常的,你不用做什麼。
· 我的筆記.md.txt
· 312 張圖的情況:列 5 個 +「…還有 307 個」,不洗版
· collector 全測試過、app 測試過、go vet 全綠
This commit is contained in:
@@ -67,22 +67,22 @@ type DirectConfig struct {
|
||||
InstanceName string `json:"instance_name,omitempty"` // 暱稱(舊制)
|
||||
Library string `json:"library"` // 藏書地圖歸庫鍵(空=kb;per-folder 未指定時的後備)
|
||||
// t52:每個看守資料夾對應自己的庫(key=絕對路徑,value=庫名);新制走 AccountConfig.Libraries。
|
||||
Libraries map[string]string `json:"libraries,omitempty"`
|
||||
IngestWF string `json:"ingest_workflow"` // 直送萃取 workflow 名(空=rag_ingest_direct)
|
||||
RemovedWF string `json:"removed_workflow"` // 下架 workflow 名(空=rag_takedown_direct)
|
||||
Libraries map[string]string `json:"libraries,omitempty"`
|
||||
IngestWF string `json:"ingest_workflow"` // 直送萃取 workflow 名(空=rag_ingest_direct)
|
||||
RemovedWF string `json:"removed_workflow"` // 下架 workflow 名(空=rag_takedown_direct)
|
||||
// —— 四步定稿(daemon-beta t3/t4/t6):本地萃卡模式 ——
|
||||
Extractor string `json:"extractor,omitempty"` // "workers-ai"(預設,免金鑰)|"gemma"|"claude"(已停用)
|
||||
Extractor string `json:"extractor,omitempty"` // "workers-ai"(預設,免金鑰)|"gemma"|"claude"(已停用)
|
||||
// t181:使用者**主動在托盤選過**萃取引擎才為 true。false=一律走 workers-ai。
|
||||
// 判準刻意不是「有沒有金鑰」——leo 08-04:「不管你現在是否有填金鑰」都要先 default
|
||||
// Workers AI,否則他得「花在解釋為什麼 Gemini 不管用上」。
|
||||
// 有金鑰但沒主動選 ⇒ 金鑰留著不動,之後選 Gemini 立刻可用。
|
||||
ExtractorExplicit bool `json:"extractor_explicit,omitempty"`
|
||||
ClaudeBin string `json:"claude_bin,omitempty"` // claude 執行檔(空=PATH 找 claude)
|
||||
GeminiAPIKey string `json:"gemini_api_key,omitempty"` // gemma 路的用戶 key
|
||||
LLMModel string `json:"llm_model,omitempty"` // gemma 路模型(空=gemma-4-31b-it)
|
||||
CardIngestWF string `json:"card_ingest_workflow,omitempty"` // 收卡 workflow(空=rag_ingest_card)
|
||||
PollSec int `json:"poll_interval_sec"` // 輪詢間隔秒(空/0=5)
|
||||
MaxRemoved float64 `json:"max_removed_ratio"` // 大量刪除防呆門檻(空/0=0.4)
|
||||
ExtractorExplicit bool `json:"extractor_explicit,omitempty"`
|
||||
ClaudeBin string `json:"claude_bin,omitempty"` // claude 執行檔(空=PATH 找 claude)
|
||||
GeminiAPIKey string `json:"gemini_api_key,omitempty"` // gemma 路的用戶 key
|
||||
LLMModel string `json:"llm_model,omitempty"` // gemma 路模型(空=gemma-4-31b-it)
|
||||
CardIngestWF string `json:"card_ingest_workflow,omitempty"` // 收卡 workflow(空=rag_ingest_card)
|
||||
PollSec int `json:"poll_interval_sec"` // 輪詢間隔秒(空/0=5)
|
||||
MaxRemoved float64 `json:"max_removed_ratio"` // 大量刪除防呆門檻(空/0=0.4)
|
||||
|
||||
// ForceSync=這一輪是使用者按「立刻同步」觸發的(t195)。
|
||||
// 為真時忽略失敗退避與次數上限,一律重送——**人明確要求時不該被機器的退避擋住**。
|
||||
@@ -430,8 +430,8 @@ func pageNameOf(relPath string) string {
|
||||
|
||||
// DirectResult 是單一事件的直送結果(隨每輪 log 輸出)。
|
||||
type DirectResult struct {
|
||||
Account string `json:"account,omitempty"` // t104: cypher_url host(多帳號標的)
|
||||
Root string `json:"root,omitempty"` // 多資料夾時標明事件屬於哪個根
|
||||
Account string `json:"account,omitempty"` // t104: cypher_url host(多帳號標的)
|
||||
Root string `json:"root,omitempty"` // 多資料夾時標明事件屬於哪個根
|
||||
Type string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
Status string `json:"status"` // ingested | removed | planned | failed | skipped
|
||||
@@ -553,6 +553,7 @@ func RunDirectOnce(cfg *DirectConfig, dryRun bool) ([]DirectResult, int, *Trigge
|
||||
// 使用者不該因為我們的內部結構而看到同一個檔名列兩次。
|
||||
skippedSeen := map[string]SkippedFile{}
|
||||
skippedOther := 0
|
||||
var skippedOtherNames []string
|
||||
|
||||
accountDetails := map[string]AccountSyncStatus{}
|
||||
for _, acc := range accounts {
|
||||
@@ -618,6 +619,8 @@ func RunDirectOnce(cfg *DirectConfig, dryRun bool) ([]DirectResult, int, *Trigge
|
||||
skippedSeen[sf.Path] = sf
|
||||
}
|
||||
skippedOther += p.SkippedOther
|
||||
// 同理,每一根的檔名都要收(上限在寫進 status 時才裁)。
|
||||
skippedOtherNames = append(skippedOtherNames, p.SkippedOtherNames...)
|
||||
}
|
||||
}
|
||||
accountDetails[accHost] = accSt
|
||||
@@ -634,6 +637,12 @@ func RunDirectOnce(cfg *DirectConfig, dryRun bool) ([]DirectResult, int, *Trigge
|
||||
// G-6.2:把「讀不了的檔」寫進狀態檔,App 首頁才有東西可以講。
|
||||
// 排序=畫面每輪穩定(map 迭代順序隨機,不排的話清單會自己跳動)。
|
||||
st.SkippedOtherCount = skippedOther
|
||||
// 少量時點名(maxOtherNames 個以內)——leo 08-06 封測:只報「1 個」等於沒說。
|
||||
sort.Strings(skippedOtherNames)
|
||||
if len(skippedOtherNames) > maxOtherNames {
|
||||
skippedOtherNames = skippedOtherNames[:maxOtherNames]
|
||||
}
|
||||
st.SkippedOtherNames = skippedOtherNames
|
||||
st.SkippedDocCount = len(skippedSeen)
|
||||
for _, sf := range skippedSeen {
|
||||
st.SkippedDocs = append(st.SkippedDocs, sf)
|
||||
@@ -994,7 +1003,6 @@ func runDirect(args []string) int {
|
||||
return exit
|
||||
}
|
||||
|
||||
|
||||
// 四步定稿第 1 步:daemon 代裝 template——常駐看守前確保每根都鋪好(冪等,不覆寫既有檔)。
|
||||
// dry-run/--once 測試情境不代裝(不留副作用),由 template-install 子命令顯式做。
|
||||
if !*once && !*dryRun {
|
||||
|
||||
Reference in New Issue
Block a user