smart-bot-factory 1.1.1__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.
Files changed (73) hide show
  1. smart_bot_factory/__init__.py +3 -0
  2. smart_bot_factory/admin/__init__.py +18 -0
  3. smart_bot_factory/admin/admin_events.py +1223 -0
  4. smart_bot_factory/admin/admin_logic.py +553 -0
  5. smart_bot_factory/admin/admin_manager.py +156 -0
  6. smart_bot_factory/admin/admin_tester.py +157 -0
  7. smart_bot_factory/admin/timeout_checker.py +547 -0
  8. smart_bot_factory/aiogram_calendar/__init__.py +14 -0
  9. smart_bot_factory/aiogram_calendar/common.py +64 -0
  10. smart_bot_factory/aiogram_calendar/dialog_calendar.py +259 -0
  11. smart_bot_factory/aiogram_calendar/schemas.py +99 -0
  12. smart_bot_factory/aiogram_calendar/simple_calendar.py +224 -0
  13. smart_bot_factory/analytics/analytics_manager.py +414 -0
  14. smart_bot_factory/cli.py +806 -0
  15. smart_bot_factory/config.py +258 -0
  16. smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
  17. smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
  18. smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
  19. smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
  20. smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
  21. smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
  22. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
  23. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
  24. smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
  25. smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +133 -0
  26. smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
  27. smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
  28. smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
  29. 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
  30. smart_bot_factory/core/bot_utils.py +1108 -0
  31. smart_bot_factory/core/conversation_manager.py +653 -0
  32. smart_bot_factory/core/decorators.py +2464 -0
  33. smart_bot_factory/core/message_sender.py +729 -0
  34. smart_bot_factory/core/router.py +347 -0
  35. smart_bot_factory/core/router_manager.py +218 -0
  36. smart_bot_factory/core/states.py +27 -0
  37. smart_bot_factory/creation/__init__.py +7 -0
  38. smart_bot_factory/creation/bot_builder.py +1093 -0
  39. smart_bot_factory/creation/bot_testing.py +1122 -0
  40. smart_bot_factory/dashboard/__init__.py +3 -0
  41. smart_bot_factory/event/__init__.py +7 -0
  42. smart_bot_factory/handlers/handlers.py +2013 -0
  43. smart_bot_factory/integrations/langchain_openai.py +542 -0
  44. smart_bot_factory/integrations/openai_client.py +513 -0
  45. smart_bot_factory/integrations/supabase_client.py +1678 -0
  46. smart_bot_factory/memory/__init__.py +8 -0
  47. smart_bot_factory/memory/memory_manager.py +299 -0
  48. smart_bot_factory/memory/static_memory.py +214 -0
  49. smart_bot_factory/message/__init__.py +56 -0
  50. smart_bot_factory/rag/__init__.py +5 -0
  51. smart_bot_factory/rag/decorators.py +29 -0
  52. smart_bot_factory/rag/router.py +54 -0
  53. smart_bot_factory/rag/templates/__init__.py +3 -0
  54. smart_bot_factory/rag/templates/create_table.sql +7 -0
  55. smart_bot_factory/rag/templates/create_table_and_function_template.py +94 -0
  56. smart_bot_factory/rag/templates/match_function.sql +61 -0
  57. smart_bot_factory/rag/templates/match_services_template.py +82 -0
  58. smart_bot_factory/rag/vectorstore.py +449 -0
  59. smart_bot_factory/router/__init__.py +10 -0
  60. smart_bot_factory/setup_checker.py +512 -0
  61. smart_bot_factory/supabase/__init__.py +7 -0
  62. smart_bot_factory/supabase/client.py +631 -0
  63. smart_bot_factory/utils/__init__.py +11 -0
  64. smart_bot_factory/utils/debug_routing.py +114 -0
  65. smart_bot_factory/utils/prompt_loader.py +529 -0
  66. smart_bot_factory/utils/tool_router.py +68 -0
  67. smart_bot_factory/utils/user_prompt_loader.py +55 -0
  68. smart_bot_factory/utm_link_generator.py +123 -0
  69. smart_bot_factory-1.1.1.dist-info/METADATA +1135 -0
  70. smart_bot_factory-1.1.1.dist-info/RECORD +73 -0
  71. smart_bot_factory-1.1.1.dist-info/WHEEL +4 -0
  72. smart_bot_factory-1.1.1.dist-info/entry_points.txt +2 -0
  73. smart_bot_factory-1.1.1.dist-info/licenses/LICENSE +24 -0
@@ -0,0 +1,156 @@
1
+ import logging
2
+ from typing import Dict, List, Set
3
+
4
+ from aiogram.types import User
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class AdminManager:
10
+ """Управление администраторами бота"""
11
+
12
+ def __init__(self, config, supabase_client):
13
+ self.config = config
14
+ self.supabase = supabase_client
15
+ self.admin_ids: Set[int] = set(config.ADMIN_TELEGRAM_IDS)
16
+ self.admin_modes: Dict[int, bool] = {} # admin_id -> is_in_admin_mode
17
+
18
+ logger.info(f"Инициализирован менеджер админов: {len(self.admin_ids)} админов")
19
+
20
+ async def sync_admins_from_config(self):
21
+ """Синхронизирует админов из конфига с базой данных"""
22
+ if not self.admin_ids:
23
+ logger.warning("Нет админов в конфигурации")
24
+ return
25
+
26
+ try:
27
+ for admin_id in self.admin_ids:
28
+ await self.supabase.sync_admin(
29
+ {
30
+ "telegram_id": admin_id,
31
+ "username": None, # будет обновлено при первом сообщении
32
+ "first_name": None,
33
+ "last_name": None,
34
+ }
35
+ )
36
+
37
+ # Устанавливаем режим администратора по умолчанию
38
+ if admin_id not in self.admin_modes:
39
+ self.admin_modes[admin_id] = True
40
+
41
+ logger.info(f"Синхронизированы админы: {self.admin_ids}")
42
+
43
+ except Exception as e:
44
+ logger.error(f"Ошибка синхронизации админов: {e}")
45
+ raise
46
+
47
+ async def update_admin_info(self, user: User):
48
+ """Обновляет информацию об админе"""
49
+ if not self.is_admin(user.id):
50
+ return
51
+
52
+ try:
53
+ await self.supabase.sync_admin(
54
+ {
55
+ "telegram_id": user.id,
56
+ "username": user.username,
57
+ "first_name": user.first_name,
58
+ "last_name": user.last_name,
59
+ }
60
+ )
61
+
62
+ except Exception as e:
63
+ logger.error(f"Ошибка обновления информации админа {user.id}: {e}")
64
+
65
+ def is_admin(self, telegram_id: int) -> bool:
66
+ """Проверяет, является ли пользователь админом"""
67
+ return telegram_id in self.admin_ids
68
+
69
+ def is_in_admin_mode(self, telegram_id: int) -> bool:
70
+ """Проверяет, находится ли админ в режиме администратора"""
71
+ if not self.is_admin(telegram_id):
72
+ return False
73
+ return self.admin_modes.get(telegram_id, True)
74
+
75
+ def toggle_admin_mode(self, telegram_id: int) -> bool:
76
+ """Переключает режим админа. Возвращает новое состояние"""
77
+ if not self.is_admin(telegram_id):
78
+ return False
79
+
80
+ current_mode = self.admin_modes.get(telegram_id, True)
81
+ new_mode = not current_mode
82
+ self.admin_modes[telegram_id] = new_mode
83
+
84
+ logger.info(
85
+ f"Админ {telegram_id} переключен в режим: {'администратор' if new_mode else 'пользователь'}"
86
+ )
87
+ return new_mode
88
+
89
+ def set_admin_mode(self, telegram_id: int, is_admin_mode: bool):
90
+ """Устанавливает режим админа"""
91
+ if not self.is_admin(telegram_id):
92
+ return
93
+
94
+ self.admin_modes[telegram_id] = is_admin_mode
95
+ logger.info(
96
+ f"Режим админа {telegram_id} установлен: {'администратор' if is_admin_mode else 'пользователь'}"
97
+ )
98
+
99
+ async def get_active_admins(self) -> List[int]:
100
+ """Возвращает список активных админов в режиме администратора"""
101
+ return [
102
+ admin_id for admin_id in self.admin_ids if self.is_in_admin_mode(admin_id)
103
+ ]
104
+
105
+ def get_admin_mode_text(self, telegram_id: int) -> str:
106
+ """Возвращает текстовое описание режима админа"""
107
+ if not self.is_admin(telegram_id):
108
+ return "Не администратор"
109
+
110
+ if self.is_in_admin_mode(telegram_id):
111
+ return "👑 Режим администратора"
112
+ else:
113
+ return "👤 Режим пользователя"
114
+
115
+ def format_admin_status(self, telegram_id: int) -> str:
116
+ """Форматирует статус админа для отображения"""
117
+ if not self.is_admin(telegram_id):
118
+ return ""
119
+
120
+ mode = "👑 АДМИН" if self.is_in_admin_mode(telegram_id) else "👤 ПОЛЬЗ"
121
+ return f"[{mode}]"
122
+
123
+ async def notify_admins(self, message: str, exclude_admin: int = None):
124
+ """Отправляет уведомление всем активным админам"""
125
+ from ..handlers.handlers import get_global_var
126
+ bot = get_global_var("bot")
127
+
128
+ active_admins = await self.get_active_admins()
129
+
130
+ if exclude_admin:
131
+ active_admins = [aid for aid in active_admins if aid != exclude_admin]
132
+
133
+ sent_count = 0
134
+ for admin_id in active_admins:
135
+ try:
136
+ await bot.send_message(admin_id, message, parse_mode="Markdown")
137
+ sent_count += 1
138
+ except Exception as e:
139
+ logger.error(f"Ошибка отправки уведомления админу {admin_id}: {e}")
140
+
141
+ logger.info(f"Уведомление отправлено {sent_count} админам")
142
+ return sent_count
143
+
144
+ def get_stats(self) -> Dict[str, any]:
145
+ """Возвращает статистику по админам"""
146
+ total_admins = len(self.admin_ids)
147
+ active_admins = len(
148
+ [aid for aid in self.admin_ids if self.is_in_admin_mode(aid)]
149
+ )
150
+
151
+ return {
152
+ "total_admins": total_admins,
153
+ "active_admins": active_admins,
154
+ "admin_ids": list(self.admin_ids),
155
+ "modes": dict(self.admin_modes),
156
+ }
@@ -0,0 +1,157 @@
1
+ """
2
+ Утилита для тестирования системы администрирования бота
3
+ """
4
+
5
+ import asyncio
6
+ import logging
7
+ import sys
8
+
9
+ from ..analytics.analytics_manager import AnalyticsManager
10
+ from ..config import Config
11
+ from ..core.conversation_manager import ConversationManager
12
+ from ..integrations.supabase_client import SupabaseClient
13
+ from .admin_manager import AdminManager
14
+ from .timeout_checker import setup_bot_environment
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ async def test_admin_system(bot_name: str = "growthmed-october-24") -> bool:
20
+ """
21
+ Тестирует систему администрирования бота
22
+
23
+ Args:
24
+ bot_name: Имя бота для тестирования
25
+
26
+ Returns:
27
+ bool: True если все тесты пройдены, False если найдены проблемы
28
+ """
29
+ logger.info(f"🚀 Тестирование системы администрирования: {bot_name}")
30
+ logger.info(f"🤖 Bot ID будет автоопределен как: {bot_name}\n")
31
+
32
+ # Настраиваем окружение для бота (автоматически устанавливает BOT_ID)
33
+ config_dir = setup_bot_environment(bot_name)
34
+ if not config_dir:
35
+ return False
36
+
37
+ # Инициализируем конфигурацию
38
+ config = Config()
39
+ logger.info("📋 Конфигурация:")
40
+ logger.info(f" BOT_ID: {config.BOT_ID}")
41
+ logger.info(
42
+ f" ADMIN_SESSION_TIMEOUT_MINUTES: {config.ADMIN_SESSION_TIMEOUT_MINUTES}"
43
+ )
44
+ logger.info(f" PROMT_FILES_DIR: {config.PROMT_FILES_DIR}")
45
+ logger.info(f" Найдено промпт-файлов: {len(config.PROMPT_FILES)}")
46
+ logger.info("")
47
+
48
+ # Проверяем админов
49
+ if not config.ADMIN_TELEGRAM_IDS:
50
+ logger.warning("⚠️ Админы не настроены (ADMIN_TELEGRAM_IDS пуст)")
51
+ return False
52
+
53
+ logger.info(f"👑 Админы: {config.ADMIN_TELEGRAM_IDS}")
54
+ logger.info("")
55
+
56
+ # Проверяем подключение к БД
57
+ try:
58
+ supabase_client = SupabaseClient(config.SUPABASE_URL, config.SUPABASE_KEY)
59
+ await supabase_client.initialize()
60
+ logger.info("✅ Подключение к Supabase успешно")
61
+
62
+ # Проверяем таблицы
63
+ tables = [
64
+ "sales_admins",
65
+ "admin_user_conversations",
66
+ "session_events",
67
+ "sales_chat_sessions",
68
+ "sales_messages",
69
+ ]
70
+
71
+ logger.info("\n📊 Проверка таблиц:")
72
+ for table in tables:
73
+ try:
74
+ supabase_client.client.table(table).select("*").limit(1).execute()
75
+ logger.info(f" ✅ {table}")
76
+ except Exception as e:
77
+ logger.error(f" ❌ {table}: {e}")
78
+ return False
79
+
80
+ # Проверяем AdminManager
81
+ admin_manager = AdminManager(config, supabase_client)
82
+ logger.info(
83
+ f"\n👑 AdminManager инициализирован ({len(admin_manager.admin_ids)} админов)"
84
+ )
85
+
86
+ # Проверяем ConversationManager
87
+ conversation_manager = ConversationManager(supabase_client, admin_manager)
88
+ logger.info("✅ ConversationManager инициализирован")
89
+
90
+ # Проверяем AnalyticsManager
91
+ analytics_manager = AnalyticsManager(supabase_client)
92
+
93
+ # Тестируем получение статистики
94
+ await analytics_manager.get_funnel_stats(1)
95
+ logger.info("✅ AnalyticsManager работает")
96
+
97
+ # Проверяем активные диалоги
98
+ conversations = await conversation_manager.get_active_conversations()
99
+ logger.info(f"\n💬 Активные диалоги: {len(conversations)}")
100
+
101
+ if conversations:
102
+ for conv in conversations:
103
+ logger.info(
104
+ f" • Диалог {conv['id']}: админ {conv['admin_id']} с пользователем {conv['user_id']}"
105
+ )
106
+ else:
107
+ logger.info(" Нет активных диалогов")
108
+ logger.info(" 💡 Создайте диалог командой /чат USER_ID для тестирования")
109
+
110
+ # Проверяем форматирование диалогов
111
+ if conversations:
112
+ formatted = conversation_manager.format_active_conversations(conversations)
113
+ logger.info("\n📝 Форматирование диалогов:")
114
+ logger.info(formatted)
115
+
116
+ logger.info("\n✅ Админская система готова к работе")
117
+ return True
118
+
119
+ except Exception as e:
120
+ logger.error(f"❌ Ошибка тестирования: {e}")
121
+ logger.exception("Стек ошибки:")
122
+ return False
123
+
124
+
125
+ def main():
126
+ """Точка входа для запуска из командной строки"""
127
+ # Настройка логирования
128
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
129
+
130
+ logger.info("🔍 Утилита тестирования админской системы")
131
+ logger.info("Использование:")
132
+ logger.info(" python -m smart_bot_factory.admin_tester [bot_name]")
133
+ logger.info(" python -m smart_bot_factory.admin_tester growthmed-october-24")
134
+ logger.info("")
135
+
136
+ if len(sys.argv) > 1 and sys.argv[1] in ["-h", "--help", "help"]:
137
+ return
138
+
139
+ # Определяем какого бота тестировать
140
+ bot_name = "growthmed-october-24" # по умолчанию
141
+ if len(sys.argv) > 1:
142
+ bot_name = sys.argv[1]
143
+
144
+ try:
145
+ success = asyncio.run(test_admin_system(bot_name))
146
+ if not success:
147
+ sys.exit(1)
148
+ except KeyboardInterrupt:
149
+ logger.info("\n⏹️ Прервано пользователем")
150
+ except Exception as e:
151
+ logger.error(f"\n💥 Критическая ошибка: {e}")
152
+ logger.exception("Стек ошибки:")
153
+ sys.exit(1)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ main()