package qcclient import ( "encoding/json" "fmt" "strconv" "strings" ) type APIResponse[T any] struct { Status string `json:"status"` Data T `json:"data"` } type APIError struct { Status string `json:"status"` Message string `json:"message"` Code string `json:"code"` Details map[string]any `json:"details,omitempty"` } type Template struct { ID int64 `json:"id"` Name string `json:"name"` Description string `json:"description"` Locale string `json:"locale"` ThumbnailURL string `json:"thumbnailUrl"` TemplatePreviewURL string `json:"templatePreviewUrl"` Type string `json:"type"` PaletteReady Boolish `json:"paletteReady"` GlobalColors map[string]any `json:"globalColors"` TextsWithGlobalColors map[string]any `json:"textsWithGlobalColors"` TemplateHeadings []TemplateHeading `json:"templateHeadings,omitempty"` Raw map[string]interface{} `json:"-"` } type Boolish bool func (b Boolish) Bool() bool { return bool(b) } func (b Boolish) MarshalJSON() ([]byte, error) { return json.Marshal(bool(b)) } func (b *Boolish) UnmarshalJSON(data []byte) error { trimmed := strings.TrimSpace(string(data)) if trimmed == "" || strings.EqualFold(trimmed, "null") { *b = false return nil } var boolVal bool if err := json.Unmarshal(data, &boolVal); err == nil { *b = Boolish(boolVal) return nil } var numVal float64 if err := json.Unmarshal(data, &numVal); err == nil { *b = Boolish(numVal != 0) return nil } var stringVal string if err := json.Unmarshal(data, &stringVal); err == nil { parsed, err := parseBoolishString(stringVal) if err != nil { return err } *b = Boolish(parsed) return nil } return fmt.Errorf("unsupported boolish value: %s", trimmed) } func parseBoolishString(v string) (bool, error) { normalized := strings.ToLower(strings.TrimSpace(v)) switch normalized { case "", "0", "false", "f", "no", "n", "off": return false, nil case "1", "true", "t", "yes", "y", "on": return true, nil } numeric, err := strconv.ParseFloat(normalized, 64) if err == nil { return numeric != 0, nil } return false, fmt.Errorf("unsupported boolish string value: %q", v) } type TemplateHeading struct { TranslationKey string `json:"translationKey"` } type GenerateContentRequest struct { TemplateID int64 `json:"templateId"` GlobalData map[string]any `json:"globalData"` Empty bool `json:"empty"` ToneOfVoice string `json:"toneOfVoice,omitempty"` TargetAudience string `json:"targetAudience,omitempty"` CustomTemplateData map[string]any `json:"customTemplateData,omitempty"` } type GenerateContentData map[string]map[string]any type CreateSiteRequest struct { TemplateID int64 `json:"templateId"` GlobalData map[string]any `json:"globalData"` Content CreateSiteContent `json:"content"` } type CreateSiteContent struct { AIData map[string]map[string]any `json:"aiData"` } type CreateSiteResponseData struct { Status string `json:"status"` JobID int64 `json:"jobId"` } type JobStatusResult struct { SiteID int64 `json:"siteId"` PreviewURL string `json:"previewUrl"` } type JobStatusData struct { JobID int64 `json:"jobId"` Status string `json:"status"` CreatedAt int64 `json:"createdAt"` Result JobStatusResult `json:"result"` } type SiteEditorLoginData struct { LoginURL string `json:"loginUrl"` }