Add support for mistral
This commit is contained in:
parent
e95f1a3810
commit
b84872f507
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -4,3 +4,5 @@ env/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
*.db
|
||||||
|
|
@ -7,6 +7,10 @@ import requests
|
||||||
from typing import Dict, Any, List
|
from typing import Dict, Any, List
|
||||||
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
|
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
|
||||||
|
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
from mistralai import Mistral
|
||||||
|
|
||||||
# --- Конфигурация LLM ---
|
# --- Конфигурация LLM ---
|
||||||
# Пустой словарь для локальных моделей (Ollama)
|
# Пустой словарь для локальных моделей (Ollama)
|
||||||
LOCAL_MODELS: Dict[str, Any] = {}
|
LOCAL_MODELS: Dict[str, Any] = {}
|
||||||
|
|
@ -64,8 +68,19 @@ MODELS: Dict[str, Dict[str, Any]] = {
|
||||||
"mistral-small-latest": {
|
"mistral-small-latest": {
|
||||||
"name": "mistral-small-latest",
|
"name": "mistral-small-latest",
|
||||||
"provider": "mistralai",
|
"provider": "mistralai",
|
||||||
"baseUrl":
|
"model_name": "mistral-small-latest", # Добавлено имя модели для LangChain
|
||||||
"https://render-service-gsu7.onrender.com/m", # "api.mistral.ai", # "https://render-service-gsu7.onrender.com/m",
|
"apiBase":
|
||||||
|
"https://api.mistral.ai",
|
||||||
|
"apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW",
|
||||||
|
"stream": True,
|
||||||
|
"capabilities": ["vision"],
|
||||||
|
},
|
||||||
|
"mistral-small-latest-r": {
|
||||||
|
"name": "mistral-small-latest",
|
||||||
|
"provider": "mistralai",
|
||||||
|
"model_name": "mistral-small-latest", # Добавлено имя модели для LangChain
|
||||||
|
"apiBase":
|
||||||
|
"https://render-service-gsu7.onrender.com/m",
|
||||||
"apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW",
|
"apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW",
|
||||||
"stream": True,
|
"stream": True,
|
||||||
"capabilities": ["vision"],
|
"capabilities": ["vision"],
|
||||||
|
|
@ -79,13 +94,14 @@ class CustomLLM:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config: Dict[str, Any]):
|
def __init__(self, config: Dict[str, Any]):
|
||||||
|
self.config = config
|
||||||
self.name = config["name"]
|
self.name = config["name"]
|
||||||
self.provider = config["provider"]
|
self.provider = config["provider"]
|
||||||
self.config = config
|
|
||||||
|
try:
|
||||||
|
|
||||||
if self.provider == "openai":
|
if self.provider == "openai":
|
||||||
# Инициализация Gemini через OpenAI API
|
# Инициализация Gemini через OpenAI API
|
||||||
from openai import OpenAI
|
|
||||||
self.client = OpenAI(api_key=config["apiKey"],
|
self.client = OpenAI(api_key=config["apiKey"],
|
||||||
base_url=config["apiBase"])
|
base_url=config["apiBase"])
|
||||||
self.model_name = config["model_name"]
|
self.model_name = config["model_name"]
|
||||||
|
|
@ -93,13 +109,18 @@ class CustomLLM:
|
||||||
|
|
||||||
elif self.provider == "mistralai":
|
elif self.provider == "mistralai":
|
||||||
# Для Mistral используем прямые HTTP-запросы
|
# Для Mistral используем прямые HTTP-запросы
|
||||||
self.base_url = config["baseUrl"]
|
self.client = Mistral(api_key=config["apiKey"],
|
||||||
self.api_key = config["apiKey"]
|
server_url=config["apiBase"])
|
||||||
self.stream = config.get("stream", False)
|
self.model_name = config["model_name"]
|
||||||
self.capabilities = config.get("capabilities", [])
|
self.stream = config["stream"]
|
||||||
|
# self.capabilities = config.get("capabilities", [])
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Неизвестный провайдер LLM: {self.provider}")
|
raise ValueError(f"Неизвестный провайдер LLM: {self.provider}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при вызове OpenAI API: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
def invoke(self, messages: List[Any]) -> str:
|
def invoke(self, messages: List[Any]) -> str:
|
||||||
"""
|
"""
|
||||||
Отправляет запрос к LLM и возвращает ответ.
|
Отправляет запрос к LLM и возвращает ответ.
|
||||||
|
|
@ -161,61 +182,61 @@ class CustomLLM:
|
||||||
print(f"Ошибка при вызове OpenAI API: {e}")
|
print(f"Ошибка при вызове OpenAI API: {e}")
|
||||||
raise
|
raise
|
||||||
elif self.provider == "mistralai":
|
elif self.provider == "mistralai":
|
||||||
# Отступы исправлены
|
mistralai_messages = []
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {self.api_key}",
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
}
|
|
||||||
# Формируем сообщения для Mistral API
|
|
||||||
mistral_messages = []
|
|
||||||
if isinstance(messages, str):
|
if isinstance(messages, str):
|
||||||
mistral_messages.append({"role": "user", "content": messages})
|
mistralai_messages.append({"role": "user", "content": messages})
|
||||||
elif isinstance(messages, list):
|
elif isinstance(messages, list):
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
if isinstance(msg, HumanMessage):
|
if isinstance(msg, HumanMessage):
|
||||||
mistral_messages.append({
|
mistralai_messages.append({
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": msg.content
|
"content": msg.content
|
||||||
})
|
})
|
||||||
elif isinstance(msg, SystemMessage):
|
elif isinstance(msg, SystemMessage):
|
||||||
mistral_messages.append({
|
mistralai_messages.append({
|
||||||
"role": "system",
|
"role": "system",
|
||||||
"content": msg.content
|
"content": msg.content
|
||||||
})
|
})
|
||||||
elif isinstance(
|
elif isinstance(
|
||||||
msg, AIMessage): # Добавляем обработку AIMessage
|
msg, AIMessage): # Добавляем обработку AIMessage
|
||||||
mistral_messages.append({
|
mistralai_messages.append({
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": msg.content
|
"content": msg.content
|
||||||
})
|
})
|
||||||
else: # Предполагаем, что это другие типы сообщений Langchain или словари
|
else: # Предполагаем, что это другие типы сообщений Langchain или словари
|
||||||
mistral_messages.append({
|
mistralai_messages.append({
|
||||||
"role":
|
"role":
|
||||||
msg.type if hasattr(msg, 'type') else 'user',
|
msg.type if hasattr(msg, 'type') else 'user',
|
||||||
"content":
|
"content":
|
||||||
msg.content
|
msg.content
|
||||||
})
|
})
|
||||||
|
|
||||||
payload = {
|
|
||||||
"model": self.name,
|
|
||||||
"messages": mistral_messages,
|
|
||||||
"stream": self.stream,
|
|
||||||
}
|
|
||||||
try:
|
try:
|
||||||
response = requests.post(self.base_url,
|
response = self.client.chat.stream(
|
||||||
json=payload,
|
model=self.model_name,
|
||||||
headers=headers)
|
messages=mistralai_messages
|
||||||
response.raise_for_status(
|
)
|
||||||
) # Вызывает исключение для HTTP ошибок
|
|
||||||
data = response.json()
|
if self.stream:
|
||||||
# Извлекаем контент ответа
|
collected_messages = []
|
||||||
return data["choices"][0]["message"]["content"]
|
for chunk in response:
|
||||||
except requests.exceptions.RequestException as e:
|
delta = chunk.data.choices[0].delta
|
||||||
print(f"Ошибка при вызове Mistral API: {e}")
|
chunk_message = getattr(delta, "content", None) # или delta.content, если всегда есть
|
||||||
|
|
||||||
|
if chunk_message is not None:
|
||||||
|
collected_messages.append(chunk_message)
|
||||||
|
|
||||||
|
if getattr(delta, "finish_reason", None) is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
full_reply_content = "".join(collected_messages)
|
||||||
|
return full_reply_content
|
||||||
|
else:
|
||||||
|
return response.choices[0].message.content
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка при вызове OpenAI API: {e}")
|
||||||
raise
|
raise
|
||||||
except KeyError:
|
|
||||||
print(f"Неверный формат ответа от Mistral API: {data}")
|
|
||||||
raise ValueError("Неверный формат ответа от Mistral API")
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ def execute_command_node(state: AgentState) -> AgentState:
|
||||||
DEFAULT_LLM_NAME = "gemini-2.0-flash" #"gemini-2.5-flash"
|
DEFAULT_LLM_NAME = "gemini-2.0-flash" #"gemini-2.5-flash"
|
||||||
main_llm = get_llm(DEFAULT_LLM_NAME)
|
main_llm = get_llm(DEFAULT_LLM_NAME)
|
||||||
|
|
||||||
DEFAULT_SUMMARIZATION_LLM_NAME = "gemini-2.0-flash"
|
DEFAULT_SUMMARIZATION_LLM_NAME = "gemini-2.0-flash-r" # "mistral-small-latest" #"gemini-2.0-flash-r"
|
||||||
|
|
||||||
|
|
||||||
def call_llm_node(state: AgentState) -> AgentState:
|
def call_llm_node(state: AgentState) -> AgentState:
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,13 @@ class TitleGenerator:
|
||||||
|
|
||||||
# Системные промпты для генерации заголовков
|
# Системные промпты для генерации заголовков
|
||||||
self.graph_title_prompt = """Создай краткий заголовок (максимум 80 символов) для диалога на основе первого сообщения пользователя.
|
self.graph_title_prompt = """Создай краткий заголовок (максимум 80 символов) для диалога на основе первого сообщения пользователя.
|
||||||
Заголовок должен отражать основную тему или вопрос. Отвечай только заголовком, без дополнительных объяснений. Ты должен сделать саммери, а не ответить на вопросы, если они есть в сообщении."""
|
Заголовок должен отражать основную тему или вопрос. Заголовок должен быть простым текстом, без какого-либо форматирования или использования
|
||||||
|
специальных символов разметки (например, #, *, _, `). Отвечай только заголовком, без дополнительных объяснений. Ты должен сделать саммери, а не ответить на вопросы, если они есть в сообщении."""
|
||||||
|
|
||||||
self.node_title_prompt = """Создай краткий заголовок (максимум 40 символов) для этого сообщения/действия.
|
self.node_title_prompt = """Создай краткий заголовок (максимум 40 символов) для этого сообщения/действия.
|
||||||
Заголовок должен кратко описывать суть сообщения или действия. Отвечай только заголовком, без дополнительных объяснений. Ты должен сделать саммери, а не ответить на вопросы, если они есть в сообщении."""
|
Заголовок должен кратко описывать суть сообщения или действия. Заголовок должен быть простым текстом, без какого-либо форматирования или использования
|
||||||
|
специальных символов разметки (например, #, *, _, `). Отвечай только заголовком, без дополнительных объяснений. Ты должен сделать саммери, а не ответить на вопросы, если они есть в сообщении."""
|
||||||
|
|
||||||
|
|
||||||
def _get_connection(self):
|
def _get_connection(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,5 @@ langchain_google_genai
|
||||||
|
|
||||||
flask
|
flask
|
||||||
flask_cors
|
flask_cors
|
||||||
|
|
||||||
|
mistralai
|
||||||
Loading…
Reference in New Issue
Block a user