Разработка ИИ-ассистента: Telegram и Google Таблицы

Практический курс по созданию умного чат-бота, интегрированного с нейросетями и облачными таблицами. Вы научитесь настраивать API, программировать логику общения и автоматизировать сбор данных.

Подготовка окружения: регистрация бота, получение API ключей OpenAI и настройка Google Cloud Console

Подготовка окружения: регистрация бота, получение API ключей Perplexity и настройка Google Cloud Console

Добро пожаловать на курс «Разработка ИИ-ассистента: Telegram и Google Таблицы». Это первая и фундаментальная статья, в которой мы заложим технический фундамент нашего проекта. Прежде чем писать код, нам необходимо подготовить инструменты и получить доступы к сервисам.

Учитывая ваши предпочтения и наличие подписки Perplexity AI Pro, мы построим архитектуру именно на базе этой нейросети. Это отличное решение, так как Perplexity предоставляет доступ к актуальным данным из интернета и мощным моделям, а их API совместим с популярными библиотеками.

Наша цель — создать систему, где:

  1. Telegram — интерфейс для общения.
  2. Perplexity AI — «мозг», обрабатывающий запросы и имеющий доступ к свежей информации.
  3. Google Таблицы — долгосрочная память и база данных.

1. Регистрация Telegram-бота

Первый шаг — создание «оболочки» для нашего ассистента. В экосистеме Telegram боты создаются через специального служебного бота — «Отца ботов».

Работа с BotFather

  1. Откройте Telegram и в строке поиска введите @BotFather. Обратите внимание на синюю галочку верификации — это официальный инструмент Telegram.
  2. Нажмите кнопку Start (или введите команду /start), чтобы запустить диалог.
  3. Отправьте команду /newbot для создания нового бота.
  4. BotFather попросит вас придумать имя (Name). Это то, что пользователи будут видеть в списке чатов (например, Мой Perplexity Ассистент). Имя может быть на русском языке.
  5. Далее нужно придумать юзернейм (Username). Это уникальный идентификатор на латинице (например, t.me/my_pplx_smart_bot).

Важно: Юзернейм обязательно должен заканчиваться на слово bot. Например: MyCourseAI_bot или smart_helper_bot.

Получение токена

После успешного создания BotFather пришлет вам сообщение с поздравлением. В этом сообщении будет находиться HTTP API Token.

Пример токена: 123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw.

Этот токен — ключ от вашего бота. Никогда не публикуйте его в открытых источниках. Скопируйте его и сохраните, он понадобится нам при настройке конфигурации.

2. Получение API ключа Perplexity AI

Вместо стандартного OpenAI мы будем использовать мощь Perplexity. Огромным преимуществом Perplexity API является его полная совместимость с клиентскими библиотеками OpenAI, что упрощает разработку.

Генерация ключа

Так как у вас есть подписка Pro, вы имеете определенные преимущества (обычно это ежемесячные кредиты на использование API, которые обновляются каждый месяц).

  1. Перейдите на официальный сайт Perplexity AI.
  2. Войдите в свой аккаунт, где активна подписка Pro.
  3. Перейдите в настройки (Settings) -> раздел API.
  4. Вам может потребоваться привязать карту, если кредиты закончатся, но для начала работы часто хватает стартового баланса Pro-подписчика.
  5. Нажмите кнопку Generate API Key.
  6. Придумайте имя ключа, например TelegramBotKey.

Сохранение ключа

Система покажет вам ключ, который начинается с pplx-....

Внимание: Ключ показывается только один раз. Скопируйте его немедленно и сохраните в безопасном месте. Если вы закроете окно, ключ восстановить не удастся, придется создавать новый.

Этот ключ позволит нашему боту отправлять запросы к моделям Perplexity (например, llama-3-sonar-large-32k-online), которые умеют искать информацию в интернете в реальном времени.

3. Настройка Google Cloud Console

Это самый технически насыщенный этап. Чтобы Python-скрипт мог читать и записывать данные в Google Таблицу, нам нужно создать «Сервисный аккаунт» (Service Account) — виртуального робота с правами доступа.

Создание проекта

  1. Перейдите в Google Cloud Console.
  2. В верхней панели нажмите на выпадающий список проектов и выберите New Project (Создать проект).
  3. Дайте проекту имя, например AI-Assistant-PPLX, и нажмите Create.
  4. Подождите уведомления о создании и выберите этот проект (кнопка Select Project).

Включение API

Нам нужно активировать два сервиса: Google Sheets (для таблиц) и Google Drive (для управления правами доступа к файлам).

  1. Откройте меню (три полоски слева) -> APIs & Services -> Library.
  2. В строке поиска введите Google Sheets API.
  3. Выберите его и нажмите кнопку Enable (Включить).
  4. Вернитесь в библиотеку (стрелка назад или снова через меню).
  5. Введите в поиске Google Drive API.
  6. Выберите его и также нажмите Enable.

Создание сервисного аккаунта

Теперь создадим «удостоверение личности» для нашего бота.

  1. Перейдите в меню APIs & Services -> Credentials (Учетные данные).
  2. Нажмите Create Credentials -> Service Account.
  3. Введите имя, например bot-editor. Поле ID заполнится автоматически.
  4. Нажмите Create and Continue.
  5. В поле Select a role выберите Editor (Редактор) или Owner (Владелец). Это критически важно, иначе бот не сможет писать в таблицу.
  6. Нажмите Continue, затем Done.

Получение JSON-ключа

  1. В списке сервисных аккаунтов (внизу страницы Credentials) нажмите на email только что созданного аккаунта (он выглядит как bot-editor@ai-assistant-pplx.iam.gserviceaccount.com).
  2. Перейдите на вкладку Keys (Ключи).
  3. Нажмите Add Key -> Create new key.
  4. Выберите формат JSON и нажмите Create.
  5. Файл автоматически скачается на ваш компьютер. Это секретный файл доступа. Переименуйте его в creds.json и сохраните в папку будущего проекта.

4. Подготовка Google Таблицы

Мы получили ключи, но наш сервисный аккаунт пока не имеет доступа к конкретной таблице. Google Таблицы приватны по умолчанию.

  1. Создайте новую Google Таблицу (введите sheets.new в браузере).
  2. Назовите её, например, AI Assistant Memory.
  3. Откройте скачанный файл creds.json (в Блокноте или редакторе кода) и найдите поле client_email.
  4. Скопируйте этот email (адрес сервисного аккаунта).
  5. В Google Таблице нажмите кнопку Настройки доступа (Share) в правом верхнем углу.
  6. Вставьте скопированный email, убедитесь, что стоит роль Редактор, и нажмите Отправить.

Теперь наш бот имеет официальное разрешение работать с этим документом.

5. Настройка окружения Python

Финальный этап — подготовка рабочего места разработчика.

Установка Python

Убедитесь, что у вас установлен Python версии 3.8 или выше. Проверка версии в терминале:

python --version

Создание проекта и виртуального окружения

Создадим изолированную среду, чтобы библиотеки проекта не конфликтовали с системой.

Выполните команды в терминале:

# Создаем папку проекта
mkdir ai_assistant_pplx
cd ai_assistant_pplx

# Создаем виртуальное окружение
python -m venv venv

# Активируем окружение
# Для Windows:
venv\Scripts\activate
# Для macOS/Linux:
source venv/bin/activate

Установка библиотек

Нам понадобятся следующие библиотеки:

  • aiogram — современный асинхронный фреймворк для Telegram ботов.
  • openai — Важный момент: мы устанавливаем библиотеку OpenAI, так как Perplexity API полностью совместим с ней. Нам не нужна отдельная библиотека для Perplexity, мы просто перенаправим запросы на другой адрес.
  • gspread — удобная библиотека для работы с Google Таблицами.
  • python-dotenv — для безопасного хранения ключей.

Установите их одной командой:

pip install aiogram openai gspread python-dotenv

Файл конфигурации .env

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

Заполните его вашими данными:

TELEGRAM_TOKEN=ваш_токен_от_botfather
PERPLEXITY_API_KEY=pplx-ваш_ключ_perplexity
GOOGLE_SHEET_KEY=creds.json

Убедитесь, что файл creds.json также перемещен в эту папку.

Итоги

Мы успешно подготовили почву для разработки. У нас есть:

  1. Telegram-бот, зарегистрированный через BotFather.
  2. API ключ Perplexity, который даст нашему боту доступ к передовым моделям и поиску.
  3. Сервисный аккаунт Google, подключенный к нашей таблице.
  4. Настроенное окружение Python с библиотеками aiogram и openai.

В следующей статье мы напишем код, который свяжет эти компоненты воедино, и научим бота отвечать на вопросы, используя интеллект Perplexity.

Мозг ассистента: подключение языковой модели и создание эффективного системного промпта

Мозг ассистента: подключение языковой модели и создание эффективного системного промпта

В предыдущей статье мы успешно зарегистрировали бота, получили заветные ключи API и настроили облачное окружение. Теперь настало время вдохнуть жизнь в наш проект. Мы переходим к самому интересному этапу — программированию «мозга» нашего ассистента.

Сегодня мы не просто напишем код для связи с OpenAI, но и научимся управлять поведением модели так, чтобы она решала именно наши задачи, а не болтала о погоде (если только это не является её целью).

1. Подключение библиотеки OpenAI

Первым делом нам необходимо научить Python общаться с серверами OpenAI. Мы уже установили необходимые библиотеки, теперь создадим базовый скрипт.

В папке вашего проекта создайте файл ai_brain.py. Это будет отдельный модуль, отвечающий за логику генерации ответов. Такой подход называется модульным программированием: мы разделяем логику бота (Telegram) и логику интеллекта (AI).

Базовая настройка

Откройте ai_brain.py и добавьте следующий код:

import os
from dotenv import load_dotenv
from openai import OpenAI

# Загружаем переменные окружения из файла .env
load_dotenv()

# Инициализируем клиента
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY")
)

def test_connection():
    try:
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "user", "content": "Привет! Ты работаешь?"}
            ]
        )
        print(response.choices[0].message.content)
    except Exception as e:
        print(f"Ошибка подключения: {e}")

if __name__ == "__main__":
    test_connection()

Запустите этот файл через терминал командой python ai_brain.py. Если вы увидели ответ вроде «Да, я работаю! Чем могу помочь?», значит, связь установлена успешно.

2. Архитектура сообщений: Роли

Чтобы создавать сложных ассистентов, важно понимать, как именно модель воспринимает диалог. Для GPT диалог — это не просто текст, а список сообщений, где у каждого сообщения есть своя роль.

Существует три основных типа ролей:

  1. system (Система) — Самая важная роль для разработчика. Это скрытая инструкция, которую пользователь не видит, но которой модель обязана следовать. Здесь мы задаем характер, ограничения и формат ответов.
  2. user (Пользователь) — Это то, что пишет ваш клиент или вы в чат.
  3. assistant (Ассистент) — Это ответы самой модели. Чтобы модель помнила контекст беседы, мы должны передавать ей историю предыдущих сообщений с этой ролью.

3. Системный промпт: Программирование на естественном языке

Качество работы вашего бота на 80% зависит не от кода на Python, а от качества системного промпта (system prompt). Это инструкция, которую мы отправляем первой.

Структура идеального промпта

Хороший промпт должен содержать следующие блоки:

  • Роль (Persona): Кто такой бот?
  • Задача (Task): Что он должен делать?
  • Контекст (Context): Какими данными он оперирует?
  • Ограничения (Constraints): Чего он делать НЕ должен?
  • Формат вывода (Output Format): В каком виде нужен ответ (текст, JSON, список)?

Пример эволюции промпта

Плохой промпт:

"Ты помощник по учету финансов."

Хороший промпт:

"Ты — строгий финансовый аналитик. Твоя задача — помогать пользователю категоризировать его расходы. Если пользователь пишет 'такси 500', ты должен определить категорию как 'Транспорт'. Отвечай кратко. Не давай финансовых советов, если тебя не просят. Если сумма выглядит подозрительно большой, уточни, не ошибка ли это."

4. Математика токенов и стоимости

При работе с API важно помнить, что OpenAI считает не слова, а токены. Токен — это часть слова. Для английского языка 1000 токенов — это примерно 750 слов. Для русского языка, из-за особенностей кодировки, один токен часто равен одной букве или части слога, поэтому расход токенов на русском выше.

Стоимость запроса рассчитывается по формуле:

C=Nin×Pin+Nout×Pout1000C = \frac{N_{in} \times P_{in} + N_{out} \times P_{out}}{1000}

Где:

  • CC — итоговая стоимость запроса в долларах.
  • NinN_{in} — количество токенов во входящем сообщении (включая системный промпт и историю переписки).
  • PinP_{in} — цена за 1000 входных токенов (зависит от модели).
  • NoutN_{out} — количество токенов в ответе модели.
  • PoutP_{out} — цена за 1000 выходных токенов.

Понимание этой формулы критически важно. Если вы будете отправлять всю историю переписки за месяц в каждом запросе, NinN_{in} будет расти линейно, и стоимость каждого следующего ответа будет увеличиваться.

5. Создание функции генерации ответа

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

Обновите файл ai_brain.py:

import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# Стандартный промпт по умолчанию
DEFAULT_SYSTEM_PROMPT = """
Ты — полезный ассистент.
Твоя цель — отвечать на вопросы пользователя четко и по делу.
Используй форматирование Markdown для выделения важных частей.
"""

def get_ai_response(user_message, history=None, system_prompt=DEFAULT_SYSTEM_PROMPT):
    """
    Получает ответ от GPT на основе сообщения и истории.
    :param user_message: Текст текущего сообщения пользователя
    :param history: Список предыдущих сообщений (list of dicts)
    :param system_prompt: Инструкция для бота
    :return: Текст ответа
    """

    # Если истории нет, создаем пустой список
    if history is None:
        messages = []
    else:
        # Копируем историю, чтобы не менять оригинал
        messages = history.copy()

    # 1. Добавляем системное сообщение в НАЧАЛО списка
    # Это важно: модель должна сначала узнать, кто она
    messages.insert(0, {"role": "system", "content": system_prompt})

    # 2. Добавляем текущее сообщение пользователя в КОНЕЦ
    messages.append({"role": "user", "content": user_message})

    try:
        response = client.chat.completions.create(
            model="gpt-3.5-turbo", # Или gpt-4o-mini для экономии
            messages=messages,
            temperature=0.7 # Креативность: 0 - робот, 1 - фантазер
        )
        return response.choices[0].message.content
    except Exception as e:
        print(f"Ошибка API OpenAI: {e}")
        return "Извините, мой мозг сейчас перегружен. Попробуйте позже."

# Тестируем функцию
if __name__ == "__main__":
    answer = get_ai_response("Напиши план изучения Python из 3 пунктов")
    print(answer)

Разбор ключевых моментов кода

  1. messages.insert(0, ...): Мы всегда ставим системный промпт первым. Если поставить его в конец, модель может «забыть» инструкцию из-за большого контекста до неё.
  2. temperature=0.7: Этот параметр отвечает за «творчество». Для бота-бухгалтера лучше ставить 0.2 (строгость), для бота-рассказчика — 0.8 (разнообразие).
  3. Обработка ошибок: Сетевые запросы могут падать. Конструкция try...except гарантирует, что ваш бот не «упадет» полностью, а вежливо сообщит об ошибке.

6. Проблема памяти (Context Window)

В текущей реализации функции get_ai_response мы принимаем аргумент history, но пока не реализуем механизм его хранения.

Важно понимать: API OpenAI не имеет памяти. Каждый запрос для него — как первый день жизни. Если вы напишете «Привет, меня зовут Иван», а следующим запросом «Как меня зовут?», модель ответит «Я не знаю», если вы не передадите ей первое сообщение снова.

В следующей статье, когда мы будем интегрировать Telegram, мы реализуем хранение истории переписки, чтобы бот мог вести связный диалог.

Заключение

Сегодня мы создали «мозг» нашего ассистента. У нас есть функция, которая принимает текст и возвращает умный ответ, руководствуясь нашими инструкциями.

Мы научились:

  • Отправлять запросы к OpenAI API.
  • Использовать роль system для настройки личности бота.
  • Понимать, как формируется стоимость запросов.

В следующей статье мы соединим этот «мозг» с «телом» — Telegram-ботом, и заставим их работать как единое целое.

Связь с миром: разработка Telegram-бота и обработка входящих сообщений на Python

Связь с миром: разработка Telegram-бота и обработка входящих сообщений на Python

Мы уже проделали большую работу: зарегистрировали бота в Telegram, получили ключи доступа к «мозгам» OpenAI и настроили облачную консоль Google. В прошлой статье мы даже написали модуль ai_brain.py, который умеет генерировать ответы. Но пока этот модуль живет в вакууме — он не может общаться с реальными пользователями.

В этой статье мы создадим «тело» нашего ассистента. Мы напишем основной скрипт на Python, который будет слушать серверы Telegram, ловить сообщения от пользователей, передавать их в OpenAI и возвращать ответ обратно.

Выбор инструментов: почему aiogram?

Для работы с Telegram API на Python существует несколько библиотек. Мы выбрали aiogram 3.x. Это современный, полностью асинхронный фреймворк.

Почему асинхронность важна? Представьте, что ваш бот обрабатывает запрос к ChatGPT, который длится 5 секунд. В синхронном коде (например, библиотека telebot) бот «зависнет» на эти 5 секунд и не сможет ответить никому другому. В асинхронном коде (aiogram) бот отправит запрос и, пока ждет ответа, спокойно продолжит общаться с сотнями других пользователей.

Архитектура бота: Long Polling

Существует два способа получения сообщений от Telegram:

  1. Webhook — Telegram сам стучится на ваш сервер, когда приходит сообщение. Это профессиональный метод для продакшена, но он требует наличия своего сервера с HTTPS.
  2. Long Polling (Длинный опрос) — Наша программа сама постоянно спрашивает у Telegram: «Есть что-то новое?». Если сообщений нет, Telegram держит соединение открытым некоторое время, а потом отвечает «нет». Если есть — отдает их сразу.

Для разработки и запуска на локальном компьютере мы будем использовать Long Polling. Это проще и не требует настройки серверов.

Создание основного файла main.py

Создайте в папке проекта файл main.py. Это будет точка входа в наше приложение. Рядом с ним должны лежать файл .env и созданный в прошлом уроке ai_brain.py.

1. Импорт библиотек и настройка

Начнем с базовой настройки. Нам нужно инициализировать объект бота и диспетчера.

import asyncio
import logging
import os
from dotenv import load_dotenv
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart

# Импортируем нашу функцию мозга
from ai_brain import get_ai_response

# Загружаем ключи
load_dotenv()

# Включаем логирование, чтобы видеть ошибки в консоли
logging.basicConfig(level=logging.INFO)

# Инициализация бота и диспетчера
bot = Bot(token=os.getenv("TELEGRAM_TOKEN"))
dp = Dispatcher()

Диспетчер (Dispatcher) — это «сортировочный центр» бота. Он получает все обновления (сообщения, нажатия кнопок) и решает, какую функцию запустить для их обработки.

2. Реализация памяти

Как мы обсуждали ранее, API OpenAI не помнит контекст. Нам нужно хранить историю переписки самостоятельно. Для простого бота мы можем использовать обычный словарь Python, где ключом будет ID пользователя, а значением — список сообщений.

Важно: Хранение данных в оперативной памяти (в переменной) означает, что при перезапуске бота вся переписка забудется. Для серьезных проектов используют базы данных, но для старта курса нам хватит и словаря.

Добавим переменную для хранения истории:

# Словарь для хранения истории: {user_id: [message_list]}
users_history = {}

3. Обработка команды /start

Любое общение с ботом начинается с нажатия кнопки Start. Нам нужно поприветствовать пользователя и инициализировать его историю.

@dp.message(CommandStart())
async def cmd_start(message: types.Message):
    user_id = message.from_user.id

    # Очищаем историю при перезапуске
    users_history[user_id] = []

    await message.answer(
        "Привет! Я твой ИИ-ассистент. "
        "Я готов помогать тебе с задачами и сохранять важное в Google Таблицы. "
        "Просто напиши мне что-нибудь!"
    )

Здесь мы используем декоратор @dp.message. Он говорит диспетчеру: «Если пришло сообщение, которое является командой /start, запусти эту функцию».

4. Обработка текстовых сообщений

Теперь самое главное — функция, которая принимает текст, отправляет его в «мозг» и возвращает ответ.

@dp.message()
async def handle_message(message: types.Message):
    user_id = message.from_user.id
    user_text = message.text

    # Если пользователя нет в базе, создаем пустую историю
    if user_id not in users_history:
        users_history[user_id] = []

    # 1. Отправляем статус "печатает...", чтобы пользователь видел активность
    await bot.send_chat_action(chat_id=user_id, action="typing")

    # 2. Получаем историю пользователя
    history = users_history[user_id]

    # 3. Обращаемся к модулю ai_brain
    # Обратите внимание: get_ai_response - синхронная функция,
    # но в простом примере это допустимо.
    # Для high-load проектов используют асинхронные клиенты OpenAI.
    ai_answer = get_ai_response(user_text, history)

    # 4. Обновляем историю (добавляем вопрос и ответ)
    # Важно: формат сообщений должен соответствовать API OpenAI
    history.append({"role": "user", "content": user_text})
    history.append({"role": "assistant", "content": ai_answer})

    # 5. Отправляем ответ пользователю
    await message.answer(ai_answer)

Проблема переполнения контекста

Мы сохраняем всю историю, но модели OpenAI имеют лимит на количество токенов (память). Если переписка будет слишком длинной, API вернет ошибку. Нам нужно следить за размером истории.

Для приблизительной оценки можно использовать простую формулу:

Ntotal=Nsys+∑i=1k(Nreq(i)+Nres(i))+NnewN_{total} = N_{sys} + \sum_{i=1}^{k} (N_{req}^{(i)} + N_{res}^{(i)}) + N_{new}

где NtotalN_{total} — общее количество токенов в запросе, NsysN_{sys} — токены системного промпта, kk — количество пар сообщений в истории, Nreq(i)N_{req}^{(i)} — токены запроса пользователя в ii-й паре, Nres(i)N_{res}^{(i)} — токены ответа ассистента в ii-й паре, а NnewN_{new} — токены нового сообщения.

Если NtotalN_{total} превышает лимит модели (например, 4096 или 16000 токенов), нам нужно удалять самые старые сообщения из начала списка history.

Добавим простую проверку длины списка в нашу функцию (упрощенный вариант очистки):

    # Оставляем только последние 10 сообщений (5 пар вопрос-ответ)
    if len(history) > 10:
        history = history[-10:]
        users_history[user_id] = history

Вставьте этот блок кода перед вызовом get_ai_response.

5. Запуск бота

В конце файла main.py нужно добавить стандартную конструкцию для запуска асинхронного цикла:

async def main():
    print("Бот запущен!")
    # Запускаем polling, пропуская накопившиеся апдейты (чтобы бот не отвечал на старое)
    await dp.start_polling(bot, skip_updates=True)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("Бот выключен")

Полный код main.py

Соберем все вместе. Вот итоговый код вашего файла main.py:

import asyncio
import logging
import os
from dotenv import load_dotenv
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
from ai_brain import get_ai_response

load_dotenv()
logging.basicConfig(level=logging.INFO)

bot = Bot(token=os.getenv("TELEGRAM_TOKEN"))
dp = Dispatcher()

users_history = {}

@dp.message(CommandStart())
async def cmd_start(message: types.Message):
    user_id = message.from_user.id
    users_history[user_id] = []
    await message.answer("Привет! Я готов к работе.")

@dp.message()
async def handle_message(message: types.Message):
    user_id = message.from_user.id
    user_text = message.text

    if user_id not in users_history:
        users_history[user_id] = []

    history = users_history[user_id]

    # Простая очистка контекста
    if len(history) > 10:
        history = history[-10:]
        users_history[user_id] = history

    await bot.send_chat_action(chat_id=user_id, action="typing")

    # Генерируем ответ
    ai_answer = get_ai_response(user_text, history)

    # Сохраняем в историю
    history.append({"role": "user", "content": user_text})
    history.append({"role": "assistant", "content": ai_answer})

    await message.answer(ai_answer)

async def main():
    print("Бот запущен...")
    await dp.start_polling(bot)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("Бот остановлен")

Запуск и тестирование

  1. Откройте терминал в папке проекта.
  2. Убедитесь, что виртуальное окружение активировано.
  3. Запустите бота командой:
python main.py
  1. Перейдите в Telegram, найдите своего бота и нажмите Start.
  2. Напишите ему: «Привет, кто ты?». Бот должен ответить, используя системный промпт, который мы задали в ai_brain.py.
  3. Напишите: «Запомни число 42». Затем спроси: «Какое число я просил запомнить?». Если бот ответит «42», значит, механизм истории работает корректно!

Заключение

Поздравляю! У вас есть работающий прототип ИИ-ассистента. Он уже умнее большинства обычных чат-ботов, так как умеет поддерживать контекст беседы.

Однако пока наш бот умеет только болтать. В следующей, заключительной части курса, мы добавим ему «руки» — научим его сохранять структурированные данные из диалога прямо в Google Таблицу, превратив его в мощный инструмент для учета финансов, задач или лидов.

База данных: настройка интеграции с Google Таблицами для чтения и записи информации

База данных: настройка интеграции с Google Таблицами для чтения и записи информации

В предыдущих частях курса мы научили нашего бота «слышать» через Telegram и «думать» с помощью OpenAI. Однако у него всё ещё есть существенный недостаток: амнезия. Бот помнит контекст только в рамках текущей оперативной памяти, и если вы перезапустите скрипт, вся история исчезнет. Кроме того, мы не сохраняем полезные данные — расходы, задачи или контакты клиентов.

В этой статье мы подключим к нашему проекту Google Таблицы. Это превратит простого собеседника в полноценный инструмент для сбора и анализа данных.

Почему Google Таблицы?

Для профессиональных высоконагруженных проектов обычно используют базы данных вроде PostgreSQL или MongoDB. Однако для создания MVP (минимально жизнеспособного продукта) или личного ассистента Google Таблицы — идеальный выбор:

  • Визуализация: Вы всегда видите данные глазами, можете править их вручную и строить графики.
  • Бесплатно: Не нужно платить за хостинг базы данных.
  • Доступность: Данные доступны с любого устройства через приложение Google Sheets.

Подключение библиотеки gspread

Мы уже установили библиотеку gspread в первой статье. Теперь создадим отдельный модуль для работы с таблицами. Это хорошая практика — разделять логику бота, ИИ и базы данных по разным файлам.

Создайте файл sheets_db.py в папке вашего проекта. Убедитесь, что файл creds.json (ключ сервисного аккаунта, который мы получили в первом уроке) находится рядом.

Инициализация соединения

Напишем код, который авторизуется в Google API и открывает нашу таблицу.

import gspread
import os
from dotenv import load_dotenv

# Загружаем переменные окружения
load_dotenv()

# Имя файла ключа (должен лежать в папке проекта)
CREDENTIALS_FILE = 'creds.json'

# Имя вашей таблицы (как вы назвали её в браузере)
SPREADSHEET_NAME = 'AI Assistant Data'

def get_worksheet():
    """
    Подключается к Google Таблицам и возвращает первый лист.
    """
    try:
        # Авторизация через сервисный аккаунт
        gc = gspread.service_account(filename=CREDENTIALS_FILE)

        # Открытие таблицы по названию
        sh = gc.open(SPREADSHEET_NAME)

        # Выбор первого листа (обычно 'Лист1' или 'Sheet1')
        return sh.sheet1
    except Exception as e:
        print(f"Ошибка подключения к Google Таблицам: {e}")
        return None

# Проверка подключения
if __name__ == "__main__":
    ws = get_worksheet()
    if ws:
        print(f"Успешно подключено к таблице: {ws.title}")

Запустите этот файл. Если вы видите сообщение «Успешно подключено...», значит, ваш сервисный аккаунт имеет доступ к файлу.

Важно: Если вы получили ошибку SpreadsheetNotFound, убедитесь, что вы дали доступ (Share) к таблице для email-адреса вашего сервисного бота (он есть внутри creds.json в поле client_email).

Запись данных: сохраняем историю

Самая частая задача — добавить новую строку в конец таблицы. Например, мы хотим сохранять каждый запрос пользователя и ответ нейросети.

Подготовьте вашу Google Таблицу. В первой строке (заголовки) напишите названия столбцов:

  1. Дата и время
  2. ID пользователя
  3. Запрос
  4. Ответ ИИ

Теперь добавим функцию записи в sheets_db.py:

from datetime import datetime

def log_message(user_id, user_question, ai_answer):
    """
    Добавляет новую строку с данными диалога.
    """
    ws = get_worksheet()
    if not ws:
        return

    # Формируем текущее время
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    # Данные для записи (порядок должен совпадать со столбцами)
    row = [timestamp, user_id, user_question, ai_answer]

    # Добавляем строку
    ws.append_row(row)
    print("Запись добавлена в таблицу")

Метод append_row автоматически находит первую пустую строку и вставляет туда данные. Это избавляет нас от необходимости вычислять координаты ячеек.

Чтение данных: получение контекста

Иногда боту нужно не только писать, но и читать. Например, проверить, есть ли у пользователя активная подписка, или получить список задач.

Добавим функцию чтения всех записей:

def get_all_logs():
    """
    Возвращает все записи из таблицы в виде списка словарей.
    """
    ws = get_worksheet()
    if not ws:
        return []

    # get_all_records превращает таблицу в список словарей,
    # где ключи — это заголовки столбцов (первая строка).
    return ws.get_all_records()

Если в вашей таблице есть столбцы Name и Age, метод get_all_records() вернет структуру вида: [{'Name': 'Ivan', 'Age': 25}, {'Name': 'Maria', 'Age': 30}].

Математика ограничений Google Таблиц

Хотя Google Таблицы кажутся бесконечными, у них есть технические лимиты. Важно понимать, на сколько хватит вашей «базы данных».

Максимальное количество ячеек в одной таблице Google Sheets составляет 10 миллионов. Рассчитаем, сколько диалогов мы сможем сохранить, используя формулу емкости:

Nrows=LtotalCusedN_{rows} = \frac{L_{total}}{C_{used}}

Где:

  • NrowsN_{rows} — максимальное количество строк (записей), которое мы можем хранить.
  • LtotalL_{total} — общий лимит ячеек (10,000,000).
  • CusedC_{used} — количество используемых столбцов в нашей таблице.

Если мы используем 4 столбца (Дата, ID, Вопрос, Ответ), то:

Nrows=10 000 0004=2 500 000N_{rows} = \frac{10\,000\,000}{4} = 2\,500\,000

Это означает, что мы можем сохранить 2.5 миллиона сообщений. Даже если вы будете писать по 1000 сообщений в день, таблицы хватит почти на 7 лет непрерывной работы. Для личного ассистента этого более чем достаточно.

Интеграция с основным ботом

Теперь самое главное — соединить всё вместе. Вернемся к файлу main.py и добавим вызов функции сохранения после того, как бот отправит ответ.

  1. Импортируйте функцию в начале main.py:
from sheets_db import log_message
  1. Обновите функцию handle_message:
@dp.message()
async def handle_message(message: types.Message):
    # ... (код получения user_id и history)

    # Генерируем ответ ИИ
    ai_answer = get_ai_response(user_text, history)

    # ... (код обновления истории и отправки ответа)
    await message.answer(ai_answer)

    # СОХРАНЕНИЕ В ТАБЛИЦУ
    # Мы используем try-except, чтобы ошибка записи не сломала бота
    try:
        # Внимание: gspread работает синхронно и может на секунду
        # "заморозить" бота. Для простых проектов это допустимо.
        log_message(message.from_user.id, user_text, ai_answer)
    except Exception as e:
        print(f"Не удалось сохранить лог: {e}")

Продвинутый уровень: Асинхронность

Библиотека gspread работает синхронно. Это значит, что пока Python отправляет данные в Google, он не может принимать новые сообщения от других пользователей. Задержка обычно составляет 0.5–1.5 секунды.

Для личного использования это незаметно. Но если ботом будут пользоваться 100 человек одновременно, это станет проблемой. В таких случаях используют обертку asyncio.to_thread, чтобы вынести операцию записи в отдельный поток, не блокируя основной цикл бота.

Пример безопасного вызова:

import asyncio

# Внутри handle_message:
await asyncio.to_thread(log_message, message.from_user.id, user_text, ai_answer)

Заключение

Поздравляю! Теперь ваш ИИ-ассистент обладает долгосрочной памятью. Все диалоги аккуратно складываются в таблицу, которую вы можете анализировать.

Что мы сделали:

  1. Настроили подключение к Google Sheets API.
  2. Научились добавлять новые строки (append_row).
  3. Научились читать данные (get_all_records).
  4. Интегрировали запись логов в основного бота.

Теперь у вас есть полностью рабочий прототип: Telegram (интерфейс) + OpenAI (мозг) + Google Sheets (память). На этой основе вы можете строить системы учета финансов, трекеры привычек или ботов для поддержки клиентов.

Финальная сборка: объединение модулей, деплой на сервер и тестирование сценариев

Финальная сборка: объединение модулей, деплой на сервер и тестирование сценариев

Мы прошли долгий путь. Начав с пустой папки, мы зарегистрировали бота, научили его «думать» с помощью OpenAI и дали ему «память» в виде Google Таблиц. Сейчас у вас на компьютере есть набор файлов, который работает, пока запущен ваш терминал. Но настоящий ИИ-ассистент должен быть доступен 24/7, даже когда вы спите или выключили ноутбук.

В этой финальной статье курса мы превратим наш проект в полноценный сервис. Мы подготовим код к переносу, арендуем виртуальный сервер и настроим автоматический запуск бота.

1. Подготовка проекта к переезду

Сервер — это чужой компьютер, на котором нет ни ваших библиотек, ни ваших настроек. Чтобы бот заработал там так же, как у вас дома, нужно составить «список покупок» — файл зависимостей.

Создание requirements.txt

В Python принят стандарт: список всех необходимых библиотек хранится в файле requirements.txt. Это позволяет одной командой установить всё необходимое на новой машине.

  1. Откройте терминал в папке вашего проекта.
  2. Убедитесь, что виртуальное окружение активировано.
  3. Введите команду:
pip freeze > requirements.txt

Теперь в вашей папке появился текстовый файл. Если вы откроете его, то увидите список вроде aiogram==3.x.x, openai==1.x.x и так далее. Это паспорт вашего проекта.

Проверка файлов

Перед отправкой на сервер убедитесь, что у вас есть следующий набор файлов:

  • main.py — основной файл запуска.
  • ai_brain.py — логика работы с OpenAI.
  • sheets_db.py — логика работы с Google Таблицами.
  • requirements.txt — список библиотек.
  • creds.json — ключ от Google (сервисный аккаунт).
  • .env — ваши токены (Telegram и OpenAI).

Важно: Файлы .env и creds.json содержат секретную информацию. Если вы используете Git для версионирования кода, эти файлы никогда не должны попадать в репозиторий. Но так как мы будем переносить файлы напрямую, нам нужно будет загрузить их на сервер вручную.

2. Аренда виртуального сервера (VPS)

Для хостинга Telegram-ботов идеально подходят VPS (Virtual Private Server) на базе Linux (обычно Ubuntu). Это дешево (от 3-5$ в месяц) и дает полный контроль.

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

  1. Регистрируетесь на хостинге.
  2. Создаете сервер (Droplet/Instance) с операционной системой Ubuntu 22.04 (или новее).
  3. Получаете IP-адрес сервера и пароль от пользователя root.

3. Перенос файлов на сервер

Самый простой способ для новичка перенести файлы на сервер — использовать протокол SFTP. Для этого подойдет бесплатная программа FileZilla.

  1. Скачайте и установите FileZilla.
  2. В поле Хост введите IP-адрес вашего сервера (например, sftp://192.168.1.1).
  3. В поле Пользователь введите root.
  4. В поле Пароль введите пароль, который выдал хостинг.
  5. Нажмите Быстрое соединение.

Слева вы увидите файлы вашего компьютера, справа — файлы сервера.

  1. В правой части (на сервере) создайте папку для бота, например /root/my_ai_bot.
  2. Перетащите туда все файлы вашего проекта из левой части (включая .env и creds.json).

4. Настройка окружения на сервере

Теперь нам нужно «зайти» внутрь сервера и запустить команды. Для этого используется SSH (Secure Shell).

Подключение через терминал

Откройте терминал (PowerShell в Windows или Terminal в macOS) и введите:

ssh root@ваш_ip_адрес

После ввода пароля вы увидите приветствие Ubuntu. Теперь вы управляете удаленным компьютером.

Установка Python и библиотек

Выполняйте команды по очереди:

  1. Обновим списки пакетов:
    apt update && apt upgrade -y
    
  2. Установим менеджер пакетов pip и утилиту для виртуальных окружений (если их нет):
    apt install python3-pip python3-venv -y
    
  3. Перейдем в папку с ботом:
    cd /root/my_ai_bot
    
  4. Создадим виртуальное окружение (как мы делали на компьютере):
    python3 -m venv venv
    
  5. Активируем его:
    source venv/bin/activate
    
  6. Установим библиотеки из нашего списка:
    pip install -r requirements.txt
    

Пробный запуск

Попробуйте запустить бота вручную:

python main.py

Если вы увидели сообщение «Бот запущен...», возьмите телефон и напишите боту. Если он отвечает — отлично! Нажмите Ctrl+C, чтобы остановить его.

Почему остановить? Потому что если вы закроете терминал сейчас, бот выключится. Нам нужно сделать так, чтобы он работал в фоновом режиме.

5. Настройка Systemd: бессмертие для бота

Systemd — это системный менеджер Linux, который умеет запускать программы при старте системы и перезапускать их, если они упали с ошибкой. Мы создадим «службу» (service) для нашего бота.

Создание файла конфигурации

В терминале сервера (находясь в папке бота) выполните команду для создания файла службы:

nano /etc/systemd/system/aibot.service

Откроется текстовый редактор nano. Вставьте туда следующий текст (скорректируйте пути, если они отличаются):

[Unit]
Description=My AI Telegram Bot
After=network.target

[Service]
User=root
WorkingDirectory=/root/my_ai_bot
ExecStart=/root/my_ai_bot/venv/bin/python main.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Разберем, что здесь написано:

  • ExecStart: указывает полный путь к Python внутри виртуального окружения и путь к файлу main.py.
  • Restart=always: приказывает серверу перезапускать бота, если он «упадет» (вылетит с ошибкой).
  • RestartSec=10: ждать 10 секунд перед перезапуском.

Нажмите Ctrl+O, затем Enter (чтобы сохранить), и Ctrl+X (чтобы выйти).

Запуск службы

Теперь активируем нашу магию:

# Перечитываем конфигурацию systemd
systemctl daemon-reload

# Включаем автозапуск бота при перезагрузке сервера
systemctl enable aibot

# Запускаем бота прямо сейчас
systemctl start aibot

Проверим статус:

systemctl status aibot

Если вы видите зеленый кружок и надпись active (running), поздравляю! Ваш бот теперь живет своей жизнью. Вы можете закрыть терминал, выключить компьютер, а бот продолжит работать.

6. Математика надежности (SLA)

В профессиональной разработке существует понятие SLA (Service Level Agreement) — соглашение об уровне доступности. Даже простой бот должен стремиться к высокой доступности.

Доступность (AA) рассчитывается по формуле:

A=TupTup+Tdown×100%A = \frac{T_{up}}{T_{up} + T_{down}} \times 100\%

Где:

  • AA — доступность в процентах.
  • TupT_{up} — время, когда сервис работал корректно.
  • TdownT_{down} — время простоя (ошибки, перезагрузки, падение сервера).

Например, если за месяц (720 часов) ваш бот не работал суммарно 4 часа, его доступность составит:

A=716716+4×100%≈99.44%A = \frac{716}{716 + 4} \times 100\% \approx 99.44\%

Использование systemd с параметром Restart=always помогает минимизировать TdownT_{down}, автоматически поднимая сервис за секунды после сбоя.

7. Тестирование сценариев

Теперь, когда бот в «продакшене» (в боевом режиме), нужно провести финальное тестирование. Мы проверим три главных сценария.

Сценарий 1: Проверка памяти (Context)

Действие:

  1. Напишите боту: «Меня зовут Алекс, я менеджер проектов».
  2. Подождите пару секунд.
  3. Спросите: «Какая у меня профессия?»

Ожидаемый результат: Бот должен ответить «Вы менеджер проектов». Это подтверждает, что переменная history в оперативной памяти сервера работает корректно.

Сценарий 2: Проверка базы данных (Integration)

Действие:

  1. Спросите бота что-то сложное, например: «Придумай 3 идеи для поста о кофе».
  2. Дождитесь ответа.
  3. Откройте вашу Google Таблицу в браузере.

Ожидаемый результат: В таблице должна мгновенно появиться новая строка с датой, вашим ID, вопросом и ответом нейросети. Это подтверждает, что файл creds.json на сервере найден и доступ к API Google работает.

Сценарий 3: Стресс-тест и восстановление

Действие: Мы намеренно «убьем» процесс бота, чтобы проверить, поднимет ли его systemd.

  1. В терминале сервера введите команду, чтобы узнать ID процесса:
    pgrep -f main.py
    
    Допустим, система выдала число 12345.
  2. Убейте процесс:
    kill -9 12345
    
  3. Попробуйте написать боту в Telegram. Сначала он может молчать.
  4. Подождите 10-15 секунд (наша настройка RestartSec).
  5. Напишите снова.

Ожидаемый результат: Бот снова начнет отвечать. Это доказывает, что ваша система автономна и устойчива к сбоям.

Заключение курса

Поздравляю! Вы прошли путь от идеи до работающего облачного продукта.

Чему вы научились:

  1. Telegram API: Создавать интерфейсы для общения.
  2. OpenAI API: Интегрировать искусственный интеллект и настраивать его поведение через системные промпты.
  3. Google Sheets API: Использовать таблицы как базу данных для чтения и записи.
  4. Deployment: Разворачивать Python-приложения на Linux-серверах и обеспечивать их бесперебойную работу.

Что дальше? Этот бот — фундамент. Вы можете улучшать его бесконечно:

  • Добавить распознавание голосовых сообщений (Whisper API).
  • Подключить генерацию картинок (DALL-E).
  • Реализовать напоминания по времени.
  • Переписать хранение истории с оперативной памяти на базу данных (SQLite или PostgreSQL), чтобы бот не забывал имена после перезагрузки сервера.

Теперь у вас есть личный цифровой помощник, который полностью под вашим контролем. Удачи в разработке!