Virtual DM chats, FSM (idle/waiting_response/settings states), SQLite local DB for tg_users+chats, converter, keyboards, and handlers for /start, /new, /chats, /settings, confirm callbacks.
189 lines
7.3 KiB
Python
189 lines
7.3 KiB
Python
# adapter/telegram/handlers/settings.py
|
||
from __future__ import annotations
|
||
|
||
from aiogram import F, Router
|
||
from aiogram.filters import Command
|
||
from aiogram.fsm.context import FSMContext
|
||
from aiogram.types import CallbackQuery, Message
|
||
|
||
from adapter.telegram.keyboards.settings import (
|
||
back_keyboard,
|
||
safety_keyboard,
|
||
settings_main_keyboard,
|
||
skills_keyboard,
|
||
)
|
||
from adapter.telegram.states import ChatState, SettingsState
|
||
from core.handler import EventDispatcher
|
||
from core.protocol import SettingsAction
|
||
|
||
router = Router(name="settings")
|
||
|
||
|
||
@router.message(Command("settings"))
|
||
async def cmd_settings(message: Message, state: FSMContext) -> None:
|
||
await state.set_state(SettingsState.menu)
|
||
await message.answer("⚙️ Настройки", reply_markup=settings_main_keyboard())
|
||
|
||
|
||
@router.callback_query(F.data == "settings:back")
|
||
async def cb_settings_back(callback: CallbackQuery, state: FSMContext) -> None:
|
||
await state.set_state(SettingsState.menu)
|
||
await callback.message.edit_text("⚙️ Настройки", reply_markup=settings_main_keyboard())
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(F.data == "settings:skills")
|
||
async def cb_skills(callback: CallbackQuery, state: FSMContext, dispatcher: EventDispatcher) -> None:
|
||
data = await state.get_data()
|
||
active_chat_id = data.get("active_chat_id", "")
|
||
tg_id = callback.from_user.id
|
||
# Get platform user id
|
||
from adapter.telegram import db as tgdb
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), callback.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
await callback.message.edit_text(
|
||
"🧩 Скиллы\nНажмите для переключения:",
|
||
reply_markup=skills_keyboard(settings.skills),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(F.data.startswith("toggle_skill:"))
|
||
async def cb_toggle_skill(
|
||
callback: CallbackQuery,
|
||
state: FSMContext,
|
||
dispatcher: EventDispatcher,
|
||
) -> None:
|
||
skill = callback.data.split(":", 1)[1]
|
||
from adapter.telegram import db as tgdb
|
||
tg_id = callback.from_user.id
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), callback.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
current = settings.skills.get(skill, False)
|
||
action = SettingsAction(
|
||
action="toggle_skill",
|
||
payload={"skill": skill, "enabled": not current},
|
||
)
|
||
await dispatcher._platform.update_settings(platform_user_id, action)
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
await callback.message.edit_reply_markup(reply_markup=skills_keyboard(settings.skills))
|
||
await callback.answer(f"{'Включён' if not current else 'Выключен'}: {skill}")
|
||
|
||
|
||
@router.callback_query(F.data == "settings:safety")
|
||
async def cb_safety(callback: CallbackQuery, state: FSMContext, dispatcher: EventDispatcher) -> None:
|
||
from adapter.telegram import db as tgdb
|
||
tg_id = callback.from_user.id
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), callback.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
await callback.message.edit_text(
|
||
"🔒 Безопасность\nПодтверждение перед выполнением:",
|
||
reply_markup=safety_keyboard(settings.safety),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(F.data.startswith("toggle_safety:"))
|
||
async def cb_toggle_safety(
|
||
callback: CallbackQuery,
|
||
state: FSMContext,
|
||
dispatcher: EventDispatcher,
|
||
) -> None:
|
||
trigger = callback.data.split(":", 1)[1]
|
||
from adapter.telegram import db as tgdb
|
||
tg_id = callback.from_user.id
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), callback.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
current = settings.safety.get(trigger, False)
|
||
action = SettingsAction(
|
||
action="set_safety",
|
||
payload={"trigger": trigger, "enabled": not current},
|
||
)
|
||
await dispatcher._platform.update_settings(platform_user_id, action)
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
await callback.message.edit_reply_markup(reply_markup=safety_keyboard(settings.safety))
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(F.data == "settings:soul")
|
||
async def cb_soul_menu(callback: CallbackQuery, state: FSMContext) -> None:
|
||
await state.set_state(SettingsState.soul_editing)
|
||
await state.update_data(soul_field=None)
|
||
await callback.message.edit_text(
|
||
"🧠 Личность агента\n\nЧто хотите изменить?\n\n"
|
||
"Отправьте: name: <имя агента>\n"
|
||
"Или: instructions: <инструкции>\n\n"
|
||
"Или нажмите Назад.",
|
||
reply_markup=back_keyboard(),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.message(SettingsState.soul_editing)
|
||
async def handle_soul_input(
|
||
message: Message,
|
||
state: FSMContext,
|
||
dispatcher: EventDispatcher,
|
||
) -> None:
|
||
text = message.text or ""
|
||
from adapter.telegram import db as tgdb
|
||
tg_id = message.from_user.id
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), message.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
if ":" in text:
|
||
field, _, value = text.partition(":")
|
||
field = field.strip().lower()
|
||
value = value.strip()
|
||
if field in ("name", "instructions"):
|
||
action = SettingsAction(
|
||
action="set_soul",
|
||
payload={"field": field, "value": value},
|
||
)
|
||
await dispatcher._platform.update_settings(platform_user_id, action)
|
||
await message.answer(f"✅ {field} обновлено.")
|
||
await state.set_state(SettingsState.menu)
|
||
await message.answer("⚙️ Настройки", reply_markup=settings_main_keyboard())
|
||
return
|
||
|
||
await message.answer(
|
||
"Формат: name: <имя> или instructions: <инструкции>\n"
|
||
"Пример: name: Алекс"
|
||
)
|
||
|
||
|
||
@router.callback_query(F.data == "settings:connectors")
|
||
async def cb_connectors(callback: CallbackQuery) -> None:
|
||
await callback.message.edit_text(
|
||
"🔗 Коннекторы\n\nОAuth-интеграции — скоро.",
|
||
reply_markup=back_keyboard(),
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.callback_query(F.data == "settings:plan")
|
||
async def cb_plan(callback: CallbackQuery, dispatcher: EventDispatcher) -> None:
|
||
from adapter.telegram import db as tgdb
|
||
tg_id = callback.from_user.id
|
||
tg_user = tgdb.get_or_create_tg_user(tg_id, str(tg_id), callback.from_user.full_name)
|
||
platform_user_id = tg_user.get("platform_user_id", str(tg_id))
|
||
|
||
settings = await dispatcher._platform.get_settings(platform_user_id)
|
||
plan = settings.plan
|
||
text = (
|
||
f"💳 Подписка\n\n"
|
||
f"Тариф: {plan.get('name', '?')}\n"
|
||
f"Токены: {plan.get('tokens_used', 0)} / {plan.get('tokens_limit', 0)}"
|
||
)
|
||
await callback.message.edit_text(text, reply_markup=back_keyboard())
|
||
await callback.answer()
|