修复视频bug

This commit is contained in:
2026-07-02 11:50:50 +08:00
parent 41bd120404
commit ab94165af2
+42 -9
View File
@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"os"
"regexp" "regexp"
"strings" "strings"
@@ -66,10 +67,27 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio,
imageRefs = append(imageRefs, url) imageRefs = append(imageRefs, url)
} }
postID, err := c.createPost(ctx, client, token, prompt) // grok occasionally accepts the conversation (HTTP 200) but closes the stream
if err != nil { // after only the conversation object — no progress events, no videoUrl. This
return nil, nil, err // is transient, so retry the whole create-post + stream a few times before
// giving up. Real out-of-credits / auth errors are returned immediately.
const maxAttempts = 3
var (
postID string
artifact string
lastBody string
lastErr error
)
for attempt := 1; attempt <= maxAttempts; attempt++ {
if ctx.Err() != nil {
return nil, nil, ctx.Err()
} }
pid, cpErr := c.createPost(ctx, client, token, prompt)
if cpErr != nil {
lastErr = cpErr
continue
}
postID = pid
videoCfg := map[string]any{ videoCfg := map[string]any{
"parentPostId": postID, "parentPostId": postID,
@@ -93,23 +111,38 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio,
}, },
} }
body, err := c.postStream(ctx, client, token, "/rest/app-chat/conversations/new", payload) body, psErr := c.postStream(ctx, client, token, "/rest/app-chat/conversations/new", payload)
if err != nil { if psErr != nil {
return nil, nil, err // Transient HTTP/2 stream resets etc. — retry.
lastErr = psErr
continue
} }
// Out-of-credits surfaces as a stream error (HTTP is still 200). if dir := strings.TrimSpace(os.Getenv("GROK_DUMP")); dir != "" {
_ = os.WriteFile(dir+"/grok_body_"+postID+".txt", []byte(body), 0o644)
}
// Out-of-credits surfaces as a stream error (HTTP is still 200) — not retryable.
if strings.Contains(body, "usagePoolExhausted") || strings.Contains(body, "media generation credits") { if strings.Contains(body, "usagePoolExhausted") || strings.Contains(body, "media generation credits") {
return nil, nil, fmt.Errorf("%w: media generation credits exhausted", ErrQuotaExhausted) return nil, nil, fmt.Errorf("%w: media generation credits exhausted", ErrQuotaExhausted)
} }
// The artifact path appears as "videoUrl":"users/.../generated_video.mp4". // The artifact path appears as "videoUrl":"users/.../generated_video.mp4".
var artifact string lastBody = body
artifact = ""
for _, m := range videoURLRe.FindAllStringSubmatch(body, -1) { for _, m := range videoURLRe.FindAllStringSubmatch(body, -1) {
if v := strings.TrimSpace(m[1]); v != "" { if v := strings.TrimSpace(m[1]); v != "" {
artifact = v // keep the last (progress=100) one artifact = v // keep the last (progress=100) one
} }
} }
if artifact != "" {
break
}
// No artifact: grok closed the stream early. Retry.
lastErr = nil
}
if artifact == "" { if artifact == "" {
return nil, nil, fmt.Errorf("%w: no video artifact in response: %s", ErrTemporaryUpstream, clip([]byte(body), 200)) if lastErr != nil {
return nil, nil, lastErr
}
return nil, nil, fmt.Errorf("%w: no video artifact in response: %s", ErrTemporaryUpstream, clip([]byte(lastBody), 200))
} }
fullURL := artifact fullURL := artifact
if !strings.HasPrefix(fullURL, "http") { if !strings.HasPrefix(fullURL, "http") {