Задать вопрос
  • Как использовать RAG с чатами без api?

    @dsignmark
    Без облачного api это нормально делается локально. Ничего сложного.

    Самый быстрый путь без кода это Ollama плюс Open WebUI. Ollama крутит модель у вас на машине, а в Open WebUI RAG уже встроен: кидаете туда выгруженный в текст чат, он сам строит индекс и отвечает со ссылками на куски. Доки тут https://docs.ollama.com/ и тут https://docs.openwebui.com/features/chat-conversat...

    Если хочется контроля, то свой маленький пайплайн строк на 50. Историю в txt или json, режете на фрагменты, эмбеддинги считаете локальной nomic-embed-text (https://ollama.com/library/nomic-embed-text), складываете в Chroma (https://docs.trychroma.com/). На вопрос достаете топ 5-10 фрагментов и подсовываете модели в контекст.

    Для кода repomix выше уже советовали, на небольшом проекте его часто хватает и вообще без RAG.

    Главное: качество тут решает нарезка, а не индекс. Чат надо резать по сообщениям или по темам, не по байтам, и тащить в каждый кусок кто и когда написал. Иначе на вопрос "что сказал клиент во вторник" модель уверенно отвечает чужими словами.
    Ответ написан
    Комментировать
  • Как через telethon отправить сообщение администратору канала?

    @dsignmark
    Дополню ответ выше про monoforum двумя вещами, на которых обычно спотыкаются дальше.

    1. Включены ли сообщения у канала вообще. У самого канала смотрите флаг broadcast_messages_allowed: если он False, админы чат с администрацией не включили, и отправлять некуда.

    2. Платные сообщения. Админы могут поставить цену за сообщение в звёздах. Тогда заполнено поле send_paid_messages_stars (смотрите и у monoforum, и у самого канала), а обычный client.send_message() упадёт с ошибкой вида ALLOW_PAYMENT_REQUIRED_<цена>. Высокоуровневый send_message() в Telethon не умеет передавать согласие на оплату, поэтому нужен «сырой» запрос:

    ```python
    from telethon.tl.functions.channels import GetFullChannelRequest
    from telethon.tl.functions.messages import SendMessageRequest

    channel = await client.get_entity('имя_канала')
    if not channel.broadcast_messages_allowed:
    raise RuntimeError('у канала выключены сообщения администрации')

    full = await client(GetFullChannelRequest(channel))
    mono = next(c for c in full.chats if c.id == channel.linked_monoforum_id)

    price = mono.send_paid_messages_stars or channel.send_paid_messages_stars or 0 # 0 — бесплатно
    await client(SendMessageRequest(
    peer=mono,
    message='Здравствуйте! ...',
    allow_paid_stars=price or None,
    ))
    ```

    Если цена больше нуля, звёзды спишутся с аккаунта, от которого работает сессия, а без нужного баланса запрос не пройдёт. Поэтому цену лучше проверить до отправки и явно решить, готовы ли вы платить.

    Telethon нужен свежий, со схемой не ниже 204: в старых версиях у Channel просто нет поля linked_monoforum_id. Проверить можно так: `from telethon.tl.alltlobjects import LAYER; print(LAYER)`.
    Ответ написан
    Комментировать
  • Как грамотно передать токен доступа к серверу из бота в Mini App?

    @dsignmark
    Токен из бота в Mini App передавать вообще не нужно. У Mini App уже есть подписанные данные о том, кто её открыл, и права на комнату проще проверять по ним на сервере.

    Как это обычно делается:

    1. Когда пользователь открывает Mini App, на фронте есть строка Telegram.WebApp.initData. В ней user.id, auth_date и hash. Подписана она токеном бота, подделать её без токена нельзя.
    2. Фронт отправляет initData на ваш сервер, например первым сообщением в WebSocket или в заголовке при подключении.
    3. Сервер проверяет подпись по алгоритму из документации (раздел «Validating data received via the Mini App»): HMAC-SHA256 с ключом, выведенным из токена бота. Заодно проверьте auth_date, чтобы старые initData нельзя было переиграть. Например, не старше часа.
    4. В момент /new_room бот уже знает message.from_user.id. Сохраните на сервере связку room_id → owner_id. Когда этот же пользователь откроет Mini App, сервер увидит его user.id в проверенной initData и сам выдаст ему права владельца, а остальным — права участника.

    Тогда в ссылке остаётся только room_id, и ничего секретного в ней нет. Ссылку можно спокойно пересылать: владельцем станет только тот, чей Telegram-id совпадает.

    Если всё же нужна именно ссылка «с правами» (например, создатель хочет назначить второго модератора), положите в startapp-параметр не сам токен, а одноразовый короткоживущий код. Сервер обменивает его на права один раз, после чего код сгорает. Даже если ссылка утечёт позже, по ней уже ничего не сделать.
    Ответ написан
    Комментировать
  • Как реализовать callback c использованием aiogram длиной более 10 секунд?

    @dsignmark
    Тут две разные проблемы, и create_task решает только первую.

    1. Колбэк должен отвечать сразу. Telegram ждёт answer() на callback_query несколько секунд, поэтому порядок такой: сразу await callback.answer() (можно с текстом «Запустил, это займёт время»), отредактировать сообщение в «⏳ Обрабатываю…» и запустить работу в фоне через asyncio.create_task(...). Ссылку на задачу сохраните (например, в set), иначе сборщик мусора может её прибить.

    2. Ошибки «Failed to fetch updates … Request timeout» говорят о том, что блокируется сам event loop. Скорее всего, клиент к ИИ синхронный: requests, синхронный openai-клиент или тяжёлые вычисления. Пока он работает, aiogram не может даже забрать обновления, отсюда таймауты polling. Варианты:
    — асинхронный клиент (AsyncOpenAI, httpx.AsyncClient);
    — или обернуть синхронный вызов: result = await asyncio.to_thread(call_ai, prompt).

    Когда фоновая задача закончится, отредактируйте то же сообщение через bot.edit_message_text(chat_id=..., message_id=...) и, если нужно, отправьте файл через send_document. Так в истории останется одно сообщение и файл, как вы хотите.

    Прогресс-бар делается тем же редактированием сообщения. Только не чаще раза в 2–3 секунды, иначе получите flood control.

    Если задачи будут идти часами, держать их внутри процесса бота уже рискованно: перезапуск бота их потеряет. Тогда выносите работу в очередь (arq, taskiq, Celery). Бот кладёт задачу и сохраняет chat_id и message_id, воркер выполняет её и по завершении сам редактирует сообщение через Bot API.
    Ответ написан
    Комментировать