smart-chatbot-api / app /services /embedding_service.py
GitHub Actions
Deploy from GitHub Actions (2026-05-31 09:04 UTC)
55c0d78
Raw
History Blame Contribute Delete
2.79 kB
from dataclasses import dataclass
import google.genai as genai
import google.genai.local_tokenizer as local_tokenizer
GEMINI_EMBEDDING_MAX_TOKENS = 8192
# The SDK does not currently expose LocalTokenizer support for `gemini-embedding-2`,
# so keep chunk sizing on a supported Gemini-family tokenizer until Google ships one.
GEMINI_LOCAL_TOKENIZER_MODEL = "gemini-2.0-flash"
class GeminiTokenizerAdapter:
model_max_length = GEMINI_EMBEDDING_MAX_TOKENS
def __init__(self, model_name: str = GEMINI_LOCAL_TOKENIZER_MODEL):
self._local_tokenizer = local_tokenizer.LocalTokenizer(model_name=model_name)
self._tokenizer = self._local_tokenizer._tokenizer
def __call__(
self,
text: str,
*,
add_special_tokens: bool = True,
truncation: bool = False,
) -> dict[str, list[int]]:
token_ids = list(self._tokenizer.encode(text or "", out_type=int))
if truncation:
token_ids = token_ids[: self.model_max_length]
return {"input_ids": token_ids}
def decode(
self,
token_ids: list[int],
*,
skip_special_tokens: bool = True,
) -> str:
del skip_special_tokens
return self._tokenizer.decode(token_ids)
@dataclass
class GeminiEmbeddingModel:
tokenizer: GeminiTokenizerAdapter
max_seq_length: int = GEMINI_EMBEDDING_MAX_TOKENS
class EmbeddingService:
def __init__(
self,
model_name: str,
api_key: str,
*,
client: genai.Client | None = None,
tokenizer_model_name: str = GEMINI_LOCAL_TOKENIZER_MODEL,
):
if not api_key:
raise ValueError("GEMINI_EMBEDDING_API_KEY (or GEMINI_API_KEY) is required")
self.api_key = api_key
self.model_name = model_name
self.client = client or genai.Client(api_key=api_key)
self.model = GeminiEmbeddingModel(
tokenizer=GeminiTokenizerAdapter(model_name=tokenizer_model_name)
)
def embed(self, text: str) -> list[float]:
try:
response = self.client.models.embed_content(
model=self.model_name,
contents=text,
)
except Exception as exc:
raise RuntimeError(
f"Gemini embedding request failed for model {self.model_name}"
) from exc
embeddings = getattr(response, "embeddings", None) or []
if len(embeddings) != 1:
raise RuntimeError(
f"Gemini embedding response returned {len(embeddings)} embeddings"
)
values = getattr(embeddings[0], "values", None)
if values is None:
raise RuntimeError("Gemini embedding response did not include values")
return list(values)