Ahmad3g commited on
Commit
78d7683
ยท
1 Parent(s): fae6cf3
Files changed (1) hide show
  1. main.py +16 -57
main.py CHANGED
@@ -1,24 +1,3 @@
1
- """
2
- main.py โ€” Webhook mode for Hugging Face Spaces.
3
-
4
- WHY WEBHOOK INSTEAD OF POLLING:
5
- โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
6
- Hugging Face blocks outbound connections from Docker containers.
7
- Polling requires the bot to connect OUT to api.telegram.org โ€” blocked.
8
- Webhook is the opposite: Telegram connects IN to our server โ€” allowed.
9
-
10
- HOW IT WORKS:
11
- โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
12
- 1. We tell Telegram: "Send all updates to https://OUR_HF_URL/webhook"
13
- 2. Telegram POSTs each update to our aiohttp server
14
- 3. aiogram processes it normally โ€” no outbound polling needed
15
-
16
- REQUIRED ENVIRONMENT VARIABLE (add to HF Secrets):
17
- โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
18
- WEBHOOK_URL = https://YOUR_USERNAME-YOUR_SPACE_NAME.hf.space
19
- Example : https://ahmad3g-telegram-bot.hf.space
20
- """
21
-
22
  import asyncio
23
  import logging
24
  import sys
@@ -59,11 +38,13 @@ WEBHOOK_PATH = "/webhook"
59
  async def handle_root(request: web.Request) -> web.Response:
60
  status = "โœ… running" if BOT_STATUS["running"] else "โณ starting"
61
  error = f"\nโŒ Last error: {BOT_STATUS['error']}" if BOT_STATUS["error"] else ""
 
 
62
  body = (
63
  f"๐Ÿค– Knowledge Base Bot โ€” {status}\n"
64
  f"๐Ÿ•’ Server time : {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n"
65
  f"๐Ÿš€ Bot started : {BOT_STATUS['started_at'] or 'not yet'}"
66
- f"{error}"
67
  )
68
  return web.Response(text=body, content_type="text/plain", status=200)
69
 
@@ -106,7 +87,6 @@ async def main() -> None:
106
  except EnvironmentError as e:
107
  logger.critical(str(e))
108
  BOT_STATUS["error"] = str(e)
109
- # Still start the web server so HF Space shows something
110
  app = web.Application()
111
  app.router.add_get("/", handle_root)
112
  runner = web.AppRunner(app)
@@ -128,11 +108,10 @@ async def main() -> None:
128
  if attempt < 5:
129
  await asyncio.sleep(5)
130
  else:
131
- logger.critical("๐Ÿ’ฅ DB unavailable โ€” bot will not start.")
132
- # Web server still starts below
133
  break
134
 
135
- # โ”€โ”€ 3. Bot + webhook setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
136
  bot = Bot(
137
  token=config.BOT_TOKEN,
138
  default=DefaultBotProperties(parse_mode=ParseMode.HTML),
@@ -140,34 +119,13 @@ async def main() -> None:
140
 
141
  dp = build_dispatcher()
142
 
143
- # Build the full webhook URL
144
- webhook_url = f"{config.WEBHOOK_URL.rstrip('/')}{WEBHOOK_PATH}"
145
- logger.info(f"๐Ÿ”— Setting webhook: {webhook_url}")
146
-
147
- # Register webhook with Telegram
148
- # (This is an OUTBOUND call โ€” but it only happens ONCE at startup,
149
- # before HF fully locks down the container network in some cases.
150
- # If it fails, set the webhook manually via browser:
151
- # https://api.telegram.org/botTOKEN/setWebhook?url=WEBHOOK_URL)
152
- try:
153
- await bot.delete_webhook(drop_pending_updates=True)
154
- await bot.set_webhook(
155
- url=webhook_url,
156
- allowed_updates=dp.resolve_used_update_types(),
157
- drop_pending_updates=True,
158
- )
159
- logger.info("โœ… Webhook registered with Telegram.")
160
- BOT_STATUS["running"] = True
161
- BOT_STATUS["started_at"] = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
162
- BOT_STATUS["error"] = None
163
- except Exception as exc:
164
- logger.error(f"โš ๏ธ Could not set webhook automatically: {exc}")
165
- logger.info(
166
- f"๐Ÿ‘‰ Set it manually in browser:\n"
167
- f" https://api.telegram.org/bot{config.BOT_TOKEN}"
168
- f"/setWebhook?url={webhook_url}"
169
- )
170
- BOT_STATUS["error"] = f"Webhook not set: {exc}"
171
 
172
  # โ”€โ”€ 4. aiohttp app with webhook handler โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
173
  app = web.Application()
@@ -176,7 +134,7 @@ async def main() -> None:
176
  app.router.add_get("/", handle_root)
177
  app.router.add_get("/health", handle_health)
178
 
179
- # aiogram webhook handler โ€” Telegram POSTs updates here
180
  SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH)
181
  setup_application(app, dp, bot=bot)
182
 
@@ -185,8 +143,9 @@ async def main() -> None:
185
  await runner.setup()
186
  site = web.TCPSite(runner, host=config.WEB_HOST, port=config.WEB_PORT)
187
  await site.start()
188
- logger.info(f"โœ… Server on http://{config.WEB_HOST}:{config.WEB_PORT}/")
189
- logger.info(f"โœ… Webhook endpoint: {WEBHOOK_PATH}")
 
190
 
191
  # Keep running forever
192
  while True:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
  import logging
3
  import sys
 
38
  async def handle_root(request: web.Request) -> web.Response:
39
  status = "โœ… running" if BOT_STATUS["running"] else "โณ starting"
40
  error = f"\nโŒ Last error: {BOT_STATUS['error']}" if BOT_STATUS["error"] else ""
41
+ # ู…ู„ุงุญุธุฉ ู„ู„ู…ุณุชุฎุฏู… ููŠ ุงู„ุตูุญุฉ ุงู„ุฑุฆูŠุณูŠุฉ
42
+ manual_notice = "\n\n๐Ÿ’ก Note: Webhook is set manually to bypass HF outbound block."
43
  body = (
44
  f"๐Ÿค– Knowledge Base Bot โ€” {status}\n"
45
  f"๐Ÿ•’ Server time : {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n"
46
  f"๐Ÿš€ Bot started : {BOT_STATUS['started_at'] or 'not yet'}"
47
+ f"{error}{manual_notice}"
48
  )
49
  return web.Response(text=body, content_type="text/plain", status=200)
50
 
 
87
  except EnvironmentError as e:
88
  logger.critical(str(e))
89
  BOT_STATUS["error"] = str(e)
 
90
  app = web.Application()
91
  app.router.add_get("/", handle_root)
92
  runner = web.AppRunner(app)
 
108
  if attempt < 5:
109
  await asyncio.sleep(5)
110
  else:
111
+ logger.critical("๐Ÿ’ฅ DB unavailable.")
 
112
  break
113
 
114
+ # โ”€โ”€ 3. Bot Setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
115
  bot = Bot(
116
  token=config.BOT_TOKEN,
117
  default=DefaultBotProperties(parse_mode=ParseMode.HTML),
 
119
 
120
  dp = build_dispatcher()
121
 
122
+ # โš ๏ธ ุชู… ุชุนุทูŠู„ ุงู„ุญุฐู ูˆุงู„ุชุณุฌูŠู„ ุงู„ุชู„ู‚ุงุฆูŠ ู„ู„ูˆูŠุจ ู‡ูˆูƒ ู‡ู†ุง ู„ุชุฌู†ุจ ุญุฌุจ HF
123
+ # ุงู„ุชุณุฌูŠู„ ูŠุชู… ูŠุฏูˆูŠุงู‹ ู…ู† ุงู„ู…ุชุตูุญ ูƒู…ุง ูุนู„ุช ุณุงุจู‚ุงู‹
124
+ logger.info("โ„น๏ธ Skipping automatic webhook registration (HF compatibility mode).")
125
+
126
+ BOT_STATUS["running"] = True
127
+ BOT_STATUS["started_at"] = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
128
+ BOT_STATUS["error"] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  # โ”€โ”€ 4. aiohttp app with webhook handler โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
131
  app = web.Application()
 
134
  app.router.add_get("/", handle_root)
135
  app.router.add_get("/health", handle_health)
136
 
137
+ # ุชุณุฌูŠู„ ู…ุนุงู„ุฌ ุงู„ูˆูŠุจ ู‡ูˆูƒ (ู‡ุฐุง ูŠุฌุนู„ ุงู„ุจูˆุช "ูŠุณู…ุน" ู„ู„ุฑุณุงุฆู„ ุงู„ู‚ุงุฏู…ุฉ)
138
  SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH)
139
  setup_application(app, dp, bot=bot)
140
 
 
143
  await runner.setup()
144
  site = web.TCPSite(runner, host=config.WEB_HOST, port=config.WEB_PORT)
145
  await site.start()
146
+
147
+ logger.info(f"๐Ÿš€ Server is UP on http://{config.WEB_HOST}:{config.WEB_PORT}/")
148
+ logger.info(f"๐Ÿ“ก Waiting for Telegram updates via: {config.WEBHOOK_URL}{WEBHOOK_PATH}")
149
 
150
  # Keep running forever
151
  while True: