Create Relay Bot MVP
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
|
||||
from openai import APIConnectionError, APIStatusError, AsyncOpenAI, RateLimitError
|
||||
|
||||
from app.llm.prompts import SYSTEM_PROMPT
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LLMUnavailable(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class DeepSeekClient:
|
||||
def __init__(
|
||||
self, api_key: str, base_url: str, model: str, timeout: float = 45, retries: int = 3
|
||||
):
|
||||
self.client = AsyncOpenAI(
|
||||
api_key=api_key, base_url=base_url, timeout=timeout, max_retries=0
|
||||
)
|
||||
self.model, self.retries = model, retries
|
||||
|
||||
async def complete(
|
||||
self, messages: Sequence[dict[str, str]], *, temperature: float = 0.1
|
||||
) -> str:
|
||||
started = time.monotonic()
|
||||
payload = [{"role": "system", "content": SYSTEM_PROMPT}, *messages]
|
||||
for attempt in range(self.retries):
|
||||
try:
|
||||
response = await self.client.chat.completions.create(
|
||||
model=self.model, messages=list(payload), temperature=temperature
|
||||
)
|
||||
content = response.choices[0].message.content or ""
|
||||
logger.info(
|
||||
"llm_complete duration_ms=%d tokens=%s",
|
||||
int((time.monotonic() - started) * 1000),
|
||||
getattr(response.usage, "total_tokens", "unknown"),
|
||||
)
|
||||
return content
|
||||
except (RateLimitError, APIConnectionError, APIStatusError) as error:
|
||||
if (
|
||||
isinstance(error, APIStatusError)
|
||||
and error.status_code < 500
|
||||
and error.status_code != 429
|
||||
):
|
||||
break
|
||||
if attempt + 1 < self.retries:
|
||||
await asyncio.sleep(2**attempt)
|
||||
logger.warning("llm_unavailable duration_ms=%d", int((time.monotonic() - started) * 1000))
|
||||
raise LLMUnavailable("Модель временно недоступна. Попробуйте ещё раз позже.")
|
||||
|
||||
async def json(self, messages: Sequence[dict[str, str]]) -> dict[str, object]:
|
||||
content = await self.complete(messages, temperature=0)
|
||||
try:
|
||||
return json.loads(content.removeprefix("```json").removesuffix("```").strip())
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
Reference in New Issue
Block a user