2026-05-18 16:32:42 +08:00
|
|
|
"""Provide service-layer logic for base client."""
|
2026-05-14 15:07:34 +08:00
|
|
|
|
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
from typing import List, Dict, Optional, Any
|
|
|
|
|
from enum import Enum
|
2026-05-18 16:32:42 +08:00
|
|
|
# Keep provider-specific behavior explicit so debugging stays straightforward.
|
|
|
|
|
|
2026-05-14 15:07:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class LLMProvider(Enum):
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Define the L L M Provider enumeration."""
|
2026-05-14 15:07:34 +08:00
|
|
|
DEEPSEEK = "deepseek"
|
|
|
|
|
QWEN = "qwen"
|
|
|
|
|
QWEN_VL = "qwen_vl"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class LLMResponse:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Represent the L L M Response type."""
|
2026-05-14 15:07:34 +08:00
|
|
|
content: str
|
|
|
|
|
model: str
|
|
|
|
|
usage: Dict[str, int] = field(default_factory=dict)
|
|
|
|
|
finish_reason: str = "stop"
|
|
|
|
|
latency_ms: int = 0
|
|
|
|
|
error: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def is_success(self) -> bool:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Return whether success for the L L M Response instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
return self.error is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class LLMConfig:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Define configuration for l l m config."""
|
2026-05-14 15:07:34 +08:00
|
|
|
provider: LLMProvider
|
|
|
|
|
model: str
|
|
|
|
|
api_key: str
|
|
|
|
|
base_url: str
|
|
|
|
|
max_tokens: int = 4096
|
|
|
|
|
temperature: float = 0.7
|
|
|
|
|
top_p: float = 0.9
|
2026-05-18 16:32:42 +08:00
|
|
|
timeout: int = 300 # Keep provider-specific behavior explicit so debugging stays straightforward.
|
2026-05-14 15:07:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class BaseLLMClient(ABC):
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Represent the Base L L M Client type."""
|
2026-05-14 15:07:34 +08:00
|
|
|
|
|
|
|
|
def __init__(self, config: LLMConfig):
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Initialize the Base L L M Client instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
self.config = config
|
|
|
|
|
self._client = None
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def _init_client(self):
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Handle init client for this module for the Base L L M Client instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def chat(
|
|
|
|
|
self,
|
|
|
|
|
messages: List[Dict[str, str]],
|
|
|
|
|
max_tokens: Optional[int] = None,
|
|
|
|
|
temperature: Optional[float] = None,
|
|
|
|
|
**kwargs
|
|
|
|
|
) -> LLMResponse:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Handle chat for the Base L L M Client instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def complete(
|
|
|
|
|
self,
|
|
|
|
|
prompt: str,
|
|
|
|
|
system_prompt: Optional[str] = None,
|
|
|
|
|
max_tokens: Optional[int] = None,
|
|
|
|
|
temperature: Optional[float] = None,
|
|
|
|
|
**kwargs
|
|
|
|
|
) -> LLMResponse:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Handle complete for the Base L L M Client instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
messages = []
|
|
|
|
|
if system_prompt:
|
|
|
|
|
messages.append({"role": "system", "content": system_prompt})
|
|
|
|
|
messages.append({"role": "user", "content": prompt})
|
|
|
|
|
|
|
|
|
|
return self.chat(messages, max_tokens, temperature, **kwargs)
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def get_available_models(self) -> List[str]:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Return available models for the Base L L M Client instance."""
|
2026-05-14 15:07:34 +08:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def estimate_tokens(self, text: str) -> int:
|
2026-05-18 16:32:42 +08:00
|
|
|
"""Handle estimate tokens for the Base L L M Client instance."""
|
|
|
|
|
# Keep provider-specific behavior explicit so debugging stays straightforward.
|
2026-05-14 15:07:34 +08:00
|
|
|
chinese_chars = sum(1 for c in text if '一' <= c <= '鿿')
|
|
|
|
|
other_chars = len(text) - chinese_chars
|
2026-05-14 18:09:15 +08:00
|
|
|
return int(chinese_chars * 1.5 + other_chars * 0.25)
|