add Custom provider

This commit is contained in:
2025-12-14 06:31:00 +03:00
parent 1e5105b7d6
commit 9bf9d8a55d
10 changed files with 197 additions and 104 deletions

View File

@@ -3,8 +3,9 @@ from services.llm_providers.ionet_provider import IoNetProvider
from services.llm_providers.gemini_provider import GeminiProvider
from services.llm_providers.gpt4free_provider import Gpt4FreeProvider
from services.llm_providers.base_provider import BaseLLMProvider
from services.llm_providers.custom_provider import CustomProvider
def get_llm_provider(provider_name: str, api_key: str | None) -> BaseLLMProvider:
def get_llm_provider(provider_name: str, api_key: str | None = None, base_url: str | None = None) -> BaseLLMProvider:
"""
Фабричная функция для получения экземпляра провайдера LLM.
"""
@@ -18,5 +19,9 @@ def get_llm_provider(provider_name: str, api_key: str | None) -> BaseLLMProvider
return GeminiProvider(api_key)
elif provider_name == 'gpt4free':
return Gpt4FreeProvider()
elif provider_name == 'Custom':
if not base_url:
raise ValueError("Base URL обязателен для Custom провайдера")
return CustomProvider(api_key, base_url) # base_url будет установлен позже
else:
raise ValueError(f"Неизвестный провайдер: {provider_name}")

View File

@@ -0,0 +1,44 @@
import requests
from .base_provider import BaseLLMProvider
class CustomProvider(BaseLLMProvider):
def __init__(self, api_key: str | None = None, base_url: str | None = None):
super().__init__(api_key)
self.base_url = base_url or 'http://127.0.0.1:1234/v1/'
# ГАРАНТИРУЕМ наличие слеша в конце URL
if not self.base_url.endswith('/'):
self.base_url += '/'
def generate(self, model: str, system_prompt: str, user_prompt: str, temp: float):
url = f"{self.base_url}chat/completions"
# Некоторые Custom провайдеры (как vLLM или Ollama) могут требовать API Key, даже если он фиктивный
headers = {"Content-Type": "application/json"}
if self.api_key:
headers["Authorization"] = f"Bearer {self.api_key}"
data = {
"model": model,
"messages": [
{'role': 'system', 'content': system_prompt},
{'role': 'user', 'content': user_prompt},
],
"temperature": temp,
"stream": False
}
try:
response = requests.post(url, headers=headers, json=data, timeout=300)
response.raise_for_status()
result = response.json()
# Обработка разных форматов ответа (на всякий случай)
if 'choices' in result and len(result['choices']) > 0:
text = str(result['choices'][0]['message']['content'])
return text, text
else:
return f"Неожиданный ответ от сервера: {result}", str(result)
except requests.exceptions.RequestException as e:
return f"Ошибка при запросе к CustomProvider API: {e}", f"Ошибка: {e}"

View File

@@ -41,7 +41,7 @@ class GeminiProvider(BaseLLMProvider):
try:
# 4. Отправляем POST-запрос с данными и настройками прокси
response = requests.post(api_url, json=data, proxies=proxies, timeout=90)
response = requests.post(api_url, json=data, proxies=proxies, timeout=400)
# Проверяем, не вернул ли сервер ошибку (например, 4xx или 5xx)
response.raise_for_status()

View File

@@ -3,6 +3,13 @@ from g4f.client import Client
from .base_provider import BaseLLMProvider
class Gpt4FreeProvider(BaseLLMProvider):
"""
Провайдер для работы с моделью GPT через библиотеку gpt4free.
Этот класс реализует интерфейс BaseLLMProvider и предоставляет возможность
взаимодействия с различными LLM через сервис gpt4free, который не требует
API ключа для работы.
"""
# gpt4free не требует API ключа
def __init__(self, api_key: str | None = None):
super().__init__(api_key)
@@ -10,6 +17,18 @@ class Gpt4FreeProvider(BaseLLMProvider):
def generate(self, model: str, system_prompt: str, user_prompt: str, temp: float):
"""
Генерирует ответ от модели GPT с использованием gpt4free.
Args:
model (str): Название модели для генерации ответа
system_prompt (str): Системное сообщение для контекста
user_prompt (str): Пользовательский запрос
temp (float): Температура генерации ( controls randomness of responses)
Returns:
tuple: Кортеж из двух одинаковых строк - сгенерированного ответа и его копии
"""
# temp в g4f может работать не для всех внутренних провайдеров
try:
response = self.client.chat.completions.create(

View File

@@ -1,23 +1,34 @@
import openai
import requests
from .base_provider import BaseLLMProvider
class IoNetProvider(BaseLLMProvider):
def __init__(self, api_key: str):
super().__init__(api_key)
self.client = openai.OpenAI(
api_key=self.api_key,
base_url='https://api.intelligence.io.solutions/api/v1/'
)
self.base_url = 'https://api.intelligence.io.solutions/api/v1'
def generate(self, model: str, system_prompt: str, user_prompt: str, temp: float):
response = self.client.chat.completions.create(
model=model,
messages=[
url = f"{self.base_url}/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}"
}
data = {
"model": model,
"messages": [
{'role': 'system', 'content': system_prompt},
{'role': 'user', 'content': user_prompt},
],
temperature=temp,
stream=False
)
text = str(response.choices[0].message.content)
return text, text # Возвращаем как чистый текст, так и Markdown
"temperature": temp
}
try:
response = requests.post(url, headers=headers, json=data)
response.raise_for_status()
result = response.json()
text = str(result['choices'][0]['message']['content'])
return text, text # Возвращаем как чистый текст, так и Markdown
except requests.exceptions.RequestException as e:
raise Exception(f"Ошибка при запросе к IO.net API: {e}")