From 57e3ee4ceface0de202722140aed6f0877d0e103 Mon Sep 17 00:00:00 2001 From: chiyi Date: Thu, 9 Jul 2026 16:26:18 +0800 Subject: [PATCH] feat(grok): route only the conversations/new submit through the proxy Reference-frame upload, the mp4 download and OpenAsset (/content) streaming now egress on the local IP; only the generate submit uses proxy.url. Verified live: submit egress 98.97.26.37 (proxy) vs upload/download 76.209.9.65 (local), 3.47MB video generated OK. --- backend/internal/provider/grok/client.go | 11 +++++++++-- backend/internal/provider/grok/video.go | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/backend/internal/provider/grok/client.go b/backend/internal/provider/grok/client.go index ad2fe06..fef7954 100644 --- a/backend/internal/provider/grok/client.go +++ b/backend/internal/provider/grok/client.go @@ -689,7 +689,14 @@ func (c *Client) applyHeaders(req *http.Request, token string, extra map[string] req.Header = h } -func (c *Client) newTLSClient() (tlsclient.HttpClient, error) { +func (c *Client) newTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(true) } + +// newDirectTLSClient egresses on the local IP (never the proxy). Used for +// reference-frame upload and result (video) download; only the generate submit +// (/rest/app-chat/conversations/new) uses the proxy. +func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) } + +func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) { options := []tlsclient.HttpClientOption{ // Video generation streams inline until progress=100; a 15s clip can take // several minutes, so allow up to 10m (caller's genCtx caps at 12m). @@ -697,7 +704,7 @@ func (c *Client) newTLSClient() (tlsclient.HttpClient, error) { tlsclient.WithClientProfile(profiles.Chrome_133), tlsclient.WithRandomTLSExtensionOrder(), } - if c.proxy != "" { + if useProxy && c.proxy != "" { options = append(options, tlsclient.WithProxyUrl(c.proxy)) } return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...) diff --git a/backend/internal/provider/grok/video.go b/backend/internal/provider/grok/video.go index 6fbc4ae..1648aa8 100644 --- a/backend/internal/provider/grok/video.go +++ b/backend/internal/provider/grok/video.go @@ -54,7 +54,13 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio, seconds = 10 } - client, err := c.newTLSClient() + // Only the conversations/new submit egresses via the proxy; reference-frame + // upload and the mp4 download run on the local IP. + submitClient, err := c.newTLSClient() + if err != nil { + return nil, nil, err + } + directClient, err := c.newDirectTLSClient() if err != nil { return nil, nil, err } @@ -65,7 +71,7 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio, if len(f) == 0 { continue } - url, upErr := c.uploadImage(ctx, client, token, f) + url, upErr := c.uploadImage(ctx, directClient, token, f) if upErr != nil { return nil, nil, upErr } @@ -87,7 +93,7 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio, if ctx.Err() != nil { return nil, nil, ctx.Err() } - pid, cpErr := c.createPost(ctx, client, token, prompt) + pid, cpErr := c.createPost(ctx, submitClient, token, prompt) if cpErr != nil { lastErr = cpErr continue @@ -116,7 +122,7 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio, }, } - body, psErr := c.postStream(ctx, client, token, "/rest/app-chat/conversations/new", payload) + body, psErr := c.postStream(ctx, submitClient, token, "/rest/app-chat/conversations/new", payload) if psErr != nil { // Transient HTTP/2 stream resets etc. — retry. lastErr = psErr @@ -169,7 +175,7 @@ func (c *Client) GenerateVideo(ctx context.Context, token, prompt, aspectRatio, if !downloadResult { return nil, meta, nil } - data, err := c.download(ctx, client, token, fullURL) + data, err := c.download(ctx, directClient, token, fullURL) if err != nil { return nil, nil, err } @@ -342,7 +348,8 @@ func (c *Client) OpenAsset(ctx context.Context, token, url string) (io.ReadClose if token == "" { return nil, "", ErrAuth } - client, err := c.newTLSClient() + // Asset streaming is pure bandwidth (no anti-bot) — egress on the local IP. + client, err := c.newDirectTLSClient() if err != nil { return nil, "", err }