# Plan refaktoryzacji integracji OpenRouter ## Cel Refaktoryzacja kodu w `resume_analysis.py` w celu eliminacji wszystkich zależności od OpenAI API i wykorzystania wyłącznie OpenRouter API, z poprawą obecnej implementacji połączenia z OpenRouter. ## Diagram przepływu zmian ```mermaid graph TD A[Obecna implementacja] --> B[Faza 1: Usunięcie zależności OpenAI] B --> C[Faza 2: Refaktoryzacja klienta OpenRouter] C --> D[Faza 3: Optymalizacja obsługi odpowiedzi] D --> E[Faza 4: Testy i walidacja] subgraph "Faza 1: Usunięcie zależności OpenAI" B1[Usuń importy OpenAI] B2[Usuń zmienne konfiguracyjne OpenAI] B3[Usuń logikę wyboru klienta] end subgraph "Faza 2: Refaktoryzacja klienta OpenRouter" C1[Stwórz dedykowaną klasę OpenRouterClient] C2[Implementuj prawidłową konfigurację nagłówków] C3[Dodaj obsługę różnych modeli] end subgraph "Faza 3: Optymalizacja obsługi odpowiedzi" D1[Ujednolicenie formatu odpowiedzi] D2[Implementacja lepszej obsługi błędów] D3[Dodanie walidacji odpowiedzi] end subgraph "Faza 4: Testy i walidacja" E1[Testy jednostkowe] E2[Testy integracyjne] E3[Dokumentacja zmian] end ``` ## Szczegółowa implementacja ### 1. Dedykowana klasa OpenRouterClient ```python class OpenRouterClient: def __init__(self, api_key: str, model_name: str): self.api_key = api_key self.model_name = model_name self.base_url = "https://openrouter.ai/api/v1" self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {api_key}", "HTTP-Referer": "https://github.com/OpenRouterTeam/openrouter-examples", "X-Title": "CV Analysis Tool" }) def create_chat_completion(self, messages: list, max_tokens: int = None): endpoint = f"{self.base_url}/chat/completions" payload = { "model": self.model_name, "messages": messages, "max_tokens": max_tokens } response = self.session.post(endpoint, json=payload) response.raise_for_status() return response.json() def get_available_models(self): endpoint = f"{self.base_url}/models" response = self.session.get(endpoint) response.raise_for_status() return response.json() ``` ### 2. Konfiguracja i inicjalizacja ```python def initialize_openrouter_client(): if not OPENROUTER_API_KEY: raise ValueError("OPENROUTER_API_KEY is required") client = OpenRouterClient( api_key=OPENROUTER_API_KEY, model_name=OPENROUTER_MODEL_NAME ) # Verify connection and model availability try: models = client.get_available_models() if not any(model["id"] == OPENROUTER_MODEL_NAME for model in models): raise ValueError(f"Model {OPENROUTER_MODEL_NAME} not available") logger.debug(f"Successfully connected to OpenRouter. Available models: {models}") return client except Exception as e: logger.error(f"Failed to initialize OpenRouter client: {e}") raise ``` ### 3. Obsługa odpowiedzi ```python class OpenRouterResponse: def __init__(self, raw_response: dict): self.raw_response = raw_response self.choices = self._parse_choices() self.usage = self._parse_usage() self.model = raw_response.get("model") def _parse_choices(self): choices = self.raw_response.get("choices", []) return [ { "message": choice.get("message", {}), "finish_reason": choice.get("finish_reason"), "index": choice.get("index") } for choice in choices ] def _parse_usage(self): usage = self.raw_response.get("usage", {}) return { "prompt_tokens": usage.get("prompt_tokens", 0), "completion_tokens": usage.get("completion_tokens", 0), "total_tokens": usage.get("total_tokens", 0) } ``` ### 4. Obsługa błędów ```python class OpenRouterError(Exception): def __init__(self, message: str, status_code: int = None, response: dict = None): super().__init__(message) self.status_code = status_code self.response = response def handle_openrouter_error(error: Exception) -> OpenRouterError: if isinstance(error, requests.exceptions.RequestException): if error.response is not None: try: error_data = error.response.json() message = error_data.get("error", {}).get("message", str(error)) return OpenRouterError( message=message, status_code=error.response.status_code, response=error_data ) except ValueError: pass return OpenRouterError(str(error)) ``` ## Kolejne kroki 1. Implementacja powyższych klas i funkcji 2. Usunięcie wszystkich zależności OpenAI 3. Aktualizacja istniejącego kodu do korzystania z nowego klienta 4. Dodanie testów jednostkowych i integracyjnych 5. Aktualizacja dokumentacji