smart-bot-factory 1.1.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.
- smart_bot_factory/__init__.py +3 -0
- smart_bot_factory/admin/__init__.py +18 -0
- smart_bot_factory/admin/admin_events.py +1223 -0
- smart_bot_factory/admin/admin_logic.py +553 -0
- smart_bot_factory/admin/admin_manager.py +156 -0
- smart_bot_factory/admin/admin_tester.py +157 -0
- smart_bot_factory/admin/timeout_checker.py +547 -0
- smart_bot_factory/aiogram_calendar/__init__.py +14 -0
- smart_bot_factory/aiogram_calendar/common.py +64 -0
- smart_bot_factory/aiogram_calendar/dialog_calendar.py +259 -0
- smart_bot_factory/aiogram_calendar/schemas.py +99 -0
- smart_bot_factory/aiogram_calendar/simple_calendar.py +224 -0
- smart_bot_factory/analytics/analytics_manager.py +414 -0
- smart_bot_factory/cli.py +806 -0
- smart_bot_factory/config.py +258 -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 +133 -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/bot_utils.py +1108 -0
- smart_bot_factory/core/conversation_manager.py +653 -0
- smart_bot_factory/core/decorators.py +2464 -0
- smart_bot_factory/core/message_sender.py +729 -0
- smart_bot_factory/core/router.py +347 -0
- smart_bot_factory/core/router_manager.py +218 -0
- smart_bot_factory/core/states.py +27 -0
- smart_bot_factory/creation/__init__.py +7 -0
- smart_bot_factory/creation/bot_builder.py +1093 -0
- smart_bot_factory/creation/bot_testing.py +1122 -0
- smart_bot_factory/dashboard/__init__.py +3 -0
- smart_bot_factory/event/__init__.py +7 -0
- smart_bot_factory/handlers/handlers.py +2013 -0
- smart_bot_factory/integrations/langchain_openai.py +542 -0
- smart_bot_factory/integrations/openai_client.py +513 -0
- smart_bot_factory/integrations/supabase_client.py +1678 -0
- smart_bot_factory/memory/__init__.py +8 -0
- smart_bot_factory/memory/memory_manager.py +299 -0
- smart_bot_factory/memory/static_memory.py +214 -0
- smart_bot_factory/message/__init__.py +56 -0
- smart_bot_factory/rag/__init__.py +5 -0
- smart_bot_factory/rag/decorators.py +29 -0
- smart_bot_factory/rag/router.py +54 -0
- smart_bot_factory/rag/templates/__init__.py +3 -0
- smart_bot_factory/rag/templates/create_table.sql +7 -0
- smart_bot_factory/rag/templates/create_table_and_function_template.py +94 -0
- smart_bot_factory/rag/templates/match_function.sql +61 -0
- smart_bot_factory/rag/templates/match_services_template.py +82 -0
- smart_bot_factory/rag/vectorstore.py +449 -0
- smart_bot_factory/router/__init__.py +10 -0
- smart_bot_factory/setup_checker.py +512 -0
- smart_bot_factory/supabase/__init__.py +7 -0
- smart_bot_factory/supabase/client.py +631 -0
- smart_bot_factory/utils/__init__.py +11 -0
- smart_bot_factory/utils/debug_routing.py +114 -0
- smart_bot_factory/utils/prompt_loader.py +529 -0
- smart_bot_factory/utils/tool_router.py +68 -0
- smart_bot_factory/utils/user_prompt_loader.py +55 -0
- smart_bot_factory/utm_link_generator.py +123 -0
- smart_bot_factory-1.1.1.dist-info/METADATA +1135 -0
- smart_bot_factory-1.1.1.dist-info/RECORD +73 -0
- smart_bot_factory-1.1.1.dist-info/WHEEL +4 -0
- smart_bot_factory-1.1.1.dist-info/entry_points.txt +2 -0
- smart_bot_factory-1.1.1.dist-info/licenses/LICENSE +24 -0
smart_bot_factory/cli.py
ADDED
|
@@ -0,0 +1,806 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI интерфейс для Smart Bot Factory
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from project_root_finder import root
|
|
13
|
+
|
|
14
|
+
PROJECT_ROOT = root
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group()
|
|
18
|
+
def cli():
|
|
19
|
+
"""Smart Bot Factory - инструмент для создания умных чат-ботов"""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@cli.command()
|
|
24
|
+
@click.argument("bot_id")
|
|
25
|
+
@click.argument("template", required=False, default="base")
|
|
26
|
+
def create(bot_id: str, template: str = "base"):
|
|
27
|
+
"""Создать нового бота"""
|
|
28
|
+
success = create_new_bot_structure(template, bot_id)
|
|
29
|
+
if not success:
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@cli.command()
|
|
34
|
+
def list():
|
|
35
|
+
"""Показать список доступных ботов"""
|
|
36
|
+
bots = list_bots_in_bots_folder()
|
|
37
|
+
if not bots:
|
|
38
|
+
click.echo("🤖 Нет доступных ботов")
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
click.echo("🤖 Доступные боты:")
|
|
42
|
+
for bot in sorted(bots):
|
|
43
|
+
click.echo(f" 📱 {bot}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@cli.command()
|
|
47
|
+
@click.argument("bot_id")
|
|
48
|
+
def run(bot_id: str):
|
|
49
|
+
"""Запустить бота"""
|
|
50
|
+
try:
|
|
51
|
+
# Проверяем существование бота
|
|
52
|
+
bot_path = PROJECT_ROOT / Path("bots") / bot_id
|
|
53
|
+
if not bot_path.exists():
|
|
54
|
+
raise click.ClickException(f"Бот {bot_id} не найден в папке bots/")
|
|
55
|
+
|
|
56
|
+
# Проверяем наличие основного файла бота в корневой директории
|
|
57
|
+
bot_file = PROJECT_ROOT / Path(f"{bot_id}.py")
|
|
58
|
+
if not bot_file.exists():
|
|
59
|
+
raise click.ClickException(
|
|
60
|
+
f"Файл {bot_id}.py не найден в корневой директории"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Проверяем наличие .env файла
|
|
64
|
+
env_file = bot_path / ".env"
|
|
65
|
+
if not env_file.exists():
|
|
66
|
+
raise click.ClickException(f"Файл .env не найден для бота {bot_id}")
|
|
67
|
+
|
|
68
|
+
# Настраиваем окружение для бота
|
|
69
|
+
from dotenv import load_dotenv
|
|
70
|
+
|
|
71
|
+
# Добавляем корень проекта в sys.path
|
|
72
|
+
sys.path.insert(0, str(PROJECT_ROOT))
|
|
73
|
+
|
|
74
|
+
# Загружаем .env файл
|
|
75
|
+
load_dotenv(env_file)
|
|
76
|
+
click.echo(f"📄 Загружен .env файл: {env_file}")
|
|
77
|
+
|
|
78
|
+
# Устанавливаем переменные окружения
|
|
79
|
+
os.environ["BOT_ID"] = bot_id
|
|
80
|
+
|
|
81
|
+
# Устанавливаем путь к промптам
|
|
82
|
+
prompts_dir = bot_path / "prompts"
|
|
83
|
+
if prompts_dir.exists():
|
|
84
|
+
os.environ["PROMT_FILES_DIR"] = str(prompts_dir)
|
|
85
|
+
click.echo(f"📝 Установлен путь к промптам: {prompts_dir}")
|
|
86
|
+
|
|
87
|
+
# Запускаем бота из корневой директории
|
|
88
|
+
click.echo(f"🚀 Запускаем бота {bot_id}...")
|
|
89
|
+
subprocess.run(
|
|
90
|
+
[sys.executable, str(bot_file)], check=True, cwd=str(PROJECT_ROOT)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
except subprocess.CalledProcessError as e:
|
|
94
|
+
click.echo(f"❌ Ошибка при запуске бота: {e}", err=True)
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
click.echo(f"❌ Ошибка: {e}", err=True)
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@cli.command()
|
|
102
|
+
@click.argument("bot_id")
|
|
103
|
+
@click.option("--file", help="Запустить тесты только из указанного файла")
|
|
104
|
+
@click.option("-v", "--verbose", is_flag=True, help="Подробный вывод")
|
|
105
|
+
@click.option("--max-concurrent", default=5, help="Максимальное количество потоков")
|
|
106
|
+
def test(bot_id: str, file: str = None, verbose: bool = False, max_concurrent: int = 5):
|
|
107
|
+
"""Запустить тесты бота"""
|
|
108
|
+
try:
|
|
109
|
+
# Проверяем существование бота
|
|
110
|
+
bot_path = PROJECT_ROOT / "bots" / bot_id
|
|
111
|
+
if not bot_path.exists():
|
|
112
|
+
raise click.ClickException(
|
|
113
|
+
f"Бот {bot_id} не найден в папке {PROJECT_ROOT}/bots/"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Проверяем наличие тестов
|
|
117
|
+
tests_dir = bot_path / "tests"
|
|
118
|
+
if not tests_dir.exists():
|
|
119
|
+
click.echo(f"⚠️ Тесты не найдены для бота {bot_id}")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
# Ищем YAML файлы с тестами
|
|
123
|
+
yaml_files = [str(f.name) for f in tests_dir.glob("*.yaml")]
|
|
124
|
+
|
|
125
|
+
if not yaml_files:
|
|
126
|
+
click.echo(f"⚠️ YAML тесты не найдены для бота {bot_id}")
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
click.echo(f"🧪 Запускаем тесты для бота {bot_id}...")
|
|
130
|
+
|
|
131
|
+
# Формируем команду для запуска
|
|
132
|
+
bot_testing_path = Path(__file__).parent / "creation" / "bot_testing.py"
|
|
133
|
+
cmd = [sys.executable, str(bot_testing_path), bot_id]
|
|
134
|
+
|
|
135
|
+
if file:
|
|
136
|
+
cmd.append(file)
|
|
137
|
+
|
|
138
|
+
if verbose:
|
|
139
|
+
cmd.append("-v")
|
|
140
|
+
|
|
141
|
+
if max_concurrent != 5:
|
|
142
|
+
cmd.extend(["--max-concurrent", str(max_concurrent)])
|
|
143
|
+
|
|
144
|
+
# Запускаем тесты
|
|
145
|
+
result = subprocess.run(cmd, check=False)
|
|
146
|
+
|
|
147
|
+
if result.returncode == 0:
|
|
148
|
+
click.echo("✅ Все тесты пройдены")
|
|
149
|
+
else:
|
|
150
|
+
click.echo("❌ Есть ошибки в тестах")
|
|
151
|
+
sys.exit(1)
|
|
152
|
+
|
|
153
|
+
except subprocess.CalledProcessError as e:
|
|
154
|
+
click.echo(f"❌ Ошибка при запуске тестов: {e}", err=True)
|
|
155
|
+
sys.exit(1)
|
|
156
|
+
except Exception as e:
|
|
157
|
+
click.echo(f"❌ Ошибка: {e}", err=True)
|
|
158
|
+
sys.exit(1)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@cli.command()
|
|
162
|
+
@click.argument("bot_id")
|
|
163
|
+
def config(bot_id: str):
|
|
164
|
+
"""Настроить конфигурацию бота"""
|
|
165
|
+
try:
|
|
166
|
+
# Проверяем существование бота
|
|
167
|
+
bot_path = PROJECT_ROOT / Path("bots") / bot_id
|
|
168
|
+
if not bot_path.exists():
|
|
169
|
+
raise click.ClickException(f"Бот {bot_id} не найден в папке bots/")
|
|
170
|
+
|
|
171
|
+
# Открываем .env файл в редакторе
|
|
172
|
+
env_file = bot_path / ".env"
|
|
173
|
+
if not env_file.exists():
|
|
174
|
+
raise click.ClickException(f"Файл .env не найден для бота {bot_id}")
|
|
175
|
+
|
|
176
|
+
# Определяем редактор
|
|
177
|
+
editor = os.environ.get("EDITOR", "notepad" if os.name == "nt" else "nano")
|
|
178
|
+
|
|
179
|
+
click.echo(f"⚙️ Открываем конфигурацию бота {bot_id}...")
|
|
180
|
+
subprocess.run([editor, str(env_file)], check=True)
|
|
181
|
+
|
|
182
|
+
except subprocess.CalledProcessError as e:
|
|
183
|
+
click.echo(f"❌ Ошибка при открытии редактора: {e}", err=True)
|
|
184
|
+
sys.exit(1)
|
|
185
|
+
except Exception as e:
|
|
186
|
+
click.echo(f"❌ Ошибка: {e}", err=True)
|
|
187
|
+
sys.exit(1)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@cli.command()
|
|
191
|
+
@click.argument("bot_id")
|
|
192
|
+
@click.option("--list", "list_prompts", is_flag=True, help="Показать список промптов")
|
|
193
|
+
@click.option("--edit", "edit_prompt", help="Редактировать промпт")
|
|
194
|
+
@click.option("--add", "add_prompt", help="Добавить новый промпт")
|
|
195
|
+
def prompts(
|
|
196
|
+
bot_id: str,
|
|
197
|
+
list_prompts: bool = False,
|
|
198
|
+
edit_prompt: str = None,
|
|
199
|
+
add_prompt: str = None,
|
|
200
|
+
):
|
|
201
|
+
"""Управление промптами бота"""
|
|
202
|
+
try:
|
|
203
|
+
# Проверяем существование бота
|
|
204
|
+
bot_path = PROJECT_ROOT / Path("bots") / bot_id
|
|
205
|
+
if not bot_path.exists():
|
|
206
|
+
raise click.ClickException(f"Бот {bot_id} не найден в папке bots/")
|
|
207
|
+
|
|
208
|
+
prompts_dir = bot_path / "prompts"
|
|
209
|
+
if not prompts_dir.exists():
|
|
210
|
+
raise click.ClickException(f"Папка промптов не найдена для бота {bot_id}")
|
|
211
|
+
|
|
212
|
+
if list_prompts or (not edit_prompt and not add_prompt):
|
|
213
|
+
# Показываем список промптов (по умолчанию или с флагом --list)
|
|
214
|
+
prompt_files = [f.name for f in prompts_dir.glob("*.txt")]
|
|
215
|
+
|
|
216
|
+
if not prompt_files:
|
|
217
|
+
click.echo("📝 Промпты не найдены")
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
click.echo(f"📝 Промпты бота {bot_id}:")
|
|
221
|
+
for prompt_file in sorted(prompt_files):
|
|
222
|
+
click.echo(f" 📄 {prompt_file[:-4]}")
|
|
223
|
+
|
|
224
|
+
# Показываем справку только если не указан флаг --list
|
|
225
|
+
if not list_prompts:
|
|
226
|
+
click.echo()
|
|
227
|
+
click.echo("Использование:")
|
|
228
|
+
click.echo(
|
|
229
|
+
" sbf prompts <bot_id> --edit <prompt_name> # Редактировать промпт"
|
|
230
|
+
)
|
|
231
|
+
click.echo(
|
|
232
|
+
" sbf prompts <bot_id> --add <prompt_name> # Добавить новый промпт"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
elif edit_prompt:
|
|
236
|
+
# Редактируем промпт
|
|
237
|
+
prompt_file = prompts_dir / f"{edit_prompt}.txt"
|
|
238
|
+
if not prompt_file.exists():
|
|
239
|
+
raise click.ClickException(f"Промпт {edit_prompt} не найден")
|
|
240
|
+
|
|
241
|
+
editor = os.environ.get("EDITOR", "notepad" if os.name == "nt" else "nano")
|
|
242
|
+
click.echo(f"✏️ Редактируем промпт {edit_prompt}...")
|
|
243
|
+
subprocess.run([editor, str(prompt_file)], check=True)
|
|
244
|
+
|
|
245
|
+
elif add_prompt:
|
|
246
|
+
# Добавляем новый промпт
|
|
247
|
+
prompt_file = prompts_dir / f"{add_prompt}.txt"
|
|
248
|
+
if prompt_file.exists():
|
|
249
|
+
raise click.ClickException(f"Промпт {add_prompt} уже существует")
|
|
250
|
+
|
|
251
|
+
# Создаем файл с базовым содержимым
|
|
252
|
+
prompt_file.write_text(
|
|
253
|
+
f"# Промпт: {add_prompt}\n\n" "Введите содержимое промпта здесь...",
|
|
254
|
+
encoding="utf-8",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Открываем в редакторе
|
|
258
|
+
editor = os.environ.get("EDITOR", "notepad" if os.name == "nt" else "nano")
|
|
259
|
+
click.echo(f"📝 Создаем новый промпт {add_prompt}...")
|
|
260
|
+
subprocess.run([editor, str(prompt_file)], check=True)
|
|
261
|
+
|
|
262
|
+
except subprocess.CalledProcessError as e:
|
|
263
|
+
click.echo(f"❌ Ошибка при открытии редактора: {e}", err=True)
|
|
264
|
+
sys.exit(1)
|
|
265
|
+
except Exception as e:
|
|
266
|
+
click.echo(f"❌ Ошибка: {e}", err=True)
|
|
267
|
+
sys.exit(1)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@cli.command()
|
|
271
|
+
def path():
|
|
272
|
+
"""Показать путь к проекту"""
|
|
273
|
+
click.echo(PROJECT_ROOT)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@cli.command()
|
|
277
|
+
@click.argument("bot_id")
|
|
278
|
+
@click.option("--force", "-f", is_flag=True, help="Удалить без подтверждения")
|
|
279
|
+
def rm(bot_id: str, force: bool = False):
|
|
280
|
+
"""Удалить бота и все его файлы"""
|
|
281
|
+
try:
|
|
282
|
+
# Проверяем существование бота
|
|
283
|
+
bot_path = PROJECT_ROOT / Path("bots") / bot_id
|
|
284
|
+
if not bot_path.exists():
|
|
285
|
+
raise click.ClickException(f"🤖 Бот {bot_id} не найден в папке bots/")
|
|
286
|
+
|
|
287
|
+
# Проверяем наличие основного файла бота в корневой директории
|
|
288
|
+
bot_file = Path(f"{bot_id}.py")
|
|
289
|
+
if not bot_file.exists():
|
|
290
|
+
raise click.ClickException(
|
|
291
|
+
f"📄 Файл {bot_id}.py не найден в корневой директории"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Показываем что будет удалено
|
|
295
|
+
click.echo("🗑️ Будет удалено:")
|
|
296
|
+
click.echo(f" 📄 Файл запускалки: {bot_file}")
|
|
297
|
+
click.echo(f" 📁 Папка бота: {bot_path}")
|
|
298
|
+
|
|
299
|
+
# Запрашиваем подтверждение если не указан --force
|
|
300
|
+
if not force:
|
|
301
|
+
if not click.confirm(f"⚠️ Вы уверены, что хотите удалить бота {bot_id}?"):
|
|
302
|
+
click.echo("❌ Удаление отменено")
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
# Удаляем файл запускалки
|
|
306
|
+
if bot_file.exists():
|
|
307
|
+
bot_file.unlink()
|
|
308
|
+
click.echo(f"✅ Файл {bot_file} удален")
|
|
309
|
+
|
|
310
|
+
# Удаляем папку бота
|
|
311
|
+
if bot_path.exists():
|
|
312
|
+
import shutil
|
|
313
|
+
|
|
314
|
+
shutil.rmtree(bot_path)
|
|
315
|
+
click.echo(f"✅ Папка {bot_path} удалена")
|
|
316
|
+
|
|
317
|
+
click.echo(f"🎉 Бот {bot_id} полностью удален")
|
|
318
|
+
|
|
319
|
+
except Exception as e:
|
|
320
|
+
click.echo(f"❌ Ошибка при удалении бота: {e}", err=True)
|
|
321
|
+
sys.exit(1)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@cli.command()
|
|
325
|
+
@click.argument("source_bot_id")
|
|
326
|
+
@click.argument("new_bot_id")
|
|
327
|
+
@click.option(
|
|
328
|
+
"--force",
|
|
329
|
+
"-f",
|
|
330
|
+
is_flag=True,
|
|
331
|
+
help="Перезаписать существующего бота без подтверждения",
|
|
332
|
+
)
|
|
333
|
+
def copy(source_bot_id: str, new_bot_id: str, force: bool = False):
|
|
334
|
+
"""Скопировать существующего бота как шаблон"""
|
|
335
|
+
try:
|
|
336
|
+
# Проверяем существование исходного бота
|
|
337
|
+
source_bot_path = PROJECT_ROOT / "bots" / source_bot_id
|
|
338
|
+
if not source_bot_path.exists():
|
|
339
|
+
raise click.ClickException(
|
|
340
|
+
f"Исходный бот {source_bot_id} не найден в папке bots/"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Проверяем наличие файла запускалки исходного бота
|
|
344
|
+
source_bot_file = PROJECT_ROOT / f"{source_bot_id}.py"
|
|
345
|
+
if not source_bot_file.exists():
|
|
346
|
+
raise click.ClickException(
|
|
347
|
+
f"Файл запускалки {source_bot_id}.py не найден в корневой директории"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# Проверяем, не существует ли уже новый бот
|
|
351
|
+
new_bot_path = PROJECT_ROOT / "bots" / new_bot_id
|
|
352
|
+
new_bot_file = PROJECT_ROOT / f"{new_bot_id}.py"
|
|
353
|
+
|
|
354
|
+
if new_bot_path.exists() or new_bot_file.exists():
|
|
355
|
+
if not force:
|
|
356
|
+
if not click.confirm(f"Бот {new_bot_id} уже существует. Перезаписать?"):
|
|
357
|
+
click.echo("Копирование отменено")
|
|
358
|
+
return
|
|
359
|
+
else:
|
|
360
|
+
click.echo(f"⚠️ Перезаписываем существующего бота {new_bot_id}")
|
|
361
|
+
|
|
362
|
+
# Копируем бота
|
|
363
|
+
click.echo(f"📋 Копируем бота {source_bot_id} → {new_bot_id}...")
|
|
364
|
+
copy_bot_template(source_bot_id, new_bot_id)
|
|
365
|
+
|
|
366
|
+
click.echo(f"✅ Бот {new_bot_id} успешно скопирован из {source_bot_id}")
|
|
367
|
+
click.echo("📝 Не забудьте настроить .env файл для нового бота")
|
|
368
|
+
|
|
369
|
+
except Exception as e:
|
|
370
|
+
click.echo(f"❌ Ошибка при копировании бота: {e}", err=True)
|
|
371
|
+
sys.exit(1)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
@cli.command()
|
|
375
|
+
def link():
|
|
376
|
+
"""Создать UTM-ссылку для бота"""
|
|
377
|
+
try:
|
|
378
|
+
# Проверяем наличие скрипта генерации ссылок
|
|
379
|
+
link_script = Path(__file__).parent / "utm_link_generator.py"
|
|
380
|
+
if not link_script.exists():
|
|
381
|
+
raise click.ClickException("Скрипт utm_link_generator.py не найден")
|
|
382
|
+
|
|
383
|
+
# Запускаем скрипт генерации ссылок
|
|
384
|
+
click.echo("🔗 Запускаем генератор UTM-ссылок...")
|
|
385
|
+
subprocess.run([sys.executable, str(link_script)], check=True)
|
|
386
|
+
|
|
387
|
+
except subprocess.CalledProcessError as e:
|
|
388
|
+
click.echo(f"❌ Ошибка при запуске генератора ссылок: {e}", err=True)
|
|
389
|
+
sys.exit(1)
|
|
390
|
+
except Exception as e:
|
|
391
|
+
click.echo(f"❌ Ошибка: {e}", err=True)
|
|
392
|
+
sys.exit(1)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def create_new_bot_structure(template: str, bot_id: str) -> bool:
|
|
396
|
+
"""Создает новую структуру бота в папке bots/"""
|
|
397
|
+
try:
|
|
398
|
+
# Создаем папку bots если её нет
|
|
399
|
+
bots_dir = PROJECT_ROOT / Path("bots")
|
|
400
|
+
bots_dir.mkdir(exist_ok=True)
|
|
401
|
+
|
|
402
|
+
# Создаем папку для нового бота
|
|
403
|
+
bot_dir = bots_dir / bot_id
|
|
404
|
+
if bot_dir.exists():
|
|
405
|
+
click.echo(f"⚠️ Бот {bot_id} уже существует")
|
|
406
|
+
return False
|
|
407
|
+
|
|
408
|
+
bot_dir.mkdir()
|
|
409
|
+
|
|
410
|
+
# Создаем структуру папок
|
|
411
|
+
(bot_dir / "prompts").mkdir()
|
|
412
|
+
(bot_dir / "tests").mkdir()
|
|
413
|
+
(bot_dir / "reports").mkdir()
|
|
414
|
+
(bot_dir / "welcome_files").mkdir()
|
|
415
|
+
(bot_dir / "files").mkdir()
|
|
416
|
+
|
|
417
|
+
if template == "base":
|
|
418
|
+
# Используем growthmed-october-24 как базовый шаблон
|
|
419
|
+
copy_from_growthmed_template(bot_dir, bot_id)
|
|
420
|
+
else:
|
|
421
|
+
# Используем другой шаблон из папки bots
|
|
422
|
+
copy_from_bot_template(template, bot_dir, bot_id)
|
|
423
|
+
|
|
424
|
+
click.echo(f"✅ Бот {bot_id} создан в папке bots/{bot_id}/")
|
|
425
|
+
click.echo("📝 Не забудьте настроить .env файл перед запуском")
|
|
426
|
+
return True
|
|
427
|
+
|
|
428
|
+
except Exception as e:
|
|
429
|
+
click.echo(f"❌ Ошибка при создании бота: {e}")
|
|
430
|
+
return False
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def list_bots_in_bots_folder() -> list:
|
|
434
|
+
"""Возвращает список ботов из папки bots/"""
|
|
435
|
+
bots_dir = PROJECT_ROOT / Path("bots")
|
|
436
|
+
if not bots_dir.exists():
|
|
437
|
+
return []
|
|
438
|
+
|
|
439
|
+
bots = []
|
|
440
|
+
for item in bots_dir.iterdir():
|
|
441
|
+
if item.is_dir() and Path(f"{item.name}.py").exists():
|
|
442
|
+
bots.append(item.name)
|
|
443
|
+
|
|
444
|
+
return bots
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def create_bot_template(bot_id: str) -> str:
|
|
448
|
+
"""Создает шаблон основного файла бота"""
|
|
449
|
+
return f'''"""
|
|
450
|
+
{bot_id.replace("-", " ").title()} Bot - Умный Telegram бот на Smart Bot Factory
|
|
451
|
+
"""
|
|
452
|
+
|
|
453
|
+
import asyncio
|
|
454
|
+
from smart_bot_factory.router import EventRouter
|
|
455
|
+
from smart_bot_factory.message import send_message_by_human
|
|
456
|
+
from smart_bot_factory.creation import BotBuilder
|
|
457
|
+
|
|
458
|
+
# Инициализация
|
|
459
|
+
event_router = EventRouter("{bot_id}")
|
|
460
|
+
bot_builder = BotBuilder("{bot_id}")
|
|
461
|
+
|
|
462
|
+
# =============================================================================
|
|
463
|
+
# ОБРАБОТЧИКИ СОБЫТИЙ
|
|
464
|
+
# =============================================================================
|
|
465
|
+
|
|
466
|
+
@event_router.event_handler("collect_contact", notify=True, once_only=True)
|
|
467
|
+
async def handle_contact(user_id: int, contact_data: str):
|
|
468
|
+
"""
|
|
469
|
+
Обрабатывает получение контактных данных
|
|
470
|
+
|
|
471
|
+
ИИ создает: {{"тип": "collect_contact", "инфо": "+79001234567"}}
|
|
472
|
+
"""
|
|
473
|
+
await send_message_by_human(
|
|
474
|
+
user_id=user_id,
|
|
475
|
+
message_text=f"✅ Спасибо! Ваши данные сохранены: {{contact_data}}"
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
return {{"status": "success", "contact": contact_data}}
|
|
479
|
+
|
|
480
|
+
# =============================================================================
|
|
481
|
+
# ЗАПУСК
|
|
482
|
+
# =============================================================================
|
|
483
|
+
|
|
484
|
+
async def main():
|
|
485
|
+
# ========== РЕГИСТРАЦИЯ РОУТЕРОВ ==========
|
|
486
|
+
bot_builder.register_routers(event_router)
|
|
487
|
+
|
|
488
|
+
# Можно добавить Telegram роутеры:
|
|
489
|
+
# from aiogram import Router
|
|
490
|
+
# telegram_router = Router(name="commands")
|
|
491
|
+
# bot_builder.register_telegram_router(telegram_router)
|
|
492
|
+
|
|
493
|
+
# ========== КАСТОМИЗАЦИЯ (до build) ==========
|
|
494
|
+
# Установить кастомный PromptLoader:
|
|
495
|
+
# from smart_bot_factory.utils import UserPromptLoader
|
|
496
|
+
# custom_loader = UserPromptLoader("{bot_id}")
|
|
497
|
+
# bot_builder.set_prompt_loader(custom_loader)
|
|
498
|
+
|
|
499
|
+
# ========== СБОРКА И ЗАПУСК ==========
|
|
500
|
+
await bot_builder.build()
|
|
501
|
+
await bot_builder.start()
|
|
502
|
+
|
|
503
|
+
if __name__ == "__main__":
|
|
504
|
+
asyncio.run(main())
|
|
505
|
+
'''
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def create_env_template(bot_id: str) -> str:
|
|
509
|
+
"""Создает шаблон .env файла"""
|
|
510
|
+
return f"""# Telegram
|
|
511
|
+
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
|
|
512
|
+
|
|
513
|
+
# Supabase
|
|
514
|
+
SUPABASE_URL=https://your-project.supabase.co
|
|
515
|
+
SUPABASE_KEY=your_supabase_anon_key
|
|
516
|
+
|
|
517
|
+
# OpenAI
|
|
518
|
+
OPENAI_API_KEY=sk-your-openai-api-key
|
|
519
|
+
OPENAI_MODEL=gpt-5-mini
|
|
520
|
+
OPENAI_MAX_TOKENS=1500
|
|
521
|
+
OPENAI_TEMPERATURE=0.7
|
|
522
|
+
|
|
523
|
+
# Промпты (каталог)
|
|
524
|
+
PROMT_FILES_DIR=prompts
|
|
525
|
+
|
|
526
|
+
# Файл после приветствия с подписью (если он есть - грузим его в папку welcome_file, если нет - ничего не делаем)
|
|
527
|
+
WELCOME_FILE_URL=welcome_files/
|
|
528
|
+
WELCOME_FILE_MSG=welcome_file_msg.txt
|
|
529
|
+
|
|
530
|
+
# 🆕 Администраторы (через запятую)
|
|
531
|
+
# Укажите Telegram ID админов
|
|
532
|
+
ADMIN_TELEGRAM_IDS=123456789,987654321
|
|
533
|
+
ADMIN_SESSION_TIMEOUT_MINUTES=30
|
|
534
|
+
|
|
535
|
+
# 🆕 Режим отладки (показывать JSON пользователям)
|
|
536
|
+
DEBUG_MODE=false
|
|
537
|
+
|
|
538
|
+
# Дополнительные настройки
|
|
539
|
+
MAX_CONTEXT_MESSAGES=50
|
|
540
|
+
LOG_LEVEL=INFO
|
|
541
|
+
MESSAGE_PARSE_MODE=Markdown
|
|
542
|
+
|
|
543
|
+
# Настройки продаж
|
|
544
|
+
LEAD_QUALIFICATION_THRESHOLD=7
|
|
545
|
+
SESSION_TIMEOUT_HOURS=24
|
|
546
|
+
|
|
547
|
+
# ⚠️ ВАЖНО: BOT_ID теперь НЕ нужен в .env!
|
|
548
|
+
# Bot ID автоматически определяется из имени файла запускалки
|
|
549
|
+
# Например: python {bot_id}.py → BOT_ID = {bot_id}
|
|
550
|
+
"""
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def copy_from_growthmed_template(bot_dir: Path, bot_id: str):
|
|
554
|
+
"""Копирует шаблон из growthmed-october-24"""
|
|
555
|
+
try:
|
|
556
|
+
# Создаем основной файл бота в корневой директории проекта
|
|
557
|
+
bot_file = PROJECT_ROOT / Path(f"{bot_id}.py")
|
|
558
|
+
bot_file.write_text(create_bot_template(bot_id), encoding="utf-8")
|
|
559
|
+
|
|
560
|
+
# Создаем .env файл в папке бота (НЕ копируем из шаблона)
|
|
561
|
+
env_file = bot_dir / ".env"
|
|
562
|
+
env_file.write_text(create_env_template(bot_id), encoding="utf-8")
|
|
563
|
+
|
|
564
|
+
# Копируем промпты из growthmed-october-24
|
|
565
|
+
source_prompts = (
|
|
566
|
+
Path(__file__).parent / "configs" / "growthmed-october-24" / "prompts"
|
|
567
|
+
)
|
|
568
|
+
target_prompts = bot_dir / "prompts"
|
|
569
|
+
|
|
570
|
+
if source_prompts.exists():
|
|
571
|
+
for prompt_file in source_prompts.glob("*.txt"):
|
|
572
|
+
shutil.copy2(prompt_file, target_prompts / prompt_file.name)
|
|
573
|
+
click.echo("📝 Промпты скопированы из growthmed-october-24")
|
|
574
|
+
else:
|
|
575
|
+
click.echo(f"⚠️ Папка промптов не найдена: {source_prompts}")
|
|
576
|
+
# Fallback к базовым промптам
|
|
577
|
+
create_basic_prompts(target_prompts)
|
|
578
|
+
click.echo("📝 Созданы базовые промпты")
|
|
579
|
+
|
|
580
|
+
# Копируем тесты из growthmed-october-24
|
|
581
|
+
source_tests = (
|
|
582
|
+
Path(__file__).parent / "configs" / "growthmed-october-24" / "tests"
|
|
583
|
+
)
|
|
584
|
+
target_tests = bot_dir / "tests"
|
|
585
|
+
|
|
586
|
+
if source_tests.exists():
|
|
587
|
+
for test_file in source_tests.glob("*"):
|
|
588
|
+
if test_file.is_file():
|
|
589
|
+
shutil.copy2(test_file, target_tests / test_file.name)
|
|
590
|
+
click.echo("🧪 Тесты скопированы из growthmed-october-24")
|
|
591
|
+
|
|
592
|
+
# Копируем welcome_files из growthmed-october-24
|
|
593
|
+
source_welcome = (
|
|
594
|
+
Path(__file__).parent / "configs" / "growthmed-october-24" / "welcome_file"
|
|
595
|
+
)
|
|
596
|
+
target_welcome = bot_dir / "welcome_files"
|
|
597
|
+
|
|
598
|
+
if source_welcome.exists():
|
|
599
|
+
for welcome_file in source_welcome.glob("*"):
|
|
600
|
+
if welcome_file.is_file():
|
|
601
|
+
shutil.copy2(welcome_file, target_welcome / welcome_file.name)
|
|
602
|
+
click.echo("📁 Welcome файлы скопированы из growthmed-october-24")
|
|
603
|
+
|
|
604
|
+
# Копируем files из growthmed-october-24
|
|
605
|
+
source_files = (
|
|
606
|
+
Path(__file__).parent / "configs" / "growthmed-october-24" / "files"
|
|
607
|
+
)
|
|
608
|
+
target_files = bot_dir / "files"
|
|
609
|
+
|
|
610
|
+
if source_files.exists():
|
|
611
|
+
for file_item in source_files.glob("*"):
|
|
612
|
+
if file_item.is_file():
|
|
613
|
+
shutil.copy2(file_item, target_files / file_item.name)
|
|
614
|
+
click.echo("📎 Файлы скопированы из growthmed-october-24")
|
|
615
|
+
|
|
616
|
+
except Exception as e:
|
|
617
|
+
click.echo(f"❌ Ошибка при копировании шаблона: {e}")
|
|
618
|
+
# Fallback к базовым промптам
|
|
619
|
+
create_basic_prompts(bot_dir / "prompts")
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def copy_bot_template(source_bot_id: str, new_bot_id: str):
|
|
623
|
+
"""Копирует существующего бота как шаблон для нового бота"""
|
|
624
|
+
try:
|
|
625
|
+
source_dir = PROJECT_ROOT / "bots" / source_bot_id
|
|
626
|
+
new_dir = PROJECT_ROOT / "bots" / new_bot_id
|
|
627
|
+
|
|
628
|
+
# Создаем папку для нового бота
|
|
629
|
+
new_dir.mkdir(exist_ok=True)
|
|
630
|
+
|
|
631
|
+
# Создаем структуру папок
|
|
632
|
+
(new_dir / "prompts").mkdir(exist_ok=True)
|
|
633
|
+
(new_dir / "tests").mkdir(exist_ok=True)
|
|
634
|
+
(new_dir / "reports").mkdir(exist_ok=True)
|
|
635
|
+
(new_dir / "welcome_files").mkdir(exist_ok=True)
|
|
636
|
+
(new_dir / "files").mkdir(exist_ok=True)
|
|
637
|
+
|
|
638
|
+
# Копируем основной файл бота в корневую директорию
|
|
639
|
+
source_bot_file = PROJECT_ROOT / f"{source_bot_id}.py"
|
|
640
|
+
new_bot_file = PROJECT_ROOT / f"{new_bot_id}.py"
|
|
641
|
+
|
|
642
|
+
if source_bot_file.exists():
|
|
643
|
+
shutil.copy2(source_bot_file, new_bot_file)
|
|
644
|
+
|
|
645
|
+
# Заменяем название бота в файле
|
|
646
|
+
content = new_bot_file.read_text(encoding="utf-8")
|
|
647
|
+
content = content.replace(
|
|
648
|
+
f'BotBuilder("{source_bot_id}")', f'BotBuilder("{new_bot_id}")'
|
|
649
|
+
)
|
|
650
|
+
content = content.replace(
|
|
651
|
+
f'bot_id="{source_bot_id}"', f'bot_id="{new_bot_id}"'
|
|
652
|
+
)
|
|
653
|
+
new_bot_file.write_text(content, encoding="utf-8")
|
|
654
|
+
click.echo(f" 📄 Файл запускалки скопирован: {new_bot_id}.py")
|
|
655
|
+
|
|
656
|
+
# Создаем шаблон .env файла (НЕ копируем существующий)
|
|
657
|
+
new_env = new_dir / ".env"
|
|
658
|
+
new_env.write_text(create_env_template(new_bot_id), encoding="utf-8")
|
|
659
|
+
click.echo(" ⚙️ Создан шаблон .env файла")
|
|
660
|
+
|
|
661
|
+
# Копируем промпты
|
|
662
|
+
source_prompts = source_dir / "prompts"
|
|
663
|
+
new_prompts = new_dir / "prompts"
|
|
664
|
+
|
|
665
|
+
if source_prompts.exists():
|
|
666
|
+
for prompt_file in source_prompts.glob("*.txt"):
|
|
667
|
+
shutil.copy2(prompt_file, new_prompts / prompt_file.name)
|
|
668
|
+
click.echo(" 📝 Промпты скопированы")
|
|
669
|
+
|
|
670
|
+
# Копируем тесты
|
|
671
|
+
source_tests = source_dir / "tests"
|
|
672
|
+
new_tests = new_dir / "tests"
|
|
673
|
+
|
|
674
|
+
if source_tests.exists():
|
|
675
|
+
for test_file in source_tests.glob("*"):
|
|
676
|
+
if test_file.is_file():
|
|
677
|
+
shutil.copy2(test_file, new_tests / test_file.name)
|
|
678
|
+
click.echo(" 🧪 Тесты скопированы")
|
|
679
|
+
|
|
680
|
+
# Копируем welcome_files
|
|
681
|
+
source_welcome = source_dir / "welcome_files"
|
|
682
|
+
new_welcome = new_dir / "welcome_files"
|
|
683
|
+
|
|
684
|
+
if source_welcome.exists():
|
|
685
|
+
for welcome_file in source_welcome.glob("*"):
|
|
686
|
+
if welcome_file.is_file():
|
|
687
|
+
shutil.copy2(welcome_file, new_welcome / welcome_file.name)
|
|
688
|
+
click.echo(" 📁 Welcome файлы скопированы")
|
|
689
|
+
|
|
690
|
+
# Копируем files
|
|
691
|
+
source_files = source_dir / "files"
|
|
692
|
+
new_files = new_dir / "files"
|
|
693
|
+
|
|
694
|
+
if source_files.exists():
|
|
695
|
+
for file_item in source_files.glob("*"):
|
|
696
|
+
if file_item.is_file():
|
|
697
|
+
shutil.copy2(file_item, new_files / file_item.name)
|
|
698
|
+
click.echo(" 📎 Файлы скопированы")
|
|
699
|
+
|
|
700
|
+
except Exception as e:
|
|
701
|
+
click.echo(f"❌ Ошибка при копировании бота: {e}")
|
|
702
|
+
raise
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
def copy_from_bot_template(template: str, bot_dir: Path, bot_id: str):
|
|
706
|
+
"""Копирует шаблон из существующего бота (для команды create)"""
|
|
707
|
+
try:
|
|
708
|
+
template_dir = PROJECT_ROOT / Path("bots") / template
|
|
709
|
+
if not template_dir.exists():
|
|
710
|
+
raise click.ClickException(f"Шаблон {template} не найден")
|
|
711
|
+
|
|
712
|
+
# Копируем основной файл бота в корневую директорию
|
|
713
|
+
template_bot_file = PROJECT_ROOT / Path(f"{template}.py")
|
|
714
|
+
if template_bot_file.exists():
|
|
715
|
+
bot_file = PROJECT_ROOT / Path(f"{bot_id}.py")
|
|
716
|
+
shutil.copy2(template_bot_file, bot_file)
|
|
717
|
+
|
|
718
|
+
# Заменяем название бота в файле
|
|
719
|
+
content = bot_file.read_text(encoding="utf-8")
|
|
720
|
+
content = content.replace(
|
|
721
|
+
f'BotBuilder("{template}")', f'BotBuilder("{bot_id}")'
|
|
722
|
+
)
|
|
723
|
+
content = content.replace(f'bot_id="{template}"', f'bot_id="{bot_id}"')
|
|
724
|
+
bot_file.write_text(content, encoding="utf-8")
|
|
725
|
+
|
|
726
|
+
# Создаем .env файл в папке бота (НЕ копируем из шаблона)
|
|
727
|
+
env_file = bot_dir / ".env"
|
|
728
|
+
env_file.write_text(create_env_template(bot_id), encoding="utf-8")
|
|
729
|
+
|
|
730
|
+
# Копируем промпты
|
|
731
|
+
template_prompts = template_dir / "prompts"
|
|
732
|
+
target_prompts = bot_dir / "prompts"
|
|
733
|
+
|
|
734
|
+
if template_prompts.exists():
|
|
735
|
+
for prompt_file in template_prompts.glob("*.txt"):
|
|
736
|
+
shutil.copy2(prompt_file, target_prompts / prompt_file.name)
|
|
737
|
+
|
|
738
|
+
# Копируем тесты
|
|
739
|
+
template_tests = template_dir / "tests"
|
|
740
|
+
target_tests = bot_dir / "tests"
|
|
741
|
+
|
|
742
|
+
if template_tests.exists():
|
|
743
|
+
for test_file in template_tests.glob("*"):
|
|
744
|
+
if test_file.is_file():
|
|
745
|
+
shutil.copy2(test_file, target_tests / test_file.name)
|
|
746
|
+
|
|
747
|
+
click.echo(f"📋 Шаблон скопирован из {template}")
|
|
748
|
+
|
|
749
|
+
except Exception as e:
|
|
750
|
+
click.echo(f"❌ Ошибка при копировании шаблона {template}: {e}")
|
|
751
|
+
raise
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
def create_basic_prompts(prompts_dir: Path):
|
|
755
|
+
"""Создает базовые промпты"""
|
|
756
|
+
# Системный промпт
|
|
757
|
+
(prompts_dir / "system_prompt.txt").write_text(
|
|
758
|
+
"Ты - помощник. Твоя задача помогать пользователям с их вопросами.\n"
|
|
759
|
+
"Будь дружелюбным и полезным.",
|
|
760
|
+
encoding="utf-8",
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
# Приветственное сообщение
|
|
764
|
+
(prompts_dir / "welcome_message.txt").write_text(
|
|
765
|
+
"👋 Привет! Я ваш помощник.\n\n" "Чем могу помочь?", encoding="utf-8"
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
# Финальные инструкции
|
|
769
|
+
(prompts_dir / "final_instructions.txt").write_text(
|
|
770
|
+
"""<instruction>
|
|
771
|
+
КРИТИЧЕСКИ ВАЖНО: В НАЧАЛЕ КАЖДОГО своего ответа добавляй служебную информацию в формате:
|
|
772
|
+
|
|
773
|
+
{
|
|
774
|
+
"этап": id,
|
|
775
|
+
"качество": 1-10,
|
|
776
|
+
"события": [
|
|
777
|
+
{
|
|
778
|
+
"тип": тип события,
|
|
779
|
+
"инфо": детали события
|
|
780
|
+
}
|
|
781
|
+
],
|
|
782
|
+
"файлы": [],
|
|
783
|
+
"каталоги": []
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
ДОСТУПНЫЕ ОБРАБОТЧИКИ СОБЫТИЙ:
|
|
787
|
+
- example_event: Пример обработчика события. Используй для демонстрации.
|
|
788
|
+
Пример: {"тип": "example_event", "инфо": {"data": "пример данных"}}
|
|
789
|
+
|
|
790
|
+
ДОСТУПНЫЕ ЗАПЛАНИРОВАННЫЕ ЗАДАЧИ:
|
|
791
|
+
- example_task: Пример запланированной задачи. Используй для демонстрации.
|
|
792
|
+
Пример: {"тип": "example_task", "инфо": "через 1 час: напомнить о чем-то"}
|
|
793
|
+
|
|
794
|
+
ДОСТУПНЫЕ ГЛОБАЛЬНЫЕ ОБРАБОТЧИКИ:
|
|
795
|
+
- global_announcement: Отправляет анонс всем пользователям. Используй для важных объявлений.
|
|
796
|
+
Пример: {"тип": "global_announcement", "инфо": "3600"} - анонс через 1 час
|
|
797
|
+
Формат: "инфо" содержит время в секундах для планирования.
|
|
798
|
+
|
|
799
|
+
Используй эти обработчики и задачи, когда это уместно в диалоге.
|
|
800
|
+
</instruction>""",
|
|
801
|
+
encoding="utf-8",
|
|
802
|
+
)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
if __name__ == "__main__":
|
|
806
|
+
cli()
|