# -*- coding: utf-8 -*-
# Copyright (c) 2025 Huawei Technologies Co., Ltd. All Rights Reserved.
from typing import Any, List, Optional, Tuple, Union
from openai import OpenAI
from pydantic import Field, PrivateAttr
from ._base import EmbedClientBase, RerankClientBase
[docs]
class OpenAIEmbedClient(EmbedClientBase):
"""OpenAI client based embedding client"""
base_url: Optional[str] = Field(default_factory=str, description="the request post url")
api_key: Optional[str] = Field(default_factory=str, description="the request api key")
model: str = Field(description="embedding model name")
dimensions: Optional[int] = Field(default=None, description="optional dimension reduction")
max_retries: Optional[int] = Field(default=2, description="post request service time")
request_timeout: Optional[Union[float, Tuple[float, float], Any]] = Field(
default=None,
description="post waiting time")
_client: Any = PrivateAttr(init=False)
[docs]
def model_post_init(self, context: Any, /) -> None:
"""Init OpenAI Client"""
self._client = OpenAI(
base_url=self.base_url or None,
api_key=self.api_key or "ollama",
max_retries=self.max_retries,
timeout=self.request_timeout,
)
[docs]
def embed_documents(self, texts: List[str], **kwargs) -> List[List[float]]:
"""batch embed texts, return matrix of embeddings"""
kwargs.setdefault("model", self.model)
if self.dimensions:
kwargs["dimensions"] = self.dimensions
resp = self._client.embeddings.create(input=texts, **kwargs)
return [d.embedding for d in resp.data]
[docs]
def embed_query(self, text: str, **kwargs) -> List[float]:
"""embed single texts"""
return self.embed_documents([text], **kwargs)[0]
[docs]
class FlagRerankModel(RerankClientBase):
"""FlagRerank based rerank model local implementation"""
model: str = Field(description="rerank model name")
top_n: int = Field(default=1, description="returned rerank num")
device: str = Field(default="cpu", description="rerank deployment device")
_rerank_model: Any = PrivateAttr(init=False)
[docs]
def model_post_init(self, context: Any, /) -> None:
"""create local rerank model"""
from FlagEmbedding import FlagReranker
self._rerank_model = FlagReranker(self.model,
top_n=self.top_n,
use_fp16=False,
devices=[self.device])
[docs]
async def rank(self, query: str, texts: List[str], **kwargs) -> List[int]:
"""FlagReranker rerank texts"""
pairs = [(query, text) for text in texts]
scores = self._rerank_model.compute_score(pairs)
indexed_scores = list(enumerate(scores))
indexed_scores.sort(key=lambda x: x[1], reverse=True)
indexes = [idx for idx, _ in indexed_scores]
return indexes[:self.top_n]