SkyAlone / bot.py
FreshPixels's picture
Update bot.py
9f67f07 verified
Raw
History Blame Contribute Delete
9.36 kB
import asyncio
import logging
import os
import ssl
import sys
import aiohttp
import certifi
from aiohttp import web
from aiogram import Bot, Dispatcher
from aiogram.enums import ParseMode
from aiogram.client.default import DefaultBotProperties
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application
from config import config
from database import db
from handlers.commands import router as commands_router
from handlers.chat import router as chat_router
from handlers.callbacks import router as callbacks_router
from middlewares.owner import OwnerMiddleware
from middlewares.rate_limit import RateLimitMiddleware
# ═══════════════════════════════════════════════════════════════════
# BLOCK 0: SSL-ΠΏΠ°Ρ‚Ρ‡ΠΈ для HF Spaces (certifi + proxy)
# ═══════════════════════════════════════════════════════════════════
custom_ssl = ssl.create_default_context(cafile=certifi.where())
custom_ssl.check_hostname = True
custom_ssl.verify_mode = ssl.CERT_REQUIRED
_orig_tcp_init = aiohttp.TCPConnector.__init__
def _patched_tcp_init(self, *args, **kwargs):
if kwargs.get("ssl") is not False:
kwargs["ssl"] = custom_ssl
_orig_tcp_init(self, *args, **kwargs)
aiohttp.TCPConnector.__init__ = _patched_tcp_init
_orig_session_init = aiohttp.ClientSession.__init__
def _patched_session_init(self, *args, **kwargs):
kwargs["trust_env"] = True
_orig_session_init(self, *args, **kwargs)
aiohttp.ClientSession.__init__ = _patched_session_init
_orig_request = aiohttp.ClientSession._request
async def _patched_request(self, method, url, *args, **kwargs):
proxy_server = os.getenv("TELEGRAM_API_SERVER")
if proxy_server and "api.telegram.org" in str(url):
proxy_server = proxy_server.strip().rstrip("/")
str_url = str(url).replace("https://api.telegram.org", proxy_server)
logging.info("πŸ”€ ΠŸΠ΅Ρ€Π΅Π°Π΄Ρ€Π΅ΡΠ°Ρ†ΠΈΡ aiogram Ρ‡Π΅Ρ€Π΅Π· прокси ➑️ %s", str_url)
url = str_url
return await _orig_request(self, method, url, *args, **kwargs)
aiohttp.ClientSession._request = _patched_request
# ═══════════════════════════════════════════════════════════════════
# BLOCK 1: Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
# ═══════════════════════════════════════════════════════════════════
def setup_logging() -> None:
level = getattr(logging, config.LOG_LEVEL.upper(), logging.INFO)
logging.basicConfig(
level=level,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
stream=sys.stdout,
)
# УмСньшаСм ΡˆΡƒΠΌ ΠΎΡ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
logging.getLogger("aiogram").setLevel(logging.INFO)
# ═══════════════════════════════════════════════════════════════════
# BLOCK 2: Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ Π±ΠΎΡ‚Π° ΠΈ диспСтчСра
# ═══════════════════════════════════════════════════════════════════
bot = Bot(
token=config.BOT_TOKEN,
default=DefaultBotProperties(parse_mode=ParseMode.HTML)
)
dp = Dispatcher()
# Middlewares (порядок Π²Π°ΠΆΠ΅Π½!)
dp.message.middleware(OwnerMiddleware())
dp.message.middleware(RateLimitMiddleware())
# Logging middleware
@dp.update.middleware()
async def log_updates(handler, event, data):
logger = logging.getLogger(__name__)
uid = event.update_id if hasattr(event, 'update_id') else 'N/A'
logger.info("β†’ Update received: %s", uid)
if hasattr(event, 'message') and event.message:
logger.info("β†’ MSG user_id=%s text=%s", event.message.from_user.id, event.message.text)
elif hasattr(event, 'callback_query') and event.callback_query:
logger.info("β†’ CB user_id=%s data=%s", event.callback_query.from_user.id, event.callback_query.data)
try:
result = await handler(event, data)
logger.info("← Handler OK for update %s", uid)
return result
except Exception as e:
logger.error("❌ Handler FAILED for update %s: %s", uid, e, exc_info=True)
raise
# Routers (порядок Π²Π°ΠΆΠ΅Π½: commands β†’ callbacks β†’ chat)
dp.include_router(commands_router)
dp.include_router(callbacks_router)
dp.include_router(chat_router)
# ═══════════════════════════════════════════════════════════════════
# BLOCK 3: HTTP Handlers
# ═══════════════════════════════════════════════════════════════════
@web.middleware
async def hf_logging_middleware(request, handler):
return await handler(request)
async def health_check(request: web.Request) -> web.Response:
"""HF Spaces Health Check β€” ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΎΡ‚Π²Π΅Ρ‡Π°Ρ‚ΡŒ 200 Π½Π° '/'."""
return web.Response(text="πŸš€ GLM Bot Π ΠΠ‘ΠžΠ’ΠΠ•Π’!")
# ═══════════════════════════════════════════════════════════════════
# BLOCK 4: Lifecycle hooks
# ═══════════════════════════════════════════════════════════════════
async def on_startup(app: web.Application) -> None:
logger = logging.getLogger(__name__)
await db.connect()
logger.info("βœ… Database connected")
space_host = os.getenv("SPACE_HOST", "")
if space_host:
full_webhook_link = f"https://{space_host.strip()}{config.WEBHOOK_PATH}"
for attempt in range(5):
try:
await bot.set_webhook(
url=full_webhook_link,
drop_pending_updates=True,
request_timeout=30,
)
logger.info("βœ… Webhook установлСн: %s", full_webhook_link)
break
except Exception as e:
logger.warning(
"⚠️ ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° %d/5 установки webhook: %s", attempt + 1, e
)
await asyncio.sleep(5)
else:
logger.warning("⚠️ SPACE_HOST Π½Π΅ Π·Π°Π΄Π°Π½, webhook Π½Π΅ установлСн!")
async def on_shutdown(app: web.Application) -> None:
logger = logging.getLogger(__name__)
logger.info("πŸ›‘ Shutdown Π½Π°Ρ‡Π°Ρ‚...")
try:
await bot.delete_webhook(drop_pending_updates=True)
logger.info("Webhook ΡƒΠ΄Π°Π»Ρ‘Π½")
except Exception as e:
logger.warning("Ошибка ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ webhook: %s", e)
try:
await dp.storage.close()
await bot.session.close()
logger.info("Bot session Π·Π°ΠΊΡ€Ρ‹Ρ‚")
except Exception as e:
logger.warning("Ошибка ΠΏΡ€ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠΈ сСссии Π±ΠΎΡ‚Π°: %s", e)
try:
await db.disconnect()
logger.info("Database disconnected")
except Exception as e:
logger.warning("Ошибка ΠΏΡ€ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ Π‘Π”: %s", e)
# ═══════════════════════════════════════════════════════════════════
# BLOCK 5: Main
# ═══════════════════════════════════════════════════════════════════
def main() -> None:
setup_logging()
logger = logging.getLogger(__name__)
logger.info("πŸš€ Starting HF Spaces bot...")
logger.info("Config: model=%s, fallback=%s, streaming=%s, rate_limit=%s",
config.PRIMARY_MODEL, config.FALLBACK_MODEL,
config.STREAMING_ENABLED, config.RATE_LIMIT_ENABLED)
app = web.Application(middlewares=[hf_logging_middleware])
app.router.add_get("/", health_check)
webhook_requests_handler = SimpleRequestHandler(dispatcher=dp, bot=bot)
webhook_requests_handler.register(app, path=config.WEBHOOK_PATH)
setup_application(app, dp, bot=bot)
app.on_startup.append(on_startup)
app.on_shutdown.append(on_shutdown)
port = int(os.environ.get("PORT", 7860))
logger.info("πŸš€ Запуск сСрвСра Π½Π° %s:%d...", "0.0.0.0", port)
web.run_app(app, host="0.0.0.0", port=port)
if __name__ == "__main__":
main()