Иногда возникают вопросы, в которых нейросети помогают подумать в правильном направлении, или дают «инсайты». Но спрашивать у каждой сетки одно и то же отдельно может быть долго и неудобно. Сегодня мы напишем бота, который умеет работать сразу с несколькими нейросетями (в дальнейшем вы можете добавить больше моделей, чем будет предоставлено в статье) и получать от них ответы в едином интерфейсе.

Функциональность бота: 

  1. Возможность выбора модели.

  2. Возможность работать с нейросетью (задавать вопросы).

  3. Каждая модель может отвечать по разному, давая инсайты на сложные вопросы.

После написания кода бота мы развернем его на облаке Amvera, которое содержит встроенное, бесплатное проксирование до API OpenAI, Gemini и Claude 3.5 Sonnet, чтобы не думать об организации прокси и не тратить лишние деньги, при этом не требует никакой дополнительной настройки.

Деплой мы осуществим, используя три команды в IDE за счет встроенного CI/CD функционала, что существенно проще, чем при использовании классического VPS.

Создание бота

Регистрация бота в BotFather

Для начала вам нужно перейти в BotFather и создать нового бота с помощью команды /newbot

Далее мы пишем имя нашего будущего бота.

Следующим этапом мы пишем юзернейм нашего будущего бота.

Успешно! Мы создали бота, теперь копируем токен, который нам выдали.

Написание бота с использованием библиотеки aiogram 3

Для начала установим все необходимые библиотеки и составим файл requirements.txt, в который пропишем наши зависимости. Мы будем использовать библиотеку aiogram 3 из-за ее простоты и популярности.

pip install aiogram nest_asyncio g4f

Переходим в командную строку и прописываем данную команду выше.

Теперь можно приступить к написанию кода

  1. Создаём файл main.py и открываем его.

  2. Импортируем необходимые библиотеки.

import logging
import asyncio
import nest_asyncio
import os
from g4f.client import Client
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
  1. Создаём экземпляр бота.

logging.basicConfig(level=logging.INFO)

bot = Bot(token=os.environ["TOKEN"]) # токен мы впишем позже на облаке amvera.ru
dp = Dispatcher()

nest_asyncio.apply() # для фикса бага с asyncio

async def main():
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

Мы сделали основу бота, теперь создадим команды

  1. Создадим переменную, которая даёт боту знать, какую модель выбрал пользователь.

user_choices = {}
  1. Создадим команду старта с кнопками, для выбора модели.

@dp.message(CommandStart())
async def cmd_start(message: Message):
    text = f"Привет, @{message.from_user.username}! Выбери модель, которую ты хочешь использовать:" # текст, который будет виден пользователю
    kb = InlineKeyboardMarkup(inline_keyboard=[
        [
            InlineKeyboardButton(text='Gemini 1.5 flash', callback_data='gemini'),
            InlineKeyboardButton(text='Claude 3.5 Sonnet', callback_data='claude-3.5-sonnet'),
            InlineKeyboardButton(text='ChatGPT 4o', callback_data='gpt-4o')
        ]
    ]) # кнопки
    await message.answer(text, parse_mode="Markdown", reply_markup=kb) # вывод сообщения
    user_choices[message.from_user.id] = None # начальный выбор пользователя
  1. Напишем callback функцию, которая даёт понять, на что нажал пользователь.

@dp.callback_query(lambda c: c.data in ['gemini', 'claude-3.5-sonnet', 'gpt-4o'])
async def process_callback(callback_query: CallbackQuery):
    user_id = callback_query.from_user.id # получаем айди пользователя
    user_choices[user_id] = callback_query.data # получаем то, на что нажал пользователь
	# проверки на что нажал пользователь
    if callback_query.data == 'gemini':
        await callback_query.message.answer("Вы успешно выбрали модель: Gemini 1.5 flash")
    elif callback_query.data == 'claude-3.5-sonnet':
        await callback_query.message.answer("Вы успешно выбрали модель: Claude 3.5 Sonnet")
    elif callback_query.data == 'gpt-4o':
        await callback_query.message.answer("Вы успешно выбрали модель: ChatGPT 4o")
    await callback_query.answer() # вывод сообщения
  1. Напишем функцию самих нейросетей.

@dp.message()
async def handle_message(message: Message):
    user_id = message.from_user.id
    choice = user_choices.get(user_id)
   
    if choice == 'gemini':
        client = Client()
        response = client.chat.completions.create(
            model="gemini-1.5-flash",
            messages=[{"role": "user", "content": message.text}]
        )
        await message.answer(response.choices[0].message.content)  
    elif choice == 'claude-3.5-sonnet':
        client = Client()
        response = client.chat.completions.create(
            model="claude-3.5-sonnet",
            messages=[{"role": "user", "content": message.text}]
        )
        await message.answer(response.choices[0].message.content)
    elif choice == 'gpt-4o':
        client = Client()
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": message.text}]
        )
        await message.answer(response.choices[0].message.content)
    else:
        await message.answer("Сначала выбери модель!")
  1. Создадим файл requirements.txt и запишем все необходимые зависимости для последующего деплоя.

Исходный код бота доступен по ссылке в репозитории GitHub.

Подготовка к деплою на сервер

Деплой мы произведем в облаке Amvera, так как оно поддерживает встроенное проксирование до API OpenAI, Gemini и Claude 3.5 Sonnet. Вам не потребуется настраивать VPN, все будет работать так, как будто блокировки для РФ-пользователей просто нет.

Встроенный функционал CI/CD Amvera позволит нам накатывать обновления простой командой git push amvera master и максимально упростить процесс развертывания в сравнении с классической VPS.

Но перед деплоем нам необходимо создать конфигурационный файл amvera.yml и файл с зависимостями requirements.txt

Файл amvera.yaml

Используем генератор для создания этого файла или просто зададим соответствующие параметры в интерфейсе личного кабинета в разделе Конфигурация.

Выбираем окружение Python

Далее вводим версию Python, в нашем случае 3.10
Указываем путь к файлу с зависимостями, requirements.txt

Вводим имя нашего основного файла, в нашем случае main.py

Нажимаем Generate YAML и закидываем получившейся файл в репозиторий с ботом.

Вот так выглядит файл конфигурации:

meta:
  environment: python
  toolchain:
    name: pip
    version: 3.10
build:
  requirementsPath: requirements.txt
run:
  scriptName: main.py
  persistenceMount: /data
  containerPort: 80

Примечание: Если вы используете SQLite3, то сохраняйте ее в постоянном хранилище /data. Это позволит избежать ее утери при пересборке проекта.

Деплой через интерфейс

  1. Нажимаем на кнопку создать проект.

  2. Выбираем тип сервиса - приложение, вводим название проекта и выбираем тарифный план.

  3. Нажимаем далее.

Выбираем тип "Приложение"
Выбираем тип "Приложение"
В нашем случае подойдет любой тариф
В нашем случае подойдет любой тариф

Выбираем файлы, которые нужно закинуть в проект, и перемещаем их в это окошко.

Загрузим main.py, amvera.yaml и requirements.txt
Загрузим main.py, amvera.yaml и requirements.txt

Перейдем к заданию конфигурации. Строго говоря, генератор yaml описанный выше можно не использовать и все ввести на этом пункте.

Тут ничего делать не надо, так как мы загрузили файл amvera.yaml на прошлом этапе, и все настраивается автоматически. Нажимаем “Завершить”
Тут ничего делать не надо, так как мы загрузили файл amvera.yaml на прошлом этапе, и все настраивается автоматически. Нажимаем “Завершить”

Если вы сделали все правильно, то ваше приложение начнет собираться, но пока уйдет в ошибку.

Теперь нам нужно добавить секрет —  токен бота. В bot.run() мы указали просто слово TOKEN, теперь нужно добавить переменную как секрет. Для этого заходим во вкладку переменные в проекте и нажимаем создать секрет. В поле название вводим нашу переменную TOKEN, а в поле значение, вводим сам токен.

Добавление секрета во вкладке "Переменные"
Добавление секрета во вкладке "Переменные"

После добавления токена перезапустим проект.

Если все сделано правильно, мы получим статус «приложение запущено».

Статус «приложение запущено»
Статус «приложение запущено»

Деплой через Git. Альтернативный способ

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

Создаем папку и закидываем туда  все файлы. Открываем командную строку и переходим в нашу папку с помощью команды cd “путь к папке”. Создаем репозиторий с помощью команды git init. Заходим в Amvera и создаем проект. 

На этапе загрузки файлов мы выбираем метод «Через Git».

Команды можно скопировать из интерфейса
Команды можно скопировать из интерфейса

Теперь нам нужно подключиться к существующему репозиторию, для этого копируем команду ниже и вставляем в командную строку.

Подключим к существующему репозиторию
Подключим к существующему репозиторию

После чего вводим команды для добавления файлов и создания коммита:

git add .
git commit -m "initial commit" 

Нам остается запушить все файлы, и сборка начнется автоматически. Для этого вводим команду: 

git push amvera master

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

Готово, наш бот запустился, и мы можем в одном интерфейсе получать ответы сразу от нескольких нейросетей, что будет полезно для нестандартных вопросов, где нужна подсказка, в каком направлении продолжать думать.

Пример работы бота
Пример работы бота

Итого:

Мы написали бота, который может работать сразу с несколькими поставщиками LLM, чтобы получать от них ответы в едином интерфейсе и использовать их как «второе мнение». И развернули бот, используя GitOps-подход, на удаленном сервере со встроенным проксированием до наиболее популярных нейронных сетей. Разумеется, вы можете изменить список используемых нейросетей, используя актуальные для вас сервисы.

Исходный код бота доступен по ссылке в репозитории GitHub.

Комментарии (0)