Files
vecna/pkg/embedclient/google.go
Hein 4009a54e39 feat: 🎉 Vectors na Vectors, the begining
Translate 1536 <-> 768 , 3072 <-> 2048
2026-04-11 18:05:05 +02:00

99 lines
2.4 KiB
Go

package embedclient
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
)
type googleClient struct {
baseURL string
apiKey string
model string
httpClient *http.Client
}
// NewGoogle returns a Client that speaks the Google Gemini batchEmbedContents API.
func NewGoogle(baseURL, apiKey, model string, httpClient *http.Client) Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &googleClient{baseURL: baseURL, apiKey: apiKey, model: model, httpClient: httpClient}
}
type googleBatchRequest struct {
Requests []googleEmbedRequest `json:"requests"`
}
type googleEmbedRequest struct {
Model string `json:"model"`
Content googleContent `json:"content"`
}
type googleContent struct {
Parts []googlePart `json:"parts"`
}
type googlePart struct {
Text string `json:"text"`
}
type googleBatchResponse struct {
Embeddings []struct {
Values []float32 `json:"values"`
} `json:"embeddings"`
}
func (c *googleClient) Embed(ctx context.Context, req Request) (Response, error) {
requests := make([]googleEmbedRequest, len(req.Texts))
for i, text := range req.Texts {
requests[i] = googleEmbedRequest{
Model: "models/" + c.model,
Content: googleContent{Parts: []googlePart{{Text: text}}},
}
}
body, err := json.Marshal(googleBatchRequest{Requests: requests})
if err != nil {
return Response{}, fmt.Errorf("google embed marshal: %w", err)
}
url := fmt.Sprintf("%s/v1/models/%s:batchEmbedContents", c.baseURL, c.model)
if c.apiKey != "" {
url += "?key=" + c.apiKey
}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
if err != nil {
return Response{}, fmt.Errorf("google embed request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(httpReq)
if err != nil {
return Response{}, fmt.Errorf("google embed do: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return Response{}, fmt.Errorf("google embed: unexpected status %d", resp.StatusCode)
}
var gResp googleBatchResponse
if err := json.NewDecoder(resp.Body).Decode(&gResp); err != nil {
return Response{}, fmt.Errorf("google embed decode: %w", err)
}
embeddings := make([][]float32, len(gResp.Embeddings))
for i, e := range gResp.Embeddings {
embeddings[i] = e.Values
}
return Response{
Embeddings: embeddings,
Model: c.model,
}, nil
}