smart-bot-factory 0.1.2__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.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.3.dist-info}/WHEEL +0 -0
  61. {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.3.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,136 @@
1
+ -- ФИНАЛЬНАЯ МИГРАЦИЯ АДМИНСКОЙ СИСТЕМЫ
2
+ -- Выполните ПОСЛЕ исправления уникальности telegram_id
3
+
4
+ -- 1. Расширяем существующие таблицы
5
+ ALTER TABLE sales_chat_sessions
6
+ ADD COLUMN IF NOT EXISTS current_stage TEXT,
7
+ ADD COLUMN IF NOT EXISTS lead_quality_score INTEGER;
8
+
9
+ ALTER TABLE sales_messages
10
+ ADD COLUMN IF NOT EXISTS ai_metadata JSONB DEFAULT '{}'::jsonb;
11
+
12
+ -- 2. Создаем функцию обновления updated_at
13
+ CREATE OR REPLACE FUNCTION update_updated_at_column()
14
+ RETURNS TRIGGER AS $$
15
+ BEGIN
16
+ NEW.updated_at = NOW();
17
+ RETURN NEW;
18
+ END;
19
+ $$ LANGUAGE plpgsql;
20
+
21
+ -- 3. Таблица администраторов
22
+ CREATE TABLE IF NOT EXISTS sales_admins (
23
+ id BIGSERIAL PRIMARY KEY,
24
+ telegram_id BIGINT UNIQUE NOT NULL,
25
+ username TEXT,
26
+ first_name TEXT,
27
+ last_name TEXT,
28
+ role TEXT DEFAULT 'admin',
29
+ is_active BOOLEAN DEFAULT TRUE,
30
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
31
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
32
+ );
33
+
34
+ -- 4. Диалоги админов с пользователями
35
+ CREATE TABLE IF NOT EXISTS admin_user_conversations (
36
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
37
+ admin_id BIGINT REFERENCES sales_admins(telegram_id) ON DELETE CASCADE,
38
+ user_id BIGINT REFERENCES sales_users(telegram_id) ON DELETE CASCADE,
39
+ session_id UUID REFERENCES sales_chat_sessions(id) ON DELETE CASCADE,
40
+ status TEXT DEFAULT 'active' CHECK (status IN ('active', 'completed')),
41
+ started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
42
+ ended_at TIMESTAMP WITH TIME ZONE,
43
+ auto_end_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() + INTERVAL '30 minutes'
44
+ );
45
+
46
+ -- 5. События из ответов ИИ
47
+ CREATE TABLE IF NOT EXISTS session_events (
48
+ id BIGSERIAL PRIMARY KEY,
49
+ session_id UUID REFERENCES sales_chat_sessions(id) ON DELETE CASCADE,
50
+ event_type TEXT NOT NULL,
51
+ event_info TEXT,
52
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
53
+ notified_admins BIGINT[] DEFAULT '{}'
54
+ );
55
+
56
+ -- 6. Индексы
57
+ CREATE INDEX IF NOT EXISTS idx_sales_admins_telegram_id ON sales_admins(telegram_id);
58
+ CREATE INDEX IF NOT EXISTS idx_admin_conversations_status ON admin_user_conversations(status);
59
+ CREATE INDEX IF NOT EXISTS idx_admin_conversations_admin ON admin_user_conversations(admin_id);
60
+ CREATE INDEX IF NOT EXISTS idx_admin_conversations_user ON admin_user_conversations(user_id);
61
+ CREATE INDEX IF NOT EXISTS idx_session_events_type ON session_events(event_type);
62
+ CREATE INDEX IF NOT EXISTS idx_session_events_session ON session_events(session_id);
63
+ CREATE INDEX IF NOT EXISTS idx_sales_chat_sessions_stage ON sales_chat_sessions(current_stage);
64
+ CREATE INDEX IF NOT EXISTS idx_sales_messages_metadata ON sales_messages USING gin(ai_metadata);
65
+
66
+ -- 7. Триггер для sales_admins
67
+ DROP TRIGGER IF EXISTS update_sales_admins_updated_at ON sales_admins;
68
+ CREATE TRIGGER update_sales_admins_updated_at
69
+ BEFORE UPDATE ON sales_admins
70
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
71
+
72
+ -- 8. Функция завершения просроченных диалогов
73
+ CREATE OR REPLACE FUNCTION end_expired_admin_conversations()
74
+ RETURNS INTEGER AS $$
75
+ DECLARE
76
+ ended_count INTEGER;
77
+ BEGIN
78
+ UPDATE admin_user_conversations
79
+ SET status = 'completed', ended_at = NOW()
80
+ WHERE status = 'active' AND auto_end_at < NOW();
81
+
82
+ GET DIAGNOSTICS ended_count = ROW_COUNT;
83
+ RETURN ended_count;
84
+ END;
85
+ $$ LANGUAGE plpgsql;
86
+
87
+ -- 9. Представления для аналитики
88
+ CREATE OR REPLACE VIEW funnel_stats AS
89
+ SELECT
90
+ current_stage,
91
+ COUNT(*) as count,
92
+ AVG(lead_quality_score) as avg_quality,
93
+ ROUND(COUNT(*) * 100.0 / NULLIF(SUM(COUNT(*)) OVER(), 0), 1) as percentage
94
+ FROM sales_chat_sessions
95
+ WHERE created_at > NOW() - INTERVAL '7 days'
96
+ AND current_stage IS NOT NULL
97
+ GROUP BY current_stage;
98
+
99
+ CREATE OR REPLACE VIEW daily_events AS
100
+ SELECT
101
+ DATE(created_at) as event_date,
102
+ event_type,
103
+ COUNT(*) as count
104
+ FROM session_events
105
+ WHERE created_at > NOW() - INTERVAL '30 days'
106
+ GROUP BY DATE(created_at), event_type
107
+ ORDER BY event_date DESC, event_type;
108
+
109
+ -- 10. RLS политики
110
+ ALTER TABLE sales_admins ENABLE ROW LEVEL SECURITY;
111
+ ALTER TABLE admin_user_conversations ENABLE ROW LEVEL SECURITY;
112
+ ALTER TABLE session_events ENABLE ROW LEVEL SECURITY;
113
+
114
+ DROP POLICY IF EXISTS "Service role can manage all admins" ON sales_admins;
115
+ DROP POLICY IF EXISTS "Service role can manage all conversations" ON admin_user_conversations;
116
+ DROP POLICY IF EXISTS "Service role can manage all events" ON session_events;
117
+
118
+ CREATE POLICY "Service role can manage all admins" ON sales_admins
119
+ FOR ALL USING (current_setting('role') = 'service_role');
120
+
121
+ CREATE POLICY "Service role can manage all conversations" ON admin_user_conversations
122
+ FOR ALL USING (current_setting('role') = 'service_role');
123
+
124
+ CREATE POLICY "Service role can manage all events" ON session_events
125
+ FOR ALL USING (current_setting('role') = 'service_role');
126
+
127
+ -- 11. Комментарии
128
+ COMMENT ON TABLE sales_admins IS 'Администраторы бота';
129
+ COMMENT ON TABLE admin_user_conversations IS 'Активные диалоги админов с пользователями';
130
+ COMMENT ON TABLE session_events IS 'События из ответов ИИ для уведомлений';
131
+
132
+ -- Финальная проверка
133
+ SELECT
134
+ 'АДМИНСКАЯ СИСТЕМА СОЗДАНА!' AS status,
135
+ (SELECT COUNT(*) FROM information_schema.tables
136
+ WHERE table_name IN ('sales_admins', 'admin_user_conversations', 'session_events')) AS tables_created;
@@ -0,0 +1,151 @@
1
+ """
2
+ Утилита для тестирования системы администрирования бота
3
+ """
4
+
5
+ import asyncio
6
+ import logging
7
+ import json
8
+ import re
9
+ import sys
10
+ import os
11
+
12
+ from ..config import Config
13
+ from ..integrations.supabase_client import SupabaseClient
14
+ from .admin_manager import AdminManager
15
+ from ..core.conversation_manager import ConversationManager
16
+ from ..analytics.analytics_manager import AnalyticsManager
17
+ from .timeout_checker import setup_bot_environment
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ async def test_admin_system(bot_name: str = "growthmed-october-24") -> bool:
22
+ """
23
+ Тестирует систему администрирования бота
24
+
25
+ Args:
26
+ bot_name: Имя бота для тестирования
27
+
28
+ Returns:
29
+ bool: True если все тесты пройдены, False если найдены проблемы
30
+ """
31
+ logger.info(f"🚀 Тестирование системы администрирования: {bot_name}")
32
+ logger.info(f"🤖 Bot ID будет автоопределен как: {bot_name}\n")
33
+
34
+ # Настраиваем окружение для бота (автоматически устанавливает BOT_ID)
35
+ config_dir = setup_bot_environment(bot_name)
36
+ if not config_dir:
37
+ return False
38
+
39
+ # Инициализируем конфигурацию
40
+ config = Config()
41
+ logger.info(f"📋 Конфигурация:")
42
+ logger.info(f" BOT_ID: {config.BOT_ID}")
43
+ logger.info(f" ADMIN_SESSION_TIMEOUT_MINUTES: {config.ADMIN_SESSION_TIMEOUT_MINUTES}")
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
+ response = 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(f"\n👑 AdminManager инициализирован ({len(admin_manager.admin_ids)} админов)")
83
+
84
+ # Проверяем ConversationManager
85
+ conversation_manager = ConversationManager(supabase_client, admin_manager)
86
+ logger.info("✅ ConversationManager инициализирован")
87
+
88
+ # Проверяем AnalyticsManager
89
+ analytics_manager = AnalyticsManager(supabase_client)
90
+
91
+ # Тестируем получение статистики
92
+ funnel_stats = await analytics_manager.get_funnel_stats(1)
93
+ logger.info("✅ AnalyticsManager работает")
94
+
95
+ # Проверяем активные диалоги
96
+ conversations = await conversation_manager.get_active_conversations()
97
+ logger.info(f"\n💬 Активные диалоги: {len(conversations)}")
98
+
99
+ if conversations:
100
+ for conv in conversations:
101
+ logger.info(f" • Диалог {conv['id']}: админ {conv['admin_id']} с пользователем {conv['user_id']}")
102
+ else:
103
+ logger.info(" Нет активных диалогов")
104
+ logger.info(" 💡 Создайте диалог командой /чат USER_ID для тестирования")
105
+
106
+ # Проверяем форматирование диалогов
107
+ if conversations:
108
+ formatted = conversation_manager.format_active_conversations(conversations)
109
+ logger.info("\n📝 Форматирование диалогов:")
110
+ logger.info(formatted)
111
+
112
+ logger.info("\n✅ Админская система готова к работе")
113
+ return True
114
+
115
+ except Exception as e:
116
+ logger.error(f"❌ Ошибка тестирования: {e}")
117
+ logger.exception("Стек ошибки:")
118
+ return False
119
+
120
+ def main():
121
+ """Точка входа для запуска из командной строки"""
122
+ # Настройка логирования
123
+ logging.basicConfig(level=logging.INFO, format='%(message)s')
124
+
125
+ logger.info("🔍 Утилита тестирования админской системы")
126
+ logger.info("Использование:")
127
+ logger.info(" python -m smart_bot_factory.admin_tester [bot_name]")
128
+ logger.info(" python -m smart_bot_factory.admin_tester growthmed-october-24")
129
+ logger.info("")
130
+
131
+ if len(sys.argv) > 1 and sys.argv[1] in ['-h', '--help', 'help']:
132
+ return
133
+
134
+ # Определяем какого бота тестировать
135
+ bot_name = "growthmed-october-24" # по умолчанию
136
+ if len(sys.argv) > 1:
137
+ bot_name = sys.argv[1]
138
+
139
+ try:
140
+ success = asyncio.run(test_admin_system(bot_name))
141
+ if not success:
142
+ sys.exit(1)
143
+ except KeyboardInterrupt:
144
+ logger.info("\n⏹️ Прервано пользователем")
145
+ except Exception as e:
146
+ logger.error(f"\n💥 Критическая ошибка: {e}")
147
+ logger.exception("Стек ошибки:")
148
+ sys.exit(1)
149
+
150
+ if __name__ == "__main__":
151
+ main()