2026-04-09 10:01:23 +08:00
|
|
|
package ai
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
openai "github.com/openai/openai-go/v3"
|
|
|
|
|
|
2026-08-21 00:41:07 +08:00
|
|
|
"code.tczkiot.com/wlw/ai-agent/internal/models"
|
|
|
|
|
"code.tczkiot.com/wlw/ai-agent/internal/pkg/enums"
|
|
|
|
|
"code.tczkiot.com/wlw/ai-agent/internal/pkg/errorsx"
|
2026-04-09 10:01:23 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type EmbeddingResult struct {
|
|
|
|
|
Vector []float32
|
|
|
|
|
TokensUsed int
|
|
|
|
|
ModelName string
|
|
|
|
|
Dimension int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type embedding struct{}
|
|
|
|
|
|
|
|
|
|
var Embedding = &embedding{}
|
|
|
|
|
|
|
|
|
|
func (s *embedding) GetModel(ctx context.Context) (*models.AIConfig, error) {
|
2026-08-28 22:23:13 +08:00
|
|
|
return resolveDefaultAIConfig(ctx, enums.AIModelTypeEmbedding)
|
2026-04-09 10:01:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *embedding) GenerateEmbedding(ctx context.Context, text string) (*EmbeddingResult, error) {
|
|
|
|
|
if text == "" {
|
2026-06-02 20:51:13 +08:00
|
|
|
return nil, errorsx.InvalidParamI18n("error.e0215")
|
2026-04-09 10:01:23 +08:00
|
|
|
}
|
2026-08-28 22:23:13 +08:00
|
|
|
ctx = ensurePlatformAIRequestScope(ctx)
|
2026-04-09 10:01:23 +08:00
|
|
|
|
|
|
|
|
result, err := s.callEmbeddingAPI(ctx, text)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *embedding) GenerateBatchEmbeddings(ctx context.Context, texts []string) ([]EmbeddingResult, error) {
|
|
|
|
|
if len(texts) == 0 {
|
2026-06-02 20:51:13 +08:00
|
|
|
return nil, errorsx.InvalidParamI18n("error.e0216")
|
2026-04-09 10:01:23 +08:00
|
|
|
}
|
2026-08-28 22:23:13 +08:00
|
|
|
ctx = ensurePlatformAIRequestScope(ctx)
|
2026-04-09 10:01:23 +08:00
|
|
|
|
|
|
|
|
results := make([]EmbeddingResult, 0, len(texts))
|
|
|
|
|
for _, text := range texts {
|
|
|
|
|
result, err := s.callEmbeddingAPI(ctx, text)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to generate embedding for text: %w", err)
|
|
|
|
|
}
|
|
|
|
|
results = append(results, *result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *embedding) callEmbeddingAPI(ctx context.Context, text string) (*EmbeddingResult, error) {
|
2026-08-28 22:23:13 +08:00
|
|
|
config, err := s.GetModel(ctx)
|
2026-04-09 10:01:23 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-04-17 17:57:01 +08:00
|
|
|
client := newOpenAIClient(*config)
|
2026-04-09 10:01:23 +08:00
|
|
|
embeddingResp, err := client.Embeddings.New(ctx, openai.EmbeddingNewParams{
|
|
|
|
|
Input: openai.EmbeddingNewParamsInputUnion{
|
|
|
|
|
OfString: openai.String(text),
|
|
|
|
|
},
|
|
|
|
|
Model: openai.EmbeddingModel(config.ModelName),
|
2026-08-28 22:23:13 +08:00
|
|
|
}, platformRequestOptions(ctx, *config, "embedding")...)
|
2026-04-09 10:01:23 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to call embedding api: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(embeddingResp.Data) == 0 {
|
|
|
|
|
return nil, fmt.Errorf("no embedding data in response")
|
|
|
|
|
}
|
|
|
|
|
vector := make([]float32, 0, len(embeddingResp.Data[0].Embedding))
|
|
|
|
|
for _, item := range embeddingResp.Data[0].Embedding {
|
|
|
|
|
vector = append(vector, float32(item))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &EmbeddingResult{
|
|
|
|
|
Vector: vector,
|
|
|
|
|
TokensUsed: int(embeddingResp.Usage.TotalTokens),
|
|
|
|
|
ModelName: embeddingResp.Model,
|
|
|
|
|
Dimension: len(vector),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *embedding) GetDimension(ctx context.Context) (int, error) {
|
|
|
|
|
model, err := s.GetModel(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
return model.Dimension, nil
|
|
|
|
|
}
|