@@ -96,6 +96,16 @@ class Chatgpt(SimpleService): 'input': Decimal('0.075'), 'output': Decimal('0.075'), }, + 'gpt-5': { + 'input': Decimal('0.000625'), + 'output': Decimal('0.005'), + 'web_search': { + 'low': Decimal('5'), # 1 call + 'medium': Decimal('5'), # 1 call + 'high': Decimal('5') # 1 call + }, + 'code_interpreter': Decimal('15') + } } TOOLS_TOKEN_COSTS = { @@ -204,7 +214,53 @@ class Chatgpt(SimpleService): self.assert_enough_balance( input_tokens, image_size, model=self.llm.model_name, embedding_tokens=input_embedding_tokens ) - if model_name in ('o3-mini', 'gpt-4.5-preview'): + if model_name == 'gpt-5': + system = chat_history.messages.pop(0) + messages = [ + {'role': 'user' if isinstance(msg, HumanMessage) else 'assistant', 'content': msg.content} + for msg in chat_history.messages + ] + messages.insert(0, {'role': 'system', 'content': system.content}) + messages.insert(0, {'role': 'system', 'content': user_system_prompt}) + json_data = { + 'model': model_name, + 'input': messages, + 'tools': [] + } + if info.get('reasoning'): + json_data['reasoning'] = {} + reasoning_data = { + 'Минимальный': 'minimal', + 'Низкий': 'low', + 'Средний': 'medium ', + 'Высокий': 'high' + } + json_data['reasoning']['effort'] = reasoning_data[info['reasoning']] + json_data['reasoning']['summary'] = 'auto' + if info.get('reasoning') == 'Минимальный': + info.pop('web_search') + info.pop('code_interpreter') + if info.get('web_search', 'Отключено') != 'Отключено': + search_context_size, json_data = self.get_web_search_data( + info.get('web_search', 'Средний контекст'), + model_name, + messages + ) + info['web_search'] = search_context_size + if info.get('code_interpreter') is True: + 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 + ) + elif model_name in ('o3-mini', 'gpt-4.5-preview'): system = chat_history.messages.pop(0) messages = [ {'role': 'user' if isinstance(msg, HumanMessage) else 'assistant', 'content': msg.content} @@ -223,11 +279,6 @@ class Chatgpt(SimpleService): } input_tokens, output_tokens, response = self.call_openai_api(proxy=proxy, endpoint='chat/completions',json_data=json_data) elif info.get('web_search', 'Отключено') != 'Отключено': - search_context_sizes = { - 'Малый контекст': 'low', - 'Средний контекст': 'medium', - 'Большой контекст': 'high' - } if model_name not in ('o1-preview', 'o1-mini'): system = chat_history.messages.pop(0) messages = [ @@ -237,19 +288,12 @@ class Chatgpt(SimpleService): if model_name not in ('o1-preview', 'o1-mini'): messages.insert(0, {'role': 'system', 'content': system.content}) messages.insert(0, {'role': 'system', 'content': user_system_prompt}) - search_context_size = search_context_sizes.get(info.get('web_search', 'Средний контекст')) + search_context_size, json_data = self.get_web_search_data( + info.get('web_search', 'Средний контекст'), + model_name, + messages + ) info['web_search'] = search_context_size - json_data = { - 'model': model_name, - 'input': messages, - 'tools': [ - { - 'type': 'web_search_preview', - 'search_context_size': search_context_size, - 'user_location': {'type': 'approximate', 'country': 'RU'} - } - ] - } input_tokens, output_tokens, response = self.call_openai_api(proxy=proxy, endpoint='responses',json_data=json_data) elif image: response = self.llm.invoke(llm_input) @@ -367,6 +411,7 @@ class Chatgpt(SimpleService): 'gpt-4o-mini': 64_000, 'gpt-4o': 64_000, 'gpt-4.5-preview': 64_000, + 'gpt-5': 200_000, } tokens = 0 history: List[BaseMessage] = [] @@ -431,6 +476,8 @@ class Chatgpt(SimpleService): ) if info.get('web_search', 'Отключено') != 'Отключено': price += self.TOKENS_COST[model]['web_search'].get(info.get('web_search', 'medium')) + if info.get('code_interpreter', False): + price += self.TOKENS_COST[model]['code_interpreter'] if embedding_tokens > 0: price += self.TOOLS_TOKEN_COSTS['text-embedding-3-large']['output'] * embedding_tokens return price.quantize(Decimal('0.1'), rounding='ROUND_UP') @@ -477,6 +524,27 @@ class Chatgpt(SimpleService): return total_tokens + + def get_web_search_data(self, search_size: str, model_name: str, messages: List[Dict[str, any]]): + search_context_sizes = { + 'Малый контекст': 'low', + 'Средний контекст': 'medium', + 'Большой контекст': 'high' + } + search_context_size = search_context_sizes.get(search_size) + json_data = { + 'model': model_name, + 'input': messages, + 'tools': [ + { + 'type': 'web_search_preview', + 'search_context_size': search_context_size, + 'user_location': {'type': 'approximate', 'country': 'RU'} + } + ] + } + return search_context_size, json_data + def get_pdf_data(self, pdf_file: UploadedFile) -> str: """ Extracting text from pdf-file @@ -698,12 +766,18 @@ class Chatgpt(SimpleService): and (data := resp.json()) and data.get('output') and ( - content := data['output'][-1]['content'][0]['text'] + output := data['output'] ) ): input_tokens = resp.json()['usage']['input_tokens'] output_tokens = resp.json()['usage']['output_tokens'] - response = AIMessage(content=content) + content = '' + for o in output: + if o['type'] == 'code_interpreter_call': + content += f'Код: {o['code']}\n\n' + if o['type'] == 'message': + content += o['content'][0]['text'] + response = AIMessage(content=content) return input_tokens, output_tokens, response else: raise Exception('GPT not answer correctly, please retry later')