import os import sqlite3 import telebot from flask import Flask, request, render_template_string, flash, redirect, url_for from werkzeug.middleware.proxy_fix import ProxyFix # ================= НАСТРОЙКИ ================= # ВАЖНО: токен теперь берётся из переменной окружения (Settings -> Variables and secrets -> BOT_TOKEN) # Никогда не храните токен прямо в коде, особенно в публичном Space! TOKEN = os.environ.get('BOT_TOKEN') if not TOKEN: raise RuntimeError( "Не найден BOT_TOKEN. Добавьте его в Settings -> Variables and secrets вашего Space " "(и не забудьте отозвать старый токен через @BotFather, если он раньше был в коде)." ) HOST = '0.0.0.0' PORT = 7860 # Если в Space включено Persistent Storage, оно монтируется в /data. # Если папка есть - используем её (данные переживут перезапуск контейнера), # иначе - как раньше, локальную папку (данные будут теряться при "засыпании" Space). BASE_DIR = os.path.dirname(os.path.abspath(__file__)) PERSIST_DIR = '/data' DB_DIR = PERSIST_DIR if os.path.isdir(PERSIST_DIR) and os.access(PERSIST_DIR, os.W_OK) else BASE_DIR DB_FILE = os.path.join(DB_DIR, 'subscribers.db') bot = telebot.TeleBot(TOKEN) app = Flask(__name__) app.secret_key = os.environ.get('FLASK_SECRET', 'super_secret_key_for_flask') # Настройка прокси для корректной работы Webhook внутри Hugging Face app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1) # ================= БАЗА ДАННЫХ ================= def init_db(): with sqlite3.connect(DB_FILE, timeout=10) as conn: cursor = conn.cursor() cursor.execute('CREATE TABLE IF NOT EXISTS subscribers (chat_id INTEGER PRIMARY KEY)') conn.commit() def add_subscriber(chat_id): try: with sqlite3.connect(DB_FILE, timeout=10) as conn: cursor = conn.cursor() cursor.execute('INSERT OR IGNORE INTO subscribers (chat_id) VALUES (?)', (chat_id,)) conn.commit() except Exception as e: print(f"Ошибка БД (добавление): {e}") def get_all_subscribers(): try: with sqlite3.connect(DB_FILE, timeout=10) as conn: cursor = conn.cursor() cursor.execute('SELECT chat_id FROM subscribers') return [row[0] for row in cursor.fetchall()] except Exception: return [] def remove_subscriber(chat_id): try: with sqlite3.connect(DB_FILE, timeout=10) as conn: cursor = conn.cursor() cursor.execute('DELETE FROM subscribers WHERE chat_id = ?', (chat_id,)) conn.commit() except Exception as e: print(f"Ошибка БД (удаление): {e}") # ================= БОТ (HANDLERS) ================= @bot.message_handler(commands=['start']) def handle_start(message): chat_id = message.chat.id first_name = message.from_user.first_name or "Пользователь" add_subscriber(chat_id) text = (f"Привет, {first_name}! 👋\n\n" f"Вы подписались на рассылку и будете получать все обновления.\n\n" f"Чтобы отписаться, напишите /stop.") bot.reply_to(message, text) @bot.message_handler(commands=['stop']) def handle_stop(message): chat_id = message.chat.id remove_subscriber(chat_id) bot.reply_to(message, "Вы успешно отписались от рассылки. 🔇") # ================= FLASK UI & WEBHOOK ================= @app.route('/webhook', methods=['POST']) def webhook(): if request.headers.get('content-type') == 'application/json': json_string = request.get_data().decode('utf-8') update = telebot.types.Update.de_json(json_string) bot.process_new_updates([update]) return '', 200 return 'Forbidden', 403 HTML_TEMPLATE = """