smart-bot-factory 0.2.0__py3-none-any.whl → 0.2.2__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.

@@ -46,6 +46,14 @@ class BotBuilder:
46
46
  self.prompt_loader: Optional[PromptLoader] = None
47
47
  self.router_manager: Optional[RouterManager] = None
48
48
  self._telegram_routers: List = [] # Список Telegram роутеров
49
+ self._start_handlers: List = [] # Список обработчиков on_start
50
+
51
+ # Хуки для кастомизации process_user_message
52
+ self._message_validators: List = [] # Валидация ДО обработки
53
+ self._prompt_enrichers: List = [] # Обогащение системного промпта
54
+ self._context_enrichers: List = [] # Обогащение контекста для AI
55
+ self._response_processors: List = [] # Обработка ответа AI
56
+ self._send_filters: List = [] # Фильтры перед отправкой пользователю
49
57
 
50
58
  # Флаги инициализации
51
59
  self._initialized = False
@@ -326,6 +334,165 @@ class BotBuilder:
326
334
 
327
335
  logger.info(f"✅ Зарегистрировано {len(telegram_routers)} Telegram роутеров")
328
336
 
337
+ def on_start(self, handler):
338
+ """
339
+ Регистрирует обработчик, который вызывается после стандартной логики /start
340
+
341
+ Обработчик получает доступ к:
342
+ - user_id: int - ID пользователя Telegram
343
+ - session_id: str - ID созданной сессии
344
+ - message: Message - Объект сообщения от aiogram
345
+ - state: FSMContext - Контекст состояния
346
+
347
+ Args:
348
+ handler: Async функция с сигнатурой:
349
+ async def handler(user_id: int, session_id: str, message: Message, state: FSMContext)
350
+
351
+ Example:
352
+ @bot_builder.on_start
353
+ async def my_start_handler(user_id, session_id, message, state):
354
+ keyboard = InlineKeyboardMarkup(...)
355
+ await message.answer("Выберите действие:", reply_markup=keyboard)
356
+ """
357
+ if not callable(handler):
358
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
359
+
360
+ self._start_handlers.append(handler)
361
+ logger.info(f"✅ Зарегистрирован обработчик on_start: {handler.__name__}")
362
+ return handler # Возвращаем handler для использования как декоратор
363
+
364
+ def get_start_handlers(self) -> List:
365
+ """Получает список обработчиков on_start"""
366
+ return self._start_handlers.copy()
367
+
368
+ # ========== ХУКИ ДЛЯ КАСТОМИЗАЦИИ ОБРАБОТКИ СООБЩЕНИЙ ==========
369
+
370
+ def validate_message(self, handler):
371
+ """
372
+ Регистрирует валидатор сообщений (вызывается ДО обработки AI)
373
+
374
+ Если валидатор возвращает False, обработка прерывается
375
+
376
+ Args:
377
+ handler: async def(message: Message, supabase_client) -> bool
378
+
379
+ Example:
380
+ @bot_builder.validate_message
381
+ async def check_service_names(message, supabase_client):
382
+ if "неправильное название" in message.text:
383
+ await message.answer("Пожалуйста, уточните название услуги")
384
+ return False # Прерываем обработку
385
+ return True # Продолжаем
386
+ """
387
+ if not callable(handler):
388
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
389
+
390
+ self._message_validators.append(handler)
391
+ logger.info(f"✅ Зарегистрирован валидатор сообщений: {handler.__name__}")
392
+ return handler
393
+
394
+ def enrich_prompt(self, handler):
395
+ """
396
+ Регистрирует обогатитель системного промпта
397
+
398
+ Args:
399
+ handler: async def(system_prompt: str, user_id: int, session_id: str, supabase_client) -> str
400
+
401
+ Example:
402
+ @bot_builder.enrich_prompt
403
+ async def add_client_info(system_prompt, user_id, session_id, supabase_client):
404
+ session = await supabase_client.get_active_session(user_id)
405
+ phone = session.get('metadata', {}).get('phone')
406
+ if phone:
407
+ return f"{system_prompt}\\n\\nТелефон клиента: {phone}"
408
+ return system_prompt
409
+ """
410
+ if not callable(handler):
411
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
412
+
413
+ self._prompt_enrichers.append(handler)
414
+ logger.info(f"✅ Зарегистрирован обогатитель промпта: {handler.__name__}")
415
+ return handler
416
+
417
+ def enrich_context(self, handler):
418
+ """
419
+ Регистрирует обогатитель контекста для AI (messages array)
420
+
421
+ Args:
422
+ handler: async def(messages: List[dict], user_id: int, session_id: str) -> List[dict]
423
+
424
+ Example:
425
+ @bot_builder.enrich_context
426
+ async def add_external_data(messages, user_id, session_id):
427
+ # Добавляем данные из внешнего API
428
+ messages.append({
429
+ "role": "system",
430
+ "content": "Дополнительная информация..."
431
+ })
432
+ return messages
433
+ """
434
+ if not callable(handler):
435
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
436
+
437
+ self._context_enrichers.append(handler)
438
+ logger.info(f"✅ Зарегистрирован обогатитель контекста: {handler.__name__}")
439
+ return handler
440
+
441
+ def process_response(self, handler):
442
+ """
443
+ Регистрирует обработчик ответа AI (ПОСЛЕ получения ответа)
444
+
445
+ Args:
446
+ handler: async def(response_text: str, ai_metadata: dict, user_id: int) -> tuple[str, dict]
447
+
448
+ Example:
449
+ @bot_builder.process_response
450
+ async def modify_response(response_text, ai_metadata, user_id):
451
+ # Модифицируем ответ
452
+ if "цена" in response_text.lower():
453
+ response_text += "\\n\\n💰 Актуальные цены на сайте"
454
+ return response_text, ai_metadata
455
+ """
456
+ if not callable(handler):
457
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
458
+
459
+ self._response_processors.append(handler)
460
+ logger.info(f"✅ Зарегистрирован обработчик ответа: {handler.__name__}")
461
+ return handler
462
+
463
+ def filter_send(self, handler):
464
+ """
465
+ Регистрирует фильтр отправки (может блокировать отправку пользователю)
466
+
467
+ Если фильтр возвращает False, сообщение НЕ отправляется
468
+
469
+ Args:
470
+ handler: async def(user_id: int, response_text: str) -> bool
471
+
472
+ Example:
473
+ @bot_builder.filter_send
474
+ async def block_during_process(user_id, response_text):
475
+ if is_processing(user_id):
476
+ return False # Не отправляем
477
+ return True # Отправляем
478
+ """
479
+ if not callable(handler):
480
+ raise TypeError(f"Обработчик должен быть callable, получен {type(handler)}")
481
+
482
+ self._send_filters.append(handler)
483
+ logger.info(f"✅ Зарегистрирован фильтр отправки: {handler.__name__}")
484
+ return handler
485
+
486
+ def get_message_hooks(self) -> Dict[str, List]:
487
+ """Получает все хуки для обработки сообщений"""
488
+ return {
489
+ 'validators': self._message_validators.copy(),
490
+ 'prompt_enrichers': self._prompt_enrichers.copy(),
491
+ 'context_enrichers': self._context_enrichers.copy(),
492
+ 'response_processors': self._response_processors.copy(),
493
+ 'send_filters': self._send_filters.copy()
494
+ }
495
+
329
496
  def get_router_manager(self) -> RouterManager:
330
497
  """Получает менеджер роутеров событий"""
331
498
  return self.router_manager
@@ -374,6 +541,8 @@ class BotBuilder:
374
541
  handlers_module.admin_manager = self.admin_manager
375
542
  handlers_module.analytics_manager = self.analytics_manager
376
543
  handlers_module.conversation_manager = self.conversation_manager
544
+ handlers_module.start_handlers = self._start_handlers # Передаем обработчики on_start
545
+ handlers_module.message_hooks = self.get_message_hooks() # Передаем хуки для обработки сообщений
377
546
  logger.info("✅ Глобальные переменные установлены в handlers")
378
547
  except Exception as e:
379
548
  logger.warning(f"⚠️ Не удалось установить глобальные переменные в handlers: {e}")
@@ -277,6 +277,23 @@ async def user_start_handler(message: Message, state: FSMContext):
277
277
 
278
278
  logging.info(f"✅ Приветственное сообщение успешно сохранено в БД для сессии {session_id}")
279
279
 
280
+ # ВЫЗЫВАЕМ ПОЛЬЗОВАТЕЛЬСКИЕ ОБРАБОТЧИКИ on_start
281
+ start_handlers = get_global_var('start_handlers')
282
+ if start_handlers:
283
+ logger.info(f"🔔 Вызов {len(start_handlers)} пользовательских обработчиков on_start")
284
+ for handler in start_handlers:
285
+ try:
286
+ await handler(
287
+ user_id=message.from_user.id,
288
+ session_id=session_id,
289
+ message=message,
290
+ state=state
291
+ )
292
+ logger.info(f"✅ Обработчик on_start '{handler.__name__}' выполнен успешно")
293
+ except Exception as handler_error:
294
+ logger.error(f"❌ Ошибка в обработчике on_start '{handler.__name__}': {handler_error}")
295
+ # Продолжаем выполнение остальных обработчиков
296
+
280
297
  except Exception as e:
281
298
  logger.error(f"Ошибка при обработке user /start: {e}")
282
299
  await send_message(message, "Произошла ошибка при инициализации. Попробуйте позже.")
@@ -475,10 +492,22 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
475
492
  config = get_global_var('config')
476
493
  bot = get_global_var('bot')
477
494
  prompt_loader = get_global_var('prompt_loader')
495
+ message_hooks = get_global_var('message_hooks') or {}
478
496
  from datetime import datetime
479
497
  import pytz # Добавляем импорт для работы с временными зонами
480
498
 
481
499
  try:
500
+ # ============ ХУК 1: ВАЛИДАЦИЯ СООБЩЕНИЯ ============
501
+ validators = message_hooks.get('validators', [])
502
+ for validator in validators:
503
+ try:
504
+ should_continue = await validator(message, supabase_client)
505
+ if not should_continue:
506
+ logger.info(f"⛔ Валидатор '{validator.__name__}' прервал обработку")
507
+ return # Прерываем обработку
508
+ except Exception as e:
509
+ logger.error(f"❌ Ошибка в валидаторе '{validator.__name__}': {e}")
510
+
482
511
  # Сохраняем сообщение пользователя
483
512
  await supabase_client.add_message(
484
513
  session_id=session_id,
@@ -497,13 +526,27 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
497
526
  current_time = datetime.now(moscow_tz)
498
527
  time_info = current_time.strftime('%H:%M, %d.%m.%Y, %A')
499
528
 
500
- # Модифицируем системный промпт, добавляя время
529
+ # Базовый системный промпт с временем
501
530
  system_prompt_with_time = f"""
502
531
  {system_prompt}
503
532
 
504
533
  ТЕКУЩЕЕ ВРЕМЯ: {time_info} (московское время)
505
534
  """
506
535
 
536
+ # ============ ХУК 2: ОБОГАЩЕНИЕ ПРОМПТА ============
537
+ prompt_enrichers = message_hooks.get('prompt_enrichers', [])
538
+ for enricher in prompt_enrichers:
539
+ try:
540
+ system_prompt_with_time = await enricher(
541
+ system_prompt_with_time,
542
+ message.from_user.id,
543
+ session_id,
544
+ supabase_client
545
+ )
546
+ logger.info(f"✅ Промпт обогащен '{enricher.__name__}'")
547
+ except Exception as e:
548
+ logger.error(f"❌ Ошибка в обогатителе промпта '{enricher.__name__}': {e}")
549
+
507
550
  # Формируем контекст для OpenAI с обновленным системным промптом
508
551
  messages = [{"role": "system", "content": system_prompt_with_time}]
509
552
 
@@ -519,6 +562,19 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
519
562
  messages.append({"role": "system", "content": final_instructions})
520
563
  logger.info(f"🎯 Добавлены финальные инструкции ({len(final_instructions)} символов)")
521
564
 
565
+ # ============ ХУК 3: ОБОГАЩЕНИЕ КОНТЕКСТА ============
566
+ context_enrichers = message_hooks.get('context_enrichers', [])
567
+ for enricher in context_enrichers:
568
+ try:
569
+ messages = await enricher(
570
+ messages,
571
+ message.from_user.id,
572
+ session_id
573
+ )
574
+ logger.info(f"✅ Контекст обогащен '{enricher.__name__}'")
575
+ except Exception as e:
576
+ logger.error(f"❌ Ошибка в обогатителе контекста '{enricher.__name__}': {e}")
577
+
522
578
  logger.info(f"📝 Контекст сформирован: {len(messages)} сообщений (включая время: {time_info})")
523
579
 
524
580
  await bot.send_chat_action(message.chat.id, "typing")
@@ -571,82 +627,95 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
571
627
  response_text = ai_response
572
628
 
573
629
  logger.info(f"✅ Финальный текст для отправки: {len(response_text)} символов")
574
-
575
- # Обновляем этап сессии и качество лида
576
- if ai_metadata:
577
- logger.info("🔍 Анализ метаданных от ИИ:")
578
-
579
- # Вывод информации об этапе
580
- stage = ai_metadata.get('этап')
581
- if stage:
582
- logger.info(f" 📈 Этап диалога: {stage}")
583
-
584
- # Вывод информации о качестве лида
585
- quality = ai_metadata.get('качество')
586
- if quality is not None:
587
- quality_emoji = "⭐" * min(quality, 5) # Максимум 5 звезд
588
- logger.info(f" {quality_emoji} Качество лида: {quality}/10")
589
-
590
- # Обновляем в базе данных
591
- if stage or quality is not None:
592
- await supabase_client.update_session_stage(session_id, stage, quality)
593
- logger.info(f" ✅ Этап и качество обновлены в БД")
594
-
595
- # Обрабатываем события
596
- events = ai_metadata.get('события', [])
597
- if events:
598
- logger.info(f"\n🔔 События в диалоге ({len(events)}):")
599
- for idx, event in enumerate(events, 1):
600
- event_type = event.get('тип', 'неизвестно')
601
- event_info = event.get('инфо', 'нет информации')
602
-
603
- # Подбираем эмодзи для разных типов событий
604
- event_emoji = {
605
- 'телефон': '📱',
606
- 'email': '📧',
607
- 'встреча': '📅',
608
- 'заказ': '🛍️',
609
- 'вопрос': '❓',
610
- 'консультация': '💬',
611
- 'жалоба': '⚠️',
612
- 'отзыв': '💭'
613
- }.get(event_type.lower(), '📌')
614
-
615
- logger.info(f" {idx}. {event_emoji} {event_type}: {event_info}")
616
-
617
- # Обрабатываем события в системе
618
- await process_events(session_id, events, message.from_user.id)
619
- logger.info(" ✅ События обработаны")
630
+
631
+ # ============ ХУК 4: ОБРАБОТКА ОТВЕТА ============
632
+ response_processors = message_hooks.get('response_processors', [])
633
+ for processor in response_processors:
634
+ try:
635
+ response_text, ai_metadata = await processor(
636
+ response_text,
637
+ ai_metadata,
638
+ message.from_user.id
639
+ )
640
+ logger.info(f"✅ Ответ обработан '{processor.__name__}'")
641
+ except Exception as e:
642
+ logger.error(f"❌ Ошибка в обработчике ответа '{processor.__name__}': {e}")
643
+
644
+ # Обновляем этап сессии и качество лида
645
+ if ai_metadata:
646
+ logger.info("🔍 Анализ метаданных от ИИ:")
620
647
 
621
- # Обрабатываем файлы и каталоги
622
- files_list = ai_metadata.get('файлы', [])
623
- directories_list = ai_metadata.get('каталоги', [])
648
+ # Вывод информации об этапе
649
+ stage = ai_metadata.get('этап')
650
+ if stage:
651
+ logger.info(f" 📈 Этап диалога: {stage}")
624
652
 
625
- # Форматируем информацию о файлах
653
+ # Вывод информации о качестве лида
654
+ quality = ai_metadata.get('качество')
655
+ if quality is not None:
656
+ quality_emoji = "⭐" * min(quality, 5) # Максимум 5 звезд
657
+ logger.info(f" {quality_emoji} Качество лида: {quality}/10")
658
+
659
+ # Обновляем в базе данных
660
+ if stage or quality is not None:
661
+ await supabase_client.update_session_stage(session_id, stage, quality)
662
+ logger.info(f" ✅ Этап и качество обновлены в БД")
663
+
664
+ # Обрабатываем события
665
+ events = ai_metadata.get('события', [])
666
+ if events:
667
+ logger.info(f"\n🔔 События в диалоге ({len(events)}):")
668
+ for idx, event in enumerate(events, 1):
669
+ event_type = event.get('тип', 'неизвестно')
670
+ event_info = event.get('инфо', 'нет информации')
671
+
672
+ # Подбираем эмодзи для разных типов событий
673
+ event_emoji = {
674
+ 'телефон': '📱',
675
+ 'email': '📧',
676
+ 'встреча': '📅',
677
+ 'заказ': '🛍️',
678
+ 'вопрос': '❓',
679
+ 'консультация': '💬',
680
+ 'жалоба': '⚠️',
681
+ 'отзыв': '💭'
682
+ }.get(event_type.lower(), '📌')
683
+
684
+ logger.info(f" {idx}. {event_emoji} {event_type}: {event_info}")
685
+
686
+ # Обрабатываем события в системе
687
+ await process_events(session_id, events, message.from_user.id)
688
+ logger.info(" ✅ События обработаны")
689
+
690
+ # Обрабатываем файлы и каталоги
691
+ files_list = ai_metadata.get('файлы', [])
692
+ directories_list = ai_metadata.get('каталоги', [])
693
+
694
+ # Форматируем информацию о файлах
695
+ if files_list:
696
+ logger.info("📎 Найденные файлы:")
697
+ for idx, file in enumerate(files_list, 1):
698
+ logger.info(f" {idx}. 📄 {file}")
699
+
700
+ # Форматируем информацию о каталогах
701
+ if directories_list:
702
+ logger.info("📂 Найденные каталоги:")
703
+ for idx, directory in enumerate(directories_list, 1):
704
+ logger.info(f" {idx}. 📁 {directory}")
705
+
706
+ # Добавляем информацию в текст ответа
707
+ if files_list or directories_list:
708
+ files_info = []
626
709
  if files_list:
627
- logger.info("📎 Найденные файлы:")
628
- for idx, file in enumerate(files_list, 1):
629
- logger.info(f" {idx}. 📄 {file}")
710
+ files_str = "\n".join(f" {file}" for file in files_list)
711
+ files_info.append(f"\n\n📎 Доступные файлы:\n{files_str}")
630
712
 
631
- # Форматируем информацию о каталогах
632
713
  if directories_list:
633
- logger.info("📂 Найденные каталоги:")
634
- for idx, directory in enumerate(directories_list, 1):
635
- logger.info(f" {idx}. 📁 {directory}")
714
+ dirs_str = "\n".join(f" {directory}" for directory in directories_list)
715
+ files_info.append(f"\n\n📂 Доступные каталоги:\n{dirs_str}")
636
716
 
637
- # Добавляем информацию в текст ответа
638
- if files_list or directories_list:
639
- files_info = []
640
- if files_list:
641
- files_str = "\n".join(f"• {file}" for file in files_list)
642
- files_info.append(f"\n\n📎 Доступные файлы:\n{files_str}")
643
-
644
- if directories_list:
645
- dirs_str = "\n".join(f"• {directory}" for directory in directories_list)
646
- files_info.append(f"\n\n📂 Доступные каталоги:\n{dirs_str}")
647
-
648
- else:
649
- logger.info("📎 Файлы и каталоги не указаны")
717
+ else:
718
+ logger.info("📎 Файлы и каталоги не указаны")
650
719
 
651
720
  # Сохраняем ответ ассистента с метаданными
652
721
  try:
@@ -680,6 +749,17 @@ async def process_user_message(message: Message, state: FSMContext, session_id:
680
749
 
681
750
  logger.info(f"📱 Отправляем пользователю: {len(final_response)} символов")
682
751
 
752
+ # ============ ХУК 5: ФИЛЬТРЫ ОТПРАВКИ ============
753
+ send_filters = message_hooks.get('send_filters', [])
754
+ for filter_func in send_filters:
755
+ try:
756
+ should_send = await filter_func(message.from_user.id, final_response)
757
+ if not should_send:
758
+ logger.info(f"⛔ Фильтр '{filter_func.__name__}' заблокировал отправку")
759
+ return # Не отправляем
760
+ except Exception as e:
761
+ logger.error(f"❌ Ошибка в фильтре отправки '{filter_func.__name__}': {e}")
762
+
683
763
  # Отправляем ответ пользователю
684
764
  try:
685
765
  await send_message(message, final_response, files_list=files_list, directories_list=directories_list)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-bot-factory
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Библиотека для создания умных чат-ботов
5
5
  Author-email: Kopatych <kopatych@example.com>
6
6
  License: MIT
@@ -33,12 +33,12 @@ smart_bot_factory/core/router_manager.py,sha256=dUwesog-oHk1U2EDdS8p0e4MTSkwtx5_
33
33
  smart_bot_factory/core/states.py,sha256=AOc19_yAsDW_8md-2oiowjBhuW3bwcsmMxszCXWZZTQ,355
34
34
  smart_bot_factory/core/telegram_router.py,sha256=LcPLOd87Y4Y4YN6TBXVAtmpSp8gAK2otgMI4YS5f5tk,2091
35
35
  smart_bot_factory/creation/__init__.py,sha256=IgDk8GDS3pg7Pw_Et41J33ZmeZIU5dRwQdTmYKXfJfE,128
36
- smart_bot_factory/creation/bot_builder.py,sha256=xWgWRe4DV3PngiLoQlzm6AdhNvPqn3wOCwcgsIoh-QA,25220
36
+ smart_bot_factory/creation/bot_builder.py,sha256=VjRPlar6xgul7QpG57od--uS-juWrlW9-YYNnFN_Yx4,33828
37
37
  smart_bot_factory/creation/bot_testing.py,sha256=JDWXyJfZmbgo-DLdAPk8Sd9FiehtHHa4sLD17lBrTOc,55669
38
38
  smart_bot_factory/database/database_structure.sql,sha256=26gFtMC2jdQGQF7Zb_F4Br56rMd4hUDTk9FkNZYneLo,2789
39
39
  smart_bot_factory/database/schema.sql,sha256=-6kOmA9QnSkUtmGI2iQRbTvbdiqOhEOQcuz1lJn79mU,28059
40
40
  smart_bot_factory/event/__init__.py,sha256=hPL449RULIOB-OXv1ZbGNiHctAYaOMUqhSWGPrDHYBM,212
41
- smart_bot_factory/handlers/handlers.py,sha256=YH8xG0tDcb7uxZXI4socXURzc-y57_FEQ6GqTgYcM5Q,37603
41
+ smart_bot_factory/handlers/handlers.py,sha256=kfzveBtye0KIrRVWhegNVQxfj3PyL9M3hvQBE-lseaY,41601
42
42
  smart_bot_factory/integrations/openai_client.py,sha256=aMcDrKO0GEx3ZSVEOGDeDtFCDWSXs6biUfgrbRK8yTU,23180
43
43
  smart_bot_factory/integrations/supabase_client.py,sha256=AfALLZdDYeMWHLJw6POTGiBd-sH3i03oT6tT7m9C28I,44644
44
44
  smart_bot_factory/message/__init__.py,sha256=6QvjdfF99venyDB9udZv9WDNjIHJLNuaVhYdTK3a44A,282
@@ -48,8 +48,8 @@ smart_bot_factory/supabase/client.py,sha256=8_-I3kxZQlKQElI4cTUjNGYcqlyIyEkSrUZa
48
48
  smart_bot_factory/utils/__init__.py,sha256=5zNjw491bj5VkOhoEAwh2hjmv8nldyDOTrG7pbGpz6A,285
49
49
  smart_bot_factory/utils/debug_routing.py,sha256=BOoDhKBg7UXe5uHQxRk3TSfPfLPOFqt0N7lAo6kjCOo,4719
50
50
  smart_bot_factory/utils/prompt_loader.py,sha256=JSn7CsWnToSbHYtURdeuZn7ectyDqQGrPGHN2ixIGkw,19930
51
- smart_bot_factory-0.2.0.dist-info/METADATA,sha256=WEC38O2La8OlQpfCZWkXjhMU70VigduV0wIrferi2w0,28224
52
- smart_bot_factory-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
- smart_bot_factory-0.2.0.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
54
- smart_bot_factory-0.2.0.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
55
- smart_bot_factory-0.2.0.dist-info/RECORD,,
51
+ smart_bot_factory-0.2.2.dist-info/METADATA,sha256=XB5NPdlGpOpGPQtsbskUmJ0SGI3hp74IfAE5OHHAmq4,28224
52
+ smart_bot_factory-0.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
+ smart_bot_factory-0.2.2.dist-info/entry_points.txt,sha256=ybKEAI0WSb7WoRiey7QE-HHfn88UGV7nxLDxXq7b7SU,50
54
+ smart_bot_factory-0.2.2.dist-info/licenses/LICENSE,sha256=OrK3cwdUTzNzIhJvSPtJaVMoYIyC_sSx5EFE_FDMvGs,1092
55
+ smart_bot_factory-0.2.2.dist-info/RECORD,,