"""Provide service-layer logic for base client.""" from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import List, Dict, Optional, Any from enum import Enum # Keep provider-specific behavior explicit so debugging stays straightforward. class LLMProvider(Enum): """Define the L L M Provider enumeration.""" DEEPSEEK = "deepseek" QWEN = "qwen" QWEN_VL = "qwen_vl" @dataclass class LLMResponse: """Represent the L L M Response type.""" 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: """Return whether success for the L L M Response instance.""" return self.error is None @dataclass class LLMConfig: """Define configuration for l l m config.""" provider: LLMProvider model: str api_key: str base_url: str max_tokens: int = 4096 temperature: float = 0.7 top_p: float = 0.9 timeout: int = 300 # Keep provider-specific behavior explicit so debugging stays straightforward. class BaseLLMClient(ABC): """Represent the Base L L M Client type.""" def __init__(self, config: LLMConfig): """Initialize the Base L L M Client instance.""" self.config = config self._client = None @abstractmethod def _init_client(self): """Handle init client for this module for the Base L L M Client instance.""" pass @abstractmethod def chat( self, messages: List[Dict[str, str]], max_tokens: Optional[int] = None, temperature: Optional[float] = None, **kwargs ) -> LLMResponse: """Handle chat for the Base L L M Client instance.""" pass def complete( self, prompt: str, system_prompt: Optional[str] = None, max_tokens: Optional[int] = None, temperature: Optional[float] = None, **kwargs ) -> LLMResponse: """Handle complete for the Base L L M Client instance.""" 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]: """Return available models for the Base L L M Client instance.""" pass def estimate_tokens(self, text: str) -> int: """Handle estimate tokens for the Base L L M Client instance.""" # Keep provider-specific behavior explicit so debugging stays straightforward. chinese_chars = sum(1 for c in text if '一' <= c <= '鿿') other_chars = len(text) - chinese_chars return int(chinese_chars * 1.5 + other_chars * 0.25)