159 lines
3.9 KiB
Python
159 lines
3.9 KiB
Python
"""
|
|
AI Provider 기본 클래스 정의
|
|
모든 AI 프로바이더는 이 기본 클래스를 상속받아 구현합니다.
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Optional, Dict, Any, List
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
|
|
|
|
class AIProviderType(Enum):
|
|
"""지원하는 AI 프로바이더 타입"""
|
|
OPENAI = "openai"
|
|
OPENROUTER = "openrouter"
|
|
GEMINI = "gemini"
|
|
XAI = "xai"
|
|
|
|
|
|
@dataclass
|
|
class AIMessage:
|
|
"""AI 메시지 데이터 클래스"""
|
|
role: str # 'system', 'user', 'assistant'
|
|
content: str
|
|
|
|
|
|
@dataclass
|
|
class AIResponse:
|
|
"""AI 응답 데이터 클래스"""
|
|
content: str
|
|
model: str
|
|
provider: str
|
|
usage: Optional[Dict[str, int]] = None
|
|
raw_response: Optional[Any] = None
|
|
|
|
|
|
class BaseAIProvider(ABC):
|
|
"""
|
|
AI Provider 추상 기본 클래스
|
|
모든 AI 프로바이더는 이 클래스를 상속받아 구현해야 합니다.
|
|
"""
|
|
|
|
def __init__(self, api_key: str, model: Optional[str] = None):
|
|
"""
|
|
Args:
|
|
api_key: API 키
|
|
model: 사용할 모델명 (None이면 기본 모델 사용)
|
|
"""
|
|
self._api_key = api_key
|
|
self._model = model or self.default_model
|
|
self._is_initialized = False
|
|
|
|
@property
|
|
@abstractmethod
|
|
def provider_type(self) -> AIProviderType:
|
|
"""프로바이더 타입 반환"""
|
|
pass
|
|
|
|
@property
|
|
@abstractmethod
|
|
def provider_name(self) -> str:
|
|
"""프로바이더 이름 반환"""
|
|
pass
|
|
|
|
@property
|
|
@abstractmethod
|
|
def default_model(self) -> str:
|
|
"""기본 모델명 반환"""
|
|
pass
|
|
|
|
@property
|
|
@abstractmethod
|
|
def available_models(self) -> List[str]:
|
|
"""사용 가능한 모델 목록 반환"""
|
|
pass
|
|
|
|
@property
|
|
def model(self) -> str:
|
|
"""현재 사용 중인 모델명"""
|
|
return self._model
|
|
|
|
@model.setter
|
|
def model(self, value: str):
|
|
"""모델 변경"""
|
|
self._model = value
|
|
|
|
@property
|
|
def api_key(self) -> str:
|
|
"""API 키 (마스킹된 값)"""
|
|
if self._api_key:
|
|
return self._api_key[:8] + "..." + self._api_key[-4:]
|
|
return ""
|
|
|
|
def update_api_key(self, api_key: str):
|
|
"""API 키 업데이트"""
|
|
self._api_key = api_key
|
|
self._is_initialized = False
|
|
|
|
@abstractmethod
|
|
def initialize(self) -> bool:
|
|
"""
|
|
프로바이더 초기화 (클라이언트 생성 등)
|
|
Returns:
|
|
초기화 성공 여부
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def chat(
|
|
self,
|
|
messages: List[AIMessage],
|
|
temperature: float = 0.7,
|
|
max_tokens: Optional[int] = None,
|
|
**kwargs
|
|
) -> AIResponse:
|
|
"""
|
|
채팅 요청 (비동기)
|
|
|
|
Args:
|
|
messages: 대화 메시지 리스트
|
|
temperature: 응답 다양성 (0.0 ~ 1.0)
|
|
max_tokens: 최대 토큰 수
|
|
**kwargs: 추가 파라미터
|
|
|
|
Returns:
|
|
AI 응답
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def chat_sync(
|
|
self,
|
|
messages: List[AIMessage],
|
|
temperature: float = 0.7,
|
|
max_tokens: Optional[int] = None,
|
|
**kwargs
|
|
) -> AIResponse:
|
|
"""
|
|
채팅 요청 (동기)
|
|
|
|
Args:
|
|
messages: 대화 메시지 리스트
|
|
temperature: 응답 다양성 (0.0 ~ 1.0)
|
|
max_tokens: 최대 토큰 수
|
|
**kwargs: 추가 파라미터
|
|
|
|
Returns:
|
|
AI 응답
|
|
"""
|
|
pass
|
|
|
|
def validate_api_key(self) -> bool:
|
|
"""API 키 유효성 검사 (간단한 형식 체크)"""
|
|
return bool(self._api_key and len(self._api_key) > 10)
|
|
|
|
def __repr__(self):
|
|
return f"{self.__class__.__name__}(model={self._model}, initialized={self._is_initialized})"
|
|
|