Files
octopus/myproject/integrations/services/ai_services/glm_service.py

218 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Dict, Any, Tuple, Optional
from ..base import BaseIntegrationService
from django.conf import settings
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 zai import ZaiClient
from .config import get_glm_config
logger = logging.getLogger(__name__)
class GLMIntegrationService(BaseIntegrationService):
"""
Сервис интеграции с GLM от Z.AI
"""
def __init__(self, config):
super().__init__(config)
logger.info(f"=== Инициализация GLMIntegrationService ===")
logger.info(f"Тип config: {type(config)}")
# Получаем конфигурацию из модели интеграции
try:
self.cfg = get_glm_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
# Создаем клиент ZaiClient
try:
logger.info(f"Попытка создать ZaiClient...")
logger.info(f"API key type: {type(self.cfg.api_key)}")
logger.info(f"API key length: {len(self.cfg.api_key) if self.cfg.api_key else 0}")
logger.info(f"API key (первые 10 символов): {self.cfg.api_key[:10] if self.cfg.api_key else 'None'}...")
logger.info(f"API key (последние 10 символов): {self.cfg.api_key[-10:] if self.cfg.api_key and len(self.cfg.api_key) > 10 else 'None'}...")
self.client = ZaiClient(api_key=self.cfg.api_key)
logger.info(f"ZaiClient успешно создан")
except Exception as e:
logger.error(f"Ошибка при создании ZaiClient: {str(e)}", exc_info=True)
raise
def test_connection(self) -> Tuple[bool, str]:
"""
Проверить соединение с API GLM
"""
import sys
import locale
logger.info(f"=== Начало тестирования соединения с GLM ===")
logger.info(f"Python default encoding: {sys.getdefaultencoding()}")
logger.info(f"Python filesystem encoding: {sys.getfilesystemencoding()}")
logger.info(f"Locale preferred encoding: {locale.getpreferredencoding()}")
try:
# Отправляем простой запрос для проверки подключения
logger.info(f"Отправка запроса к API GLM...")
logger.info(f"Model: {self.cfg.model_name}, Temperature: {self.cfg.temperature}")
# Используем английский текст для теста, чтобы избежать проблем с кодировкой
messages = [{"role": "user", "content": "ping"}]
logger.info(f"Messages: {messages}")
response = self.client.chat.completions.create(
model=self.cfg.model_name,
messages=messages,
temperature=self.cfg.temperature,
max_tokens=10
)
logger.info(f"Получен ответ от API GLM")
logger.info(f"Тип ответа: {type(response)}")
logger.info(f"Атрибуты ответа: {dir(response)}")
# Проверяем, что получили ответ
if hasattr(response, 'choices') and len(response.choices) > 0:
logger.info(f"Успешное подключение к GLM")
return True, "Connection to GLM successful"
else:
logger.error(f"Некорректный ответ от API GLM: нет choices")
return False, "Invalid response from GLM API"
except Exception as e:
logger.error(f"Ошибка подключения к GLM: {str(e)}", exc_info=True)
return False, f"Connection error: {str(e)}"
def sync(self) -> Tuple[bool, str]:
"""
Основная операция синхронизации (в случае GLM - может быть вызовом API для обработки данных)
"""
# Реализация будет зависеть от конкретных требований
return True, "Синхронизация GLM не требуется"
def generate_text(self,
prompt: str,
system_prompt: Optional[str] = None,
max_tokens: int = 1000) -> Tuple[bool, str, Optional[Dict]]:
"""
Генерация текста с помощью GLM
Args:
prompt: Входной текст для генерации
system_prompt: Системный промпт (опционально)
max_tokens: Максимальное количество токенов в ответе
Returns:
tuple: (success: bool, message: str, response_data: dict or None)
"""
if not self.is_available():
return False, "Интеграция GLM не активна", 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
)
# Извлекаем сгенерированный текст
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"Ошибка генерации текста с помощью GLM: {str(e)}")
return False, f"Ошибка генерации: {str(e)}", None
def generate_code(self,
prompt: str,
language: Optional[str] = None,
max_tokens: int = 1000) -> Tuple[bool, str, Optional[Dict]]:
"""
Генерация кода с помощью GLM (использует специальный эндпоинт, если указан)
Args:
prompt: Описание задачи для генерации кода
language: Язык программирования (опционально)
max_tokens: Максимальное количество токенов в ответе
Returns:
tuple: (success: bool, message: str, response_data: dict or None)
"""
if not self.is_available():
return False, "Интеграция GLM не активна", 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
)
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"Ошибка генерации кода с помощью GLM: {str(e)}")
return False, f"Ошибка генерации кода: {str(e)}", None