FGAO-API / src /fgao /integrations /providers.py
Angshul's picture
Upload 27 files
0703e2b verified
Raw History Blame Contribute Delete
4.12 kB
"""OpenAI-compatible and Anthropic chat models as FGAO LLMs (sync and native async).
``OpenAILLM`` also serves any OpenAI-compatible endpoint (vLLM, TGI, Ollama,
LM Studio, ...) through ``base_url``. Clients are created lazily, so a process
that only uses the async API never opens a sync client and vice versa.
"""
from __future__ import annotations
from typing import Any, Dict, List, Optional
from ..rag.prompts import SYSTEM_PROMPT
def _messages(system: Optional[str], prompt: str) -> List[Dict[str, str]]:
return ([{"role": "system", "content": system}] if system else []) + [{"role": "user", "content": prompt}]
class OpenAILLM:
def __init__(self, model: str, *, client: Any = None, aclient: Any = None, base_url: Optional[str] = None,
api_key: Optional[str] = None, max_tokens: int = 128, temperature: float = 0.0,
system: Optional[str] = SYSTEM_PROMPT, timeout: Optional[float] = None,
max_retries: Optional[int] = None) -> None:
self.model, self.max_tokens, self.temperature, self.system = model, max_tokens, temperature, system
self._kw = {k: v for k, v in (("base_url", base_url), ("api_key", api_key), ("timeout", timeout),
("max_retries", max_retries)) if v is not None}
self._client, self._aclient = client, aclient
@property
def client(self):
if self._client is None:
from openai import OpenAI
self._client = OpenAI(**self._kw)
return self._client
@property
def aclient(self):
if self._aclient is None:
from openai import AsyncOpenAI
self._aclient = AsyncOpenAI(**self._kw)
return self._aclient
def _args(self, prompt: str) -> Dict[str, Any]:
return {"model": self.model, "messages": _messages(self.system, prompt), "max_tokens": self.max_tokens,
"temperature": self.temperature}
def complete(self, prompt: str) -> str:
out = self.client.chat.completions.create(**self._args(prompt))
return (out.choices[0].message.content or "").strip()
async def acomplete(self, prompt: str) -> str:
out = await self.aclient.chat.completions.create(**self._args(prompt))
return (out.choices[0].message.content or "").strip()
class AnthropicLLM:
def __init__(self, model: str, *, client: Any = None, aclient: Any = None, api_key: Optional[str] = None,
max_tokens: int = 128, temperature: float = 0.0, system: Optional[str] = SYSTEM_PROMPT,
timeout: Optional[float] = None, max_retries: Optional[int] = None) -> None:
self.model, self.max_tokens, self.temperature, self.system = model, max_tokens, temperature, system
self._kw = {k: v for k, v in (("api_key", api_key), ("timeout", timeout), ("max_retries", max_retries))
if v is not None}
self._client, self._aclient = client, aclient
@property
def client(self):
if self._client is None:
from anthropic import Anthropic
self._client = Anthropic(**self._kw)
return self._client
@property
def aclient(self):
if self._aclient is None:
from anthropic import AsyncAnthropic
self._aclient = AsyncAnthropic(**self._kw)
return self._aclient
def _args(self, prompt: str) -> Dict[str, Any]:
kw: Dict[str, Any] = {"model": self.model, "max_tokens": self.max_tokens, "temperature": self.temperature,
"messages": [{"role": "user", "content": prompt}]}
if self.system:
kw["system"] = self.system
return kw
def complete(self, prompt: str) -> str:
out = self.client.messages.create(**self._args(prompt))
return "".join(getattr(b, "text", "") for b in out.content).strip()
async def acomplete(self, prompt: str) -> str:
out = await self.aclient.messages.create(**self._args(prompt))
return "".join(getattr(b, "text", "") for b in out.content).strip()
__all__ = ["OpenAILLM", "AnthropicLLM"]