package chatgpt import ( "encoding/json" "fmt" "io" "net/http" "strings" "go-helper/internal/model" ) // FetchAccountInfo queries the ChatGPT accounts check API and returns team accounts // with subscription expiry information. func (c *Client) FetchAccountInfo(accessToken string) ([]model.TeamAccountInfo, error) { token := strings.TrimPrefix(strings.TrimSpace(accessToken), "Bearer ") if token == "" { return nil, fmt.Errorf("缺少 access token") } apiURL := "https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27" req, err := http.NewRequest("GET", apiURL, nil) if err != nil { return nil, err } req.Header.Set("Accept", "*/*") req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Set("Oai-Client-Version", oaiClientVersion) req.Header.Set("Oai-Language", "zh-CN") req.Header.Set("User-Agent", userAgent) resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("请求 ChatGPT API 失败: %w", err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode == 401 || resp.StatusCode == 402 { return nil, fmt.Errorf("Token 已过期或被封禁") } if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, fmt.Errorf("ChatGPT API 错误 %d: %s", resp.StatusCode, truncate(string(body), 300)) } var data struct { Accounts map[string]json.RawMessage `json:"accounts"` AccountOrdering []string `json:"account_ordering"` } if err := json.Unmarshal(body, &data); err != nil { return nil, fmt.Errorf("解析响应失败: %w", err) } var results []model.TeamAccountInfo // Determine order. seen := make(map[string]bool) var orderedIDs []string for _, id := range data.AccountOrdering { if _, ok := data.Accounts[id]; ok && !seen[id] { orderedIDs = append(orderedIDs, id) seen[id] = true } } for id := range data.Accounts { if !seen[id] && id != "default" { orderedIDs = append(orderedIDs, id) } } for _, id := range orderedIDs { raw := data.Accounts[id] var acc struct { Account struct { Name string `json:"name"` PlanType string `json:"plan_type"` } `json:"account"` Entitlement struct { ExpiresAt string `json:"expires_at"` HasActiveSubscription bool `json:"has_active_subscription"` } `json:"entitlement"` } if err := json.Unmarshal(raw, &acc); err != nil { continue } if acc.Account.PlanType != "team" { continue } results = append(results, model.TeamAccountInfo{ AccountID: id, Name: acc.Account.Name, PlanType: acc.Account.PlanType, ExpiresAt: acc.Entitlement.ExpiresAt, HasActiveSubscription: acc.Entitlement.HasActiveSubscription, }) } if len(results) == 0 { return nil, fmt.Errorf("未找到 Team 类型的账号") } return results, nil } func truncate(s string, max int) string { if len(s) <= max { return s } return s[:max] + "..." }