fix(adobe): 媒体分类接口抓不到参考图的 400 归为临时错误,自动换号重试

This commit is contained in:
2026-08-09 13:40:08 +08:00
parent eee8698f46
commit 4c5b932e81
+20
View File
@@ -74,6 +74,20 @@ func isContentRejection(status int, body string) bool {
return strings.Contains(body, "unsafe") || strings.Contains(body, "privacy_error") return strings.Contains(body, "unsafe") || strings.Contains(body, "privacy_error")
} }
// isClassifierGlitch reports whether a 400 comes from Adobe's media moderation
// backend failing to READ the media it was handed ("Gemini classification API
// returned HTTP 400 ... Cannot fetch content from the provided URL") rather than
// from the request being wrong. The blobs were just uploaded and the identical
// request succeeds on a retry, so this is a transient upstream fault: retrying
// (with freshly uploaded blobs) is the fix, and the account must not be blamed.
func isClassifierGlitch(status int, body string) bool {
if status != 400 {
return false
}
return strings.Contains(body, "media_classification_client_error") ||
strings.Contains(body, "classification API returned")
}
var profileURLs = []string{ var profileURLs = []string{
"https://ims-na1.adobelogin.com/ims/profile/v1", "https://ims-na1.adobelogin.com/ims/profile/v1",
"https://adobeid-na1.services.adobe.com/ims/profile/v1", "https://adobeid-na1.services.adobe.com/ims/profile/v1",
@@ -667,6 +681,9 @@ func (c *Client) pollImage(ctx context.Context, sess *tlsSession, token, pollURL
if resp.StatusCode == 429 || resp.StatusCode == 451 || resp.StatusCode >= 500 { if resp.StatusCode == 429 || resp.StatusCode == 451 || resp.StatusCode >= 500 {
return nil, nil, fmt.Errorf("%w (poll %d: %s)", ErrDeadUpstream, resp.StatusCode, clip(body, 300)) return nil, nil, fmt.Errorf("%w (poll %d: %s)", ErrDeadUpstream, resp.StatusCode, clip(body, 300))
} }
if isClassifierGlitch(resp.StatusCode, string(body)) {
return nil, nil, fmt.Errorf("%w (poll classifier: %s)", ErrTemporaryUpstream, clip(body, 300))
}
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
return nil, nil, fmt.Errorf("adobe poll failed: %d %s", resp.StatusCode, clip(body, 300)) return nil, nil, fmt.Errorf("adobe poll failed: %d %s", resp.StatusCode, clip(body, 300))
} }
@@ -867,6 +884,9 @@ func (c *Client) pollVideo(ctx context.Context, sess *tlsSession, token, pollURL
if resp.StatusCode == 429 || resp.StatusCode == 451 || resp.StatusCode >= 500 { if resp.StatusCode == 429 || resp.StatusCode == 451 || resp.StatusCode >= 500 {
return nil, nil, fmt.Errorf("%w (video poll %d: %s)", ErrDeadUpstream, resp.StatusCode, clip(body, 300)) return nil, nil, fmt.Errorf("%w (video poll %d: %s)", ErrDeadUpstream, resp.StatusCode, clip(body, 300))
} }
if isClassifierGlitch(resp.StatusCode, string(body)) {
return nil, nil, fmt.Errorf("%w (video poll classifier: %s)", ErrTemporaryUpstream, clip(body, 300))
}
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
return nil, nil, fmt.Errorf("adobe video poll failed: %d %s", resp.StatusCode, clip(body, 300)) return nil, nil, fmt.Errorf("adobe video poll failed: %d %s", resp.StatusCode, clip(body, 300))
} }