github.com/weaviate/weaviate@v1.24.6/modules/multi2vec-bind/clients/vectorizer.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package clients 13 14 import ( 15 "bytes" 16 "context" 17 "encoding/json" 18 "fmt" 19 "io" 20 "net/http" 21 "time" 22 23 "github.com/pkg/errors" 24 "github.com/sirupsen/logrus" 25 "github.com/weaviate/weaviate/modules/multi2vec-bind/ent" 26 ) 27 28 type vectorizer struct { 29 origin string 30 httpClient *http.Client 31 logger logrus.FieldLogger 32 } 33 34 func New(origin string, timeout time.Duration, logger logrus.FieldLogger) *vectorizer { 35 return &vectorizer{ 36 origin: origin, 37 httpClient: &http.Client{ 38 Timeout: timeout, 39 }, 40 logger: logger, 41 } 42 } 43 44 func (v *vectorizer) Vectorize(ctx context.Context, 45 texts, images, audio, video, imu, thermal, depth []string, 46 ) (*ent.VectorizationResult, error) { 47 body, err := json.Marshal(vecRequest{ 48 Texts: texts, 49 Images: images, 50 Audio: audio, 51 Video: video, 52 IMU: imu, 53 Thermal: thermal, 54 Depth: depth, 55 }) 56 if err != nil { 57 return nil, errors.Wrapf(err, "marshal body") 58 } 59 60 req, err := http.NewRequestWithContext(ctx, "POST", v.url("/vectorize"), 61 bytes.NewReader(body)) 62 if err != nil { 63 return nil, errors.Wrap(err, "create POST request") 64 } 65 66 res, err := v.httpClient.Do(req) 67 if err != nil { 68 return nil, errors.Wrap(err, "send POST request") 69 } 70 defer res.Body.Close() 71 72 bodyBytes, err := io.ReadAll(res.Body) 73 if err != nil { 74 return nil, errors.Wrap(err, "read response body") 75 } 76 77 var resBody vecResponse 78 if err := json.Unmarshal(bodyBytes, &resBody); err != nil { 79 return nil, errors.Wrap(err, "unmarshal response body") 80 } 81 82 if res.StatusCode != 200 { 83 if resBody.Error != "" { 84 return nil, errors.Errorf("fail with status %d: %s", res.StatusCode, 85 resBody.Error) 86 } 87 return nil, errors.Errorf("fail with status %d", res.StatusCode) 88 } 89 90 return &ent.VectorizationResult{ 91 TextVectors: resBody.TextVectors, 92 ImageVectors: resBody.ImageVectors, 93 AudioVectors: resBody.AudioVectors, 94 VideoVectors: resBody.VideoVectors, 95 IMUVectors: resBody.IMUVectors, 96 ThermalVectors: resBody.ThermalVectors, 97 DepthVectors: resBody.DepthVectors, 98 }, nil 99 } 100 101 func (v *vectorizer) url(path string) string { 102 return fmt.Sprintf("%s%s", v.origin, path) 103 } 104 105 type vecRequest struct { 106 Texts []string `json:"texts,omitempty"` 107 Images []string `json:"images,omitempty"` 108 Audio []string `json:"audio,omitempty"` 109 Video []string `json:"video,omitempty"` 110 IMU []string `json:"imu,omitempty"` 111 Thermal []string `json:"thermal,omitempty"` 112 Depth []string `json:"depth,omitempty"` 113 } 114 115 type vecResponse struct { 116 TextVectors [][]float32 `json:"textVectors,omitempty"` 117 ImageVectors [][]float32 `json:"imageVectors,omitempty"` 118 AudioVectors [][]float32 `json:"audioVectors,omitempty"` 119 VideoVectors [][]float32 `json:"videoVectors,omitempty"` 120 IMUVectors [][]float32 `json:"imuVectors,omitempty"` 121 ThermalVectors [][]float32 `json:"thermalVectors,omitempty"` 122 DepthVectors [][]float32 `json:"depthVectors,omitempty"` 123 Error string `json:"error,omitempty"` 124 }