"""
Этап 1: Агентный пайплайн для ОЧИСТКИ данных.
"""
import json
import re
import os
import requests
import pandas as pd
class LLMClient:
"""Чистый мультимодальный клиент для отправки текста и графиков на LLM сервер."""
def __init__(self, base_url: str, model_name: str, api_key: str = "none"):
self.base_url = base_url.rstrip("/")
self.server_url = self.base_url + "/v1/chat/completions"
self.models_url = self.base_url + "/v1/models"
self.model_name = model_name
self.headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
def get_models(self) -> list:
"""Получает список доступных моделей с сервера."""
try:
response = requests.get(
self.models_url, headers=self.headers, timeout=30
)
response.raise_for_status()
data = response.json()
# OpenAI-совместимые API возвращают список в объекте {"data": [...]}
if "data" in data:
return [model["id"] for model in data["data"]]
return []
except requests.exceptions.RequestException as e:
print(f"Ошибка при получении списка моделей: {e}")
return []
except (KeyError, TypeError):
print(f"Ошибка парсинга списка моделей. Ответ: {response.text}")
return []
def _encode_image(self, image_path: str) -> str:
"""Кодирует локальное изображение графика в Base64."""
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
def send_multimodal_prompt(
self,
system_role: str,
user_text: str,
temperature: float = 0.5
) -> str:
"""Отправляет текст и опциональный список путей к графикам (PNG/JPG) на модель."""
# Начинаем формировать контент пользователя (сначала всегда идет текст)
user_content = [{"type": "text", "text": user_text}]
payload = {
"model": self.model_name,
"messages": [
{"role": "system", "content": system_role},
{"role": "user", "content": user_content},
],
"temperature": temperature,
}
try:
response = requests.post(
self.server_url, headers=self.headers, json=payload, timeout=120
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except requests.exceptions.RequestException as e:
return f"Ошибка соединения с VL-моделью: {e}"
except (KeyError, IndexError):
return f"Ошибка парсинга ответа. Сервер вернул: {response.text}"