from typing import Dict, Any, Tuple, Optional from ..base import BaseIntegrationService from .config import get_openrouter_config import logging import sys import locale # Патч для исправления проблемы с кодировкой в httpx на Windows # Устанавливаем кодировку по умолчанию для Python if sys.platform == 'win32': try: import httpx._models original_normalize_header_value = httpx._models._normalize_header_value def patched_normalize_header_value(value, encoding): """Патч для использования UTF-8 вместо ASCII для заголовков""" # Если значение уже bytes, возвращаем его как есть if isinstance(value, bytes): return value # Всегда используем UTF-8 вместо ASCII encoding = encoding or 'utf-8' if encoding.lower() == 'ascii': encoding = 'utf-8' return value.encode(encoding) httpx._models._normalize_header_value = patched_normalize_header_value logging.getLogger(__name__).info("Applied patch for httpx header encoding on Windows") except Exception as e: logging.getLogger(__name__).warning(f"Failed to apply httpx patch: {e}") from openai import OpenAI logger = logging.getLogger(__name__) class OpenRouterIntegrationService(BaseIntegrationService): """ Сервис интеграции с OpenRouter.ai """ def __init__(self, config): super().__init__(config) logger.info(f"=== Инициализация OpenRouterIntegrationService ===") try: self.cfg = get_openrouter_config(config) logger.info(f"Конфигурация успешно получена") logger.info(f"API URL: {self.cfg.api_url}") logger.info(f"Model name: {self.cfg.model_name}") logger.info(f"Temperature: {self.cfg.temperature}") logger.info(f"API key (первые 10 символов): {self.cfg.api_key[:10] if self.cfg.api_key else 'None'}...") except Exception as e: logger.error(f"Ошибка при получении конфигурации: {str(e)}", exc_info=True) raise # Импортируем клиент OpenAI (OpenRouter совместим с OpenAI API) try: self.client = OpenAI( api_key=self.cfg.api_key, base_url=self.cfg.api_url, ) logger.info(f"OpenAI клиент для OpenRouter успешно создан") except ImportError: logger.error("Библиотека openai не установлена") raise ImportError( "Необходимо установить библиотеку openai: pip install openai" ) except Exception as e: logger.error(f"Ошибка при создании клиента: {str(e)}", exc_info=True) raise def test_connection(self) -> Tuple[bool, str]: """ Проверить соединение с API OpenRouter """ logger.info(f"=== Начало тестирования соединения с OpenRouter ===") try: logger.info(f"Отправка запроса к API OpenRouter...") logger.info(f"Model: {self.cfg.model_name}, Temperature: {self.cfg.temperature}") messages = [{"role": "user", "content": "ping"}] response = self.client.chat.completions.create( model=self.cfg.model_name, messages=messages, temperature=self.cfg.temperature, max_tokens=10 ) logger.info(f"Получен ответ от API OpenRouter") if response.choices and len(response.choices) > 0: logger.info(f"Успешное подключение к OpenRouter") return True, "Connection to OpenRouter successful" else: logger.error(f"Некорректный ответ от API OpenRouter: нет choices") return False, "Invalid response from OpenRouter API" except Exception as e: logger.error(f"Ошибка подключения к OpenRouter: {str(e)}", exc_info=True) return False, f"Connection error: {str(e)}" def sync(self) -> Tuple[bool, str]: """ Основная операция синхронизации (для OpenRouter не требуется) """ return True, "Синхронизация OpenRouter не требуется" def generate_text(self, prompt: str, system_prompt: Optional[str] = None, max_tokens: Optional[int] = None) -> Tuple[bool, str, Optional[Dict]]: """ Генерация текста с помощью OpenRouter Args: prompt: Входной текст для генерации system_prompt: Системный промпт (опционально) max_tokens: Максимальное количество токенов в ответе Returns: tuple: (success: bool, message: str, response_data: dict or None) """ if not self.is_available(): return False, "Интеграция OpenRouter не активна", None try: messages = [] if system_prompt: messages.append({"role": "system", "content": system_prompt}) messages.append({"role": "user", "content": prompt}) response = self.client.chat.completions.create( model=self.cfg.model_name, messages=messages, temperature=self.cfg.temperature, max_tokens=max_tokens or self.cfg.max_tokens ) generated_text = response.choices[0].message.content usage_info = getattr(response, 'usage', {}) return True, "Текст успешно сгенерирован", { 'generated_text': generated_text, 'usage': usage_info, 'model': self.cfg.model_name } except Exception as e: logger.error(f"Ошибка генерации текста с помощью OpenRouter: {str(e)}") return False, f"Ошибка генерации: {str(e)}", None def generate_code(self, prompt: str, language: Optional[str] = None, max_tokens: Optional[int] = None) -> Tuple[bool, str, Optional[Dict]]: """ Генерация кода с помощью OpenRouter Args: prompt: Описание задачи для генерации кода language: Язык программирования (опционально) max_tokens: Максимальное количество токенов в ответе Returns: tuple: (success: bool, message: str, response_data: dict or None) """ if not self.is_available(): return False, "Интеграция OpenRouter не активна", None try: system_prompt = "You are a helpful AI coding assistant. Generate clean, efficient, and well-documented code." if language: system_prompt += f" The code should be in {language}." messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt} ] response = self.client.chat.completions.create( model=self.cfg.model_name, messages=messages, temperature=self.cfg.temperature, max_tokens=max_tokens or self.cfg.max_tokens ) generated_code = response.choices[0].message.content usage_info = getattr(response, 'usage', {}) return True, "Код успешно сгенерирован", { 'generated_code': generated_code, 'usage': usage_info, 'model': self.cfg.model_name } except Exception as e: logger.error(f"Ошибка генерации кода с помощью OpenRouter: {str(e)}") return False, f"Ошибка генерации кода: {str(e)}", None