Files
xinmi/internal/models/embedding/ollama.go
T
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

140 lines
3.7 KiB
Go

package embedding
import (
"context"
"fmt"
"time"
"github.com/Tencent/WeKnora/internal/logger"
"github.com/Tencent/WeKnora/internal/models/requestbudget"
"github.com/Tencent/WeKnora/internal/models/utils/ollama"
ollamaapi "github.com/ollama/ollama/api"
)
// OllamaEmbedder implements text vectorization functionality using Ollama
type OllamaEmbedder struct {
modelName string
truncatePromptTokens int
ollamaService *ollama.OllamaService
dimensions int
modelID string
supportsDimensionOverride bool
EmbedderPooler
}
// OllamaEmbedRequest represents an Ollama embedding request
type OllamaEmbedRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
TruncatePromptTokens int `json:"truncate_prompt_tokens"`
}
// OllamaEmbedResponse represents an Ollama embedding response
type OllamaEmbedResponse struct {
Embedding []float32 `json:"embedding"`
}
// NewOllamaEmbedder creates a new Ollama embedder
func NewOllamaEmbedder(baseURL,
modelName string,
truncatePromptTokens int,
dimensions int,
modelID string,
pooler EmbedderPooler,
ollamaService *ollama.OllamaService,
) (*OllamaEmbedder, error) {
if modelName == "" {
modelName = "nomic-embed-text"
}
if truncatePromptTokens == 0 {
truncatePromptTokens = 511
}
return &OllamaEmbedder{
modelName: modelName,
truncatePromptTokens: truncatePromptTokens,
ollamaService: ollamaService,
EmbedderPooler: pooler,
dimensions: dimensions,
modelID: modelID,
}, nil
}
// ensureModelAvailable ensures that the model is available
func (e *OllamaEmbedder) ensureModelAvailable(ctx context.Context) error {
logger.GetLogger(ctx).Infof("Ensuring model %s is available", e.modelName)
return e.ollamaService.EnsureModelAvailable(ctx, e.modelName)
}
func (e *OllamaEmbedder) SetSupportsDimensionOverride(supported bool) {
e.supportsDimensionOverride = supported
}
// Embed converts text to vector
func (e *OllamaEmbedder) Embed(ctx context.Context, text string) ([]float32, error) {
embedding, err := e.BatchEmbed(ctx, []string{text})
if err != nil {
return nil, fmt.Errorf("failed to embed text: %w", err)
}
if len(embedding) == 0 {
return nil, fmt.Errorf("failed to embed text: %w", err)
}
return embedding[0], nil
}
// BatchEmbed converts multiple texts to vectors in batch
func (e *OllamaEmbedder) BatchEmbed(ctx context.Context, texts []string) ([][]float32, error) {
if err := requestbudget.RequireSupported(ctx, false); err != nil {
return nil, err
}
// Ensure model is available
if err := e.ensureModelAvailable(ctx); err != nil {
return nil, err
}
// Create request
req := &ollamaapi.EmbedRequest{
Model: e.modelName,
Input: texts,
Options: make(map[string]interface{}),
}
if e.supportsDimensionOverride && e.dimensions > 0 {
req.Dimensions = e.dimensions
}
// Set truncation parameters
if e.truncatePromptTokens > 0 {
req.Options["num_ctx"] = e.truncatePromptTokens
truncate := true
req.Truncate = &truncate
}
// Send request
startTime := time.Now()
resp, err := e.ollamaService.Embeddings(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to get embedding vectors: %w", err)
}
logger.GetLogger(ctx).Debugf("Embedding vector retrieval took: %v", time.Since(startTime))
return resp.Embeddings, nil
}
// GetModelName returns the model name
func (e *OllamaEmbedder) GetModelName() string {
return e.modelName
}
// GetDimensions returns the vector dimensions
func (e *OllamaEmbedder) GetDimensions() int {
return e.dimensions
}
// GetModelID returns the model ID
func (e *OllamaEmbedder) GetModelID() string {
return e.modelID
}