sync: collector/ 同步自 inkstone/arcrun-rag@740c55c(桌面小幫手 0.18.44)
This commit is contained in:
+36
-8
@@ -23,6 +23,7 @@ package collector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -31,6 +32,10 @@ import (
|
||||
)
|
||||
|
||||
// probeHTTP 探測用短逾時:只是要知道 route 在不在,不等 LLM 生成。
|
||||
//
|
||||
// 🔴 `inkstone/arcrun-rag#153`:這把 20 秒是保險,真正的上限由呼叫端帶進來的
|
||||
// context 決定。探測是**每輪、每個帳號的第一發**——它撞到不回應的端點時,
|
||||
// 後面所有帳號都還沒開始,所以它也是最早能認出「這個帳號今天不回應」的位置。
|
||||
var probeHTTP = &http.Client{Timeout: 20 * time.Second}
|
||||
|
||||
// CloudAIState 是「某個雲端實例的 Workers AI 萃取能力」探測結果。
|
||||
@@ -47,25 +52,27 @@ type CloudAIState struct {
|
||||
// ⇒ 算通。這樣探測不會真的燒 LLM 額度,也不會產生垃圾卡片。
|
||||
// - 401 代表 route 在、只是金鑰不對 ⇒ route 存在,同樣算「雲端有這功能」,
|
||||
// 金鑰問題由既有的連線流程去報,不混在這裡講。
|
||||
func ProbeWorkersAI(cypherURL, apiKey string) CloudAIState {
|
||||
func ProbeWorkersAI(ctx context.Context, cypherURL, apiKey string) (CloudAIState, error) {
|
||||
base := strings.TrimSuffix(strings.TrimSpace(cypherURL), "/")
|
||||
if base == "" {
|
||||
return CloudAIState{Ready: false, Note: "還沒連上知識庫"}
|
||||
return CloudAIState{Ready: false, Note: "還沒連上知識庫"}, nil
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(map[string]string{"page_name": "", "text": ""})
|
||||
req, err := http.NewRequest(http.MethodPost, base+"/portal/daemon/extract", bytes.NewReader(body))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, base+"/portal/daemon/extract", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return CloudAIState{Ready: false, Note: "雲端 AI 狀態查不到"}
|
||||
return CloudAIState{Ready: false, Note: "雲端 AI 狀態查不到"}, nil
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-Arcrun-API-Key", strings.TrimSpace(apiKey))
|
||||
|
||||
resp, err := probeHTTP.Do(req)
|
||||
if err != nil {
|
||||
// #153:錯誤原件一起回去,呼叫端才分得出「等到超時」與「立刻連不上」——
|
||||
// 前者要記進斷路器,後者不該(不然一次斷網就把帳號判成停機)。
|
||||
// 連不上(離線/網路問題)≠ 雲端沒裝。講「查不到」而不是「還沒通」,
|
||||
// 免得把網路問題誤報成「你沒更新」讓用戶白跑一趟。
|
||||
return CloudAIState{Ready: false, Note: "連不上你的知識庫,雲端 AI 狀態查不到"}
|
||||
return CloudAIState{Ready: false, Note: "連不上你的知識庫,雲端 AI 狀態查不到"}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -74,14 +81,35 @@ func ProbeWorkersAI(cypherURL, apiKey string) CloudAIState {
|
||||
return CloudAIState{
|
||||
Ready: false,
|
||||
Note: "雲端 AI 還沒通 ⇒ 你的知識庫是舊版,請到 portal 按「立即更新」重裝一次",
|
||||
}
|
||||
}, nil
|
||||
case resp.StatusCode < 500:
|
||||
// 200/400/401… 都代表這條 route 存在=雲端有這個功能。
|
||||
return CloudAIState{Ready: true}
|
||||
return CloudAIState{Ready: true}, nil
|
||||
default:
|
||||
return CloudAIState{
|
||||
Ready: false,
|
||||
Note: fmt.Sprintf("雲端 AI 暫時有狀況(HTTP %d),稍後會自動再試", resp.StatusCode),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// probeWorkersAI=帶「等待閘」的探測(`inkstone/arcrun-rag#153`)。
|
||||
//
|
||||
// 為什麼這一發特別重要:它是每輪、每個帳號的**第一發**。撞到不回應的端點時,
|
||||
// 後面的資料夾一件都還沒開始 ⇒ 這裡認出來,整個帳號的其餘工作就都省下來了。
|
||||
// 反過來說,漏掉這一發的話,前面所有的閘都白裝——2026-08-28 第一版就是這樣:
|
||||
// 斷路器跳了,可是一輪還是要 20 秒,因為那 20 秒全花在這一發上。
|
||||
func (c *DirectConfig) probeWorkersAI() CloudAIState {
|
||||
if note := c.unreachableNote(); note != "" {
|
||||
return CloudAIState{Ready: false, Note: note}
|
||||
}
|
||||
gate := c.openGate(stepProbeAI)
|
||||
state, err := ProbeWorkersAI(gate.ctx, c.CypherURL, c.APIKey)
|
||||
gate.release()
|
||||
if perr := gate.record(err); perr != nil {
|
||||
// 等到超時 ⇒ 講的是「沒有回應」,不是「你的雲端沒裝好」。
|
||||
// 把等待誤報成「你沒更新」會害使用者白跑一趟去按重裝。
|
||||
return CloudAIState{Ready: false, Note: perr.Error()}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user