package mrktplaats import ( "bytes" "context" "fmt" "io" "mime/multipart" ) // SaleabilityService handles image recognition for listings. type SaleabilityService struct { t *transport } // Prediction is an image recognition result. type Prediction struct { CategoryID int `json:"categoryId"` CategoryName string `json:"categoryName"` Confidence float64 `json:"confidence"` Attributes []any `json:"attributes"` } // RecognizeResponse contains image recognition predictions. type RecognizeResponse struct { Predictions []Prediction `json:"predictions"` } // Recognize uploads an image and returns category/attribute predictions. // Large images are automatically compressed to stay within the API size limit. func (s *SaleabilityService) Recognize(ctx context.Context, img io.Reader, filename string) (*RecognizeResponse, error) { data, err := autoCompressImage(img) if err != nil { return nil, fmt.Errorf("mrktplaats: reading image: %w", err) } var buf bytes.Buffer w := multipart.NewWriter(&buf) part, err := w.CreateFormFile("picture", filename) if err != nil { return nil, fmt.Errorf("mrktplaats: creating form file: %w", err) } if _, err := io.Copy(part, bytes.NewReader(data)); err != nil { return nil, fmt.Errorf("mrktplaats: copying image: %w", err) } w.Close() var resp RecognizeResponse if err := s.t.postMultipart(ctx, "/app/saleability/v4/recognize", nil, nil, w.FormDataContentType(), &buf, &resp); err != nil { return nil, err } return &resp, nil }