feat(providers): route only the generate submit through the proxy
Extends the adobe split to leonardo, krea, imagine, runway (image+video) and chatgpt: reference-image upload, polling and result download egress on the local IP; only the generate/task-create submit uses proxy.url. chatgpt keeps its anti-bot-guarded submit+upload phase on the proxy and moves only the existing second (poll/resolve/download) session to local. custom is already direct. Build+vet pass; adobe verified live, the other providers are code-complete but not yet live-tested (no dev accounts).
This commit is contained in:
@@ -110,7 +110,9 @@ func (c *Client) GenerateImage(ctx context.Context, accessToken, prompt, model,
|
|||||||
refIDs := uploadedRefIDSet(uploadedRefs)
|
refIDs := uploadedRefIDSet(uploadedRefs)
|
||||||
fileIDs = dropIDs(fileIDs, refIDs)
|
fileIDs = dropIDs(fileIDs, refIDs)
|
||||||
sedimentIDs = dropIDs(sedimentIDs, refIDs)
|
sedimentIDs = dropIDs(sedimentIDs, refIDs)
|
||||||
session, err = c.newSession(accessToken)
|
// Poll / resolve / download run on the local IP (fresh direct session);
|
||||||
|
// only the submit phase above egressed via the proxy.
|
||||||
|
session, err = c.newDirectSession(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -219,6 +221,17 @@ type chatRequirements struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) newSession(accessToken string) (tlsclient.HttpClient, error) {
|
func (c *Client) newSession(accessToken string) (tlsclient.HttpClient, error) {
|
||||||
|
return c.newSessionP(accessToken, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDirectSession egresses on the local IP (never the proxy). Used for the
|
||||||
|
// poll / resolve / download phase; only the anti-bot-guarded submit phase
|
||||||
|
// (bootstrap, chat-requirements, upload, conversation create) uses the proxy.
|
||||||
|
func (c *Client) newDirectSession(accessToken string) (tlsclient.HttpClient, error) {
|
||||||
|
return c.newSessionP(accessToken, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) newSessionP(accessToken string, useProxy bool) (tlsclient.HttpClient, error) {
|
||||||
options := []tlsclient.HttpClientOption{
|
options := []tlsclient.HttpClientOption{
|
||||||
tlsclient.WithTimeoutSeconds(600),
|
tlsclient.WithTimeoutSeconds(600),
|
||||||
// Match the Python reference (curl_cffi impersonate="chrome110"): the
|
// Match the Python reference (curl_cffi impersonate="chrome110"): the
|
||||||
@@ -226,7 +239,7 @@ func (c *Client) newSession(accessToken string) (tlsclient.HttpClient, error) {
|
|||||||
tlsclient.WithClientProfile(profiles.Chrome_110),
|
tlsclient.WithClientProfile(profiles.Chrome_110),
|
||||||
tlsclient.WithRandomTLSExtensionOrder(),
|
tlsclient.WithRandomTLSExtensionOrder(),
|
||||||
}
|
}
|
||||||
if c.proxy != "" {
|
if useProxy && c.proxy != "" {
|
||||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||||
}
|
}
|
||||||
client, err := tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
client, err := tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||||
|
|||||||
@@ -337,7 +337,12 @@ func (c *Client) FetchCreditsBalance(ctx context.Context, cred string) (map[stri
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func (c *Client) apiGet(ctx context.Context, token, url string) ([]byte, int, error) {
|
func (c *Client) apiGet(ctx context.Context, token, url string) ([]byte, int, error) {
|
||||||
client, err := c.newTLSClient()
|
return c.apiGetP(ctx, token, url, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apiGetP picks the egress: polling runs direct (local IP).
|
||||||
|
func (c *Client) apiGetP(ctx context.Context, token, url string, useProxy bool) ([]byte, int, error) {
|
||||||
|
client, err := c.newTLSClientP(useProxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -365,12 +370,18 @@ func (c *Client) apiGet(ctx context.Context, token, url string) ([]byte, int, er
|
|||||||
return b, resp.StatusCode, err
|
return b, resp.StatusCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
// polling and result download.
|
||||||
|
func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) }
|
||||||
|
|
||||||
|
func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) {
|
||||||
options := []tlsclient.HttpClientOption{
|
options := []tlsclient.HttpClientOption{
|
||||||
tlsclient.WithTimeoutSeconds(60),
|
tlsclient.WithTimeoutSeconds(60),
|
||||||
tlsclient.WithClientProfile(profiles.Chrome_120),
|
tlsclient.WithClientProfile(profiles.Chrome_120),
|
||||||
}
|
}
|
||||||
if c.proxy != "" {
|
if useProxy && c.proxy != "" {
|
||||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||||
}
|
}
|
||||||
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func (c *Client) pollImage(ctx context.Context, token, userID, batchID string) (
|
|||||||
|
|
||||||
url := teamsBase + "/v1/org/" + userID + "/objects?batch=true&limit=50&service=image,chat-image"
|
url := teamsBase + "/v1/org/" + userID + "/objects?batch=true&limit=50&service=image,chat-image"
|
||||||
for {
|
for {
|
||||||
body, status, err := c.apiGet(ctx, token, url)
|
body, status, err := c.apiGetP(ctx, token, url, false)
|
||||||
if err == nil && status == 200 {
|
if err == nil && status == 200 {
|
||||||
var resp struct {
|
var resp struct {
|
||||||
Data []struct {
|
Data []struct {
|
||||||
@@ -181,7 +181,7 @@ func firstImageURL(raw string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) download(ctx context.Context, url string) ([]byte, error) {
|
func (c *Client) download(ctx context.Context, url string) ([]byte, error) {
|
||||||
client, err := c.newTLSClient()
|
client, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,12 @@ func accountKey(cookie string) string {
|
|||||||
|
|
||||||
// apiGet issues a GET to a krea.ai API path carrying the account cookie.
|
// apiGet issues a GET to a krea.ai API path carrying the account cookie.
|
||||||
func (c *Client) apiGet(ctx context.Context, cookie, path string) ([]byte, int, error) {
|
func (c *Client) apiGet(ctx context.Context, cookie, path string) ([]byte, int, error) {
|
||||||
client, err := c.newTLSClient()
|
return c.apiGetP(ctx, cookie, path, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apiGetP picks the egress: polling / asset resolution run direct (local IP).
|
||||||
|
func (c *Client) apiGetP(ctx context.Context, cookie, path string, useProxy bool) ([]byte, int, error) {
|
||||||
|
client, err := c.newTLSClientP(useProxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -426,12 +431,18 @@ func (c *Client) apiGet(ctx context.Context, cookie, path string) ([]byte, int,
|
|||||||
return b, resp.StatusCode, err
|
return b, resp.StatusCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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-image upload, polling and result download.
|
||||||
|
func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) }
|
||||||
|
|
||||||
|
func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) {
|
||||||
options := []tlsclient.HttpClientOption{
|
options := []tlsclient.HttpClientOption{
|
||||||
tlsclient.WithTimeoutSeconds(60),
|
tlsclient.WithTimeoutSeconds(60),
|
||||||
tlsclient.WithClientProfile(profiles.Chrome_120),
|
tlsclient.WithClientProfile(profiles.Chrome_120),
|
||||||
}
|
}
|
||||||
if c.proxy != "" {
|
if useProxy && c.proxy != "" {
|
||||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||||
}
|
}
|
||||||
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func (c *Client) uploadImage(ctx context.Context, cookie string, img []byte) (st
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_ = w.Close()
|
_ = w.Close()
|
||||||
body, status, err := c.apiPost(ctx, cookie, "/api/upload?", w.FormDataContentType(), buf.Bytes())
|
body, status, err := c.apiPostP(ctx, cookie, "/api/upload?", w.FormDataContentType(), buf.Bytes(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%w: upload: %s", ErrTemporaryUpstream, err.Error())
|
return "", fmt.Errorf("%w: upload: %s", ErrTemporaryUpstream, err.Error())
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ func (c *Client) pollImage(ctx context.Context, cookie, jobID string) (string, e
|
|||||||
deadline := time.Now().Add(4 * time.Minute)
|
deadline := time.Now().Add(4 * time.Minute)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
body, status, err := c.apiGet(ctx, cookie, "/api/job-status?id="+jobID)
|
body, status, err := c.apiGetP(ctx, cookie, "/api/job-status?id="+jobID, false)
|
||||||
if err == nil && status == 200 {
|
if err == nil && status == 200 {
|
||||||
var js struct {
|
var js struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
@@ -215,7 +215,7 @@ func (c *Client) pollImage(ctx context.Context, cookie, jobID string) (string, e
|
|||||||
|
|
||||||
// assetForJob finds the generated asset produced by a job and returns its URL.
|
// assetForJob finds the generated asset produced by a job and returns its URL.
|
||||||
func (c *Client) assetForJob(ctx context.Context, cookie, jobID string) (string, error) {
|
func (c *Client) assetForJob(ctx context.Context, cookie, jobID string) (string, error) {
|
||||||
body, status, err := c.apiGet(ctx, cookie, "/api/assets?filter=generated&offset=0")
|
body, status, err := c.apiGetP(ctx, cookie, "/api/assets?filter=generated&offset=0", false)
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
return "", fmt.Errorf("assets http %d", status)
|
return "", fmt.Errorf("assets http %d", status)
|
||||||
}
|
}
|
||||||
@@ -237,7 +237,7 @@ func (c *Client) assetForJob(ctx context.Context, cookie, jobID string) (string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) download(ctx context.Context, url string) ([]byte, error) {
|
func (c *Client) download(ctx context.Context, url string) ([]byte, error) {
|
||||||
client, err := c.newTLSClient()
|
client, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,13 @@ func (c *Client) download(ctx context.Context, url string) ([]byte, error) {
|
|||||||
|
|
||||||
// apiPost issues a POST with a raw body + content-type, carrying the cookie.
|
// apiPost issues a POST with a raw body + content-type, carrying the cookie.
|
||||||
func (c *Client) apiPost(ctx context.Context, cookie, path, contentType string, body []byte) ([]byte, int, error) {
|
func (c *Client) apiPost(ctx context.Context, cookie, path, contentType string, body []byte) ([]byte, int, error) {
|
||||||
client, err := c.newTLSClient()
|
return c.apiPostP(ctx, cookie, path, contentType, body, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// apiPostP picks the egress: reference-image upload runs direct (local IP), the
|
||||||
|
// generate submit uses the proxy.
|
||||||
|
func (c *Client) apiPostP(ctx context.Context, cookie, path, contentType string, body []byte, useProxy bool) ([]byte, int, error) {
|
||||||
|
client, err := c.newTLSClientP(useProxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,10 +248,15 @@ func (c *Client) FetchCreditsBalance(ctx context.Context, cookie string) (map[st
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// graphql POSTs a GraphQL body to the Leonardo API with the bearer + schema header,
|
// graphql runs a GraphQL call through the proxy. graphqlP lets callers pick the
|
||||||
// returning the raw response body and status.
|
// egress: only the generate submit uses the proxy; reference-image upload and
|
||||||
|
// polling run direct (local IP).
|
||||||
func (c *Client) graphql(ctx context.Context, accessToken string, payload []byte) ([]byte, int, error) {
|
func (c *Client) graphql(ctx context.Context, accessToken string, payload []byte) ([]byte, int, error) {
|
||||||
client, err := c.newTLSClient()
|
return c.graphqlP(ctx, accessToken, payload, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) graphqlP(ctx context.Context, accessToken string, payload []byte, useProxy bool) ([]byte, int, error) {
|
||||||
|
client, err := c.newTLSClientP(useProxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -300,7 +305,13 @@ func unknownBalance(reason string) map[string]any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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-image upload, polling and result download.
|
||||||
|
func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) }
|
||||||
|
|
||||||
|
func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) {
|
||||||
// Match the fingerprint proven to work against Leonardo's Cloudflare edge:
|
// Match the fingerprint proven to work against Leonardo's Cloudflare edge:
|
||||||
// Chrome_120, fixed extension order. A randomized JA3 (Chrome_133 +
|
// Chrome_120, fixed extension order. A randomized JA3 (Chrome_133 +
|
||||||
// WithRandomTLSExtensionOrder) gets flagged and 429'd at get-session.
|
// WithRandomTLSExtensionOrder) gets flagged and 429'd at get-session.
|
||||||
@@ -308,7 +319,7 @@ func (c *Client) newTLSClient() (tlsclient.HttpClient, error) {
|
|||||||
tlsclient.WithTimeoutSeconds(60),
|
tlsclient.WithTimeoutSeconds(60),
|
||||||
tlsclient.WithClientProfile(profiles.Chrome_120),
|
tlsclient.WithClientProfile(profiles.Chrome_120),
|
||||||
}
|
}
|
||||||
if c.proxy != "" {
|
if useProxy && c.proxy != "" {
|
||||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||||
}
|
}
|
||||||
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||||
@@ -319,7 +330,7 @@ func (c *Client) downloadImage(ctx context.Context, imageURL string) ([]byte, er
|
|||||||
if _, err := url.Parse(imageURL); err != nil {
|
if _, err := url.Parse(imageURL); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
client, err := c.newTLSClient()
|
client, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func (c *Client) uploadInitImage(ctx context.Context, accessToken string, img []
|
|||||||
"query": mUploadImage,
|
"query": mUploadImage,
|
||||||
"variables": map[string]any{"uploadImageInput": map[string]any{"uploadType": "INIT", "extension": "png"}},
|
"variables": map[string]any{"uploadImageInput": map[string]any{"uploadType": "INIT", "extension": "png"}},
|
||||||
})
|
})
|
||||||
body, status, err := c.graphql(ctx, accessToken, payload)
|
body, status, err := c.graphqlP(ctx, accessToken, payload, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%w: upload-init: %s", ErrTemporaryUpstream, err.Error())
|
return "", fmt.Errorf("%w: upload-init: %s", ErrTemporaryUpstream, err.Error())
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ func (c *Client) uploadInitImage(ctx context.Context, accessToken string, img []
|
|||||||
}
|
}
|
||||||
_ = w.Close()
|
_ = w.Close()
|
||||||
|
|
||||||
client, err := c.newTLSClient()
|
client, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ func (c *Client) pollImage(ctx context.Context, accessToken, genID string) (stri
|
|||||||
deadline := time.Now().Add(5 * time.Minute)
|
deadline := time.Now().Add(5 * time.Minute)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
body, status, err := c.graphql(ctx, accessToken, payload)
|
body, status, err := c.graphqlP(ctx, accessToken, payload, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%w: poll: %s", ErrTemporaryUpstream, err.Error())
|
return "", fmt.Errorf("%w: poll: %s", ErrTemporaryUpstream, err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,13 +180,19 @@ func unknownBalance(reason string) map[string]any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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-image upload, polling and result download.
|
||||||
|
func (c *Client) newDirectTLSClient() (tlsclient.HttpClient, error) { return c.newTLSClientP(false) }
|
||||||
|
|
||||||
|
func (c *Client) newTLSClientP(useProxy bool) (tlsclient.HttpClient, error) {
|
||||||
options := []tlsclient.HttpClientOption{
|
options := []tlsclient.HttpClientOption{
|
||||||
tlsclient.WithTimeoutSeconds(30),
|
tlsclient.WithTimeoutSeconds(30),
|
||||||
tlsclient.WithClientProfile(profiles.Chrome_133),
|
tlsclient.WithClientProfile(profiles.Chrome_133),
|
||||||
tlsclient.WithRandomTLSExtensionOrder(),
|
tlsclient.WithRandomTLSExtensionOrder(),
|
||||||
}
|
}
|
||||||
if c.proxy != "" {
|
if useProxy && c.proxy != "" {
|
||||||
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
options = append(options, tlsclient.WithProxyUrl(c.proxy))
|
||||||
}
|
}
|
||||||
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
return tlsclient.NewHttpClient(tlsclient.NewNoopLogger(), options...)
|
||||||
|
|||||||
@@ -39,7 +39,13 @@ func (c *Client) GenerateImage(ctx context.Context, token, teamID, prompt, aspec
|
|||||||
imageSize = "1K"
|
imageSize = "1K"
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := c.newTLSClient()
|
// Only the task-create (generate submit) egresses via the proxy; reference
|
||||||
|
// upload, polling and download run on the local IP.
|
||||||
|
submitClient, err := c.newTLSClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
directClient, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -50,7 +56,7 @@ func (c *Client) GenerateImage(ctx context.Context, token, teamID, prompt, aspec
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filename := fmt.Sprintf("ref_%s_%d.png", time.Now().UTC().Format("20060102_150405"), i+1)
|
filename := fmt.Sprintf("ref_%s_%d.png", time.Now().UTC().Format("20060102_150405"), i+1)
|
||||||
assetID, url, upErr := c.uploadReference(ctx, client, token, teamID, filename, raw)
|
assetID, url, upErr := c.uploadReference(ctx, directClient, token, teamID, filename, raw)
|
||||||
if upErr != nil {
|
if upErr != nil {
|
||||||
return nil, nil, upErr
|
return nil, nil, upErr
|
||||||
}
|
}
|
||||||
@@ -61,15 +67,15 @@ func (c *Client) GenerateImage(ctx context.Context, token, teamID, prompt, aspec
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
taskID, err := c.createImageTask(ctx, client, token, teamID, prompt, aspectRatio, imageSize, refImages)
|
taskID, err := c.createImageTask(ctx, submitClient, token, teamID, prompt, aspectRatio, imageSize, refImages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
artifactURL, err := c.pollTask(ctx, client, token, teamID, taskID)
|
artifactURL, err := c.pollTask(ctx, directClient, token, teamID, taskID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
data, err := c.download(ctx, client, artifactURL)
|
data, err := c.download(ctx, directClient, artifactURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,33 +70,39 @@ func (c *Client) GenerateVideo(ctx context.Context, token, teamID, prompt, aspec
|
|||||||
return nil, nil, errors.New("runway: failed to decode first-frame image")
|
return nil, nil, errors.New("runway: failed to decode first-frame image")
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := c.newTLSClient()
|
// Only the task-create (generate submit) egresses via the proxy; first-frame
|
||||||
|
// upload, polling and download run on the local IP.
|
||||||
|
submitClient, err := c.newTLSClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
directClient, err := c.newDirectTLSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := "frame_" + time.Now().UTC().Format("20060102_150405") + ".png"
|
filename := "frame_" + time.Now().UTC().Format("20060102_150405") + ".png"
|
||||||
previewUploadID, _, err := c.uploadFile(ctx, client, token, teamID, filename, "DATASET_PREVIEW", frame)
|
previewUploadID, _, err := c.uploadFile(ctx, directClient, token, teamID, filename, "DATASET_PREVIEW", frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
datasetUploadID, _, err := c.uploadFile(ctx, client, token, teamID, filename, "DATASET", frame)
|
datasetUploadID, _, err := c.uploadFile(ctx, directClient, token, teamID, filename, "DATASET", frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
assetID, imageURL, err := c.createDataset(ctx, client, token, teamID, filename, datasetUploadID, previewUploadID, cfg.Width, cfg.Height)
|
assetID, imageURL, err := c.createDataset(ctx, directClient, token, teamID, filename, datasetUploadID, previewUploadID, cfg.Width, cfg.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
assetGroupID, _ := c.assetGroupID(ctx, client, token, teamID) // best-effort
|
assetGroupID, _ := c.assetGroupID(ctx, directClient, token, teamID) // best-effort
|
||||||
|
|
||||||
taskID, err := c.createTask(ctx, client, token, teamID, prompt, imageURL, assetID, assetGroupID, aspectRatio, seconds)
|
taskID, err := c.createTask(ctx, submitClient, token, teamID, prompt, imageURL, assetID, assetGroupID, aspectRatio, seconds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactURL, err := c.pollTask(ctx, client, token, teamID, taskID)
|
artifactURL, err := c.pollTask(ctx, directClient, token, teamID, taskID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -109,7 +115,7 @@ func (c *Client) GenerateVideo(ctx context.Context, token, teamID, prompt, aspec
|
|||||||
if !downloadResult {
|
if !downloadResult {
|
||||||
return nil, meta, nil
|
return nil, meta, nil
|
||||||
}
|
}
|
||||||
data, err := c.download(ctx, client, artifactURL)
|
data, err := c.download(ctx, directClient, artifactURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user