smart-bot-factory 0.1.2__py3-none-any.whl → 0.1.4__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 +33 -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 +768 -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 +703 -0
  37. smart_bot_factory/core/conversation_manager.py +536 -0
  38. smart_bot_factory/core/decorators.py +230 -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/utm_link_generator.py +106 -0
  55. smart_bot_factory-0.1.4.dist-info/METADATA +126 -0
  56. smart_bot_factory-0.1.4.dist-info/RECORD +59 -0
  57. smart_bot_factory-0.1.4.dist-info/licenses/LICENSE +24 -0
  58. smart_bot_factory-0.1.2.dist-info/METADATA +0 -31
  59. smart_bot_factory-0.1.2.dist-info/RECORD +0 -4
  60. {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.4.dist-info}/WHEEL +0 -0
  61. {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.4.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,427 @@
1
+ # Обновленный prompt_loader.py с поддержкой финальных инструкций
2
+
3
+ import logging
4
+ import aiofiles
5
+ from pathlib import Path
6
+ from typing import List, Dict
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class PromptLoader:
11
+ """Класс для загрузки промптов из локального каталога"""
12
+
13
+ def __init__(self, prompts_dir: str):
14
+ self.prompts_dir = Path(prompts_dir)
15
+ self.welcome_file = self.prompts_dir / 'welcome_message.txt'
16
+ self.help_file = self.prompts_dir / 'help_message.txt'
17
+ self.final_instructions_file = self.prompts_dir / 'final_instructions.txt'
18
+
19
+ # Автоматически находим все .txt файлы промптов (кроме специальных)
20
+ all_txt_files = list(self.prompts_dir.glob('*.txt'))
21
+ special_files = {'welcome_message.txt', 'help_message.txt', 'final_instructions.txt'}
22
+ self.prompt_files = [f.name for f in all_txt_files if f.name not in special_files]
23
+
24
+ logger.info(f"Инициализирован загрузчик промптов: {self.prompts_dir}")
25
+ logger.info(f"Найдено файлов промптов: {len(self.prompt_files)}")
26
+ logger.info(f"Файлы промптов: {self.prompt_files}")
27
+
28
+ async def load_system_prompt(self) -> str:
29
+ """
30
+ Загружает и объединяет все файлы промптов в один системный промпт
31
+
32
+ Returns:
33
+ Объединенный системный промпт с инструкциями по JSON
34
+ """
35
+ try:
36
+ prompt_parts = []
37
+
38
+ for filename in self.prompt_files:
39
+ logger.debug(f"Загружаем промпт из {filename}")
40
+ content = await self._load_file(filename)
41
+
42
+ if content:
43
+ # Добавляем заголовок секции
44
+ section_name = self._get_section_name(filename)
45
+ prompt_parts.append(f"\n### {section_name} ###\n")
46
+ prompt_parts.append(content.strip())
47
+ prompt_parts.append("\n")
48
+ else:
49
+ logger.warning(f"Файл {filename} пуст")
50
+
51
+ if not prompt_parts:
52
+ error_msg = "Не удалось загрузить ни одного промпт файла"
53
+ logger.error(error_msg)
54
+ raise ValueError(error_msg)
55
+
56
+ # Добавляем инструкции по JSON метаданным
57
+ json_instructions = self._get_json_instructions()
58
+ prompt_parts.append("\n")
59
+ prompt_parts.append(json_instructions)
60
+
61
+ # Объединяем все части
62
+ full_prompt = "".join(prompt_parts).strip()
63
+
64
+ logger.info(f"Системный промпт загружен успешно ({len(full_prompt)} символов)")
65
+ return full_prompt
66
+
67
+ except Exception as e:
68
+ logger.error(f"Ошибка при загрузке системного промпта: {e}")
69
+ raise
70
+
71
+ async def load_final_instructions(self) -> str:
72
+ """
73
+ Загружает финальные инструкции из final_instructions.txt
74
+
75
+ Returns:
76
+ Финальные инструкции или пустая строка если файла нет
77
+ """
78
+ try:
79
+ logger.debug(f"Загружаем финальные инструкции из {self.final_instructions_file.name}")
80
+
81
+ if not self.final_instructions_file.exists():
82
+ logger.debug(f"Файл {self.final_instructions_file.name} не найден - пропускаем")
83
+ return ""
84
+
85
+ async with aiofiles.open(self.final_instructions_file, 'r', encoding='utf-8') as f:
86
+ content = await f.read()
87
+
88
+ if not content.strip():
89
+ logger.debug(f"Файл {self.final_instructions_file.name} пуст - пропускаем")
90
+ return ""
91
+
92
+ logger.info(f"Финальные инструкции загружены ({len(content)} символов)")
93
+ return content.strip()
94
+
95
+ except Exception as e:
96
+ logger.error(f"Ошибка при загрузке финальных инструкций: {e}")
97
+ # Не прерываем работу - финальные инструкции опциональны
98
+ return ""
99
+
100
+ def _get_json_instructions(self) -> str:
101
+ """Возвращает инструкции по JSON метаданным для ИИ"""
102
+ return """
103
+ ### КРИТИЧЕСКИ ВАЖНЫЕ ИНСТРУКЦИИ ПО JSON МЕТАДАННЫМ ###
104
+
105
+ В КОНЦЕ КАЖДОГО своего ответа ОБЯЗАТЕЛЬНО добавляй служебную информацию в JSON формате:
106
+
107
+ {
108
+ "этап": "introduction|consult|offer|contacts",
109
+ "качество": 1-10,
110
+ "события": [
111
+ {
112
+ "тип": "телефон|консультация|покупка|отказ",
113
+ "инфо": "детали события"
114
+ }
115
+ ],
116
+ "файлы": ["file1.pdf", "file2.mp4"],
117
+ "каталоги": ["каталог1", "каталог2"]
118
+ }
119
+
120
+ ОПИСАНИЕ ЭТАПОВ:
121
+ - introduction: знакомство, сбор базовой информации о клиенте
122
+ - consult: консультирование, ответы на вопросы о конференции
123
+ - offer: предложение тарифов, обработка возражений
124
+ - contacts: получение контактов, завершение сделки
125
+
126
+ СИСТЕМА ОЦЕНКИ КАЧЕСТВА (1-10):
127
+ 1-3: низкий интерес, много возражений, скептически настроен
128
+ 4-6: средний интерес, есть вопросы, обдумывает
129
+ 7-8: высокий интерес, готов к покупке, активно интересуется
130
+ 9-10: горячий лид, предоставил контакты или готов к действию
131
+
132
+ СОБЫТИЯ - добавляй ТОЛЬКО когда происходит что-то из этого:
133
+ - "телефон": пользователь предоставил номер телефона
134
+ - "консультация": пользователь просит живую консультацию по телефону
135
+ - "покупка": пользователь готов купить/записаться на конференцию
136
+ - "отказ": пользователь явно отказывается участвовать
137
+
138
+ ВАЖНО:
139
+ - Добавляй файлы и катологи только в том случае, если они относятся к этому этапу. (Прописаны в самом этапе) Если не относятся - отсылай пустой массив []
140
+
141
+ ПРИМЕРЫ ПРАВИЛЬНОГО ИСПОЛЬЗОВАНИЯ:
142
+
143
+ Пример 1 - обычный диалог:
144
+ "Расскажу подробнее о конференции GrowthMED. Она пройдет 24-25 октября..."
145
+
146
+ {
147
+ "этап": "consult",
148
+ "качество": 6,
149
+ "события": [],
150
+ "файлы": [],
151
+ "каталоги": []
152
+ }
153
+
154
+ Пример 2 - получен телефон:
155
+ "Отлично! Записал ваш номер. Мы перезвоним в течение 10 минут!"
156
+
157
+ {
158
+ "этап": "contacts",
159
+ "качество": 9,
160
+ "события": [
161
+ {
162
+ "тип": "телефон",
163
+ "инфо": "Иван Петров +79219603144"
164
+ }
165
+ ],
166
+ "файлы": [],
167
+ "каталоги": []
168
+ }
169
+
170
+ Пример 3 - отправка презентации:
171
+ "Отправляю вам презентацию о нашей компании и прайс-лист с актуальными ценами."
172
+
173
+ {
174
+ "этап": "offer",
175
+ "качество": 7,
176
+ "события": [
177
+ {
178
+ "тип": "консультация",
179
+ "инфо": "Запросил материалы"
180
+ }
181
+ ],
182
+ "файлы": ["презентация.pdf", "прайс.pdf"],
183
+ "каталоги": []
184
+ }
185
+
186
+ Пример 4 - отправка файлов из каталога:
187
+ "В каталоге 'примеры_работ' вы можете посмотреть наши последние проекты."
188
+
189
+ {
190
+ "этап": "presentation",
191
+ "качество": 8,
192
+ "события": [],
193
+ "файлы": [],
194
+ "каталоги": ["примеры_работ"]
195
+ }
196
+
197
+ Пример 5 - комбинированная отправка:
198
+ "Отправляю вам коммерческое предложение и примеры похожих проектов из нашего портфолио."
199
+
200
+ {
201
+ "этап": "offer",
202
+ "качество": 9,
203
+ "события": [
204
+ {
205
+ "тип": "предложение",
206
+ "инфо": "Отправлено КП"
207
+ }
208
+ ],
209
+ "файлы": ["коммерческое_предложение.pdf"],
210
+ "каталоги": ["портфолио_2023"]
211
+ }
212
+
213
+ ТРЕБОВАНИЯ К JSON:
214
+ - JSON должен быть валидным и находиться в самом конце ответа
215
+ - Всегда используй кавычки для строк
216
+ - Массив "события" может быть пустым []
217
+ - Если событий нет - не добавляй их в массив
218
+ - Качество должно быть числом от 1 до 10
219
+
220
+ ПОМНИ: Этот JSON критически важен для работы системы администрирования и аналитики!
221
+ """
222
+
223
+ async def load_welcome_message(self) -> str:
224
+ """
225
+ Загружает приветственное сообщение из welcome_message.txt
226
+
227
+ Returns:
228
+ Текст приветственного сообщения
229
+ """
230
+ try:
231
+ logger.debug(f"Загружаем приветственное сообщение из {self.welcome_file.name}")
232
+
233
+ if not self.welcome_file.exists():
234
+ error_msg = f"Файл приветствия не найден: {self.welcome_file}"
235
+ logger.error(error_msg)
236
+ raise FileNotFoundError(error_msg)
237
+
238
+ async with aiofiles.open(self.welcome_file, 'r', encoding='utf-8') as f:
239
+ content = await f.read()
240
+
241
+ if not content.strip():
242
+ error_msg = f"Файл приветствия пуст: {self.welcome_file}"
243
+ logger.error(error_msg)
244
+ raise ValueError(error_msg)
245
+
246
+ logger.info(f"Приветственное сообщение загружено ({len(content)} символов)")
247
+ return content.strip()
248
+
249
+ except Exception as e:
250
+ logger.error(f"Ошибка при загрузке приветственного сообщения: {e}")
251
+ raise
252
+
253
+ async def load_help_message(self) -> str:
254
+ """
255
+ Загружает справочное сообщение из help_message.txt
256
+
257
+ Returns:
258
+ Текст справочного сообщения
259
+ """
260
+ try:
261
+ logger.debug(f"Загружаем справочное сообщение из {self.help_file.name}")
262
+
263
+ if self.help_file.exists():
264
+ async with aiofiles.open(self.help_file, 'r', encoding='utf-8') as f:
265
+ content = await f.read()
266
+
267
+ if content.strip():
268
+ logger.info(f"Справочное сообщение загружено ({len(content)} символов)")
269
+ return content.strip()
270
+
271
+ # Fallback если файл не найден или пуст
272
+ logger.warning("Файл help_message.txt не найден или пуст, используем дефолтную справку")
273
+ return "🤖 **Ваш помощник готов к работе!**\n\n**Команды:**\n/start - Начать диалог\n/help - Показать справку\n/status - Проверить статус"
274
+
275
+ except Exception as e:
276
+ logger.error(f"Ошибка при загрузке справочного сообщения: {e}")
277
+ # Возвращаем простую справку в случае ошибки
278
+ return "🤖 Ваш помощник готов к работе! Напишите /start для начала диалога."
279
+
280
+ async def _load_file(self, filename: str) -> str:
281
+ """Загружает содержимое файла из каталога промптов"""
282
+ file_path = self.prompts_dir / filename
283
+
284
+ try:
285
+ if not file_path.exists():
286
+ error_msg = f"Файл промпта не найден: {file_path}"
287
+ logger.error(error_msg)
288
+ raise FileNotFoundError(error_msg)
289
+
290
+ async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
291
+ content = await f.read()
292
+
293
+ if not content.strip():
294
+ logger.warning(f"Файл {filename} пуст")
295
+ return ""
296
+
297
+ logger.debug(f"Загружен файл {filename} ({len(content)} символов)")
298
+ return content
299
+
300
+ except Exception as e:
301
+ logger.error(f"Ошибка чтения файла {file_path}: {e}")
302
+ raise
303
+
304
+ def _get_section_name(self, filename: str) -> str:
305
+ """Получает название секции по имени файла"""
306
+ name_mapping = {
307
+ 'system_prompt.txt': 'СИСТЕМНЫЙ ПРОМПТ',
308
+ 'sales_context.txt': 'КОНТЕКСТ ПРОДАЖ',
309
+ 'product_info.txt': 'ИНФОРМАЦИЯ О ПРОДУКТЕ',
310
+ 'objection_handling.txt': 'ОБРАБОТКА ВОЗРАЖЕНИЙ',
311
+ '1sales_context.txt': 'КОНТЕКСТ ПРОДАЖ',
312
+ '2product_info.txt': 'ИНФОРМАЦИЯ О ПРОДУКТЕ',
313
+ '3objection_handling.txt': 'ОБРАБОТКА ВОЗРАЖЕНИЙ',
314
+ 'final_instructions.txt': 'ФИНАЛЬНЫЕ ИНСТРУКЦИИ' # 🆕
315
+ }
316
+
317
+ return name_mapping.get(filename, filename.replace('.txt', '').upper())
318
+
319
+ async def reload_prompts(self) -> str:
320
+ """Перезагружает промпты (для обновления без перезапуска бота)"""
321
+ logger.info("Перезагрузка промптов...")
322
+ return await self.load_system_prompt()
323
+
324
+ async def validate_prompts(self) -> Dict[str, bool]:
325
+ """Проверяет доступность всех файлов промптов и приветственного сообщения"""
326
+ results = {}
327
+
328
+ # Проверяем файлы промптов
329
+ for filename in self.prompt_files:
330
+ file_path = self.prompts_dir / filename
331
+ try:
332
+ if file_path.exists():
333
+ async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
334
+ content = await f.read()
335
+ results[filename] = bool(content.strip() and len(content.strip()) > 10)
336
+ else:
337
+ results[filename] = False
338
+ except Exception:
339
+ results[filename] = False
340
+
341
+ # Проверяем файл приветственного сообщения
342
+ try:
343
+ if self.welcome_file.exists():
344
+ async with aiofiles.open(self.welcome_file, 'r', encoding='utf-8') as f:
345
+ content = await f.read()
346
+ results['welcome_message.txt'] = bool(content.strip() and len(content.strip()) > 5)
347
+ else:
348
+ results['welcome_message.txt'] = False
349
+ except Exception:
350
+ results['welcome_message.txt'] = False
351
+
352
+ # Проверяем файл справки (опционально)
353
+ try:
354
+ if self.help_file.exists():
355
+ async with aiofiles.open(self.help_file, 'r', encoding='utf-8') as f:
356
+ content = await f.read()
357
+ results['help_message.txt'] = bool(content.strip() and len(content.strip()) > 5)
358
+ else:
359
+ results['help_message.txt'] = False # Не критично
360
+ except Exception:
361
+ results['help_message.txt'] = False
362
+
363
+ # 🆕 Проверяем финальные инструкции (опционально)
364
+ try:
365
+ if self.final_instructions_file.exists():
366
+ async with aiofiles.open(self.final_instructions_file, 'r', encoding='utf-8') as f:
367
+ content = await f.read()
368
+ results['final_instructions.txt'] = bool(content.strip() and len(content.strip()) > 5)
369
+ else:
370
+ results['final_instructions.txt'] = False # Не критично - опциональный файл
371
+ except Exception:
372
+ results['final_instructions.txt'] = False
373
+
374
+ return results
375
+
376
+ def get_prompt_info(self) -> Dict[str, any]:
377
+ """Возвращает информацию о конфигурации промптов"""
378
+ return {
379
+ 'prompts_dir': str(self.prompts_dir),
380
+ 'prompt_files': self.prompt_files,
381
+ 'welcome_file': 'welcome_message.txt',
382
+ 'help_file': 'help_message.txt',
383
+ 'final_instructions_file': 'final_instructions.txt', # 🆕
384
+ 'total_files': len(self.prompt_files) + 1, # +1 для welcome message
385
+ 'json_instructions_included': True
386
+ }
387
+
388
+ async def test_json_parsing(self, test_response: str) -> Dict[str, any]:
389
+ """Тестирует парсинг JSON из ответа ИИ (для отладки)"""
390
+ import json
391
+ import re
392
+
393
+ try:
394
+ # Используем тот же алгоритм что и в main.py
395
+ json_pattern = r'\{[^{}]*"этап"[^{}]*\}$'
396
+ match = re.search(json_pattern, test_response.strip())
397
+
398
+ if match:
399
+ json_str = match.group(0)
400
+ response_text = test_response[:match.start()].strip()
401
+
402
+ try:
403
+ metadata = json.loads(json_str)
404
+ return {
405
+ 'success': True,
406
+ 'response_text': response_text,
407
+ 'metadata': metadata,
408
+ 'json_str': json_str
409
+ }
410
+ except json.JSONDecodeError as e:
411
+ return {
412
+ 'success': False,
413
+ 'error': f"JSON decode error: {e}",
414
+ 'json_str': json_str
415
+ }
416
+ else:
417
+ return {
418
+ 'success': False,
419
+ 'error': "JSON pattern not found",
420
+ 'response_text': test_response
421
+ }
422
+
423
+ except Exception as e:
424
+ return {
425
+ 'success': False,
426
+ 'error': f"Parse error: {e}"
427
+ }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Генератор UTM-ссылок для Telegram ботов
4
+ Создает ссылки в формате: @https://t.me/bot?start=source-vk_campaign-summer2025
5
+ """
6
+
7
+ def get_user_input():
8
+ """Получает данные от пользователя через консоль"""
9
+ print("🔗 Генератор UTM-ссылок для Telegram")
10
+ print("=" * 50)
11
+
12
+ # Основные параметры
13
+ bot_username = input("Введите username бота (без @): ").strip()
14
+ if not bot_username:
15
+ print("❌ Username бота обязателен!")
16
+ return None
17
+
18
+ print("\n📊 Введите UTM-метки (нажмите Enter для пропуска):")
19
+
20
+ # UTM параметры (соответствуют полям в базе данных)
21
+ utm_source = input("utm_source (источник): ").strip()
22
+ utm_medium = input("utm_medium (канал): ").strip()
23
+ utm_campaign = input("utm_campaign (кампания): ").strip()
24
+ utm_content = input("utm_content (контент): ").strip()
25
+ utm_term = input("utm_term (ключевое слово): ").strip()
26
+
27
+ return {
28
+ 'bot_username': bot_username,
29
+ 'utm_source': utm_source,
30
+ 'utm_medium': utm_medium,
31
+ 'utm_campaign': utm_campaign,
32
+ 'utm_content': utm_content,
33
+ 'utm_term': utm_term
34
+ }
35
+
36
+ def create_utm_string(utm_data):
37
+ """Создает строку UTM параметров в формате source-vk_campaign-summer2025"""
38
+ utm_parts = []
39
+
40
+ # Маппинг полей базы данных на новый формат (без utm, в нижнем регистре)
41
+ field_mapping = {
42
+ 'utm_source': 'source',
43
+ 'utm_medium': 'medium',
44
+ 'utm_campaign': 'campaign',
45
+ 'utm_content': 'content',
46
+ 'utm_term': 'term'
47
+ }
48
+
49
+ for db_field, utm_field in field_mapping.items():
50
+ value = utm_data.get(db_field)
51
+ if value:
52
+ utm_parts.append(f"{utm_field}-{value}")
53
+
54
+ return "_".join(utm_parts)
55
+
56
+ def generate_telegram_link(bot_username, utm_string):
57
+ """Генерирует полную ссылку на Telegram бота"""
58
+ return f"https://t.me/{bot_username}?start={utm_string}"
59
+
60
+ def check_size_and_validate(utm_string):
61
+ """Проверяет размер строки после start= и валидирует"""
62
+ MAX_SIZE = 64
63
+
64
+ if len(utm_string) > MAX_SIZE:
65
+ return False, f"Строка слишком большая: {len(utm_string)} символов (максимум {MAX_SIZE})"
66
+
67
+ return True, f"Размер OK: {len(utm_string)} символов"
68
+
69
+
70
+ def main():
71
+ """Основная функция"""
72
+ try:
73
+ # Получаем данные от пользователя
74
+ data = get_user_input()
75
+ if not data:
76
+ return
77
+
78
+ # Создаем UTM строку
79
+ utm_string = create_utm_string(data)
80
+
81
+ if not utm_string:
82
+ print("❌ Не указано ни одной UTM-метки!")
83
+ return
84
+
85
+ # Проверяем размер
86
+ is_valid, size_message = check_size_and_validate(utm_string)
87
+
88
+ print(f"\n📏 {size_message}")
89
+
90
+ if not is_valid:
91
+ print("❌ Ссылка превышает максимальный размер!")
92
+ print("💡 Сократите значения UTM-меток или уберите менее важные")
93
+ return
94
+
95
+ # Генерируем и выводим ссылку
96
+ telegram_link = generate_telegram_link(data['bot_username'], utm_string)
97
+
98
+ print(f"\n✅ Сгенерированная ссылка:")
99
+ print(f"🔗 {telegram_link}")
100
+ except KeyboardInterrupt:
101
+ print("\n\n👋 Отменено пользователем")
102
+ except Exception as e:
103
+ print(f"\n❌ Ошибка: {e}")
104
+
105
+ if __name__ == "__main__":
106
+ main()
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: smart-bot-factory
3
+ Version: 0.1.4
4
+ Summary: Библиотека для создания умных чат-ботов
5
+ Author-email: Kopatych <kopatych@example.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: chatbot,cli,openai,supabase,telegram
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Framework :: AsyncIO
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Communications :: Chat
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: aiofiles>=23.0.0
24
+ Requires-Dist: aiogram>=3.4.1
25
+ Requires-Dist: click>=8.0.0
26
+ Requires-Dist: openai>=1.12.0
27
+ Requires-Dist: project-root-finder>=1.9
28
+ Requires-Dist: python-dotenv>=1.0.1
29
+ Requires-Dist: pytz>=2023.3
30
+ Requires-Dist: pyyaml>=6.0.2
31
+ Requires-Dist: supabase>=2.3.4
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Smart Bot Factory
35
+
36
+ Библиотека для создания умных чат-ботов с использованием OpenAI, Telegram и Supabase.
37
+
38
+ ## Установка
39
+
40
+ ```bash
41
+ pip install smart-bot-factory
42
+ ```
43
+
44
+ ## Быстрый старт
45
+
46
+ 1. Создайте нового бота:
47
+ ```bash
48
+ sbf create my-bot
49
+ ```
50
+
51
+ 2. Настройте конфигурацию в `bots/my-bot/.env`
52
+
53
+ 3. Запустите бота:
54
+ ```bash
55
+ sbf run my-bot
56
+ ```
57
+
58
+ ## Возможности
59
+
60
+ - 🤖 Интеграция с OpenAI GPT для умных ответов
61
+ - 📱 Поддержка Telegram Bot API через aiogram
62
+ - 💾 Хранение данных в Supabase
63
+ - 🔄 Система событий и обработчиков
64
+ - ⏰ Планировщик задач
65
+ - 🧪 Встроенная система тестирования
66
+ - 📝 Управление промптами
67
+ - 🛠️ Удобный CLI интерфейс
68
+
69
+ ## CLI команды
70
+
71
+ ```bash
72
+ # Создать нового бота
73
+ sbf create my-bot
74
+
75
+ # Запустить бота
76
+ sbf run my-bot
77
+
78
+ # Показать список ботов
79
+ sbf list
80
+
81
+ # Управление промптами
82
+ sbf prompts my-bot --list
83
+ sbf prompts my-bot --edit welcome_message
84
+ sbf prompts my-bot --add new_prompt
85
+
86
+ # Запустить тесты
87
+ sbf test my-bot
88
+ ```
89
+
90
+ ## Пример использования
91
+
92
+ ```python
93
+ from smart_bot_factory import BotBuilder, event_handler, schedule_task
94
+
95
+ # Обработчик события
96
+ @event_handler("book_appointment", "Запись на прием")
97
+ async def handle_booking(user_id: int, event_data: dict):
98
+ # Логика обработки записи на прием
99
+ return {"status": "success"}
100
+
101
+ # Запланированная задача
102
+ @schedule_task("send_reminder", "Отправка напоминания")
103
+ async def send_reminder(user_id: int, message: str):
104
+ # Логика отправки напоминания
105
+ return {"status": "sent"}
106
+
107
+ # Запуск бота
108
+ async def main():
109
+ bot = BotBuilder("my-bot")
110
+ await bot.build()
111
+ await bot.start()
112
+
113
+ if __name__ == "__main__":
114
+ asyncio.run(main())
115
+ ```
116
+
117
+ ## Требования
118
+
119
+ - Python 3.9+
120
+ - OpenAI API ключ
121
+ - Telegram Bot Token
122
+ - Supabase проект
123
+
124
+ ## Лицензия
125
+
126
+ MIT