Иногда возникают вопросы, в которых нейросети помогают подумать в правильном направлении, или дают «инсайты». Но спрашивать у каждой сетки одно и то же отдельно может быть долго и неудобно. Сегодня мы напишем бота, который умеет работать сразу с несколькими нейросетями (в дальнейшем вы можете добавить больше моделей, чем будет предоставлено в статье) и получать от них ответы в едином интерфейсе.
Функциональность бота:
Возможность выбора модели.
Возможность работать с нейросетью (задавать вопросы).
Каждая модель может отвечать по разному, давая инсайты на сложные вопросы.
После написания кода бота мы развернем его на облаке 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
Переходим в командную строку и прописываем данную команду выше.
Теперь можно приступить к написанию кода
Создаём файл main.py и открываем его.
Импортируем необходимые библиотеки.
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
Создаём экземпляр бота.
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())
Мы сделали основу бота, теперь создадим команды
Создадим переменную, которая даёт боту знать, какую модель выбрал пользователь.
user_choices = {}
Создадим команду старта с кнопками, для выбора модели.
@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 # начальный выбор пользователя
Напишем 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() # вывод сообщения
Напишем функцию самих нейросетей.
@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("Сначала выбери модель!")
Создадим файл 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. Это позволит избежать ее утери при пересборке проекта.
Деплой через интерфейс
Нажимаем на кнопку создать проект.
Выбираем тип сервиса - приложение, вводим название проекта и выбираем тарифный план.
Нажимаем далее.
Выбираем файлы, которые нужно закинуть в проект, и перемещаем их в это окошко.
Перейдем к заданию конфигурации. Строго говоря, генератор 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-подход, на удаленном сервере со встроенным проксированием до наиболее популярных нейронных сетей. Разумеется, вы можете изменить список используемых нейросетей, используя актуальные для вас сервисы.