diff --git a/requirements.txt b/requirements.txt index 9380374..41e8980 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ mysqlclient qrcode django-environ pillow +openai diff --git a/restoran_max_bot/ai_agent/api_common.py b/restoran_max_bot/ai_agent/api_common.py index 3c92509..d61534f 100644 --- a/restoran_max_bot/ai_agent/api_common.py +++ b/restoran_max_bot/ai_agent/api_common.py @@ -1,23 +1,43 @@ # api_common.py import os import json +import re from datetime import datetime -from typing import Dict, Any, List -from max_bot.models import Client, ProductCategory, Product, Qr +from typing import Dict, Any, List, Optional +from django.core.cache import cache +from max_bot.models import Client, ProductCategory, Product, Qr, Partner, Integration +from restoran_max_bot import settings -# Кеш для базового промта _BASE_PROMPT_CACHE = None +GLOBAL_ERROR_MSG = '⚠️ К сожалению, я не могу ответить на этот вопрос.' + +AI_AGENT_REGISTRY = { + 'yandexai': { + 'slug': 'yandexai', + 'module': 'api_yandex_ai', + 'function': 'yandex_chat_structured', + 'required_settings': ['yandex_folder_id'], + 'default_model': 'yandexgpt', + }, + 'deepseek': { + 'slug': 'deepseek', + 'module': 'api_deepseek_ai', + 'function': 'deepseek_chat_structured', + 'required_settings': [], + 'default_model': 'deepseek-chat', + }, +} def _log_dialogue(session_id: str, role: str, content: str, log_file: str = None) -> None: - """ - Записывает сообщение диалога в файл лога. - """ + if role.upper() == 'SYSTEM' and not getattr(settings, 'LOG_SYSTEM_PROMPT', False): + return + if log_file is None: base_dir = os.path.dirname(os.path.abspath(__file__)) log_dir = os.path.join(base_dir, 'logs') os.makedirs(log_dir, exist_ok=True) - log_file = os.path.join(log_dir, 'ai_dialogs.log') # общий лог для всех AI + log_file = os.path.join(log_dir, 'ai_dialogs.log') timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') log_entry = f"[{timestamp}] [{role.upper()}] [{session_id}]: {content}\n" @@ -31,7 +51,6 @@ def _log_dialogue(session_id: str, role: str, content: str, log_file: str = None def _load_base_prompt() -> str: - """Загружает базовый текст системного промта из файла.""" global _BASE_PROMPT_CACHE if _BASE_PROMPT_CACHE is not None: return _BASE_PROMPT_CACHE @@ -53,7 +72,11 @@ def _load_base_prompt() -> str: def get_system_prompt(client: Client) -> str: - """Генерирует системный промпт на основе данных клиента.""" + cache_key = f"system_prompt_{client.id}" + cached = cache.get(cache_key) + if cached: + return cached + prompt = _load_base_prompt() qr = Qr.objects.filter(client=client).first() @@ -89,34 +112,157 @@ def get_system_prompt(client: Client) -> str: prompt += "\nМеню не загружено.\n" prompt += """ - При ответах на вопросы о меню используй только те блюда, которые перечислены выше. - Если клиент спрашивает о блюде, которого нет в списке, честно скажи об этом и предложи посмотреть другие позиции. - Всегда помни, что ты должен возвращать только JSON, без лишнего текста вне JSON. - """ + При ответах на вопросы о меню используй только те блюда, которые перечислены выше. + Если клиент спрашивает о блюде, которого нет в списке, честно скажи об этом и предложи посмотреть другие позиции. + Всегда помни, что ты должен возвращать только JSON, без лишнего текста вне JSON. + """ + cache.set(cache_key, prompt, 300) return prompt def parse_ai_response(assistant_content: str) -> Dict[str, Any]: - """ - Универсальный парсер для ответа AI (ожидается JSON с полями intent, message, entities, status). - Возвращает словарь с гарантированными ключами. - """ + content = re.sub(r'```(?:json)?\s*', '', assistant_content) + content = re.sub(r'\s*```', '', content) + content = content.strip() + try: - parsed = json.loads(assistant_content) + parsed = json.loads(content) required = ["intent", "message", "entities", "status"] if all(k in parsed for k in required): return parsed else: return { "intent": "general", - "message": assistant_content, + "message": content, "entities": {}, "status": "complete" } except json.JSONDecodeError: return { "intent": "general", - "message": assistant_content, + "message": content, + "entities": {}, + "status": "complete" + } + + +def get_ai_agent(client: Client) -> Dict[str, Optional[str]]: + for agent_slug, config in AI_AGENT_REGISTRY.items(): + partner = Partner.objects.filter(slug=agent_slug).first() + if not partner: + continue + integration = Integration.objects.filter( + client=client, + partner=partner, + status=True + ).first() + if integration: + try: + settings = json.loads(integration.setting) if integration.setting else {} + except json.JSONDecodeError: + settings = {} + + required_settings = config.get('required_settings', []) + missing = [f for f in required_settings if f not in settings] + if missing: + _log_dialogue(str(client.id), 'ERROR', + f"AI agent {agent_slug} missing settings: {missing}") + continue + + if not integration.token: + _log_dialogue(str(client.id), 'ERROR', + f"AI agent {agent_slug} missing token") + continue + + result = { + 'ai_agent': agent_slug, + 'token': integration.token, + 'client_prompt': settings.get('promt'), + 'settings': settings, + } + if agent_slug == 'yandexai' and 'yandex_folder_id' in settings: + result['folder_id'] = settings['yandex_folder_id'] + return result + + return { + 'ai_agent': None, + 'token': None, + 'client_prompt': None, + 'settings': None, + 'folder_id': None, + } + + +def call_ai_agent(client: Client, session_id: str, user_query: str) -> Dict[str, Any]: + agent_info = get_ai_agent(client) + ai_agent = agent_info.get('ai_agent') + if not ai_agent: + return { + "intent": "general", + "message": GLOBAL_ERROR_MSG, + "entities": {}, + "status": "complete" + } + + config = AI_AGENT_REGISTRY.get(ai_agent) + if not config: + return { + "intent": "general", + "message": f"Агент {ai_agent} не зарегистрирован.", + "entities": {}, + "status": "complete" + } + + try: + module = __import__(f"ai_agent.{config['module']}", fromlist=[config['function']]) + func = getattr(module, config['function']) + except (ImportError, AttributeError) as e: + error_msg = f"Не удалось загрузить функцию для агента {ai_agent}: {e}" + _log_dialogue(session_id, 'ERROR', error_msg) + return { + "intent": "general", + "message": GLOBAL_ERROR_MSG, + "entities": {}, + "status": "complete" + } + + system_prompt = get_system_prompt(client) + client_prompt = agent_info.get('client_prompt') + if client_prompt: + system_prompt += f"\n\nДополнительная информация о ресторане:\n{client_prompt}" + + kwargs = { + 'session_id': session_id, + 'system_prompt': system_prompt, + 'user_query': user_query, + 'api_token': agent_info.get('token'), + } + + if ai_agent == 'yandexai': + folder_id = agent_info.get('folder_id') + if not folder_id: + return { + "intent": "general", + "message": "Ошибка конфигурации Yandex: не указан folder_id.", + "entities": {}, + "status": "complete" + } + kwargs['folder_id'] = folder_id + # Можно задать модель из настроек или использовать default + model = agent_info.get('settings', {}).get('model', config.get('default_model', 'yandexgpt')) + kwargs['model'] = model + + # Логируем вызов + _log_dialogue(session_id, 'DEBUG', f"Calling {ai_agent} with kwargs: {kwargs}") + + try: + response = func(**kwargs) + return response + except Exception as e: + _log_dialogue(session_id, 'ERROR', f"Error calling {ai_agent}: {e}") + return { + "intent": "general", + "message": GLOBAL_ERROR_MSG, "entities": {}, "status": "complete" - } \ No newline at end of file + } diff --git a/restoran_max_bot/ai_agent/api_deepseek_ai.py b/restoran_max_bot/ai_agent/api_deepseek_ai.py index 3c7d1bb..18cbbc3 100644 --- a/restoran_max_bot/ai_agent/api_deepseek_ai.py +++ b/restoran_max_bot/ai_agent/api_deepseek_ai.py @@ -1,7 +1,7 @@ # api_deepseek_ai.py import requests from typing import Dict, Any, List -from api_common import _log_dialogue, get_system_prompt, parse_ai_response +from ai_agent.api_common import _log_dialogue, parse_ai_response, GLOBAL_ERROR_MSG # Хранилище контекстов для DeepSeek _contexts: Dict[str, List[Dict[str, str]]] = {} @@ -55,7 +55,7 @@ def deepseek_chat_structured( except requests.exceptions.HTTPError as e: if e.response.status_code == 402: - user_message = "⚠️ К сожалению, я сейчас не могу отвечать на эти вопросы, попробуйте позже." + user_message = GLOBAL_ERROR_MSG _log_dialogue(session_id, 'ERROR', f"Payment Required (402): {e}") return { "intent": "general", @@ -64,7 +64,7 @@ def deepseek_chat_structured( "status": "complete" } else: - error_msg = "⚠️ Произошла ошибка при обращении к серверу. Попробуйте позже." + error_msg = GLOBAL_ERROR_MSG _log_dialogue(session_id, 'ERROR', f"HTTP error: {e}") return { "intent": "general", @@ -73,7 +73,7 @@ def deepseek_chat_structured( "status": "complete" } except Exception as e: - error_msg = "⚠️ Извините, произошла ошибка. Попробуйте позже." + error_msg = GLOBAL_ERROR_MSG _log_dialogue(session_id, 'ERROR', f"DeepSeek error: {e}") return { "intent": "general", diff --git a/restoran_max_bot/ai_agent/api_yandex_ai.py b/restoran_max_bot/ai_agent/api_yandex_ai.py index 692794d..ec055c4 100644 --- a/restoran_max_bot/ai_agent/api_yandex_ai.py +++ b/restoran_max_bot/ai_agent/api_yandex_ai.py @@ -1,20 +1,19 @@ # api_yandex_ai.py from typing import Dict, Any, List from openai import OpenAI -from api_common import _log_dialogue, get_system_prompt, parse_ai_response +from ai_agent.api_common import _log_dialogue, parse_ai_response, GLOBAL_ERROR_MSG -# Хранилище контекстов для Yandex _contexts: Dict[str, List[Dict[str, str]]] = {} def yandex_chat_structured( session_id: str, - api_key: str, + api_token: str, folder_id: str, system_prompt: str, user_query: str, - model: str = "yandexgpt", - max_tokens: int = 1000, + model: str = "yandexgpt", # можно "yandexgpt-lite" + max_tokens: int = 500, temperature: float = 0.3, ) -> Dict[str, Any]: """ @@ -30,18 +29,21 @@ def yandex_chat_structured( _contexts[session_id].append({"role": "user", "content": user_query}) try: + if not folder_id: + raise ValueError("folder_id is empty") + client = OpenAI( - api_key=api_key, + api_key=api_token, base_url="https://ai.api.cloud.yandex.net/v1", project=folder_id, ) + # Убираем response_format – он может вызывать ошибку парсинга URI модели response = client.chat.completions.create( model=model, messages=_contexts[session_id], max_tokens=max_tokens, temperature=temperature, - response_format={"type": "json_object"} ) assistant_content = response.choices[0].message.content @@ -52,11 +54,11 @@ def yandex_chat_structured( return parse_ai_response(assistant_content) except Exception as e: - error_msg = "⚠️ Извините, произошла ошибка при обращении к Yandex GPT. Попробуйте позже." + error_msg = GLOBAL_ERROR_MSG _log_dialogue(session_id, 'ERROR', f"Yandex GPT error: {e}") return { "intent": "general", "message": error_msg, "entities": {}, "status": "complete" - } \ No newline at end of file + } diff --git a/restoran_max_bot/max_bot/views.py b/restoran_max_bot/max_bot/views.py index 331922a..f20441f 100644 --- a/restoran_max_bot/max_bot/views.py +++ b/restoran_max_bot/max_bot/views.py @@ -50,21 +50,9 @@ def api_decorator(func): settings_max = json.loads(integration.setting) settings_max['token'] = integration.token - - # проверка на интеграцию с максом - partner = Partner.objects.filter(slug='deepseek').first() - integration = Integration.objects.filter(client=client, partner=partner, status=True).first() - - if not integration: - settings_deepseek = {'token': None, 'deepseek_system_prompt': None} - else: - deepseek_system_prompt = json.loads(integration.setting).get('system_prompt', None) - settings_deepseek = {'token': integration.token, 'deepseek_system_prompt': deepseek_system_prompt} - kwargs['client'] = client kwargs['integration'] = integration kwargs['settings_max'] = settings_max - kwargs['settings_deepseek'] = settings_deepseek return func(*args, **kwargs) return wrapper_api_decorator @@ -76,7 +64,6 @@ def api_start_max_v1(request, token, **kwargs): data = json.loads(request.body.decode('utf-8')) client = kwargs['client'] settings_max = kwargs['settings_max'] - settings_deepseek = kwargs['settings_deepseek'] if DEBUG: print(data) @@ -87,12 +74,10 @@ def api_start_max_v1(request, token, **kwargs): # получение сообщения из бота if data['update_type'] == 'message_created': - bot_message(client=client, message=data, settings_max=settings_max, settings_deepseek=settings_deepseek, - message_type='message_created') + bot_message(client=client, message=data, settings_max=settings_max, message_type='message_created') if data['update_type'] == 'message_callback': - bot_message(client=client, message=data, settings_max=settings_max, settings_deepseek=settings_deepseek, - message_type='message_callback') + bot_message(client=client, message=data, settings_max=settings_max, message_type='message_callback') # start - запуск бота if data['update_type'] == 'bot_started': @@ -106,7 +91,7 @@ def api_start_max_v1(request, token, **kwargs): return JsonResponse(rt, status=200) -#https://maxbot.telefon-ip.ru/max/iiko/webhook/71232b71-dacc-4586-95d0-0f352d9d09c3 +# https://maxbot.telefon-ip.ru/max/iiko/webhook/71232b71-dacc-4586-95d0-0f352d9d09c3 @csrf_exempt def iiko_webhook(request: WSGIRequest, token): rt = {'success': False, 'data': ''} diff --git a/restoran_max_bot/restoran_max_bot/bot_message.py b/restoran_max_bot/restoran_max_bot/bot_message.py index 3236128..617e1a0 100644 --- a/restoran_max_bot/restoran_max_bot/bot_message.py +++ b/restoran_max_bot/restoran_max_bot/bot_message.py @@ -1,8 +1,9 @@ +# bot_message.py import re - -from ai_agent.api_deepseek_ai import get_system_prompt, deepseek_chat_structured -from max_bot.max_api import * +import json import qrcode +from ai_agent.api_common import get_system_prompt, get_ai_agent, call_ai_agent +from max_bot.max_api import * from restoran_max_bot.bot_started import check_registration from restoran_max_bot.common import * from restoran_max_bot.iiko_api import customer_info, customer_create, customer_wallet @@ -11,24 +12,24 @@ from restoran_max_bot.settings import STATICFILES_DIRS from restoran_max_bot.utils import has_key, is_json -# отправка сообщения в группу администраторв по бронированию -def send_booking_to_crm(chat_id, date, time, people, contact): +# ---------- вспомогательные функции ---------- +def send_booking_to_crm(chat_id, date, time, people, phone): + # TODO: реализовать отправку в CRM return True def send_contact_to_admin(chat_id, phone, contact_method, question, preferred_time, contact): + # TODO: реализовать отправку администратору return True -# получение информации по интеграции с терминалом ikko, rkeeper +# ---------- получение бонусов ---------- def get_bonus(client: Client, phone: str, default_bonus: float, contact: Contact): integration = common_get_integration(client=client) bonus = 0 date = contact.field1 - if len(date) < 2: date = '0' + date - month = contact.field2 if len(month) < 2: month = '0' + month @@ -39,23 +40,16 @@ def get_bonus(client: Client, phone: str, default_bonus: float, contact: Contact customerinfo = customer_info(config['token'], phone, config['id_org']) if not customerinfo: birthday = f"1990-{month}-{date} 00:00:00.000" - dt = customer_create(api_key=config['token'], phone=phone, name=contact.name, organization_id=config['id_org'], birthday=birthday) - dt = customer_info(config['token'], phone, config['id_org']) - customer_wallet(api_key=config['token'], iiko_wallet_id=dt['walletBalances'][0]['id'], customer_id=dt['id'], organization_id=config['id_org'], bonus=default_bonus) - bonus = default_bonus - else: - bonus = customerinfo['walletBalances'] - bonus = bonus[0]['balance'] + bonus = customerinfo['walletBalances'][0]['balance'] - # http://192.168.9.186:8890/docs if integration.partner.slug == 'rkeeper': config = json.loads(integration.setting) rs = rkiper_customer_info(rkiper_server=config['url'], rkiper_token=config['token'], phone=phone) @@ -72,26 +66,24 @@ def get_bonus(client: Client, phone: str, default_bonus: float, contact: Contact return bonus -# получение вложения в сообщениях для их обработки (регистрация по номеру) +# ---------- получение вложений ---------- def get_attachments(message: dict): - chat_id = message['message']['recipient']['chat_id'] if 'attachments' in message['message']['body']: if 'vcf_info' in message['message']['body']['attachments'][0]['payload']: - # Регулярное выражение: ищем всё после 'TEL;TYPE=cell:' до \r или конца строки match = re.search(r'TEL;TYPE=cell:(\d+)', message['message']['body']['attachments'][0]['payload']['vcf_info']) if match: phone_number = match.group(1) return {'attachments_type': 'vcf_info', 'data': phone_number} - return {'attachments_type': False, 'data': ''} -def bot_message(client: Client, message: dict, settings_max: dict, settings_deepseek: dict, message_type): +# ---------- основной обработчик ---------- +def bot_message(client: Client, message: dict, settings_max: dict, message_type): chat_id = message['message']['recipient']['chat_id'] attachments = get_attachments(message=message) - # регистрируем по номеру телефона выдаем соответствующий контент + # регистрация по vcf if attachments['attachments_type'] == 'vcf_info': common_set_contact(client=client, uid_client=chat_id, name=message['message']['sender']['name'], phone=attachments['data']) @@ -104,10 +96,11 @@ def bot_message(client: Client, message: dict, settings_max: dict, settings_deep data = None if message_type == 'message_created': data = common_get_data(client=client, key=str(message['message']['body']['text']).lower()) - - if message_type == 'message_callback': + elif message_type == 'message_callback': payload = json.loads(message['callback']['payload']) data = common_get_data(client=client, key=str(payload['data']).lower()) + + # ---------- обработка стандартных команд (меню, бонусы и т.п.) ---------- if data: for dt in data: if dt.title == '##bonus##': @@ -116,28 +109,26 @@ def bot_message(client: Client, message: dict, settings_max: dict, settings_deep url = f"https://maxbot.telefon-ip.ru/static/client_qr/{contact.phone}.png" maxbot_send_img_message(chat_id=chat_id, max_token=settings_max['token'], img=url, message='QR-код для начисления, списания бонусов.') - bonus = get_bonus(client=client, phone=contact.phone, default_bonus=float(dt.price), contact=contact) maxbot_send_text_message(chat_id=chat_id, max_token=settings_max['token'], message=f"💰 Ваш бонусный баланс: {bonus} руб") - if dt.title == '##feedback##': - maxbot_send_feedback_button(client=client, message='👇', chat_id=chat_id, max_token=settings_max['token']) + elif dt.title == '##feedback##': + maxbot_send_feedback_button(client=client, message='👇', chat_id=chat_id, + max_token=settings_max['token']) return True - if dt.title == '##booking##': + elif dt.title == '##booking##': maxbot_send_booking_count_people_button(client=client, message='👇', chat_id=chat_id, max_token=settings_max['token']) return True - # для более сложных функций + # сложные кнопки if is_json(dt.title): - data = json.loads(dt.title) - if 'type' in dt.title: - if data['type'] == 'linkbutton': - maxbot_send_link_button(text=dt.descr, title_button=data['button'], link=dt.url, - chat_id=chat_id, - max_token=settings_max['token']) + data_json = json.loads(dt.title) + if 'type' in dt.title and data_json.get('type') == 'linkbutton': + maxbot_send_link_button(text=dt.descr, title_button=data_json['button'], link=dt.url, + chat_id=chat_id, max_token=settings_max['token']) if dt.img: url = f"https://cdn.telefon-ip.ru/{dt.img}?thumb=600" @@ -149,86 +140,79 @@ def bot_message(client: Client, message: dict, settings_max: dict, settings_deep if dt.url and not is_json(dt.title): maxbot_send_text_message(chat_id=chat_id, max_token=settings_max['token'], message=dt.url) - # отправка меню maxbot_send_menu_button(chat_id=chat_id, max_token=settings_max['token'], message='👇 Выберите раздел', client=client) - else: - # =========================== обработка сообщения через ИИ =========================== - if settings_deepseek.get('token', False): - text = message['message']['body']['text'] - # Получаем системный промт из настроек - system_prompt = get_system_prompt(client) - if settings_deepseek.get('deepseek_system_prompt', False): - system_prompt = (system_prompt + "\n Дополнительная информация:\n" + - settings_deepseek.get('deepseek_system_prompt')) - - # Отправляем запрос в DeepSeek - response = deepseek_chat_structured( - session_id=str(chat_id), - api_token=settings_deepseek.get('token'), - system_prompt=system_prompt, - user_query=text - ) - - intent = response.get('intent') - message_text = response.get('message', '') - entities = response.get('entities', {}) - status = response.get('status', 'complete') - - # Если общий вопрос — просто отвечаем - if intent == 'general': - maxbot_send_text_message(chat_id, settings_max['token'], message_text) - elif intent == 'booking': - if status == 'need_more_info': - # Отправляем уточняющий вопрос - maxbot_send_text_message(chat_id, settings_max['token'], message_text) - elif status == 'complete': - # Все данные собраны — передаём в CRM - date = entities.get('date') - time = entities.get('time') - people = entities.get('people') - phone = entities.get('phone') - if date and time and people: - # Вызываем функцию для отправки в CRM - success = send_booking_to_crm(chat_id, date, time, people, phone) - if success: - confirm_msg = f"✅ Бронирование на {date} в {time} на {people} чел. принято! " \ - f"Администратор свяжется с вами для уточнения вопросов" - else: - confirm_msg = "❌ Не удалось забронировать. Попробуйте позже." - maxbot_send_text_message(chat_id, settings_max['token'], confirm_msg) - else: - maxbot_send_text_message(chat_id, settings_max['token'], "⚠️ Не хватает данных для бронирования.") + return True + + # ---------- обработка через AI ---------- + # Проверяем, есть ли AI-агент у клиента + ai_agent = get_ai_agent(client) + if not ai_agent.get('ai_agent'): + maxbot_send_menu_button(chat_id=chat_id, max_token=settings_max['token'], + message='👇 Выберите раздел', client=client) + return True + + # Вызываем AI-агента через универсальную функцию + response = call_ai_agent( + client=client, + session_id=str(chat_id), + user_query=message['message']['body']['text'] + ) + + # ---------- обработка ответа AI ---------- + intent = response.get('intent') + message_text = response.get('message', '') + entities = response.get('entities', {}) + status = response.get('status', 'complete') + + if intent == 'general': + maxbot_send_text_message(chat_id, settings_max['token'], message_text) + + elif intent == 'booking': + if status == 'need_more_info': + maxbot_send_text_message(chat_id, settings_max['token'], message_text) + elif status == 'complete': + date = entities.get('date') + time = entities.get('time') + people = entities.get('people') + phone = entities.get('phone') + if date and time and people: + success = send_booking_to_crm(chat_id, date, time, people, phone) + if success: + confirm_msg = f"✅ Бронирование на {date} в {time} на {people} чел. принято! Администратор свяжется с вами." else: - maxbot_send_text_message(chat_id, settings_max['token'], message_text) - elif intent == 'contact_admin': - if status == 'need_more_info': - # Отправляем уточняющий вопрос - maxbot_send_text_message(chat_id, settings_max['token'], message_text) - elif status == 'complete': - # Все данные собраны — передаём администратору - phone = entities.get('phone') - contact_method = entities.get('contact_method') - question = entities.get('question', '') - preferred_time = entities.get('preferred_time', '') - if phone and contact_method: - # Вызываем функцию отправки уведомления администратору - success = send_contact_to_admin(chat_id, phone, contact_method, question, preferred_time, contact) - if success: - confirm_msg = f"✅ Ваш запрос передан администратору. Способ связи: {contact_method}. Скоро с вами свяжутся." - else: - confirm_msg = "❌ Не удалось отправить запрос. Попробуйте позже." - maxbot_send_text_message(chat_id, settings_max['token'], confirm_msg) - else: - maxbot_send_text_message(chat_id, settings_max['token'], - "⚠️ Не хватает данных для связи с администратором.") + confirm_msg = "❌ Не удалось забронировать. Попробуйте позже." + maxbot_send_text_message(chat_id, settings_max['token'], confirm_msg) + else: + maxbot_send_text_message(chat_id, settings_max['token'], "⚠️ Не хватает данных для бронирования.") + else: + maxbot_send_text_message(chat_id, settings_max['token'], message_text) + + elif intent == 'contact_admin': + if status == 'need_more_info': + maxbot_send_text_message(chat_id, settings_max['token'], message_text) + elif status == 'complete': + phone = entities.get('phone') + contact_method = entities.get('contact_method') + question = entities.get('question', '') + preferred_time = entities.get('preferred_time', '') + if phone and contact_method: + success = send_contact_to_admin(chat_id, phone, contact_method, question, preferred_time, contact) + if success: + confirm_msg = f"✅ Ваш запрос передан администратору. Способ связи: {contact_method}. Скоро с вами свяжутся." else: - maxbot_send_text_message(chat_id, settings_max['token'], message_text) + confirm_msg = "❌ Не удалось отправить запрос. Попробуйте позже." + maxbot_send_text_message(chat_id, settings_max['token'], confirm_msg) else: - maxbot_send_text_message(chat_id, settings_max['token'], message_text) + maxbot_send_text_message(chat_id, settings_max['token'], + "⚠️ Не хватает данных для связи с администратором.") + else: + maxbot_send_text_message(chat_id, settings_max['token'], message_text) - # После ответа отправляем меню (если нужно) - maxbot_send_menu_button(chat_id=chat_id, max_token=settings_max['token'], - message='👇 Выберите раздел', client=client) + else: + maxbot_send_text_message(chat_id, settings_max['token'], message_text) + # всегда отправляем меню после ответа + maxbot_send_menu_button(chat_id=chat_id, max_token=settings_max['token'], + message='👇 Выберите раздел', client=client) return True diff --git a/restoran_max_bot/restoran_max_bot/settings.py b/restoran_max_bot/restoran_max_bot/settings.py index cfd6dcb..94ba147 100644 --- a/restoran_max_bot/restoran_max_bot/settings.py +++ b/restoran_max_bot/restoran_max_bot/settings.py @@ -125,3 +125,5 @@ STATICFILES_DIRS = [(os.path.join(BASE_DIR, "static"))] # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +LOG_SYSTEM_PROMPT = False # False - не логировать системный промт