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.
- smart_bot_factory/__init__.py +51 -0
- smart_bot_factory/admin/__init__.py +16 -0
- smart_bot_factory/admin/admin_logic.py +430 -0
- smart_bot_factory/admin/admin_manager.py +141 -0
- smart_bot_factory/admin/admin_migration.sql +136 -0
- smart_bot_factory/admin/admin_tester.py +151 -0
- smart_bot_factory/admin/timeout_checker.py +499 -0
- smart_bot_factory/analytics/__init__.py +7 -0
- smart_bot_factory/analytics/analytics_manager.py +355 -0
- smart_bot_factory/cli.py +642 -0
- smart_bot_factory/config.py +235 -0
- smart_bot_factory/configs/growthmed-helper/env_example.txt +1 -0
- smart_bot_factory/configs/growthmed-helper/prompts/1sales_context.txt +9 -0
- smart_bot_factory/configs/growthmed-helper/prompts/2product_info.txt +582 -0
- smart_bot_factory/configs/growthmed-helper/prompts/3objection_handling.txt +66 -0
- smart_bot_factory/configs/growthmed-helper/prompts/final_instructions.txt +232 -0
- smart_bot_factory/configs/growthmed-helper/prompts/help_message.txt +28 -0
- smart_bot_factory/configs/growthmed-helper/prompts/welcome_message.txt +7 -0
- smart_bot_factory/configs/growthmed-helper/welcome_file/welcome_file_msg.txt +16 -0
- 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
- smart_bot_factory/configs/growthmed-october-24/prompts/1sales_context.txt +16 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/2product_info.txt +582 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/3objection_handling.txt +66 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/final_instructions.txt +212 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/help_message.txt +28 -0
- smart_bot_factory/configs/growthmed-october-24/prompts/welcome_message.txt +8 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064229.txt +818 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064335.txt +32 -0
- smart_bot_factory/configs/growthmed-october-24/reports/test_20250924_064638.txt +35 -0
- smart_bot_factory/configs/growthmed-october-24/tests/quick_scenarios.yaml +66 -0
- smart_bot_factory/configs/growthmed-october-24/tests/realistic_scenarios.yaml +108 -0
- smart_bot_factory/configs/growthmed-october-24/tests/scenario_examples.yaml +46 -0
- smart_bot_factory/configs/growthmed-october-24/welcome_file/welcome_file_msg.txt +16 -0
- 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
- smart_bot_factory/core/__init__.py +22 -0
- smart_bot_factory/core/bot_utils.py +693 -0
- smart_bot_factory/core/conversation_manager.py +536 -0
- smart_bot_factory/core/decorators.py +229 -0
- smart_bot_factory/core/message_sender.py +249 -0
- smart_bot_factory/core/states.py +14 -0
- smart_bot_factory/creation/__init__.py +8 -0
- smart_bot_factory/creation/bot_builder.py +329 -0
- smart_bot_factory/creation/bot_testing.py +986 -0
- smart_bot_factory/database/database_structure.sql +57 -0
- smart_bot_factory/database/schema.sql +1094 -0
- smart_bot_factory/handlers/handlers.py +583 -0
- smart_bot_factory/integrations/__init__.py +9 -0
- smart_bot_factory/integrations/openai_client.py +435 -0
- smart_bot_factory/integrations/supabase_client.py +592 -0
- smart_bot_factory/setup_checker.py +476 -0
- smart_bot_factory/utils/__init__.py +9 -0
- smart_bot_factory/utils/debug_routing.py +103 -0
- smart_bot_factory/utils/prompt_loader.py +427 -0
- smart_bot_factory/uv.lock +2004 -0
- smart_bot_factory-0.1.3.dist-info/METADATA +126 -0
- smart_bot_factory-0.1.3.dist-info/RECORD +59 -0
- smart_bot_factory-0.1.3.dist-info/licenses/LICENSE +24 -0
- smart_bot_factory-0.1.2.dist-info/METADATA +0 -31
- smart_bot_factory-0.1.2.dist-info/RECORD +0 -4
- {smart_bot_factory-0.1.2.dist-info → smart_bot_factory-0.1.3.dist-info}/WHEEL +0 -0
- {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()
|