Написание Telegram бота с помощью нейросетей

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

У меня возникло желание написть Телеграм-бота, чтобы он  отвечал на ряд команд и как дальнейшее развитие отдавал или ссыли или изображения документов, а также давал справку по событиям. Т.е. некий семейный ассистент.  Я попробовал несколько чатботов, как говорится  дал им одинаковое описание задачи  и первым критерием было, чтобы заработало сразу.  ChatGPT(OpenAI), LeChat (Mistral), DeepSeek R1, чуть позже подключил Qwen Max.

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

Далее я дал коррекцию- подключить  гугл таблицу. И вот тут пошли проблемы. Только ChatGPT сразу справился, потому его я взял как основной инструмент для работы, а остальные сети использовал в качестве проверяющих, в случае проблем, как консультантов.  Решение было предложено-  создать таблицу, дан шаблон  с описанием какие  листы и какие данные в них должны быть, как создать токены и дать доступк  Таблице Гугл.

Третья коррекция — добавить события из Календаря, причем календарь общесемейный. Вот тут уже  ChatGPT  сам стал чудить. Я отложил  работы на другой день.  После чего попытался продолжить общение в том же чате. Все было вроде логично, но начались пропуски в ответах, например на мои  ошибки он давал способы устранения, которые ломали доступ к таблице. Начинаю править таблицу- слетает Календарь, и так по кругу,  Потом  и вовсе случился казус- к таблице доступ он  переделал, но почему то он «забыл»  о ее структуре. Попытка получить в качестве ответа готовый единый скрипт не привела к успеху.  Тут сказались и ограничения бесплатного использования, не мог загрузить готовые  рабочиие скрипты.

Наконец в игру вступил Qwen. Принципиально не хотел использовать платные или  специализированные решения. Ему задачу поставил другую- есть 2 рабочих скрипта- сделай один. Все аналогично вышеупомянутым проблемам, но осознавая, что уже надо ускоряться , я  уже все правки доводил в этом чатботе. Но и здесь не без «греха». Отказался выдавать мне полный текст  скрипта, пришлось в явном виде указать, чтобы разбис скрипт на несколько частей при выводе.

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

Для галочки, здесь приведу окончательный скрипт на этот момент. Конечно аппетит приходит во время еды, так и у меня уже идеи срастить бота с Immich, Webtrees да и может своего асистента поднять по анализу внутренних ресурсов моей сети.

 

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

Краткий обзор настроек:

  1. Google Cloud Console:
  • Создали проект.
  • Включили необходимые API: Google Sheets API, Google Drive API, Google Calendar API.
  • Настроили Consent Screen.
  • Создали учетные данные OAuth 2.0 для Google Sheets и Google Calendar с правильными областями (scopes).
  1. Файлы учетных данных:
  • Скачали и сохранили credentials_sheets.json и credentials_calendar.json.
  • Убедились, что файлы имеют правильный формат и содержат данные для Desktop app.
  1. Скрипт:
  • Разделили учетные данные для Google Sheets и Google Calendar.
  • Реализовали методы авторизации для каждого сервиса.
  • Объединили функциональность обоих скриптов в один.

Полный итоговый скрипт для удобства:

Часть 1: Начало кода (до функции get_today_events)

import logging
from telegram import Update
from telegram.ext import (
    ApplicationBuilder,
    CommandHandler,
    MessageHandler,
    ContextTypes,
    filters,
)
import gspread
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from datetime import datetime, timedelta, date, UTC  # Используем встроенный UTC
import os
import googleapiclient.discovery

# Отключаем кэширование для предотвращения предупреждений
googleapiclient.discovery.CACHE_DISCOVERY = False

# ----------------------------
# 🔐 НАСТРОЙКИ ПОД СЕБЯ
# ----------------------------

TELEGRAM_BOT_TOKEN = "ТВОЙ_ТОКЕН_БОТА"  # ← Вставь сюда свой токен Telegram бота

CREDENTIALS_SHEETS_FILE = "credentials_sheets.json"  # Файл для OAuth 2.0 Google Sheets
CREDENTIALS_CALENDAR_FILE = "credentials_calendar.json"  # Файл для OAuth 2.0 Google Calendar
SPREADSHEET_NAME = "Family_Data"  # Название таблицы в Google Sheets

GOOGLE_CALENDAR_ID = 'your-family-calendar@group.calendar.google.com'  # ID семейного календаря

# Настройка логирования
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO)

# ----------------------------
# 🛠️ Универсальный метод авторизации для Google Sheets
# ----------------------------

def get_credentials_sheets():
    creds = None
    # Проверяем, есть ли уже сохраненный токен для Sheets
    if os.path.exists('token_sheets.json'):
        creds = Credentials.from_authorized_user_file('token_sheets.json', ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive'])
    # Если нет валидных учетных данных, запрашиваем их
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_SHEETS_FILE, ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive'])
            creds = flow.run_local_server(port=0)
        # Сохраняем учетные данные для следующего запуска
        with open('token_sheets.json', 'w') as token:
            token.write(creds.to_json())
    return creds

# Авторизация Google Sheets API
creds_sheets = get_credentials_sheets()
client = gspread.authorize(creds_sheets)
sheet = client.open(SPREADSHEET_NAME)

# ----------------------------
# 🛠️ Универсальный метод авторизации для Google Calendar
# ----------------------------

def get_credentials_calendar():
    creds = None
    # Проверяем, есть ли уже сохраненный токен для Calendar
    if os.path.exists('token_calendar.json'):
        creds = Credentials.from_authorized_user_file('token_calendar.json', ['https://www.googleapis.com/auth/calendar.readonly'])
    # Если нет валидных учетных данных, запрашиваем их
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_CALENDAR_FILE, ['https://www.googleapis.com/auth/calendar.readonly'])
            creds = flow.run_local_server(port=0)
        # Сохраняем учетные данные для следующего запуска
        with open('token_calendar.json', 'w') as token:
            token.write(creds.to_json())
    return creds

# Авторизация Google Calendar API
creds_calendar = get_credentials_calendar()
calendar_service = build('calendar', 'v3', credentials=creds_calendar)

# ----------------------------
# 📂 Загрузка данных из Google Sheets
# ----------------------------

def load_birthdays():
    try:
        data = sheet.worksheet("birthdays").get_all_records()
        return {row["имя"].strip().lower(): row["дата"] for row in data}
    except Exception as e:
        print(f"[Ошибка] Не удалось загрузить дни рождения: {e}")
        return {}

def load_events():
    try:
        data = sheet.worksheet("events").get_all_records()
        events = {}
        for row in data:
            key = row["дата (ISO)"].strip()
            if key not in events:
                events[key] = []
            events[key].append(row["событие"])
        return events
    except Exception as e:
        print(f"[Ошибка] Не удалось загрузить события: {e}")
        return {}

def load_documents():
    try:
        data = sheet.worksheet("documents").get_all_records()
        return {row["название"].strip().lower(): row["ссылка"] for row in data}
    except Exception as e:
        print(f"[Ошибка] Не удалось загрузить документы: {e}")
        return {}

# ----------------------------
# 📅 Получение событий на сегодня из Google Calendar
# ----------------------------

def get_today_events():
    now = datetime.now(UTC).isoformat()  # Текущее время в UTC
    end_of_day = (datetime.now(UTC) + timedelta(hours=23)).isoformat()

    events_result = calendar_service.events().list(
        calendarId=GOOGLE_CALENDAR_ID,
        timeMin=now,
        timeMax=end_of_day,
        singleEvents=True,
        orderBy='startTime'
    ).execute()

    events = events_result.get('items', [])

    if not events:
        return ["📭 Сегодня в календаре нет событий."]

    event_list = []
    for event in events:
        start = event['start'].get('dateTime', event['start'].get('date'))
        summary = event.get('summary', 'Без названия')
        try:
            time_str = datetime.fromisoformat(start).strftime("%H:%M")
        except:
            time_str = "весь день"
        event_list.append(f"🕒 {time_str} — {summary}")

    return event_list

Часть 2: Продолжение функции get_today_events и команды бота

# ----------------------------
# 🤖 Команды бота
# ----------------------------

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "👋 Привет! Я семейный помощник.\n"
        "Доступные команды:\n"
        "/today — события из календаря на сегодня 📅\n"
        "др мама — узнать день рождения\n"
        "события — что сегодня запланировано\n"
        "док паспорт мамы — получить ссылку на документ"
    )

async def today_summary(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("🔎 Проверяю календарь...")
    events = get_today_events()
    await update.message.reply_text("📅 События на сегодня:\n" + "\n".join(events))

async def today_events(update: Update, context: ContextTypes.DEFAULT_TYPE):
    events = load_events()
    today = date.today().isoformat()
    if today in events:
        await update.message.reply_text("Сегодня:\n" + "\n".join(events[today]))
    else:
        await update.message.reply_text("Сегодня нет запланированных событий.")

Часть 3: Обработка обычных сообщений

# ----------------------------
# 📩 Обработка обычных сообщений
# ----------------------------

async def message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    text = update.message.text.lower().strip()
    birthdays = load_birthdays()
    events = load_events()
    documents = load_documents()

    if text.startswith("др"):
        name = text.replace("др", "").strip()
        if name in birthdays:
            await update.message.reply_text(f"У {name} день рождения {birthdays[name]}")
        else:
            await update.message.reply_text("Не нашёл такого имени.")

    elif text == "события":
        await today_events(update, context)

    elif text.startswith("док"):
        doc = text.replace("док", "").strip()
        if doc in documents:
            await update.message.reply_text(f"Вот ссылка на «{doc}»: {documents[doc]}")
        else:
            await update.message.reply_text("Документ не найден.")

    else:
        await update.message.reply_text("Не понял запрос. Пример: 'др мама', 'события', 'док паспорт мамы'")

Часть 4: Запуск бота

# ----------------------------
# 🚀 Запуск бота
# ----------------------------

if __name__ == "__main__":
    app = ApplicationBuilder().token(TELEGRAM_BOT_TOKEN).build()

    # Команды
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("today", today_summary))
    app.add_handler(CommandHandler("events", today_events))

    # Текстовые сообщения
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, message_handler))

    print("✅ Бот запущен. Ожидаю сообщений...")
    app.run_polling()

Дополнительные рекомендации

  1. Безопасность:
  • Не публикуйте файлы credentials_sheets.json, credentials_calendar.json, token_sheets.json и token_calendar.json в открытых репозиториях или других общедоступных местах.
  1. Логирование:
  • Убедитесь, что логирование настроено правильно для отслеживания ошибок и работы бота.
  1. Обновление зависимостей:
  • Регулярно обновляйте зависимости, чтобы избежать уязвимостей и использовать последние возможности библиотек:
    bash pip install --upgrade pip pip install --upgrade python-telegram-bot google-api-python-client google-auth-httplib2 google-auth-oauthlib gspread

Если у вас возникнут дополнительные вопросы или потребуется новая функциональность, дайте знать! 😊

Разместить:
  • Добавить ВКонтакте заметку об этой странице
  • PDF
  • Яндекс.Закладки