package chinamobile_seedance import ( "fmt" "strings" "sync" "time" maas "maas_seedance_sdk_1.0.0_go" ) const ( defaultBaseURL = "https://zhenze-huhehaote.cmecloud.cn/api/v3" defaultModel = "doubao-seedance-2.0" defaultSubmitTimeout = 180 * time.Second defaultQueryTimeout = 60 * time.Second sdkAcquireTimeout = 2 * time.Second ) var sdkSemaphore = make(chan struct{}, 4) type seedanceSDK interface { CreateVideoGenerationTask(data map[string]interface{}) (string, error) QueryVideoGenerationTask(taskID string) (map[string]interface{}, error) } type seedanceSDKFactory func(baseURL, apiKey, model string) (seedanceSDK, error) func newRealSDK(baseURL, apiKey, model string) (seedanceSDK, error) { baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/") if baseURL == "" { baseURL = defaultBaseURL } model = strings.TrimSpace(model) if model == "" { model = defaultModel } return runSDKCall[seedanceSDK](defaultQueryTimeout, func() (seedanceSDK, error) { return maas.NewMaasSeedanceClient(baseURL, apiKey, model, false) }) } func runSDKCall[T any](timeout time.Duration, fn func() (T, error)) (T, error) { var zero T select { case sdkSemaphore <- struct{}{}: case <-time.After(sdkAcquireTimeout): return zero, fmt.Errorf("upstream_busy: sdk concurrency limit reached") } type result struct { value T err error } var releaseOnce sync.Once release := func() { releaseOnce.Do(func() { <-sdkSemaphore }) } done := make(chan result, 1) go func() { res := result{} defer func() { if r := recover(); r != nil { res.err = fmt.Errorf("upstream_sdk_panic: %v", r) } release() done <- res }() res.value, res.err = fn() }() select { case res := <-done: return res.value, res.err case <-time.After(timeout): release() return zero, fmt.Errorf("upstream_timeout: sdk call exceeded %s", timeout) } }