smart-bot-factory 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of smart-bot-factory might be problematic. Click here for more details.

Files changed (61) hide show
  1. smart_bot_factory/__init__.py +51 -0
  2. smart_bot_factory/admin/__init__.py +16 -0
  3. smart_bot_factory/admin/admin_logic.py +430 -0
  4. smart_bot_factory/admin/admin_manager.py +141 -0
  5. smart_bot_factory/admin/admin_migration.sql +136 -0
  6. smart_bot_factory/admin/admin_tester.py +151 -0
  7. smart_bot_factory/admin/timeout_checker.py +499 -0
  8. smart_bot_factory/analytics/__init__.py +7 -0
  9. smart_bot_factory/analytics/analytics_manager.py +355 -0
  10. smart_bot_factory/cli.py +642 -0
  11. smart_bot_factory/config.py +235 -0
  12. smart_bot_factory/configs/growthmed-helper/env_example.txt +1 -0
  13. smart_bot_factory/configs/growthmed-helper/prompts/1sales_context.txt +9 -0
  14. smart_bot_factory/configs/growthmed-helper/prompts/2product_info.txt +582 -0
  15. smart_bot_factory/configs/growthmed-helper/prompts/3objection_handling.txt +66 -0
  16. smart_bot_factory/configs/growthmed-helper/prompts/final_instructions.txt +232 -0
  17. smart_bot_factory/configs/growthmed-helper/prompts/help_message.txt +28 -0
  18. smart_bot_factory/configs/growthmed-helper/prompts/welcome_message.txt +7 -0
  19. smart_bot_factory/configs/growthmed-helper/welcome_file/welcome_file_msg.txt +16 -0
  20. smart_bot_factory/configs/growthmed-helper/welcome_file//342/225/250/320/267/342/225/250/342/225/241/342/225/250/342/225/221 /342/225/250/342/225/227/342/225/250/342/225/225/342/225/244/320/221/342/225/244/320/222 /342/225/250/342/224/220/342/225/250/342/225/233 152/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/225/225 323/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/224/244/342/225/250/342/225/227/342/225/244/320/237 /342/225/250/342/225/235/342/225/250/342/225/241/342/225/250/342/224/244/342/225/250/342/225/225/342/225/244/320/226/342/225/250/342/225/225/342/225/250/342/225/234/342/225/244/320/233.pdf +0 -0
  21. smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
  22. smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
  23. smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
  24. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
  25. smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
  26. smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
  27. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
  28. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
  29. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
  30. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +66 -0
  31. smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
  32. smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
  33. smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
  34. smart_bot_factory/configs/growthmed-october-24/welcome_file//342/225/250/320/267/342/225/250/342/225/241/342/225/250/342/225/221 /342/225/250/342/225/227/342/225/250/342/225/225/342/225/244/320/221/342/225/244/320/222 /342/225/250/342/224/220/342/225/250/342/225/233 152/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/225/225 323/342/225/250/320/264/342/225/250/320/247 /342/225/250/342/224/244/342/225/250/342/225/227/342/225/244/320/237 /342/225/250/342/225/235/342/225/250/342/225/241/342/225/250/342/224/244/342/225/250/342/225/225/342/225/244/320/226/342/225/250/342/225/225/342/225/250/342/225/234/342/225/244/320/233.pdf +0 -0
  35. smart_bot_factory/core/__init__.py +22 -0
  36. smart_bot_factory/core/bot_utils.py +693 -0
  37. smart_bot_factory/core/conversation_manager.py +536 -0
  38. smart_bot_factory/core/decorators.py +229 -0
  39. smart_bot_factory/core/message_sender.py +249 -0
  40. smart_bot_factory/core/states.py +14 -0
  41. smart_bot_factory/creation/__init__.py +8 -0
  42. smart_bot_factory/creation/bot_builder.py +329 -0
  43. smart_bot_factory/creation/bot_testing.py +986 -0
  44. smart_bot_factory/database/database_structure.sql +57 -0
  45. smart_bot_factory/database/schema.sql +1094 -0
  46. smart_bot_factory/handlers/handlers.py +583 -0
  47. smart_bot_factory/integrations/__init__.py +9 -0
  48. smart_bot_factory/integrations/openai_client.py +435 -0
  49. smart_bot_factory/integrations/supabase_client.py +592 -0
  50. smart_bot_factory/setup_checker.py +476 -0
  51. smart_bot_factory/utils/__init__.py +9 -0
  52. smart_bot_factory/utils/debug_routing.py +103 -0
  53. smart_bot_factory/utils/prompt_loader.py +427 -0
  54. smart_bot_factory/uv.lock +2004 -0
  55. smart_bot_factory-0.1.3.dist-info/METADATA +126 -0
  56. smart_bot_factory-0.1.3.dist-info/RECORD +59 -0
  57. smart_bot_factory-0.1.3.dist-info/licenses/LICENSE +24 -0
  58. smart_bot_factory-0.1.1.dist-info/METADATA +0 -31
  59. smart_bot_factory-0.1.1.dist-info/RECORD +0 -4
  60. {smart_bot_factory-0.1.1.dist-info → smart_bot_factory-0.1.3.dist-info}/WHEEL +0 -0
  61. {smart_bot_factory-0.1.1.dist-info → smart_bot_factory-0.1.3.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,229 @@
1
+ """
2
+ Декораторы для обработчиков событий и временных задач
3
+ """
4
+
5
+ import asyncio
6
+ import logging
7
+ from typing import Callable, Any, Dict, Optional
8
+ from datetime import datetime, timedelta
9
+ from functools import wraps
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Глобальный реестр обработчиков событий
14
+ _event_handlers: Dict[str, Callable] = {}
15
+ _scheduled_tasks: Dict[str, Dict[str, Any]] = {}
16
+
17
+ def event_handler(event_type: str, description: str = ""):
18
+ """
19
+ Декоратор для регистрации обработчика события
20
+
21
+ Args:
22
+ event_type: Тип события (например, 'appointment_booking', 'phone_collection')
23
+ description: Описание что делает обработчик (для добавления в промпт)
24
+
25
+ Example:
26
+ @event_handler("appointment_booking", "Записывает пользователя на прием")
27
+ async def book_appointment(user_id: int, appointment_data: dict):
28
+ # Логика записи на прием
29
+ return {"status": "success", "appointment_id": "123"}
30
+ """
31
+ def decorator(func: Callable) -> Callable:
32
+ _event_handlers[event_type] = {
33
+ 'handler': func,
34
+ 'description': description,
35
+ 'name': func.__name__
36
+ }
37
+
38
+ logger.info(f"📝 Зарегистрирован обработчик события '{event_type}': {func.__name__}")
39
+
40
+ @wraps(func)
41
+ async def wrapper(*args, **kwargs):
42
+ try:
43
+ logger.info(f"🔧 Выполняем обработчик события '{event_type}'")
44
+ result = await func(*args, **kwargs)
45
+ logger.info(f"✅ Обработчик '{event_type}' выполнен успешно")
46
+ return result
47
+ except Exception as e:
48
+ logger.error(f"❌ Ошибка в обработчике '{event_type}': {e}")
49
+ raise
50
+
51
+ return wrapper
52
+ return decorator
53
+
54
+ def schedule_task(task_name: str, description: str = ""):
55
+ """
56
+ Декоратор для регистрации задачи, которую можно запланировать на время
57
+
58
+ Args:
59
+ task_name: Название задачи (например, 'send_reminder', 'follow_up')
60
+ description: Описание задачи (для добавления в промпт)
61
+
62
+ Example:
63
+ @schedule_task("send_reminder", "Отправляет напоминание пользователю")
64
+ async def send_reminder(user_id: int, message: str):
65
+ # Логика отправки напоминания
66
+ return {"status": "sent"}
67
+ """
68
+ def decorator(func: Callable) -> Callable:
69
+ _scheduled_tasks[task_name] = {
70
+ 'handler': func,
71
+ 'description': description,
72
+ 'name': func.__name__
73
+ }
74
+
75
+ logger.info(f"⏰ Зарегистрирована задача '{task_name}': {func.__name__}")
76
+
77
+ @wraps(func)
78
+ async def wrapper(*args, **kwargs):
79
+ try:
80
+ logger.info(f"⏰ Выполняем запланированную задачу '{task_name}'")
81
+ result = await func(*args, **kwargs)
82
+ logger.info(f"✅ Задача '{task_name}' выполнена успешно")
83
+ return result
84
+ except Exception as e:
85
+ logger.error(f"❌ Ошибка в задаче '{task_name}': {e}")
86
+ raise
87
+
88
+ return wrapper
89
+ return decorator
90
+
91
+ def get_event_handlers() -> Dict[str, Dict[str, Any]]:
92
+ """Возвращает все зарегистрированные обработчики событий"""
93
+ return _event_handlers.copy()
94
+
95
+ def get_scheduled_tasks() -> Dict[str, Dict[str, Any]]:
96
+ """Возвращает все зарегистрированные задачи"""
97
+ return _scheduled_tasks.copy()
98
+
99
+ def get_handlers_for_prompt() -> str:
100
+ """
101
+ Возвращает описание всех обработчиков для добавления в промпт
102
+ """
103
+ if not _event_handlers and not _scheduled_tasks:
104
+ return ""
105
+
106
+ prompt_parts = []
107
+
108
+ if _event_handlers:
109
+ prompt_parts.append("ДОСТУПНЫЕ ОБРАБОТЧИКИ СОБЫТИЙ:")
110
+ for event_type, handler_info in _event_handlers.items():
111
+ prompt_parts.append(f"- {event_type}: {handler_info['description']}")
112
+
113
+ if _scheduled_tasks:
114
+ prompt_parts.append("\nДОСТУПНЫЕ ЗАДАЧИ ДЛЯ ПЛАНИРОВАНИЯ:")
115
+ for task_name, task_info in _scheduled_tasks.items():
116
+ prompt_parts.append(f"- {task_name}: {task_info['description']}")
117
+
118
+ return "\n".join(prompt_parts)
119
+
120
+ async def execute_event_handler(event_type: str, *args, **kwargs) -> Any:
121
+ """Выполняет обработчик события по типу"""
122
+ if event_type not in _event_handlers:
123
+ raise ValueError(f"Обработчик события '{event_type}' не найден")
124
+
125
+ handler_info = _event_handlers[event_type]
126
+ return await handler_info['handler'](*args, **kwargs)
127
+
128
+ async def execute_scheduled_task(task_name: str, *args, **kwargs) -> Any:
129
+ """Выполняет запланированную задачу по имени"""
130
+ if task_name not in _scheduled_tasks:
131
+ raise ValueError(f"Задача '{task_name}' не найдена")
132
+
133
+ task_info = _scheduled_tasks[task_name]
134
+ return await task_info['handler'](*args, **kwargs)
135
+
136
+ async def schedule_task_for_later(task_name: str, delay_seconds: int, *args, **kwargs):
137
+ """
138
+ Планирует выполнение задачи через указанное время
139
+
140
+ Args:
141
+ task_name: Название задачи
142
+ delay_seconds: Задержка в секундах
143
+ *args, **kwargs: Аргументы для задачи
144
+ """
145
+ if task_name not in _scheduled_tasks:
146
+ raise ValueError(f"Задача '{task_name}' не найдена")
147
+
148
+ logger.info(f"⏰ Планируем задачу '{task_name}' через {delay_seconds} секунд")
149
+
150
+ async def delayed_task():
151
+ await asyncio.sleep(delay_seconds)
152
+ await execute_scheduled_task(task_name, *args, **kwargs)
153
+
154
+ # Запускаем задачу в фоне
155
+ asyncio.create_task(delayed_task())
156
+
157
+ return {
158
+ "status": "scheduled",
159
+ "task_name": task_name,
160
+ "delay_seconds": delay_seconds,
161
+ "scheduled_at": datetime.now().isoformat()
162
+ }
163
+
164
+ async def execute_scheduled_task_from_event(user_id: int, task_name: str, event_info: str):
165
+ """
166
+ Выполняет запланированную задачу на основе события от ИИ
167
+
168
+ Args:
169
+ user_id: ID пользователя
170
+ task_name: Название задачи
171
+ event_info: Информация от ИИ (содержит время и сообщение)
172
+ """
173
+ if task_name not in _scheduled_tasks:
174
+ raise ValueError(f"Задача '{task_name}' не найдена")
175
+
176
+ # Парсим event_info для извлечения времени и сообщения
177
+ # Формат: "через 2 часа: напомнить о приеме"
178
+ try:
179
+ if ":" in event_info:
180
+ time_part, message = event_info.split(":", 1)
181
+ time_part = time_part.strip()
182
+ message = message.strip()
183
+ else:
184
+ time_part = event_info
185
+ message = "Напоминание"
186
+
187
+ # Парсим время
188
+ delay_seconds = _parse_time_to_seconds(time_part)
189
+
190
+ # Планируем задачу
191
+ result = await schedule_task_for_later(task_name, delay_seconds, user_id, message)
192
+
193
+ return result
194
+
195
+ except Exception as e:
196
+ logger.error(f"Ошибка парсинга времени из event_info '{event_info}': {e}")
197
+ # Fallback - планируем через 1 час
198
+ return await schedule_task_for_later(task_name, 3600, user_id, event_info)
199
+
200
+ def _parse_time_to_seconds(time_str: str) -> int:
201
+ """
202
+ Парсит строку времени в секунды
203
+ Поддерживает форматы:
204
+ - "через 2 часа"
205
+ - "через 30 минут"
206
+ - "через 1 день"
207
+ - "через 2 часа 30 минут"
208
+ """
209
+ import re
210
+
211
+ time_str = time_str.lower().strip()
212
+
213
+ # Ищем часы
214
+ hours_match = re.search(r'(\d+)\s*час', time_str)
215
+ hours = int(hours_match.group(1)) if hours_match else 0
216
+
217
+ # Ищем минуты
218
+ minutes_match = re.search(r'(\d+)\s*минут', time_str)
219
+ minutes = int(minutes_match.group(1)) if minutes_match else 0
220
+
221
+ # Ищем дни
222
+ days_match = re.search(r'(\d+)\s*дн', time_str)
223
+ days = int(days_match.group(1)) if days_match else 0
224
+
225
+ # Конвертируем в секунды
226
+ total_seconds = (days * 24 * 3600) + (hours * 3600) + (minutes * 60)
227
+
228
+ # Минимум 1 минута
229
+ return max(total_seconds, 60)
@@ -0,0 +1,249 @@
1
+ """
2
+ Функции для отправки сообщений через ИИ и от человека
3
+ """
4
+
5
+ import logging
6
+ import time
7
+ from datetime import datetime
8
+ from typing import Dict, Any, Optional
9
+ import pytz
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ async def send_message_by_ai(
14
+ user_id: int,
15
+ message_text: str,
16
+ session_id: str = None
17
+ ) -> Dict[str, Any]:
18
+ """
19
+ Отправляет сообщение пользователю через ИИ (копирует логику process_user_message)
20
+
21
+ Args:
22
+ user_id: ID пользователя в Telegram
23
+ message_text: Текст сообщения для обработки ИИ
24
+ session_id: ID сессии чата (если не указан, будет использована активная сессия)
25
+
26
+ Returns:
27
+ Результат отправки
28
+ """
29
+ try:
30
+ # Импортируем необходимые компоненты
31
+ from .bot_utils import parse_ai_response, process_events
32
+ from .config import Config
33
+ from .openai_client import OpenAIClient
34
+ from .supabase_client import SupabaseClient
35
+ from .prompt_loader import PromptLoader
36
+ from aiogram import Bot
37
+
38
+ # Получаем компоненты из глобального контекста
39
+ from .handlers import get_global_var
40
+ bot = get_global_var('bot')
41
+ supabase_client = get_global_var('supabase_client')
42
+ openai_client = get_global_var('openai_client')
43
+ config = get_global_var('config')
44
+ prompt_loader = get_global_var('prompt_loader')
45
+
46
+ # Если session_id не указан, получаем активную сессию пользователя
47
+ if not session_id:
48
+ session_info = await supabase_client.get_active_session(user_id)
49
+ if not session_info:
50
+ return {
51
+ "status": "error",
52
+ "error": "Активная сессия не найдена",
53
+ "user_id": user_id
54
+ }
55
+ session_id = session_info['id']
56
+
57
+ # Загружаем системный промпт
58
+ try:
59
+ system_prompt = await prompt_loader.load_system_prompt()
60
+ logger.info(f"✅ Системный промпт загружен ({len(system_prompt)} символов)")
61
+ except Exception as e:
62
+ logger.error(f"❌ Ошибка загрузки системного промпта: {e}")
63
+ return {
64
+ "status": "error",
65
+ "error": "Не удалось загрузить системный промпт",
66
+ "user_id": user_id
67
+ }
68
+
69
+ # Сохраняем сообщение пользователя в БД
70
+ await supabase_client.add_message(
71
+ session_id=session_id,
72
+ role='user',
73
+ content=message_text,
74
+ message_type='text'
75
+ )
76
+ logger.info(f"✅ Сообщение пользователя сохранено в БД")
77
+
78
+ # Получаем историю сообщений
79
+ chat_history = await supabase_client.get_chat_history(session_id, limit=config.MAX_CONTEXT_MESSAGES)
80
+ logger.info(f"📚 Загружена история: {len(chat_history)} сообщений")
81
+
82
+ # Добавляем текущее время
83
+ moscow_tz = pytz.timezone('Europe/Moscow')
84
+ current_time = datetime.now(moscow_tz)
85
+ time_info = current_time.strftime('%H:%M, %d.%m.%Y, %A')
86
+
87
+ # Модифицируем системный промпт, добавляя время
88
+ system_prompt_with_time = f"""
89
+ {system_prompt}
90
+
91
+ ТЕКУЩЕЕ ВРЕМЯ: {time_info} (московское время)
92
+ """
93
+
94
+ # Формируем контекст для OpenAI
95
+ messages = [{"role": "system", "content": system_prompt_with_time}]
96
+
97
+ for msg in chat_history[-config.MAX_CONTEXT_MESSAGES:]:
98
+ messages.append({
99
+ "role": msg['role'],
100
+ "content": msg['content']
101
+ })
102
+
103
+ # Добавляем финальные инструкции
104
+ final_instructions = await prompt_loader.load_final_instructions()
105
+ if final_instructions:
106
+ messages.append({"role": "system", "content": final_instructions})
107
+ logger.info(f"🎯 Добавлены финальные инструкции")
108
+
109
+ logger.info(f"📝 Контекст сформирован: {len(messages)} сообщений")
110
+
111
+ # Отправляем действие "печатает"
112
+ await bot.send_chat_action(user_id, "typing")
113
+
114
+ # Получаем ответ от ИИ
115
+ start_time = time.time()
116
+ ai_response = await openai_client.get_completion(messages)
117
+ processing_time = int((time.time() - start_time) * 1000)
118
+
119
+ logger.info(f"🤖 OpenAI ответил за {processing_time}мс")
120
+
121
+ # Обрабатываем ответ
122
+ tokens_used = 0
123
+ ai_metadata = {}
124
+ response_text = ""
125
+
126
+ if not ai_response or not ai_response.strip():
127
+ logger.warning(f"❌ OpenAI вернул пустой ответ!")
128
+ fallback_message = "Извините, произошла техническая ошибка. Попробуйте переформулировать вопрос."
129
+ ai_response = fallback_message
130
+ response_text = fallback_message
131
+ else:
132
+ tokens_used = openai_client.estimate_tokens(ai_response)
133
+ response_text, ai_metadata = parse_ai_response(ai_response)
134
+
135
+ if not ai_metadata:
136
+ response_text = ai_response
137
+ ai_metadata = {}
138
+ elif not response_text.strip():
139
+ response_text = ai_response
140
+
141
+ # Обновляем этап сессии и качество лида
142
+ if ai_metadata:
143
+ stage = ai_metadata.get('этап')
144
+ quality = ai_metadata.get('качество')
145
+
146
+ if stage or quality is not None:
147
+ await supabase_client.update_session_stage(session_id, stage, quality)
148
+ logger.info(f"✅ Этап и качество обновлены в БД")
149
+
150
+ # Обрабатываем события
151
+ events = ai_metadata.get('события', [])
152
+ if events:
153
+ logger.info(f"🔔 Обрабатываем {len(events)} событий")
154
+ await process_events(session_id, events, user_id)
155
+
156
+ # Сохраняем ответ ассистента
157
+ await supabase_client.add_message(
158
+ session_id=session_id,
159
+ role='assistant',
160
+ content=response_text,
161
+ message_type='text',
162
+ tokens_used=tokens_used,
163
+ processing_time_ms=processing_time,
164
+ ai_metadata=ai_metadata
165
+ )
166
+
167
+ # Определяем финальный ответ
168
+ if config.DEBUG_MODE:
169
+ final_response = ai_response
170
+ else:
171
+ final_response = response_text
172
+
173
+ # Отправляем ответ пользователю напрямую через бота
174
+ await bot.send_message(
175
+ chat_id=user_id,
176
+ text=final_response
177
+ )
178
+
179
+ return {
180
+ "status": "success",
181
+ "user_id": user_id,
182
+ "response_text": response_text,
183
+ "tokens_used": tokens_used,
184
+ "processing_time_ms": processing_time,
185
+ "events_processed": len(events) if events else 0
186
+ }
187
+
188
+ except Exception as e:
189
+ logger.error(f"❌ Ошибка в send_message_by_ai: {e}")
190
+ return {
191
+ "status": "error",
192
+ "error": str(e),
193
+ "user_id": user_id
194
+ }
195
+
196
+ async def send_message_by_human(
197
+ user_id: int,
198
+ message_text: str,
199
+ session_id: Optional[str] = None
200
+ ) -> Dict[str, Any]:
201
+ """
202
+ Отправляет сообщение пользователю от имени человека (готовый текст)
203
+
204
+ Args:
205
+ user_id: ID пользователя в Telegram
206
+ message_text: Готовый текст сообщения
207
+ session_id: ID сессии (опционально, для сохранения в БД)
208
+
209
+ Returns:
210
+ Результат отправки
211
+ """
212
+ try:
213
+ # Импортируем необходимые компоненты
214
+ from .handlers import get_global_var
215
+ bot = get_global_var('bot')
216
+ supabase_client = get_global_var('supabase_client')
217
+
218
+ # Отправляем сообщение пользователю
219
+ message = await bot.send_message(
220
+ chat_id=user_id,
221
+ text=message_text
222
+ )
223
+
224
+ # Если указана сессия, сохраняем сообщение в БД
225
+ if session_id:
226
+ await supabase_client.add_message(
227
+ session_id=session_id,
228
+ role='assistant',
229
+ content=message_text,
230
+ message_type='text',
231
+ metadata={'sent_by_human': True}
232
+ )
233
+ logger.info(f"💾 Сообщение от человека сохранено в БД")
234
+
235
+ return {
236
+ "status": "success",
237
+ "user_id": user_id,
238
+ "message_id": message.message_id,
239
+ "message_text": message_text,
240
+ "saved_to_db": bool(session_id)
241
+ }
242
+
243
+ except Exception as e:
244
+ logger.error(f"❌ Ошибка в send_message_by_human: {e}")
245
+ return {
246
+ "status": "error",
247
+ "error": str(e),
248
+ "user_id": user_id
249
+ }
@@ -0,0 +1,14 @@
1
+ """
2
+ Состояния FSM для бота
3
+ """
4
+
5
+ from aiogram.fsm.state import State, StatesGroup
6
+
7
+ class UserStates(StatesGroup):
8
+ waiting_for_message = State()
9
+ admin_chat = State() # пользователь в диалоге с админом
10
+
11
+ class AdminStates(StatesGroup):
12
+ admin_mode = State()
13
+ in_conversation = State()
14
+
@@ -0,0 +1,8 @@
1
+ """
2
+ Creation модули smart_bot_factory
3
+ """
4
+
5
+ from ..creation.bot_builder import BotBuilder
6
+ from ..creation.bot_testing import main as bot_testing_main
7
+
8
+ __all__ = ['BotBuilder', 'bot_testing_main']