- /rag/commands/expert.py - /core/services/__init__.py - /core/services/embedding_service.py - /core/services/file_service.py - /core/services/giga_client.py - /core/services/kb_service.py - /core/services/postgres_service.py - /core/services/qdrant_service.py - /core/services/reranker_service.py - /core/functions/__init__.py - /core/functions/check_consistency.py - /core/functions/check_spelling.py - /core/functions/critique_answer.py - /core/functions/expand_query.py - /core/functions/extract_metrics.py - /core/functions/file_processor.py - /core/functions/generate_document.py - /core/functions/intent_classify.py - /core/functions/rerank_context.py - /core/functions/summarize_document.py - /core/utils/__init__.py - /core/utils/arg_parser.py - /core/utils/config_loader.py - /core/utils/layout_converter.py - /core/utils/logger.py - /core/utils/text_utils.py - /core/utils/web_utils.py - /bots/commands/__init__.py - /bots/commands/base.py - /bots/commands/create.py - /core/commands/global_remove.py - /core/commands/help.py - /core/commands/info.py - /core/commands/kb.py - /core/commands/learn.py - /core/commands/other.py - /core/commands/registry.py - /core/commands/stats.py - /core/commands/template.py - /core/handlers/__init__.py - /core/handlers/message_handler.py - /core/workers/__init__.py - /core/workers/indexing_worker.py - /core/xmpp/__init__.py - /core/xmpp/client.py - /bots/commands/global_remove.py - /bots/commands/help.py - /bots/commands/info.py - /bots/commands/kb.py - /bots/commands/registry.py - /bots/commands/other.py - /bots/commands/template.py - /bots/commands/learn.py - /bots/commands/stats.py - /bots/handlers/message_handler.py - /bots/handlers/__init__.py - /bots/workers/__init__.py - /bots/workers/indexing_worker.py - /bots/xmpp/__init__.py - /bots/xmpp/client.py - /rag/services/qdrant_service.py - /rag/services/giga_client.py - /rag/services/embedding_service.py - /rag/services/reranker_service.py - /rag/services/__init__.py - /rag/services/file_service.py - /rag/services/postgres_service.py - /rag/services/kb_service.py - /rag/functions/check_spelling.py - /rag/functions/__init__.py - /rag/functions/extract_metrics.py - /rag/functions/generate_document.py - /rag/functions/expand_query.py - /rag/functions/critique_answer.py - /rag/functions/file_processor.py - /rag/functions/check_consistency.py - /rag/functions/summarize_document.py - /rag/functions/rerank_context.py - /rag/functions/intent_classify.py - /rag/utils/__init__.py - /rag/utils/layout_converter.py - /rag/utils/text_utils.py - /rag/utils/arg_parser.py - /rag/utils/config_loader.py - /rag/utils/logger.py - /rag/utils/web_utils.py
109 lines
4.8 KiB
Python
109 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Простой клиент для GigaChat API.
|
||
Только вызовы chat и upload_file, без бизнес-логики.
|
||
Используется AIService и другими модулями.
|
||
"""
|
||
|
||
import asyncio
|
||
import logging
|
||
from typing import List, Dict, Optional
|
||
|
||
from gigachat import GigaChat
|
||
from gigachat.models import Chat, Messages, MessagesRole
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class GigaClient:
|
||
def __init__(self, api_key: str, model: str, temperature: float, timeout: int, verify_ssl: bool = False):
|
||
self.api_key = api_key
|
||
self.model = model
|
||
self.temperature = temperature
|
||
self.timeout = timeout
|
||
self.verify_ssl = verify_ssl
|
||
self._client = None
|
||
|
||
def _get_client(self) -> GigaChat:
|
||
"""Ленивое создание клиента (создаётся при первом запросе)."""
|
||
if self._client is None:
|
||
self._client = GigaChat(
|
||
credentials=self.api_key,
|
||
model=self.model,
|
||
verify_ssl_certs=self.verify_ssl,
|
||
timeout=self.timeout
|
||
)
|
||
logger.debug("GigaChat client initialized")
|
||
return self._client
|
||
|
||
async def chat(
|
||
self,
|
||
history: List[Dict[str, str]],
|
||
query: str,
|
||
system_prompt: Optional[str] = None,
|
||
file_id: Optional[str] = None,
|
||
temperature: Optional[float] = None,
|
||
) -> str:
|
||
"""
|
||
Отправляет запрос к GigaChat и возвращает ответ.
|
||
|
||
Аргументы:
|
||
history: список предыдущих сообщений (каждое с ключами role и content).
|
||
query: текущий запрос пользователя.
|
||
system_prompt: системный промпт (если задан, добавляется первым сообщением).
|
||
file_id: идентификатор загруженного файла (для Vision).
|
||
|
||
Возвращает:
|
||
str: ответ модели или сообщение об ошибке.
|
||
"""
|
||
messages = []
|
||
if system_prompt:
|
||
messages.append(Messages(role=MessagesRole.SYSTEM, content=system_prompt))
|
||
for msg in history[-10:]: # ограничим историю 10 сообщениями для экономии токенов
|
||
role = MessagesRole.USER if msg['role'] == 'user' else MessagesRole.ASSISTANT
|
||
messages.append(Messages(role=role, content=msg['content']))
|
||
messages.append(Messages(role=MessagesRole.USER, content=query))
|
||
|
||
attachments = [file_id] if file_id else None
|
||
|
||
actual_temp = temperature if temperature is not None else self.temperature
|
||
|
||
try:
|
||
# Запускаем синхронный вызов giga.chat в отдельном потоке
|
||
response = await asyncio.to_thread(
|
||
self._get_client().chat,
|
||
Chat(
|
||
messages=messages,
|
||
model=self.model,
|
||
temperature=actual_temp,
|
||
n=1,
|
||
attachments=attachments
|
||
)
|
||
)
|
||
return response.choices[0].message.content
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при вызове GigaChat: {e}", exc_info=True)
|
||
return "Извините, произошла ошибка при обращении к сервису ИИ."
|
||
|
||
async def upload_file(self, file_path: str) -> Optional[str]:
|
||
"""
|
||
Загружает файл в GigaChat для Vision-анализа (изображения).
|
||
Возвращает file_id для использования в chat().
|
||
"""
|
||
try:
|
||
with open(file_path, "rb") as f:
|
||
# Загружаем файл синхронно в потоке
|
||
uploaded = await asyncio.to_thread(self._get_client().upload_file, f, "general")
|
||
# В разных версиях SDK поле может называться id_, id или file_id
|
||
if hasattr(uploaded, "id_"):
|
||
return uploaded.id_
|
||
if hasattr(uploaded, "id"):
|
||
return uploaded.id
|
||
if hasattr(uploaded, "file_id"):
|
||
return uploaded.file_id
|
||
# fallback: пробуем преобразовать в словарь
|
||
data = uploaded.dict() if hasattr(uploaded, "dict") else {}
|
||
return data.get("id_") or data.get("id") or data.get("file_id")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка загрузки файла в GigaChat: {e}", exc_info=True)
|
||
return None |