smart-bot-factory 0.1.0__py3-none-any.whl → 0.1.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.

@@ -1,83 +0,0 @@
1
- """
2
- Интеграции с существующими файлами проекта
3
- """
4
-
5
- # Импортируем существующие классы из корня проекта
6
- import sys
7
- from pathlib import Path
8
-
9
- # Добавляем корень проекта в путь для импорта существующих файлов
10
- project_root = Path(__file__).parent.parent.parent.parent
11
- if str(project_root) not in sys.path:
12
- sys.path.insert(0, str(project_root))
13
-
14
- try:
15
- from openai_client import OpenAIClient
16
- from supabase_client import SupabaseClient
17
- from config import Config
18
- from conversation_manager import ConversationManager
19
- from admin_manager import AdminManager
20
- from prompt_loader import PromptLoader
21
- from bot_utils import send_message, parse_ai_response, process_events
22
- from handlers import router, setup_handlers
23
- from admin_logic import setup_admin_handlers
24
- from bot_utils import setup_utils_handlers
25
- except ImportError as e:
26
- # Если файлы не найдены, создаем заглушки
27
- print(f"⚠️ Предупреждение: не удалось импортировать существующие файлы: {e}")
28
-
29
- class OpenAIClient:
30
- def __init__(self, *args, **kwargs):
31
- raise NotImplementedError("OpenAIClient не найден. Убедитесь, что openai_client.py существует в корне проекта")
32
-
33
- class SupabaseClient:
34
- def __init__(self, *args, **kwargs):
35
- raise NotImplementedError("SupabaseClient не найден. Убедитесь, что supabase_client.py существует в корне проекта")
36
-
37
- class Config:
38
- def __init__(self, *args, **kwargs):
39
- raise NotImplementedError("Config не найден. Убедитесь, что config.py существует в корне проекта")
40
-
41
- class ConversationManager:
42
- def __init__(self, *args, **kwargs):
43
- raise NotImplementedError("ConversationManager не найден. Убедитесь, что conversation_manager.py существует в корне проекта")
44
-
45
- class AdminManager:
46
- def __init__(self, *args, **kwargs):
47
- raise NotImplementedError("AdminManager не найден. Убедитесь, что admin_manager.py существует в корне проекта")
48
-
49
- class PromptLoader:
50
- def __init__(self, *args, **kwargs):
51
- raise NotImplementedError("PromptLoader не найден. Убедитесь, что prompt_loader.py существует в корне проекта")
52
-
53
- # Заглушки для функций
54
- def send_message(*args, **kwargs):
55
- raise NotImplementedError("send_message не найден. Убедитесь, что bot_utils.py существует в корне проекта")
56
-
57
- def parse_ai_response(*args, **kwargs):
58
- raise NotImplementedError("parse_ai_response не найден. Убедитесь, что bot_utils.py существует в корне проекта")
59
-
60
- def process_events(*args, **kwargs):
61
- raise NotImplementedError("process_events не найден. Убедитесь, что bot_utils.py существует в корне проекта")
62
-
63
- # Заглушки для роутера
64
- router = None
65
- setup_handlers = None
66
- setup_admin_handlers = None
67
- setup_utils_handlers = None
68
-
69
- __all__ = [
70
- 'OpenAIClient',
71
- 'SupabaseClient',
72
- 'Config',
73
- 'ConversationManager',
74
- 'AdminManager',
75
- 'PromptLoader',
76
- 'send_message',
77
- 'parse_ai_response',
78
- 'process_events',
79
- 'router',
80
- 'setup_handlers',
81
- 'setup_admin_handlers',
82
- 'setup_utils_handlers'
83
- ]
@@ -1,224 +0,0 @@
1
- """
2
- Интеграция с bot_utils.py для обработки событий
3
- """
4
-
5
- import logging
6
- from typing import List, Dict, Any
7
-
8
- logger = logging.getLogger(__name__)
9
-
10
- async def enhanced_process_events(session_id: str, events: List[Dict[str, Any]], user_id: int):
11
- """
12
- Улучшенная версия process_events из bot_utils.py
13
- с поддержкой декораторов обработчиков событий
14
- """
15
- from ..events.decorators import (
16
- execute_event_handler,
17
- get_event_handlers,
18
- get_scheduled_tasks,
19
- execute_scheduled_task_from_event
20
- )
21
-
22
- logger.info(f"🔔 Обрабатываем {len(events)} событий для пользователя {user_id}")
23
-
24
- for event in events:
25
- try:
26
- event_type = event.get('тип', '')
27
- event_info = event.get('инфо', '')
28
-
29
- if not event_type:
30
- continue
31
-
32
- logger.info(f"📝 Обрабатываем событие: {event_type}")
33
-
34
- # Проверяем, есть ли зарегистрированный обработчик событий
35
- event_handlers = get_event_handlers()
36
- scheduled_tasks = get_scheduled_tasks()
37
-
38
- if event_type in event_handlers:
39
- # Используем зарегистрированный обработчик событий
40
- logger.info(f"🔧 Используем зарегистрированный обработчик для '{event_type}'")
41
-
42
- try:
43
- # Парсим event_info если это строка
44
- if isinstance(event_info, str):
45
- event_data = _parse_event_info(event_info, user_id)
46
- else:
47
- event_data = event_info
48
-
49
- # Вызываем обработчик
50
- result = await execute_event_handler(event_type, user_id, event_data)
51
- logger.info(f"✅ Обработчик '{event_type}' выполнен: {result}")
52
-
53
- except Exception as e:
54
- logger.error(f"❌ Ошибка в обработчике '{event_type}': {e}")
55
- # Fallback к стандартной обработке
56
- await _fallback_event_processing(session_id, event_type, event_info, user_id)
57
-
58
- elif event_type in scheduled_tasks:
59
- # Это запланированная задача - парсим время из event_info
60
- logger.info(f"⏰ Планируем задачу '{event_type}' на основе event_info: {event_info}")
61
-
62
- try:
63
- result = await execute_scheduled_task_from_event(user_id, event_type, event_info)
64
- logger.info(f"✅ Задача '{event_type}' запланирована: {result}")
65
-
66
- except Exception as e:
67
- logger.error(f"❌ Ошибка в планировании задачи '{event_type}': {e}")
68
- # Fallback к стандартной обработке
69
- await _fallback_event_processing(session_id, event_type, event_info, user_id)
70
- else:
71
- # Используем стандартную обработку из bot_utils.py
72
- logger.info(f"📋 Используем стандартную обработку для '{event_type}'")
73
- await _fallback_event_processing(session_id, event_type, event_info, user_id)
74
-
75
- except Exception as e:
76
- logger.error(f"❌ Ошибка при обработке события {event}: {e}")
77
-
78
- def _parse_event_info(event_info: str, user_id: int) -> Dict[str, Any]:
79
- """
80
- Парсит строку event_info и извлекает структурированные данные
81
- """
82
- # Простой парсинг для типичных случаев
83
- # Например: "Иван Петров, +7-999-123-45-67, интересуется имплантацией"
84
-
85
- data = {
86
- "user_id": user_id,
87
- "raw_info": event_info
88
- }
89
-
90
- # Пытаемся извлечь телефон
91
- import re
92
- phone_match = re.search(r'\+?[7-8]?[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}', event_info)
93
- if phone_match:
94
- data["phone"] = phone_match.group(0)
95
-
96
- # Пытаемся извлечь имя (первое слово)
97
- words = event_info.split(',')
98
- if words:
99
- data["name"] = words[0].strip()
100
-
101
- # Пытаемся извлечь услугу/интерес
102
- if len(words) > 2:
103
- data["interest"] = words[2].strip()
104
-
105
- return data
106
-
107
- async def _fallback_event_processing(session_id: str, event_type: str, event_info: str, user_id: int):
108
- """
109
- Стандартная обработка событий (из оригинального bot_utils.py)
110
- """
111
- # Импортируем оригинальную функцию
112
- import sys
113
- from pathlib import Path
114
-
115
- # Добавляем корень проекта в путь
116
- project_root = Path(__file__).parent.parent.parent.parent
117
- if str(project_root) not in sys.path:
118
- sys.path.insert(0, str(project_root))
119
-
120
- try:
121
- from supabase_client import SupabaseClient
122
- from main import supabase_client
123
-
124
- # Сохраняем в БД
125
- await supabase_client.add_session_event(session_id, event_type, event_info)
126
-
127
- # Уведомляем админов
128
- await _notify_admins_about_event(user_id, {
129
- 'тип': event_type,
130
- 'инфо': event_info
131
- })
132
-
133
- except ImportError:
134
- logger.warning("Не удалось импортировать оригинальные модули для fallback обработки")
135
-
136
- async def _notify_admins_about_event(user_id: int, event: Dict[str, Any]):
137
- """
138
- Уведомление админов о событии (из оригинального bot_utils.py)
139
- """
140
- try:
141
- import sys
142
- from pathlib import Path
143
-
144
- # Добавляем корень проекта в путь
145
- project_root = Path(__file__).parent.parent.parent.parent
146
- if str(project_root) not in sys.path:
147
- sys.path.insert(0, str(project_root))
148
-
149
- from main import supabase_client, admin_manager, bot
150
- from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
151
- from datetime import datetime
152
-
153
- event_type = event.get('тип', '')
154
- event_info = event.get('инфо', '')
155
-
156
- if not event_type:
157
- return
158
-
159
- # Получаем информацию о пользователе
160
- try:
161
- user_response = supabase_client.client.table('sales_users').select(
162
- 'first_name', 'last_name', 'username'
163
- ).eq('telegram_id', user_id).execute()
164
-
165
- user_info = user_response.data[0] if user_response.data else {}
166
-
167
- # Формируем имя пользователя
168
- name_parts = []
169
- if user_info.get('first_name'):
170
- name_parts.append(user_info['first_name'])
171
- if user_info.get('last_name'):
172
- name_parts.append(user_info['last_name'])
173
-
174
- user_name = " ".join(name_parts) if name_parts else "Без имени"
175
-
176
- # Формируем отображение пользователя
177
- if user_info.get('username'):
178
- user_display = f"{user_name} (@{user_info['username']})"
179
- else:
180
- user_display = user_name
181
-
182
- except Exception as e:
183
- logger.error(f"Ошибка получения информации о пользователе {user_id}: {e}")
184
- user_display = "Пользователь"
185
-
186
- # Маппинг эмодзи
187
- emoji_map = {
188
- 'телефон': '📱',
189
- 'консультация': '💬',
190
- 'покупка': '💰',
191
- 'отказ': '❌',
192
- 'appointment_booking': '📅',
193
- 'phone_collection': '📱'
194
- }
195
-
196
- emoji = emoji_map.get(event_type, '🔔')
197
-
198
- # Формируем уведомление
199
- notification = f"""
200
- {emoji} {event_type.upper()}!
201
- 👤 {user_display}
202
- 🆔 ID: {user_id}
203
- 📝 {event_info}
204
- 🕐 {datetime.now().strftime('%H:%M')}
205
- """
206
-
207
- # Создаем клавиатуру
208
- keyboard = InlineKeyboardMarkup(inline_keyboard=[
209
- [
210
- InlineKeyboardButton(text="💬 Чат", callback_data=f"admin_chat_{user_id}"),
211
- InlineKeyboardButton(text="📋 История", callback_data=f"admin_history_{user_id}")
212
- ]
213
- ])
214
-
215
- # Отправляем всем активным админам
216
- active_admins = await admin_manager.get_active_admins()
217
- for admin_id in active_admins:
218
- try:
219
- await bot.send_message(admin_id, notification.strip(), reply_markup=keyboard)
220
- except Exception as e:
221
- logger.error(f"Ошибка отправки уведомления админу {admin_id}: {e}")
222
-
223
- except Exception as e:
224
- logger.error(f"Ошибка отправки уведомления админам: {e}")
@@ -1,12 +0,0 @@
1
- """
2
- Сервисы для работы с внешними API
3
- """
4
-
5
- from .telegram_integration import TelegramIntegration
6
- from .message_sender import send_message_by_ai, send_message_by_human
7
-
8
- __all__ = [
9
- 'TelegramIntegration',
10
- 'send_message_by_ai',
11
- 'send_message_by_human'
12
- ]
@@ -1,235 +0,0 @@
1
- """
2
- Функции для отправки сообщений через ИИ и от человека
3
- """
4
-
5
- import logging
6
- import time
7
- from datetime import datetime
8
- from typing import Dict, Any, Optional
9
- import pytz
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
- async def send_message_by_ai(
14
- user_id: int,
15
- message_text: str,
16
- session_id: str = None,
17
- system_prompt: str = None
18
- ) -> Dict[str, Any]:
19
- """
20
- Отправляет сообщение пользователю через ИИ (копирует логику process_user_message)
21
-
22
- Args:
23
- user_id: ID пользователя в Telegram
24
- message_text: Текст сообщения для обработки ИИ
25
- session_id: ID сессии чата
26
- system_prompt: Системный промпт для ИИ
27
-
28
- Returns:
29
- Результат отправки
30
- """
31
- try:
32
- # Импортируем необходимые компоненты
33
- from ..integrations import supabase_client, openai_client, config, bot, prompt_loader, parse_ai_response, process_events
34
-
35
- # Если session_id не указан, получаем активную сессию пользователя
36
- if not session_id:
37
- session_info = await supabase_client.get_active_session(user_id)
38
- if not session_info:
39
- return {
40
- "status": "error",
41
- "error": "Активная сессия не найдена",
42
- "user_id": user_id
43
- }
44
- session_id = session_info['id']
45
-
46
- # Если system_prompt не указан, получаем из сессии
47
- if not system_prompt:
48
- session_info = await supabase_client.get_session_info(session_id)
49
- if not session_info:
50
- return {
51
- "status": "error",
52
- "error": "Информация о сессии не найдена",
53
- "user_id": user_id
54
- }
55
- system_prompt = session_info['system_prompt']
56
-
57
- # Сохраняем сообщение пользователя в БД
58
- await supabase_client.add_message(
59
- session_id=session_id,
60
- role='user',
61
- content=message_text,
62
- message_type='text'
63
- )
64
- logger.info(f"✅ Сообщение пользователя сохранено в БД")
65
-
66
- # Получаем историю сообщений
67
- chat_history = await supabase_client.get_chat_history(session_id, limit=config.MAX_CONTEXT_MESSAGES)
68
- logger.info(f"📚 Загружена история: {len(chat_history)} сообщений")
69
-
70
- # Добавляем текущее время
71
- moscow_tz = pytz.timezone('Europe/Moscow')
72
- current_time = datetime.now(moscow_tz)
73
- time_info = current_time.strftime('%H:%M, %d.%m.%Y, %A')
74
-
75
- # Модифицируем системный промпт, добавляя время
76
- system_prompt_with_time = f"""
77
- {system_prompt}
78
-
79
- ТЕКУЩЕЕ ВРЕМЯ: {time_info} (московское время)
80
- """
81
-
82
- # Формируем контекст для OpenAI
83
- messages = [{"role": "system", "content": system_prompt_with_time}]
84
-
85
- for msg in chat_history[-config.MAX_CONTEXT_MESSAGES:]:
86
- messages.append({
87
- "role": msg['role'],
88
- "content": msg['content']
89
- })
90
-
91
- # Добавляем финальные инструкции
92
- final_instructions = await prompt_loader.load_final_instructions()
93
- if final_instructions:
94
- messages.append({"role": "system", "content": final_instructions})
95
- logger.info(f"🎯 Добавлены финальные инструкции")
96
-
97
- logger.info(f"📝 Контекст сформирован: {len(messages)} сообщений")
98
-
99
- # Отправляем действие "печатает"
100
- await bot.send_chat_action(user_id, "typing")
101
-
102
- # Получаем ответ от ИИ
103
- start_time = time.time()
104
- ai_response = await openai_client.get_completion(messages)
105
- processing_time = int((time.time() - start_time) * 1000)
106
-
107
- logger.info(f"🤖 OpenAI ответил за {processing_time}мс")
108
-
109
- # Обрабатываем ответ
110
- tokens_used = 0
111
- ai_metadata = {}
112
- response_text = ""
113
-
114
- if not ai_response or not ai_response.strip():
115
- logger.warning(f"❌ OpenAI вернул пустой ответ!")
116
- fallback_message = "Извините, произошла техническая ошибка. Попробуйте переформулировать вопрос."
117
- ai_response = fallback_message
118
- response_text = fallback_message
119
- else:
120
- tokens_used = openai_client.estimate_tokens(ai_response)
121
- response_text, ai_metadata = parse_ai_response(ai_response)
122
-
123
- if not ai_metadata:
124
- response_text = ai_response
125
- ai_metadata = {}
126
- elif not response_text.strip():
127
- response_text = ai_response
128
-
129
- # Обновляем этап сессии и качество лида
130
- if ai_metadata:
131
- stage = ai_metadata.get('этап')
132
- quality = ai_metadata.get('качество')
133
-
134
- if stage or quality is not None:
135
- await supabase_client.update_session_stage(session_id, stage, quality)
136
- logger.info(f"✅ Этап и качество обновлены в БД")
137
-
138
- # Обрабатываем события
139
- events = ai_metadata.get('события', [])
140
- if events:
141
- logger.info(f"🔔 Обрабатываем {len(events)} событий")
142
- await process_events(session_id, events, user_id)
143
-
144
- # Сохраняем ответ ассистента
145
- await supabase_client.add_message(
146
- session_id=session_id,
147
- role='assistant',
148
- content=response_text,
149
- message_type='text',
150
- tokens_used=tokens_used,
151
- processing_time_ms=processing_time,
152
- ai_metadata=ai_metadata
153
- )
154
-
155
- # Определяем финальный ответ
156
- if config.DEBUG_MODE:
157
- final_response = ai_response
158
- else:
159
- final_response = response_text
160
-
161
- # Отправляем ответ пользователю напрямую через бота
162
- await bot.send_message(
163
- chat_id=user_id,
164
- text=final_response
165
- )
166
-
167
- return {
168
- "status": "success",
169
- "user_id": user_id,
170
- "response_text": response_text,
171
- "tokens_used": tokens_used,
172
- "processing_time_ms": processing_time,
173
- "events_processed": len(events) if events else 0
174
- }
175
-
176
- except Exception as e:
177
- logger.error(f"❌ Ошибка в send_message_by_ai: {e}")
178
- return {
179
- "status": "error",
180
- "error": str(e),
181
- "user_id": user_id
182
- }
183
-
184
- async def send_message_by_human(
185
- user_id: int,
186
- message_text: str,
187
- session_id: Optional[str] = None
188
- ) -> Dict[str, Any]:
189
- """
190
- Отправляет сообщение пользователю от имени человека (готовый текст)
191
-
192
- Args:
193
- user_id: ID пользователя в Telegram
194
- message_text: Готовый текст сообщения
195
- session_id: ID сессии (опционально, для сохранения в БД)
196
-
197
- Returns:
198
- Результат отправки
199
- """
200
- try:
201
- # Импортируем необходимые компоненты
202
- from ..integrations import bot, supabase_client
203
-
204
- # Отправляем сообщение пользователю
205
- message = await bot.send_message(
206
- chat_id=user_id,
207
- text=message_text
208
- )
209
-
210
- # Если указана сессия, сохраняем сообщение в БД
211
- if session_id:
212
- await supabase_client.add_message(
213
- session_id=session_id,
214
- role='assistant',
215
- content=message_text,
216
- message_type='text',
217
- metadata={'sent_by_human': True}
218
- )
219
- logger.info(f"💾 Сообщение от человека сохранено в БД")
220
-
221
- return {
222
- "status": "success",
223
- "user_id": user_id,
224
- "message_id": message.message_id,
225
- "message_text": message_text,
226
- "saved_to_db": bool(session_id)
227
- }
228
-
229
- except Exception as e:
230
- logger.error(f"❌ Ошибка в send_message_by_human: {e}")
231
- return {
232
- "status": "error",
233
- "error": str(e),
234
- "user_id": user_id
235
- }