system-prompts-and-models-o.../dealix/core/llm/base.py
2026-05-01 14:03:52 +03:00

88 lines
2.2 KiB
Python

"""
Base LLM abstraction — unified interface across all providers.
واجهة موحدة لجميع مزودي النماذج اللغوية.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any, Literal
Role = Literal["system", "user", "assistant"]
@dataclass
class Message:
"""A conversation message | رسالة محادثة."""
role: Role
content: str
def to_dict(self) -> dict[str, str]:
return {"role": self.role, "content": self.content}
@dataclass
class LLMResponse:
"""Standardized LLM response | رد موحد من النموذج."""
content: str
provider: str
model: str
input_tokens: int = 0
output_tokens: int = 0
cached_tokens: int = 0
finish_reason: str | None = None
raw: dict[str, Any] = field(default_factory=dict)
@property
def total_tokens(self) -> int:
return self.input_tokens + self.output_tokens
class LLMClient(ABC):
"""Abstract LLM client | عميل نموذج لغوي مجرد."""
provider_name: str = "base"
def __init__(
self,
api_key: str,
model: str,
base_url: str | None = None,
timeout: int = 60,
) -> None:
self.api_key = api_key
self.model = model
self.base_url = base_url
self.timeout = timeout
@abstractmethod
async def chat(
self,
messages: list[Message],
*,
max_tokens: int = 4096,
temperature: float = 0.7,
system: str | None = None,
**kwargs: Any,
) -> LLMResponse:
"""Send a chat completion request | أرسل طلب محادثة."""
...
async def complete(
self,
prompt: str,
*,
system: str | None = None,
max_tokens: int = 4096,
temperature: float = 0.7,
) -> str:
"""Convenience wrapper — returns just the string content."""
messages = [Message(role="user", content=prompt)]
response = await self.chat(
messages, max_tokens=max_tokens, temperature=temperature, system=system
)
return response.content