@@ -7,6 +7,7 @@ from langchain_core.messages import HumanMessage, SystemMessage from messages.models import Message from ml_model.exceptions import FileExtensionNotSupported +from ml_model.models import NeuronModel from ml_model.services import Chatgpt from poller.models import Proxy @@ -19,9 +20,9 @@ class Chatgpt_5(Chatgpt): 'web_search': { 'low': Decimal('5'), # 1 call 'medium': Decimal('5'), # 1 call - 'high': Decimal('5') # 1 call + 'high': Decimal('5'), # 1 call }, - 'code_interpreter': Decimal('15') + 'code_interpreter': Decimal('15'), }, 'gpt-5-mini': { 'input': Decimal('0.000125'), @@ -29,14 +30,14 @@ class Chatgpt_5(Chatgpt): 'web_search': { 'low': Decimal('5'), # 1 call 'medium': Decimal('5'), # 1 call - 'high': Decimal('5') # 1 call + 'high': Decimal('5'), # 1 call }, - 'code_interpreter': Decimal('15') + 'code_interpreter': Decimal('15'), }, 'gpt-5-nano': { 'input': Decimal('0.000025'), 'output': Decimal('0.0002'), - 'code_interpreter': Decimal('15') + 'code_interpreter': Decimal('15'), }, 'gpt-5.1': { 'input': Decimal('0.000625'), @@ -44,9 +45,9 @@ class Chatgpt_5(Chatgpt): 'web_search': { 'low': Decimal('5'), # 1 call 'medium': Decimal('5'), # 1 call - 'high': Decimal('5') # 1 call + 'high': Decimal('5'), # 1 call }, - 'code_interpreter': Decimal('15') # 1 call + 'code_interpreter': Decimal('15'), # 1 call }, 'gpt-5-pro': { 'input': Decimal('0.0075'), @@ -54,7 +55,7 @@ class Chatgpt_5(Chatgpt): 'web_search': { 'low': Decimal('5'), # 1 call 'medium': Decimal('5'), # 1 call - 'high': Decimal('5') # 1 call + 'high': Decimal('5'), # 1 call }, }, 'gpt-5.1-codex-max': { @@ -75,14 +76,18 @@ class Chatgpt_5(Chatgpt): 'web_search': { 'low': Decimal('5'), # 1 call 'medium': Decimal('5'), # 1 call - 'high': Decimal('5') # 1 call + 'high': Decimal('5'), # 1 call }, - 'code_interpreter': Decimal('15') # 1 call + 'code_interpreter': Decimal('15'), # 1 call }, } TOKEN_LIMITS = {key: 200_000 for key in TOKENS_COST.keys()} + @property + def neuron_model(self): + return NeuronModel.objects.get(slug='chatgpt_5') + def make( self, input_message: Message, @@ -115,7 +120,9 @@ class Chatgpt_5(Chatgpt): chat_history = self.get_chat_history(model_name=model_name) chat_history.add_message(HumanMessage(content=input_message.content)) llm_input = [SystemMessage(content=user_system_prompt), HumanMessage(content=input_content)] - input_tokens, input_embedding_tokens = self._get_input_tokens(file, image, chunks, chat_history, llm_input) + input_tokens, input_embedding_tokens = self._get_input_tokens( + file, image, chunks, chat_history, llm_input + ) self.assert_enough_balance( input_tokens, image_size, model=model_name, embedding_tokens=input_embedding_tokens ) @@ -130,40 +137,46 @@ class Chatgpt_5(Chatgpt): if image: messages[-1]['content'] = [ {'type': 'input_text', 'text': input_message.content}, - {'type': 'input_image', 'image_url': image_data['image_url']['url']} + {'type': 'input_image', 'image_url': image_data['image_url']['url']}, ] elif file: if sum([len(chunk.content) for chunk in chunks]) > 20_000: - document_name = chunks[0].content.partition(f':{chr(10)}')[2].split(f'{chr(10)}')[0][:100] - embedding_tokens, file_data = self.get_large_file_data(chunks, proxy, input_message.content) + document_name = ( + chunks[0].content.partition(f':{chr(10)}')[2].split(f'{chr(10)}')[0][:100] + ) + embedding_tokens, file_data = self.get_large_file_data( + chunks, proxy, input_message.content + ) messages[-1]['content'] = self.make_embeddings_prompt( document_name=document_name, section_texts=file_data, question=input_message.content ) else: - messages[-1]['content'] = (f'Используй системный промпт. Содержание файла: ' - f'{chunks}. Вопрос: {input_message.content}') + messages[-1]['content'] = ( + f'Используй системный промпт. Содержание файла: ' + f'{chunks}. Вопрос: {input_message.content}' + ) json_data = { 'model': model_name, 'input': messages, 'tools': [], 'instructions': ( - "Форматирование — обязательное требование. Выполняй строго по правилам:\n\n" + 'Форматирование — обязательное требование. Выполняй строго по правилам:\n\n' "1) Используй реальные символы новой строки, не выводи '\\n' как текст — вставляй переносы.\n\n" - "2) Абзацы: между абзацами ставь две пустые строки (два символа новой строки подряд).\n\n" - "3) Нумерованные и маркированные списки: каждый пункт на отдельной строке;\n" - " между списком и текстом оставляй две пустые строки.\n\n" - "4) Блоки кода: любые фрагменты кода выделяй тройными бэктиками (```) с указанием языка программирования;\n" - " перед и после блока оставляй две пустые строки.\n\n" + '2) Абзацы: между абзацами ставь две пустые строки (два символа новой строки подряд).\n\n' + '3) Нумерованные и маркированные списки: каждый пункт на отдельной строке;\n' + ' между списком и текстом оставляй две пустые строки.\n\n' + '4) Блоки кода: любые фрагменты кода выделяй тройными бэктиками (```) с указанием языка программирования;\n' + ' перед и после блока оставляй две пустые строки.\n\n' "5) Заголовки абзацев: делай крупным, используя Markdown '####' (например, '### Заголовок');\n" - " выделяй жирным (**Заголовок**); оставляй две пустые строки перед и после заголовка.\n\n" - "6) Используй Markdown для всего форматирования, не используй HTML.\n\n" - "7) Исправление формата: если формат неверный, перепиши ответ и верни исправленный вариант.\n\n" - "Строго разделяй текст на абзацы с жирными заголовками;\n" - "нумерованные и маркированные списки выводи с переносами строк;\n" - "блоки кода — с тройными бэктиками и указанием языка;\n" + ' выделяй жирным (**Заголовок**); оставляй две пустые строки перед и после заголовка.\n\n' + '6) Используй Markdown для всего форматирования, не используй HTML.\n\n' + '7) Исправление формата: если формат неверный, перепиши ответ и верни исправленный вариант.\n\n' + 'Строго разделяй текст на абзацы с жирными заголовками;\n' + 'нумерованные и маркированные списки выводи с переносами строк;\n' + 'блоки кода — с тройными бэктиками и указанием языка;\n' "не выводи '\\n' как текст, используйте реальные переносы строк;\n" - "добавляй две пустые строки между абзацами и блоками для улучшения читаемости." - ) + 'добавляй две пустые строки между абзацами и блоками для улучшения читаемости.' + ), } if info.get('reasoning'): json_data['reasoning'] = {} @@ -172,7 +185,7 @@ class Chatgpt_5(Chatgpt): 'Низкий': 'low', 'Средний': 'medium', 'Высокий': 'high', - 'Сверхвысокий': 'xhigh' + 'Сверхвысокий': 'xhigh', } json_data['reasoning']['effort'] = reasoning_data[info['reasoning']] json_data['reasoning']['summary'] = 'auto' @@ -190,36 +203,29 @@ class Chatgpt_5(Chatgpt): info.pop('web_search', None) if info.get('web_search', 'Отключено') != 'Отключено': search_context_size, json_data = self.get_web_search_data( - info.get('web_search', 'Средний контекст'), - model_name, - messages + info.get('web_search', 'Средний контекст'), model_name, messages ) info['web_search'] = search_context_size - if info.get('code_interpreter') is True and model_name in ('gpt-5-mini', 'gpt-5-nano', 'gpt-5', 'gpt-5.1'): - json_data['tools'].append( - { - 'type': 'code_interpreter', - 'container': {'type': 'auto'} - } - ) + if info.get('code_interpreter') is True and model_name in ( + 'gpt-5-mini', + 'gpt-5-nano', + 'gpt-5', + 'gpt-5.1', + ): + json_data['tools'].append({'type': 'code_interpreter', 'container': {'type': 'auto'}}) messages[-1]['content'] += 'the python tool' input_tokens, output_tokens, response = self.call_openai_api( - proxy=proxy, - endpoint='responses', - json_data=json_data + proxy=proxy, endpoint='responses', json_data=json_data ) self.logger.info(f'Input количество токенов для {model_name} - {input_tokens}') self.logger.info(f'Output количество токенов для {model_name} - {output_tokens}') self.logger.info(f'Embedding количество токенов для {model_name} - {embedding_tokens}') - self.logger.info(f'Общее количество токенов для {model_name} - {input_tokens + output_tokens + embedding_tokens}') + self.logger.info( + f'Общее количество токенов для {model_name} - {input_tokens + output_tokens + embedding_tokens}' + ) process_time = timedelta(seconds=time.time() - start_time) self.handle_invoice( - self.neuron_model, - input_tokens, - output_tokens, - model_name, - info, - embedding_tokens + self.neuron_model, input_tokens, output_tokens, model_name, info, embedding_tokens ) msgs = self.save_results([response], process_time, save) return msgs