smart-bot-factory 0.2.10__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of smart-bot-factory might be problematic. Click here for more details.
- smart_bot_factory/cli.py +35 -64
- smart_bot_factory/core/bot_utils.py +69 -21
- smart_bot_factory/core/decorators.py +377 -143
- smart_bot_factory/core/router.py +7 -4
- smart_bot_factory/creation/bot_builder.py +47 -14
- smart_bot_factory/handlers/handlers.py +5 -4
- smart_bot_factory/router/__init__.py +2 -3
- smart_bot_factory-0.3.1.dist-info/METADATA +905 -0
- {smart_bot_factory-0.2.10.dist-info → smart_bot_factory-0.3.1.dist-info}/RECORD +12 -13
- smart_bot_factory/core/telegram_router.py +0 -58
- smart_bot_factory-0.2.10.dist-info/METADATA +0 -789
- {smart_bot_factory-0.2.10.dist-info → smart_bot_factory-0.3.1.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.2.10.dist-info → smart_bot_factory-0.3.1.dist-info}/entry_points.txt +0 -0
- {smart_bot_factory-0.2.10.dist-info → smart_bot_factory-0.3.1.dist-info}/licenses/LICENSE +0 -0
smart_bot_factory/cli.py
CHANGED
|
@@ -408,88 +408,59 @@ def list_bots_in_bots_folder() -> list:
|
|
|
408
408
|
|
|
409
409
|
def create_bot_template(bot_id: str) -> str:
|
|
410
410
|
"""Создает шаблон основного файла бота"""
|
|
411
|
-
return f'''
|
|
411
|
+
return f'''"""
|
|
412
|
+
{bot_id.replace("-", " ").title()} Bot - Умный Telegram бот на Smart Bot Factory
|
|
413
|
+
"""
|
|
412
414
|
|
|
413
|
-
|
|
414
|
-
from smart_bot_factory.
|
|
415
|
-
from smart_bot_factory.
|
|
415
|
+
import asyncio
|
|
416
|
+
from smart_bot_factory.router import EventRouter
|
|
417
|
+
from smart_bot_factory.message import send_message_by_human
|
|
416
418
|
from smart_bot_factory.creation import BotBuilder
|
|
417
419
|
|
|
418
|
-
#
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
supabase_client = SupabaseClient("{bot_id}")
|
|
420
|
+
# Инициализация
|
|
421
|
+
event_router = EventRouter("{bot_id}")
|
|
422
|
+
bot_builder = BotBuilder("{bot_id}")
|
|
422
423
|
|
|
423
424
|
# =============================================================================
|
|
424
425
|
# ОБРАБОТЧИКИ СОБЫТИЙ
|
|
425
426
|
# =============================================================================
|
|
426
427
|
|
|
427
|
-
@
|
|
428
|
-
async def
|
|
429
|
-
"""
|
|
430
|
-
|
|
431
|
-
await send_message_by_human(
|
|
432
|
-
user_id=user_id,
|
|
433
|
-
message_text=f"✅ Событие обработано! Данные: {{event_data}}"
|
|
434
|
-
)
|
|
428
|
+
@event_router.event_handler("collect_contact", notify=True, once_only=True)
|
|
429
|
+
async def handle_contact(user_id: int, contact_data: str):
|
|
430
|
+
"""
|
|
431
|
+
Обрабатывает получение контактных данных
|
|
435
432
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
"message": "Событие обработано"
|
|
439
|
-
}}
|
|
440
|
-
|
|
441
|
-
# =============================================================================
|
|
442
|
-
# ВРЕМЕННЫЕ ЗАДАЧИ ДЛЯ ОДНОГО ПОЛЬЗОВАТЕЛЯ
|
|
443
|
-
# =============================================================================
|
|
444
|
-
|
|
445
|
-
@router.schedule_task("send_reminder", delay="1h")
|
|
446
|
-
async def send_user_reminder(user_id: int, reminder_text: str):
|
|
447
|
-
"""Отправляет напоминание пользователю"""
|
|
433
|
+
ИИ создает: {{"тип": "collect_contact", "инфо": "+79001234567"}}
|
|
434
|
+
"""
|
|
448
435
|
await send_message_by_human(
|
|
449
436
|
user_id=user_id,
|
|
450
|
-
message_text=f"
|
|
437
|
+
message_text=f"✅ Спасибо! Ваши данные сохранены: {{contact_data}}"
|
|
451
438
|
)
|
|
452
439
|
|
|
453
|
-
return {{
|
|
454
|
-
"status": "reminder_sent",
|
|
455
|
-
"message": f"Напоминание отправлено пользователю {{user_id}}"
|
|
456
|
-
}}
|
|
457
|
-
|
|
458
|
-
# =============================================================================
|
|
459
|
-
# ГЛОБАЛЬНЫЕ ОБРАБОТЧИКИ (для всех пользователей)
|
|
460
|
-
# =============================================================================
|
|
461
|
-
|
|
462
|
-
@router.global_handler("mass_notification", delay="1h", notify=True)
|
|
463
|
-
async def send_global_announcement(announcement_text: str):
|
|
464
|
-
"""Отправляет анонс всем пользователям бота"""
|
|
465
|
-
|
|
466
|
-
await send_message_to_users_by_stage(
|
|
467
|
-
stage="introduction",
|
|
468
|
-
message_text=announcement_text,
|
|
469
|
-
bot_id="{bot_id}"
|
|
470
|
-
)
|
|
440
|
+
return {{"status": "success", "contact": contact_data}}
|
|
471
441
|
|
|
472
442
|
# =============================================================================
|
|
473
|
-
#
|
|
443
|
+
# ЗАПУСК
|
|
474
444
|
# =============================================================================
|
|
475
445
|
|
|
476
446
|
async def main():
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
447
|
+
# ========== РЕГИСТРАЦИЯ РОУТЕРОВ ==========
|
|
448
|
+
bot_builder.register_routers(event_router)
|
|
449
|
+
|
|
450
|
+
# Можно добавить Telegram роутеры:
|
|
451
|
+
# from aiogram import Router
|
|
452
|
+
# telegram_router = Router(name="commands")
|
|
453
|
+
# bot_builder.register_telegram_router(telegram_router)
|
|
454
|
+
|
|
455
|
+
# ========== КАСТОМИЗАЦИЯ (до build) ==========
|
|
456
|
+
# Установить кастомный PromptLoader:
|
|
457
|
+
# from smart_bot_factory.utils import UserPromptLoader
|
|
458
|
+
# custom_loader = UserPromptLoader("{bot_id}")
|
|
459
|
+
# bot_builder.set_prompt_loader(custom_loader)
|
|
460
|
+
|
|
461
|
+
# ========== СБОРКА И ЗАПУСК ==========
|
|
462
|
+
await bot_builder.build()
|
|
463
|
+
await bot_builder.start()
|
|
493
464
|
|
|
494
465
|
if __name__ == "__main__":
|
|
495
466
|
asyncio.run(main())
|
|
@@ -229,17 +229,76 @@ async def process_events(session_id: str, events: list, user_id: int):
|
|
|
229
229
|
|
|
230
230
|
# Сначала пробуем как обычное событие
|
|
231
231
|
if event_type in event_handlers:
|
|
232
|
+
from ..core.decorators import execute_event_handler, update_event_result
|
|
233
|
+
|
|
234
|
+
event_handler_info = event_handlers.get(event_type, {})
|
|
235
|
+
once_only = event_handler_info.get('once_only', True)
|
|
236
|
+
|
|
237
|
+
logger.info(f" 🔍 Обработчик '{event_type}': once_only={once_only}")
|
|
238
|
+
|
|
239
|
+
# Если once_only=True - проверяем в БД наличие выполненных событий
|
|
240
|
+
if once_only:
|
|
241
|
+
check_query = supabase_client.client.table('scheduled_events')\
|
|
242
|
+
.select('id, status, session_id')\
|
|
243
|
+
.eq('event_type', event_type)\
|
|
244
|
+
.eq('user_id', user_id)\
|
|
245
|
+
.eq('status', 'completed')
|
|
246
|
+
|
|
247
|
+
# НЕ фильтруем по session_id - проверяем ВСЕ выполненные события пользователя
|
|
248
|
+
# if session_id:
|
|
249
|
+
# check_query = check_query.eq('session_id', session_id)
|
|
250
|
+
|
|
251
|
+
existing = check_query.execute()
|
|
252
|
+
|
|
253
|
+
logger.info(f" 🔍 Проверка БД: найдено {len(existing.data) if existing.data else 0} выполненных событий '{event_type}' для user_id={user_id}")
|
|
254
|
+
|
|
255
|
+
if existing.data:
|
|
256
|
+
logger.info(f" 🔄 Событие '{event_type}' уже выполнялось для пользователя {user_id}, пропускаем (once_only=True)")
|
|
257
|
+
logger.info(f" 📋 Найденные события: {existing.data}")
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
# Немедленно выполняем событие
|
|
261
|
+
logger.info(f" 🎯 Немедленно выполняем user_event: '{event_type}'")
|
|
262
|
+
|
|
232
263
|
try:
|
|
233
|
-
|
|
234
|
-
|
|
264
|
+
# Выполняем СНАЧАЛА
|
|
265
|
+
result = await execute_event_handler(event_type, user_id, event_info)
|
|
266
|
+
|
|
267
|
+
# Сохраняем в БД УЖЕ со статусом completed (избегаем дублирования)
|
|
268
|
+
event_record = {
|
|
269
|
+
'event_type': event_type,
|
|
270
|
+
'event_category': 'user_event',
|
|
271
|
+
'user_id': user_id,
|
|
272
|
+
'event_data': event_info,
|
|
273
|
+
'scheduled_at': None,
|
|
274
|
+
'status': 'completed', # Сразу completed!
|
|
275
|
+
'session_id': session_id,
|
|
276
|
+
'executed_at': __import__('datetime').datetime.now(__import__('datetime').timezone.utc).isoformat(),
|
|
277
|
+
'result_data': __import__('json').dumps(result, ensure_ascii=False) if result else None
|
|
278
|
+
}
|
|
279
|
+
response = supabase_client.client.table('scheduled_events').insert(event_record).execute()
|
|
280
|
+
event_id = response.data[0]['id']
|
|
281
|
+
|
|
282
|
+
should_notify = event_handler_info.get('notify', False)
|
|
235
283
|
should_execute_immediately = True
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
284
|
+
|
|
285
|
+
logger.info(f" ✅ Событие {event_id} выполнено и сохранено как completed")
|
|
286
|
+
|
|
287
|
+
except Exception as e:
|
|
288
|
+
logger.error(f" ❌ Ошибка выполнения события: {e}")
|
|
289
|
+
# Сохраняем ошибку в БД
|
|
290
|
+
event_record = {
|
|
291
|
+
'event_type': event_type,
|
|
292
|
+
'event_category': 'user_event',
|
|
293
|
+
'user_id': user_id,
|
|
294
|
+
'event_data': event_info,
|
|
295
|
+
'scheduled_at': None,
|
|
296
|
+
'status': 'failed',
|
|
297
|
+
'session_id': session_id,
|
|
298
|
+
'last_error': str(e)
|
|
299
|
+
}
|
|
300
|
+
supabase_client.client.table('scheduled_events').insert(event_record).execute()
|
|
301
|
+
raise
|
|
243
302
|
|
|
244
303
|
# Если не user_event, пробуем как запланированную задачу
|
|
245
304
|
elif event_type in scheduled_tasks:
|
|
@@ -283,18 +342,7 @@ async def process_events(session_id: str, events: list, user_id: int):
|
|
|
283
342
|
logger.debug(f" - event_handlers: {list(event_handlers.keys())}")
|
|
284
343
|
logger.debug(f" - scheduled_tasks: {list(scheduled_tasks.keys())}")
|
|
285
344
|
logger.debug(f" - global_handlers: {list(global_handlers.keys())}")
|
|
286
|
-
|
|
287
|
-
# Выполняем немедленные события
|
|
288
|
-
if should_execute_immediately and event_id:
|
|
289
|
-
try:
|
|
290
|
-
result = await execute_event_handler(event_type, user_id, event_info)
|
|
291
|
-
should_notify = result.get('notify', False)
|
|
292
|
-
await update_event_result(event_id, 'completed', result)
|
|
293
|
-
logger.info(f" ✅ Событие выполнено: {result}")
|
|
294
|
-
except Exception as e:
|
|
295
|
-
await update_event_result(event_id, 'failed', None, str(e))
|
|
296
|
-
logger.error(f" ❌ Ошибка выполнения события: {e}")
|
|
297
|
-
|
|
345
|
+
|
|
298
346
|
except ValueError as e:
|
|
299
347
|
logger.warning(f" ⚠️ Обработчик/задача не найдены: {e}")
|
|
300
348
|
except Exception as e:
|