OpenAIEmbedder
On this page
embeddings.openai_embedder.OpenAIEmbedder(BaseEmbedder) — OpenAI Embeddings API client.
Purpose
Wraps the openai Python SDK's client.embeddings.create() with request-level rate limiting, tiktoken-based token counting, cost tracking, retry-with-backoff, response-level caching, and optional embedding-dimension reduction (for text-embedding-3-* models).
Constructor
OpenAIEmbedder(
model_name: str = "text-embedding-3-small",
api_key: Optional[str] = None,
dimensions: Optional[int] = None,
device: Optional[str] = None,
normalize_embeddings: bool = True,
batch_size: int = 100,
max_length: Optional[int] = None,
cache_embeddings: bool = True,
show_progress: bool = False,
timeout: int = 60,
max_retries: int = 3,
retry_delay: float = 1.0,
enable_rate_limiting: bool = True,
max_requests_per_minute: int = 3000,
max_tokens_per_minute: int = 1_000_000,
track_costs: bool = True,
**kwargs,
)
Parameters
MODEL_SPECS (class attribute)
Raises
ValueErrorif no API key is resolvable.ValueErrorifdimensions < 1.ImportErrorif theopenaipackage isn't installed.ValueErrorfrom_validate_api_key()if the test request raises the SDK'sAPIError.
encode()
encode(
texts: Union[str, List[str]],
show_progress_bar: bool = False,
convert_to_numpy: bool = True,
batch_size: Optional[int] = None,
**kwargs,
) -> np.ndarray
Behavior
- Wraps a single string in a list; raises
ValueErrorif the (post-filter) list is empty. - Filters out empty/whitespace-only entries, logging a warning about how many were dropped.
- Splits each batch into cache hits and misses; only misses are sent to
_process_batch(). _process_batch()counts tokens viatiktoken(falls back tolen(text)//4if the tokenizer failed to load), applies rate limiting, and callsclient.embeddings.create()withdimensions=self.dimensionsfortext-embedding-3-*models. Retries onRateLimitError/APIConnectionErrorwith exponential backoff; does not retry on genericAPIError(re-raises immediately).- Merges cached and freshly-fetched embeddings back into original batch order.
- Stacks all batches, then L2-normalizes if
normalize_embeddings=True(guarding against division by zero). - Updates
self._statsand logs a summary including cache hit rate, tokens used, and cost.
Returns
np.ndarray of shape (n, dimensions) — always 2D, even for single-string input (no unwrap step exists in this class, unlike ArabicEmbedder).
Raises
ValueErrorif all input texts are empty.- Propagates
RuntimeErrorif all retries in_process_batchare exhausted, or re-raises the original SDK exception for non-retryable API errors.
Cost and usage tracking
estimate_cost(texts) -> Dict[str, Any]
Counts tokens via _count_tokens() (accurate tiktoken count, or len(text)//4 fallback) and multiplies by MODEL_SPECS[model]['cost_per_1m_tokens']. Does not call the API — purely a local estimate.
get_usage_stats() -> Dict[str, Any]
Merges self._stats with cache_hit_rate and (if track_costs) self.usage_stats.get_summary() (UsageStats: total tokens, requests, cost, elapsed time, requests-per-minute bucket count).
clear_cache(), get_model_info()
Standard cache-clear and model-info introspection; get_model_info() includes the full model_spec dict plus configured dimensions and tracking flags.
RateLimiter (module-level class)
Sliding-window limiter tracking request timestamps and per-token timestamps over the last 60 seconds, protected by a threading.RLock. wait_if_needed(estimated_tokens) sleeps as needed before allowing a new request through. Note: it appends one timestamp per estimated token to self.tokens, which is a memory/CPU cost proportional to token volume for high-throughput use.
UsageStats (dataclass)
Fields: total_tokens, total_requests, total_cost, start_time, requests_by_minute (a dict keyed by "YYYY-MM-DD HH:MM"). .get_summary() returns aggregated totals plus requests_per_minute (actually the count of distinct minute buckets seen, not a live rate).
Context manager
__enter__ returns self; __exit__ logs a session summary of tokens/requests/cost/elapsed time if track_costs=True.
Examples
import os
from zerda.embeddings import OpenAIEmbedder
os.environ["OPENAI_API_KEY"] = "sk-..."
embedder = OpenAIEmbedder(model_name="text-embedding-3-large", dimensions=1024)
vectors = embedder.encode(["first document", "second document"])
cost_estimate = embedder.estimate_cost(["a fairly long piece of text to embed"])
with OpenAIEmbedder() as e:
v = e.encode("hello")
# session summary logged on exit
Related APIs
- BaseEmbedder — parent class
- GeminiEmbedder, MistralEmbedder — sibling hosted-API embedders with a similar rate-limit/retry/cost-tracking shape