diff --git a/app/llm_client.py b/app/llm_client.py index 43bc306..e639423 100644 --- a/app/llm_client.py +++ b/app/llm_client.py @@ -55,14 +55,17 @@ MODELS: Dict[str, Dict[str, Any]] = { "capabilities": ["vision"], }, "gemini-2.5-flash-openrouter": { - "name": "gemini-2.5-flash-openrouter", - "provider": "openai", # Изменено на "openai" - "model_name": "gemini-2.5-flash", # Добавлено имя модели для LangChain - "apiBase": - "https://openrouter.ai", # "generativelanguage.googleapis.com", # "https://render-service-gsu7.onrender.com/g/v1beta", - "apiKey": "AIzaSyDpueKFWVqknVKlQn6TdasLmJ2lvAUiBik", + "name": "google/gemini-2.5-flash", + "provider": "openai", + "model_name": "google/gemini-2.5-flash", + "apiBase": "https://openrouter.ai/api/v1", # Добавлено /api/v1 + "apiKey": + "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", "stream": True, - "capabilities": ["vision"], + "capabilities": ["vision", "reasoning"], + "model_kwargs": { + "include_reasoning": True + } }, "gemini-2.5-flash-bh": { "name": "gemini-2.5-flash", @@ -77,7 +80,8 @@ MODELS: Dict[str, Dict[str, Any]] = { "gemini-3-flash-preview-bh": { "name": "gemini-3-flash-preview", "provider": "openai", # Изменено на "openai" - "model_name": "gemini-3-flash-preview", # Добавлено имя модели для LangChain + "model_name": + "gemini-3-flash-preview", # Добавлено имя модели для LangChain "apiBase": "https://bothub.chat/api/v2/openai/v1", "apiKey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ3MTMwYTk0LTJiNmMtNDgzZi04Y2NiLWM5MjgwNzlmNDFlZSIsImlzRGV2ZWxvcGVyIjp0cnVlLCJpYXQiOjE3NTQ0NzYwMDcsImV4cCI6MjA3MDA1MjAwN30._64_DXNZatdd4-4VbXp8dOXdDhIlNWMQt9A_Nn6mu3g", @@ -87,7 +91,8 @@ MODELS: Dict[str, Dict[str, Any]] = { "gemini-3.1-pro-preview-bh": { "name": "gemini-3.1-pro-preview", "provider": "openai", # Изменено на "openai" - "model_name": "gemini-3.1-pro-preview", # Добавлено имя модели для LangChain + "model_name": + "gemini-3.1-pro-preview", # Добавлено имя модели для LangChain "apiBase": "https://bothub.chat/api/v2/openai/v1", "apiKey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ3MTMwYTk0LTJiNmMtNDgzZi04Y2NiLWM5MjgwNzlmNDFlZSIsImlzRGV2ZWxvcGVyIjp0cnVlLCJpYXQiOjE3NTQ0NzYwMDcsImV4cCI6MjA3MDA1MjAwN30._64_DXNZatdd4-4VbXp8dOXdDhIlNWMQt9A_Nn6mu3g", @@ -97,7 +102,8 @@ MODELS: Dict[str, Dict[str, Any]] = { "claude-4.5-sonnet-bh": { "name": "claude-4.5-sonnet-bh", "provider": "openai", # Изменено на "openai" - "model_name": "claude-sonnet-4.5", # Добавлено имя модели для LangChain + "model_name": + "claude-sonnet-4.5", # Добавлено имя модели для LangChain "apiBase": "https://bothub.chat/api/v2/openai/v1", "apiKey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImQ3MTMwYTk0LTJiNmMtNDgzZi04Y2NiLWM5MjgwNzlmNDFlZSIsImlzRGV2ZWxvcGVyIjp0cnVlLCJpYXQiOjE3NTQ0NzYwMDcsImV4cCI6MjA3MDA1MjAwN30._64_DXNZatdd4-4VbXp8dOXdDhIlNWMQt9A_Nn6mu3g", @@ -107,9 +113,9 @@ MODELS: Dict[str, Dict[str, Any]] = { "mistral-small-latest": { "name": "mistral-small-latest", "provider": "mistralai", - "model_name": "mistral-small-latest", # Добавлено имя модели для LangChain - "apiBase": - "https://api.mistral.ai", + "model_name": + "mistral-small-latest", # Добавлено имя модели для LangChain + "apiBase": "https://api.mistral.ai", "apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW", "stream": True, "capabilities": ["vision"], @@ -117,9 +123,9 @@ MODELS: Dict[str, Dict[str, Any]] = { "mistral-small-latest-r": { "name": "mistral-small-latest", "provider": "mistralai", - "model_name": "mistral-small-latest", # Добавлено имя модели для LangChain - "apiBase": - "https://render-service-gsu7.onrender.com/m", + "model_name": + "mistral-small-latest", # Добавлено имя модели для LangChain + "apiBase": "https://render-service-gsu7.onrender.com/m", "apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW", "stream": True, "capabilities": ["vision"], @@ -127,9 +133,9 @@ MODELS: Dict[str, Dict[str, Any]] = { "mistral-small-latest-error": { "name": "mistral-small-latest", "provider": "mistralai", - "model_name": "mistral-small-latest-error", # Добавлено имя модели для LangChain - "apiBase": - "https://render-service-gsu7.onrender.com/m", + "model_name": + "mistral-small-latest-error", # Добавлено имя модели для LangChain + "apiBase": "https://render-service-gsu7.onrender.com/m", "apiKey": "Q0m29fvxBY0Cfdj4sjHaKqccy1NjonLW", "stream": True, "capabilities": ["vision"], @@ -152,14 +158,14 @@ class CustomLLM: if self.provider == "openai": # Инициализация Gemini через OpenAI API self.client = OpenAI(api_key=config["apiKey"], - base_url=config["apiBase"]) + base_url=config["apiBase"]) self.model_name = config["model_name"] self.stream = config["stream"] elif self.provider == "mistralai": # Для Mistral используем прямые HTTP-запросы self.client = Mistral(api_key=config["apiKey"], - server_url=config["apiBase"]) + server_url=config["apiBase"]) self.model_name = config["model_name"] self.stream = config["stream"] # self.capabilities = config.get("capabilities", []) @@ -233,7 +239,10 @@ class CustomLLM: elif self.provider == "mistralai": mistralai_messages = [] if isinstance(messages, str): - mistralai_messages.append({"role": "user", "content": messages}) + mistralai_messages.append({ + "role": "user", + "content": messages + }) elif isinstance(messages, list): for msg in messages: if isinstance(msg, HumanMessage): @@ -261,16 +270,16 @@ class CustomLLM: }) try: - response = self.client.chat.stream( - model=self.model_name, - messages=mistralai_messages - ) + response = self.client.chat.stream(model=self.model_name, + messages=mistralai_messages) if self.stream: collected_messages = [] for chunk in response: delta = chunk.data.choices[0].delta - chunk_message = getattr(delta, "content", None) # или delta.content, если всегда есть + chunk_message = getattr( + delta, "content", + None) # или delta.content, если всегда есть if chunk_message is not None: collected_messages.append(chunk_message) @@ -295,7 +304,7 @@ class CustomLLM: """ if self.provider == "openai": openai_messages = self._prepare_openai_messages(messages) - + try: response = self.client.chat.completions.create( model=self.model_name, @@ -318,20 +327,18 @@ class CustomLLM: elif self.provider == "mistralai": mistralai_messages = self._prepare_mistralai_messages(messages) - + try: - response = self.client.chat.stream( - model=self.model_name, - messages=mistralai_messages - ) + response = self.client.chat.stream(model=self.model_name, + messages=mistralai_messages) for chunk in response: delta = chunk.data.choices[0].delta chunk_message = getattr(delta, "content", None) - + if chunk_message is not None: yield chunk_message - + if getattr(delta, "finish_reason", None) is not None: break @@ -343,7 +350,8 @@ class CustomLLM: print(f"Ошибка при стриминге Mistral API: {e}") raise - def _prepare_openai_messages(self, messages: List[Any]) -> List[Dict[str, str]]: + def _prepare_openai_messages(self, + messages: List[Any]) -> List[Dict[str, str]]: """Подготавливает сообщения в формате OpenAI.""" openai_messages = [] if isinstance(messages, str): @@ -351,19 +359,31 @@ class CustomLLM: elif isinstance(messages, list): for msg in messages: if isinstance(msg, HumanMessage): - openai_messages.append({"role": "user", "content": msg.content}) + openai_messages.append({ + "role": "user", + "content": msg.content + }) elif isinstance(msg, SystemMessage): - openai_messages.append({"role": "system", "content": msg.content}) + openai_messages.append({ + "role": "system", + "content": msg.content + }) elif isinstance(msg, AIMessage): - openai_messages.append({"role": "assistant", "content": msg.content}) + openai_messages.append({ + "role": "assistant", + "content": msg.content + }) else: openai_messages.append({ - "role": msg.type if hasattr(msg, 'type') else 'user', - "content": msg.content + "role": + msg.type if hasattr(msg, 'type') else 'user', + "content": + msg.content }) return openai_messages - def _prepare_mistralai_messages(self, messages: List[Any]) -> List[Dict[str, str]]: + def _prepare_mistralai_messages( + self, messages: List[Any]) -> List[Dict[str, str]]: """Подготавливает сообщения в формате Mistral AI.""" mistralai_messages = [] if isinstance(messages, str): @@ -371,15 +391,26 @@ class CustomLLM: elif isinstance(messages, list): for msg in messages: if isinstance(msg, HumanMessage): - mistralai_messages.append({"role": "user", "content": msg.content}) + mistralai_messages.append({ + "role": "user", + "content": msg.content + }) elif isinstance(msg, SystemMessage): - mistralai_messages.append({"role": "system", "content": msg.content}) + mistralai_messages.append({ + "role": "system", + "content": msg.content + }) elif isinstance(msg, AIMessage): - mistralai_messages.append({"role": "assistant", "content": msg.content}) + mistralai_messages.append({ + "role": "assistant", + "content": msg.content + }) else: mistralai_messages.append({ - "role": msg.type if hasattr(msg, 'type') else 'user', - "content": msg.content + "role": + msg.type if hasattr(msg, 'type') else 'user', + "content": + msg.content }) return mistralai_messages