nvikou's picture
Deploy TechDocs GraphRAG
da21448 verified
Raw History Blame Contribute Delete
2.3 kB
from collections.abc import Sequence
from itertools import batched
from typing import Any
from openai import APIConnectionError, APITimeoutError, InternalServerError, OpenAI, RateLimitError
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_random_exponential
from techdocs_graphrag.config import Settings
EMBEDDING_BATCH_SIZE = 96
TRANSIENT_ERRORS = (APIConnectionError, APITimeoutError, InternalServerError, RateLimitError)
with_retry = retry(
retry=retry_if_exception_type(TRANSIENT_ERRORS),
wait=wait_random_exponential(min=1, max=30),
stop=stop_after_attempt(5),
reraise=True,
)
class OpenAIGateway:
def __init__(self, settings: Settings) -> None:
self._client = OpenAI(api_key=settings.openai_api_key.get_secret_value())
self._chat_model = settings.chat_model
self._chat_temperature = settings.chat_temperature
self._embedding_model = settings.embedding_model
self._embedding_dimensions = settings.embedding_dimensions
@with_retry
def complete(self, system_prompt: str, user_prompt: str, *, json_mode: bool = False) -> str:
options: dict[str, Any] = {}
if json_mode:
options["response_format"] = {"type": "json_object"}
if self._chat_temperature is not None:
options["temperature"] = self._chat_temperature
response = self._client.chat.completions.create(
model=self._chat_model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
**options,
)
return response.choices[0].message.content or ""
def embed(self, texts: Sequence[str]) -> list[list[float]]:
return [
vector
for batch in batched(texts, EMBEDDING_BATCH_SIZE)
for vector in self._embed_batch(batch)
]
@with_retry
def _embed_batch(self, texts: Sequence[str]) -> list[list[float]]:
response = self._client.embeddings.create(
model=self._embedding_model,
input=list(texts),
dimensions=self._embedding_dimensions,
)
return [item.embedding for item in sorted(response.data, key=lambda item: item.index)]